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

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial: (31 commits)
  trivial: remove the trivial patch monkey's name from SubmittingPatches
  trivial: Fix a typo in comment of addrconf_dad_start()
  trivial: usb: fix missing space typo in doc
  trivial: pci hotplug: adding __init/__exit macros to sgi_hotplug
  trivial: Remove the hyphen from git commands
  trivial: fix ETIMEOUT -> ETIMEDOUT typos
  trivial: Kconfig: .ko is normally not included in module names
  trivial: SubmittingPatches: fix typo
  trivial: Documentation/dell_rbu.txt: fix typos
  trivial: Fix Pavel's address in MAINTAINERS
  trivial: ftrace:fix description of trace directory
  trivial: unnecessary (void*) cast removal in sound/oss/msnd.c
  trivial: input/misc: Fix typo in Kconfig
  trivial: fix grammo in bus_for_each_dev() kerneldoc
  trivial: rbtree.txt: fix rb_entry() parameters in sample code
  trivial: spelling fix in ppc code comments
  trivial: fix typo in bio_alloc kernel doc
  trivial: Documentation/rbtree.txt: cleanup kerneldoc of rbtree.txt
  trivial: Miscellaneous documentation typo fixes
  trivial: fix typo milisecond/millisecond for documentation and source comments.
  ...
diff --git a/Documentation/Changes b/Documentation/Changes
index b95082b..d21b3b5 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -48,6 +48,7 @@
 o  oprofile               0.9                     # oprofiled --version
 o  udev                   081                     # udevinfo -V
 o  grub                   0.93                    # grub --version
+o  mcelog		  0.6
 
 Kernel compilation
 ==================
@@ -276,6 +277,16 @@
 services be protected from the internet-at-large by a firewall where
 that is possible.
 
+mcelog
+------
+
+In Linux 2.6.31+ the i386 kernel needs to run the mcelog utility
+as a regular cronjob similar to the x86-64 kernel to process and log
+machine check events when CONFIG_X86_NEW_MCE is enabled. Machine check
+events are errors reported by the CPU. Processing them is strongly encouraged.
+All x86-64 kernels since 2.6.4 require the mcelog utility to
+process machine checks.
+
 Getting updated software
 ========================
 
@@ -365,6 +376,10 @@
 ----
 o <http://sourceforge.net/projects/fuse>
 
+mcelog
+------
+o <ftp://ftp.kernel.org/pub/linux/utils/cpu/mce/mcelog/>
+
 Networking
 **********
 
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index ddc903a..5c555a8b 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -91,6 +91,10 @@
 things like "update driver X", "bug fix for driver X", or "this patch
 includes updates for subsystem X.  Please apply."
 
+The maintainer will thank you if you write your patch description in a
+form which can be easily pulled into Linux's source code management
+system, git, as a "commit log".  See #15, below.
+
 If your description starts to get long, that's a sign that you probably
 need to split up your patch.  See #3, next.
 
@@ -405,7 +409,14 @@
 have been included in the discussion
 
 
-14) Using Tested-by: and Reviewed-by:
+14) Using Reported-by:, Tested-by: and Reviewed-by:
+
+If this patch fixes a problem reported by somebody else, consider adding a
+Reported-by: tag to credit the reporter for their contribution.  Please
+note that this tag should not be added without the reporter's permission,
+especially if the problem was not reported in a public forum.  That said,
+if we diligently credit our bug reporters, they will, hopefully, be
+inspired to help us again in the future.
 
 A Tested-by: tag indicates that the patch has been successfully tested (in
 some environment) by the person named.  This tag informs maintainers that
@@ -485,12 +496,33 @@
 phrase" for every patch in a whole patch series (where a "patch
 series" is an ordered sequence of multiple, related patches).
 
-Bear in mind that the "summary phrase" of your email becomes
-a globally-unique identifier for that patch.  It propagates
-all the way into the git changelog.  The "summary phrase" may
-later be used in developer discussions which refer to the patch.
-People will want to google for the "summary phrase" to read
-discussion regarding that patch.
+Bear in mind that the "summary phrase" of your email becomes a
+globally-unique identifier for that patch.  It propagates all the way
+into the git changelog.  The "summary phrase" may later be used in
+developer discussions which refer to the patch.  People will want to
+google for the "summary phrase" to read discussion regarding that
+patch.  It will also be the only thing that people may quickly see
+when, two or three months later, they are going through perhaps
+thousands of patches using tools such as "gitk" or "git log
+--oneline".
+
+For these reasons, the "summary" must be no more than 70-75
+characters, and it must describe both what the patch changes, as well
+as why the patch might be necessary.  It is challenging to be both
+succinct and descriptive, but that is what a well-written summary
+should do.
+
+The "summary phrase" may be prefixed by tags enclosed in square
+brackets: "Subject: [PATCH tag] <summary phrase>".  The tags are not
+considered part of the summary phrase, but describe how the patch
+should be treated.  Common tags might include a version descriptor if
+the multiple versions of the patch have been sent out in response to
+comments (i.e., "v1, v2, v3"), or "RFC" to indicate a request for
+comments.  If there are four patches in a patch series the individual
+patches may be numbered like this: 1/4, 2/4, 3/4, 4/4.  This assures
+that developers understand the order in which the patches should be
+applied and that they have reviewed or applied all of the patches in
+the patch series.
 
 A couple of example Subjects:
 
@@ -510,19 +542,31 @@
 The explanation body will be committed to the permanent source
 changelog, so should make sense to a competent reader who has long
 since forgotten the immediate details of the discussion that might
-have led to this patch.
+have led to this patch.  Including symptoms of the failure which the
+patch addresses (kernel log messages, oops messages, etc.) is
+especially useful for people who might be searching the commit logs
+looking for the applicable patch.  If a patch fixes a compile failure,
+it may not be necessary to include _all_ of the compile failures; just
+enough that it is likely that someone searching for the patch can find
+it.  As in the "summary phrase", it is important to be both succinct as
+well as descriptive.
 
 The "---" marker line serves the essential purpose of marking for patch
 handling tools where the changelog message ends.
 
 One good use for the additional comments after the "---" marker is for
-a diffstat, to show what files have changed, and the number of inserted
-and deleted lines per file.  A diffstat is especially useful on bigger
-patches.  Other comments relevant only to the moment or the maintainer,
-not suitable for the permanent changelog, should also go here.
-Use diffstat options "-p 1 -w 70" so that filenames are listed from the
-top of the kernel source tree and don't use too much horizontal space
-(easily fit in 80 columns, maybe with some indentation).
+a diffstat, to show what files have changed, and the number of
+inserted and deleted lines per file.  A diffstat is especially useful
+on bigger patches.  Other comments relevant only to the moment or the
+maintainer, not suitable for the permanent changelog, should also go
+here.  A good example of such comments might be "patch changelogs"
+which describe what has changed between the v1 and v2 version of the
+patch.
+
+If you are going to include a diffstat after the "---" marker, please
+use diffstat options "-p 1 -w 70" so that filenames are listed from
+the top of the kernel source tree and don't use too much horizontal
+space (easily fit in 80 columns, maybe with some indentation).
 
 See more details on the proper patch format in the following
 references.
diff --git a/Documentation/arm/Samsung-S3C24XX/GPIO.txt b/Documentation/arm/Samsung-S3C24XX/GPIO.txt
index ea7ccfc..948c871 100644
--- a/Documentation/arm/Samsung-S3C24XX/GPIO.txt
+++ b/Documentation/arm/Samsung-S3C24XX/GPIO.txt
@@ -51,7 +51,7 @@
 -----------
 
   Each pin has an unique number associated with it in regs-gpio.h,
-  eg S3C2410_GPA0 or S3C2410_GPF1. These defines are used to tell
+  eg S3C2410_GPA(0) or S3C2410_GPF(1). These defines are used to tell
   the GPIO functions which pin is to be used.
 
 
@@ -65,11 +65,11 @@
 
   Eg:
 
-     s3c2410_gpio_cfgpin(S3C2410_GPA0, S3C2410_GPA0_ADDR0);
-     s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1);
+     s3c2410_gpio_cfgpin(S3C2410_GPA(0), S3C2410_GPA0_ADDR0);
+     s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1);
 
-   which would turn GPA0 into the lowest Address line A0, and set
-   GPE8 to be connected to the SDIO/MMC controller's SDDAT1 line.
+   which would turn GPA(0) into the lowest Address line A0, and set
+   GPE(8) to be connected to the SDIO/MMC controller's SDDAT1 line.
 
 
 Reading the current configuration
diff --git a/Documentation/development-process/5.Posting b/Documentation/development-process/5.Posting
index dd48132..f622c1e 100644
--- a/Documentation/development-process/5.Posting
+++ b/Documentation/development-process/5.Posting
@@ -119,7 +119,7 @@
 done.  When done properly, though, it is time well spent.
 
 
-5.4: PATCH FORMATTING
+5.4: PATCH FORMATTING AND CHANGELOGS
 
 So now you have a perfect series of patches for posting, but the work is
 not done quite yet.  Each patch needs to be formatted into a message which
@@ -146,8 +146,33 @@
  - One or more tag lines, with, at a minimum, one Signed-off-by: line from
    the author of the patch.  Tags will be described in more detail below.
 
-The above three items should, normally, be the text used when committing
-the change to a revision control system.  They are followed by:
+The items above, together, form the changelog for the patch.  Writing good
+changelogs is a crucial but often-neglected art; it's worth spending
+another moment discussing this issue.  When writing a changelog, you should
+bear in mind that a number of different people will be reading your words.
+These include subsystem maintainers and reviewers who need to decide
+whether the patch should be included, distributors and other maintainers
+trying to decide whether a patch should be backported to other kernels, bug
+hunters wondering whether the patch is responsible for a problem they are
+chasing, users who want to know how the kernel has changed, and more.  A
+good changelog conveys the needed information to all of these people in the
+most direct and concise way possible.
+
+To that end, the summary line should describe the effects of and motivation
+for the change as well as possible given the one-line constraint.  The
+detailed description can then amplify on those topics and provide any
+needed additional information.  If the patch fixes a bug, cite the commit
+which introduced the bug if possible.  If a problem is associated with
+specific log or compiler output, include that output to help others
+searching for a solution to the same problem.  If the change is meant to
+support other changes coming in later patch, say so.  If internal APIs are
+changed, detail those changes and how other developers should respond.  In
+general, the more you can put yourself into the shoes of everybody who will
+be reading your changelog, the better that changelog (and the kernel as a
+whole) will be.
+
+Needless to say, the changelog should be the text used when committing the
+change to a revision control system.  It will be followed by:
 
  - The patch itself, in the unified ("-u") patch format.  Using the "-p"
    option to diff will associate function names with changes, making the
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index de491a3..ec9ef5d 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -437,3 +437,13 @@
 	driver but this caused driver conflicts.
 Who:	Jean Delvare <khali@linux-fr.org>
 	Krzysztof Helt <krzysztof.h1@wp.pl>
+
+----------------------------
+
+What:	CONFIG_X86_OLD_MCE
+When:	2.6.32
+Why:	Remove the old legacy 32bit machine check code. This has been
+	superseded by the newer machine check code from the 64bit port,
+	but the old version has been kept around for easier testing. Note this
+	doesn't impact the old P5 and WinChip machine check handlers.
+Who:	Andi Kleen <andi@firstfloor.org>
diff --git a/Documentation/filesystems/debugfs.txt b/Documentation/filesystems/debugfs.txt
new file mode 100644
index 0000000..ed52af6
--- /dev/null
+++ b/Documentation/filesystems/debugfs.txt
@@ -0,0 +1,158 @@
+Copyright 2009 Jonathan Corbet <corbet@lwn.net>
+
+Debugfs exists as a simple way for kernel developers to make information
+available to user space.  Unlike /proc, which is only meant for information
+about a process, or sysfs, which has strict one-value-per-file rules,
+debugfs has no rules at all.  Developers can put any information they want
+there.  The debugfs filesystem is also intended to not serve as a stable
+ABI to user space; in theory, there are no stability constraints placed on
+files exported there.  The real world is not always so simple, though [1];
+even debugfs interfaces are best designed with the idea that they will need
+to be maintained forever.
+
+Debugfs is typically mounted with a command like:
+
+    mount -t debugfs none /sys/kernel/debug
+
+(Or an equivalent /etc/fstab line). 
+
+Note that the debugfs API is exported GPL-only to modules.
+
+Code using debugfs should include <linux/debugfs.h>.  Then, the first order
+of business will be to create at least one directory to hold a set of
+debugfs files:
+
+    struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
+
+This call, if successful, will make a directory called name underneath the
+indicated parent directory.  If parent is NULL, the directory will be
+created in the debugfs root.  On success, the return value is a struct
+dentry pointer which can be used to create files in the directory (and to
+clean it up at the end).  A NULL return value indicates that something went
+wrong.  If ERR_PTR(-ENODEV) is returned, that is an indication that the
+kernel has been built without debugfs support and none of the functions
+described below will work.
+
+The most general way to create a file within a debugfs directory is with:
+
+    struct dentry *debugfs_create_file(const char *name, mode_t mode,
+				       struct dentry *parent, void *data,
+				       const struct file_operations *fops);
+
+Here, name is the name of the file to create, mode describes the access
+permissions the file should have, parent indicates the directory which
+should hold the file, data will be stored in the i_private field of the
+resulting inode structure, and fops is a set of file operations which
+implement the file's behavior.  At a minimum, the read() and/or write()
+operations should be provided; others can be included as needed.  Again,
+the return value will be a dentry pointer to the created file, NULL for
+error, or ERR_PTR(-ENODEV) if debugfs support is missing.
+
+In a number of cases, the creation of a set of file operations is not
+actually necessary; the debugfs code provides a number of helper functions
+for simple situations.  Files containing a single integer value can be
+created with any of:
+
+    struct dentry *debugfs_create_u8(const char *name, mode_t mode,
+				     struct dentry *parent, u8 *value);
+    struct dentry *debugfs_create_u16(const char *name, mode_t mode,
+				      struct dentry *parent, u16 *value);
+    struct dentry *debugfs_create_u32(const char *name, mode_t mode,
+				      struct dentry *parent, u32 *value);
+    struct dentry *debugfs_create_u64(const char *name, mode_t mode,
+				      struct dentry *parent, u64 *value);
+
+These files support both reading and writing the given value; if a specific
+file should not be written to, simply set the mode bits accordingly.  The
+values in these files are in decimal; if hexadecimal is more appropriate,
+the following functions can be used instead:
+
+    struct dentry *debugfs_create_x8(const char *name, mode_t mode,
+				     struct dentry *parent, u8 *value);
+    struct dentry *debugfs_create_x16(const char *name, mode_t mode,
+				      struct dentry *parent, u16 *value);
+    struct dentry *debugfs_create_x32(const char *name, mode_t mode,
+				      struct dentry *parent, u32 *value);
+
+Note that there is no debugfs_create_x64().
+
+These functions are useful as long as the developer knows the size of the
+value to be exported.  Some types can have different widths on different
+architectures, though, complicating the situation somewhat.  There is a
+function meant to help out in one special case:
+
+    struct dentry *debugfs_create_size_t(const char *name, mode_t mode,
+				         struct dentry *parent, 
+					 size_t *value);
+
+As might be expected, this function will create a debugfs file to represent
+a variable of type size_t.
+
+Boolean values can be placed in debugfs with:
+
+    struct dentry *debugfs_create_bool(const char *name, mode_t mode,
+				       struct dentry *parent, u32 *value);
+
+A read on the resulting file will yield either Y (for non-zero values) or
+N, followed by a newline.  If written to, it will accept either upper- or
+lower-case values, or 1 or 0.  Any other input will be silently ignored.
+
+Finally, a block of arbitrary binary data can be exported with:
+
+    struct debugfs_blob_wrapper {
+	void *data;
+	unsigned long size;
+    };
+
+    struct dentry *debugfs_create_blob(const char *name, mode_t mode,
+				       struct dentry *parent,
+				       struct debugfs_blob_wrapper *blob);
+
+A read of this file will return the data pointed to by the
+debugfs_blob_wrapper structure.  Some drivers use "blobs" as a simple way
+to return several lines of (static) formatted text output.  This function
+can be used to export binary information, but there does not appear to be
+any code which does so in the mainline.  Note that all files created with
+debugfs_create_blob() are read-only.
+
+There are a couple of other directory-oriented helper functions:
+
+    struct dentry *debugfs_rename(struct dentry *old_dir, 
+    				  struct dentry *old_dentry,
+		                  struct dentry *new_dir, 
+				  const char *new_name);
+
+    struct dentry *debugfs_create_symlink(const char *name, 
+                                          struct dentry *parent,
+				      	  const char *target);
+
+A call to debugfs_rename() will give a new name to an existing debugfs
+file, possibly in a different directory.  The new_name must not exist prior
+to the call; the return value is old_dentry with updated information.
+Symbolic links can be created with debugfs_create_symlink().
+
+There is one important thing that all debugfs users must take into account:
+there is no automatic cleanup of any directories created in debugfs.  If a
+module is unloaded without explicitly removing debugfs entries, the result
+will be a lot of stale pointers and no end of highly antisocial behavior.
+So all debugfs users - at least those which can be built as modules - must
+be prepared to remove all files and directories they create there.  A file
+can be removed with:
+
+    void debugfs_remove(struct dentry *dentry);
+
+The dentry value can be NULL, in which case nothing will be removed.
+
+Once upon a time, debugfs users were required to remember the dentry
+pointer for every debugfs file they created so that all files could be
+cleaned up.  We live in more civilized times now, though, and debugfs users
+can call:
+
+    void debugfs_remove_recursive(struct dentry *dentry);
+
+If this function is passed a pointer for the dentry corresponding to the
+top-level directory, the entire hierarchy below that directory will be
+removed.
+
+Notes:
+	[1] http://lwn.net/Articles/309298/
diff --git a/Documentation/i2c/busses/i2c-ocores b/Documentation/i2c/busses/i2c-ocores
index cfcebb1..c269aaa 100644
--- a/Documentation/i2c/busses/i2c-ocores
+++ b/Documentation/i2c/busses/i2c-ocores
@@ -20,6 +20,8 @@
 dev.platform_data of the device should also point to a struct
 ocores_i2c_platform_data (see linux/i2c-ocores.h) describing the
 distance between registers and the input clock speed.
+There is also a possibility to attach a list of i2c_board_info which
+the i2c-ocores driver will add to the bus upon creation.
 
 E.G. something like:
 
@@ -36,9 +38,24 @@
 	},
 };
 
+/* optional board info */
+struct i2c_board_info ocores_i2c_board_info[] = {
+	{
+		I2C_BOARD_INFO("tsc2003", 0x48),
+		.platform_data = &tsc2003_platform_data,
+		.irq = TSC_IRQ
+	},
+	{
+		I2C_BOARD_INFO("adv7180", 0x42 >> 1),
+		.irq = ADV_IRQ
+	}
+};
+
 static struct ocores_i2c_platform_data myi2c_data = {
 	.regstep	= 2,		/* two bytes between registers */
 	.clock_khz	= 50000,	/* input clock of 50MHz */
+	.devices	= ocores_i2c_board_info, /* optional table of devices */
+	.num_devices	= ARRAY_SIZE(ocores_i2c_board_info), /* table size */
 };
 
 static struct platform_device myi2c = {
diff --git a/Documentation/ide/ide.txt b/Documentation/ide/ide.txt
index 0c78f4b..e77bebf 100644
--- a/Documentation/ide/ide.txt
+++ b/Documentation/ide/ide.txt
@@ -216,6 +216,8 @@
 
 * "noflush=[interface_number.device_number]" to disable flush requests
 
+* "nohpa=[interface_number.device_number]" to disable Host Protected Area
+
 * "noprobe=[interface_number.device_number]" to skip probing
 
 * "nowerr=[interface_number.device_number]" to ignore the WRERR_STAT bit
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 24d726f..5f66ba2 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -887,11 +887,8 @@
 
 	ide-core.nodma=	[HW] (E)IDE subsystem
 			Format: =0.0 to prevent dma on hda, =0.1 hdb =1.0 hdc
-			.vlb_clock .pci_clock .noflush .noprobe .nowerr .cdrom
-			.chs .ignore_cable are additional options
-			See Documentation/ide/ide.txt.
-
-	idebus=		[HW] (E)IDE subsystem - VLB/PCI bus speed
+			.vlb_clock .pci_clock .noflush .nohpa .noprobe .nowerr
+			.cdrom .chs .ignore_cable are additional options
 			See Documentation/ide/ide.txt.
 
 	ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem
diff --git a/Documentation/lguest/Makefile b/Documentation/lguest/Makefile
index 1f4f9e8..28c8cdf 100644
--- a/Documentation/lguest/Makefile
+++ b/Documentation/lguest/Makefile
@@ -1,6 +1,5 @@
 # This creates the demonstration utility "lguest" which runs a Linux guest.
-CFLAGS:=-Wall -Wmissing-declarations -Wmissing-prototypes -O3 -I../../include -I../../arch/x86/include -U_FORTIFY_SOURCE
-LDLIBS:=-lz
+CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -I../../include -I../../arch/x86/include -U_FORTIFY_SOURCE
 
 all: lguest
 
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
index d36fcc0..9ebcd6e 100644
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -16,6 +16,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
+#include <sys/eventfd.h>
 #include <fcntl.h>
 #include <stdbool.h>
 #include <errno.h>
@@ -59,7 +60,6 @@
 /*:*/
 
 #define PAGE_PRESENT 0x7 	/* Present, RW, Execute */
-#define NET_PEERNUM 1
 #define BRIDGE_PFX "bridge:"
 #ifndef SIOCBRADDIF
 #define SIOCBRADDIF	0x89a2		/* add interface to bridge      */
@@ -76,19 +76,12 @@
 	do { if (verbose) printf(args); } while(0)
 /*:*/
 
-/* File descriptors for the Waker. */
-struct {
-	int pipe[2];
-	int lguest_fd;
-} waker_fds;
-
 /* The pointer to the start of guest memory. */
 static void *guest_base;
 /* The maximum guest physical address allowed, and maximum possible. */
 static unsigned long guest_limit, guest_max;
-/* The pipe for signal hander to write to. */
-static int timeoutpipe[2];
-static unsigned int timeout_usec = 500;
+/* The /dev/lguest file descriptor. */
+static int lguest_fd;
 
 /* a per-cpu variable indicating whose vcpu is currently running */
 static unsigned int __thread cpu_id;
@@ -96,11 +89,6 @@
 /* This is our list of devices. */
 struct device_list
 {
-	/* Summary information about the devices in our list: ready to pass to
-	 * select() to ask which need servicing.*/
-	fd_set infds;
-	int max_infd;
-
 	/* Counter to assign interrupt numbers. */
 	unsigned int next_irq;
 
@@ -126,22 +114,21 @@
 	/* The linked-list pointer. */
 	struct device *next;
 
-	/* The this device's descriptor, as mapped into the Guest. */
+	/* The device's descriptor, as mapped into the Guest. */
 	struct lguest_device_desc *desc;
 
+	/* We can't trust desc values once Guest has booted: we use these. */
+	unsigned int feature_len;
+	unsigned int num_vq;
+
 	/* The name of this device, for --verbose. */
 	const char *name;
 
-	/* If handle_input is set, it wants to be called when this file
-	 * descriptor is ready. */
-	int fd;
-	bool (*handle_input)(int fd, struct device *me);
-
 	/* Any queues attached to this device */
 	struct virtqueue *vq;
 
-	/* Handle status being finalized (ie. feature bits stable). */
-	void (*ready)(struct device *me);
+	/* Is it operational */
+	bool running;
 
 	/* Device-specific data. */
 	void *priv;
@@ -164,22 +151,28 @@
 	/* Last available index we saw. */
 	u16 last_avail_idx;
 
-	/* The routine to call when the Guest pings us, or timeout. */
-	void (*handle_output)(int fd, struct virtqueue *me, bool timeout);
+	/* How many are used since we sent last irq? */
+	unsigned int pending_used;
 
-	/* Outstanding buffers */
-	unsigned int inflight;
+	/* Eventfd where Guest notifications arrive. */
+	int eventfd;
 
-	/* Is this blocked awaiting a timer? */
-	bool blocked;
+	/* Function for the thread which is servicing this virtqueue. */
+	void (*service)(struct virtqueue *vq);
+	pid_t thread;
 };
 
 /* Remember the arguments to the program so we can "reboot" */
 static char **main_args;
 
-/* Since guest is UP and we don't run at the same time, we don't need barriers.
- * But I include them in the code in case others copy it. */
-#define wmb()
+/* The original tty settings to restore on exit. */
+static struct termios orig_term;
+
+/* We have to be careful with barriers: our devices are all run in separate
+ * threads and so we need to make sure that changes visible to the Guest happen
+ * in precise order. */
+#define wmb() __asm__ __volatile__("" : : : "memory")
+#define mb() __asm__ __volatile__("" : : : "memory")
 
 /* Convert an iovec element to the given type.
  *
@@ -245,7 +238,7 @@
 static u8 *get_feature_bits(struct device *dev)
 {
 	return (u8 *)(dev->desc + 1)
-		+ dev->desc->num_vq * sizeof(struct lguest_vqconfig);
+		+ dev->num_vq * sizeof(struct lguest_vqconfig);
 }
 
 /*L:100 The Launcher code itself takes us out into userspace, that scary place
@@ -505,99 +498,19 @@
  * saw the arguments it expects when we looked at initialize() in lguest_user.c:
  * the base of Guest "physical" memory, the top physical page to allow and the
  * entry point for the Guest. */
-static int tell_kernel(unsigned long start)
+static void tell_kernel(unsigned long start)
 {
 	unsigned long args[] = { LHREQ_INITIALIZE,
 				 (unsigned long)guest_base,
 				 guest_limit / getpagesize(), start };
-	int fd;
-
 	verbose("Guest: %p - %p (%#lx)\n",
 		guest_base, guest_base + guest_limit, guest_limit);
-	fd = open_or_die("/dev/lguest", O_RDWR);
-	if (write(fd, args, sizeof(args)) < 0)
+	lguest_fd = open_or_die("/dev/lguest", O_RDWR);
+	if (write(lguest_fd, args, sizeof(args)) < 0)
 		err(1, "Writing to /dev/lguest");
-
-	/* We return the /dev/lguest file descriptor to control this Guest */
-	return fd;
 }
 /*:*/
 
-static void add_device_fd(int fd)
-{
-	FD_SET(fd, &devices.infds);
-	if (fd > devices.max_infd)
-		devices.max_infd = fd;
-}
-
-/*L:200
- * The Waker.
- *
- * With console, block and network devices, we can have lots of input which we
- * need to process.  We could try to tell the kernel what file descriptors to
- * watch, but handing a file descriptor mask through to the kernel is fairly
- * icky.
- *
- * Instead, we clone off a thread which watches the file descriptors and writes
- * the LHREQ_BREAK command to the /dev/lguest file descriptor to tell the Host
- * stop running the Guest.  This causes the Launcher to return from the
- * /dev/lguest read with -EAGAIN, where it will write to /dev/lguest to reset
- * the LHREQ_BREAK and wake us up again.
- *
- * This, of course, is merely a different *kind* of icky.
- *
- * Given my well-known antipathy to threads, I'd prefer to use processes.  But
- * it's easier to share Guest memory with threads, and trivial to share the
- * devices.infds as the Launcher changes it.
- */
-static int waker(void *unused)
-{
-	/* Close the write end of the pipe: only the Launcher has it open. */
-	close(waker_fds.pipe[1]);
-
-	for (;;) {
-		fd_set rfds = devices.infds;
-		unsigned long args[] = { LHREQ_BREAK, 1 };
-		unsigned int maxfd = devices.max_infd;
-
-		/* We also listen to the pipe from the Launcher. */
-		FD_SET(waker_fds.pipe[0], &rfds);
-		if (waker_fds.pipe[0] > maxfd)
-			maxfd = waker_fds.pipe[0];
-
-		/* Wait until input is ready from one of the devices. */
-		select(maxfd+1, &rfds, NULL, NULL, NULL);
-
-		/* Message from Launcher? */
-		if (FD_ISSET(waker_fds.pipe[0], &rfds)) {
-			char c;
-			/* If this fails, then assume Launcher has exited.
-			 * Don't do anything on exit: we're just a thread! */
-			if (read(waker_fds.pipe[0], &c, 1) != 1)
-				_exit(0);
-			continue;
-		}
-
-		/* Send LHREQ_BREAK command to snap the Launcher out of it. */
-		pwrite(waker_fds.lguest_fd, args, sizeof(args), cpu_id);
-	}
-	return 0;
-}
-
-/* This routine just sets up a pipe to the Waker process. */
-static void setup_waker(int lguest_fd)
-{
-	/* This pipe is closed when Launcher dies, telling Waker. */
-	if (pipe(waker_fds.pipe) != 0)
-		err(1, "Creating pipe for Waker");
-
-	/* Waker also needs to know the lguest fd */
-	waker_fds.lguest_fd = lguest_fd;
-
-	if (clone(waker, malloc(4096) + 4096, CLONE_VM | SIGCHLD, NULL) == -1)
-		err(1, "Creating Waker");
-}
-
 /*
  * Device Handling.
  *
@@ -623,49 +536,90 @@
 /* Each buffer in the virtqueues is actually a chain of descriptors.  This
  * function returns the next descriptor in the chain, or vq->vring.num if we're
  * at the end. */
-static unsigned next_desc(struct virtqueue *vq, unsigned int i)
+static unsigned next_desc(struct vring_desc *desc,
+			  unsigned int i, unsigned int max)
 {
 	unsigned int next;
 
 	/* If this descriptor says it doesn't chain, we're done. */
-	if (!(vq->vring.desc[i].flags & VRING_DESC_F_NEXT))
-		return vq->vring.num;
+	if (!(desc[i].flags & VRING_DESC_F_NEXT))
+		return max;
 
 	/* Check they're not leading us off end of descriptors. */
-	next = vq->vring.desc[i].next;
+	next = desc[i].next;
 	/* Make sure compiler knows to grab that: we don't want it changing! */
 	wmb();
 
-	if (next >= vq->vring.num)
+	if (next >= max)
 		errx(1, "Desc next is %u", next);
 
 	return next;
 }
 
+/* This actually sends the interrupt for this virtqueue */
+static void trigger_irq(struct virtqueue *vq)
+{
+	unsigned long buf[] = { LHREQ_IRQ, vq->config.irq };
+
+	/* Don't inform them if nothing used. */
+	if (!vq->pending_used)
+		return;
+	vq->pending_used = 0;
+
+	/* If they don't want an interrupt, don't send one, unless empty. */
+	if ((vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
+	    && lg_last_avail(vq) != vq->vring.avail->idx)
+		return;
+
+	/* Send the Guest an interrupt tell them we used something up. */
+	if (write(lguest_fd, buf, sizeof(buf)) != 0)
+		err(1, "Triggering irq %i", vq->config.irq);
+}
+
 /* This looks in the virtqueue and for the first available buffer, and converts
  * it to an iovec for convenient access.  Since descriptors consist of some
  * number of output then some number of input descriptors, it's actually two
  * iovecs, but we pack them into one and note how many of each there were.
  *
- * This function returns the descriptor number found, or vq->vring.num (which
- * is never a valid descriptor number) if none was found. */
-static unsigned get_vq_desc(struct virtqueue *vq,
-			    struct iovec iov[],
-			    unsigned int *out_num, unsigned int *in_num)
+ * This function returns the descriptor number found. */
+static unsigned wait_for_vq_desc(struct virtqueue *vq,
+				 struct iovec iov[],
+				 unsigned int *out_num, unsigned int *in_num)
 {
-	unsigned int i, head;
-	u16 last_avail;
+	unsigned int i, head, max;
+	struct vring_desc *desc;
+	u16 last_avail = lg_last_avail(vq);
+
+	while (last_avail == vq->vring.avail->idx) {
+		u64 event;
+
+		/* OK, tell Guest about progress up to now. */
+		trigger_irq(vq);
+
+		/* OK, now we need to know about added descriptors. */
+		vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
+
+		/* They could have slipped one in as we were doing that: make
+		 * sure it's written, then check again. */
+		mb();
+		if (last_avail != vq->vring.avail->idx) {
+			vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
+			break;
+		}
+
+		/* Nothing new?  Wait for eventfd to tell us they refilled. */
+		if (read(vq->eventfd, &event, sizeof(event)) != sizeof(event))
+			errx(1, "Event read failed?");
+
+		/* We don't need to be notified again. */
+		vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
+	}
 
 	/* Check it isn't doing very strange things with descriptor numbers. */
-	last_avail = lg_last_avail(vq);
 	if ((u16)(vq->vring.avail->idx - last_avail) > vq->vring.num)
 		errx(1, "Guest moved used index from %u to %u",
 		     last_avail, vq->vring.avail->idx);
 
-	/* If there's nothing new since last we looked, return invalid. */
-	if (vq->vring.avail->idx == last_avail)
-		return vq->vring.num;
-
 	/* Grab the next descriptor number they're advertising, and increment
 	 * the index we've seen. */
 	head = vq->vring.avail->ring[last_avail % vq->vring.num];
@@ -678,15 +632,28 @@
 	/* When we start there are none of either input nor output. */
 	*out_num = *in_num = 0;
 
+	max = vq->vring.num;
+	desc = vq->vring.desc;
 	i = head;
+
+	/* If this is an indirect entry, then this buffer contains a descriptor
+	 * table which we handle as if it's any normal descriptor chain. */
+	if (desc[i].flags & VRING_DESC_F_INDIRECT) {
+		if (desc[i].len % sizeof(struct vring_desc))
+			errx(1, "Invalid size for indirect buffer table");
+
+		max = desc[i].len / sizeof(struct vring_desc);
+		desc = check_pointer(desc[i].addr, desc[i].len);
+		i = 0;
+	}
+
 	do {
 		/* Grab the first descriptor, and check it's OK. */
-		iov[*out_num + *in_num].iov_len = vq->vring.desc[i].len;
+		iov[*out_num + *in_num].iov_len = desc[i].len;
 		iov[*out_num + *in_num].iov_base
-			= check_pointer(vq->vring.desc[i].addr,
-					vq->vring.desc[i].len);
+			= check_pointer(desc[i].addr, desc[i].len);
 		/* If this is an input descriptor, increment that count. */
-		if (vq->vring.desc[i].flags & VRING_DESC_F_WRITE)
+		if (desc[i].flags & VRING_DESC_F_WRITE)
 			(*in_num)++;
 		else {
 			/* If it's an output descriptor, they're all supposed
@@ -697,11 +664,10 @@
 		}
 
 		/* If we've got too many, that implies a descriptor loop. */
-		if (*out_num + *in_num > vq->vring.num)
+		if (*out_num + *in_num > max)
 			errx(1, "Looped descriptor");
-	} while ((i = next_desc(vq, i)) != vq->vring.num);
+	} while ((i = next_desc(desc, i, max)) != max);
 
-	vq->inflight++;
 	return head;
 }
 
@@ -719,44 +685,20 @@
 	/* Make sure buffer is written before we update index. */
 	wmb();
 	vq->vring.used->idx++;
-	vq->inflight--;
-}
-
-/* This actually sends the interrupt for this virtqueue */
-static void trigger_irq(int fd, struct virtqueue *vq)
-{
-	unsigned long buf[] = { LHREQ_IRQ, vq->config.irq };
-
-	/* If they don't want an interrupt, don't send one, unless empty. */
-	if ((vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
-	    && vq->inflight)
-		return;
-
-	/* Send the Guest an interrupt tell them we used something up. */
-	if (write(fd, buf, sizeof(buf)) != 0)
-		err(1, "Triggering irq %i", vq->config.irq);
+	vq->pending_used++;
 }
 
 /* And here's the combo meal deal.  Supersize me! */
-static void add_used_and_trigger(int fd, struct virtqueue *vq,
-				 unsigned int head, int len)
+static void add_used_and_trigger(struct virtqueue *vq, unsigned head, int len)
 {
 	add_used(vq, head, len);
-	trigger_irq(fd, vq);
+	trigger_irq(vq);
 }
 
 /*
  * The Console
  *
- * Here is the input terminal setting we save, and the routine to restore them
- * on exit so the user gets their terminal back. */
-static struct termios orig_term;
-static void restore_term(void)
-{
-	tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
-}
-
-/* We associate some data with the console for our exit hack. */
+ * We associate some data with the console for our exit hack. */
 struct console_abort
 {
 	/* How many times have they hit ^C? */
@@ -766,276 +708,275 @@
 };
 
 /* This is the routine which handles console input (ie. stdin). */
-static bool handle_console_input(int fd, struct device *dev)
+static void console_input(struct virtqueue *vq)
 {
 	int len;
 	unsigned int head, in_num, out_num;
-	struct iovec iov[dev->vq->vring.num];
-	struct console_abort *abort = dev->priv;
+	struct console_abort *abort = vq->dev->priv;
+	struct iovec iov[vq->vring.num];
 
-	/* First we need a console buffer from the Guests's input virtqueue. */
-	head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
-
-	/* If they're not ready for input, stop listening to this file
-	 * descriptor.  We'll start again once they add an input buffer. */
-	if (head == dev->vq->vring.num)
-		return false;
-
+	/* Make sure there's a descriptor waiting. */
+	head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
 	if (out_num)
 		errx(1, "Output buffers in console in queue?");
 
-	/* This is why we convert to iovecs: the readv() call uses them, and so
-	 * it reads straight into the Guest's buffer. */
-	len = readv(dev->fd, iov, in_num);
+	/* Read it in. */
+	len = readv(STDIN_FILENO, iov, in_num);
 	if (len <= 0) {
-		/* This implies that the console is closed, is /dev/null, or
-		 * something went terribly wrong. */
+		/* Ran out of input? */
 		warnx("Failed to get console input, ignoring console.");
-		/* Put the input terminal back. */
-		restore_term();
-		/* Remove callback from input vq, so it doesn't restart us. */
-		dev->vq->handle_output = NULL;
-		/* Stop listening to this fd: don't call us again. */
-		return false;
+		/* For simplicity, dying threads kill the whole Launcher.  So
+		 * just nap here. */
+		for (;;)
+			pause();
 	}
 
-	/* Tell the Guest about the new input. */
-	add_used_and_trigger(fd, dev->vq, head, len);
+	add_used_and_trigger(vq, head, len);
 
 	/* Three ^C within one second?  Exit.
 	 *
-	 * This is such a hack, but works surprisingly well.  Each ^C has to be
-	 * in a buffer by itself, so they can't be too fast.  But we check that
-	 * we get three within about a second, so they can't be too slow. */
-	if (len == 1 && ((char *)iov[0].iov_base)[0] == 3) {
-		if (!abort->count++)
-			gettimeofday(&abort->start, NULL);
-		else if (abort->count == 3) {
-			struct timeval now;
-			gettimeofday(&now, NULL);
-			if (now.tv_sec <= abort->start.tv_sec+1) {
-				unsigned long args[] = { LHREQ_BREAK, 0 };
-				/* Close the fd so Waker will know it has to
-				 * exit. */
-				close(waker_fds.pipe[1]);
-				/* Just in case Waker is blocked in BREAK, send
-				 * unbreak now. */
-				write(fd, args, sizeof(args));
-				exit(2);
-			}
-			abort->count = 0;
-		}
-	} else
-		/* Any other key resets the abort counter. */
+	 * This is such a hack, but works surprisingly well.  Each ^C has to
+	 * be in a buffer by itself, so they can't be too fast.  But we check
+	 * that we get three within about a second, so they can't be too
+	 * slow. */
+	if (len != 1 || ((char *)iov[0].iov_base)[0] != 3) {
 		abort->count = 0;
+		return;
+	}
 
-	/* Everything went OK! */
-	return true;
-}
-
-/* Handling output for console is simple: we just get all the output buffers
- * and write them to stdout. */
-static void handle_console_output(int fd, struct virtqueue *vq, bool timeout)
-{
-	unsigned int head, out, in;
-	int len;
-	struct iovec iov[vq->vring.num];
-
-	/* Keep getting output buffers from the Guest until we run out. */
-	while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) {
-		if (in)
-			errx(1, "Input buffers in output queue?");
-		len = writev(STDOUT_FILENO, iov, out);
-		add_used_and_trigger(fd, vq, head, len);
+	abort->count++;
+	if (abort->count == 1)
+		gettimeofday(&abort->start, NULL);
+	else if (abort->count == 3) {
+		struct timeval now;
+		gettimeofday(&now, NULL);
+		/* Kill all Launcher processes with SIGINT, like normal ^C */
+		if (now.tv_sec <= abort->start.tv_sec+1)
+			kill(0, SIGINT);
+		abort->count = 0;
 	}
 }
 
-/* This is called when we no longer want to hear about Guest changes to a
- * virtqueue.  This is more efficient in high-traffic cases, but it means we
- * have to set a timer to check if any more changes have occurred. */
-static void block_vq(struct virtqueue *vq)
+/* This is the routine which handles console output (ie. stdout). */
+static void console_output(struct virtqueue *vq)
 {
-	struct itimerval itm;
+	unsigned int head, out, in;
+	struct iovec iov[vq->vring.num];
 
-	vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
-	vq->blocked = true;
-
-	itm.it_interval.tv_sec = 0;
-	itm.it_interval.tv_usec = 0;
-	itm.it_value.tv_sec = 0;
-	itm.it_value.tv_usec = timeout_usec;
-
-	setitimer(ITIMER_REAL, &itm, NULL);
+	head = wait_for_vq_desc(vq, iov, &out, &in);
+	if (in)
+		errx(1, "Input buffers in console output queue?");
+	while (!iov_empty(iov, out)) {
+		int len = writev(STDOUT_FILENO, iov, out);
+		if (len <= 0)
+			err(1, "Write to stdout gave %i", len);
+		iov_consume(iov, out, len);
+	}
+	add_used(vq, head, 0);
 }
 
 /*
  * The Network
  *
  * Handling output for network is also simple: we get all the output buffers
- * and write them (ignoring the first element) to this device's file descriptor
- * (/dev/net/tun).
+ * and write them to /dev/net/tun.
  */
-static void handle_net_output(int fd, struct virtqueue *vq, bool timeout)
+struct net_info {
+	int tunfd;
+};
+
+static void net_output(struct virtqueue *vq)
 {
-	unsigned int head, out, in, num = 0;
-	int len;
+	struct net_info *net_info = vq->dev->priv;
+	unsigned int head, out, in;
 	struct iovec iov[vq->vring.num];
-	static int last_timeout_num;
 
-	/* Keep getting output buffers from the Guest until we run out. */
-	while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) {
-		if (in)
-			errx(1, "Input buffers in output queue?");
-		len = writev(vq->dev->fd, iov, out);
-		if (len < 0)
-			err(1, "Writing network packet to tun");
-		add_used_and_trigger(fd, vq, head, len);
-		num++;
-	}
-
-	/* Block further kicks and set up a timer if we saw anything. */
-	if (!timeout && num)
-		block_vq(vq);
-
-	/* We never quite know how long should we wait before we check the
-	 * queue again for more packets.  We start at 500 microseconds, and if
-	 * we get fewer packets than last time, we assume we made the timeout
-	 * too small and increase it by 10 microseconds.  Otherwise, we drop it
-	 * by one microsecond every time.  It seems to work well enough. */
-	if (timeout) {
-		if (num < last_timeout_num)
-			timeout_usec += 10;
-		else if (timeout_usec > 1)
-			timeout_usec--;
-		last_timeout_num = num;
-	}
+	head = wait_for_vq_desc(vq, iov, &out, &in);
+	if (in)
+		errx(1, "Input buffers in net output queue?");
+	if (writev(net_info->tunfd, iov, out) < 0)
+		errx(1, "Write to tun failed?");
+	add_used(vq, head, 0);
 }
 
-/* This is where we handle a packet coming in from the tun device to our
+/* Will reading from this file descriptor block? */
+static bool will_block(int fd)
+{
+	fd_set fdset;
+	struct timeval zero = { 0, 0 };
+	FD_ZERO(&fdset);
+	FD_SET(fd, &fdset);
+	return select(fd+1, &fdset, NULL, NULL, &zero) != 1;
+}
+
+/* This is where we handle packets coming in from the tun device to our
  * Guest. */
-static bool handle_tun_input(int fd, struct device *dev)
+static void net_input(struct virtqueue *vq)
 {
-	unsigned int head, in_num, out_num;
 	int len;
-	struct iovec iov[dev->vq->vring.num];
+	unsigned int head, out, in;
+	struct iovec iov[vq->vring.num];
+	struct net_info *net_info = vq->dev->priv;
 
-	/* First we need a network buffer from the Guests's recv virtqueue. */
-	head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
-	if (head == dev->vq->vring.num) {
-		/* Now, it's expected that if we try to send a packet too
-		 * early, the Guest won't be ready yet.  Wait until the device
-		 * status says it's ready. */
-		/* FIXME: Actually want DRIVER_ACTIVE here. */
+	head = wait_for_vq_desc(vq, iov, &out, &in);
+	if (out)
+		errx(1, "Output buffers in net input queue?");
 
-		/* Now tell it we want to know if new things appear. */
-		dev->vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
-		wmb();
+	/* Deliver interrupt now, since we're about to sleep. */
+	if (vq->pending_used && will_block(net_info->tunfd))
+		trigger_irq(vq);
 
-		/* We'll turn this back on if input buffers are registered. */
-		return false;
-	} else if (out_num)
-		errx(1, "Output buffers in network recv queue?");
-
-	/* Read the packet from the device directly into the Guest's buffer. */
-	len = readv(dev->fd, iov, in_num);
+	len = readv(net_info->tunfd, iov, in);
 	if (len <= 0)
-		err(1, "reading network");
-
-	/* Tell the Guest about the new packet. */
-	add_used_and_trigger(fd, dev->vq, head, len);
-
-	verbose("tun input packet len %i [%02x %02x] (%s)\n", len,
-		((u8 *)iov[1].iov_base)[0], ((u8 *)iov[1].iov_base)[1],
-		head != dev->vq->vring.num ? "sent" : "discarded");
-
-	/* All good. */
-	return true;
+		err(1, "Failed to read from tun.");
+	add_used(vq, head, len);
 }
 
-/*L:215 This is the callback attached to the network and console input
- * virtqueues: it ensures we try again, in case we stopped console or net
- * delivery because Guest didn't have any buffers. */
-static void enable_fd(int fd, struct virtqueue *vq, bool timeout)
+/* This is the helper to create threads. */
+static int do_thread(void *_vq)
 {
-	add_device_fd(vq->dev->fd);
-	/* Snap the Waker out of its select loop. */
-	write(waker_fds.pipe[1], "", 1);
+	struct virtqueue *vq = _vq;
+
+	for (;;)
+		vq->service(vq);
+	return 0;
 }
 
-static void net_enable_fd(int fd, struct virtqueue *vq, bool timeout)
+/* When a child dies, we kill our entire process group with SIGTERM.  This
+ * also has the side effect that the shell restores the console for us! */
+static void kill_launcher(int signal)
 {
-	/* We don't need to know again when Guest refills receive buffer. */
-	vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
-	enable_fd(fd, vq, timeout);
+	kill(0, SIGTERM);
+}
+
+static void reset_device(struct device *dev)
+{
+	struct virtqueue *vq;
+
+	verbose("Resetting device %s\n", dev->name);
+
+	/* Clear any features they've acked. */
+	memset(get_feature_bits(dev) + dev->feature_len, 0, dev->feature_len);
+
+	/* We're going to be explicitly killing threads, so ignore them. */
+	signal(SIGCHLD, SIG_IGN);
+
+	/* Zero out the virtqueues, get rid of their threads */
+	for (vq = dev->vq; vq; vq = vq->next) {
+		if (vq->thread != (pid_t)-1) {
+			kill(vq->thread, SIGTERM);
+			waitpid(vq->thread, NULL, 0);
+			vq->thread = (pid_t)-1;
+		}
+		memset(vq->vring.desc, 0,
+		       vring_size(vq->config.num, LGUEST_VRING_ALIGN));
+		lg_last_avail(vq) = 0;
+	}
+	dev->running = false;
+
+	/* Now we care if threads die. */
+	signal(SIGCHLD, (void *)kill_launcher);
+}
+
+static void create_thread(struct virtqueue *vq)
+{
+	/* Create stack for thread and run it.  Since stack grows
+	 * upwards, we point the stack pointer to the end of this
+	 * region. */
+	char *stack = malloc(32768);
+	unsigned long args[] = { LHREQ_EVENTFD,
+				 vq->config.pfn*getpagesize(), 0 };
+
+	/* Create a zero-initialized eventfd. */
+	vq->eventfd = eventfd(0, 0);
+	if (vq->eventfd < 0)
+		err(1, "Creating eventfd");
+	args[2] = vq->eventfd;
+
+	/* Attach an eventfd to this virtqueue: it will go off
+	 * when the Guest does an LHCALL_NOTIFY for this vq. */
+	if (write(lguest_fd, &args, sizeof(args)) != 0)
+		err(1, "Attaching eventfd");
+
+	/* CLONE_VM: because it has to access the Guest memory, and
+	 * SIGCHLD so we get a signal if it dies. */
+	vq->thread = clone(do_thread, stack + 32768, CLONE_VM | SIGCHLD, vq);
+	if (vq->thread == (pid_t)-1)
+		err(1, "Creating clone");
+	/* We close our local copy, now the child has it. */
+	close(vq->eventfd);
+}
+
+static void start_device(struct device *dev)
+{
+	unsigned int i;
+	struct virtqueue *vq;
+
+	verbose("Device %s OK: offered", dev->name);
+	for (i = 0; i < dev->feature_len; i++)
+		verbose(" %02x", get_feature_bits(dev)[i]);
+	verbose(", accepted");
+	for (i = 0; i < dev->feature_len; i++)
+		verbose(" %02x", get_feature_bits(dev)
+			[dev->feature_len+i]);
+
+	for (vq = dev->vq; vq; vq = vq->next) {
+		if (vq->service)
+			create_thread(vq);
+	}
+	dev->running = true;
+}
+
+static void cleanup_devices(void)
+{
+	struct device *dev;
+
+	for (dev = devices.dev; dev; dev = dev->next)
+		reset_device(dev);
+
+	/* If we saved off the original terminal settings, restore them now. */
+	if (orig_term.c_lflag & (ISIG|ICANON|ECHO))
+		tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
 }
 
 /* When the Guest tells us they updated the status field, we handle it. */
 static void update_device_status(struct device *dev)
 {
-	struct virtqueue *vq;
-
-	/* This is a reset. */
-	if (dev->desc->status == 0) {
-		verbose("Resetting device %s\n", dev->name);
-
-		/* Clear any features they've acked. */
-		memset(get_feature_bits(dev) + dev->desc->feature_len, 0,
-		       dev->desc->feature_len);
-
-		/* Zero out the virtqueues. */
-		for (vq = dev->vq; vq; vq = vq->next) {
-			memset(vq->vring.desc, 0,
-			       vring_size(vq->config.num, LGUEST_VRING_ALIGN));
-			lg_last_avail(vq) = 0;
-		}
-	} else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
+	/* A zero status is a reset, otherwise it's a set of flags. */
+	if (dev->desc->status == 0)
+		reset_device(dev);
+	else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
 		warnx("Device %s configuration FAILED", dev->name);
+		if (dev->running)
+			reset_device(dev);
 	} else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {
-		unsigned int i;
-
-		verbose("Device %s OK: offered", dev->name);
-		for (i = 0; i < dev->desc->feature_len; i++)
-			verbose(" %02x", get_feature_bits(dev)[i]);
-		verbose(", accepted");
-		for (i = 0; i < dev->desc->feature_len; i++)
-			verbose(" %02x", get_feature_bits(dev)
-				[dev->desc->feature_len+i]);
-
-		if (dev->ready)
-			dev->ready(dev);
+		if (!dev->running)
+			start_device(dev);
 	}
 }
 
 /* This is the generic routine we call when the Guest uses LHCALL_NOTIFY. */
-static void handle_output(int fd, unsigned long addr)
+static void handle_output(unsigned long addr)
 {
 	struct device *i;
-	struct virtqueue *vq;
 
-	/* Check each device and virtqueue. */
+	/* Check each device. */
 	for (i = devices.dev; i; i = i->next) {
+		struct virtqueue *vq;
+
 		/* Notifications to device descriptors update device status. */
 		if (from_guest_phys(addr) == i->desc) {
 			update_device_status(i);
 			return;
 		}
 
-		/* Notifications to virtqueues mean output has occurred. */
+		/* Devices *can* be used before status is set to DRIVER_OK. */
 		for (vq = i->vq; vq; vq = vq->next) {
-			if (vq->config.pfn != addr/getpagesize())
+			if (addr != vq->config.pfn*getpagesize())
 				continue;
-
-			/* Guest should acknowledge (and set features!)  before
-			 * using the device. */
-			if (i->desc->status == 0) {
-				warnx("%s gave early output", i->name);
-				return;
-			}
-
-			if (strcmp(vq->dev->name, "console") != 0)
-				verbose("Output to %s\n", vq->dev->name);
-			if (vq->handle_output)
-				vq->handle_output(fd, vq, false);
+			if (i->running)
+				errx(1, "Notification on running %s", i->name);
+			start_device(i);
 			return;
 		}
 	}
@@ -1049,71 +990,6 @@
 	      strnlen(from_guest_phys(addr), guest_limit - addr));
 }
 
-static void handle_timeout(int fd)
-{
-	char buf[32];
-	struct device *i;
-	struct virtqueue *vq;
-
-	/* Clear the pipe */
-	read(timeoutpipe[0], buf, sizeof(buf));
-
-	/* Check each device and virtqueue: flush blocked ones. */
-	for (i = devices.dev; i; i = i->next) {
-		for (vq = i->vq; vq; vq = vq->next) {
-			if (!vq->blocked)
-				continue;
-
-			vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
-			vq->blocked = false;
-			if (vq->handle_output)
-				vq->handle_output(fd, vq, true);
-		}
-	}
-}
-
-/* This is called when the Waker wakes us up: check for incoming file
- * descriptors. */
-static void handle_input(int fd)
-{
-	/* select() wants a zeroed timeval to mean "don't wait". */
-	struct timeval poll = { .tv_sec = 0, .tv_usec = 0 };
-
-	for (;;) {
-		struct device *i;
-		fd_set fds = devices.infds;
-		int num;
-
-		num = select(devices.max_infd+1, &fds, NULL, NULL, &poll);
-		/* Could get interrupted */
-		if (num < 0)
-			continue;
-		/* If nothing is ready, we're done. */
-		if (num == 0)
-			break;
-
-		/* Otherwise, call the device(s) which have readable file
-		 * descriptors and a method of handling them.  */
-		for (i = devices.dev; i; i = i->next) {
-			if (i->handle_input && FD_ISSET(i->fd, &fds)) {
-				if (i->handle_input(fd, i))
-					continue;
-
-				/* If handle_input() returns false, it means we
-				 * should no longer service it.  Networking and
-				 * console do this when there's no input
-				 * buffers to deliver into.  Console also uses
-				 * it when it discovers that stdin is closed. */
-				FD_CLR(i->fd, &devices.infds);
-			}
-		}
-
-		/* Is this the timeout fd? */
-		if (FD_ISSET(timeoutpipe[0], &fds))
-			handle_timeout(fd);
-	}
-}
-
 /*L:190
  * Device Setup
  *
@@ -1129,8 +1005,8 @@
 static u8 *device_config(const struct device *dev)
 {
 	return (void *)(dev->desc + 1)
-		+ dev->desc->num_vq * sizeof(struct lguest_vqconfig)
-		+ dev->desc->feature_len * 2;
+		+ dev->num_vq * sizeof(struct lguest_vqconfig)
+		+ dev->feature_len * 2;
 }
 
 /* This routine allocates a new "struct lguest_device_desc" from descriptor
@@ -1159,7 +1035,7 @@
 /* Each device descriptor is followed by the description of its virtqueues.  We
  * specify how many descriptors the virtqueue is to have. */
 static void add_virtqueue(struct device *dev, unsigned int num_descs,
-			  void (*handle_output)(int, struct virtqueue *, bool))
+			  void (*service)(struct virtqueue *))
 {
 	unsigned int pages;
 	struct virtqueue **i, *vq = malloc(sizeof(*vq));
@@ -1174,8 +1050,8 @@
 	vq->next = NULL;
 	vq->last_avail_idx = 0;
 	vq->dev = dev;
-	vq->inflight = 0;
-	vq->blocked = false;
+	vq->service = service;
+	vq->thread = (pid_t)-1;
 
 	/* Initialize the configuration. */
 	vq->config.num = num_descs;
@@ -1191,6 +1067,7 @@
 	 * yet, otherwise we'd be overwriting them. */
 	assert(dev->desc->config_len == 0 && dev->desc->feature_len == 0);
 	memcpy(device_config(dev), &vq->config, sizeof(vq->config));
+	dev->num_vq++;
 	dev->desc->num_vq++;
 
 	verbose("Virtqueue page %#lx\n", to_guest_phys(p));
@@ -1199,15 +1076,6 @@
 	 * second.  */
 	for (i = &dev->vq; *i; i = &(*i)->next);
 	*i = vq;
-
-	/* Set the routine to call when the Guest does something to this
-	 * virtqueue. */
-	vq->handle_output = handle_output;
-
-	/* As an optimization, set the advisory "Don't Notify Me" flag if we
-	 * don't have a handler */
-	if (!handle_output)
-		vq->vring.used->flags = VRING_USED_F_NO_NOTIFY;
 }
 
 /* The first half of the feature bitmask is for us to advertise features.  The
@@ -1219,7 +1087,7 @@
 	/* We can't extend the feature bits once we've added config bytes */
 	if (dev->desc->feature_len <= bit / CHAR_BIT) {
 		assert(dev->desc->config_len == 0);
-		dev->desc->feature_len = (bit / CHAR_BIT) + 1;
+		dev->feature_len = dev->desc->feature_len = (bit/CHAR_BIT) + 1;
 	}
 
 	features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT));
@@ -1243,22 +1111,17 @@
  * calling new_dev_desc() to allocate the descriptor and device memory.
  *
  * See what I mean about userspace being boring? */
-static struct device *new_device(const char *name, u16 type, int fd,
-				 bool (*handle_input)(int, struct device *))
+static struct device *new_device(const char *name, u16 type)
 {
 	struct device *dev = malloc(sizeof(*dev));
 
 	/* Now we populate the fields one at a time. */
-	dev->fd = fd;
-	/* If we have an input handler for this file descriptor, then we add it
-	 * to the device_list's fdset and maxfd. */
-	if (handle_input)
-		add_device_fd(dev->fd);
 	dev->desc = new_dev_desc(type);
-	dev->handle_input = handle_input;
 	dev->name = name;
 	dev->vq = NULL;
-	dev->ready = NULL;
+	dev->feature_len = 0;
+	dev->num_vq = 0;
+	dev->running = false;
 
 	/* Append to device list.  Prepending to a single-linked list is
 	 * easier, but the user expects the devices to be arranged on the bus
@@ -1286,13 +1149,10 @@
 		 * raw input stream to the Guest. */
 		term.c_lflag &= ~(ISIG|ICANON|ECHO);
 		tcsetattr(STDIN_FILENO, TCSANOW, &term);
-		/* If we exit gracefully, the original settings will be
-		 * restored so the user can see what they're typing. */
-		atexit(restore_term);
 	}
 
-	dev = new_device("console", VIRTIO_ID_CONSOLE,
-			 STDIN_FILENO, handle_console_input);
+	dev = new_device("console", VIRTIO_ID_CONSOLE);
+
 	/* We store the console state in dev->priv, and initialize it. */
 	dev->priv = malloc(sizeof(struct console_abort));
 	((struct console_abort *)dev->priv)->count = 0;
@@ -1301,31 +1161,13 @@
 	 * they put something the input queue, we make sure we're listening to
 	 * stdin.  When they put something in the output queue, we write it to
 	 * stdout. */
-	add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd);
-	add_virtqueue(dev, VIRTQUEUE_NUM, handle_console_output);
+	add_virtqueue(dev, VIRTQUEUE_NUM, console_input);
+	add_virtqueue(dev, VIRTQUEUE_NUM, console_output);
 
-	verbose("device %u: console\n", devices.device_num++);
+	verbose("device %u: console\n", ++devices.device_num);
 }
 /*:*/
 
-static void timeout_alarm(int sig)
-{
-	write(timeoutpipe[1], "", 1);
-}
-
-static void setup_timeout(void)
-{
-	if (pipe(timeoutpipe) != 0)
-		err(1, "Creating timeout pipe");
-
-	if (fcntl(timeoutpipe[1], F_SETFL,
-		  fcntl(timeoutpipe[1], F_GETFL) | O_NONBLOCK) != 0)
-		err(1, "Making timeout pipe nonblocking");
-
-	add_device_fd(timeoutpipe[0]);
-	signal(SIGALRM, timeout_alarm);
-}
-
 /*M:010 Inter-guest networking is an interesting area.  Simplest is to have a
  * --sharenet=<name> option which opens or creates a named pipe.  This can be
  * used to send packets to another guest in a 1:1 manner.
@@ -1447,21 +1289,23 @@
 static void setup_tun_net(char *arg)
 {
 	struct device *dev;
-	int netfd, ipfd;
+	struct net_info *net_info = malloc(sizeof(*net_info));
+	int ipfd;
 	u32 ip = INADDR_ANY;
 	bool bridging = false;
 	char tapif[IFNAMSIZ], *p;
 	struct virtio_net_config conf;
 
-	netfd = get_tun_device(tapif);
+	net_info->tunfd = get_tun_device(tapif);
 
 	/* First we create a new network device. */
-	dev = new_device("net", VIRTIO_ID_NET, netfd, handle_tun_input);
+	dev = new_device("net", VIRTIO_ID_NET);
+	dev->priv = net_info;
 
 	/* Network devices need a receive and a send queue, just like
 	 * console. */
-	add_virtqueue(dev, VIRTQUEUE_NUM, net_enable_fd);
-	add_virtqueue(dev, VIRTQUEUE_NUM, handle_net_output);
+	add_virtqueue(dev, VIRTQUEUE_NUM, net_input);
+	add_virtqueue(dev, VIRTQUEUE_NUM, net_output);
 
 	/* We need a socket to perform the magic network ioctls to bring up the
 	 * tap interface, connect to the bridge etc.  Any socket will do! */
@@ -1502,6 +1346,8 @@
 	add_feature(dev, VIRTIO_NET_F_HOST_TSO4);
 	add_feature(dev, VIRTIO_NET_F_HOST_TSO6);
 	add_feature(dev, VIRTIO_NET_F_HOST_ECN);
+	/* We handle indirect ring entries */
+	add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC);
 	set_config(dev, sizeof(conf), &conf);
 
 	/* We don't need the socket any more; setup is done. */
@@ -1550,20 +1396,18 @@
  * Remember that the block device is handled by a separate I/O thread.  We head
  * straight into the core of that thread here:
  */
-static bool service_io(struct device *dev)
+static void blk_request(struct virtqueue *vq)
 {
-	struct vblk_info *vblk = dev->priv;
+	struct vblk_info *vblk = vq->dev->priv;
 	unsigned int head, out_num, in_num, wlen;
 	int ret;
 	u8 *in;
 	struct virtio_blk_outhdr *out;
-	struct iovec iov[dev->vq->vring.num];
+	struct iovec iov[vq->vring.num];
 	off64_t off;
 
-	/* See if there's a request waiting.  If not, nothing to do. */
-	head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
-	if (head == dev->vq->vring.num)
-		return false;
+	/* Get the next request. */
+	head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
 
 	/* Every block request should contain at least one output buffer
 	 * (detailing the location on disk and the type of request) and one
@@ -1637,83 +1481,21 @@
 	if (out->type & VIRTIO_BLK_T_BARRIER)
 		fdatasync(vblk->fd);
 
-	/* We can't trigger an IRQ, because we're not the Launcher.  It does
-	 * that when we tell it we're done. */
-	add_used(dev->vq, head, wlen);
-	return true;
-}
-
-/* This is the thread which actually services the I/O. */
-static int io_thread(void *_dev)
-{
-	struct device *dev = _dev;
-	struct vblk_info *vblk = dev->priv;
-	char c;
-
-	/* Close other side of workpipe so we get 0 read when main dies. */
-	close(vblk->workpipe[1]);
-	/* Close the other side of the done_fd pipe. */
-	close(dev->fd);
-
-	/* When this read fails, it means Launcher died, so we follow. */
-	while (read(vblk->workpipe[0], &c, 1) == 1) {
-		/* We acknowledge each request immediately to reduce latency,
-		 * rather than waiting until we've done them all.  I haven't
-		 * measured to see if it makes any difference.
-		 *
-		 * That would be an interesting test, wouldn't it?  You could
-		 * also try having more than one I/O thread. */
-		while (service_io(dev))
-			write(vblk->done_fd, &c, 1);
-	}
-	return 0;
-}
-
-/* Now we've seen the I/O thread, we return to the Launcher to see what happens
- * when that thread tells us it's completed some I/O. */
-static bool handle_io_finish(int fd, struct device *dev)
-{
-	char c;
-
-	/* If the I/O thread died, presumably it printed the error, so we
-	 * simply exit. */
-	if (read(dev->fd, &c, 1) != 1)
-		exit(1);
-
-	/* It did some work, so trigger the irq. */
-	trigger_irq(fd, dev->vq);
-	return true;
-}
-
-/* When the Guest submits some I/O, we just need to wake the I/O thread. */
-static void handle_virtblk_output(int fd, struct virtqueue *vq, bool timeout)
-{
-	struct vblk_info *vblk = vq->dev->priv;
-	char c = 0;
-
-	/* Wake up I/O thread and tell it to go to work! */
-	if (write(vblk->workpipe[1], &c, 1) != 1)
-		/* Presumably it indicated why it died. */
-		exit(1);
+	add_used(vq, head, wlen);
 }
 
 /*L:198 This actually sets up a virtual block device. */
 static void setup_block_file(const char *filename)
 {
-	int p[2];
 	struct device *dev;
 	struct vblk_info *vblk;
-	void *stack;
 	struct virtio_blk_config conf;
 
-	/* This is the pipe the I/O thread will use to tell us I/O is done. */
-	pipe(p);
-
 	/* The device responds to return from I/O thread. */
-	dev = new_device("block", VIRTIO_ID_BLOCK, p[0], handle_io_finish);
+	dev = new_device("block", VIRTIO_ID_BLOCK);
 
 	/* The device has one virtqueue, where the Guest places requests. */
-	add_virtqueue(dev, VIRTQUEUE_NUM, handle_virtblk_output);
+	add_virtqueue(dev, VIRTQUEUE_NUM, blk_request);
 
 	/* Allocate the room for our own bookkeeping */
 	vblk = dev->priv = malloc(sizeof(*vblk));
@@ -1735,49 +1517,29 @@
 
 	set_config(dev, sizeof(conf), &conf);
 
-	/* The I/O thread writes to this end of the pipe when done. */
-	vblk->done_fd = p[1];
-
-	/* This is the second pipe, which is how we tell the I/O thread about
-	 * more work. */
-	pipe(vblk->workpipe);
-
-	/* Create stack for thread and run it.  Since stack grows upwards, we
-	 * point the stack pointer to the end of this region. */
-	stack = malloc(32768);
-	/* SIGCHLD - We dont "wait" for our cloned thread, so prevent it from
-	 * becoming a zombie. */
-	if (clone(io_thread, stack + 32768, CLONE_VM | SIGCHLD, dev) == -1)
-		err(1, "Creating clone");
-
-	/* We don't need to keep the I/O thread's end of the pipes open. */
-	close(vblk->done_fd);
-	close(vblk->workpipe[0]);
-
 	verbose("device %u: virtblock %llu sectors\n",
-		devices.device_num, le64_to_cpu(conf.capacity));
+		++devices.device_num, le64_to_cpu(conf.capacity));
 }
 
+struct rng_info {
+	int rfd;
+};
+
 /* Our random number generator device reads from /dev/random into the Guest's
  * input buffers.  The usual case is that the Guest doesn't want random numbers
  * and so has no buffers although /dev/random is still readable, whereas
  * console is the reverse.
  *
  * The same logic applies, however. */
-static bool handle_rng_input(int fd, struct device *dev)
+static void rng_input(struct virtqueue *vq)
 {
 	int len;
 	unsigned int head, in_num, out_num, totlen = 0;
-	struct iovec iov[dev->vq->vring.num];
+	struct rng_info *rng_info = vq->dev->priv;
+	struct iovec iov[vq->vring.num];
 
 	/* First we need a buffer from the Guests's virtqueue. */
-	head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
-
-	/* If they're not ready for input, stop listening to this file
-	 * descriptor.  We'll start again once they add an input buffer. */
-	if (head == dev->vq->vring.num)
-		return false;
-
+	head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
 	if (out_num)
 		errx(1, "Output buffers in rng?");
 
@@ -1785,7 +1547,7 @@
 	 * it reads straight into the Guest's buffer.  We loop to make sure we
 	 * fill it. */
 	while (!iov_empty(iov, in_num)) {
-		len = readv(dev->fd, iov, in_num);
+		len = readv(rng_info->rfd, iov, in_num);
 		if (len <= 0)
 			err(1, "Read from /dev/random gave %i", len);
 		iov_consume(iov, in_num, len);
@@ -1793,25 +1555,23 @@
 	}
 
 	/* Tell the Guest about the new input. */
-	add_used_and_trigger(fd, dev->vq, head, totlen);
-
-	/* Everything went OK! */
-	return true;
+	add_used(vq, head, totlen);
 }
 
 /* And this creates a "hardware" random number device for the Guest. */
 static void setup_rng(void)
 {
 	struct device *dev;
-	int fd;
+	struct rng_info *rng_info = malloc(sizeof(*rng_info));
 
-	fd = open_or_die("/dev/random", O_RDONLY);
+	rng_info->rfd = open_or_die("/dev/random", O_RDONLY);
 
 	/* The device responds to return from I/O thread. */
-	dev = new_device("rng", VIRTIO_ID_RNG, fd, handle_rng_input);
+	dev = new_device("rng", VIRTIO_ID_RNG);
+	dev->priv = rng_info;
 
 	/* The device has one virtqueue, where the Guest places inbufs. */
-	add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd);
+	add_virtqueue(dev, VIRTQUEUE_NUM, rng_input);
 
 	verbose("device %u: rng\n", devices.device_num++);
 }
@@ -1827,17 +1587,18 @@
 	for (i = 3; i < FD_SETSIZE; i++)
 		close(i);
 
-	/* The exec automatically gets rid of the I/O and Waker threads. */
+	/* Reset all the devices (kills all threads). */
+	cleanup_devices();
+
 	execv(main_args[0], main_args);
 	err(1, "Could not exec %s", main_args[0]);
 }
 
 /*L:220 Finally we reach the core of the Launcher which runs the Guest, serves
  * its input and output, and finally, lays it to rest. */
-static void __attribute__((noreturn)) run_guest(int lguest_fd)
+static void __attribute__((noreturn)) run_guest(void)
 {
 	for (;;) {
-		unsigned long args[] = { LHREQ_BREAK, 0 };
 		unsigned long notify_addr;
 		int readval;
 
@@ -1848,8 +1609,7 @@
 		/* One unsigned long means the Guest did HCALL_NOTIFY */
 		if (readval == sizeof(notify_addr)) {
 			verbose("Notify on address %#lx\n", notify_addr);
-			handle_output(lguest_fd, notify_addr);
-			continue;
+			handle_output(notify_addr);
 		/* ENOENT means the Guest died.  Reading tells us why. */
 		} else if (errno == ENOENT) {
 			char reason[1024] = { 0 };
@@ -1858,19 +1618,9 @@
 		/* ERESTART means that we need to reboot the guest */
 		} else if (errno == ERESTART) {
 			restart_guest();
-		/* EAGAIN means a signal (timeout).
-		 * Anything else means a bug or incompatible change. */
-		} else if (errno != EAGAIN)
+		/* Anything else means a bug or incompatible change. */
+		} else
 			err(1, "Running guest failed");
-
-		/* Only service input on thread for CPU 0. */
-		if (cpu_id != 0)
-			continue;
-
-		/* Service input, then unset the BREAK to release the Waker. */
-		handle_input(lguest_fd);
-		if (pwrite(lguest_fd, args, sizeof(args), cpu_id) < 0)
-			err(1, "Resetting break");
 	}
 }
 /*L:240
@@ -1904,8 +1654,8 @@
 	/* Memory, top-level pagetable, code startpoint and size of the
 	 * (optional) initrd. */
 	unsigned long mem = 0, start, initrd_size = 0;
-	/* Two temporaries and the /dev/lguest file descriptor. */
-	int i, c, lguest_fd;
+	/* Two temporaries. */
+	int i, c;
 	/* The boot information for the Guest. */
 	struct boot_params *boot;
 	/* If they specify an initrd file to load. */
@@ -1913,18 +1663,10 @@
 
 	/* Save the args: we "reboot" by execing ourselves again. */
 	main_args = argv;
-	/* We don't "wait" for the children, so prevent them from becoming
-	 * zombies. */
-	signal(SIGCHLD, SIG_IGN);
 
-	/* First we initialize the device list.  Since console and network
-	 * device receive input from a file descriptor, we keep an fdset
-	 * (infds) and the maximum fd number (max_infd) with the head of the
-	 * list.  We also keep a pointer to the last device.  Finally, we keep
-	 * the next interrupt number to use for devices (1: remember that 0 is
-	 * used by the timer). */
-	FD_ZERO(&devices.infds);
-	devices.max_infd = -1;
+	/* First we initialize the device list.  We keep a pointer to the last
+	 * device, and the next interrupt number to use for devices (1:
+	 * remember that 0 is used by the timer). */
 	devices.lastdev = NULL;
 	devices.next_irq = 1;
 
@@ -1982,9 +1724,6 @@
 	/* We always have a console device */
 	setup_console();
 
-	/* We can timeout waiting for Guest network transmit. */
-	setup_timeout();
-
 	/* Now we load the kernel */
 	start = load_kernel(open_or_die(argv[optind+1], O_RDONLY));
 
@@ -2023,15 +1762,16 @@
 
 	/* We tell the kernel to initialize the Guest: this returns the open
 	 * /dev/lguest file descriptor. */
-	lguest_fd = tell_kernel(start);
+	tell_kernel(start);
 
-	/* We clone off a thread, which wakes the Launcher whenever one of the
-	 * input file descriptors needs attention.  We call this the Waker, and
-	 * we'll cover it in a moment. */
-	setup_waker(lguest_fd);
+	/* Ensure that we terminate if a child dies. */
+	signal(SIGCHLD, kill_launcher);
+
+	/* If we exit via err(), this kills all the threads, restores tty. */
+	atexit(cleanup_devices);
 
 	/* Finally, run the Guest.  This doesn't return. */
-	run_guest(lguest_fd);
+	run_guest();
 }
 /*:*/
 
diff --git a/Documentation/lguest/lguest.txt b/Documentation/lguest/lguest.txt
index 28c7473..efb3a6a 100644
--- a/Documentation/lguest/lguest.txt
+++ b/Documentation/lguest/lguest.txt
@@ -37,7 +37,6 @@
      "Paravirtualized guest support" = Y
         "Lguest guest support" = Y
      "High Memory Support" = off/4GB
-     "PAE (Physical Address Extension) Support" = N
      "Alignment value to which kernel should be aligned" = 0x100000
         (CONFIG_PARAVIRT=y, CONFIG_LGUEST_GUEST=y, CONFIG_HIGHMEM64G=n and
          CONFIG_PHYSICAL_ALIGN=0x100000)
diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
index 421e7d0..c9abbd8 100644
--- a/Documentation/power/devices.txt
+++ b/Documentation/power/devices.txt
@@ -75,9 +75,6 @@
 struct bus_type {
 	...
 	int  (*suspend)(struct device *dev, pm_message_t state);
-	int  (*suspend_late)(struct device *dev, pm_message_t state);
-
-	int  (*resume_early)(struct device *dev);
 	int  (*resume)(struct device *dev);
 };
 
@@ -226,20 +223,7 @@
 
 	This call should handle parts of device suspend logic that require
 	sleeping.  It probably does work to quiesce the device which hasn't
-	been abstracted into class.suspend() or bus.suspend_late().
-
-   3	bus.suspend_late(dev, message) is called with IRQs disabled, and
-	with only one CPU active.  Until the bus.resume_early() phase
-	completes (see later), IRQs are not enabled again.  This method
-	won't be exposed by all busses; for message based busses like USB,
-	I2C, or SPI, device interactions normally require IRQs.  This bus
-	call may be morphed into a driver call with bus-specific parameters.
-
-	This call might save low level hardware state that might otherwise
-	be lost in the upcoming low power state, and actually put the
-	device into a low power state ... so that in some cases the device
-	may stay partly usable until this late.  This "late" call may also
-	help when coping with hardware that behaves badly.
+	been abstracted into class.suspend().
 
 The pm_message_t parameter is currently used to refine those semantics
 (described later).
@@ -351,19 +335,11 @@
 
 The phases are seen by driver notifications issued in this order:
 
-   1	bus.resume_early(dev) is called with IRQs disabled, and with
-   	only one CPU active.  As with bus.suspend_late(), this method
-	won't be supported on busses that require IRQs in order to
-	interact with devices.
+   1	bus.resume(dev) reverses the effects of bus.suspend().  This may
+	be morphed into a device driver call with bus-specific parameters;
+	implementations may sleep.
 
-	This reverses the effects of bus.suspend_late().
-
-   2	bus.resume(dev) is called next.  This may be morphed into a device
-   	driver call with bus-specific parameters; implementations may sleep.
-
-	This reverses the effects of bus.suspend().
-
-   3	class.resume(dev) is called for devices associated with a class
+   2	class.resume(dev) is called for devices associated with a class
 	that has such a method.  Implementations may sleep.
 
 	This reverses the effects of class.suspend(), and would usually
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index ecb969b..4252697 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -460,6 +460,25 @@
 
     The power-management is supported.
 
+  Module snd-ctxfi
+  ----------------
+
+    Module for Creative Sound Blaster X-Fi boards (20k1 / 20k2 chips)
+	* Creative Sound Blaster X-Fi Titanium Fatal1ty Champion Series
+	* Creative Sound Blaster X-Fi Titanium Fatal1ty Professional Series
+	* Creative Sound Blaster X-Fi Titanium Professional Audio
+	* Creative Sound Blaster X-Fi Titanium
+	* Creative Sound Blaster X-Fi Elite Pro
+	* Creative Sound Blaster X-Fi Platinum
+	* Creative Sound Blaster X-Fi Fatal1ty
+	* Creative Sound Blaster X-Fi XtremeGamer
+	* Creative Sound Blaster X-Fi XtremeMusic
+
+    reference_rate	- reference sample rate, 44100 or 48000 (default)
+    multiple		- multiple to ref. sample rate, 1 or 2 (default)
+
+    This module supports multiple cards.
+
   Module snd-darla20
   ------------------
 
@@ -925,6 +944,7 @@
 			* Onkyo SE-90PCI
 			* Onkyo SE-200PCI
 			* ESI Juli@
+			* ESI Maya44
 			* Hercules Fortissimo IV
 			* EGO-SYS WaveTerminal 192M
 
@@ -933,7 +953,7 @@
 		  prodigy71xt, prodigy71hifi, prodigyhd2, prodigy192,
 		  juli, aureon51, aureon71, universe, ap192, k8x800,
 		  phase22, phase28, ms300, av710, se200pci, se90pci,
-		  fortissimo4, sn25p, WT192M
+		  fortissimo4, sn25p, WT192M, maya44
 
     This module supports multiple cards and autoprobe.
 
@@ -1093,6 +1113,13 @@
     This module supports multiple cards.
     The driver requires the firmware loader support on kernel.
 
+  Module snd-lx6464es
+  -------------------
+
+    Module for Digigram LX6464ES boards
+
+    This module supports multiple cards.
+
   Module snd-maestro3
   -------------------
 
@@ -1543,13 +1570,15 @@
   Module snd-sc6000
   -----------------
 
-    Module for Gallant SC-6000 soundcard.
+    Module for Gallant SC-6000 soundcard and later models: SC-6600
+    and SC-7000.
 
     port	- Port # (0x220 or 0x240)
     mss_port	- MSS Port # (0x530 or 0xe80)
     irq		- IRQ # (5,7,9,10,11)
     mpu_irq	- MPU-401 IRQ # (5,7,9,10) ,0 - no MPU-401 irq
     dma		- DMA # (1,3,0)
+    joystick	- Enable gameport - 0 = disable (default), 1 = enable
 
     This module supports multiple cards.
 
@@ -1859,7 +1888,8 @@
   -------------------
 
     Module for sound cards based on the Asus AV100/AV200 chips,
-    i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), and Essence STX.
+    i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), Essence ST
+    (Deluxe) and Essence STX.
 
     This module supports autoprobe and multiple cards.
 
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index 322869f..de8e10a 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -36,6 +36,7 @@
   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
@@ -85,10 +86,11 @@
   eeepc-p703	ASUS Eeepc P703 P900A
   eeepc-p901	ASUS Eeepc P901 S101
   fujitsu	FSC Amilo
+  lifebook	Fujitsu Lifebook S6420
   auto		auto-config reading BIOS (default)
 
-ALC662/663
-==========
+ALC662/663/272
+==============
   3stack-dig	3-stack (2-channel) with SPDIF
   3stack-6ch	 3-stack (6-channel)
   3stack-6ch-dig 3-stack (6-channel) with SPDIF
@@ -107,6 +109,9 @@
   asus-mode4	ASUS
   asus-mode5	ASUS
   asus-mode6	ASUS
+  dell		Dell with ALC272
+  dell-zm1	Dell ZM1 with ALC272
+  samsung-nc10	Samsung NC10 mini notebook
   auto		auto-config reading BIOS (default)
 
 ALC882/885
@@ -118,6 +123,7 @@
   asus-a7j	ASUS A7J
   asus-a7m	ASUS A7M
   macpro	MacPro support
+  mb5		Macbook 5,1
   mbp3		Macbook Pro rev3
   imac24	iMac 24'' with jack detection
   w2jc		ASUS W2JC
@@ -133,10 +139,12 @@
   acer		Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
   acer-aspire	Acer Aspire 9810
   acer-aspire-4930g Acer Aspire 4930G
+  acer-aspire-8930g Acer Aspire 8930G
   medion	Medion Laptops
   medion-md2	Medion MD2
   targa-dig	Targa/MSI
-  targa-2ch-dig	Targs/MSI with 2-channel
+  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
@@ -150,6 +158,9 @@
   fujitsu-pi2515 Fujitsu AMILO Pi2515
   fujitsu-xa3530 Fujitsu AMILO XA3530
   3stack-6ch-intel Intel DG33* boards
+  asus-p5q	ASUS P5Q-EM boards
+  mb31		MacBook 3,1
+  sony-vaio-tt  Sony VAIO TT
   auto		auto-config reading BIOS (default)
 
 ALC861/660
@@ -348,6 +359,7 @@
   hp-m4		HP mini 1000
   hp-dv5	HP dv series
   hp-hdx	HP HDX series
+  hp-dv4-1222nr	HP dv4-1222nr (with LED support)
   auto		BIOS setup (default)
 
 STAC92HD73*
diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt
index cfac20c..381908d 100644
--- a/Documentation/sound/alsa/Procfile.txt
+++ b/Documentation/sound/alsa/Procfile.txt
@@ -88,26 +88,34 @@
 	substreams, etc.
 
 card*/pcm*/xrun_debug
-	This file appears when CONFIG_SND_DEBUG=y.
-	This shows the status of xrun (= buffer overrun/xrun) debug of
-	ALSA PCM middle layer, as an integer from 0 to 2.  The value
-	can be changed by writing to this file, such as
+	This file appears when CONFIG_SND_DEBUG=y and
+	CONFIG_PCM_XRUN_DEBUG=y.
+	This shows the status of xrun (= buffer overrun/xrun) and
+	invalid PCM position debug/check of ALSA PCM middle layer.
+	It takes an integer value, can be changed by writing to this
+	file, such as
 
-		 # cat 2 > /proc/asound/card0/pcm0p/xrun_debug
+		 # cat 5 > /proc/asound/card0/pcm0p/xrun_debug
 
-	When this value is greater than 0, the driver will show the
-	messages to kernel log when an xrun is detected.  The debug
-	message is shown also when the invalid H/W pointer is detected
-	at the update of periods (usually called from the interrupt
+	The value consists of the following bit flags:
+	  bit 0 = Enable XRUN/jiffies debug messages
+	  bit 1 = Show stack trace at XRUN / jiffies check
+	  bit 2 = Enable additional jiffies check
+
+	When the bit 0 is set, the driver will show the messages to
+	kernel log when an xrun is detected.  The debug message is
+	shown also when the invalid H/W pointer is detected at the
+	update of periods (usually called from the interrupt
 	handler).
 
-	When this value is greater than 1, the driver will show the
-	stack trace additionally.  This may help the debugging.
+	When the bit 1 is set, the driver will show the stack trace
+	additionally.  This may help the debugging.
 
-	Since 2.6.30, this option also enables the hwptr check using
+	Since 2.6.30, this option can enable the hwptr check using
 	jiffies.  This detects spontaneous invalid pointer callback
 	values, but can be lead to too much corrections for a (mostly
 	buggy) hardware that doesn't give smooth pointer updates.
+	This feature is enabled via the bit 2.
 
 card*/pcm*/sub*/info
 	The general information of this PCM sub-stream.
diff --git a/Documentation/sound/alsa/README.maya44 b/Documentation/sound/alsa/README.maya44
new file mode 100644
index 0000000..0e41576
--- /dev/null
+++ b/Documentation/sound/alsa/README.maya44
@@ -0,0 +1,163 @@
+NOTE: The following is the original document of Rainer's patch that the
+current maya44 code based on.  Some contents might be obsoleted, but I
+keep here as reference -- tiwai
+
+----------------------------------------------------------------
+ 
+STATE OF DEVELOPMENT:
+
+This driver is being developed on the initiative of Piotr Makowski (oponek@gmail.com) and financed by Lars Bergmann.
+Development is carried out by Rainer Zimmermann (mail@lightshed.de).
+
+ESI provided a sample Maya44 card for the development work.
+
+However, unfortunately it has turned out difficult to get detailed programming information, so I (Rainer Zimmermann) had to find out some card-specific information by experiment and conjecture. Some information (in particular, several GPIO bits) is still missing.
+
+This is the first testing version of the Maya44 driver released to the alsa-devel mailing list (Feb 5, 2008).
+
+
+The following functions work, as tested by Rainer Zimmermann and Piotr Makowski:
+
+- playback and capture at all sampling rates
+- input/output level
+- crossmixing
+- line/mic switch
+- phantom power switch
+- analogue monitor a.k.a bypass
+
+
+The following functions *should* work, but are not fully tested:
+
+- Channel 3+4 analogue - S/PDIF input switching
+- S/PDIF output
+- all inputs/outputs on the M/IO/DIO extension card
+- internal/external clock selection
+
+
+*In particular, we would appreciate testing of these functions by anyone who has access to an M/IO/DIO extension card.*
+
+
+Things that do not seem to work:
+
+- The level meters ("multi track") in 'alsamixer' do not seem to react to signals in (if this is a bug, it would probably be in the existing ICE1724 code).
+
+- Ardour 2.1 seems to work only via JACK, not using ALSA directly or via OSS. This still needs to be tracked down.
+
+
+DRIVER DETAILS:
+
+the following files were added:
+
+pci/ice1724/maya44.c        - Maya44 specific code
+pci/ice1724/maya44.h
+pci/ice1724/ice1724.patch
+pci/ice1724/ice1724.h.patch - PROPOSED patch to ice1724.h (see SAMPLING RATES)
+i2c/other/wm8776.c  - low-level access routines for Wolfson WM8776 codecs 
+include/wm8776.h
+
+
+Note that the wm8776.c code is meant to be card-independent and does not actually register the codec with the ALSA infrastructure.
+This is done in maya44.c, mainly because some of the WM8776 controls are used in Maya44-specific ways, and should be named appropriately.
+
+
+the following files were created in pci/ice1724, simply #including the corresponding file from the alsa-kernel tree:
+
+wtm.h
+vt1720_mobo.h
+revo.h
+prodigy192.h
+pontis.h
+phase.h
+maya44.h
+juli.h
+aureon.h
+amp.h
+envy24ht.h
+se.h
+prodigy_hifi.h
+
+
+*I hope this is the correct way to do things.*
+
+
+SAMPLING RATES:
+
+The Maya44 card (or more exactly, the Wolfson WM8776 codecs) allow a maximum sampling rate of 192 kHz for playback and 92 kHz for capture.
+
+As the ICE1724 chip only allows one global sampling rate, this is handled as follows:
+
+* setting the sampling rate on any open PCM device on the maya44 card will always set the *global* sampling rate for all playback and capture channels.
+
+* In the current state of the driver, setting rates of up to 192 kHz is permitted even for capture devices.
+
+*AVOID CAPTURING AT RATES ABOVE 96kHz*, even though it may appear to work. The codec cannot actually capture at such rates, meaning poor quality.
+
+
+I propose some additional code for limiting the sampling rate when setting on a capture pcm device. However because of the global sampling rate, this logic would be somewhat problematic.
+
+The proposed code (currently deactivated) is in ice1712.h.patch, ice1724.c and maya44.c (in pci/ice1712).
+
+
+SOUND DEVICES:
+
+PCM devices correspond to inputs/outputs as follows (assuming Maya44 is card #0):
+
+hw:0,0 input - stereo, analog input 1+2
+hw:0,0 output - stereo, analog output 1+2
+hw:0,1 input - stereo, analog input 3+4 OR S/PDIF input
+hw:0,1 output - stereo, analog output 3+4 (and SPDIF out)
+
+
+NAMING OF MIXER CONTROLS:
+
+(for more information about the signal flow, please refer to the block diagram on p.24 of the ESI Maya44 manual, or in the ESI windows software).
+
+
+PCM: (digital) output level for channel 1+2
+PCM 1: same for channel 3+4
+
+Mic Phantom+48V: switch for +48V phantom power for electrostatic microphones on input 1/2.
+    Make sure this is not turned on while any other source is connected to input 1/2.
+    It might damage the source and/or the maya44 card.
+
+Mic/Line input: if switch is is on, input jack 1/2 is microphone input (mono), otherwise line input (stereo).
+
+Bypass: analogue bypass from ADC input to output for channel 1+2. Same as "Monitor" in the windows driver.
+Bypass 1: same for channel 3+4.
+
+Crossmix: cross-mixer from channels 1+2 to channels 3+4
+Crossmix 1: cross-mixer from channels 3+4 to channels 1+2
+
+IEC958 Output: switch for S/PDIF output.
+    This is not supported by the ESI windows driver.
+    S/PDIF should output the same signal as channel 3+4. [untested!]
+
+
+Digitial output selectors:
+
+    These switches allow a direct digital routing from the ADCs to the DACs.
+    Each switch determines where the digital input data to one of the DACs comes from.
+    They are not supported by the ESI windows driver.
+    For normal operation, they should all be set to "PCM out".
+
+H/W: Output source channel 1
+H/W 1: Output source channel 2
+H/W 2: Output source channel 3
+H/W 3: Output source channel 4
+
+H/W 4 ... H/W 9: unknown function, left in to enable testing.
+    Possibly some of these control S/PDIF output(s).
+    If these turn out to be unused, they will go away in later driver versions.
+
+Selectable values for each of the digital output selectors are:
+   "PCM out" -> DAC output of the corresponding channel (default setting)
+   "Input 1"...
+   "Input 4" -> direct routing from ADC output of the selected input channel
+
+
+--------
+
+Feb 14, 2008
+Rainer Zimmermann
+mail@lightshed.de
+
diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt
index 9e67632..9ac842b 100644
--- a/Documentation/sound/alsa/soc/dapm.txt
+++ b/Documentation/sound/alsa/soc/dapm.txt
@@ -62,6 +62,7 @@
  o Mic        - Mic (and optional Jack)
  o Line       - Line Input/Output (and optional Jack)
  o Speaker    - Speaker
+ o Supply     - Power or clock supply widget used by other widgets.
  o Pre        - Special PRE widget (exec before all others)
  o Post       - Special POST widget (exec after all others)
 
diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt
index 2db5893..29a6ff8 100644
--- a/Documentation/x86/x86_64/boot-options.txt
+++ b/Documentation/x86/x86_64/boot-options.txt
@@ -5,21 +5,51 @@
 
 Machine check
 
-   mce=off disable machine check
-   mce=bootlog Enable logging of machine checks left over from booting.
-               Disabled by default on AMD because some BIOS leave bogus ones.
-               If your BIOS doesn't do that it's a good idea to enable though
-               to make sure you log even machine check events that result
-               in a reboot. On Intel systems it is enabled by default.
+   Please see Documentation/x86/x86_64/machinecheck for sysfs runtime tunables.
+
+   mce=off
+		Disable machine check
+   mce=no_cmci
+		Disable CMCI(Corrected Machine Check Interrupt) that
+		Intel processor supports.  Usually this disablement is
+		not recommended, but it might be handy if your hardware
+		is misbehaving.
+		Note that you'll get more problems without CMCI than with
+		due to the shared banks, i.e. you might get duplicated
+		error logs.
+   mce=dont_log_ce
+		Don't make logs for corrected errors.  All events reported
+		as corrected are silently cleared by OS.
+		This option will be useful if you have no interest in any
+		of corrected errors.
+   mce=ignore_ce
+		Disable features for corrected errors, e.g. polling timer
+		and CMCI.  All events reported as corrected are not cleared
+		by OS and remained in its error banks.
+		Usually this disablement is not recommended, however if
+		there is an agent checking/clearing corrected errors
+		(e.g. BIOS or hardware monitoring applications), conflicting
+		with OS's error handling, and you cannot deactivate the agent,
+		then this option will be a help.
+   mce=bootlog
+		Enable logging of machine checks left over from booting.
+		Disabled by default on AMD because some BIOS leave bogus ones.
+		If your BIOS doesn't do that it's a good idea to enable though
+		to make sure you log even machine check events that result
+		in a reboot. On Intel systems it is enabled by default.
    mce=nobootlog
 		Disable boot machine check logging.
-   mce=tolerancelevel (number)
+   mce=tolerancelevel[,monarchtimeout] (number,number)
+		tolerance levels:
 		0: always panic on uncorrected errors, log corrected errors
 		1: panic or SIGBUS on uncorrected errors, log corrected errors
 		2: SIGBUS or log uncorrected errors, log corrected errors
 		3: never panic or SIGBUS, log all errors (for testing only)
 		Default is 1
 		Can be also set using sysfs which is preferable.
+		monarchtimeout:
+		Sets the time in us to wait for other CPUs on machine checks. 0
+		to disable.
 
    nomce (for compatibility with i386): same as mce=off
 
diff --git a/Documentation/x86/x86_64/machinecheck b/Documentation/x86/x86_64/machinecheck
index a05e58e..b1fb302 100644
--- a/Documentation/x86/x86_64/machinecheck
+++ b/Documentation/x86/x86_64/machinecheck
@@ -41,7 +41,9 @@
 	the polling interval.  When the poller stops finding MCEs, it
 	triggers an exponential backoff (poll less often) on the polling
 	interval. The check_interval variable is both the initial and
-	maximum polling interval.
+	maximum polling interval. 0 means no polling for corrected machine
+	check errors (but some corrected errors might be still reported
+	in other ways)
 
 tolerant
 	Tolerance level. When a machine check exception occurs for a non
@@ -67,6 +69,10 @@
 	Program to run when a machine check event is detected.
 	This is an alternative to running mcelog regularly from cron
 	and allows to detect events faster.
+monarch_timeout
+	How long to wait for the other CPUs to machine check too on a
+	exception. 0 to disable waiting for other CPUs.
+	Unit: us
 
 TBD document entries for AMD threshold interrupt configuration
 
diff --git a/MAINTAINERS b/MAINTAINERS
index 8f6b38d..9e28c5c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -681,6 +681,13 @@
 L:	linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 S:	Maintained
 
+ARM/H4700 (HP IPAQ HX4700) MACHINE SUPPORT
+P:	Philipp Zabel
+M:	philipp.zabel@gmail.com
+S:	Maintained
+F:	arch/arm/mach-pxa/hx4700.c
+F:	arch/arm/mach-pxa/include/mach/hx4700.h
+
 ARM/HP JORNADA 7XX MACHINE SUPPORT
 P:	Kristoffer Ericson
 M:	kristoffer.ericson@gmail.com
@@ -3363,6 +3370,16 @@
 F:	include/linux/kgdb.h
 F:	kernel/kgdb.c
 
+KMEMLEAK
+P:	Catalin Marinas
+M:	catalin.marinas@arm.com
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+F:	Documentation/kmemleak.txt
+F:	include/linux/kmemleak.h
+F:	mm/kmemleak.c
+F:	mm/kmemleak-test.c
+
 KMEMTRACE
 P:	Eduard - Gabriel Munteanu
 M:	eduard.munteanu@linux360.ro
@@ -3372,12 +3389,6 @@
 F:	include/trace/kmemtrace.h
 F:	kernel/trace/kmemtrace.c
 
-KMEMLEAK
-P:	Catalin Marinas
-M:	catalin.marinas@arm.com
-L:	linux-kernel@vger.kernel.org
-S:	Maintained
-
 KPROBES
 P:	Ananth N Mavinakayanahalli
 M:	ananth@in.ibm.com
@@ -4155,6 +4166,69 @@
 F:	drivers/video/riva/
 F:	drivers/video/nvidia/
 
+OMAP SUPPORT
+P:	Tony Lindgren <tony@atomide.com>
+M:	tony@atomide.com
+L:	linux-omap@vger.kernel.org
+W:	http://www.muru.com/linux/omap/
+W:	http://linux.omap.com/
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6.git
+S:	Maintained
+F:	arch/arm/*omap*
+
+OMAP CLOCK FRAMEWORK SUPPORT
+P:	Paul Walmsley
+M:	paul@pwsan.com
+L:	linux-omap@vger.kernel.org
+S:	Maintained
+F:	arch/arm/*omap*/*clock*
+
+OMAP POWER MANAGEMENT SUPPORT
+P:	Kevin Hilman
+M:	khilman@deeprootsystems.com
+L:	linux-omap@vger.kernel.org
+S:	Maintained
+F:	arch/arm/*omap*/*pm*
+
+OMAP AUDIO SUPPORT
+P:	Jarkko Nikula
+M:	jhnikula@gmail.com
+L:	alsa-devel@alsa-project.org (subscribers-only)
+L:	linux-omap@vger.kernel.org
+S:	Maintained
+F:	sound/soc/omap/
+
+OMAP FRAMEBUFFER SUPPORT
+P:	Imre Deak
+M:	imre.deak@nokia.com
+L:	linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
+L:	linux-omap@vger.kernel.org
+S:	Maintained
+F:	drivers/video/omap/
+
+OMAP MMC SUPPORT
+P:	Jarkko Lavinen
+M:	jarkko.lavinen@nokia.com
+L:	linux-kernel@vger.kernel.org
+L:	linux-omap@vger.kernel.org
+S:	Maintained
+F:	drivers/mmc/host/*omap*
+
+OMAP RANDOM NUMBER GENERATOR SUPPORT
+P:	Deepak Saxena
+M:	dsaxena@plexity.net
+S:	Maintained
+F:	drivers/char/hw_random/omap-rng.c
+
+OMAP USB SUPPORT
+P:	Felipe Balbi
+M:	felipe.balbi@nokia.com
+P:	David Brownell
+M:	dbrownell@users.sourceforge.net
+L:	linux-usb@vger.kernel.org
+L:	linux-omap@vger.kernel.org
+S:	Maintained
+
 OMFS FILESYSTEM
 P:	Bob Copeland
 M:	me@bobcopeland.com
@@ -4593,7 +4667,7 @@
 
 PXA2xx/PXA3xx SUPPORT
 P:	Eric Miao
-M:	eric.miao@marvell.com
+M:	eric.y.miao@gmail.com
 P:	Russell King
 M:	linux@arm.linux.org.uk
 L:	linux-arm-kernel@lists.arm.linux.org.uk	(subscribers-only)
@@ -4603,23 +4677,24 @@
 F:	drivers/spi/pxa2xx*
 F:	drivers/usb/gadget/pxa2*
 F:	include/sound/pxa2xx-lib.h
-F:	sound/soc/pxa/pxa2xx*
+F:	sound/arm/pxa*
+F:	sound/soc/pxa
 
 PXA168 SUPPORT
 P:	Eric Miao
-M:	eric.miao@marvell.com
+M:	eric.y.miao@gmail.com
 P:	Jason Chagas
 M:	jason.chagas@marvell.com
 L:	linux-arm-kernel@lists.arm.linux.org.uk	(subscribers-only)
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/ycmiao/pxa-linux-2.6.git
-S:	Supported
+S:	Maintained
 
 PXA910 SUPPORT
 P:	Eric Miao
-M:	eric.miao@marvell.com
+M:	eric.y.miao@gmail.com
 L:	linux-arm-kernel@lists.arm.linux.org.uk	(subscribers-only)
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/ycmiao/pxa-linux-2.6.git
-S:	Supported
+S:	Maintained
 
 PXA MMCI DRIVER
 S:	Orphan
@@ -5140,7 +5215,6 @@
 M:	support@simtec.co.uk
 W:	http://www.simtec.co.uk/products/EB110ATX/
 S:	Supported
-F:	arch/arm/mach-ebsa110/
 
 SIMTEC EB2410ITX (BAST)
 P:	Ben Dooks
@@ -5331,11 +5405,12 @@
 M:	lrg@slimlogic.co.uk
 P:	Mark Brown
 M:	broonie@opensource.wolfsonmicro.com
-T:	git git://opensource.wolfsonmicro.com/linux-2.6-asoc
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git
 L:	alsa-devel@alsa-project.org (subscribers-only)
 W:	http://alsa-project.org/main/index.php/ASoC
 S:	Supported
 F:	sound/soc/
+F:	include/sound/soc*
 
 SPARC + UltraSPARC (sparc/sparc64)
 P:	David S. Miller
@@ -5553,20 +5628,6 @@
 F:	drivers/mmc/host/tifm_sd.c
 F:	include/linux/tifm.h
 
-TI OMAP MMC INTERFACE DRIVER
-P:	Carlos Aguiar, Anderson Briglia and Syed Khasim
-M:	linux-omap@vger.kernel.org
-W:	http://linux.omap.com
-W:	http://www.muru.com/linux/omap/
-S:	Maintained
-F:	drivers/mmc/host/omap.c
-
-TI OMAP RANDOM NUMBER GENERATOR SUPPORT
-P:	Deepak Saxena
-M:	dsaxena@plexity.net
-S:	Maintained
-F:	drivers/char/hw_random/omap-rng.c
-
 TIPC NETWORK LAYER
 P:	Per Liden
 M:	per.liden@ericsson.com
diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h
index 62b3635..610dff4 100644
--- a/arch/alpha/include/asm/atomic.h
+++ b/arch/alpha/include/asm/atomic.h
@@ -256,5 +256,5 @@
 #define smp_mb__before_atomic_inc()	smp_mb()
 #define smp_mb__after_atomic_inc()	smp_mb()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* _ALPHA_ATOMIC_H */
diff --git a/arch/alpha/include/asm/bitsperlong.h b/arch/alpha/include/asm/bitsperlong.h
new file mode 100644
index 0000000..ad57f78
--- /dev/null
+++ b/arch/alpha/include/asm/bitsperlong.h
@@ -0,0 +1,8 @@
+#ifndef __ASM_ALPHA_BITSPERLONG_H
+#define __ASM_ALPHA_BITSPERLONG_H
+
+#define __BITS_PER_LONG 64
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_ALPHA_BITSPERLONG_H */
diff --git a/arch/alpha/include/asm/page.h b/arch/alpha/include/asm/page.h
index 0995f9d1..07af062 100644
--- a/arch/alpha/include/asm/page.h
+++ b/arch/alpha/include/asm/page.h
@@ -93,6 +93,6 @@
 					 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _ALPHA_PAGE_H */
diff --git a/arch/alpha/include/asm/signal.h b/arch/alpha/include/asm/signal.h
index 13c2305..a938830 100644
--- a/arch/alpha/include/asm/signal.h
+++ b/arch/alpha/include/asm/signal.h
@@ -111,7 +111,7 @@
 #define SIG_UNBLOCK        2	/* for unblocking signals */
 #define SIG_SETMASK        3	/* for setting the signal mask */
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct osf_sigaction {
diff --git a/arch/alpha/include/asm/suspend.h b/arch/alpha/include/asm/suspend.h
deleted file mode 100644
index c7042d5..0000000
--- a/arch/alpha/include/asm/suspend.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ALPHA_SUSPEND_H
-#define __ALPHA_SUSPEND_H
-
-/* Dummy include. */
-
-#endif  /* __ALPHA_SUSPEND_H */
diff --git a/arch/alpha/include/asm/types.h b/arch/alpha/include/asm/types.h
index f072f34..bd621ec 100644
--- a/arch/alpha/include/asm/types.h
+++ b/arch/alpha/include/asm/types.h
@@ -25,9 +25,6 @@
  * These aren't exported outside the kernel to avoid name space clashes
  */
 #ifdef __KERNEL__
-
-#define BITS_PER_LONG 64
-
 #ifndef __ASSEMBLY__
 
 typedef u64 dma_addr_t;
diff --git a/arch/alpha/mm/extable.c b/arch/alpha/mm/extable.c
index 62dc379..813c9b6 100644
--- a/arch/alpha/mm/extable.c
+++ b/arch/alpha/mm/extable.c
@@ -48,6 +48,27 @@
 	     cmp_ex, swap_ex);
 }
 
+#ifdef CONFIG_MODULES
+/*
+ * Any entry referring to the module init will be at the beginning or
+ * the end.
+ */
+void trim_init_extable(struct module *m)
+{
+	/*trim the beginning*/
+	while (m->num_exentries &&
+	       within_module_init(ex_to_addr(&m->extable[0]), m)) {
+		m->extable++;
+		m->num_exentries--;
+	}
+	/*trim the end*/
+	while (m->num_exentries &&
+	       within_module_init(ex_to_addr(&m->extable[m->num_exentries-1]),
+				  m))
+		m->num_exentries--;
+}
+#endif /* CONFIG_MODULES */
+
 const struct exception_table_entry *
 search_extable(const struct exception_table_entry *first,
 	       const struct exception_table_entry *last,
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9d02cdb..2947510 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -34,15 +34,12 @@
 
 config GENERIC_GPIO
 	bool
-	default n
 
 config GENERIC_TIME
 	bool
-	default n
 
 config GENERIC_CLOCKEVENTS
 	bool
-	default n
 
 config GENERIC_CLOCKEVENTS_BROADCAST
 	bool
@@ -55,7 +52,6 @@
 
 config NO_IOPORT
 	bool
-	default n
 
 config EISA
 	bool
@@ -126,11 +122,9 @@
 
 config ARCH_HAS_ILOG2_U32
 	bool
-	default n
 
 config ARCH_HAS_ILOG2_U64
 	bool
-	default n
 
 config GENERIC_HWEIGHT
 	bool
@@ -253,6 +247,14 @@
 	help
 	  Support for Cirrus Logic 711x/721x based boards.
 
+config ARCH_GEMINI
+	bool "Cortina Systems Gemini"
+	select CPU_FA526
+	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
+	help
+	  Support for the Cortina Systems Gemini family SoCs
+
 config ARCH_EBSA110
 	bool "EBSA-110"
 	select CPU_SA110
@@ -277,14 +279,6 @@
 	help
 	  This enables support for the Cirrus EP93xx series of CPUs.
 
-config ARCH_GEMINI
-	bool "Cortina Systems Gemini"
-	select CPU_FA526
-	select GENERIC_GPIO
-	select ARCH_REQUIRE_GPIOLIB
-	help
-	  Support for the Cortina Systems Gemini family SoCs
-
 config ARCH_FOOTBRIDGE
 	bool "FootBridge"
 	select CPU_SA110
@@ -293,6 +287,30 @@
 	  Support for systems based on the DC21285 companion chip
 	  ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder.
 
+config ARCH_MXC
+	bool "Freescale MXC/iMX-based"
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
+	select ARCH_MTD_XIP
+	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
+	select HAVE_CLK
+	help
+	  Support for Freescale MXC/iMX-based family of processors
+
+config ARCH_STMP3XXX
+	bool "Freescale STMP3xxx"
+	select CPU_ARM926T
+	select HAVE_CLK
+	select COMMON_CLKDEV
+	select ARCH_REQUIRE_GPIOLIB
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
+	select GENERIC_GPIO
+	select USB_ARCH_HAS_EHCI
+	help
+	  Support for systems based on the Freescale 3xxx CPUs.
+
 config ARCH_NETX
 	bool "Hilscher NetX based"
 	select CPU_ARM926T
@@ -309,15 +327,6 @@
 	help
 	  This enables support for systems based on the Hynix HMS720x
 
-config ARCH_IMX
-	bool "IMX"
-	select CPU_ARM920T
-	select GENERIC_GPIO
-	select GENERIC_TIME
-	select GENERIC_CLOCKEVENTS
-	help
-	  Support for Motorola's i.MX family of processors (MX1, MXL).
-
 config ARCH_IOP13XX
 	bool "IOP13xx-based"
 	depends on MMU
@@ -398,6 +407,7 @@
 	select CPU_FEROCEON
 	select PCI
 	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_TIME
 	select GENERIC_CLOCKEVENTS
 	select PLAT_ORION
@@ -405,6 +415,57 @@
 	  Support for the following Marvell Kirkwood series SoCs:
 	  88F6180, 88F6192 and 88F6281.
 
+config ARCH_LOKI
+	bool "Marvell Loki (88RC8480)"
+	select CPU_FEROCEON
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
+	select PLAT_ORION
+	help
+	  Support for the Marvell Loki (88RC8480) SoC.
+
+config ARCH_MV78XX0
+	bool "Marvell MV78xx0"
+	select CPU_FEROCEON
+	select PCI
+	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
+	select PLAT_ORION
+	help
+	  Support for the following Marvell MV78xx0 series SoCs:
+	  MV781x0, MV782x0.
+
+config ARCH_ORION5X
+	bool "Marvell Orion"
+	depends on MMU
+	select CPU_FEROCEON
+	select PCI
+	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
+	select PLAT_ORION
+	help
+	  Support for the following Marvell Orion 5x series SoCs:
+	  Orion-1 (5181), Orion-VoIP (5181L), Orion-NAS (5182),
+	  Orion-2 (5281), Orion-1-90 (6183).
+
+config ARCH_MMP
+	bool "Marvell PXA168/910"
+	depends on MMU
+	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
+	select HAVE_CLK
+	select COMMON_CLKDEV
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
+	select TICK_ONESHOT
+	select PLAT_PXA
+	help
+	  Support for Marvell's PXA168/910 processor line.
+
 config ARCH_KS8695
 	bool "Micrel/Kendin KS8695"
 	select CPU_ARM922T
@@ -427,51 +488,15 @@
 
 	  <http://www.digi.com/products/microprocessors/index.jsp>
 
-config ARCH_LOKI
-	bool "Marvell Loki (88RC8480)"
-	select CPU_FEROCEON
-	select GENERIC_TIME
-	select GENERIC_CLOCKEVENTS
-	select PLAT_ORION
-	help
-	  Support for the Marvell Loki (88RC8480) SoC.
-
-config ARCH_MV78XX0
-	bool "Marvell MV78xx0"
-	select CPU_FEROCEON
-	select PCI
-	select GENERIC_GPIO
-	select GENERIC_TIME
-	select GENERIC_CLOCKEVENTS
-	select PLAT_ORION
-	help
-	  Support for the following Marvell MV78xx0 series SoCs:
-	  MV781x0, MV782x0.
-
-config ARCH_MXC
-	bool "Freescale MXC/iMX-based"
-	select GENERIC_TIME
-	select GENERIC_CLOCKEVENTS
-	select ARCH_MTD_XIP
-	select GENERIC_GPIO
+config ARCH_W90X900
+	bool "Nuvoton W90X900 CPU"
+	select CPU_ARM926T
 	select ARCH_REQUIRE_GPIOLIB
-	select HAVE_CLK
-	help
-	  Support for Freescale MXC/iMX-based family of processors
-
-config ARCH_ORION5X
-	bool "Marvell Orion"
-	depends on MMU
-	select CPU_FEROCEON
-	select PCI
 	select GENERIC_GPIO
-	select GENERIC_TIME
-	select GENERIC_CLOCKEVENTS
-	select PLAT_ORION
+	select COMMON_CLKDEV
 	help
-	  Support for the following Marvell Orion 5x series SoCs:
-	  Orion-1 (5181), Orion-VoIP (5181L), Orion-NAS (5182),
-	  Orion-2 (5281), Orion-1-90 (6183).
+		Support for Nuvoton (Winbond logic dept.) ARM9 processor,You
+		can login www.mcuos.com or www.nuvoton.com to know more.
 
 config ARCH_PNX4008
 	bool "Philips Nexperia PNX4008 Mobile"
@@ -495,19 +520,16 @@
 	help
 	  Support for Intel/Marvell's PXA2xx/PXA3xx processor line.
 
-config ARCH_MMP
-	bool "Marvell PXA168/910"
-	depends on MMU
-	select GENERIC_GPIO
-	select ARCH_REQUIRE_GPIOLIB
-	select HAVE_CLK
-	select COMMON_CLKDEV
+config ARCH_MSM
+	bool "Qualcomm MSM"
+	select CPU_V6
 	select GENERIC_TIME
 	select GENERIC_CLOCKEVENTS
-	select TICK_ONESHOT
-	select PLAT_PXA
 	help
-	  Support for Marvell's PXA168/910 processor line.
+	  Support for Qualcomm MSM7K based systems.  This runs on the ARM11
+	  apps processor of the MSM7K and depends on a shared memory
+	  interface to the ARM9 modem processor which runs the baseband stack
+	  and controls some vital subsystems (clock and power control, etc).
 
 config ARCH_RPC
 	bool "RiscPC"
@@ -576,6 +598,20 @@
 	  core with a wide array of integrated devices for
 	  hand-held and low-power applications.
 
+config ARCH_U300
+	bool "ST-Ericsson U300 Series"
+	depends on MMU
+	select CPU_ARM926T
+	select ARM_AMBA
+	select ARM_VIC
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
+	select HAVE_CLK
+	select COMMON_CLKDEV
+	select GENERIC_GPIO
+	help
+	  Support for ST-Ericsson U300 series mobile platforms.
+
 config ARCH_DAVINCI
 	bool "TI DaVinci"
 	select CPU_ARM926T
@@ -587,6 +623,7 @@
 	select ZONE_DMA
 	select HAVE_IDE
 	select COMMON_CLKDEV
+	select GENERIC_ALLOCATOR
 	help
 	  Support for TI's DaVinci platform.
 
@@ -600,24 +637,6 @@
 	help
 	  Support for TI's OMAP platform (OMAP1 and OMAP2).
 
-config ARCH_MSM
-	bool "Qualcomm MSM"
-	select CPU_V6
-	select GENERIC_TIME
-	select GENERIC_CLOCKEVENTS
-	help
-	  Support for Qualcomm MSM7K based systems.  This runs on the ARM11
-	  apps processor of the MSM7K and depends on a shared memory
-	  interface to the ARM9 modem processor which runs the baseband stack
-	  and controls some vital subsystems (clock and power control, etc).
-
-config ARCH_W90X900
-	bool "Nuvoton W90X900 CPU"
-	select CPU_ARM926T
-	help
-		Support for Nuvoton (Winbond logic dept.) ARM9 processor,You
-		can login www.mcuos.com or www.nuvoton.com to know more.
-
 endchoice
 
 source "arch/arm/mach-clps711x/Kconfig"
@@ -681,9 +700,9 @@
 source "arch/arm/mach-s3c6410/Kconfig"
 endif
 
-source "arch/arm/mach-lh7a40x/Kconfig"
+source "arch/arm/plat-stmp3xxx/Kconfig"
 
-source "arch/arm/mach-imx/Kconfig"
+source "arch/arm/mach-lh7a40x/Kconfig"
 
 source "arch/arm/mach-h720x/Kconfig"
 
@@ -707,6 +726,8 @@
 
 source "arch/arm/mach-msm/Kconfig"
 
+source "arch/arm/mach-u300/Kconfig"
+
 source "arch/arm/mach-w90x900/Kconfig"
 
 # Definitions to make life easier
@@ -859,8 +880,11 @@
 
 config SMP
 	bool "Symmetric Multi-Processing (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP)
+	depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP ||\
+		 MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4)
+	depends on GENERIC_CLOCKEVENTS
 	select USE_GENERIC_SMP_HELPERS
+	select HAVE_ARM_SCU if (ARCH_REALVIEW || ARCH_OMAP4)
 	help
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, like most personal computers, say N. If
@@ -878,6 +902,18 @@
 
 	  If you don't know what to do here, say N.
 
+config HAVE_ARM_SCU
+	bool
+	depends on SMP
+	help
+	  This option enables support for the ARM system coherency unit
+
+config HAVE_ARM_TWD
+	bool
+	depends on SMP
+	help
+	  This options enables support for the ARM timer and watchdog unit
+
 choice
 	prompt "Memory split"
 	default VMSPLIT_3G
@@ -916,8 +952,10 @@
 
 config LOCAL_TIMERS
 	bool "Use local timer interrupts"
-	depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || REALVIEW_EB_A9MP)
+	depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || \
+		REALVIEW_EB_A9MP || MACH_REALVIEW_PBX || ARCH_OMAP4)
 	default y
+	select HAVE_ARM_TWD if (ARCH_REALVIEW || ARCH_OMAP4)
 	help
 	  Enable support for local timers on SMP platforms, rather then the
 	  legacy IPI broadcast method.  Local timers allows the system
@@ -979,7 +1017,6 @@
 
 config ARCH_HAS_HOLES_MEMORYMODEL
 	bool
-	default n
 
 # Discontigmem is deprecated
 config ARCH_DISCONTIGMEM_ENABLE
@@ -1022,12 +1059,12 @@
 config LEDS
 	bool "Timer and CPU usage LEDs"
 	depends on ARCH_CDB89712 || ARCH_EBSA110 || \
-		   ARCH_EBSA285 || ARCH_IMX || ARCH_INTEGRATOR || \
+		   ARCH_EBSA285 || ARCH_INTEGRATOR || \
 		   ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_NETWINDER || \
 		   ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \
 		   ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \
 		   ARCH_AT91 || ARCH_DAVINCI || \
-		   ARCH_KS8695 || MACH_RD88F5182
+		   ARCH_KS8695 || MACH_RD88F5182 || ARCH_REALVIEW
 	help
 	  If you say Y here, the LEDs on your machine will be used
 	  to provide useful information about your current system status.
@@ -1085,6 +1122,22 @@
 	  correct operation of some network protocols. With an IP-only
 	  configuration it is safe to say N, otherwise say Y.
 
+config UACCESS_WITH_MEMCPY
+	bool "Use kernel mem{cpy,set}() for {copy_to,clear}_user() (EXPERIMENTAL)"
+	depends on MMU && EXPERIMENTAL
+	default y if CPU_FEROCEON
+	help
+	  Implement faster copy_to_user and clear_user methods for CPU
+	  cores where a 8-word STM instruction give significantly higher
+	  memory write throughput than a sequence of individual 32bit stores.
+
+	  A possible side effect is a slight increase in scheduling latency
+	  between threads sharing the same address space if they invoke
+	  such copy operations with large buffers.
+
+	  However, if the CPU data cache is using a write-allocate mode,
+	  this option is unlikely to provide any performance gain.
+
 endmenu
 
 menu "Boot options"
@@ -1188,7 +1241,7 @@
 
 menu "CPU Power Management"
 
-if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA)
+if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_PXA)
 
 source "drivers/cpufreq/Kconfig"
 
@@ -1213,14 +1266,11 @@
 
 	  If in doubt, say Y.
 
-config CPU_FREQ_IMX
-	tristate "CPUfreq driver for i.MX CPUs"
-	depends on ARCH_IMX && CPU_FREQ
-	default n
-	help
-	  This enables the CPUfreq driver for i.MX CPUs.
-
-	  If in doubt, say N.
+config CPU_FREQ_PXA
+	bool
+	depends on CPU_FREQ && ARCH_PXA && PXA25x
+	default y
+	select CPU_FREQ_DEFAULT_GOV_USERSPACE
 
 endif
 
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index e84729b..c877d6d 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -11,6 +11,9 @@
 # Copyright (C) 1995-2001 by Russell King
 
 LDFLAGS_vmlinux	:=-p --no-undefined -X
+ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
+LDFLAGS_vmlinux	+= --be8
+endif
 CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
 OBJCOPYFLAGS	:=-O binary -R .note -R .note.gnu.build-id -R .comment -S
 GZFLAGS		:=-9
@@ -99,64 +102,73 @@
 #Default value
 head-y		:= arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
 textofs-y	:= 0x00008000
-
- machine-$(CONFIG_ARCH_RPC)	   := rpc
- machine-$(CONFIG_ARCH_EBSA110)	   := ebsa110
- machine-$(CONFIG_FOOTBRIDGE)	   := footbridge
- machine-$(CONFIG_ARCH_SHARK)	   := shark
- machine-$(CONFIG_ARCH_SA1100)	   := sa1100
-ifeq ($(CONFIG_ARCH_SA1100),y)
+textofs-$(CONFIG_ARCH_CLPS711X) := 0x00028000
 # SA1111 DMA bug: we don't want the kernel to live in precious DMA-able memory
- textofs-$(CONFIG_SA1111)	   := 0x00208000
+ifeq ($(CONFIG_ARCH_SA1100),y)
+textofs-$(CONFIG_SA1111) := 0x00208000
 endif
- machine-$(CONFIG_ARCH_PXA)	   := pxa
- machine-$(CONFIG_ARCH_MMP)	   := mmp
-    plat-$(CONFIG_PLAT_PXA)	   := pxa
- machine-$(CONFIG_ARCH_L7200)	   := l7200
- machine-$(CONFIG_ARCH_INTEGRATOR) := integrator
- machine-$(CONFIG_ARCH_GEMINI)     := gemini
- textofs-$(CONFIG_ARCH_CLPS711X)   := 0x00028000
- machine-$(CONFIG_ARCH_CLPS711X)   := clps711x
- machine-$(CONFIG_ARCH_IOP32X)	   := iop32x
- machine-$(CONFIG_ARCH_IOP33X)	   := iop33x
- machine-$(CONFIG_ARCH_IOP13XX)	   := iop13xx
-    plat-$(CONFIG_PLAT_IOP)	   := iop
- machine-$(CONFIG_ARCH_IXP4XX)	   := ixp4xx
- machine-$(CONFIG_ARCH_IXP2000)    := ixp2000
- machine-$(CONFIG_ARCH_IXP23XX)    := ixp23xx
- machine-$(CONFIG_ARCH_OMAP1)	   := omap1
- machine-$(CONFIG_ARCH_OMAP2)	   := omap2
- machine-$(CONFIG_ARCH_OMAP3)	   := omap2
-    plat-$(CONFIG_ARCH_OMAP)	   := omap
- machine-$(CONFIG_ARCH_S3C2410)	   := s3c2410 s3c2400 s3c2412 s3c2440 s3c2442 s3c2443
- machine-$(CONFIG_ARCH_S3C24A0)	   := s3c24a0
-    plat-$(CONFIG_PLAT_S3C24XX)	   := s3c24xx s3c
- machine-$(CONFIG_ARCH_S3C64XX)	   := s3c6400 s3c6410
-    plat-$(CONFIG_PLAT_S3C64XX)	   := s3c64xx s3c
- machine-$(CONFIG_ARCH_LH7A40X)	   := lh7a40x
- machine-$(CONFIG_ARCH_VERSATILE)  := versatile
- machine-$(CONFIG_ARCH_IMX)	   := imx
- machine-$(CONFIG_ARCH_H720X)	   := h720x
- machine-$(CONFIG_ARCH_AAEC2000)   := aaec2000
- machine-$(CONFIG_ARCH_REALVIEW)   := realview
- machine-$(CONFIG_ARCH_AT91)	   := at91
- machine-$(CONFIG_ARCH_EP93XX)	   := ep93xx
- machine-$(CONFIG_ARCH_PNX4008)	   := pnx4008
- machine-$(CONFIG_ARCH_NETX)	   := netx
- machine-$(CONFIG_ARCH_NS9XXX)	   := ns9xxx
- machine-$(CONFIG_ARCH_DAVINCI)	   := davinci
- machine-$(CONFIG_ARCH_KIRKWOOD)   := kirkwood
- machine-$(CONFIG_ARCH_KS8695)     := ks8695
-    plat-$(CONFIG_ARCH_MXC)	   := mxc
- machine-$(CONFIG_ARCH_MX2)	   := mx2
- machine-$(CONFIG_ARCH_MX3)	   := mx3
- machine-$(CONFIG_ARCH_MX1)	   := mx1
- machine-$(CONFIG_ARCH_ORION5X)	   := orion5x
-    plat-$(CONFIG_PLAT_ORION)	   := orion
- machine-$(CONFIG_ARCH_MSM)	   := msm
- machine-$(CONFIG_ARCH_LOKI)       := loki
- machine-$(CONFIG_ARCH_MV78XX0)    := mv78xx0
- machine-$(CONFIG_ARCH_W90X900)    := w90x900
+
+# Machine directory name.  This list is sorted alphanumerically
+# by CONFIG_* macro name.
+machine-$(CONFIG_ARCH_AAEC2000)		:= aaec2000
+machine-$(CONFIG_ARCH_AT91)		:= at91
+machine-$(CONFIG_ARCH_CLPS711X)		:= clps711x
+machine-$(CONFIG_ARCH_DAVINCI)		:= davinci
+machine-$(CONFIG_ARCH_EBSA110)		:= ebsa110
+machine-$(CONFIG_ARCH_EP93XX)		:= ep93xx
+machine-$(CONFIG_ARCH_GEMINI)		:= gemini
+machine-$(CONFIG_ARCH_H720X)		:= h720x
+machine-$(CONFIG_ARCH_INTEGRATOR)	:= integrator
+machine-$(CONFIG_ARCH_IOP13XX)		:= iop13xx
+machine-$(CONFIG_ARCH_IOP32X)		:= iop32x
+machine-$(CONFIG_ARCH_IOP33X)		:= iop33x
+machine-$(CONFIG_ARCH_IXP2000)		:= ixp2000
+machine-$(CONFIG_ARCH_IXP23XX)		:= ixp23xx
+machine-$(CONFIG_ARCH_IXP4XX)		:= ixp4xx
+machine-$(CONFIG_ARCH_KIRKWOOD)		:= kirkwood
+machine-$(CONFIG_ARCH_KS8695)		:= ks8695
+machine-$(CONFIG_ARCH_L7200)		:= l7200
+machine-$(CONFIG_ARCH_LH7A40X)		:= lh7a40x
+machine-$(CONFIG_ARCH_LOKI) 		:= loki
+machine-$(CONFIG_ARCH_MMP)		:= mmp
+machine-$(CONFIG_ARCH_MSM)		:= msm
+machine-$(CONFIG_ARCH_MV78XX0)		:= mv78xx0
+machine-$(CONFIG_ARCH_MX1)		:= mx1
+machine-$(CONFIG_ARCH_MX2)		:= mx2
+machine-$(CONFIG_ARCH_MX3)		:= mx3
+machine-$(CONFIG_ARCH_NETX)		:= netx
+machine-$(CONFIG_ARCH_NS9XXX)		:= ns9xxx
+machine-$(CONFIG_ARCH_OMAP1)		:= omap1
+machine-$(CONFIG_ARCH_OMAP2)		:= omap2
+machine-$(CONFIG_ARCH_OMAP3)		:= omap2
+machine-$(CONFIG_ARCH_OMAP4)		:= omap2
+machine-$(CONFIG_ARCH_ORION5X)		:= orion5x
+machine-$(CONFIG_ARCH_PNX4008)		:= pnx4008
+machine-$(CONFIG_ARCH_PXA)		:= pxa
+machine-$(CONFIG_ARCH_REALVIEW)		:= realview
+machine-$(CONFIG_ARCH_RPC)		:= rpc
+machine-$(CONFIG_ARCH_S3C2410)		:= s3c2410 s3c2400 s3c2412 s3c2440 s3c2442 s3c2443
+machine-$(CONFIG_ARCH_S3C24A0)		:= s3c24a0
+machine-$(CONFIG_ARCH_S3C64XX)		:= s3c6400 s3c6410
+machine-$(CONFIG_ARCH_SA1100)		:= sa1100
+machine-$(CONFIG_ARCH_SHARK)		:= shark
+machine-$(CONFIG_ARCH_STMP378X)		:= stmp378x
+machine-$(CONFIG_ARCH_STMP37XX)		:= stmp37xx
+machine-$(CONFIG_ARCH_U300)		:= u300
+machine-$(CONFIG_ARCH_VERSATILE)	:= versatile
+machine-$(CONFIG_ARCH_W90X900)		:= w90x900
+machine-$(CONFIG_FOOTBRIDGE)		:= footbridge
+
+# Platform directory name.  This list is sorted alphanumerically
+# by CONFIG_* macro name.
+plat-$(CONFIG_ARCH_MXC)		:= mxc
+plat-$(CONFIG_ARCH_OMAP)	:= omap
+plat-$(CONFIG_PLAT_IOP)		:= iop
+plat-$(CONFIG_PLAT_ORION)	:= orion
+plat-$(CONFIG_PLAT_PXA)		:= pxa
+plat-$(CONFIG_PLAT_S3C24XX)	:= s3c24xx s3c
+plat-$(CONFIG_PLAT_S3C64XX)	:= s3c64xx s3c
+plat-$(CONFIG_ARCH_STMP3XXX)	:= stmp3xxx
 
 ifeq ($(CONFIG_ARCH_EBSA110),y)
 # This is what happens if you forget the IOCS16 line.
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index fbe5eef..ce39dc5 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -40,7 +40,7 @@
 OBJS		+= head-sharpsl.o
 endif
 
-ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
+ifeq ($(CONFIG_CPU_ENDIAN_BE32),y)
 ifeq ($(CONFIG_CPU_CP15),y)
 OBJS		+= big-endian.o
 else
@@ -78,6 +78,9 @@
 # linker symbols.  We only define initrd_phys and params_phys if the
 # machine class defined the corresponding makefile variable.
 LDFLAGS_vmlinux := --defsym zreladdr=$(ZRELADDR)
+ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
+LDFLAGS_vmlinux += --be8
+endif
 ifneq ($(INITRD_PHYS),)
 LDFLAGS_vmlinux += --defsym initrd_phys=$(INITRD_PHYS)
 endif
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index b371fba..01d49be 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -438,6 +438,9 @@
 		mrc	p15, 0, r0, c1, c0, 0	@ read control reg
 		orr	r0, r0, #0x5000		@ I-cache enable, RR cache replacement
 		orr	r0, r0, #0x0030
+#ifdef CONFIG_CPU_ENDIAN_BE8
+		orr	r0, r0, #1 << 25	@ big-endian page tables
+#endif
 		bl	__common_mmu_cache_on
 		mov	r0, #0
 		mcr	p15, 0, r0, c8, c7, 0	@ flush I,D TLBs
@@ -455,6 +458,9 @@
 		mrc	p15, 0, r0, c1, c0, 0	@ read control reg
 		orr	r0, r0, #0x5000		@ I-cache enable, RR cache replacement
 		orr	r0, r0, #0x003c		@ write buffer
+#ifdef CONFIG_CPU_ENDIAN_BE8
+		orr	r0, r0, #1 << 25	@ big-endian page tables
+#endif
 		orrne	r0, r0, #1		@ MMU enabled
 		movne	r1, #-1
 		mcrne	p15, 0, r3, c2, c0, 0	@ load page table pointer
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index a2cd9be..4efbb9d 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -4,6 +4,14 @@
 config ARM_VIC
 	bool
 
+config ARM_VIC_NR
+	int
+	default 2
+	depends on ARM_VIC
+	help
+	  The maximum number of VICs available in the system, for
+	  power management.
+
 config ICST525
 	bool
 
@@ -27,10 +35,6 @@
 config SHARP_PARAM
 	bool
 
-config SHARPSL_PM
-	bool
-	select APM_EMULATION
-
 config SHARP_SCOOP
 	bool
 
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index 7cb7961..76be7ff 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -12,7 +12,6 @@
 obj-$(CONFIG_TIMER_ACORN)	+= time-acorn.o
 obj-$(CONFIG_SHARP_LOCOMO)	+= locomo.o
 obj-$(CONFIG_SHARP_PARAM)	+= sharpsl_param.o
-obj-$(CONFIG_SHARPSL_PM)	+= sharpsl_pm.o
 obj-$(CONFIG_SHARP_SCOOP)	+= scoop.o
 obj-$(CONFIG_ARCH_IXP2000)	+= uengine.o
 obj-$(CONFIG_ARCH_IXP23XX)	+= uengine.o
diff --git a/arch/arm/common/clkdev.c b/arch/arm/common/clkdev.c
index 5589444..f37afd9 100644
--- a/arch/arm/common/clkdev.c
+++ b/arch/arm/common/clkdev.c
@@ -135,6 +135,24 @@
 }
 EXPORT_SYMBOL(clkdev_alloc);
 
+int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
+	struct device *dev)
+{
+	struct clk *r = clk_get(dev, id);
+	struct clk_lookup *l;
+
+	if (IS_ERR(r))
+		return PTR_ERR(r);
+
+	l = clkdev_alloc(r, alias, alias_dev_name);
+	clk_put(r);
+	if (!l)
+		return -ENODEV;
+	clkdev_add(l);
+	return 0;
+}
+EXPORT_SYMBOL(clk_add_alias);
+
 /*
  * clkdev_drop - remove a clock dynamically allocated
  */
diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c
deleted file mode 100644
index 140f1d7..0000000
--- a/arch/arm/common/sharpsl_pm.c
+++ /dev/null
@@ -1,859 +0,0 @@
-/*
- * Battery and Power Management code for the Sharp SL-C7xx and SL-Cxx00
- * series of PDAs
- *
- * Copyright (c) 2004-2005 Richard Purdie
- *
- * Based on code written by Sharp for 2.4 kernels
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#undef DEBUG
-
-#include <linux/module.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/apm_bios.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/leds.h>
-#include <linux/apm-emulation.h>
-#include <linux/suspend.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <mach/pm.h>
-#include <mach/pxa2xx-regs.h>
-#include <mach/regs-rtc.h>
-#include <mach/sharpsl.h>
-#include <asm/hardware/sharpsl_pm.h>
-
-/*
- * Constants
- */
-#define SHARPSL_CHARGE_ON_TIME_INTERVAL        (msecs_to_jiffies(1*60*1000))  /* 1 min */
-#define SHARPSL_CHARGE_FINISH_TIME             (msecs_to_jiffies(10*60*1000)) /* 10 min */
-#define SHARPSL_BATCHK_TIME                    (msecs_to_jiffies(15*1000))    /* 15 sec */
-#define SHARPSL_BATCHK_TIME_SUSPEND            (60*10)                        /* 10 min */
-
-#define SHARPSL_WAIT_CO_TIME                   15  /* 15 sec */
-#define SHARPSL_WAIT_DISCHARGE_ON              100 /* 100 msec */
-#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP   10  /* 10 msec */
-#define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT   10  /* 10 msec */
-#define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN   10  /* 10 msec */
-#define SHARPSL_CHARGE_WAIT_TIME               15  /* 15 msec */
-#define SHARPSL_CHARGE_CO_CHECK_TIME           5   /* 5 msec */
-#define SHARPSL_CHARGE_RETRY_CNT               1   /* eqv. 10 min */
-
-/*
- * Prototypes
- */
-#ifdef CONFIG_PM
-static int sharpsl_off_charge_battery(void);
-static int sharpsl_check_battery_voltage(void);
-static int sharpsl_fatal_check(void);
-#endif
-static int sharpsl_check_battery_temp(void);
-static int sharpsl_ac_check(void);
-static int sharpsl_average_value(int ad);
-static void sharpsl_average_clear(void);
-static void sharpsl_charge_toggle(struct work_struct *private_);
-static void sharpsl_battery_thread(struct work_struct *private_);
-
-
-/*
- * Variables
- */
-struct sharpsl_pm_status sharpsl_pm;
-DECLARE_DELAYED_WORK(toggle_charger, sharpsl_charge_toggle);
-DECLARE_DELAYED_WORK(sharpsl_bat, sharpsl_battery_thread);
-DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger);
-
-
-static int get_percentage(int voltage)
-{
-	int i = sharpsl_pm.machinfo->bat_levels - 1;
-	int bl_status = sharpsl_pm.machinfo->backlight_get_status ? sharpsl_pm.machinfo->backlight_get_status() : 0;
-	struct battery_thresh *thresh;
-
-	if (sharpsl_pm.charge_mode == CHRG_ON)
-		thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_acin_bl : sharpsl_pm.machinfo->bat_levels_acin;
-	else
-		thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_noac_bl : sharpsl_pm.machinfo->bat_levels_noac;
-
-	while (i > 0 && (voltage > thresh[i].voltage))
-		i--;
-
-	return thresh[i].percentage;
-}
-
-static int get_apm_status(int voltage)
-{
-	int low_thresh, high_thresh;
-
-	if (sharpsl_pm.charge_mode == CHRG_ON) {
-		high_thresh = sharpsl_pm.machinfo->status_high_acin;
-		low_thresh = sharpsl_pm.machinfo->status_low_acin;
-	} else {
-		high_thresh = sharpsl_pm.machinfo->status_high_noac;
-		low_thresh = sharpsl_pm.machinfo->status_low_noac;
-	}
-
-	if (voltage >= high_thresh)
-		return APM_BATTERY_STATUS_HIGH;
-	if (voltage >= low_thresh)
-		return APM_BATTERY_STATUS_LOW;
-	return APM_BATTERY_STATUS_CRITICAL;
-}
-
-void sharpsl_battery_kick(void)
-{
-	schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125));
-}
-EXPORT_SYMBOL(sharpsl_battery_kick);
-
-
-static void sharpsl_battery_thread(struct work_struct *private_)
-{
-	int voltage, percent, apm_status, i = 0;
-
-	if (!sharpsl_pm.machinfo)
-		return;
-
-	sharpsl_pm.battstat.ac_status = (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN) ? APM_AC_ONLINE : APM_AC_OFFLINE);
-
-	/* Corgi cannot confirm when battery fully charged so periodically kick! */
-	if (!sharpsl_pm.machinfo->batfull_irq && (sharpsl_pm.charge_mode == CHRG_ON)
-			&& time_after(jiffies, sharpsl_pm.charge_start_time +  SHARPSL_CHARGE_ON_TIME_INTERVAL))
-		schedule_delayed_work(&toggle_charger, 0);
-
-	while(1) {
-		voltage = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
-
-		if (voltage > 0) break;
-		if (i++ > 5) {
-			voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage;
-			dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n");
-			break;
-		}
-	}
-
-	voltage = sharpsl_average_value(voltage);
-	apm_status = get_apm_status(voltage);
-	percent = get_percentage(voltage);
-
-	/* At low battery voltages, the voltage has a tendency to start
-           creeping back up so we try to avoid this here */
-	if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE) || (apm_status == APM_BATTERY_STATUS_HIGH) ||  percent <= sharpsl_pm.battstat.mainbat_percent) {
-		sharpsl_pm.battstat.mainbat_voltage = voltage;
-		sharpsl_pm.battstat.mainbat_status = apm_status;
-		sharpsl_pm.battstat.mainbat_percent = percent;
-	}
-
-	dev_dbg(sharpsl_pm.dev, "Battery: voltage: %d, status: %d, percentage: %d, time: %ld\n", voltage,
-			sharpsl_pm.battstat.mainbat_status, sharpsl_pm.battstat.mainbat_percent, jiffies);
-
-#ifdef CONFIG_BACKLIGHT_CORGI
-	/* If battery is low. limit backlight intensity to save power. */
-	if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)
-			&& ((sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_LOW) ||
-			(sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL))) {
-		if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) {
-			sharpsl_pm.machinfo->backlight_limit(1);
-			sharpsl_pm.flags |= SHARPSL_BL_LIMIT;
-		}
-	} else if (sharpsl_pm.flags & SHARPSL_BL_LIMIT) {
-		sharpsl_pm.machinfo->backlight_limit(0);
-		sharpsl_pm.flags &= ~SHARPSL_BL_LIMIT;
-	}
-#endif
-
-	/* Suspend if critical battery level */
-	if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)
-			&& (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL)
-			&& !(sharpsl_pm.flags & SHARPSL_APM_QUEUED)) {
-		sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
-		dev_err(sharpsl_pm.dev, "Fatal Off\n");
-		apm_queue_event(APM_CRITICAL_SUSPEND);
-	}
-
-	schedule_delayed_work(&sharpsl_bat, SHARPSL_BATCHK_TIME);
-}
-
-void sharpsl_pm_led(int val)
-{
-	if (val == SHARPSL_LED_ERROR) {
-		dev_err(sharpsl_pm.dev, "Charging Error!\n");
-	} else if (val == SHARPSL_LED_ON) {
-		dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
-		led_trigger_event(sharpsl_charge_led_trigger, LED_FULL);
-	} else {
-		dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
-		led_trigger_event(sharpsl_charge_led_trigger, LED_OFF);
-	}
-}
-
-static void sharpsl_charge_on(void)
-{
-	dev_dbg(sharpsl_pm.dev, "Turning Charger On\n");
-
-	sharpsl_pm.full_count = 0;
-	sharpsl_pm.charge_mode = CHRG_ON;
-	schedule_delayed_work(&toggle_charger, msecs_to_jiffies(250));
-	schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(500));
-}
-
-static void sharpsl_charge_off(void)
-{
-	dev_dbg(sharpsl_pm.dev, "Turning Charger Off\n");
-
-	sharpsl_pm.machinfo->charge(0);
-	sharpsl_pm_led(SHARPSL_LED_OFF);
-	sharpsl_pm.charge_mode = CHRG_OFF;
-
-	schedule_delayed_work(&sharpsl_bat, 0);
-}
-
-static void sharpsl_charge_error(void)
-{
-	sharpsl_pm_led(SHARPSL_LED_ERROR);
-	sharpsl_pm.machinfo->charge(0);
-	sharpsl_pm.charge_mode = CHRG_ERROR;
-}
-
-static void sharpsl_charge_toggle(struct work_struct *private_)
-{
-	dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies);
-
-	if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
-		sharpsl_charge_off();
-		return;
-	} else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) {
-		sharpsl_charge_error();
-		return;
-	}
-
-	sharpsl_pm_led(SHARPSL_LED_ON);
-	sharpsl_pm.machinfo->charge(0);
-	mdelay(SHARPSL_CHARGE_WAIT_TIME);
-	sharpsl_pm.machinfo->charge(1);
-
-	sharpsl_pm.charge_start_time = jiffies;
-}
-
-static void sharpsl_ac_timer(unsigned long data)
-{
-	int acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
-
-	dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin);
-
-	sharpsl_average_clear();
-	if (acin && (sharpsl_pm.charge_mode != CHRG_ON))
-		sharpsl_charge_on();
-	else if (sharpsl_pm.charge_mode == CHRG_ON)
-		sharpsl_charge_off();
-
-	schedule_delayed_work(&sharpsl_bat, 0);
-}
-
-
-irqreturn_t sharpsl_ac_isr(int irq, void *dev_id)
-{
-	/* Delay the event slightly to debounce */
-	/* Must be a smaller delay than the chrg_full_isr below */
-	mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
-
-	return IRQ_HANDLED;
-}
-
-static void sharpsl_chrg_full_timer(unsigned long data)
-{
-	dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies);
-
-	sharpsl_pm.full_count++;
-
-	if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
-		dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n");
-		if (sharpsl_pm.charge_mode == CHRG_ON)
-			sharpsl_charge_off();
-	} else if (sharpsl_pm.full_count < 2) {
-		dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n");
-		schedule_delayed_work(&toggle_charger, 0);
-	} else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) {
-		dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n");
-		schedule_delayed_work(&toggle_charger, 0);
-	} else {
-		sharpsl_charge_off();
-		sharpsl_pm.charge_mode = CHRG_DONE;
-		dev_dbg(sharpsl_pm.dev, "Charge Full: Charging Finished\n");
-	}
-}
-
-/* Charging Finished Interrupt (Not present on Corgi) */
-/* Can trigger at the same time as an AC status change so
-   delay until after that has been processed */
-irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id)
-{
-	if (sharpsl_pm.flags & SHARPSL_SUSPENDED)
-		return IRQ_HANDLED;
-
-	/* delay until after any ac interrupt */
-	mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500));
-
-	return IRQ_HANDLED;
-}
-
-irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id)
-{
-	int is_fatal = 0;
-
-	if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) {
-		dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n");
-		is_fatal = 1;
-	}
-
-	if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_FATAL)) {
-		dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n");
-		is_fatal = 1;
-	}
-
-	if (!(sharpsl_pm.flags & SHARPSL_APM_QUEUED) && is_fatal) {
-		sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
-		apm_queue_event(APM_CRITICAL_SUSPEND);
-	}
-
-	return IRQ_HANDLED;
-}
-
-/*
- * Maintain an average of the last 10 readings
- */
-#define SHARPSL_CNV_VALUE_NUM    10
-static int sharpsl_ad_index;
-
-static void sharpsl_average_clear(void)
-{
-	sharpsl_ad_index = 0;
-}
-
-static int sharpsl_average_value(int ad)
-{
-	int i, ad_val = 0;
-	static int sharpsl_ad[SHARPSL_CNV_VALUE_NUM+1];
-
-	if (sharpsl_pm.battstat.mainbat_status != APM_BATTERY_STATUS_HIGH) {
-		sharpsl_ad_index = 0;
-		return ad;
-	}
-
-	sharpsl_ad[sharpsl_ad_index] = ad;
-	sharpsl_ad_index++;
-	if (sharpsl_ad_index >= SHARPSL_CNV_VALUE_NUM) {
-		for (i=0; i < (SHARPSL_CNV_VALUE_NUM-1); i++)
-			sharpsl_ad[i] = sharpsl_ad[i+1];
-		sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1;
-	}
-	for (i=0; i < sharpsl_ad_index; i++)
-		ad_val += sharpsl_ad[i];
-
-	return (ad_val / sharpsl_ad_index);
-}
-
-/*
- * Take an array of 5 integers, remove the maximum and minimum values
- * and return the average.
- */
-static int get_select_val(int *val)
-{
-	int i, j, k, temp, sum = 0;
-
-	/* Find MAX val */
-	temp = val[0];
-	j=0;
-	for (i=1; i<5; i++) {
-		if (temp < val[i]) {
-			temp = val[i];
-			j = i;
-		}
-	}
-
-	/* Find MIN val */
-	temp = val[4];
-	k=4;
-	for (i=3; i>=0; i--) {
-		if (temp > val[i]) {
-			temp = val[i];
-			k = i;
-		}
-	}
-
-	for (i=0; i<5; i++)
-		if (i != j && i != k )
-			sum += val[i];
-
-	dev_dbg(sharpsl_pm.dev, "Average: %d from values: %d, %d, %d, %d, %d\n", sum/3, val[0], val[1], val[2], val[3], val[4]);
-
-	return (sum/3);
-}
-
-static int sharpsl_check_battery_temp(void)
-{
-	int val, i, buff[5];
-
-	/* Check battery temperature */
-	for (i=0; i<5; i++) {
-		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
-		sharpsl_pm.machinfo->measure_temp(1);
-		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
-		buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_TEMP);
-		sharpsl_pm.machinfo->measure_temp(0);
-	}
-
-	val = get_select_val(buff);
-
-	dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val);
-	if (val > sharpsl_pm.machinfo->charge_on_temp) {
-		printk(KERN_WARNING "Not charging: temperature out of limits.\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int sharpsl_check_battery_voltage(void)
-{
-	int val, i, buff[5];
-
-	/* disable charge, enable discharge */
-	sharpsl_pm.machinfo->charge(0);
-	sharpsl_pm.machinfo->discharge(1);
-	mdelay(SHARPSL_WAIT_DISCHARGE_ON);
-
-	if (sharpsl_pm.machinfo->discharge1)
-		sharpsl_pm.machinfo->discharge1(1);
-
-	/* Check battery voltage */
-	for (i=0; i<5; i++) {
-		buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
-		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
-	}
-
-	if (sharpsl_pm.machinfo->discharge1)
-		sharpsl_pm.machinfo->discharge1(0);
-
-	sharpsl_pm.machinfo->discharge(0);
-
-	val = get_select_val(buff);
-	dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val);
-
-	if (val < sharpsl_pm.machinfo->charge_on_volt)
-		return -1;
-
-	return 0;
-}
-#endif
-
-static int sharpsl_ac_check(void)
-{
-	int temp, i, buff[5];
-
-	for (i=0; i<5; i++) {
-		buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_ACIN_VOLT);
-		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN);
-	}
-
-	temp = get_select_val(buff);
-	dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp);
-
-	if ((temp > sharpsl_pm.machinfo->charge_acin_high) || (temp < sharpsl_pm.machinfo->charge_acin_low)) {
-		dev_err(sharpsl_pm.dev, "Error: AC check failed.\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state)
-{
-	sharpsl_pm.flags |= SHARPSL_SUSPENDED;
-	flush_scheduled_work();
-
-	if (sharpsl_pm.charge_mode == CHRG_ON)
-		sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
-	else
-		sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
-
-	return 0;
-}
-
-static int sharpsl_pm_resume(struct platform_device *pdev)
-{
-	/* Clear the reset source indicators as they break the bootloader upon reboot */
-	RCSR = 0x0f;
-	sharpsl_average_clear();
-	sharpsl_pm.flags &= ~SHARPSL_APM_QUEUED;
-	sharpsl_pm.flags &= ~SHARPSL_SUSPENDED;
-
-	return 0;
-}
-
-static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state)
-{
-	dev_dbg(sharpsl_pm.dev, "Time is: %08x\n",RCNR);
-
-	dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n",sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG);
-	/* not charging and AC-IN! */
-
-	if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN))) {
-		dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n");
-		sharpsl_pm.charge_mode = CHRG_OFF;
-		sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
-		sharpsl_off_charge_battery();
-	}
-
-	sharpsl_pm.machinfo->presuspend();
-
-	PEDR = 0xffffffff; /* clear it */
-
-	sharpsl_pm.flags &= ~SHARPSL_ALARM_ACTIVE;
-	if ((sharpsl_pm.charge_mode == CHRG_ON) && ((alarm_enable && ((alarm_time - RCNR) > (SHARPSL_BATCHK_TIME_SUSPEND + 30))) || !alarm_enable)) {
-		RTSR &= RTSR_ALE;
-		RTAR = RCNR + SHARPSL_BATCHK_TIME_SUSPEND;
-		dev_dbg(sharpsl_pm.dev, "Charging alarm at: %08x\n",RTAR);
-		sharpsl_pm.flags |= SHARPSL_ALARM_ACTIVE;
-	} else if (alarm_enable) {
-		RTSR &= RTSR_ALE;
-		RTAR = alarm_time;
-		dev_dbg(sharpsl_pm.dev, "User alarm at: %08x\n",RTAR);
-	} else {
-		dev_dbg(sharpsl_pm.dev, "No alarms set.\n");
-	}
-
-	pxa_pm_enter(state);
-
-	sharpsl_pm.machinfo->postsuspend();
-
-	dev_dbg(sharpsl_pm.dev, "Corgi woken up from suspend: %08x\n",PEDR);
-}
-
-static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state)
-{
-	if (!sharpsl_pm.machinfo->should_wakeup(!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE) && alarm_enable) )
-	{
-		if (!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE)) {
-			dev_dbg(sharpsl_pm.dev, "No user triggered wakeup events and not charging. Strange. Suspend.\n");
-			corgi_goto_sleep(alarm_time, alarm_enable, state);
-			return 1;
-		}
-		if(sharpsl_off_charge_battery()) {
-			dev_dbg(sharpsl_pm.dev, "Charging. Suspend...\n");
-			corgi_goto_sleep(alarm_time, alarm_enable, state);
-			return 1;
-		}
-		dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n");
-	}
-
-	if ((!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) || (sharpsl_fatal_check() < 0) )
-	{
-		dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n");
-		corgi_goto_sleep(alarm_time, alarm_enable, state);
-		return 1;
-	}
-
-	return 0;
-}
-
-static int corgi_pxa_pm_enter(suspend_state_t state)
-{
-	unsigned long alarm_time = RTAR;
-	unsigned int alarm_status = ((RTSR & RTSR_ALE) != 0);
-
-	dev_dbg(sharpsl_pm.dev, "SharpSL suspending for first time.\n");
-
-	corgi_goto_sleep(alarm_time, alarm_status, state);
-
-	while (corgi_enter_suspend(alarm_time,alarm_status,state))
-		{}
-
-	if (sharpsl_pm.machinfo->earlyresume)
-		sharpsl_pm.machinfo->earlyresume();
-
-	dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n");
-
-	return 0;
-}
-
-/*
- * Check for fatal battery errors
- * Fatal returns -1
- */
-static int sharpsl_fatal_check(void)
-{
-	int buff[5], temp, i, acin;
-
-	dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n");
-
-	/* Check AC-Adapter */
-	acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
-
-	if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
-		sharpsl_pm.machinfo->charge(0);
-		udelay(100);
-		sharpsl_pm.machinfo->discharge(1);	/* enable discharge */
-		mdelay(SHARPSL_WAIT_DISCHARGE_ON);
-	}
-
-	if (sharpsl_pm.machinfo->discharge1)
-		sharpsl_pm.machinfo->discharge1(1);
-
-	/* Check battery : check inserting battery ? */
-	for (i=0; i<5; i++) {
-		buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
-		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
-	}
-
-	if (sharpsl_pm.machinfo->discharge1)
-		sharpsl_pm.machinfo->discharge1(0);
-
-	if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
-		udelay(100);
-		sharpsl_pm.machinfo->charge(1);
-		sharpsl_pm.machinfo->discharge(0);
-	}
-
-	temp = get_select_val(buff);
-	dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %ld\n", acin, temp, sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT));
-
-	if ((acin && (temp < sharpsl_pm.machinfo->fatal_acin_volt)) ||
-			(!acin && (temp < sharpsl_pm.machinfo->fatal_noacin_volt)))
-		return -1;
-	return 0;
-}
-
-static int sharpsl_off_charge_error(void)
-{
-	dev_err(sharpsl_pm.dev, "Offline Charger: Error occurred.\n");
-	sharpsl_pm.machinfo->charge(0);
-	sharpsl_pm_led(SHARPSL_LED_ERROR);
-	sharpsl_pm.charge_mode = CHRG_ERROR;
-	return 1;
-}
-
-/*
- * Charging Control while suspended
- * Return 1 - go straight to sleep
- * Return 0 - sleep or wakeup depending on other factors
- */
-static int sharpsl_off_charge_battery(void)
-{
-	int time;
-
-	dev_dbg(sharpsl_pm.dev, "Charge Mode: %d\n", sharpsl_pm.charge_mode);
-
-	if (sharpsl_pm.charge_mode == CHRG_OFF) {
-		dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n");
-
-		/* AC Check */
-		if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery_temp() < 0))
-			return sharpsl_off_charge_error();
-
-		/* Start Charging */
-		sharpsl_pm_led(SHARPSL_LED_ON);
-		sharpsl_pm.machinfo->charge(0);
-		mdelay(SHARPSL_CHARGE_WAIT_TIME);
-		sharpsl_pm.machinfo->charge(1);
-
-		sharpsl_pm.charge_mode = CHRG_ON;
-		sharpsl_pm.full_count = 0;
-
-		return 1;
-	} else if (sharpsl_pm.charge_mode != CHRG_ON) {
-		return 1;
-	}
-
-	if (sharpsl_pm.full_count == 0) {
-		int time;
-
-		dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n");
-
-		if ((sharpsl_check_battery_temp() < 0) || (sharpsl_check_battery_voltage() < 0))
-			return sharpsl_off_charge_error();
-
-		sharpsl_pm.machinfo->charge(0);
-		mdelay(SHARPSL_CHARGE_WAIT_TIME);
-		sharpsl_pm.machinfo->charge(1);
-		sharpsl_pm.charge_mode = CHRG_ON;
-
-		mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
-
-		time = RCNR;
-		while(1) {
-			/* Check if any wakeup event had occurred */
-			if (sharpsl_pm.machinfo->charger_wakeup() != 0)
-				return 0;
-			/* Check for timeout */
-			if ((RCNR - time) > SHARPSL_WAIT_CO_TIME)
-				return 1;
-			if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
-				dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occurred. Retrying to check\n");
-	   			sharpsl_pm.full_count++;
-				sharpsl_pm.machinfo->charge(0);
-				mdelay(SHARPSL_CHARGE_WAIT_TIME);
-				sharpsl_pm.machinfo->charge(1);
-				return 1;
-			}
-		}
-	}
-
-	dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 3\n");
-
-	mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
-
-	time = RCNR;
-	while(1) {
-		/* Check if any wakeup event had occurred */
-		if (sharpsl_pm.machinfo->charger_wakeup() != 0)
-			return 0;
-		/* Check for timeout */
-		if ((RCNR-time) > SHARPSL_WAIT_CO_TIME) {
-			if (sharpsl_pm.full_count > SHARPSL_CHARGE_RETRY_CNT) {
-				dev_dbg(sharpsl_pm.dev, "Offline Charger: Not charged sufficiently. Retrying.\n");
-				sharpsl_pm.full_count = 0;
-			}
-			sharpsl_pm.full_count++;
-			return 1;
-		}
-		if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
-			dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n");
-			sharpsl_pm_led(SHARPSL_LED_OFF);
-			sharpsl_pm.machinfo->charge(0);
-			sharpsl_pm.charge_mode = CHRG_DONE;
-			return 1;
-		}
-	}
-}
-#else
-#define sharpsl_pm_suspend	NULL
-#define sharpsl_pm_resume	NULL
-#endif
-
-static ssize_t battery_percentage_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_percent);
-}
-
-static ssize_t battery_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_voltage);
-}
-
-static DEVICE_ATTR(battery_percentage, 0444, battery_percentage_show, NULL);
-static DEVICE_ATTR(battery_voltage, 0444, battery_voltage_show, NULL);
-
-extern void (*apm_get_power_status)(struct apm_power_info *);
-
-static void sharpsl_apm_get_power_status(struct apm_power_info *info)
-{
-	info->ac_line_status = sharpsl_pm.battstat.ac_status;
-
-	if (sharpsl_pm.charge_mode == CHRG_ON)
-		info->battery_status = APM_BATTERY_STATUS_CHARGING;
-	else
-		info->battery_status = sharpsl_pm.battstat.mainbat_status;
-
-	info->battery_flag = (1 << info->battery_status);
-	info->battery_life = sharpsl_pm.battstat.mainbat_percent;
-}
-
-#ifdef CONFIG_PM
-static struct platform_suspend_ops sharpsl_pm_ops = {
-	.enter		= corgi_pxa_pm_enter,
-	.valid		= suspend_valid_only_mem,
-};
-#endif
-
-static int __init sharpsl_pm_probe(struct platform_device *pdev)
-{
-	int ret;
-
-	if (!pdev->dev.platform_data)
-		return -EINVAL;
-
-	sharpsl_pm.dev = &pdev->dev;
-	sharpsl_pm.machinfo = pdev->dev.platform_data;
-	sharpsl_pm.charge_mode = CHRG_OFF;
-	sharpsl_pm.flags = 0;
-
-	init_timer(&sharpsl_pm.ac_timer);
-	sharpsl_pm.ac_timer.function = sharpsl_ac_timer;
-
-	init_timer(&sharpsl_pm.chrg_full_timer);
-	sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer;
-
-	led_trigger_register_simple("sharpsl-charge", &sharpsl_charge_led_trigger);
-
-	sharpsl_pm.machinfo->init();
-
-	ret = device_create_file(&pdev->dev, &dev_attr_battery_percentage);
-	ret |= device_create_file(&pdev->dev, &dev_attr_battery_voltage);
-	if (ret != 0)
-		dev_warn(&pdev->dev, "Failed to register attributes (%d)\n", ret);
-
-	apm_get_power_status = sharpsl_apm_get_power_status;
-
-#ifdef CONFIG_PM
-	suspend_set_ops(&sharpsl_pm_ops);
-#endif
-
-	mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
-
-	return 0;
-}
-
-static int sharpsl_pm_remove(struct platform_device *pdev)
-{
-	suspend_set_ops(NULL);
-
-	device_remove_file(&pdev->dev, &dev_attr_battery_percentage);
-	device_remove_file(&pdev->dev, &dev_attr_battery_voltage);
-
-	led_trigger_unregister_simple(sharpsl_charge_led_trigger);
-
-	sharpsl_pm.machinfo->exit();
-
-	del_timer_sync(&sharpsl_pm.chrg_full_timer);
-	del_timer_sync(&sharpsl_pm.ac_timer);
-
-	return 0;
-}
-
-static struct platform_driver sharpsl_pm_driver = {
-	.probe		= sharpsl_pm_probe,
-	.remove		= sharpsl_pm_remove,
-	.suspend	= sharpsl_pm_suspend,
-	.resume		= sharpsl_pm_resume,
-	.driver		= {
-		.name		= "sharpsl-pm",
-	},
-};
-
-static int __devinit sharpsl_pm_init(void)
-{
-	return platform_driver_register(&sharpsl_pm_driver);
-}
-
-static void sharpsl_pm_exit(void)
-{
- 	platform_driver_unregister(&sharpsl_pm_driver);
-}
-
-late_initcall(sharpsl_pm_init);
-module_exit(sharpsl_pm_exit);
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
index b2a781d..887c6eb 100644
--- a/arch/arm/common/vic.c
+++ b/arch/arm/common/vic.c
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/io.h>
+#include <linux/sysdev.h>
 
 #include <asm/mach/irq.h>
 #include <asm/hardware/vic.h>
@@ -39,11 +40,219 @@
 	writel(1 << irq, base + VIC_INT_ENABLE);
 }
 
+/**
+ * vic_init2 - common initialisation code
+ * @base: Base of the VIC.
+ *
+ * Common initialisation code for registeration
+ * and resume.
+*/
+static void vic_init2(void __iomem *base)
+{
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
+		writel(VIC_VECT_CNTL_ENABLE | i, reg);
+	}
+
+	writel(32, base + VIC_PL190_DEF_VECT_ADDR);
+}
+
+#if defined(CONFIG_PM)
+/**
+ * struct vic_device - VIC PM device
+ * @sysdev: The system device which is registered.
+ * @irq: The IRQ number for the base of the VIC.
+ * @base: The register base for the VIC.
+ * @resume_sources: A bitmask of interrupts for resume.
+ * @resume_irqs: The IRQs enabled for resume.
+ * @int_select: Save for VIC_INT_SELECT.
+ * @int_enable: Save for VIC_INT_ENABLE.
+ * @soft_int: Save for VIC_INT_SOFT.
+ * @protect: Save for VIC_PROTECT.
+ */
+struct vic_device {
+	struct sys_device sysdev;
+
+	void __iomem	*base;
+	int		irq;
+	u32		resume_sources;
+	u32		resume_irqs;
+	u32		int_select;
+	u32		int_enable;
+	u32		soft_int;
+	u32		protect;
+};
+
+/* we cannot allocate memory when VICs are initially registered */
+static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
+
+static inline struct vic_device *to_vic(struct sys_device *sys)
+{
+	return container_of(sys, struct vic_device, sysdev);
+}
+
+static int vic_id;
+
+static int vic_class_resume(struct sys_device *dev)
+{
+	struct vic_device *vic = to_vic(dev);
+	void __iomem *base = vic->base;
+
+	printk(KERN_DEBUG "%s: resuming vic at %p\n", __func__, base);
+
+	/* re-initialise static settings */
+	vic_init2(base);
+
+	writel(vic->int_select, base + VIC_INT_SELECT);
+	writel(vic->protect, base + VIC_PROTECT);
+
+	/* set the enabled ints and then clear the non-enabled */
+	writel(vic->int_enable, base + VIC_INT_ENABLE);
+	writel(~vic->int_enable, base + VIC_INT_ENABLE_CLEAR);
+
+	/* and the same for the soft-int register */
+
+	writel(vic->soft_int, base + VIC_INT_SOFT);
+	writel(~vic->soft_int, base + VIC_INT_SOFT_CLEAR);
+
+	return 0;
+}
+
+static int vic_class_suspend(struct sys_device *dev, pm_message_t state)
+{
+	struct vic_device *vic = to_vic(dev);
+	void __iomem *base = vic->base;
+
+	printk(KERN_DEBUG "%s: suspending vic at %p\n", __func__, base);
+
+	vic->int_select = readl(base + VIC_INT_SELECT);
+	vic->int_enable = readl(base + VIC_INT_ENABLE);
+	vic->soft_int = readl(base + VIC_INT_SOFT);
+	vic->protect = readl(base + VIC_PROTECT);
+
+	/* set the interrupts (if any) that are used for
+	 * resuming the system */
+
+	writel(vic->resume_irqs, base + VIC_INT_ENABLE);
+	writel(~vic->resume_irqs, base + VIC_INT_ENABLE_CLEAR);
+
+	return 0;
+}
+
+struct sysdev_class vic_class = {
+	.name		= "vic",
+	.suspend	= vic_class_suspend,
+	.resume		= vic_class_resume,
+};
+
+/**
+ * vic_pm_register - Register a VIC for later power management control
+ * @base: The base address of the VIC.
+ * @irq: The base IRQ for the VIC.
+ * @resume_sources: bitmask of interrupts allowed for resume sources.
+ *
+ * Register the VIC with the system device tree so that it can be notified
+ * of suspend and resume requests and ensure that the correct actions are
+ * taken to re-instate the settings on resume.
+ */
+static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources)
+{
+	struct vic_device *v;
+
+	if (vic_id >= ARRAY_SIZE(vic_devices))
+		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
+	else {
+		v = &vic_devices[vic_id];
+		v->base = base;
+		v->resume_sources = resume_sources;
+		v->irq = irq;
+		vic_id++;
+	}
+}
+
+/**
+ * vic_pm_init - initicall to register VIC pm
+ *
+ * This is called via late_initcall() to register
+ * the resources for the VICs due to the early
+ * nature of the VIC's registration.
+*/
+static int __init vic_pm_init(void)
+{
+	struct vic_device *dev = vic_devices;
+	int err;
+	int id;
+
+	if (vic_id == 0)
+		return 0;
+
+	err = sysdev_class_register(&vic_class);
+	if (err) {
+		printk(KERN_ERR "%s: cannot register class\n", __func__);
+		return err;
+	}
+
+	for (id = 0; id < vic_id; id++, dev++) {
+		dev->sysdev.id = id;
+		dev->sysdev.cls = &vic_class;
+
+		err = sysdev_register(&dev->sysdev);
+		if (err) {
+			printk(KERN_ERR "%s: failed to register device\n",
+			       __func__);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+late_initcall(vic_pm_init);
+
+static struct vic_device *vic_from_irq(unsigned int irq)
+{
+        struct vic_device *v = vic_devices;
+	unsigned int base_irq = irq & ~31;
+	int id;
+
+	for (id = 0; id < vic_id; id++, v++) {
+		if (v->irq == base_irq)
+			return v;
+	}
+
+	return NULL;
+}
+
+static int vic_set_wake(unsigned int irq, unsigned int on)
+{
+	struct vic_device *v = vic_from_irq(irq);
+	unsigned int off = irq & 31;
+
+	if (!v)
+		return -EINVAL;
+
+	if (on)
+		v->resume_irqs |= 1 << off;
+	else
+		v->resume_irqs &= ~(1 << off);
+
+	return 0;
+}
+
+#else
+static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
+
+#define vic_set_wake NULL
+#endif /* CONFIG_PM */
+
 static struct irq_chip vic_chip = {
 	.name	= "VIC",
 	.ack	= vic_mask_irq,
 	.mask	= vic_mask_irq,
 	.unmask	= vic_unmask_irq,
+	.set_wake = vic_set_wake,
 };
 
 /**
@@ -51,9 +260,10 @@
  * @base: iomem base address
  * @irq_start: starting interrupt number, must be muliple of 32
  * @vic_sources: bitmask of interrupt sources to allow
+ * @resume_sources: bitmask of interrupt sources to allow for resume
  */
 void __init vic_init(void __iomem *base, unsigned int irq_start,
-		     u32 vic_sources)
+		     u32 vic_sources, u32 resume_sources)
 {
 	unsigned int i;
 
@@ -77,12 +287,7 @@
 		writel(value, base + VIC_PL190_VECT_ADDR);
 	}
 
-	for (i = 0; i < 16; i++) {
-		void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
-		writel(VIC_VECT_CNTL_ENABLE | i, reg);
-	}
-
-	writel(32, base + VIC_PL190_DEF_VECT_ADDR);
+	vic_init2(base);
 
 	for (i = 0; i < 32; i++) {
 		if (vic_sources & (1 << i)) {
@@ -94,4 +299,6 @@
 			set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 		}
 	}
+
+	vic_pm_register(base, irq_start, resume_sources);
 }
diff --git a/arch/arm/configs/cm_x300_defconfig b/arch/arm/configs/cm_x300_defconfig
index 227da08..d18d21b 100644
--- a/arch/arm/configs/cm_x300_defconfig
+++ b/arch/arm/configs/cm_x300_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.27-rc3
-# Tue Aug 19 11:26:54 2008
+# Linux kernel version: 2.6.30-rc8
+# Thu Jun  4 09:53:21 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -22,8 +22,6 @@
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_ARCH_SUPPORTS_AOUT=y
-CONFIG_ZONE_DMA=y
 CONFIG_ARCH_MTD_XIP=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_VECTORS_BASE=0xffff0000
@@ -44,15 +42,24 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=18
-# CONFIG_CGROUPS is not set
 CONFIG_GROUP_SCHED=y
 CONFIG_FAIR_GROUP_SCHED=y
 # CONFIG_RT_GROUP_SCHED is not set
 CONFIG_USER_SCHED=y
 # CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_RELAY is not set
@@ -61,31 +68,37 @@
 # 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_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 # CONFIG_EMBEDDED is not set
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
-CONFIG_COMPAT_BRK=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_VM_EVENT_COUNTERS=y
 CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
@@ -93,19 +106,13 @@
 # CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
-# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
-# CONFIG_HAVE_IOREMAP_PROT is not set
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
-# CONFIG_HAVE_ARCH_TRACEHOOK is not set
-# CONFIG_HAVE_DMA_ATTRS is not set
-# CONFIG_USE_GENERIC_SMP_HELPERS is not set
 CONFIG_HAVE_CLK=y
-CONFIG_PROC_PAGE_MONITOR=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 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
@@ -113,11 +120,8 @@
 # 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_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -133,7 +137,7 @@
 CONFIG_DEFAULT_CFQ=y
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="cfq"
-CONFIG_CLASSIC_RCU=y
+CONFIG_FREEZER=y
 
 #
 # System Type
@@ -143,10 +147,10 @@
 # CONFIG_ARCH_REALVIEW is not set
 # CONFIG_ARCH_VERSATILE is not set
 # CONFIG_ARCH_AT91 is not set
-# CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_GEMINI is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_NETX is not set
 # CONFIG_ARCH_H720X is not set
@@ -167,14 +171,17 @@
 # CONFIG_ARCH_ORION5X is not set
 # CONFIG_ARCH_PNX4008 is not set
 CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_MMP is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
 # CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM7X00A is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_W90X900 is not set
 
 #
 # Intel PXA2xx/PXA3xx Implementations
@@ -187,16 +194,24 @@
 # CONFIG_CPU_PXA310 is not set
 # CONFIG_CPU_PXA320 is not set
 # CONFIG_CPU_PXA930 is not set
+# CONFIG_CPU_PXA935 is not set
 # CONFIG_ARCH_GUMSTIX is not set
+# CONFIG_MACH_INTELMOTE2 is not set
 # CONFIG_ARCH_LUBBOCK is not set
 # CONFIG_MACH_LOGICPD_PXA270 is not set
 # CONFIG_MACH_MAINSTONE is not set
+# CONFIG_MACH_MP900C is not set
 # CONFIG_ARCH_PXA_IDP is not set
 # CONFIG_PXA_SHARPSL is not set
+# CONFIG_ARCH_VIPER is not set
 # CONFIG_ARCH_PXA_ESERIES is not set
-# CONFIG_MACH_TRIZEPS4 is not set
+# CONFIG_TRIZEPS_PXA is not set
+# CONFIG_MACH_H5000 is not set
 # CONFIG_MACH_EM_X270 is not set
+# CONFIG_MACH_EXEDA is not set
 # CONFIG_MACH_COLIBRI is not set
+# CONFIG_MACH_COLIBRI300 is not set
+# CONFIG_MACH_COLIBRI320 is not set
 # CONFIG_MACH_ZYLONITE is not set
 # CONFIG_MACH_LITTLETON is not set
 # CONFIG_MACH_TAVOREVB is not set
@@ -204,19 +219,15 @@
 # CONFIG_MACH_ARMCORE is not set
 CONFIG_MACH_CM_X300=y
 # CONFIG_MACH_MAGICIAN is not set
+# CONFIG_MACH_HIMALAYA is not set
+# CONFIG_MACH_MIOA701 is not set
 # CONFIG_MACH_PCM027 is not set
 # CONFIG_ARCH_PXA_PALM is not set
+# CONFIG_MACH_CSB726 is not set
 # CONFIG_PXA_EZX is not set
 CONFIG_PXA3xx=y
 # CONFIG_PXA_PWM is not set
-
-#
-# Boot options
-#
-
-#
-# Power management
-#
+CONFIG_PLAT_PXA=y
 
 #
 # Processor Type
@@ -241,6 +252,7 @@
 CONFIG_OUTER_CACHE=y
 CONFIG_CACHE_XSC3L2=y
 CONFIG_IWMMXT=y
+CONFIG_COMMON_CLKDEV=y
 
 #
 # Bus support
@@ -256,25 +268,33 @@
 CONFIG_NO_HZ=y
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
 # CONFIG_PREEMPT is not set
 CONFIG_HZ=100
 CONFIG_AEABI=y
 CONFIG_OABI_COMPAT=y
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# CONFIG_ARCH_HAS_HOLES_MEMORYMODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_HIGHMEM=y
 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=4096
-# CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
 CONFIG_BOUNCE=y
 CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -287,7 +307,7 @@
 # CONFIG_KEXEC is not set
 
 #
-# CPU Frequency scaling
+# CPU Power Management
 #
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_TABLE=y
@@ -304,6 +324,7 @@
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 # CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
 # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_IDLE is not set
 
 #
 # Floating point emulation
@@ -320,6 +341,8 @@
 # Userspace binary formats
 #
 CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
 
@@ -376,6 +399,7 @@
 # CONFIG_TIPC is not set
 # CONFIG_ATM 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
@@ -385,7 +409,9 @@
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
 
 #
 # Network testing
@@ -407,8 +433,7 @@
 #
 # Bluetooth device drivers
 #
-CONFIG_BT_HCIUSB=m
-CONFIG_BT_HCIUSB_SCO=y
+# CONFIG_BT_HCIBTUSB is not set
 # CONFIG_BT_HCIBTSDIO is not set
 # CONFIG_BT_HCIUART is not set
 # CONFIG_BT_HCIBCM203X is not set
@@ -416,19 +441,15 @@
 # CONFIG_BT_HCIBFUSB is not set
 # CONFIG_BT_HCIVHCI is not set
 # CONFIG_AF_RXRPC is not set
-
-#
-# Wireless
-#
+CONFIG_WIRELESS=y
 # CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
 CONFIG_WIRELESS_EXT=y
 CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_LIB80211=m
+# CONFIG_LIB80211_DEBUG is not set
 # CONFIG_MAC80211 is not set
-CONFIG_IEEE80211=m
-# CONFIG_IEEE80211_DEBUG is not set
-CONFIG_IEEE80211_CRYPT_WEP=m
-CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
+# CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
 
@@ -453,6 +474,7 @@
 # CONFIG_MTD_DEBUG is not set
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_REDBOOT_PARTS is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
@@ -494,7 +516,6 @@
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_SHARP_SL is not set
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -516,16 +537,23 @@
 # CONFIG_MTD_NAND_ECC_SMC is not set
 # CONFIG_MTD_NAND_MUSEUM_IDS is not set
 # CONFIG_MTD_NAND_H1900 is not set
+# CONFIG_MTD_NAND_GPIO is not set
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_SHARPSL is not set
 CONFIG_MTD_NAND_PXA3xx=y
+# CONFIG_MTD_NAND_PXA3xx_BUILTIN is not set
 # CONFIG_MTD_NAND_NANDSIM is not set
 # CONFIG_MTD_NAND_PLATFORM is not set
 # CONFIG_MTD_ALAUDA is not set
 # CONFIG_MTD_ONENAND is not set
 
 #
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
@@ -585,11 +613,15 @@
 # CONFIG_SCSI_SRP_ATTRS is not set
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
 CONFIG_NETDEVICES=y
+CONFIG_COMPAT_NET_DEV_OPS=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
@@ -604,11 +636,17 @@
 CONFIG_DM9000=y
 CONFIG_DM9000_DEBUGLEVEL=0
 CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y
+# CONFIG_ETHOC is not set
 # CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
 # CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
@@ -624,10 +662,13 @@
 # CONFIG_LIBERTAS_DEBUG is not set
 # CONFIG_USB_ZD1201 is not set
 # CONFIG_USB_NET_RNDIS_WLAN is not set
-# CONFIG_IWLWIFI_LEDS is not set
 # CONFIG_HOSTAP is not set
 
 #
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
 # USB Network Adapters
 #
 # CONFIG_USB_CATC is not set
@@ -677,18 +718,21 @@
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
 # CONFIG_TOUCHSCREEN_MTOUCH is not set
 # CONFIG_TOUCHSCREEN_INEXIO is not set
 # CONFIG_TOUCHSCREEN_MK712 is not set
 # CONFIG_TOUCHSCREEN_PENMOUNT is not set
 # CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
 # CONFIG_TOUCHSCREEN_TOUCHWIN is not set
-# CONFIG_TOUCHSCREEN_UCB1400 is not set
 # CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
 # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
 # CONFIG_INPUT_MISC is not set
 
 #
@@ -721,10 +765,10 @@
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
-# CONFIG_NVRAM is not set
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
@@ -763,12 +807,8 @@
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-# CONFIG_EEPROM_AT24 is not set
-# CONFIG_EEPROM_LEGACY is not set
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_TPS65010 is not set
 # CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
@@ -782,6 +822,10 @@
 # CONFIG_GPIO_SYSFS is not set
 
 #
+# Memory mapped GPIO expanders:
+#
+
+#
 # I2C GPIO expanders:
 #
 # CONFIG_GPIO_MAX732X is not set
@@ -798,12 +842,14 @@
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
 # CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
 
 #
 # Sonics Silicon Backplane
 #
-CONFIG_SSB_POSSIBLE=y
 # CONFIG_SSB is not set
 
 #
@@ -811,12 +857,19 @@
 #
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
 # CONFIG_HTC_EGPIO is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_MFD_T7L66XB is not set
 # CONFIG_MFD_TC6387XB is not set
 # CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
 
 #
 # Multimedia devices
@@ -842,6 +895,7 @@
 CONFIG_FB=y
 # CONFIG_FIRMWARE_EDID is not set
 # CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
@@ -862,12 +916,15 @@
 #
 # CONFIG_FB_S1D13XXX is not set
 CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_OVERLAY is not set
 # CONFIG_FB_PXA_SMARTPANEL is not set
 # CONFIG_FB_PXA_PARAMETERS is not set
 # CONFIG_FB_MBX is not set
 # CONFIG_FB_W100 is not set
-# CONFIG_FB_AM200EPD is not set
 # CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
@@ -899,9 +956,11 @@
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
 CONFIG_SOUND=m
+# CONFIG_SOUND_OSS_CORE is not set
 CONFIG_SND=m
 CONFIG_SND_TIMER=m
 CONFIG_SND_PCM=m
+CONFIG_SND_JACK=y
 # CONFIG_SND_SEQUENCER is not set
 # CONFIG_SND_MIXER_OSS is not set
 # CONFIG_SND_PCM_OSS is not set
@@ -916,12 +975,15 @@
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_MPU401 is not set
 CONFIG_SND_ARM=y
+CONFIG_SND_PXA2XX_LIB=m
 # CONFIG_SND_PXA2XX_AC97 is not set
 CONFIG_SND_USB=y
 # CONFIG_SND_USB_AUDIO is not set
 # CONFIG_SND_USB_CAIAQ is not set
 CONFIG_SND_SOC=m
 CONFIG_SND_PXA2XX_SOC=m
+CONFIG_SND_SOC_I2C_AND_SPI=m
+# CONFIG_SND_SOC_ALL_CODECS is not set
 # CONFIG_SOUND_PRIME is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
@@ -932,9 +994,39 @@
 # USB Input Devices
 #
 CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
+# CONFIG_HID_PID is not set
 # CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+# CONFIG_DRAGONRISE_FF is not set
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KYE=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+# CONFIG_GREENASIA_FF is not set
+CONFIG_HID_TOPSEED=y
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
@@ -952,11 +1044,14 @@
 # CONFIG_USB_SUSPEND is not set
 # CONFIG_USB_OTG is not set
 CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
 
 #
 # USB Host Controller Drivers
 #
 # CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
 # CONFIG_USB_ISP1760_HCD is not set
 CONFIG_USB_OHCI_HCD=y
@@ -965,6 +1060,7 @@
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_SL811_HCD is not set
 # CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
 # CONFIG_USB_MUSB_HDRC is not set
 
 #
@@ -973,20 +1069,20 @@
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
 # CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
 #
 
 #
-# may also be needed; see USB_STORAGE Help for more information
+# also be needed; see USB_STORAGE Help for more info
 #
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
 # CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_USBAT is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
@@ -994,7 +1090,6 @@
 # CONFIG_USB_STORAGE_ALAUDA is not set
 # CONFIG_USB_STORAGE_ONETOUCH is not set
 # CONFIG_USB_STORAGE_KARMA is not set
-# CONFIG_USB_STORAGE_SIERRA is not set
 # CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
 # CONFIG_USB_LIBUSUAL is not set
 
@@ -1015,6 +1110,7 @@
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
 # CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
@@ -1022,7 +1118,6 @@
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
 # CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_FTDI_ELAN is not set
 # CONFIG_USB_APPLEDISPLAY is not set
@@ -1031,13 +1126,20 @@
 # CONFIG_USB_IOWARRIOR is not set
 # CONFIG_USB_TEST is not set
 # CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
 # CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
 CONFIG_MMC=m
 # CONFIG_MMC_DEBUG is not set
 # CONFIG_MMC_UNSAFE_RESUME is not set
 
 #
-# MMC/SD Card Drivers
+# MMC/SD/SDIO Card Drivers
 #
 CONFIG_MMC_BLOCK=m
 CONFIG_MMC_BLOCK_BOUNCE=y
@@ -1045,10 +1147,12 @@
 # CONFIG_MMC_TEST is not set
 
 #
-# MMC/SD Host Controller Drivers
+# MMC/SD/SDIO Host Controller Drivers
 #
 CONFIG_MMC_PXA=m
 # CONFIG_MMC_SDHCI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 
@@ -1057,7 +1161,10 @@
 #
 # CONFIG_LEDS_PCA9532 is not set
 CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP5521 is not set
 # CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_BD2802 is not set
 
 #
 # LED Triggers
@@ -1065,7 +1172,13 @@
 CONFIG_LEDS_TRIGGERS=y
 # CONFIG_LEDS_TRIGGER_TIMER is not set
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
 # CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
 CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HCTOSYS=y
@@ -1096,6 +1209,7 @@
 # CONFIG_RTC_DRV_M41T80 is not set
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
 
 #
 # SPI RTC drivers
@@ -1105,28 +1219,27 @@
 # Platform RTC drivers
 #
 # CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
 # CONFIG_RTC_DRV_DS1511 is not set
 # CONFIG_RTC_DRV_DS1553 is not set
 # CONFIG_RTC_DRV_DS1742 is not set
 # CONFIG_RTC_DRV_STK17TA8 is not set
 # CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
 # CONFIG_RTC_DRV_M48T59 is not set
-# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+CONFIG_RTC_DRV_V3020=y
 
 #
 # on-CPU RTC drivers
 #
 CONFIG_RTC_DRV_SA1100=y
+# CONFIG_RTC_DRV_PXA is not set
 # CONFIG_DMADEVICES is not set
-
-#
-# Voltage and Current regulators
-#
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_REGULATOR is not set
-# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
-# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
-# CONFIG_REGULATOR_BQ24022 is not set
 # CONFIG_UIO is not set
+# CONFIG_STAGING is not set
 
 #
 # File systems
@@ -1135,15 +1248,18 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 # CONFIG_EXT3_FS_XATTR is not set
-# CONFIG_EXT4DEV_FS is not set
+# CONFIG_EXT4_FS is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
 # CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
 CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1153,6 +1269,11 @@
 # CONFIG_FUSE_FS is not set
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 # CONFIG_ISO9660_FS is not set
@@ -1173,15 +1294,13 @@
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL 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
@@ -1201,6 +1320,7 @@
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN 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
@@ -1209,6 +1329,7 @@
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -1313,6 +1434,7 @@
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 # CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_DETECT_HUNG_TASK is not set
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1329,6 +1451,7 @@
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_VM is not set
@@ -1336,22 +1459,38 @@
 CONFIG_DEBUG_MEMORY_INIT=y
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
-CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_NOTIFIERS is not set
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_HAVE_FTRACE=y
-CONFIG_HAVE_DYNAMIC_FTRACE=y
-# CONFIG_FTRACE is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
 # CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_ERRORS is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
@@ -1363,17 +1502,28 @@
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 CONFIG_CRYPTO=y
 
 #
 # Crypto core or helper
 #
+# CONFIG_CRYPTO_FIPS is not set
 CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
 CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
 CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
 # CONFIG_CRYPTO_GF128MUL is not set
 # CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
 # CONFIG_CRYPTO_CRYPTD is not set
 # CONFIG_CRYPTO_AUTHENC is not set
 # CONFIG_CRYPTO_TEST is not set
@@ -1442,15 +1592,21 @@
 # Compression
 #
 # CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
-# CONFIG_GENERIC_FIND_FIRST_BIT is not set
-# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_GENERIC_FIND_LAST_BIT=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
 CONFIG_CRC_T10DIF=y
@@ -1460,7 +1616,10 @@
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
-CONFIG_PLIST=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig
index eb2738b..ac18662 100644
--- a/arch/arm/configs/davinci_all_defconfig
+++ b/arch/arm/configs/davinci_all_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2
-# Wed Apr 15 08:16:53 2009
+# Linux kernel version: 2.6.30-rc7
+# Tue May 26 07:24:28 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -179,6 +179,7 @@
 # CONFIG_ARCH_OMAP is not set
 # CONFIG_ARCH_MSM is not set
 # CONFIG_ARCH_W90X900 is not set
+CONFIG_AINTC=y
 
 #
 # TI DaVinci Implementations
@@ -188,11 +189,17 @@
 # DaVinci Core Type
 #
 CONFIG_ARCH_DAVINCI_DM644x=y
+CONFIG_ARCH_DAVINCI_DM355=y
+CONFIG_ARCH_DAVINCI_DM646x=y
 
 #
 # DaVinci Board Type
 #
 CONFIG_MACH_DAVINCI_EVM=y
+CONFIG_MACH_SFFSDR=y
+CONFIG_MACH_DAVINCI_DM355_EVM=y
+CONFIG_MACH_DM355_LEOPARD=y
+CONFIG_MACH_DAVINCI_DM6467_EVM=y
 CONFIG_DAVINCI_MUX=y
 CONFIG_DAVINCI_MUX_DEBUG=y
 CONFIG_DAVINCI_MUX_WARNINGS=y
@@ -245,7 +252,7 @@
 CONFIG_HZ=100
 CONFIG_AEABI=y
 # CONFIG_OABI_COMPAT is not set
-CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_HAS_HOLES_MEMORYMODEL is not set
 # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
 # CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
 # CONFIG_HIGHMEM is not set
@@ -661,7 +668,10 @@
 CONFIG_MII=y
 # CONFIG_AX88796 is not set
 # CONFIG_SMC91X is not set
-# CONFIG_DM9000 is not set
+CONFIG_TI_DAVINCI_EMAC=y
+CONFIG_DM9000=y
+CONFIG_DM9000_DEBUGLEVEL=4
+# CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL is not set
 # CONFIG_ETHOC is not set
 # CONFIG_SMC911X is not set
 # CONFIG_SMSC911X is not set
@@ -963,6 +973,7 @@
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_MFD_ASIC3 is not set
+# CONFIG_MFD_DM355EVM_MSP is not set
 # CONFIG_HTC_EGPIO is not set
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_TPS65010 is not set
@@ -1317,6 +1328,7 @@
 # MMC/SD/SDIO Host Controller Drivers
 #
 # CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_DAVINCI is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_ACCESSIBILITY is not set
 CONFIG_NEW_LEDS=y
@@ -1778,6 +1790,7 @@
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
 CONFIG_DECOMPRESS_GZIP=y
+CONFIG_GENERIC_ALLOCATOR=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/ep93xx_defconfig b/arch/arm/configs/ep93xx_defconfig
index 3f89d5f..3fb083b 100644
--- a/arch/arm/configs/ep93xx_defconfig
+++ b/arch/arm/configs/ep93xx_defconfig
@@ -1,12 +1,19 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20-rc1
-# Sat Dec 16 06:05:24 2006
+# Linux kernel version: 2.6.30-rc3
+# Tue May 19 12:26:49 2009
 #
 CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
 # CONFIG_GENERIC_TIME is not set
+# CONFIG_GENERIC_CLOCKEVENTS is not set
 CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
 CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_HARDIRQS_SW_RESEND=y
 CONFIG_GENERIC_IRQ_PROBE=y
@@ -15,42 +22,54 @@
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
 # CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_RELAY is not set
-CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -58,31 +77,38 @@
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_SLAB=y
+CONFIG_AIO=y
 CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
 
 #
 # IO Schedulers
@@ -96,6 +122,7 @@
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="deadline"
+# CONFIG_FREEZER is not set
 
 #
 # System Type
@@ -105,29 +132,40 @@
 # CONFIG_ARCH_REALVIEW is not set
 # CONFIG_ARCH_VERSATILE is not set
 # CONFIG_ARCH_AT91 is not set
-# CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_GEMINI is not set
 # CONFIG_ARCH_EBSA110 is not set
 CONFIG_ARCH_EP93XX=y
 # CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
 # CONFIG_ARCH_NETX is not set
 # CONFIG_ARCH_H720X is not set
 # CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
 # CONFIG_ARCH_IOP32X is not set
 # CONFIG_ARCH_IOP33X is not set
-# CONFIG_ARCH_IOP13XX is not set
-# CONFIG_ARCH_IXP4XX is not set
-# CONFIG_ARCH_IXP2000 is not set
 # CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
 # CONFIG_ARCH_PNX4008 is not set
 # CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
 # CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
 
 #
@@ -138,14 +176,24 @@
 #
 # EP93xx Platforms
 #
+# CONFIG_EP93XX_SDCE0_PHYS_OFFSET is not set
+CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET=y
 CONFIG_MACH_ADSSPHERE=y
+CONFIG_MACH_EDB93XX=y
+CONFIG_MACH_EDB9301=y
 CONFIG_MACH_EDB9302=y
-CONFIG_MACH_EDB9302A=y
+CONFIG_MACH_EDB9307=y
 CONFIG_MACH_EDB9312=y
 CONFIG_MACH_EDB9315=y
-CONFIG_MACH_EDB9315A=y
 CONFIG_MACH_GESBC9312=y
+CONFIG_MACH_MICRO9=y
+CONFIG_MACH_MICRO9H=y
+CONFIG_MACH_MICRO9M=y
+CONFIG_MACH_MICRO9L=y
 CONFIG_MACH_TS72XX=y
+CONFIG_EP93XX_EARLY_UART1=y
+# CONFIG_EP93XX_EARLY_UART2 is not set
+# CONFIG_EP93XX_EARLY_UART3 is not set
 
 #
 # Processor Type
@@ -154,6 +202,7 @@
 CONFIG_CPU_ARM920T=y
 CONFIG_CPU_32v4T=y
 CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_PABRT_NOIFAR=y
 CONFIG_CPU_CACHE_V4WT=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
@@ -168,34 +217,47 @@
 # CONFIG_CPU_ICACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_OUTER_CACHE is not set
 CONFIG_ARM_VIC=y
+CONFIG_COMMON_CLKDEV=y
 
 #
 # Bus support
 #
 CONFIG_ARM_AMBA=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 # CONFIG_PCCARD is not set
 
 #
 # Kernel Features
 #
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
 # CONFIG_PREEMPT is not set
 CONFIG_HZ=100
-# CONFIG_AEABI is not set
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM 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_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4096
-# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -205,6 +267,12 @@
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="console=ttyAM0,115200 root=/dev/nfs ip=bootp"
 # CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
 
 #
 # Floating point emulation
@@ -221,32 +289,31 @@
 # Userspace binary formats
 #
 CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_ARTHUR is not set
 
 #
 # Power management options
 #
 # CONFIG_PM is not set
-# CONFIG_APM is not set
-
-#
-# Networking
-#
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
 # CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
 CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -267,6 +334,7 @@
 CONFIG_INET_XFRM_MODE_TRANSPORT=y
 CONFIG_INET_XFRM_MODE_TUNNEL=y
 CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
@@ -276,6 +344,7 @@
 CONFIG_IPV6=y
 # CONFIG_IPV6_PRIVACY is not set
 # CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
 # CONFIG_INET6_AH is not set
 # CONFIG_INET6_ESP is not set
 # CONFIG_INET6_IPCOMP is not set
@@ -289,25 +358,15 @@
 # CONFIG_IPV6_SIT is not set
 # CONFIG_IPV6_TUNNEL is not set
 # CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM 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
@@ -317,20 +376,28 @@
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
+# CONFIG_PHONET is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
 # CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_LIB80211 is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -339,41 +406,39 @@
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
 # CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
 CONFIG_MTD_CONCAT=y
 CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 # CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
 # CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 CONFIG_MTD_CMDLINE_PARTS=y
 # CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
 
 #
 # User Modules And Translation Layers
 #
 CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
 # CONFIG_INFTL is not set
 # CONFIG_RFD_FTL is not set
 # CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -404,16 +469,13 @@
 # CONFIG_MTD_RAM is not set
 CONFIG_MTD_ROM=y
 # CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PHYSMAP_START=0x0
-CONFIG_MTD_PHYSMAP_LEN=0x0
-CONFIG_MTD_PHYSMAP_BANKWIDTH=1
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_PLATRAM is not set
 
@@ -431,49 +493,58 @@
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
 # CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_VERIFY_WRITE=y
 # CONFIG_MTD_NAND_ECC_SMC is not set
-CONFIG_MTD_NAND_TS7250=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+# CONFIG_MTD_NAND_TS7250 is not set
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_NANDSIM is not set
-
-#
-# OneNAND Flash Device Drivers
-#
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
 # CONFIG_MTD_ONENAND is not set
 
 #
-# Parallel port support
+# LPDDR flash memory drivers
 #
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 CONFIG_BLK_DEV_NBD=y
 # CONFIG_BLK_DEV_UB is not set
 # CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+CONFIG_EEPROM_LEGACY=y
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
 
 #
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
 # CONFIG_SCSI_PROC_FS is not set
@@ -495,6 +566,7 @@
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
 # CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
 
 #
 # SCSI Transports
@@ -502,92 +574,71 @@
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
 # CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
-
-#
-# SCSI low-level drivers
-#
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 # CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+CONFIG_COMPAT_NET_DEV_OPS=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-
-#
-# PHY device support
-#
+# CONFIG_VETH is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 CONFIG_EP93XX_ETH=y
+# CONFIG_AX88796 is not set
 # CONFIG_SMC91X is not set
 # CONFIG_DM9000 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
 
 #
-# Ethernet (1000 Mbit)
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
 #
 
 #
-# Ethernet (10000 Mbit)
+# USB Network Adapters
 #
-
-#
-# Token Ring devices
-#
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+# CONFIG_USB_USBNET is not set
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
 
 #
@@ -605,6 +656,7 @@
 # Character devices
 #
 # CONFIG_VT is not set
+CONFIG_DEVKMEM=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -621,104 +673,101 @@
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-
-#
-# Watchdog Device Drivers
-#
-# CONFIG_SOFT_WATCHDOG is not set
-CONFIG_EP93XX_WATCHDOG=y
-
-#
-# USB-based Watchdog Cards
-#
-# CONFIG_USBPCWATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
-# CONFIG_NVRAM is not set
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
 CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
 CONFIG_I2C_CHARDEV=y
-
-#
-# I2C Algorithms
-#
-CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_ALGOPCA is not set
+CONFIG_I2C_HELPER_AUTO=y
 
 #
 # I2C Hardware Bus support
 #
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
 # CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
 # CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
 # CONFIG_I2C_STUB is not set
-# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Miscellaneous I2C Chip support
 #
-# CONFIG_SENSORS_DS1337 is not set
-# CONFIG_SENSORS_DS1374 is not set
-CONFIG_EEPROM_LEGACY=y
+# CONFIG_DS1682 is not set
 # CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
 # CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
 CONFIG_I2C_DEBUG_CORE=y
 CONFIG_I2C_DEBUG_ALGO=y
 CONFIG_I2C_DEBUG_BUS=y
 CONFIG_I2C_DEBUG_CHIP=y
-
-#
-# SPI support
-#
 # CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
 
 #
-# Dallas's 1-wire bus
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
 #
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ADM9240 is not set
-# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ADT7475 is not set
 # CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
@@ -732,158 +781,188 @@
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
 # CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_DME1737 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
 # CONFIG_SENSORS_VT1211 is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83791D is not set
 # CONFIG_SENSORS_W83792D is not set
 # CONFIG_SENSORS_W83793 is not set
 # CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
 # CONFIG_SENSORS_W83627HF is not set
 # CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
 
 #
-# Misc devices
+# Watchdog Device Drivers
 #
-# CONFIG_TIFM_CORE is not set
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_EP93XX_WATCHDOG=y
 
 #
-# LED devices
+# USB-based Watchdog Cards
 #
-# CONFIG_NEW_LEDS is not set
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
 
 #
-# LED drivers
+# Sonics Silicon Backplane
 #
+# CONFIG_SSB is not set
 
 #
-# LED Triggers
+# Multifunction device drivers
 #
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
 
 #
 # Multimedia devices
 #
-# CONFIG_VIDEO_DEV is not set
 
 #
-# Digital Video Broadcasting Devices
+# Multimedia core support
 #
-# CONFIG_DVB is not set
-# CONFIG_USB_DABUSB is not set
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
 
 #
 # Graphics support
 #
-# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
 # CONFIG_FB is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# Sound
+# Display device support
 #
+# CONFIG_DISPLAY_SUPPORT is not set
 # CONFIG_SOUND is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 # CONFIG_USB_ARCH_HAS_EHCI is not set
 CONFIG_USB=y
 CONFIG_USB_DEBUG=y
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
 
 #
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DEVICE_CLASS=y
 CONFIG_USB_DYNAMIC_MINORS=y
-# CONFIG_USB_MULTITHREAD_PROBE is not set
 # CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
 
 #
 # USB Host Controller Drivers
 #
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
 CONFIG_USB_OHCI_HCD=y
-# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
 
 #
 # USB Device Class drivers
 #
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
 #
 
 #
-# may also be needed; see USB_STORAGE Help for more information
+# also be needed; see USB_STORAGE Help for more info
 #
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
 # CONFIG_USB_STORAGE_USBAT is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 # CONFIG_USB_STORAGE_ALAUDA is not set
 # CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
 # CONFIG_USB_LIBUSUAL is not set
 
 #
-# USB Input Devices
-#
-
-#
-# USB HID Boot Protocol drivers
-#
-
-#
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
 
 #
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-CONFIG_USB_RTL8150=y
-# CONFIG_USB_USBNET_MII is not set
-# CONFIG_USB_USBNET is not set
-# CONFIG_USB_MON is not set
-
-#
 # USB port drivers
 #
-
-#
-# USB Serial Converter support
-#
 CONFIG_USB_SERIAL=y
 CONFIG_USB_SERIAL_CONSOLE=y
+# CONFIG_USB_EZUSB is not set
 # CONFIG_USB_SERIAL_GENERIC is not set
 # CONFIG_USB_SERIAL_AIRCABLE is not set
-# CONFIG_USB_SERIAL_AIRPRIME is not set
 # CONFIG_USB_SERIAL_ARK3116 is not set
 # CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
 # CONFIG_USB_SERIAL_WHITEHEAT is not set
 # CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CP210X is not set
 # CONFIG_USB_SERIAL_CYPRESS_M8 is not set
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
@@ -895,6 +974,7 @@
 # CONFIG_USB_SERIAL_EDGEPORT_TI is not set
 # CONFIG_USB_SERIAL_GARMIN is not set
 # CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
 # CONFIG_USB_SERIAL_KEYSPAN is not set
 # CONFIG_USB_SERIAL_KLSI is not set
@@ -902,16 +982,23 @@
 # CONFIG_USB_SERIAL_MCT_U232 is not set
 # CONFIG_USB_SERIAL_MOS7720 is not set
 # CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
 # CONFIG_USB_SERIAL_NAVMAN is not set
 CONFIG_USB_SERIAL_PL2303=y
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
 # CONFIG_USB_SERIAL_HP4X is not set
 # CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
 # CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_SYMBOL is not set
 # CONFIG_USB_SERIAL_TI is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
 # CONFIG_USB_SERIAL_OPTION is not set
 # CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
 # CONFIG_USB_SERIAL_DEBUG is not set
 
 #
@@ -920,38 +1007,34 @@
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
 # CONFIG_USB_ADUTUX is not set
-# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_SEVSEG is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
 # CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_FTDI_ELAN is not set
 # CONFIG_USB_APPLEDISPLAY is not set
 # CONFIG_USB_LD is not set
 # CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
 # CONFIG_USB_TEST is not set
-
-#
-# USB DSL modem support
-#
-
-#
-# USB Gadget Support
-#
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
 # CONFIG_USB_GADGET is not set
 
 #
-# MMC/SD Card support
+# OTG and related infrastructure
 #
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
 # CONFIG_MMC is not set
-
-#
-# Real Time Clock
-#
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
 CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HCTOSYS=y
@@ -965,53 +1048,88 @@
 CONFIG_RTC_INTF_PROC=y
 CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
 
 #
-# RTC drivers
+# I2C RTC drivers
 #
-# CONFIG_RTC_DRV_X1205 is not set
 CONFIG_RTC_DRV_DS1307=y
-# CONFIG_RTC_DRV_DS1553 is not set
-# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
 # CONFIG_RTC_DRV_DS1672 is not set
-# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
 # CONFIG_RTC_DRV_PCF8563 is not set
 # CONFIG_RTC_DRV_PCF8583 is not set
-# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
 CONFIG_RTC_DRV_M48T86=y
-CONFIG_RTC_DRV_EP93XX=y
-# CONFIG_RTC_DRV_PL031 is not set
-# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
 # CONFIG_RTC_DRV_V3020 is not set
 
 #
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_EP93XX=y
+# CONFIG_RTC_DRV_PL030 is not set
+# CONFIG_RTC_DRV_PL031 is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 # CONFIG_EXT3_FS_XATTR is not set
-# CONFIG_EXT4DEV_FS is not set
+# CONFIG_EXT4_FS is not set
 CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
 # 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_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 # CONFIG_ISO9660_FS is not set
@@ -1032,16 +1150,13 @@
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
 # 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
@@ -1049,33 +1164,35 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
 # CONFIG_JFFS2_SUMMARY is not set
 # CONFIG_JFFS2_FS_XATTR is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN 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_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+# CONFIG_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
@@ -1087,7 +1204,6 @@
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1109,10 +1225,7 @@
 # CONFIG_SUN_PARTITION is not set
 # CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
-
-#
-# Native Language Support
-#
+# CONFIG_SYSV68_PARTITION is not set
 CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=y
@@ -1153,49 +1266,83 @@
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
-
-#
-# Distributed Lock Manager
-#
 # CONFIG_DLM is not set
 
 #
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_UNUSED_SYMBOLS is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
 CONFIG_DEBUG_SLAB=y
 # CONFIG_DEBUG_SLAB_LEAK is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_MUTEXES=y
-# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
 # CONFIG_DEBUG_LIST is not set
-CONFIG_FRAME_POINTER=y
-CONFIG_FORCED_INLINING=y
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
 
@@ -1204,21 +1351,115 @@
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
 
 #
-# Cryptographic options
+# Crypto core or helper
 #
-# CONFIG_CRYPTO is not set
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_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
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES 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_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 CONFIG_LIBCRC32C=y
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
-CONFIG_PLIST=y
-CONFIG_IOMAP_COPY=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/kirkwood_defconfig b/arch/arm/configs/kirkwood_defconfig
index dcf8153..0a1abb9 100644
--- a/arch/arm/configs/kirkwood_defconfig
+++ b/arch/arm/configs/kirkwood_defconfig
@@ -182,6 +182,7 @@
 CONFIG_MACH_DB88F6281_BP=y
 CONFIG_MACH_RD88F6192_NAS=y
 CONFIG_MACH_RD88F6281=y
+CONFIG_MACH_MV88F6281GTW_GE=y
 CONFIG_MACH_SHEEVAPLUG=y
 CONFIG_MACH_TS219=y
 CONFIG_PLAT_ORION=y
@@ -270,7 +271,9 @@
 #
 # CPU Power Management
 #
-# CONFIG_CPU_IDLE is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
 
 #
 # Floating point emulation
diff --git a/arch/arm/configs/magician_defconfig b/arch/arm/configs/magician_defconfig
index f56837f..957fd5f 100644
--- a/arch/arm/configs/magician_defconfig
+++ b/arch/arm/configs/magician_defconfig
@@ -190,6 +190,7 @@
 # CONFIG_MACH_SAAR is not set
 # CONFIG_MACH_ARMCORE is not set
 # CONFIG_MACH_CM_X300 is not set
+CONFIG_MACH_H4700=y
 CONFIG_MACH_MAGICIAN=y
 # CONFIG_MACH_MIOA701 is not set
 # CONFIG_MACH_PCM027 is not set
@@ -828,7 +829,7 @@
 #
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
-# CONFIG_MFD_ASIC3 is not set
+CONFIG_MFD_ASIC3=y
 CONFIG_HTC_EGPIO=y
 CONFIG_HTC_PASIC3=y
 # CONFIG_TPS65010 is not set
@@ -891,7 +892,7 @@
 # CONFIG_FB_PXA_SMARTPANEL is not set
 # CONFIG_FB_PXA_PARAMETERS is not set
 # CONFIG_FB_MBX is not set
-# CONFIG_FB_W100 is not set
+CONFIG_FB_W100=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_METRONOME is not set
 # CONFIG_FB_MB862XX is not set
diff --git a/arch/arm/configs/mx21_defconfig b/arch/arm/configs/mx21_defconfig
new file mode 100644
index 0000000..4b04290
--- /dev/null
+++ b/arch/arm/configs/mx21_defconfig
@@ -0,0 +1,1170 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc1
+# Tue Apr 14 16:58:09 2009
+#
+CONFIG_ARM=y
+CONFIG_HAVE_PWM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+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_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+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=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+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_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+CONFIG_ARCH_MXC=y
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_W90X900 is not set
+
+#
+# Freescale MXC Implementations
+#
+# CONFIG_ARCH_MX1 is not set
+CONFIG_ARCH_MX2=y
+# CONFIG_ARCH_MX3 is not set
+CONFIG_MACH_MX21=y
+# CONFIG_MACH_MX27 is not set
+
+#
+# MX2 platforms:
+#
+CONFIG_MACH_MX21ADS=y
+# CONFIG_MXC_IRQ_PRIOR is not set
+CONFIG_MXC_PWM=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM 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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_UNIX is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+# 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_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_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_LIB80211 is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=3
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+CONFIG_MTD_NAND_MXC=y
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# 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_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+CONFIG_COMPAT_NET_DEV_OPS=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+CONFIG_CS89x0=y
+CONFIG_CS89x0_NONISA_IRQ=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_CONSOLE_TRANSLATIONS is not set
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_IMX=y
+CONFIG_SERIAL_IMX_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+CONFIG_I2C_IMX=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_IMX=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_MXC=y
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_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
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_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
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES 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_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/omap3_evm_defconfig b/arch/arm/configs/omap3_evm_defconfig
new file mode 100644
index 0000000..28be17f
--- /dev/null
+++ b/arch/arm/configs/omap3_evm_defconfig
@@ -0,0 +1,1528 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc5
+# Mon May 18 14:01:52 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_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=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+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=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# 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_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_W90X900 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OVERO is not set
+CONFIG_MACH_OMAP3EVM=y
+# CONFIG_MACH_OMAP3_PANDORA is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_NOKIA_RX51 is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# CONFIG_OUTER_CACHE is not set
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM 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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# 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_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_LIB80211 is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_OMAP_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+# CONFIG_MTD_ONENAND_OTP is not set
+# CONFIG_MTD_ONENAND_2X_PROGRAM is not set
+# CONFIG_MTD_ONENAND_SIM is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+CONFIG_COMPAT_NET_DEV_OPS=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+CONFIG_SMC911X=y
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+CONFIG_TWL4030_CORE=y
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=y
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ZERO_HNPTEST is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_ISP1301_OMAP is not set
+CONFIG_TWL4030_USB=y
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+CONFIG_MMC_OMAP_HS=m
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+CONFIG_REGULATOR_TWL4030=y
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO 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_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_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=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# 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=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# 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=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES 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_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/omap_4430sdp_defconfig b/arch/arm/configs/omap_4430sdp_defconfig
new file mode 100644
index 0000000..23e43ea
--- /dev/null
+++ b/arch/arm/configs/omap_4430sdp_defconfig
@@ -0,0 +1,866 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc7
+# Tue Jun  9 12:36:23 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_CLK=y
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+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=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# 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_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
+CONFIG_ARCH_OMAP4=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_MUX is not set
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_4430SDP=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_DISABLE=y
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+CONFIG_ARM_GIC=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_SMP=y
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=2
+# CONFIG_HOTPLUG_CPU is not set
+CONFIG_LOCAL_TIMERS=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM 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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_UNEVICTABLE_LRU is not set
+CONFIG_HAVE_MLOCK=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 rw mem=128M console=ttyS0,115200n8 initrd=0x81600000,20M ramdisk_size=20480"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+# CONFIG_NEON is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# 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_ATA is not set
+# CONFIG_MD is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+CONFIG_PRINT_QUOTA_WARNING=y
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_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_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_ARM_UNWIND is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# 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=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES 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_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=y
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/omap_zoom2_defconfig b/arch/arm/configs/omap_zoom2_defconfig
new file mode 100644
index 0000000..213fe9c
--- /dev/null
+++ b/arch/arm/configs/omap_zoom2_defconfig
@@ -0,0 +1,1211 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc5
+# Fri Oct 10 11:49:41 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=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_COMPAT_BRK=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_VM_EVENT_COUNTERS=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=y
+# CONFIG_KPROBES is not set
+# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+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=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+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_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# 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_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+# CONFIG_MACH_OMAP_LDP is not set
+CONFIG_MACH_OMAP_ZOOM2=y
+# CONFIG_MACH_OVERO is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE 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_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+# CONFIG_NEON is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# 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_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+CONFIG_W1=y
+
+#
+# 1-wire Bus Masters
+#
+# CONFIG_W1_MASTER_DS2482 is not set
+# CONFIG_W1_MASTER_DS1WM is not set
+# CONFIG_W1_MASTER_GPIO is not set
+
+#
+# 1-wire Slaves
+#
+# CONFIG_W1_SLAVE_THERM is not set
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+# CONFIG_W1_SLAVE_DS2760 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_SPI=y
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO 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_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS 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_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_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=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_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=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# 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=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES 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_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=y
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/orion5x_defconfig b/arch/arm/configs/orion5x_defconfig
index 5b98f76..9e23852 100644
--- a/arch/arm/configs/orion5x_defconfig
+++ b/arch/arm/configs/orion5x_defconfig
@@ -903,7 +903,8 @@
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=16
 # CONFIG_IPMI_HANDLER is not set
-# CONFIG_HW_RANDOM is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_TIMERIOMEM=m
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 # CONFIG_RAW_DRIVER is not set
diff --git a/arch/arm/configs/rx51_defconfig b/arch/arm/configs/rx51_defconfig
index 593102da..eb2cb31 100644
--- a/arch/arm/configs/rx51_defconfig
+++ b/arch/arm/configs/rx51_defconfig
@@ -282,7 +282,7 @@
 #
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="init=/sbin/preinit ubi.mtd=4 root=ubi0:rootfs rootfstype=ubifs rw console=ttyMTD5"
+CONFIG_CMDLINE="init=/sbin/preinit ubi.mtd=rootfs root=ubi0:rootfs rootfstype=ubifs rootflags=bulk_read,no_chk_data_crc rw console=ttyMTD,log console=tty0"
 # CONFIG_XIP_KERNEL is not set
 # CONFIG_KEXEC is not set
 
diff --git a/arch/arm/configs/stmp378x_defconfig b/arch/arm/configs/stmp378x_defconfig
new file mode 100644
index 0000000..44461f1
--- /dev/null
+++ b/arch/arm/configs/stmp378x_defconfig
@@ -0,0 +1,1141 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc2
+# Thu Apr 23 02:44:13 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION="-default"
+CONFIG_LOCALVERSION_AUTO=y
+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_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_INITRAMFS_COMPRESSION_NONE is not set
+CONFIG_INITRAMFS_COMPRESSION_GZIP=y
+# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
+# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_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_TRACEPOINTS=y
+CONFIG_MARKERS=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_W90X900 is not set
+CONFIG_ARCH_STMP3XXX=y
+
+#
+# Freescale STMP3xxx implementations
+#
+# CONFIG_ARCH_STMP37XX is not set
+CONFIG_ARCH_STMP378X=y
+# CONFIG_MACH_STMP37XX is not set
+CONFIG_MACH_STMP378X=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_HIGHMEM=y
+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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttySDBG0,115200 mem=32M"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# 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_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_DRR is not set
+
+#
+# Classification
+#
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_FW is not set
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_DROP_MONITOR is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_STANDALONE is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_PARTITIONS is not set
+# CONFIG_MTD_TESTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_BLKDEVS is not set
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+CONFIG_MTD_UBI_GLUEBI=y
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+CONFIG_BLK_DEV_RAM_SIZE=6144
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+CONFIG_INPUT_POLLDEV=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+# CONFIG_VIDEO_ALLOW_V4L1 is not set
+# CONFIG_VIDEO_V4L1_COMPAT is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+
+#
+# RDS decoders
+#
+
+#
+# Video decoders
+#
+
+#
+# Video and audio decoders
+#
+
+#
+# MPEG video encoders
+#
+# CONFIG_VIDEO_CX2341X is not set
+
+#
+# Video encoders
+#
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+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_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=m
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_SELFTEST=y
+CONFIG_DEBUG_OBJECTS_FREE=y
+CONFIG_DEBUG_OBJECTS_TIMERS=y
+CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_SLAB_LEAK=y
+CONFIG_DEBUG_PREEMPT=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_PI_LIST=y
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_LOCKDEP=y
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_LOCKDEP is not set
+CONFIG_TRACE_IRQFLAGS=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+CONFIG_DEBUG_KOBJECT=y
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_PAGE_POISONING is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+CONFIG_FUNCTION_TRACER=y
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+CONFIG_CONTEXT_SWITCH_TRACER=y
+# CONFIG_EVENT_TRACER is not set
+CONFIG_BOOT_TRACER=y
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_STACK_TRACER=y
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+CONFIG_SECURITY=y
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+# CONFIG_SECURITY_TOMOYO is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_TEST=m
+
+#
+# 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=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# 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=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+CONFIG_BINARY_PRINTF=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/stmp37xx_defconfig b/arch/arm/configs/stmp37xx_defconfig
new file mode 100644
index 0000000..401279d
--- /dev/null
+++ b/arch/arm/configs/stmp37xx_defconfig
@@ -0,0 +1,1002 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29.1
+# Mon Apr 20 04:41:26 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION="-default"
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_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_TRACEPOINTS=y
+CONFIG_MARKERS=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_W90X900 is not set
+CONFIG_ARCH_STMP3XXX=y
+
+#
+# Freescale STMP3xxx implementations
+#
+CONFIG_ARCH_STMP37XX=y
+# CONFIG_ARCH_STMP378X is not set
+CONFIG_MACH_STMP37XX=y
+# CONFIG_MACH_STMP378X is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL 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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttySDBG0,115200 mem=32M lcd_panel=lms350 rdinit=/bin/sh ignore_loglevel"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# 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_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_DRR is not set
+
+#
+# Classification
+#
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_FW is not set
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+CONFIG_FIB_RULES=y
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_STANDALONE is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+CONFIG_BLK_DEV_RAM_SIZE=6144
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+CONFIG_INPUT_POLLDEV=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_STMP_DBG is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+# CONFIG_VIDEO_ALLOW_V4L1 is not set
+# CONFIG_VIDEO_V4L1_COMPAT is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+
+#
+# Video decoders
+#
+
+#
+# Video and audio decoders
+#
+
+#
+# MPEG video encoders
+#
+# CONFIG_VIDEO_CX2341X is not set
+
+#
+# Video encoders
+#
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+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_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=m
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+
+#
+# Tracers
+#
+CONFIG_FUNCTION_TRACER=y
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_BOOT_TRACER=y
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_STACK_TRACER=y
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+CONFIG_SECURITY=y
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# 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=m
+
+#
+# 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=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# 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=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/u300_defconfig b/arch/arm/configs/u300_defconfig
new file mode 100644
index 0000000..2d827e1
--- /dev/null
+++ b/arch/arm/configs/u300_defconfig
@@ -0,0 +1,1115 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc6
+# Mon Jun  1 09:18:22 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+# CONFIG_AIO is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+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_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_U300=y
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# ST-Ericsson AB U300/U330/U335/U365 Platform
+#
+
+#
+# ST-Ericsson Mobile Platform Products
+#
+CONFIG_MACH_U300=y
+
+#
+# ST-Ericsson U300/U330/U335/U365 Feature Selections
+#
+# CONFIG_MACH_U300_BS2X is not set
+# CONFIG_MACH_U300_BS330 is not set
+CONFIG_MACH_U300_BS335=y
+# CONFIG_MACH_U300_BS365 is not set
+# CONFIG_MACH_U300_SINGLE_RAM is not set
+CONFIG_MACH_U300_DUAL_RAM=y
+CONFIG_U300_DEBUG=y
+# CONFIG_MACH_U300_SEMI_IS_SHARED is not set
+
+#
+# All the settings below must match the bootloader's settings
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
+CONFIG_ARM_VIC=y
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM 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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/mtdblock2 rw rootfstype=yaffs2 console=ttyAMA0,115200n8 ab3100.force=0,0x48 mtdparts=u300nand:128k@0x0(bootrecords)ro,8064k@128k(free)ro,253952k@8192k(platform) lpj=515072"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_SUSPEND is not set
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+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_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# 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_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_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD 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_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# 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_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_ARMCLCD is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_LOGO is not set
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG 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_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+# CONFIG_SOUND_PRIME is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_ARMMMCI=y
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_GPIO is not set
+# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_BD2802 is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PL030 is not set
+# CONFIG_RTC_DRV_PL031 is not set
+CONFIG_DMADEVICES=y
+
+#
+# DMA Devices
+#
+# CONFIG_AUXDISPLAY is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=y
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS 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_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_NETWORK_FILESYSTEMS 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
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+# CONFIG_CRC32 is not set
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/w90p910_defconfig b/arch/arm/configs/w90p910_defconfig
index 56bda7c..5245655 100644
--- a/arch/arm/configs/w90p910_defconfig
+++ b/arch/arm/configs/w90p910_defconfig
@@ -1,11 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.27-rc8-git8
-# Sat Nov 15 10:05:00 2008
+# Linux kernel version: 2.6.30
+# Wed Jun 10 22:09:25 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
-# CONFIG_GENERIC_GPIO is not set
+CONFIG_GENERIC_GPIO=y
 # CONFIG_GENERIC_TIME is not set
 # CONFIG_GENERIC_CLOCKEVENTS is not set
 CONFIG_MMU=y
@@ -22,8 +22,6 @@
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_ARCH_SUPPORTS_AOUT=y
-CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -42,10 +40,19 @@
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=17
-# CONFIG_CGROUPS is not set
 # CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
@@ -56,52 +63,53 @@
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+# CONFIG_INITRAMFS_COMPRESSION_NONE is not set
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
+# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 # CONFIG_EMBEDDED is not set
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
-CONFIG_COMPAT_BRK=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_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_TRACEPOINTS=y
 # CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
-# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
-# CONFIG_HAVE_IOREMAP_PROT is not set
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
-# CONFIG_HAVE_ARCH_TRACEHOOK is not set
-# CONFIG_HAVE_DMA_ATTRS is not set
-# CONFIG_USE_GENERIC_SMP_HELPERS is not set
-# CONFIG_HAVE_CLK is not set
-CONFIG_PROC_PAGE_MONITOR=y
+# CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
 # CONFIG_MODULES is not set
 CONFIG_BLOCK=y
 CONFIG_LBD=y
-CONFIG_BLK_DEV_IO_TRACE=y
-CONFIG_LSF=y
 CONFIG_BLK_DEV_BSG=y
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -117,7 +125,7 @@
 CONFIG_DEFAULT_CFQ=y
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="cfq"
-CONFIG_CLASSIC_RCU=y
+# CONFIG_FREEZER is not set
 
 #
 # System Type
@@ -127,10 +135,10 @@
 # CONFIG_ARCH_REALVIEW is not set
 # CONFIG_ARCH_VERSATILE is not set
 # CONFIG_ARCH_AT91 is not set
-# CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_GEMINI is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_NETX is not set
 # CONFIG_ARCH_H720X is not set
@@ -151,23 +159,17 @@
 # CONFIG_ARCH_ORION5X is not set
 # CONFIG_ARCH_PNX4008 is not set
 # CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MMP is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
 # CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM7X00A is not set
+# CONFIG_ARCH_MSM is not set
 CONFIG_ARCH_W90X900=y
-
-#
-# Boot options
-#
-
-#
-# Power management
-#
 CONFIG_CPU_W90P910=y
 
 #
@@ -198,6 +200,7 @@
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 # CONFIG_CPU_CACHE_ROUND_ROBIN is not set
 # CONFIG_OUTER_CACHE is not set
+CONFIG_COMMON_CLKDEV=y
 
 #
 # Bus support
@@ -209,27 +212,32 @@
 #
 # Kernel Features
 #
-# CONFIG_TICK_ONESHOT is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
 CONFIG_PREEMPT=y
 CONFIG_HZ=100
 CONFIG_AEABI=y
 CONFIG_OABI_COMPAT=y
-CONFIG_ARCH_FLATMEM_HAS_HOLES=y
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# CONFIG_ARCH_HAS_HOLES_MEMORYMODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM 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=4096
-# CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -237,12 +245,17 @@
 #
 CONFIG_ZBOOT_ROM_TEXT=0
 CONFIG_ZBOOT_ROM_BSS=0
-CONFIG_CMDLINE="root=/dev/ram0 console=ttyS0,115200n8 initrd=0xa00000,4000000 mem=64M"
+CONFIG_CMDLINE="root=/dev/ram0 console=ttyS0,115200n8 rdinit=/sbin/init mem=64M"
 # CONFIG_XIP_KERNEL is not set
 CONFIG_KEXEC=y
 CONFIG_ATAGS_PROC=y
 
 #
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
 # Floating point emulation
 #
 
@@ -258,6 +271,8 @@
 # Userspace binary formats
 #
 CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
 
@@ -282,11 +297,93 @@
 CONFIG_FIRMWARE_IN_KERNEL=y
 CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=16384
@@ -300,9 +397,41 @@
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_DMA is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
 
@@ -354,38 +483,57 @@
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+# CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_W90X900=y
-# CONFIG_SERIAL_W90X900_PORT1 is not set
-# CONFIG_SERIAL_W90X900_PORT2 is not set
-# CONFIG_SERIAL_W90X900_PORT3 is not set
-# CONFIG_SERIAL_W90X900_PORT4 is not set
-CONFIG_SERIAL_W90X900_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
-# CONFIG_NVRAM is not set
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
 # CONFIG_I2C is not set
 # CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
 # CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
 
 #
 # Sonics Silicon Backplane
 #
-CONFIG_SSB_POSSIBLE=y
 # CONFIG_SSB is not set
 
 #
@@ -393,10 +541,11 @@
 #
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_MFD_TMIO is not set
-# CONFIG_MFD_T7L66XB is not set
-# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
 
 #
 # Multimedia devices
@@ -433,33 +582,131 @@
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_SOUND is not set
 # CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
 # CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
 # CONFIG_NEW_LEDS is not set
 CONFIG_RTC_LIB=y
 # CONFIG_RTC_CLASS is not set
 # CONFIG_DMADEVICES is not set
-
-#
-# Voltage and Current regulators
-#
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_REGULATOR is not set
-# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
-# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
-# CONFIG_REGULATOR_BQ24022 is not set
 # CONFIG_UIO is not set
+# CONFIG_STAGING is not set
 
 #
 # File systems
 #
 # CONFIG_EXT2_FS is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_EXT4DEV_FS is not set
+# CONFIG_EXT4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
 # CONFIG_GFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
 # CONFIG_DNOTIFY is not set
 # CONFIG_INOTIFY is not set
 # CONFIG_QUOTA is not set
@@ -469,6 +716,11 @@
 CONFIG_GENERIC_ACL=y
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 # CONFIG_ISO9660_FS is not set
@@ -486,15 +738,13 @@
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
 # 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
@@ -502,15 +752,22 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS 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=y
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 
 #
 # Partition Types
@@ -586,18 +843,36 @@
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 # CONFIG_DEBUG_KERNEL is not set
+CONFIG_STACKTRACE=y
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_MEMORY_INIT=y
-CONFIG_FRAME_POINTER=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_LATENCYTOP is not set
 # CONFIG_SYSCTL_SYSCALL_CHECK is not set
-CONFIG_HAVE_FTRACE=y
-CONFIG_HAVE_DYNAMIC_FTRACE=y
-# CONFIG_FTRACE is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_ARM_UNWIND=y
 # CONFIG_DEBUG_USER is not set
 
 #
@@ -605,14 +880,15 @@
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 # CONFIG_CRYPTO is not set
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
 #
-# CONFIG_GENERIC_FIND_FIRST_BIT is not set
-# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_GENERIC_FIND_LAST_BIT=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
@@ -620,7 +896,10 @@
 # CONFIG_CRC32 is not set
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
-CONFIG_PLIST=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h
index 16b52f3..9e07fe5 100644
--- a/arch/arm/include/asm/atomic.h
+++ b/arch/arm/include/asm/atomic.h
@@ -249,6 +249,6 @@
 #define smp_mb__before_atomic_inc()	smp_mb()
 #define smp_mb__after_atomic_inc()	smp_mb()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif
 #endif
diff --git a/arch/arm/include/asm/bitsperlong.h b/arch/arm/include/asm/bitsperlong.h
new file mode 100644
index 0000000..6dc0bb0
--- /dev/null
+++ b/arch/arm/include/asm/bitsperlong.h
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index bb7d695..1a711ea 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -429,6 +429,14 @@
 		__flush_anon_page(vma, page, vmaddr);
 }
 
+#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
+static inline void flush_kernel_dcache_page(struct page *page)
+{
+	/* highmem pages are always flushed upon kunmap already */
+	if ((cache_is_vivt() || cache_is_vipt_aliasing()) && !PageHighMem(page))
+		__cpuc_flush_dcache_page(page_address(page));
+}
+
 #define flush_dcache_mmap_lock(mapping) \
 	spin_lock_irq(&(mapping)->tree_lock)
 #define flush_dcache_mmap_unlock(mapping) \
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index 7b9d27e..b3e656c 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -8,6 +8,21 @@
 #define CPUID_TCM	2
 #define CPUID_TLBTYPE	3
 
+#define CPUID_EXT_PFR0	"c1, 0"
+#define CPUID_EXT_PFR1	"c1, 1"
+#define CPUID_EXT_DFR0	"c1, 2"
+#define CPUID_EXT_AFR0	"c1, 3"
+#define CPUID_EXT_MMFR0	"c1, 4"
+#define CPUID_EXT_MMFR1	"c1, 5"
+#define CPUID_EXT_MMFR2	"c1, 6"
+#define CPUID_EXT_MMFR3	"c1, 7"
+#define CPUID_EXT_ISAR0	"c2, 0"
+#define CPUID_EXT_ISAR1	"c2, 1"
+#define CPUID_EXT_ISAR2	"c2, 2"
+#define CPUID_EXT_ISAR3	"c2, 3"
+#define CPUID_EXT_ISAR4	"c2, 4"
+#define CPUID_EXT_ISAR5	"c2, 5"
+
 #ifdef CONFIG_CPU_CP15
 #define read_cpuid(reg)							\
 	({								\
@@ -18,9 +33,19 @@
 		    : "cc");						\
 		__val;							\
 	})
+#define read_cpuid_ext(ext_reg)						\
+	({								\
+		unsigned int __val;					\
+		asm("mrc	p15, 0, %0, c0, " ext_reg		\
+		    : "=r" (__val)					\
+		    :							\
+		    : "cc");						\
+		__val;							\
+	})
 #else
 extern unsigned int processor_id;
 #define read_cpuid(reg) (processor_id)
+#define read_cpuid_ext(reg) 0
 #endif
 
 /*
diff --git a/arch/arm/include/asm/hardware/arm_twd.h b/arch/arm/include/asm/hardware/arm_twd.h
deleted file mode 100644
index e521b70..0000000
--- a/arch/arm/include/asm/hardware/arm_twd.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __ASM_HARDWARE_TWD_H
-#define __ASM_HARDWARE_TWD_H
-
-#define TWD_TIMER_LOAD 			0x00
-#define TWD_TIMER_COUNTER		0x04
-#define TWD_TIMER_CONTROL		0x08
-#define TWD_TIMER_INTSTAT		0x0C
-
-#define TWD_WDOG_LOAD			0x20
-#define TWD_WDOG_COUNTER		0x24
-#define TWD_WDOG_CONTROL		0x28
-#define TWD_WDOG_INTSTAT		0x2C
-#define TWD_WDOG_RESETSTAT		0x30
-#define TWD_WDOG_DISABLE		0x34
-
-#define TWD_TIMER_CONTROL_ENABLE	(1 << 0)
-#define TWD_TIMER_CONTROL_ONESHOT	(0 << 1)
-#define TWD_TIMER_CONTROL_PERIODIC	(1 << 1)
-#define TWD_TIMER_CONTROL_IT_ENABLE	(1 << 2)
-
-#endif
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index 64f2252..cdb9022 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -24,6 +24,8 @@
 #define L2X0_CACHE_TYPE			0x004
 #define L2X0_CTRL			0x100
 #define L2X0_AUX_CTRL			0x104
+#define L2X0_TAG_LATENCY_CTRL		0x108
+#define L2X0_DATA_LATENCY_CTRL		0x10C
 #define L2X0_EVENT_CNT_CTRL		0x200
 #define L2X0_EVENT_CNT1_CFG		0x204
 #define L2X0_EVENT_CNT0_CFG		0x208
diff --git a/arch/arm/include/asm/hardware/pl080.h b/arch/arm/include/asm/hardware/pl080.h
new file mode 100644
index 0000000..6a6c66b
--- /dev/null
+++ b/arch/arm/include/asm/hardware/pl080.h
@@ -0,0 +1,138 @@
+/* arch/arm/include/asm/hardware/pl080.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      http://armlinux.simtec.co.uk/
+ *      Ben Dooks <ben@simtec.co.uk>
+ *
+ * ARM PrimeCell PL080 DMA controller
+ *
+ * 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.
+*/
+
+/* Note, there are some Samsung updates to this controller block which
+ * make it not entierly compatible with the PL080 specification from
+ * ARM. When in doubt, check the Samsung documentation first.
+ *
+ * The Samsung defines are PL080S, and add an extra controll register,
+ * the ability to move more than 2^11 counts of data and some extra
+ * OneNAND features.
+*/
+
+#define PL080_INT_STATUS			(0x00)
+#define PL080_TC_STATUS				(0x04)
+#define PL080_TC_CLEAR				(0x08)
+#define PL080_ERR_STATUS			(0x0C)
+#define PL080_ERR_CLEAR				(0x10)
+#define PL080_RAW_TC_STATUS			(0x14)
+#define PL080_RAW_ERR_STATUS			(0x18)
+#define PL080_EN_CHAN				(0x1c)
+#define PL080_SOFT_BREQ				(0x20)
+#define PL080_SOFT_SREQ				(0x24)
+#define PL080_SOFT_LBREQ			(0x28)
+#define PL080_SOFT_LSREQ			(0x2C)
+
+#define PL080_CONFIG				(0x30)
+#define PL080_CONFIG_M2_BE			(1 << 2)
+#define PL080_CONFIG_M1_BE			(1 << 1)
+#define PL080_CONFIG_ENABLE			(1 << 0)
+
+#define PL080_SYNC				(0x34)
+
+/* Per channel configuration registers */
+
+#define PL008_Cx_STRIDE				(0x20)
+#define PL080_Cx_BASE(x)			((0x100 + (x * 0x20)))
+#define PL080_Cx_SRC_ADDR(x)			((0x100 + (x * 0x20)))
+#define PL080_Cx_DST_ADDR(x)			((0x104 + (x * 0x20)))
+#define PL080_Cx_LLI(x)				((0x108 + (x * 0x20)))
+#define PL080_Cx_CONTROL(x)			((0x10C + (x * 0x20)))
+#define PL080_Cx_CONFIG(x)			((0x110 + (x * 0x20)))
+#define PL080S_Cx_CONTROL2(x)			((0x110 + (x * 0x20)))
+#define PL080S_Cx_CONFIG(x)			((0x114 + (x * 0x20)))
+
+#define PL080_CH_SRC_ADDR			(0x00)
+#define PL080_CH_DST_ADDR			(0x04)
+#define PL080_CH_LLI				(0x08)
+#define PL080_CH_CONTROL			(0x0C)
+#define PL080_CH_CONFIG				(0x10)
+#define PL080S_CH_CONTROL2			(0x10)
+#define PL080S_CH_CONFIG			(0x14)
+
+#define PL080_LLI_ADDR_MASK			(0x3fffffff << 2)
+#define PL080_LLI_ADDR_SHIFT			(2)
+#define PL080_LLI_LM_AHB2			(1 << 0)
+
+#define PL080_CONTROL_TC_IRQ_EN			(1 << 31)
+#define PL080_CONTROL_PROT_MASK			(0x7 << 28)
+#define PL080_CONTROL_PROT_SHIFT		(28)
+#define PL080_CONTROL_PROT_SYS			(1 << 28)
+#define PL080_CONTROL_DST_INCR			(1 << 27)
+#define PL080_CONTROL_SRC_INCR			(1 << 26)
+#define PL080_CONTROL_DST_AHB2			(1 << 25)
+#define PL080_CONTROL_SRC_AHB2			(1 << 24)
+#define PL080_CONTROL_DWIDTH_MASK		(0x7 << 21)
+#define PL080_CONTROL_DWIDTH_SHIFT		(21)
+#define PL080_CONTROL_SWIDTH_MASK		(0x7 << 18)
+#define PL080_CONTROL_SWIDTH_SHIFT		(18)
+#define PL080_CONTROL_DB_SIZE_MASK		(0x7 << 15)
+#define PL080_CONTROL_DB_SIZE_SHIFT		(15)
+#define PL080_CONTROL_SB_SIZE_MASK		(0x7 << 12)
+#define PL080_CONTROL_SB_SIZE_SHIFT		(12)
+#define PL080_CONTROL_TRANSFER_SIZE_MASK	(0xfff << 0)
+#define PL080_CONTROL_TRANSFER_SIZE_SHIFT	(0)
+
+#define PL080_BSIZE_1				(0x0)
+#define PL080_BSIZE_4				(0x1)
+#define PL080_BSIZE_8				(0x2)
+#define PL080_BSIZE_16				(0x3)
+#define PL080_BSIZE_32				(0x4)
+#define PL080_BSIZE_64				(0x5)
+#define PL080_BSIZE_128				(0x6)
+#define PL080_BSIZE_256				(0x7)
+
+#define PL080_WIDTH_8BIT			(0x0)
+#define PL080_WIDTH_16BIT			(0x1)
+#define PL080_WIDTH_32BIT			(0x2)
+
+#define PL080_CONFIG_HALT			(1 << 18)
+#define PL080_CONFIG_ACTIVE			(1 << 17)  /* RO */
+#define PL080_CONFIG_LOCK			(1 << 16)
+#define PL080_CONFIG_TC_IRQ_MASK		(1 << 15)
+#define PL080_CONFIG_ERR_IRQ_MASK		(1 << 14)
+#define PL080_CONFIG_FLOW_CONTROL_MASK		(0x7 << 11)
+#define PL080_CONFIG_FLOW_CONTROL_SHIFT		(11)
+#define PL080_CONFIG_DST_SEL_MASK		(0xf << 6)
+#define PL080_CONFIG_DST_SEL_SHIFT		(6)
+#define PL080_CONFIG_SRC_SEL_MASK		(0xf << 1)
+#define PL080_CONFIG_SRC_SEL_SHIFT		(1)
+#define PL080_CONFIG_ENABLE			(1 << 0)
+
+#define PL080_FLOW_MEM2MEM			(0x0)
+#define PL080_FLOW_MEM2PER			(0x1)
+#define PL080_FLOW_PER2MEM			(0x2)
+#define PL080_FLOW_SRC2DST			(0x3)
+#define PL080_FLOW_SRC2DST_DST			(0x4)
+#define PL080_FLOW_MEM2PER_PER			(0x5)
+#define PL080_FLOW_PER2MEM_PER			(0x6)
+#define PL080_FLOW_SRC2DST_SRC			(0x7)
+
+/* DMA linked list chain structure */
+
+struct pl080_lli {
+	u32	src_addr;
+	u32	dst_addr;
+	u32	next_lli;
+	u32	control0;
+};
+
+struct pl080s_lli {
+	u32	src_addr;
+	u32	dst_addr;
+	u32	next_lli;
+	u32	control0;
+	u32	control1;
+};
+
diff --git a/arch/arm/include/asm/hardware/sharpsl_pm.h b/arch/arm/include/asm/hardware/sharpsl_pm.h
deleted file mode 100644
index 2d00db2..0000000
--- a/arch/arm/include/asm/hardware/sharpsl_pm.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * SharpSL Battery/PM Driver
- *
- * Copyright (c) 2004-2005 Richard Purdie
- *
- * 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/interrupt.h>
-
-struct sharpsl_charger_machinfo {
-	void (*init)(void);
-	void (*exit)(void);
-	int gpio_acin;
-	int gpio_batfull;
-	int batfull_irq;
-	int gpio_batlock;
-	int gpio_fatal;
-	void (*discharge)(int);
-	void (*discharge1)(int);
-	void (*charge)(int);
-	void (*measure_temp)(int);
-	void (*presuspend)(void);
-	void (*postsuspend)(void);
-	void (*earlyresume)(void);
-	unsigned long (*read_devdata)(int);
-#define SHARPSL_BATT_VOLT       1
-#define SHARPSL_BATT_TEMP       2
-#define SHARPSL_ACIN_VOLT       3
-#define SHARPSL_STATUS_ACIN     4
-#define SHARPSL_STATUS_LOCK     5
-#define SHARPSL_STATUS_CHRGFULL 6
-#define SHARPSL_STATUS_FATAL    7
-	unsigned long (*charger_wakeup)(void);
-	int (*should_wakeup)(unsigned int resume_on_alarm);
-	void (*backlight_limit)(int);
-	int (*backlight_get_status) (void);
-	int charge_on_volt;
-	int charge_on_temp;
-	int charge_acin_high;
-	int charge_acin_low;
-	int fatal_acin_volt;
-	int fatal_noacin_volt;
-	int bat_levels;
-	struct battery_thresh *bat_levels_noac;
-	struct battery_thresh *bat_levels_acin;
-	struct battery_thresh *bat_levels_noac_bl;
-	struct battery_thresh *bat_levels_acin_bl;
-	int status_high_acin;
-	int status_low_acin;
-	int status_high_noac;
-	int status_low_noac;
-};
-
-struct battery_thresh {
-	int voltage;
-	int percentage;
-};
-
-struct battery_stat {
-	int ac_status;         /* APM AC Present/Not Present */
-	int mainbat_status;    /* APM Main Battery Status */
-	int mainbat_percent;   /* Main Battery Percentage Charge */
-	int mainbat_voltage;   /* Main Battery Voltage */
-};
-
-struct sharpsl_pm_status {
-	struct device *dev;
-	struct timer_list ac_timer;
-	struct timer_list chrg_full_timer;
-
-	int charge_mode;
-#define CHRG_ERROR    (-1)
-#define CHRG_OFF      (0)
-#define CHRG_ON       (1)
-#define CHRG_DONE     (2)
-
-	unsigned int flags;
-#define SHARPSL_SUSPENDED       (1 << 0)  /* Device is Suspended */
-#define SHARPSL_ALARM_ACTIVE    (1 << 1)  /* Alarm is for charging event (not user) */
-#define SHARPSL_BL_LIMIT        (1 << 2)  /* Backlight Intensity Limited */
-#define SHARPSL_APM_QUEUED      (1 << 3)  /* APM Event Queued */
-#define SHARPSL_DO_OFFLINE_CHRG (1 << 4)  /* Trigger the offline charger */
-
-	int full_count;
-	unsigned long charge_start_time;
-	struct sharpsl_charger_machinfo *machinfo;
-	struct battery_stat battstat;
-};
-
-extern struct sharpsl_pm_status sharpsl_pm;
-
-
-#define SHARPSL_LED_ERROR  2
-#define SHARPSL_LED_ON     1
-#define SHARPSL_LED_OFF    0
-
-void sharpsl_battery_kick(void);
-void sharpsl_pm_led(int val);
-irqreturn_t sharpsl_ac_isr(int irq, void *dev_id);
-irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id);
-irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id);
-
diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
index f87328d..5d72550 100644
--- a/arch/arm/include/asm/hardware/vic.h
+++ b/arch/arm/include/asm/hardware/vic.h
@@ -41,7 +41,7 @@
 #define VIC_PL192_VECT_ADDR		0xF00
 
 #ifndef __ASSEMBLY__
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources);
+void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
 #endif
 
 #endif
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
new file mode 100644
index 0000000..50c7e7c
--- /dev/null
+++ b/arch/arm/include/asm/localtimer.h
@@ -0,0 +1,63 @@
+/*
+ *  arch/arm/include/asm/localtimer.h
+ *
+ *  Copyright (C) 2004-2005 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.
+ */
+#ifndef __ASM_ARM_LOCALTIMER_H
+#define __ASM_ARM_LOCALTIMER_H
+
+struct clock_event_device;
+
+/*
+ * Setup a per-cpu timer, whether it be a local timer or dummy broadcast
+ */
+void percpu_timer_setup(void);
+
+/*
+ * Called from assembly, this is the local timer IRQ handler
+ */
+asmlinkage void do_local_timer(struct pt_regs *);
+
+
+#ifdef CONFIG_LOCAL_TIMERS
+
+#ifdef CONFIG_HAVE_ARM_TWD
+
+#include "smp_twd.h"
+
+#define local_timer_ack()	twd_timer_ack()
+#define local_timer_stop()	twd_timer_stop()
+
+#else
+
+/*
+ * Platform provides this to acknowledge a local timer IRQ.
+ * Returns true if the local timer IRQ is to be processed.
+ */
+int local_timer_ack(void);
+
+/*
+ * Stop a local timer interrupt.
+ */
+void local_timer_stop(void);
+
+#endif
+
+/*
+ * Setup a local timer interrupt for a CPU.
+ */
+void local_timer_setup(struct clock_event_device *);
+
+#else
+
+static inline void local_timer_stop(void)
+{
+}
+
+#endif
+
+#endif
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index 58cf91f..742c2aa 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -30,6 +30,14 @@
 
 #ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
+
+struct mem_type;
+extern const struct mem_type *get_mem_type(unsigned int type);
+/*
+ * external interface to remap single page with appropriate type
+ */
+extern int ioremap_page(unsigned long virt, unsigned long phys,
+			const struct mem_type *mtype);
 #else
 #define iotable_init(map,num)	do { } while (0)
 #endif
diff --git a/arch/arm/include/asm/mman.h b/arch/arm/include/asm/mman.h
index 54570d2..fc26976 100644
--- a/arch/arm/include/asm/mman.h
+++ b/arch/arm/include/asm/mman.h
@@ -1,7 +1,7 @@
 #ifndef __ARM_MMAN_H__
 #define __ARM_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index 7b52277..be962c1 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -202,6 +202,6 @@
 	(((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
 	 VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 110295c..1cd2d64 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -342,7 +342,7 @@
 	return __va(ptr);
 }
 
-#define pmd_page(pmd) virt_to_page(__va(pmd_val(pmd)))
+#define pmd_page(pmd)		pfn_to_page(__phys_to_pfn(pmd_val(pmd)))
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index 1845892..6a89567 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -71,6 +71,7 @@
 		regs->ARM_cpsr = USR26_MODE;				\
 	if (elf_hwcap & HWCAP_THUMB && pc & 1)				\
 		regs->ARM_cpsr |= PSR_T_BIT;				\
+	regs->ARM_cpsr |= PSR_ENDSTATE;					\
 	regs->ARM_pc = pc & ~1;		/* pc */			\
 	regs->ARM_sp = sp;		/* sp */			\
 	regs->ARM_r2 = stack[2];	/* r2 (envp) */			\
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 236a06b..67b833c 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -50,6 +50,7 @@
 #define PSR_F_BIT	0x00000040
 #define PSR_I_BIT	0x00000080
 #define PSR_A_BIT	0x00000100
+#define PSR_E_BIT	0x00000200
 #define PSR_J_BIT	0x01000000
 #define PSR_Q_BIT	0x08000000
 #define PSR_V_BIT	0x10000000
@@ -65,6 +66,22 @@
 #define PSR_x		0x0000ff00	/* Extension		*/
 #define PSR_c		0x000000ff	/* Control		*/
 
+/*
+ * ARMv7 groups of APSR bits
+ */
+#define PSR_ISET_MASK	0x01000010	/* ISA state (J, T) mask */
+#define PSR_IT_MASK	0x0600fc00	/* If-Then execution state mask */
+#define PSR_ENDIAN_MASK	0x00000200	/* Endianness state mask */
+
+/*
+ * Default endianness state
+ */
+#ifdef CONFIG_CPU_ENDIAN_BE8
+#define PSR_ENDSTATE	PSR_E_BIT
+#else
+#define PSR_ENDSTATE	0
+#endif
+
 #ifndef __ASSEMBLY__
 
 /*
diff --git a/arch/arm/include/asm/signal.h b/arch/arm/include/asm/signal.h
index d0fb487..43ba0fb 100644
--- a/arch/arm/include/asm/signal.h
+++ b/arch/arm/include/asm/signal.h
@@ -111,7 +111,7 @@
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/arch/arm/include/asm/sizes.h b/arch/arm/include/asm/sizes.h
index ada93a8..4fc1565 100644
--- a/arch/arm/include/asm/sizes.h
+++ b/arch/arm/include/asm/sizes.h
@@ -29,6 +29,7 @@
 #define SZ_512				0x00000200
 
 #define SZ_1K                           0x00000400
+#define SZ_2K                           0x00000800
 #define SZ_4K                           0x00001000
 #define SZ_8K                           0x00002000
 #define SZ_16K                          0x00004000
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 5995935..a06e735 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -41,7 +41,7 @@
 asmlinkage void do_IPI(struct pt_regs *regs);
 
 /*
- * Setup the SMP cpu_possible_map
+ * Setup the set of possible CPUs (via set_cpu_possible)
  */
 extern void smp_init_cpus(void);
 
@@ -56,11 +56,6 @@
 extern void smp_cross_call(const struct cpumask *mask);
 
 /*
- * Broadcast a clock event to other CPUs.
- */
-extern void smp_timer_broadcast(const struct cpumask *mask);
-
-/*
  * Boot a secondary CPU, and assign it the specified idle task.
  * This also gives us the initial stack to use for this CPU.
  */
@@ -101,43 +96,8 @@
 #define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
 
 /*
- * Local timer interrupt handling function (can be IPI'ed).
- */
-extern void local_timer_interrupt(void);
-
-#ifdef CONFIG_LOCAL_TIMERS
-
-/*
- * Stop a local timer interrupt.
- */
-extern void local_timer_stop(void);
-
-/*
- * Platform provides this to acknowledge a local timer IRQ
- */
-extern int local_timer_ack(void);
-
-#else
-
-static inline void local_timer_stop(void)
-{
-}
-
-#endif
-
-/*
- * Setup a local timer interrupt for a CPU.
- */
-extern void local_timer_setup(void);
-
-/*
  * show local interrupt info
  */
 extern void show_local_irqs(struct seq_file *);
 
-/*
- * Called from assembly, this is the local timer IRQ handler
- */
-asmlinkage void do_local_timer(struct pt_regs *);
-
 #endif /* ifndef __ASM_ARM_SMP_H */
diff --git a/arch/arm/include/asm/smp_scu.h b/arch/arm/include/asm/smp_scu.h
new file mode 100644
index 0000000..2376835
--- /dev/null
+++ b/arch/arm/include/asm/smp_scu.h
@@ -0,0 +1,7 @@
+#ifndef __ASMARM_ARCH_SCU_H
+#define __ASMARM_ARCH_SCU_H
+
+unsigned int scu_get_core_count(void __iomem *);
+void scu_enable(void __iomem *);
+
+#endif
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
new file mode 100644
index 0000000..7be0978
--- /dev/null
+++ b/arch/arm/include/asm/smp_twd.h
@@ -0,0 +1,12 @@
+#ifndef __ASMARM_SMP_TWD_H
+#define __ASMARM_SMP_TWD_H
+
+struct clock_event_device;
+
+extern void __iomem *twd_base;
+
+void twd_timer_stop(void);
+int twd_timer_ack(void);
+void twd_timer_setup(struct clock_event_device *);
+
+#endif
diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h
deleted file mode 100644
index cf0d0bd..0000000
--- a/arch/arm/include/asm/suspend.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef _ASMARM_SUSPEND_H
-#define _ASMARM_SUSPEND_H
-
-#endif
diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h
index a622180..c964f3f 100644
--- a/arch/arm/include/asm/tlbflush.h
+++ b/arch/arm/include/asm/tlbflush.h
@@ -40,6 +40,12 @@
 #define TLB_V6_I_ASID	(1 << 18)
 
 #define TLB_BTB		(1 << 28)
+
+/* Unified Inner Shareable TLB operations (ARMv7 MP extensions) */
+#define TLB_V7_UIS_PAGE	(1 << 19)
+#define TLB_V7_UIS_FULL (1 << 20)
+#define TLB_V7_UIS_ASID (1 << 21)
+
 #define TLB_L2CLEAN_FR	(1 << 29)		/* Feroceon */
 #define TLB_DCLEAN	(1 << 30)
 #define TLB_WB		(1 << 31)
@@ -176,9 +182,17 @@
 # define v6wbi_always_flags	(-1UL)
 #endif
 
+#ifdef CONFIG_SMP
+#define v7wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \
+			 TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | TLB_V7_UIS_ASID)
+#else
+#define v7wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \
+			 TLB_V6_U_FULL | TLB_V6_U_PAGE | TLB_V6_U_ASID)
+#endif
+
 #ifdef CONFIG_CPU_TLB_V7
-# define v7wbi_possible_flags	v6wbi_tlb_flags
-# define v7wbi_always_flags	v6wbi_tlb_flags
+# define v7wbi_possible_flags	v7wbi_tlb_flags
+# define v7wbi_always_flags	v7wbi_tlb_flags
 # ifdef _TLB
 #  define MULTI_TLB 1
 # else
@@ -316,6 +330,8 @@
 		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");
 
 	if (tlb_flag(TLB_BTB)) {
 		/* flush the branch target cache */
@@ -351,6 +367,8 @@
 		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))
+		asm("mcr p15, 0, %0, c8, c3, 2" : : "r" (asid) : "cc");
 
 	if (tlb_flag(TLB_BTB)) {
 		/* flush the branch target cache */
@@ -389,6 +407,8 @@
 		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))
+		asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (uaddr) : "cc");
 
 	if (tlb_flag(TLB_BTB)) {
 		/* flush the branch target cache */
@@ -424,6 +444,8 @@
 		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");
 
 	if (tlb_flag(TLB_BTB)) {
 		/* flush the branch target cache */
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 7897464..0da9bc9 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -386,7 +386,9 @@
 #ifdef CONFIG_MMU
 extern unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n);
 extern unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n);
+extern unsigned long __must_check __copy_to_user_std(void __user *to, const void *from, unsigned long n);
 extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n);
+extern unsigned long __must_check __clear_user_std(void __user *addr, unsigned long n);
 #else
 #define __copy_from_user(to,from,n)	(memcpy(to, (void __force *)from, n), 0)
 #define __copy_to_user(to,from,n)	(memcpy((void __force *)to, from, n), 0)
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 11a5197..ff89d0b 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -22,6 +22,8 @@
 obj-$(CONFIG_ISA_DMA)		+= dma-isa.o
 obj-$(CONFIG_PCI)		+= bios32.o isa.o
 obj-$(CONFIG_SMP)		+= smp.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_KEXEC)		+= machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o kprobes-decode.o
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 83b1da6..fc8af43 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -482,6 +482,9 @@
 	subeq	r4, r2, #4			@ ARM instr at LR - 4
 	subne	r4, r2, #2			@ Thumb instr at LR - 2
 1:	ldreqt	r0, [r4]
+#ifdef CONFIG_CPU_ENDIAN_BE8
+	reveq	r0, r0				@ little endian instruction
+#endif
 	beq	call_fpe
 	@ Thumb instruction
 #if __LINUX_ARM_ARCH__ >= 7
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index b55cb03..366e509 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -210,6 +210,9 @@
   A710(	teq	ip, #0x0f000000						)
   A710(	bne	.Larm710bug						)
 #endif
+#ifdef CONFIG_CPU_ENDIAN_BE8
+	rev	r10, r10			@ little endian instruction
+#endif
 
 #elif defined(CONFIG_AEABI)
 
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index c3265a2..1585423 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -365,7 +365,7 @@
 	regs.ARM_r2 = (unsigned long)fn;
 	regs.ARM_r3 = (unsigned long)do_exit;
 	regs.ARM_pc = (unsigned long)kernel_thread_helper;
-	regs.ARM_cpsr = SVC_MODE;
+	regs.ARM_cpsr = SVC_MODE | PSR_ENDSTATE;
 
 	return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
 }
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 80b8b5c..442b874 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -426,9 +426,13 @@
 		 */
 		thumb = handler & 1;
 
-		if (thumb)
+		if (thumb) {
 			cpsr |= PSR_T_BIT;
-		else
+#if __LINUX_ARM_ARCH__ >= 7
+			/* clear the If-Then Thumb-2 execution state */
+			cpsr &= ~PSR_IT_MASK;
+#endif
+		} else
 			cpsr &= ~PSR_T_BIT;
 	}
 #endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 6014dfd..de885fd 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -22,16 +22,20 @@
 #include <linux/smp.h>
 #include <linux/seq_file.h>
 #include <linux/irq.h>
+#include <linux/percpu.h>
+#include <linux/clockchips.h>
 
 #include <asm/atomic.h>
 #include <asm/cacheflush.h>
 #include <asm/cpu.h>
+#include <asm/cputype.h>
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
 #include <asm/tlbflush.h>
 #include <asm/ptrace.h>
+#include <asm/localtimer.h>
 
 /*
  * as from 2.5, kernels no longer have an init_tasks structure
@@ -163,7 +167,7 @@
 	 * Take this CPU offline.  Once we clear this, we can't return,
 	 * and we must not schedule until we're ready to give up the cpu.
 	 */
-	cpu_clear(cpu, cpu_online_map);
+	set_cpu_online(cpu, false);
 
 	/*
 	 * OK - migrate IRQs away from this CPU
@@ -274,9 +278,9 @@
 	local_fiq_enable();
 
 	/*
-	 * Setup local timer for this CPU.
+	 * Setup the percpu timer for this CPU.
 	 */
-	local_timer_setup();
+	percpu_timer_setup();
 
 	calibrate_delay();
 
@@ -285,7 +289,7 @@
 	/*
 	 * OK, now it's safe to let the boot CPU continue
 	 */
-	cpu_set(cpu, cpu_online_map);
+	set_cpu_online(cpu, true);
 
 	/*
 	 * OK, it's off to the idle thread for us
@@ -383,10 +387,16 @@
 	seq_putc(p, '\n');
 }
 
+/*
+ * Timer (local or broadcast) support
+ */
+static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent);
+
 static void ipi_timer(void)
 {
+	struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
 	irq_enter();
-	local_timer_interrupt();
+	evt->event_handler(evt);
 	irq_exit();
 }
 
@@ -405,6 +415,42 @@
 }
 #endif
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+static void smp_timer_broadcast(const struct cpumask *mask)
+{
+	send_ipi_message(mask, IPI_TIMER);
+}
+
+static void broadcast_timer_set_mode(enum clock_event_mode mode,
+	struct clock_event_device *evt)
+{
+}
+
+static void local_timer_setup(struct clock_event_device *evt)
+{
+	evt->name	= "dummy_timer";
+	evt->features	= CLOCK_EVT_FEAT_ONESHOT |
+			  CLOCK_EVT_FEAT_PERIODIC |
+			  CLOCK_EVT_FEAT_DUMMY;
+	evt->rating	= 400;
+	evt->mult	= 1;
+	evt->set_mode	= broadcast_timer_set_mode;
+	evt->broadcast	= smp_timer_broadcast;
+
+	clockevents_register_device(evt);
+}
+#endif
+
+void __cpuinit percpu_timer_setup(void)
+{
+	unsigned int cpu = smp_processor_id();
+	struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
+
+	evt->cpumask = cpumask_of(cpu);
+
+	local_timer_setup(evt);
+}
+
 static DEFINE_SPINLOCK(stop_lock);
 
 /*
@@ -417,7 +463,7 @@
 	dump_stack();
 	spin_unlock(&stop_lock);
 
-	cpu_clear(cpu, cpu_online_map);
+	set_cpu_online(cpu, false);
 
 	local_fiq_disable();
 	local_irq_disable();
@@ -501,11 +547,6 @@
 	send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
 }
 
-void smp_timer_broadcast(const struct cpumask *mask)
-{
-	send_ipi_message(mask, IPI_TIMER);
-}
-
 void smp_send_stop(void)
 {
 	cpumask_t mask = cpu_online_map;
@@ -545,6 +586,12 @@
 	unsigned long ta_end;
 };
 
+/* all SMP configurations have the extended CPUID registers */
+static inline int tlb_ops_need_broadcast(void)
+{
+	return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2;
+}
+
 static inline void ipi_flush_tlb_all(void *ignored)
 {
 	local_flush_tlb_all();
@@ -587,51 +634,61 @@
 
 void flush_tlb_all(void)
 {
-	on_each_cpu(ipi_flush_tlb_all, NULL, 1);
+	if (tlb_ops_need_broadcast())
+		on_each_cpu(ipi_flush_tlb_all, NULL, 1);
+	else
+		local_flush_tlb_all();
 }
 
 void flush_tlb_mm(struct mm_struct *mm)
 {
-	on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, &mm->cpu_vm_mask);
+	if (tlb_ops_need_broadcast())
+		on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, &mm->cpu_vm_mask);
+	else
+		local_flush_tlb_mm(mm);
 }
 
 void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
 {
-	struct tlb_args ta;
-
-	ta.ta_vma = vma;
-	ta.ta_start = uaddr;
-
-	on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, &vma->vm_mm->cpu_vm_mask);
+	if (tlb_ops_need_broadcast()) {
+		struct tlb_args ta;
+		ta.ta_vma = vma;
+		ta.ta_start = uaddr;
+		on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, &vma->vm_mm->cpu_vm_mask);
+	} else
+		local_flush_tlb_page(vma, uaddr);
 }
 
 void flush_tlb_kernel_page(unsigned long kaddr)
 {
-	struct tlb_args ta;
-
-	ta.ta_start = kaddr;
-
-	on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1);
+	if (tlb_ops_need_broadcast()) {
+		struct tlb_args ta;
+		ta.ta_start = kaddr;
+		on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1);
+	} else
+		local_flush_tlb_kernel_page(kaddr);
 }
 
 void flush_tlb_range(struct vm_area_struct *vma,
                      unsigned long start, unsigned long end)
 {
-	struct tlb_args ta;
-
-	ta.ta_vma = vma;
-	ta.ta_start = start;
-	ta.ta_end = end;
-
-	on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, &vma->vm_mm->cpu_vm_mask);
+	if (tlb_ops_need_broadcast()) {
+		struct tlb_args ta;
+		ta.ta_vma = vma;
+		ta.ta_start = start;
+		ta.ta_end = end;
+		on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, &vma->vm_mm->cpu_vm_mask);
+	} else
+		local_flush_tlb_range(vma, start, end);
 }
 
 void flush_tlb_kernel_range(unsigned long start, unsigned long end)
 {
-	struct tlb_args ta;
-
-	ta.ta_start = start;
-	ta.ta_end = end;
-
-	on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1);
+	if (tlb_ops_need_broadcast()) {
+		struct tlb_args ta;
+		ta.ta_start = start;
+		ta.ta_end = end;
+		on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1);
+	} else
+		local_flush_tlb_kernel_range(start, end);
 }
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
new file mode 100644
index 0000000..d3831f6
--- /dev/null
+++ b/arch/arm/kernel/smp_scu.c
@@ -0,0 +1,48 @@
+/*
+ *  linux/arch/arm/kernel/smp_scu.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/io.h>
+
+#include <asm/smp_scu.h>
+#include <asm/cacheflush.h>
+
+#define SCU_CTRL		0x00
+#define SCU_CONFIG		0x04
+#define SCU_CPU_STATUS		0x08
+#define SCU_INVALIDATE		0x0c
+#define SCU_FPGA_REVISION	0x10
+
+/*
+ * Get the number of CPU cores from the SCU configuration
+ */
+unsigned int __init scu_get_core_count(void __iomem *scu_base)
+{
+	unsigned int ncores = __raw_readl(scu_base + SCU_CONFIG);
+	return (ncores & 0x03) + 1;
+}
+
+/*
+ * Enable the SCU
+ */
+void __init scu_enable(void __iomem *scu_base)
+{
+	u32 scu_ctrl;
+
+	scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
+	scu_ctrl |= 1;
+	__raw_writel(scu_ctrl, scu_base + SCU_CTRL);
+
+	/*
+	 * Ensure that the data accessed by CPU0 before the SCU was
+	 * initialised is visible to the other CPUs.
+	 */
+	flush_cache_all();
+}
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
new file mode 100644
index 0000000..d8c88c6
--- /dev/null
+++ b/arch/arm/kernel/smp_twd.c
@@ -0,0 +1,175 @@
+/*
+ *  linux/arch/arm/kernel/smp_twd.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/kernel.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/smp.h>
+#include <linux/jiffies.h>
+#include <linux/clockchips.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <asm/smp_twd.h>
+#include <asm/hardware/gic.h>
+
+#define TWD_TIMER_LOAD 			0x00
+#define TWD_TIMER_COUNTER		0x04
+#define TWD_TIMER_CONTROL		0x08
+#define TWD_TIMER_INTSTAT		0x0C
+
+#define TWD_WDOG_LOAD			0x20
+#define TWD_WDOG_COUNTER		0x24
+#define TWD_WDOG_CONTROL		0x28
+#define TWD_WDOG_INTSTAT		0x2C
+#define TWD_WDOG_RESETSTAT		0x30
+#define TWD_WDOG_DISABLE		0x34
+
+#define TWD_TIMER_CONTROL_ENABLE	(1 << 0)
+#define TWD_TIMER_CONTROL_ONESHOT	(0 << 1)
+#define TWD_TIMER_CONTROL_PERIODIC	(1 << 1)
+#define TWD_TIMER_CONTROL_IT_ENABLE	(1 << 2)
+
+/* set up by the platform code */
+void __iomem *twd_base;
+
+static unsigned long twd_timer_rate;
+
+static void twd_set_mode(enum clock_event_mode mode,
+			struct clock_event_device *clk)
+{
+	unsigned long ctrl;
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		/* timer load already set up */
+		ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE
+			| TWD_TIMER_CONTROL_PERIODIC;
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		/* period set, and timer enabled in 'next_event' hook */
+		ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT;
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	default:
+		ctrl = 0;
+	}
+
+	__raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);
+}
+
+static int twd_set_next_event(unsigned long evt,
+			struct clock_event_device *unused)
+{
+	unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);
+
+	ctrl |= TWD_TIMER_CONTROL_ENABLE;
+
+	__raw_writel(evt, twd_base + TWD_TIMER_COUNTER);
+	__raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);
+
+	return 0;
+}
+
+/*
+ * local_timer_ack: checks for a local timer interrupt.
+ *
+ * If a local timer interrupt has occurred, acknowledge and return 1.
+ * Otherwise, return 0.
+ */
+int twd_timer_ack(void)
+{
+	if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {
+		__raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
+		return 1;
+	}
+
+	return 0;
+}
+
+static void __cpuinit twd_calibrate_rate(void)
+{
+	unsigned long load, count;
+	u64 waitjiffies;
+
+	/*
+	 * If this is the first time round, we need to work out how fast
+	 * the timer ticks
+	 */
+	if (twd_timer_rate == 0) {
+		printk(KERN_INFO "Calibrating local timer... ");
+
+		/* Wait for a tick to start */
+		waitjiffies = get_jiffies_64() + 1;
+
+		while (get_jiffies_64() < waitjiffies)
+			udelay(10);
+
+		/* OK, now the tick has started, let's get the timer going */
+		waitjiffies += 5;
+
+				 /* enable, no interrupt or reload */
+		__raw_writel(0x1, twd_base + TWD_TIMER_CONTROL);
+
+				 /* maximum value */
+		__raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);
+
+		while (get_jiffies_64() < waitjiffies)
+			udelay(10);
+
+		count = __raw_readl(twd_base + TWD_TIMER_COUNTER);
+
+		twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
+
+		printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000,
+			(twd_timer_rate / 100000) % 100);
+	}
+
+	load = twd_timer_rate / HZ;
+
+	__raw_writel(load, twd_base + TWD_TIMER_LOAD);
+}
+
+/*
+ * Setup the local clock events for a CPU.
+ */
+void __cpuinit twd_timer_setup(struct clock_event_device *clk)
+{
+	unsigned long flags;
+
+	twd_calibrate_rate();
+
+	clk->name = "local_timer";
+	clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+	clk->rating = 350;
+	clk->set_mode = twd_set_mode;
+	clk->set_next_event = twd_set_next_event;
+	clk->shift = 20;
+	clk->mult = div_sc(twd_timer_rate, NSEC_PER_SEC, clk->shift);
+	clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
+	clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
+
+	/* Make sure our local interrupt controller has this enabled */
+	local_irq_save(flags);
+	get_irq_chip(clk->irq)->unmask(clk->irq);
+	local_irq_restore(flags);
+
+	clockevents_register_device(clk);
+}
+
+/*
+ * take a local timer down
+ */
+void __cpuexit twd_timer_stop(void)
+{
+	__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
+}
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index c90f272..6c07797 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -141,6 +141,7 @@
 
 	.data : AT(__data_loc) {
 		_data = .;		/* address in memory */
+		_sdata = .;
 
 		/*
 		 * first, the init task union, aligned
@@ -192,6 +193,7 @@
 		__bss_start = .;	/* BSS				*/
 		*(.bss)
 		*(COMMON)
+		__bss_stop = .;
 		_end = .;
 	}
 					/* Stabs debugging sections.	*/
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 866f84a..030ba72 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -29,6 +29,9 @@
 endif
 endif
 
+# using lib_ here won't override already available weak symbols
+obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o
+
 lib-$(CONFIG_MMU) += $(mmu-y)
 
 ifeq ($(CONFIG_CPU_32v3),y)
diff --git a/arch/arm/lib/clear_user.S b/arch/arm/lib/clear_user.S
index 4d6bc71..844f567 100644
--- a/arch/arm/lib/clear_user.S
+++ b/arch/arm/lib/clear_user.S
@@ -18,7 +18,8 @@
  *          : sz   - number of bytes to clear
  * Returns  : number of bytes NOT cleared
  */
-ENTRY(__clear_user)
+ENTRY(__clear_user_std)
+WEAK(__clear_user)
 		stmfd	sp!, {r1, lr}
 		mov	r2, #0
 		cmp	r1, #4
diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S
index 22f968b..878820f 100644
--- a/arch/arm/lib/copy_to_user.S
+++ b/arch/arm/lib/copy_to_user.S
@@ -86,7 +86,8 @@
 
 	.text
 
-ENTRY(__copy_to_user)
+ENTRY(__copy_to_user_std)
+WEAK(__copy_to_user)
 
 #include "copy_template.S"
 
diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c
new file mode 100644
index 0000000..6b967ff
--- /dev/null
+++ b/arch/arm/lib/uaccess_with_memcpy.c
@@ -0,0 +1,228 @@
+/*
+ *  linux/arch/arm/lib/uaccess_with_memcpy.c
+ *
+ *  Written by: Lennert Buytenhek and Nicolas Pitre
+ *  Copyright (C) 2009 Marvell Semiconductor
+ *
+ * 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/ctype.h>
+#include <linux/uaccess.h>
+#include <linux/rwsem.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/hardirq.h> /* for in_atomic() */
+#include <asm/current.h>
+#include <asm/page.h>
+
+static int
+pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
+{
+	unsigned long addr = (unsigned long)_addr;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	spinlock_t *ptl;
+
+	pgd = pgd_offset(current->mm, addr);
+	if (unlikely(pgd_none(*pgd) || pgd_bad(*pgd)))
+		return 0;
+
+	pmd = pmd_offset(pgd, addr);
+	if (unlikely(pmd_none(*pmd) || pmd_bad(*pmd)))
+		return 0;
+
+	pte = pte_offset_map_lock(current->mm, pmd, addr, &ptl);
+	if (unlikely(!pte_present(*pte) || !pte_young(*pte) ||
+	    !pte_write(*pte) || !pte_dirty(*pte))) {
+		pte_unmap_unlock(pte, ptl);
+		return 0;
+	}
+
+	*ptep = pte;
+	*ptlp = ptl;
+
+	return 1;
+}
+
+static unsigned long noinline
+__copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
+{
+	int atomic;
+
+	if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
+		memcpy((void *)to, from, n);
+		return 0;
+	}
+
+	/* the mmap semaphore is taken only if not in an atomic context */
+	atomic = in_atomic();
+
+	if (!atomic)
+		down_read(&current->mm->mmap_sem);
+	while (n) {
+		pte_t *pte;
+		spinlock_t *ptl;
+		int tocopy;
+
+		while (!pin_page_for_write(to, &pte, &ptl)) {
+			if (!atomic)
+				up_read(&current->mm->mmap_sem);
+			if (__put_user(0, (char __user *)to))
+				goto out;
+			if (!atomic)
+				down_read(&current->mm->mmap_sem);
+		}
+
+		tocopy = (~(unsigned long)to & ~PAGE_MASK) + 1;
+		if (tocopy > n)
+			tocopy = n;
+
+		memcpy((void *)to, from, tocopy);
+		to += tocopy;
+		from += tocopy;
+		n -= tocopy;
+
+		pte_unmap_unlock(pte, ptl);
+	}
+	if (!atomic)
+		up_read(&current->mm->mmap_sem);
+
+out:
+	return n;
+}
+
+unsigned long
+__copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+	/*
+	 * This test is stubbed out of the main function above to keep
+	 * the overhead for small copies low by avoiding a large
+	 * register dump on the stack just to reload them right away.
+	 * With frame pointer disabled, tail call optimization kicks in
+	 * as well making this test almost invisible.
+	 */
+	if (n < 64)
+		return __copy_to_user_std(to, from, n);
+	return __copy_to_user_memcpy(to, from, n);
+}
+	
+static unsigned long noinline
+__clear_user_memset(void __user *addr, unsigned long n)
+{
+	if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
+		memset((void *)addr, 0, n);
+		return 0;
+	}
+
+	down_read(&current->mm->mmap_sem);
+	while (n) {
+		pte_t *pte;
+		spinlock_t *ptl;
+		int tocopy;
+
+		while (!pin_page_for_write(addr, &pte, &ptl)) {
+			up_read(&current->mm->mmap_sem);
+			if (__put_user(0, (char __user *)addr))
+				goto out;
+			down_read(&current->mm->mmap_sem);
+		}
+
+		tocopy = (~(unsigned long)addr & ~PAGE_MASK) + 1;
+		if (tocopy > n)
+			tocopy = n;
+
+		memset((void *)addr, 0, tocopy);
+		addr += tocopy;
+		n -= tocopy;
+
+		pte_unmap_unlock(pte, ptl);
+	}
+	up_read(&current->mm->mmap_sem);
+
+out:
+	return n;
+}
+
+unsigned long __clear_user(void __user *addr, unsigned long n)
+{
+	/* See rational for this in __copy_to_user() above. */
+	if (n < 64)
+		return __clear_user_std(addr, n);
+	return __clear_user_memset(addr, n);
+}
+
+#if 0
+
+/*
+ * This code is disabled by default, but kept around in case the chosen
+ * thresholds need to be revalidated.  Some overhead (small but still)
+ * would be implied by a runtime determined variable threshold, and
+ * so far the measurement on concerned targets didn't show a worthwhile
+ * variation.
+ *
+ * Note that a fairly precise sched_clock() implementation is needed
+ * for results to make some sense.
+ */
+
+#include <linux/vmalloc.h>
+
+static int __init test_size_treshold(void)
+{
+	struct page *src_page, *dst_page;
+	void *user_ptr, *kernel_ptr;
+	unsigned long long t0, t1, t2;
+	int size, ret;
+
+	ret = -ENOMEM;
+	src_page = alloc_page(GFP_KERNEL);
+	if (!src_page)
+		goto no_src;
+	dst_page = alloc_page(GFP_KERNEL);
+	if (!dst_page)
+		goto no_dst;
+	kernel_ptr = page_address(src_page);
+	user_ptr = vmap(&dst_page, 1, VM_IOREMAP, __pgprot(__P010));
+	if (!user_ptr)
+		goto no_vmap;
+
+	/* warm up the src page dcache */
+	ret = __copy_to_user_memcpy(user_ptr, kernel_ptr, PAGE_SIZE);
+
+	for (size = PAGE_SIZE; size >= 4; size /= 2) {
+		t0 = sched_clock();
+		ret |= __copy_to_user_memcpy(user_ptr, kernel_ptr, size);
+		t1 = sched_clock();
+		ret |= __copy_to_user_std(user_ptr, kernel_ptr, size);
+		t2 = sched_clock();
+		printk("copy_to_user: %d %llu %llu\n", size, t1 - t0, t2 - t1);
+	}
+
+	for (size = PAGE_SIZE; size >= 4; size /= 2) {
+		t0 = sched_clock();
+		ret |= __clear_user_memset(user_ptr, size);
+		t1 = sched_clock();
+		ret |= __clear_user_std(user_ptr, size);
+		t2 = sched_clock();
+		printk("clear_user: %d %llu %llu\n", size, t1 - t0, t2 - t1);
+	}
+
+	if (ret)
+		ret = -EFAULT;
+
+	vunmap(user_ptr);
+no_vmap:
+	put_page(dst_page);
+no_dst:
+	put_page(src_page);
+no_src:
+	return ret;
+}
+
+subsys_initcall(test_size_treshold);
+
+#endif
diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
index e263fda..970fd6b 100644
--- a/arch/arm/mach-at91/board-afeb-9260v1.c
+++ b/arch/arm/mach-at91/board-afeb-9260v1.c
@@ -156,6 +156,8 @@
  * MCI (SD/MMC)
  */
 static struct at91_mmc_data __initdata afeb9260_mmc_data = {
+	.det_pin 	= AT91_PIN_PC9,
+	.wp_pin 	= AT91_PIN_PC4,
 	.slot_b		= 1,
 	.wire4		= 1,
 };
@@ -164,6 +166,8 @@
 
 static struct i2c_board_info __initdata afeb9260_i2c_devices[] = {
 	{
+		I2C_BOARD_INFO("tlv320aic23", 0x1a),
+	}, {
 		I2C_BOARD_INFO("fm3130", 0x68),
 	}, {
 		I2C_BOARD_INFO("24c64", 0x50),
@@ -196,6 +200,8 @@
 	/* I2C */
 	at91_add_device_i2c(afeb9260_i2c_devices,
 			ARRAY_SIZE(afeb9260_i2c_devices));
+	/* Audio */
+	at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
 }
 
 MACHINE_START(AFEB9260, "Custom afeb9260 board")
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
index 438efbb..cc270be 100644
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ b/arch/arm/mach-at91/board-sam9g20ek.c
@@ -218,6 +218,13 @@
 	}
 };
 
+static struct i2c_board_info __initdata ek_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("24c512", 0x50),
+	},
+};
+
+
 static void __init ek_board_init(void)
 {
 	/* Serial */
@@ -235,7 +242,7 @@
 	/* MMC */
 	at91_add_device_mmc(0, &ek_mmc_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
 	/* LEDs */
 	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
 	/* PCK0 provides MCLK to the WM8731 */
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
index e434510..bac578f 100644
--- a/arch/arm/mach-at91/clock.c
+++ b/arch/arm/mach-at91/clock.c
@@ -43,6 +43,25 @@
 #define clk_is_sys(x)		((x)->type & CLK_TYPE_SYSTEM)
 
 
+/*
+ * Chips have some kind of clocks : group them by functionality
+ */
+#define cpu_has_utmi()		(  cpu_is_at91cap9() \
+				|| cpu_is_at91sam9rl())
+
+#define cpu_has_800M_plla()	(cpu_is_at91sam9g20())
+
+#define cpu_has_pllb()		(!cpu_is_at91sam9rl())
+
+#define cpu_has_upll()		(0)
+
+/* USB host HS & FS */
+#define cpu_has_uhp()		(!cpu_is_at91sam9rl())
+
+/* USB device FS only */
+#define cpu_has_udpfs()		(!cpu_is_at91sam9rl())
+
+
 static LIST_HEAD(clocks);
 static DEFINE_SPINLOCK(clk_lock);
 
@@ -140,7 +159,7 @@
 };
 static struct clk uhpck = {
 	.name		= "uhpck",
-	.parent		= &pllb,
+	/*.parent		= ... we choose parent at runtime */
 	.mode		= pmc_sys_mode,
 };
 
@@ -173,7 +192,11 @@
 		case AT91_PMC_CSS_PLLA:
 			return &plla;
 		case AT91_PMC_CSS_PLLB:
-			return &pllb;
+			if (cpu_has_upll())
+				/* CSS_PLLB == CSS_UPLL */
+				return &utmi_clk;
+			else if (cpu_has_pllb())
+				return &pllb;
 	}
 
 	return NULL;
@@ -322,7 +345,7 @@
 			u32	pckr;
 
 			pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
-			pckr &= AT91_PMC_CSS_PLLB;	/* clock selection */
+			pckr &= AT91_PMC_CSS;	/* clock selection */
 			pckr |= prescale << 2;
 			at91_sys_write(AT91_PMC_PCKR(clk->id), pckr);
 			clk->rate_hz = actual;
@@ -361,7 +384,7 @@
 }
 EXPORT_SYMBOL(clk_set_parent);
 
-/* establish PCK0..PCK3 parentage and rate */
+/* establish PCK0..PCKN parentage and rate */
 static void __init init_programmable_clock(struct clk *clk)
 {
 	struct clk	*parent;
@@ -389,11 +412,13 @@
 	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));
-	if (!cpu_is_at91sam9rl())
+	if (cpu_has_pllb())
 		seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR));
-	if (cpu_is_at91cap9() || cpu_is_at91sam9rl())
+	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));
+	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, "\n");
@@ -554,16 +579,60 @@
 	&clk32k,
 	&main_clk,
 	&plla,
-	&pllb,
-
-	/* PLLB children (USB) */
-	&udpck,
-	&uhpck,
 
 	/* MCK */
 	&mck
 };
 
+/* PLLB generated USB full speed clock init */
+static void __init at91_pllb_usbfs_clock_init(unsigned long main_clock)
+{
+	/*
+	 * USB clock init:  choose 48 MHz PLLB value,
+	 * disable 48MHz clock during usb peripheral suspend.
+	 *
+	 * REVISIT:  assumes MCK doesn't derive from PLLB!
+	 */
+	uhpck.parent = &pllb;
+
+	at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | AT91_PMC_USB96M;
+	pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init);
+	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);
+	} else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
+		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);
+
+	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);
+}
+
+/* UPLL generated USB full speed clock init */
+static void __init at91_upll_usbfs_clock_init(unsigned long main_clock)
+{
+	/*
+	 * USB clock init: choose 480 MHz from UPLL,
+	 */
+	unsigned int usbr = AT91_PMC_USBS_UPLL;
+
+	/* Setup divider by 10 to reach 48 MHz */
+	usbr |= ((10 - 1) << 8) & AT91_PMC_OHCIUSBDIV;
+
+	at91_sys_write(AT91_PMC_USB, usbr);
+
+	/* Now set uhpck values */
+	uhpck.parent = &utmi_clk;
+	uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
+	uhpck.rate_hz = utmi_clk.parent->rate_hz;
+	uhpck.rate_hz /= 1 + ((at91_sys_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8);
+}
+
 int __init at91_clock_init(unsigned long main_clock)
 {
 	unsigned tmp, freq, mckr;
@@ -585,43 +654,37 @@
 
 	/* report if PLLA is more than mildly overclocked */
 	plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_sys_read(AT91_CKGR_PLLAR));
-	if ((!cpu_is_at91sam9g20() && plla.rate_hz > 209000000)
-	   || (cpu_is_at91sam9g20() && plla.rate_hz > 800000000))
+	if ((!cpu_has_800M_plla() && plla.rate_hz > 209000000)
+	   || (cpu_has_800M_plla() && plla.rate_hz > 800000000))
 		pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000);
 
-	/*
-	 * USB clock init:  choose 48 MHz PLLB value,
-	 * disable 48MHz clock during usb peripheral suspend.
-	 *
-	 * REVISIT:  assumes MCK doesn't derive from PLLB!
-	 */
-	at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | AT91_PMC_USB96M;
-	pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init);
-	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);
-	} else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
-		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);
 
-	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);
+	if (cpu_has_upll() && !cpu_has_pllb()) {
+		/* setup UTMI clock as the fourth primary clock
+		 * (instead of pllb) */
+		utmi_clk.type |= CLK_TYPE_PRIMARY;
+		utmi_clk.id = 3;
+	}
+
 
 	/*
 	 * USB HS clock init
 	 */
-	if (cpu_is_at91cap9() || cpu_is_at91sam9rl()) {
+	if (cpu_has_utmi())
 		/*
 		 * multiplier is hard-wired to 40
 		 * (obtain the USB High Speed 480 MHz when input is 12 MHz)
 		 */
 		utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz;
-	}
+
+	/*
+	 * USB FS clock init
+	 */
+	if (cpu_has_pllb())
+		at91_pllb_usbfs_clock_init(main_clock);
+	if (cpu_has_upll())
+		/* assumes that we choose UPLL for USB and not PLLA */
+		at91_upll_usbfs_clock_init(main_clock);
 
 	/*
 	 * MCK and CPU derive from one of those primary clocks.
@@ -631,21 +694,31 @@
 	mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS);
 	freq = mck.parent->rate_hz;
 	freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2));				/* prescale */
-	if (cpu_is_at91rm9200())
+	if (cpu_is_at91rm9200()) {
 		mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8));	/* mdiv */
-	else if (cpu_is_at91sam9g20()) {
+	} else if (cpu_is_at91sam9g20()) {
 		mck.rate_hz = (mckr & AT91_PMC_MDIV) ?
 			freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq;	/* mdiv ; (x >> 7) = ((x >> 8) * 2) */
 		if (mckr & AT91_PMC_PDIV)
 			freq /= 2;		/* processor clock division */
-	} else
+	} else {
 		mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8));      /* mdiv */
+	}
 
 	/* Register the PMC's standard clocks */
 	for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
 		list_add_tail(&standard_pmc_clocks[i]->node, &clocks);
 
-	if (cpu_is_at91cap9() || cpu_is_at91sam9rl())
+	if (cpu_has_pllb())
+		list_add_tail(&pllb.node, &clocks);
+
+	if (cpu_has_uhp())
+		list_add_tail(&uhpck.node, &clocks);
+
+	if (cpu_has_udpfs())
+		list_add_tail(&udpck.node, &clocks);
+
+	if (cpu_has_utmi())
 		list_add_tail(&utmi_clk.node, &clocks);
 
 	/* MCK and CPU clock are "always on" */
diff --git a/arch/arm/mach-at91/include/mach/at91_pmc.h b/arch/arm/mach-at91/include/mach/at91_pmc.h
index 9561e33..64589ea 100644
--- a/arch/arm/mach-at91/include/mach/at91_pmc.h
+++ b/arch/arm/mach-at91/include/mach/at91_pmc.h
@@ -23,7 +23,7 @@
 #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 [AT91CAP9 revC 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] */
@@ -39,11 +39,11 @@
 #define	AT91_PMC_PCDR		(AT91_PMC + 0x14)	/* Peripheral Clock Disable Register */
 #define	AT91_PMC_PCSR		(AT91_PMC + 0x18)	/* Peripheral Clock Status Register */
 
-#define	AT91_CKGR_UCKR		(AT91_PMC + 0x1C)	/* UTMI Clock Register [SAM9RL, CAP9] */
+#define	AT91_CKGR_UCKR		(AT91_PMC + 0x1C)	/* UTMI Clock Register [some SAM9, CAP9] */
 #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 PLL Start-up Time */
+#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 */
@@ -72,6 +72,7 @@
 #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)
@@ -88,12 +89,25 @@
 #define			AT91SAM9_PMC_MDIV_1		(0 << 8)	/* [SAM9,CAP9 only] */
 #define			AT91SAM9_PMC_MDIV_2		(1 << 8)
 #define			AT91SAM9_PMC_MDIV_4		(2 << 8)
-#define			AT91SAM9_PMC_MDIV_6		(3 << 8)
+#define			AT91SAM9_PMC_MDIV_6		(3 << 8)	/* [some SAM9 only] */
+#define			AT91SAM9_PMC_MDIV_3		(3 << 8)	/* [some SAM9 only] */
 #define		AT91_PMC_PDIV		(1 << 12)		/* Processor Clock Division [some SAM9 only] */
 #define			AT91_PMC_PDIV_1			(0 << 12)
 #define			AT91_PMC_PDIV_2			(1 << 12)
+#define		AT91_PMC_PLLADIV2	(1 << 12)		/* PLLA divisor by 2 [some SAM9 only] */
+#define			AT91_PMC_PLLADIV2_OFF		(0 << 12)
+#define			AT91_PMC_PLLADIV2_ON		(1 << 12)
 
-#define	AT91_PMC_PCKR(n)	(AT91_PMC + 0x40 + ((n) * 4))	/* Programmable Clock 0-3 Registers */
+#define	AT91_PMC_USB		(AT91_PMC + 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_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 */
@@ -102,7 +116,7 @@
 #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 [AT91CAP9 only] */
+#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_PCK0RDY	(1 <<  8)		/* Programmable Clock 0 */
 #define		AT91_PMC_PCK1RDY	(1 <<  9)		/* Programmable Clock 1 */
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index a9c78bc..be747f5 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -1,11 +1,26 @@
 if ARCH_DAVINCI
 
+config AINTC
+	bool
+
+config CP_INTC
+	bool
+
 menu "TI DaVinci Implementations"
 
 comment "DaVinci Core Type"
 
 config ARCH_DAVINCI_DM644x
 	bool "DaVinci 644x based system"
+	select AINTC
+
+config ARCH_DAVINCI_DM355
+        bool "DaVinci 355 based system"
+	select AINTC
+
+config ARCH_DAVINCI_DM646x
+        bool "DaVinci 646x based system"
+	select AINTC
 
 comment "DaVinci Board Type"
 
@@ -17,6 +32,34 @@
 	  Configure this option to specify the whether the board used
 	  for development is a DM644x EVM
 
+config MACH_SFFSDR
+	bool "Lyrtech SFFSDR"
+	depends on ARCH_DAVINCI_DM644x
+	help
+	  Say Y here to select the Lyrtech Small Form Factor
+	  Software Defined Radio (SFFSDR) board.
+
+config MACH_DAVINCI_DM355_EVM
+	bool "TI DM355 EVM"
+	depends on ARCH_DAVINCI_DM355
+	help
+	  Configure this option to specify the whether the board used
+	  for development is a DM355 EVM
+
+config MACH_DM355_LEOPARD
+	bool "DM355 Leopard board"
+	depends on ARCH_DAVINCI_DM355
+	help
+	  Configure this option to specify the whether the board used
+	  for development is a DM355 Leopard board.
+
+config MACH_DAVINCI_DM6467_EVM
+	bool "TI DM6467 EVM"
+	depends on ARCH_DAVINCI_DM646x
+	help
+	  Configure this option to specify the whether the board used
+	  for development is a DM6467 EVM
+
 
 config DAVINCI_MUX
 	bool "DAVINCI multiplexing support"
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index 1674661..059ab78 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -4,13 +4,22 @@
 #
 
 # Common objects
-obj-y 			:= time.o irq.o clock.o serial.o io.o id.o psc.o \
-			   gpio.o devices.o dma.o usb.o
+obj-y 			:= time.o clock.o serial.o io.o psc.o \
+			   gpio.o devices.o dma.o usb.o common.o sram.o
 
 obj-$(CONFIG_DAVINCI_MUX)		+= mux.o
 
 # Chip specific
 obj-$(CONFIG_ARCH_DAVINCI_DM644x)       += dm644x.o
+obj-$(CONFIG_ARCH_DAVINCI_DM355)        += dm355.o
+obj-$(CONFIG_ARCH_DAVINCI_DM646x)       += dm646x.o
+
+obj-$(CONFIG_AINTC)			+= irq.o
+obj-$(CONFIG_CP_INTC)			+= cp_intc.o
 
 # Board specific
 obj-$(CONFIG_MACH_DAVINCI_EVM)  	+= board-dm644x-evm.o
+obj-$(CONFIG_MACH_SFFSDR)		+= board-sffsdr.o
+obj-$(CONFIG_MACH_DAVINCI_DM355_EVM)	+= board-dm355-evm.o
+obj-$(CONFIG_MACH_DM355_LEOPARD)	+= board-dm355-leopard.o
+obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM)	+= board-dm646x-evm.o
diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c
new file mode 100644
index 0000000..5ac2f56
--- /dev/null
+++ b/arch/arm/mach-davinci/board-dm355-evm.c
@@ -0,0 +1,298 @@
+/*
+ * TI DaVinci EVM board support
+ *
+ * Author: Kevin Hilman, Deep Root Systems, LLC
+ *
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/eeprom.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <mach/hardware.h>
+#include <mach/dm355.h>
+#include <mach/psc.h>
+#include <mach/common.h>
+#include <mach/i2c.h>
+#include <mach/serial.h>
+#include <mach/nand.h>
+#include <mach/mmc.h>
+#include <mach/common.h>
+
+#define DAVINCI_ASYNC_EMIF_CONTROL_BASE		0x01e10000
+#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE	0x02000000
+
+/* 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
+ * need to be changed.
+ */
+#define NAND_BLOCK_SIZE		SZ_128K
+
+static struct mtd_partition davinci_nand_partitions[] = {
+	{
+		/* UBL (a few copies) plus U-Boot */
+		.name		= "bootloader",
+		.offset		= 0,
+		.size		= 15 * NAND_BLOCK_SIZE,
+		.mask_flags	= MTD_WRITEABLE, /* force read-only */
+	}, {
+		/* U-Boot environment */
+		.name		= "params",
+		.offset		= MTDPART_OFS_APPEND,
+		.size		= 1 * NAND_BLOCK_SIZE,
+		.mask_flags	= 0,
+	}, {
+		.name		= "kernel",
+		.offset		= MTDPART_OFS_APPEND,
+		.size		= SZ_4M,
+		.mask_flags	= 0,
+	}, {
+		.name		= "filesystem1",
+		.offset		= MTDPART_OFS_APPEND,
+		.size		= SZ_512M,
+		.mask_flags	= 0,
+	}, {
+		.name		= "filesystem2",
+		.offset		= MTDPART_OFS_APPEND,
+		.size		= MTDPART_SIZ_FULL,
+		.mask_flags	= 0,
+	}
+	/* two blocks with bad block table (and mirror) at the end */
+};
+
+static struct davinci_nand_pdata davinci_nand_data = {
+	.mask_chipsel		= BIT(14),
+	.parts			= davinci_nand_partitions,
+	.nr_parts		= ARRAY_SIZE(davinci_nand_partitions),
+	.ecc_mode		= NAND_ECC_HW_SYNDROME,
+	.options		= NAND_USE_FLASH_BBT,
+};
+
+static struct resource davinci_nand_resources[] = {
+	{
+		.start		= DAVINCI_ASYNC_EMIF_DATA_CE0_BASE,
+		.end		= DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_32M - 1,
+		.flags		= IORESOURCE_MEM,
+	}, {
+		.start		= DAVINCI_ASYNC_EMIF_CONTROL_BASE,
+		.end		= DAVINCI_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device davinci_nand_device = {
+	.name			= "davinci_nand",
+	.id			= 0,
+
+	.num_resources		= ARRAY_SIZE(davinci_nand_resources),
+	.resource		= davinci_nand_resources,
+
+	.dev			= {
+		.platform_data	= &davinci_nand_data,
+	},
+};
+
+static struct davinci_i2c_platform_data i2c_pdata = {
+	.bus_freq	= 400	/* kHz */,
+	.bus_delay	= 0	/* usec */,
+};
+
+static int dm355evm_mmc_gpios = -EINVAL;
+
+static void dm355evm_mmcsd_gpios(unsigned gpio)
+{
+	gpio_request(gpio + 0, "mmc0_ro");
+	gpio_request(gpio + 1, "mmc0_cd");
+	gpio_request(gpio + 2, "mmc1_ro");
+	gpio_request(gpio + 3, "mmc1_cd");
+
+	/* we "know" these are input-only so we don't
+	 * need to call gpio_direction_input()
+	 */
+
+	dm355evm_mmc_gpios = gpio;
+}
+
+static struct i2c_board_info dm355evm_i2c_info[] = {
+	{ I2C_BOARD_INFO("dm355evm_msp", 0x25),
+		.platform_data = dm355evm_mmcsd_gpios,
+		/* plus irq */ },
+	/* { I2C_BOARD_INFO("tlv320aic3x", 0x1b), }, */
+	/* { I2C_BOARD_INFO("tvp5146", 0x5d), }, */
+};
+
+static void __init evm_init_i2c(void)
+{
+	davinci_init_i2c(&i2c_pdata);
+
+	gpio_request(5, "dm355evm_msp");
+	gpio_direction_input(5);
+	dm355evm_i2c_info[0].irq = gpio_to_irq(5);
+
+	i2c_register_board_info(1, dm355evm_i2c_info,
+			ARRAY_SIZE(dm355evm_i2c_info));
+}
+
+static struct resource dm355evm_dm9000_rsrc[] = {
+	{
+		/* addr */
+		.start	= 0x04014000,
+		.end	= 0x04014001,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		/* data */
+		.start	= 0x04014002,
+		.end	= 0x04014003,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.flags	= IORESOURCE_IRQ
+			| IORESOURCE_IRQ_HIGHEDGE /* rising (active high) */,
+	},
+};
+
+static struct platform_device dm355evm_dm9000 = {
+	.name		= "dm9000",
+	.id		= -1,
+	.resource	= dm355evm_dm9000_rsrc,
+	.num_resources	= ARRAY_SIZE(dm355evm_dm9000_rsrc),
+};
+
+static struct platform_device *davinci_evm_devices[] __initdata = {
+	&dm355evm_dm9000,
+	&davinci_nand_device,
+};
+
+static struct davinci_uart_config uart_config __initdata = {
+	.enabled_uarts = (1 << 0),
+};
+
+static void __init dm355_evm_map_io(void)
+{
+	dm355_init();
+}
+
+static int dm355evm_mmc_get_cd(int module)
+{
+	if (!gpio_is_valid(dm355evm_mmc_gpios))
+		return -ENXIO;
+	/* low == card present */
+	return !gpio_get_value_cansleep(dm355evm_mmc_gpios + 2 * module + 1);
+}
+
+static int dm355evm_mmc_get_ro(int module)
+{
+	if (!gpio_is_valid(dm355evm_mmc_gpios))
+		return -ENXIO;
+	/* high == card's write protect switch active */
+	return gpio_get_value_cansleep(dm355evm_mmc_gpios + 2 * module + 0);
+}
+
+static struct davinci_mmc_config dm355evm_mmc_config = {
+	.get_cd		= dm355evm_mmc_get_cd,
+	.get_ro		= dm355evm_mmc_get_ro,
+	.wires		= 4,
+	.max_freq       = 50000000,
+	.caps           = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
+	.version	= MMC_CTLR_VERSION_1,
+};
+
+/* Don't connect anything to J10 unless you're only using USB host
+ * mode *and* have to do so with some kind of gender-bender.  If
+ * you have proper Mini-B or Mini-A cables (or Mini-A adapters)
+ * the ID pin won't need any help.
+ */
+#ifdef CONFIG_USB_MUSB_PERIPHERAL
+#define USB_ID_VALUE	0	/* ID pulled high; *should* float */
+#else
+#define USB_ID_VALUE	1	/* ID pulled low */
+#endif
+
+static struct spi_eeprom at25640a = {
+	.byte_len	= SZ_64K / 8,
+	.name		= "at25640a",
+	.page_size	= 32,
+	.flags		= EE_ADDR2,
+};
+
+static struct spi_board_info dm355_evm_spi_info[] __initconst = {
+	{
+		.modalias	= "at25",
+		.platform_data	= &at25640a,
+		.max_speed_hz	= 10 * 1000 * 1000,	/* at 3v3 */
+		.bus_num	= 0,
+		.chip_select	= 0,
+		.mode		= SPI_MODE_0,
+	},
+};
+
+static __init void dm355_evm_init(void)
+{
+	struct clk *aemif;
+
+	gpio_request(1, "dm9000");
+	gpio_direction_input(1);
+	dm355evm_dm9000_rsrc[2].start = gpio_to_irq(1);
+
+	aemif = clk_get(&dm355evm_dm9000.dev, "aemif");
+	if (IS_ERR(aemif))
+		WARN("%s: unable to get AEMIF clock\n", __func__);
+	else
+		clk_enable(aemif);
+
+	platform_add_devices(davinci_evm_devices,
+			     ARRAY_SIZE(davinci_evm_devices));
+	evm_init_i2c();
+	davinci_serial_init(&uart_config);
+
+	/* NOTE:  NAND flash timings set by the UBL are slower than
+	 * needed by MT29F16G08FAA chips ... EMIF.A1CR is 0x40400204
+	 * but could be 0x0400008c for about 25% faster page reads.
+	 */
+
+	gpio_request(2, "usb_id_toggle");
+	gpio_direction_output(2, USB_ID_VALUE);
+	/* irlml6401 switches over 1A in under 8 msec */
+	setup_usb(500, 8);
+
+	davinci_setup_mmc(0, &dm355evm_mmc_config);
+	davinci_setup_mmc(1, &dm355evm_mmc_config);
+
+	dm355_init_spi0(BIT(0), dm355_evm_spi_info,
+			ARRAY_SIZE(dm355_evm_spi_info));
+}
+
+static __init void dm355_evm_irq_init(void)
+{
+	davinci_irq_init();
+}
+
+MACHINE_START(DAVINCI_DM355_EVM, "DaVinci DM355 EVM")
+	.phys_io      = IO_PHYS,
+	.io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+	.boot_params  = (0x80000100),
+	.map_io	      = dm355_evm_map_io,
+	.init_irq     = dm355_evm_irq_init,
+	.timer	      = &davinci_timer,
+	.init_machine = dm355_evm_init,
+MACHINE_END
diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c
new file mode 100644
index 0000000..28c9008
--- /dev/null
+++ b/arch/arm/mach-davinci/board-dm355-leopard.c
@@ -0,0 +1,296 @@
+/*
+ * DM355 leopard board support
+ *
+ * Based on board-dm355-evm.c
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/eeprom.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <mach/hardware.h>
+#include <mach/dm355.h>
+#include <mach/psc.h>
+#include <mach/common.h>
+#include <mach/i2c.h>
+#include <mach/serial.h>
+#include <mach/nand.h>
+#include <mach/mmc.h>
+#include <mach/common.h>
+
+#define DAVINCI_ASYNC_EMIF_CONTROL_BASE		0x01e10000
+#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE	0x02000000
+
+/* 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
+ * need to be changed.
+ */
+#define NAND_BLOCK_SIZE		SZ_128K
+
+static struct mtd_partition davinci_nand_partitions[] = {
+	{
+		/* UBL (a few copies) plus U-Boot */
+		.name		= "bootloader",
+		.offset		= 0,
+		.size		= 15 * NAND_BLOCK_SIZE,
+		.mask_flags	= MTD_WRITEABLE, /* force read-only */
+	}, {
+		/* U-Boot environment */
+		.name		= "params",
+		.offset		= MTDPART_OFS_APPEND,
+		.size		= 1 * NAND_BLOCK_SIZE,
+		.mask_flags	= 0,
+	}, {
+		.name		= "kernel",
+		.offset		= MTDPART_OFS_APPEND,
+		.size		= SZ_4M,
+		.mask_flags	= 0,
+	}, {
+		.name		= "filesystem1",
+		.offset		= MTDPART_OFS_APPEND,
+		.size		= SZ_512M,
+		.mask_flags	= 0,
+	}, {
+		.name		= "filesystem2",
+		.offset		= MTDPART_OFS_APPEND,
+		.size		= MTDPART_SIZ_FULL,
+		.mask_flags	= 0,
+	}
+	/* two blocks with bad block table (and mirror) at the end */
+};
+
+static struct davinci_nand_pdata davinci_nand_data = {
+	.mask_chipsel		= BIT(14),
+	.parts			= davinci_nand_partitions,
+	.nr_parts		= ARRAY_SIZE(davinci_nand_partitions),
+	.ecc_mode		= NAND_ECC_HW_SYNDROME,
+	.options		= NAND_USE_FLASH_BBT,
+};
+
+static struct resource davinci_nand_resources[] = {
+	{
+		.start		= DAVINCI_ASYNC_EMIF_DATA_CE0_BASE,
+		.end		= DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_32M - 1,
+		.flags		= IORESOURCE_MEM,
+	}, {
+		.start		= DAVINCI_ASYNC_EMIF_CONTROL_BASE,
+		.end		= DAVINCI_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device davinci_nand_device = {
+	.name			= "davinci_nand",
+	.id			= 0,
+
+	.num_resources		= ARRAY_SIZE(davinci_nand_resources),
+	.resource		= davinci_nand_resources,
+
+	.dev			= {
+		.platform_data	= &davinci_nand_data,
+	},
+};
+
+static struct davinci_i2c_platform_data i2c_pdata = {
+	.bus_freq	= 400	/* kHz */,
+	.bus_delay	= 0	/* usec */,
+};
+
+static int leopard_mmc_gpio = -EINVAL;
+
+static void dm355leopard_mmcsd_gpios(unsigned gpio)
+{
+	gpio_request(gpio + 0, "mmc0_ro");
+	gpio_request(gpio + 1, "mmc0_cd");
+	gpio_request(gpio + 2, "mmc1_ro");
+	gpio_request(gpio + 3, "mmc1_cd");
+
+	/* we "know" these are input-only so we don't
+	 * need to call gpio_direction_input()
+	 */
+
+	leopard_mmc_gpio = gpio;
+}
+
+static struct i2c_board_info dm355leopard_i2c_info[] = {
+	{ I2C_BOARD_INFO("dm355leopard_msp", 0x25),
+		.platform_data = dm355leopard_mmcsd_gpios,
+		/* plus irq */ },
+	/* { I2C_BOARD_INFO("tlv320aic3x", 0x1b), }, */
+	/* { I2C_BOARD_INFO("tvp5146", 0x5d), }, */
+};
+
+static void __init leopard_init_i2c(void)
+{
+	davinci_init_i2c(&i2c_pdata);
+
+	gpio_request(5, "dm355leopard_msp");
+	gpio_direction_input(5);
+	dm355leopard_i2c_info[0].irq = gpio_to_irq(5);
+
+	i2c_register_board_info(1, dm355leopard_i2c_info,
+			ARRAY_SIZE(dm355leopard_i2c_info));
+}
+
+static struct resource dm355leopard_dm9000_rsrc[] = {
+	{
+		/* addr */
+		.start	= 0x04000000,
+		.end	= 0x04000001,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		/* data */
+		.start	= 0x04000016,
+		.end	= 0x04000017,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.flags	= IORESOURCE_IRQ
+			| IORESOURCE_IRQ_HIGHEDGE /* rising (active high) */,
+	},
+};
+
+static struct platform_device dm355leopard_dm9000 = {
+	.name		= "dm9000",
+	.id		= -1,
+	.resource	= dm355leopard_dm9000_rsrc,
+	.num_resources	= ARRAY_SIZE(dm355leopard_dm9000_rsrc),
+};
+
+static struct platform_device *davinci_leopard_devices[] __initdata = {
+	&dm355leopard_dm9000,
+	&davinci_nand_device,
+};
+
+static struct davinci_uart_config uart_config __initdata = {
+	.enabled_uarts = (1 << 0),
+};
+
+static void __init dm355_leopard_map_io(void)
+{
+	dm355_init();
+}
+
+static int dm355leopard_mmc_get_cd(int module)
+{
+	if (!gpio_is_valid(leopard_mmc_gpio))
+		return -ENXIO;
+	/* low == card present */
+	return !gpio_get_value_cansleep(leopard_mmc_gpio + 2 * module + 1);
+}
+
+static int dm355leopard_mmc_get_ro(int module)
+{
+	if (!gpio_is_valid(leopard_mmc_gpio))
+		return -ENXIO;
+	/* high == card's write protect switch active */
+	return gpio_get_value_cansleep(leopard_mmc_gpio + 2 * module + 0);
+}
+
+static struct davinci_mmc_config dm355leopard_mmc_config = {
+	.get_cd		= dm355leopard_mmc_get_cd,
+	.get_ro		= dm355leopard_mmc_get_ro,
+	.wires		= 4,
+	.max_freq       = 50000000,
+	.caps           = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
+};
+
+/* Don't connect anything to J10 unless you're only using USB host
+ * mode *and* have to do so with some kind of gender-bender.  If
+ * you have proper Mini-B or Mini-A cables (or Mini-A adapters)
+ * the ID pin won't need any help.
+ */
+#ifdef CONFIG_USB_MUSB_PERIPHERAL
+#define USB_ID_VALUE	0	/* ID pulled high; *should* float */
+#else
+#define USB_ID_VALUE	1	/* ID pulled low */
+#endif
+
+static struct spi_eeprom at25640a = {
+	.byte_len	= SZ_64K / 8,
+	.name		= "at25640a",
+	.page_size	= 32,
+	.flags		= EE_ADDR2,
+};
+
+static struct spi_board_info dm355_leopard_spi_info[] __initconst = {
+	{
+		.modalias	= "at25",
+		.platform_data	= &at25640a,
+		.max_speed_hz	= 10 * 1000 * 1000,	/* at 3v3 */
+		.bus_num	= 0,
+		.chip_select	= 0,
+		.mode		= SPI_MODE_0,
+	},
+};
+
+static __init void dm355_leopard_init(void)
+{
+	struct clk *aemif;
+
+	gpio_request(9, "dm9000");
+	gpio_direction_input(9);
+	dm355leopard_dm9000_rsrc[2].start = gpio_to_irq(9);
+
+	aemif = clk_get(&dm355leopard_dm9000.dev, "aemif");
+	if (IS_ERR(aemif))
+		WARN("%s: unable to get AEMIF clock\n", __func__);
+	else
+		clk_enable(aemif);
+
+	platform_add_devices(davinci_leopard_devices,
+			     ARRAY_SIZE(davinci_leopard_devices));
+	leopard_init_i2c();
+	davinci_serial_init(&uart_config);
+
+	/* NOTE:  NAND flash timings set by the UBL are slower than
+	 * needed by MT29F16G08FAA chips ... EMIF.A1CR is 0x40400204
+	 * but could be 0x0400008c for about 25% faster page reads.
+	 */
+
+	gpio_request(2, "usb_id_toggle");
+	gpio_direction_output(2, USB_ID_VALUE);
+	/* irlml6401 switches over 1A in under 8 msec */
+	setup_usb(500, 8);
+
+	davinci_setup_mmc(0, &dm355leopard_mmc_config);
+	davinci_setup_mmc(1, &dm355leopard_mmc_config);
+
+	dm355_init_spi0(BIT(0), dm355_leopard_spi_info,
+			ARRAY_SIZE(dm355_leopard_spi_info));
+}
+
+static __init void dm355_leopard_irq_init(void)
+{
+	davinci_irq_init();
+}
+
+MACHINE_START(DM355_LEOPARD, "DaVinci DM355 leopard")
+	.phys_io      = IO_PHYS,
+	.io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+	.boot_params  = (0x80000100),
+	.map_io	      = dm355_leopard_map_io,
+	.init_irq     = dm355_leopard_irq_init,
+	.timer	      = &davinci_timer,
+	.init_machine = dm355_leopard_init,
+MACHINE_END
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index b2e7f9c..d9d4045 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -16,12 +16,11 @@
 #include <linux/gpio.h>
 #include <linux/leds.h>
 #include <linux/memory.h>
-#include <linux/etherdevice.h>
 
 #include <linux/i2c.h>
 #include <linux/i2c/pcf857x.h>
 #include <linux/i2c/at24.h>
-
+#include <linux/etherdevice.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
@@ -44,6 +43,9 @@
 #include <mach/mux.h>
 #include <mach/psc.h>
 #include <mach/nand.h>
+#include <mach/mmc.h>
+#include <mach/emac.h>
+#include <mach/common.h>
 
 #define DM644X_EVM_PHY_MASK		(0x2)
 #define DM644X_EVM_MDIO_FREQUENCY	(2200000) /* PHY bus frequency */
@@ -436,45 +438,15 @@
  *  - 0x0039, 1 byte NTSC vs PAL (bit 0x80 == PAL)
  *  - ... newer boards may have more
  */
-static struct memory_accessor *at24_mem_acc;
-
-static void at24_setup(struct memory_accessor *mem_acc, void *context)
-{
-	DECLARE_MAC_BUF(mac_str);
-	char mac_addr[6];
-
-	at24_mem_acc = mem_acc;
-
-	/* Read MAC addr from EEPROM */
-	if (at24_mem_acc->read(at24_mem_acc, mac_addr, 0x7f00, 6) == 6) {
-		printk(KERN_INFO "Read MAC addr from EEPROM: %s\n",
-		       print_mac(mac_str, mac_addr));
-	}
-}
 
 static struct at24_platform_data eeprom_info = {
 	.byte_len	= (256*1024) / 8,
 	.page_size	= 64,
 	.flags		= AT24_FLAG_ADDR16,
-	.setup          = at24_setup,
+	.setup          = davinci_get_mac_addr,
+	.context	= (void *)0x7f00,
 };
 
-int dm6446evm_eeprom_read(void *buf, off_t off, size_t count)
-{
-	if (at24_mem_acc)
-		return at24_mem_acc->read(at24_mem_acc, buf, off, count);
-	return -ENODEV;
-}
-EXPORT_SYMBOL(dm6446evm_eeprom_read);
-
-int dm6446evm_eeprom_write(void *buf, off_t off, size_t count)
-{
-	if (at24_mem_acc)
-		return at24_mem_acc->write(at24_mem_acc, buf, off, count);
-	return -ENODEV;
-}
-EXPORT_SYMBOL(dm6446evm_eeprom_write);
-
 /*
  * MSP430 supports RTC, card detection, input from IR remote, and
  * a bit more.  It triggers interrupts on GPIO(7) from pressing
@@ -545,6 +517,27 @@
 	return (buf[3] << 8) | buf[2];
 }
 
+static int dm6444evm_mmc_get_cd(int module)
+{
+	int status = dm6444evm_msp430_get_pins();
+
+	return (status < 0) ? status : !(status & BIT(1));
+}
+
+static int dm6444evm_mmc_get_ro(int module)
+{
+	int status = dm6444evm_msp430_get_pins();
+
+	return (status < 0) ? status : status & BIT(6 + 8);
+}
+
+static struct davinci_mmc_config dm6446evm_mmc_config = {
+	.get_cd		= dm6444evm_mmc_get_cd,
+	.get_ro		= dm6444evm_mmc_get_ro,
+	.wires		= 4,
+	.version	= MMC_CTLR_VERSION_1
+};
+
 static struct i2c_board_info __initdata i2c_info[] =  {
 	{
 		I2C_BOARD_INFO("dm6446evm_msp", 0x23),
@@ -598,7 +591,6 @@
 static void __init
 davinci_evm_map_io(void)
 {
-	davinci_map_common_io();
 	dm644x_init();
 }
 
@@ -639,6 +631,7 @@
 static __init void davinci_evm_init(void)
 {
 	struct clk *aemif_clk;
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
 
 	aemif_clk = clk_get(NULL, "aemif");
 	clk_enable(aemif_clk);
@@ -671,8 +664,13 @@
 			     ARRAY_SIZE(davinci_evm_devices));
 	evm_init_i2c();
 
+	davinci_setup_mmc(0, &dm6446evm_mmc_config);
+
 	davinci_serial_init(&uart_config);
 
+	soc_info->emac_pdata->phy_mask = DM644X_EVM_PHY_MASK;
+	soc_info->emac_pdata->mdio_max_freq = DM644X_EVM_MDIO_FREQUENCY;
+
 	/* Register the fixup for PHY on DaVinci */
 	phy_register_fixup_for_uid(LXT971_PHY_ID, LXT971_PHY_MASK,
 					davinci_phy_fixup);
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
new file mode 100644
index 0000000..e17de63
--- /dev/null
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -0,0 +1,262 @@
+/*
+ * TI DaVinci DM646X EVM board
+ *
+ * Derived from: arch/arm/mach-davinci/board-evm.c
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * (C) 2007-2008, 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.
+ *
+ */
+
+/**************************************************************************
+ * Included Files
+ **************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <linux/root_dev.h>
+#include <linux/dma-mapping.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+#include <linux/i2c/pcf857x.h>
+#include <linux/etherdevice.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <mach/dm646x.h>
+#include <mach/common.h>
+#include <mach/psc.h>
+#include <mach/serial.h>
+#include <mach/i2c.h>
+#include <mach/mmc.h>
+#include <mach/emac.h>
+#include <mach/common.h>
+
+#define DM646X_EVM_PHY_MASK		(0x2)
+#define DM646X_EVM_MDIO_FREQUENCY	(2200000) /* PHY bus frequency */
+
+static struct davinci_uart_config uart_config __initdata = {
+	.enabled_uarts = (1 << 0),
+};
+
+/* LEDS */
+
+static struct gpio_led evm_leds[] = {
+	{ .name = "DS1", .active_low = 1, },
+	{ .name = "DS2", .active_low = 1, },
+	{ .name = "DS3", .active_low = 1, },
+	{ .name = "DS4", .active_low = 1, },
+};
+
+static __initconst struct gpio_led_platform_data evm_led_data = {
+	.num_leds = ARRAY_SIZE(evm_leds),
+	.leds     = evm_leds,
+};
+
+static struct platform_device *evm_led_dev;
+
+static int evm_led_setup(struct i2c_client *client, int gpio,
+			unsigned int ngpio, void *c)
+{
+	struct gpio_led *leds = evm_leds;
+	int status;
+
+	while (ngpio--) {
+		leds->gpio = gpio++;
+		leds++;
+	};
+
+	evm_led_dev = platform_device_alloc("leds-gpio", 0);
+	platform_device_add_data(evm_led_dev, &evm_led_data,
+				sizeof(evm_led_data));
+
+	evm_led_dev->dev.parent = &client->dev;
+	status = platform_device_add(evm_led_dev);
+	if (status < 0) {
+		platform_device_put(evm_led_dev);
+		evm_led_dev = NULL;
+	}
+	return status;
+}
+
+static int evm_led_teardown(struct i2c_client *client, int gpio,
+				unsigned ngpio, void *c)
+{
+	if (evm_led_dev) {
+		platform_device_unregister(evm_led_dev);
+		evm_led_dev = NULL;
+	}
+	return 0;
+}
+
+static int evm_sw_gpio[4] = { -EINVAL, -EINVAL, -EINVAL, -EINVAL };
+
+static int evm_sw_setup(struct i2c_client *client, int gpio,
+			unsigned ngpio, void *c)
+{
+	int status;
+	int i;
+	char label[10];
+
+	for (i = 0; i < 4; ++i) {
+		snprintf(label, 10, "user_sw%d", i);
+		status = gpio_request(gpio, label);
+		if (status)
+			goto out_free;
+		evm_sw_gpio[i] = gpio++;
+
+		status = gpio_direction_input(evm_sw_gpio[i]);
+		if (status) {
+			gpio_free(evm_sw_gpio[i]);
+			evm_sw_gpio[i] = -EINVAL;
+			goto out_free;
+		}
+
+		status = gpio_export(evm_sw_gpio[i], 0);
+		if (status) {
+			gpio_free(evm_sw_gpio[i]);
+			evm_sw_gpio[i] = -EINVAL;
+			goto out_free;
+		}
+	}
+	return status;
+out_free:
+	for (i = 0; i < 4; ++i) {
+		if (evm_sw_gpio[i] != -EINVAL) {
+			gpio_free(evm_sw_gpio[i]);
+			evm_sw_gpio[i] = -EINVAL;
+		}
+	}
+	return status;
+}
+
+static int evm_sw_teardown(struct i2c_client *client, int gpio,
+			unsigned ngpio, void *c)
+{
+	int i;
+
+	for (i = 0; i < 4; ++i) {
+		if (evm_sw_gpio[i] != -EINVAL) {
+			gpio_unexport(evm_sw_gpio[i]);
+			gpio_free(evm_sw_gpio[i]);
+			evm_sw_gpio[i] = -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static int evm_pcf_setup(struct i2c_client *client, int gpio,
+			unsigned int ngpio, void *c)
+{
+	int status;
+
+	if (ngpio < 8)
+		return -EINVAL;
+
+	status = evm_sw_setup(client, gpio, 4, c);
+	if (status)
+		return status;
+
+	return evm_led_setup(client, gpio+4, 4, c);
+}
+
+static int evm_pcf_teardown(struct i2c_client *client, int gpio,
+			unsigned int ngpio, void *c)
+{
+	BUG_ON(ngpio < 8);
+
+	evm_sw_teardown(client, gpio, 4, c);
+	evm_led_teardown(client, gpio+4, 4, c);
+
+	return 0;
+}
+
+static struct pcf857x_platform_data pcf_data = {
+	.gpio_base	= DAVINCI_N_GPIO+1,
+	.setup		= evm_pcf_setup,
+	.teardown	= evm_pcf_teardown,
+};
+
+/* Most of this EEPROM is unused, but U-Boot uses some data:
+ *  - 0x7f00, 6 bytes Ethernet Address
+ *  - ... newer boards may have more
+ */
+
+static struct at24_platform_data eeprom_info = {
+	.byte_len       = (256*1024) / 8,
+	.page_size      = 64,
+	.flags          = AT24_FLAG_ADDR16,
+	.setup          = davinci_get_mac_addr,
+	.context	= (void *)0x7f00,
+};
+
+static struct i2c_board_info __initdata i2c_info[] =  {
+	{
+		I2C_BOARD_INFO("24c256", 0x50),
+		.platform_data  = &eeprom_info,
+	},
+	{
+		I2C_BOARD_INFO("pcf8574a", 0x38),
+		.platform_data	= &pcf_data,
+	},
+};
+
+static struct davinci_i2c_platform_data i2c_pdata = {
+	.bus_freq       = 100 /* kHz */,
+	.bus_delay      = 0 /* usec */,
+};
+
+static void __init evm_init_i2c(void)
+{
+	davinci_init_i2c(&i2c_pdata);
+	i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
+}
+
+static void __init davinci_map_io(void)
+{
+	dm646x_init();
+}
+
+static __init void evm_init(void)
+{
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+	evm_init_i2c();
+	davinci_serial_init(&uart_config);
+
+	soc_info->emac_pdata->phy_mask = DM646X_EVM_PHY_MASK;
+	soc_info->emac_pdata->mdio_max_freq = DM646X_EVM_MDIO_FREQUENCY;
+}
+
+static __init void davinci_dm646x_evm_irq_init(void)
+{
+	davinci_irq_init();
+}
+
+MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM")
+	.phys_io      = IO_PHYS,
+	.io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+	.boot_params  = (0x80000100),
+	.map_io       = davinci_map_io,
+	.init_irq     = davinci_dm646x_evm_irq_init,
+	.timer        = &davinci_timer,
+	.init_machine = evm_init,
+MACHINE_END
+
diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c
new file mode 100644
index 0000000..748a8e4
--- /dev/null
+++ b/arch/arm/mach-davinci/board-sffsdr.c
@@ -0,0 +1,189 @@
+/*
+ * Lyrtech SFFSDR board support.
+ *
+ * Copyright (C) 2008 Philip Balister, OpenSDR <philip@opensdr.com>
+ * Copyright (C) 2008 Lyrtech <www.lyrtech.com>
+ *
+ * Based on DV-EVM platform, original copyright follows:
+ *
+ * Copyright (C) 2007 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+#include <linux/etherdevice.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/io.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <mach/dm644x.h>
+#include <mach/common.h>
+#include <mach/i2c.h>
+#include <mach/serial.h>
+#include <mach/psc.h>
+#include <mach/mux.h>
+#include <mach/common.h>
+
+#define SFFSDR_PHY_MASK		(0x2)
+#define SFFSDR_MDIO_FREQUENCY	(2200000) /* PHY bus frequency */
+
+#define DAVINCI_ASYNC_EMIF_CONTROL_BASE   0x01e00000
+#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE  0x02000000
+
+struct mtd_partition davinci_sffsdr_nandflash_partition[] = {
+	/* U-Boot Environment: Block 0
+	 * UBL:                Block 1
+	 * U-Boot:             Blocks 6-7 (256 kb)
+	 * Integrity Kernel:   Blocks 8-31 (3 Mb)
+	 * Integrity Data:     Blocks 100-END
+	 */
+	{
+		.name		= "Linux Kernel",
+		.offset		= 32 * SZ_128K,
+		.size		= 16 * SZ_128K, /* 2 Mb */
+		.mask_flags	= MTD_WRITEABLE, /* Force read-only */
+	},
+	{
+		.name		= "Linux ROOT",
+		.offset		= MTDPART_OFS_APPEND,
+		.size		= 256 * SZ_128K, /* 32 Mb */
+		.mask_flags	= 0, /* R/W */
+	},
+};
+
+static struct flash_platform_data davinci_sffsdr_nandflash_data = {
+	.parts		= davinci_sffsdr_nandflash_partition,
+	.nr_parts	= ARRAY_SIZE(davinci_sffsdr_nandflash_partition),
+};
+
+static struct resource davinci_sffsdr_nandflash_resource[] = {
+	{
+		.start		= DAVINCI_ASYNC_EMIF_DATA_CE0_BASE,
+		.end		= DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_16M - 1,
+		.flags		= IORESOURCE_MEM,
+	}, {
+		.start		= DAVINCI_ASYNC_EMIF_CONTROL_BASE,
+		.end		= DAVINCI_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device davinci_sffsdr_nandflash_device = {
+	.name		= "davinci_nand", /* Name of driver */
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &davinci_sffsdr_nandflash_data,
+	},
+	.num_resources	= ARRAY_SIZE(davinci_sffsdr_nandflash_resource),
+	.resource	= davinci_sffsdr_nandflash_resource,
+};
+
+static struct emac_platform_data sffsdr_emac_pdata = {
+	.phy_mask	= SFFSDR_PHY_MASK,
+	.mdio_max_freq	= SFFSDR_MDIO_FREQUENCY,
+};
+
+static struct at24_platform_data eeprom_info = {
+	.byte_len	= (64*1024) / 8,
+	.page_size	= 32,
+	.flags		= AT24_FLAG_ADDR16,
+};
+
+static struct i2c_board_info __initdata i2c_info[] =  {
+	{
+		I2C_BOARD_INFO("24lc64", 0x50),
+		.platform_data	= &eeprom_info,
+	},
+	/* Other I2C devices:
+	 * MSP430,  addr 0x23 (not used)
+	 * PCA9543, addr 0x70 (setup done by U-Boot)
+	 * ADS7828, addr 0x48 (ADC for voltage monitoring.)
+	 */
+};
+
+static struct davinci_i2c_platform_data i2c_pdata = {
+	.bus_freq	= 20 /* kHz */,
+	.bus_delay	= 100 /* usec */,
+};
+
+static void __init sffsdr_init_i2c(void)
+{
+	davinci_init_i2c(&i2c_pdata);
+	i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
+}
+
+static struct platform_device *davinci_sffsdr_devices[] __initdata = {
+	&davinci_sffsdr_nandflash_device,
+};
+
+static struct davinci_uart_config uart_config __initdata = {
+	.enabled_uarts = (1 << 0),
+};
+
+static void __init davinci_sffsdr_map_io(void)
+{
+	dm644x_init();
+}
+
+static __init void davinci_sffsdr_init(void)
+{
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+	platform_add_devices(davinci_sffsdr_devices,
+			     ARRAY_SIZE(davinci_sffsdr_devices));
+	sffsdr_init_i2c();
+	davinci_serial_init(&uart_config);
+	soc_info->emac_pdata->phy_mask = SFFSDR_PHY_MASK;
+	soc_info->emac_pdata->mdio_max_freq = SFFSDR_MDIO_FREQUENCY;
+	setup_usb(0, 0); /* We support only peripheral mode. */
+
+	/* mux VLYNQ pins */
+	davinci_cfg_reg(DM644X_VLYNQEN);
+	davinci_cfg_reg(DM644X_VLYNQWD);
+}
+
+static __init void davinci_sffsdr_irq_init(void)
+{
+	davinci_irq_init();
+}
+
+MACHINE_START(SFFSDR, "Lyrtech SFFSDR")
+	/* Maintainer: Hugo Villeneuve hugo.villeneuve@lyrtech.com */
+	.phys_io      = IO_PHYS,
+	.io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+	.boot_params  = (DAVINCI_DDR_BASE + 0x100),
+	.map_io	      = davinci_sffsdr_map_io,
+	.init_irq     = davinci_sffsdr_irq_init,
+	.timer	      = &davinci_timer,
+	.init_machine = davinci_sffsdr_init,
+MACHINE_END
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index f0baaa1..39bf321 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -42,7 +42,8 @@
 	if (clk->parent)
 		__clk_enable(clk->parent);
 	if (clk->usecount++ == 0 && (clk->flags & CLK_PSC))
-		davinci_psc_config(psc_domain(clk), clk->lpsc, 1);
+		davinci_psc_config(psc_domain(clk), clk->psc_ctlr,
+				clk->lpsc, 1);
 }
 
 static void __clk_disable(struct clk *clk)
@@ -50,7 +51,8 @@
 	if (WARN_ON(clk->usecount == 0))
 		return;
 	if (--clk->usecount == 0 && !(clk->flags & CLK_PLL))
-		davinci_psc_config(psc_domain(clk), clk->lpsc, 0);
+		davinci_psc_config(psc_domain(clk), clk->psc_ctlr,
+				clk->lpsc, 0);
 	if (clk->parent)
 		__clk_disable(clk->parent);
 }
@@ -164,11 +166,11 @@
 			continue;
 
 		/* ignore if in Disabled or SwRstDisable states */
-		if (!davinci_psc_is_clk_active(ck->lpsc))
+		if (!davinci_psc_is_clk_active(ck->psc_ctlr, ck->lpsc))
 			continue;
 
 		pr_info("Clocks: disable unused %s\n", ck->name);
-		davinci_psc_config(psc_domain(ck), ck->lpsc, 0);
+		davinci_psc_config(psc_domain(ck), ck->psc_ctlr, ck->lpsc, 0);
 	}
 	spin_unlock_irq(&clockfw_lock);
 
diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
index 35736ec..27233cb 100644
--- a/arch/arm/mach-davinci/clock.h
+++ b/arch/arm/mach-davinci/clock.h
@@ -67,6 +67,7 @@
 	u8			usecount;
 	u8			flags;
 	u8			lpsc;
+	u8			psc_ctlr;
 	struct clk              *parent;
 	struct pll_data         *pll_data;
 	u32                     div_reg;
@@ -93,4 +94,7 @@
 	}
 
 int davinci_clk_init(struct davinci_clk *clocks);
+
+extern struct platform_device davinci_wdt_device;
+
 #endif
diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c
new file mode 100644
index 0000000..61ede19
--- /dev/null
+++ b/arch/arm/mach-davinci/common.c
@@ -0,0 +1,108 @@
+/*
+ * Code commons to all DaVinci SoCs.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2009 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/etherdevice.h>
+
+#include <asm/tlb.h>
+#include <asm/mach/map.h>
+
+#include <mach/common.h>
+#include <mach/cputype.h>
+#include <mach/emac.h>
+
+#include "clock.h"
+
+struct davinci_soc_info davinci_soc_info;
+EXPORT_SYMBOL(davinci_soc_info);
+
+void __iomem *davinci_intc_base;
+int davinci_intc_type;
+
+void davinci_get_mac_addr(struct memory_accessor *mem_acc, void *context)
+{
+	char *mac_addr = davinci_soc_info.emac_pdata->mac_addr;
+	off_t offset = (off_t)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);
+}
+
+static struct davinci_id * __init davinci_get_id(u32 jtag_id)
+{
+	int i;
+	struct davinci_id *dip;
+	u8 variant = (jtag_id & 0xf0000000) >> 28;
+	u16 part_no = (jtag_id & 0x0ffff000) >> 12;
+
+	for (i = 0, dip = davinci_soc_info.ids; i < davinci_soc_info.ids_num;
+			i++, dip++)
+		/* Don't care about the manufacturer right now */
+		if ((dip->part_no == part_no) && (dip->variant == variant))
+			return dip;
+
+	return NULL;
+}
+
+void __init davinci_common_init(struct davinci_soc_info *soc_info)
+{
+	int ret;
+	struct davinci_id *dip;
+
+	if (!soc_info) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	memcpy(&davinci_soc_info, soc_info, sizeof(struct davinci_soc_info));
+
+	if (davinci_soc_info.io_desc && (davinci_soc_info.io_desc_num > 0))
+		iotable_init(davinci_soc_info.io_desc,
+				davinci_soc_info.io_desc_num);
+
+	/*
+	 * Normally devicemaps_init() would flush caches and tlb after
+	 * mdesc->map_io(), but we must also do it here because of the CPU
+	 * revision check below.
+	 */
+	local_flush_tlb_all();
+	flush_cache_all();
+
+	/*
+	 * We want to check CPU revision early for cpu_is_xxxx() macros.
+	 * IO space mapping must be initialized before we can do that.
+	 */
+	davinci_soc_info.jtag_id = __raw_readl(davinci_soc_info.jtag_id_base);
+
+	dip = davinci_get_id(davinci_soc_info.jtag_id);
+	if (!dip) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	davinci_soc_info.cpu_id = dip->cpu_id;
+	pr_info("DaVinci %s variant 0x%x\n", dip->name, dip->variant);
+
+	if (davinci_soc_info.cpu_clks) {
+		ret = davinci_clk_init(davinci_soc_info.cpu_clks);
+
+		if (ret != 0)
+			goto err;
+	}
+
+	davinci_intc_base = davinci_soc_info.intc_base;
+	davinci_intc_type = davinci_soc_info.intc_type;
+	return;
+
+err:
+	pr_err("davinci_common_init: SoC Initialization failed\n");
+}
diff --git a/arch/arm/mach-davinci/cp_intc.c b/arch/arm/mach-davinci/cp_intc.c
new file mode 100644
index 0000000..96c8e97
--- /dev/null
+++ b/arch/arm/mach-davinci/cp_intc.c
@@ -0,0 +1,161 @@
+/*
+ * TI Common Platform Interrupt Controller (cp_intc) driver
+ *
+ * Author: Steve Chen <schen@mvista.com>
+ * Copyright (C) 2008-2009, MontaVista Software, Inc. <source@mvista.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/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <mach/cp_intc.h>
+
+static void __iomem *cp_intc_base;
+
+static inline unsigned int cp_intc_read(unsigned offset)
+{
+	return __raw_readl(cp_intc_base + offset);
+}
+
+static inline void cp_intc_write(unsigned long value, unsigned offset)
+{
+	__raw_writel(value, cp_intc_base + offset);
+}
+
+static void cp_intc_ack_irq(unsigned int irq)
+{
+	cp_intc_write(irq, CP_INTC_SYS_STAT_IDX_CLR);
+}
+
+/* Disable interrupt */
+static void cp_intc_mask_irq(unsigned int irq)
+{
+	/* XXX don't know why we need to disable nIRQ here... */
+	cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR);
+	cp_intc_write(irq, CP_INTC_SYS_ENABLE_IDX_CLR);
+	cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET);
+}
+
+/* Enable interrupt */
+static void cp_intc_unmask_irq(unsigned int irq)
+{
+	cp_intc_write(irq, CP_INTC_SYS_ENABLE_IDX_SET);
+}
+
+static int cp_intc_set_irq_type(unsigned int irq, unsigned int flow_type)
+{
+	unsigned reg		= BIT_WORD(irq);
+	unsigned mask		= BIT_MASK(irq);
+	unsigned polarity	= cp_intc_read(CP_INTC_SYS_POLARITY(reg));
+	unsigned type		= cp_intc_read(CP_INTC_SYS_TYPE(reg));
+
+	switch (flow_type) {
+	case IRQ_TYPE_EDGE_RISING:
+		polarity |= mask;
+		type |= mask;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		polarity &= ~mask;
+		type |= mask;
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		polarity |= mask;
+		type &= ~mask;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		polarity &= ~mask;
+		type &= ~mask;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	cp_intc_write(polarity, CP_INTC_SYS_POLARITY(reg));
+	cp_intc_write(type, CP_INTC_SYS_TYPE(reg));
+
+	return 0;
+}
+
+static struct irq_chip cp_intc_irq_chip = {
+	.name		= "cp_intc",
+	.ack		= cp_intc_ack_irq,
+	.mask		= cp_intc_mask_irq,
+	.unmask		= cp_intc_unmask_irq,
+	.set_type	= cp_intc_set_irq_type,
+};
+
+void __init cp_intc_init(void __iomem *base, unsigned short num_irq,
+			 u8 *irq_prio)
+{
+	unsigned num_reg	= BITS_TO_LONGS(num_irq);
+	int i;
+
+	cp_intc_base = base;
+
+	cp_intc_write(0, CP_INTC_GLOBAL_ENABLE);
+
+	/* Disable all host interrupts */
+	cp_intc_write(0, CP_INTC_HOST_ENABLE(0));
+
+	/* Disable system interrupts */
+	for (i = 0; i < num_reg; i++)
+		cp_intc_write(~0, CP_INTC_SYS_ENABLE_CLR(i));
+
+	/* Set to normal mode, no nesting, no priority hold */
+	cp_intc_write(0, CP_INTC_CTRL);
+	cp_intc_write(0, CP_INTC_HOST_CTRL);
+
+	/* Clear system interrupt status */
+	for (i = 0; i < num_reg; i++)
+		cp_intc_write(~0, CP_INTC_SYS_STAT_CLR(i));
+
+	/* Enable nIRQ (what about nFIQ?) */
+	cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET);
+
+	/*
+	 * Priority is determined by host channel: lower channel number has
+	 * higher priority i.e. channel 0 has highest priority and channel 31
+	 * had the lowest priority.
+	 */
+	num_reg = (num_irq + 3) >> 2;	/* 4 channels per register */
+	if (irq_prio) {
+		unsigned j, k;
+		u32 val;
+
+		for (k = i = 0; i < num_reg; i++) {
+			for (val = j = 0; j < 4; j++, k++) {
+				val >>= 8;
+				if (k < num_irq)
+					val |= irq_prio[k] << 24;
+			}
+
+			cp_intc_write(val, CP_INTC_CHAN_MAP(i));
+		}
+	} else	{
+		/*
+		 * Default everything to channel 15 if priority not specified.
+		 * Note that channel 0-1 are mapped to nFIQ and channels 2-31
+		 * are mapped to nIRQ.
+		 */
+		for (i = 0; i < num_reg; i++)
+			cp_intc_write(0x0f0f0f0f, CP_INTC_CHAN_MAP(i));
+	}
+
+	/* Set up genirq dispatching for cp_intc */
+	for (i = 0; i < num_irq; i++) {
+		set_irq_chip(i, &cp_intc_irq_chip);
+		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+		set_irq_handler(i, handle_edge_irq);
+	}
+
+	/* Enable global interrupt */
+	cp_intc_write(1, CP_INTC_GLOBAL_ENABLE);
+}
diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c
index a31370b..de16f34 100644
--- a/arch/arm/mach-davinci/devices.c
+++ b/arch/arm/mach-davinci/devices.c
@@ -23,8 +23,14 @@
 #include <mach/irqs.h>
 #include <mach/cputype.h>
 #include <mach/mux.h>
+#include <mach/edma.h>
+#include <mach/mmc.h>
+#include <mach/time.h>
 
 #define DAVINCI_I2C_BASE	     0x01C21000
+#define DAVINCI_MMCSD0_BASE	     0x01E10000
+#define DM355_MMCSD0_BASE	     0x01E11000
+#define DM355_MMCSD1_BASE	     0x01E00000
 
 static struct resource i2c_resources[] = {
 	{
@@ -54,3 +60,208 @@
 	(void) platform_device_register(&davinci_i2c_device);
 }
 
+#if	defined(CONFIG_MMC_DAVINCI) || defined(CONFIG_MMC_DAVINCI_MODULE)
+
+static u64 mmcsd0_dma_mask = DMA_BIT_MASK(32);
+
+static struct resource mmcsd0_resources[] = {
+	{
+		/* different on dm355 */
+		.start = DAVINCI_MMCSD0_BASE,
+		.end   = DAVINCI_MMCSD0_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	/* IRQs:  MMC/SD, then SDIO */
+	{
+		.start = IRQ_MMCINT,
+		.flags = IORESOURCE_IRQ,
+	}, {
+		/* different on dm355 */
+		.start = IRQ_SDIOINT,
+		.flags = IORESOURCE_IRQ,
+	},
+	/* DMA channels: RX, then TX */
+	{
+		.start = DAVINCI_DMA_MMCRXEVT,
+		.flags = IORESOURCE_DMA,
+	}, {
+		.start = DAVINCI_DMA_MMCTXEVT,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device davinci_mmcsd0_device = {
+	.name = "davinci_mmc",
+	.id = 0,
+	.dev = {
+		.dma_mask = &mmcsd0_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.num_resources = ARRAY_SIZE(mmcsd0_resources),
+	.resource = mmcsd0_resources,
+};
+
+static u64 mmcsd1_dma_mask = DMA_BIT_MASK(32);
+
+static struct resource mmcsd1_resources[] = {
+	{
+		.start = DM355_MMCSD1_BASE,
+		.end   = DM355_MMCSD1_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	/* IRQs:  MMC/SD, then SDIO */
+	{
+		.start = IRQ_DM355_MMCINT1,
+		.flags = IORESOURCE_IRQ,
+	}, {
+		.start = IRQ_DM355_SDIOINT1,
+		.flags = IORESOURCE_IRQ,
+	},
+	/* DMA channels: RX, then TX */
+	{
+		.start = 30,	/* rx */
+		.flags = IORESOURCE_DMA,
+	}, {
+		.start = 31,	/* tx */
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device davinci_mmcsd1_device = {
+	.name = "davinci_mmc",
+	.id = 1,
+	.dev = {
+		.dma_mask = &mmcsd1_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.num_resources = ARRAY_SIZE(mmcsd1_resources),
+	.resource = mmcsd1_resources,
+};
+
+
+void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
+{
+	struct platform_device	*pdev = NULL;
+
+	if (WARN_ON(cpu_is_davinci_dm646x()))
+		return;
+
+	/* REVISIT: update PINMUX, ARM_IRQMUX, and EDMA_EVTMUX here too;
+	 * for example if MMCSD1 is used for SDIO, maybe DAT2 is unused.
+	 *
+	 * FIXME dm6441 (no MMC/SD), dm357 (one), and dm335 (two) are
+	 * not handled right here ...
+	 */
+	switch (module) {
+	case 1:
+		if (!cpu_is_davinci_dm355())
+			break;
+
+		/* REVISIT we may not need all these pins if e.g. this
+		 * is a hard-wired SDIO device...
+		 */
+		davinci_cfg_reg(DM355_SD1_CMD);
+		davinci_cfg_reg(DM355_SD1_CLK);
+		davinci_cfg_reg(DM355_SD1_DATA0);
+		davinci_cfg_reg(DM355_SD1_DATA1);
+		davinci_cfg_reg(DM355_SD1_DATA2);
+		davinci_cfg_reg(DM355_SD1_DATA3);
+
+		pdev = &davinci_mmcsd1_device;
+		break;
+	case 0:
+		if (cpu_is_davinci_dm355()) {
+			mmcsd0_resources[0].start = DM355_MMCSD0_BASE;
+			mmcsd0_resources[0].end = DM355_MMCSD0_BASE + SZ_4K - 1;
+			mmcsd0_resources[2].start = IRQ_DM355_SDIOINT0;
+
+			/* expose all 6 MMC0 signals:  CLK, CMD, DATA[0..3] */
+			davinci_cfg_reg(DM355_MMCSD0);
+
+			/* enable RX EDMA */
+			davinci_cfg_reg(DM355_EVT26_MMC0_RX);
+		}
+
+		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);
+			/*Set up the pull regiter for MMC */
+			davinci_cfg_reg(DM644X_MSTK);
+		}
+
+		pdev = &davinci_mmcsd0_device;
+		break;
+	}
+
+	if (WARN_ON(!pdev))
+		return;
+
+	pdev->dev.platform_data = config;
+	platform_device_register(pdev);
+}
+
+#else
+
+void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
+{
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static struct resource wdt_resources[] = {
+	{
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device davinci_wdt_device = {
+	.name		= "watchdog",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(wdt_resources),
+	.resource	= wdt_resources,
+};
+
+static void davinci_init_wdt(void)
+{
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+	wdt_resources[0].start = (resource_size_t)soc_info->wdt_base;
+	wdt_resources[0].end = (resource_size_t)soc_info->wdt_base + SZ_1K - 1;
+
+	platform_device_register(&davinci_wdt_device);
+}
+
+/*-------------------------------------------------------------------------*/
+
+struct davinci_timer_instance davinci_timer_instance[2] = {
+	{
+		.base		= IO_ADDRESS(DAVINCI_TIMER0_BASE),
+		.bottom_irq	= IRQ_TINT0_TINT12,
+		.top_irq	= IRQ_TINT0_TINT34,
+	},
+	{
+		.base		= IO_ADDRESS(DAVINCI_TIMER1_BASE),
+		.bottom_irq	= IRQ_TINT1_TINT12,
+		.top_irq	= IRQ_TINT1_TINT34,
+	},
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init davinci_init_devices(void)
+{
+	/* please keep these calls, and their implementations above,
+	 * in alphabetical order so they're easier to sort through.
+	 */
+	davinci_init_wdt();
+
+	return 0;
+}
+arch_initcall(davinci_init_devices);
+
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
new file mode 100644
index 0000000..baaaf32
--- /dev/null
+++ b/arch/arm/mach-davinci/dm355.c
@@ -0,0 +1,730 @@
+/*
+ * TI DaVinci DM355 chip specific setup
+ *
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/serial_8250.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+
+#include <linux/spi/spi.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/dm355.h>
+#include <mach/clock.h>
+#include <mach/cputype.h>
+#include <mach/edma.h>
+#include <mach/psc.h>
+#include <mach/mux.h>
+#include <mach/irqs.h>
+#include <mach/time.h>
+#include <mach/serial.h>
+#include <mach/common.h>
+
+#include "clock.h"
+#include "mux.h"
+
+#define DM355_UART2_BASE	(IO_PHYS + 0x206000)
+
+/*
+ * Device specific clocks
+ */
+#define DM355_REF_FREQ		24000000	/* 24 or 36 MHz */
+
+static struct pll_data pll1_data = {
+	.num       = 1,
+	.phys_base = DAVINCI_PLL1_BASE,
+	.flags     = PLL_HAS_PREDIV | PLL_HAS_POSTDIV,
+};
+
+static struct pll_data pll2_data = {
+	.num       = 2,
+	.phys_base = DAVINCI_PLL2_BASE,
+	.flags     = PLL_HAS_PREDIV,
+};
+
+static struct clk ref_clk = {
+	.name = "ref_clk",
+	/* FIXME -- crystal rate is board-specific */
+	.rate = DM355_REF_FREQ,
+};
+
+static struct clk pll1_clk = {
+	.name = "pll1",
+	.parent = &ref_clk,
+	.flags = CLK_PLL,
+	.pll_data = &pll1_data,
+};
+
+static struct clk pll1_aux_clk = {
+	.name = "pll1_aux_clk",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL | PRE_PLL,
+};
+
+static struct clk pll1_sysclk1 = {
+	.name = "pll1_sysclk1",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL,
+	.div_reg = PLLDIV1,
+};
+
+static struct clk pll1_sysclk2 = {
+	.name = "pll1_sysclk2",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL,
+	.div_reg = PLLDIV2,
+};
+
+static struct clk pll1_sysclk3 = {
+	.name = "pll1_sysclk3",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL,
+	.div_reg = PLLDIV3,
+};
+
+static struct clk pll1_sysclk4 = {
+	.name = "pll1_sysclk4",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL,
+	.div_reg = PLLDIV4,
+};
+
+static struct clk pll1_sysclkbp = {
+	.name = "pll1_sysclkbp",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL | PRE_PLL,
+	.div_reg = BPDIV
+};
+
+static struct clk vpss_dac_clk = {
+	.name = "vpss_dac",
+	.parent = &pll1_sysclk3,
+	.lpsc = DM355_LPSC_VPSS_DAC,
+};
+
+static struct clk vpss_master_clk = {
+	.name = "vpss_master",
+	.parent = &pll1_sysclk4,
+	.lpsc = DAVINCI_LPSC_VPSSMSTR,
+	.flags = CLK_PSC,
+};
+
+static struct clk vpss_slave_clk = {
+	.name = "vpss_slave",
+	.parent = &pll1_sysclk4,
+	.lpsc = DAVINCI_LPSC_VPSSSLV,
+};
+
+
+static struct clk clkout1_clk = {
+	.name = "clkout1",
+	.parent = &pll1_aux_clk,
+	/* NOTE:  clkout1 can be externally gated by muxing GPIO-18 */
+};
+
+static struct clk clkout2_clk = {
+	.name = "clkout2",
+	.parent = &pll1_sysclkbp,
+};
+
+static struct clk pll2_clk = {
+	.name = "pll2",
+	.parent = &ref_clk,
+	.flags = CLK_PLL,
+	.pll_data = &pll2_data,
+};
+
+static struct clk pll2_sysclk1 = {
+	.name = "pll2_sysclk1",
+	.parent = &pll2_clk,
+	.flags = CLK_PLL,
+	.div_reg = PLLDIV1,
+};
+
+static struct clk pll2_sysclkbp = {
+	.name = "pll2_sysclkbp",
+	.parent = &pll2_clk,
+	.flags = CLK_PLL | PRE_PLL,
+	.div_reg = BPDIV
+};
+
+static struct clk clkout3_clk = {
+	.name = "clkout3",
+	.parent = &pll2_sysclkbp,
+	/* NOTE:  clkout3 can be externally gated by muxing GPIO-16 */
+};
+
+static struct clk arm_clk = {
+	.name = "arm_clk",
+	.parent = &pll1_sysclk1,
+	.lpsc = DAVINCI_LPSC_ARM,
+	.flags = ALWAYS_ENABLED,
+};
+
+/*
+ * NOT LISTED below, and not touched by Linux
+ *   - in SyncReset state by default
+ *	.lpsc = DAVINCI_LPSC_TPCC,
+ *	.lpsc = DAVINCI_LPSC_TPTC0,
+ *	.lpsc = DAVINCI_LPSC_TPTC1,
+ *	.lpsc = DAVINCI_LPSC_DDR_EMIF, .parent = &sysclk2_clk,
+ *	.lpsc = DAVINCI_LPSC_MEMSTICK,
+ *   - in Enabled state by default
+ *	.lpsc = DAVINCI_LPSC_SYSTEM_SUBSYS,
+ *	.lpsc = DAVINCI_LPSC_SCR2,	// "bus"
+ *	.lpsc = DAVINCI_LPSC_SCR3,	// "bus"
+ *	.lpsc = DAVINCI_LPSC_SCR4,	// "bus"
+ *	.lpsc = DAVINCI_LPSC_CROSSBAR,	// "emulation"
+ *	.lpsc = DAVINCI_LPSC_CFG27,	// "test"
+ *	.lpsc = DAVINCI_LPSC_CFG3,	// "test"
+ *	.lpsc = DAVINCI_LPSC_CFG5,	// "test"
+ */
+
+static struct clk mjcp_clk = {
+	.name = "mjcp",
+	.parent = &pll1_sysclk1,
+	.lpsc = DAVINCI_LPSC_IMCOP,
+};
+
+static struct clk uart0_clk = {
+	.name = "uart0",
+	.parent = &pll1_aux_clk,
+	.lpsc = DAVINCI_LPSC_UART0,
+};
+
+static struct clk uart1_clk = {
+	.name = "uart1",
+	.parent = &pll1_aux_clk,
+	.lpsc = DAVINCI_LPSC_UART1,
+};
+
+static struct clk uart2_clk = {
+	.name = "uart2",
+	.parent = &pll1_sysclk2,
+	.lpsc = DAVINCI_LPSC_UART2,
+};
+
+static struct clk i2c_clk = {
+	.name = "i2c",
+	.parent = &pll1_aux_clk,
+	.lpsc = DAVINCI_LPSC_I2C,
+};
+
+static struct clk asp0_clk = {
+	.name = "asp0",
+	.parent = &pll1_sysclk2,
+	.lpsc = DAVINCI_LPSC_McBSP,
+};
+
+static struct clk asp1_clk = {
+	.name = "asp1",
+	.parent = &pll1_sysclk2,
+	.lpsc = DM355_LPSC_McBSP1,
+};
+
+static struct clk mmcsd0_clk = {
+	.name = "mmcsd0",
+	.parent = &pll1_sysclk2,
+	.lpsc = DAVINCI_LPSC_MMC_SD,
+};
+
+static struct clk mmcsd1_clk = {
+	.name = "mmcsd1",
+	.parent = &pll1_sysclk2,
+	.lpsc = DM355_LPSC_MMC_SD1,
+};
+
+static struct clk spi0_clk = {
+	.name = "spi0",
+	.parent = &pll1_sysclk2,
+	.lpsc = DAVINCI_LPSC_SPI,
+};
+
+static struct clk spi1_clk = {
+	.name = "spi1",
+	.parent = &pll1_sysclk2,
+	.lpsc = DM355_LPSC_SPI1,
+};
+
+static struct clk spi2_clk = {
+	.name = "spi2",
+	.parent = &pll1_sysclk2,
+	.lpsc = DM355_LPSC_SPI2,
+};
+
+static struct clk gpio_clk = {
+	.name = "gpio",
+	.parent = &pll1_sysclk2,
+	.lpsc = DAVINCI_LPSC_GPIO,
+};
+
+static struct clk aemif_clk = {
+	.name = "aemif",
+	.parent = &pll1_sysclk2,
+	.lpsc = DAVINCI_LPSC_AEMIF,
+};
+
+static struct clk pwm0_clk = {
+	.name = "pwm0",
+	.parent = &pll1_aux_clk,
+	.lpsc = DAVINCI_LPSC_PWM0,
+};
+
+static struct clk pwm1_clk = {
+	.name = "pwm1",
+	.parent = &pll1_aux_clk,
+	.lpsc = DAVINCI_LPSC_PWM1,
+};
+
+static struct clk pwm2_clk = {
+	.name = "pwm2",
+	.parent = &pll1_aux_clk,
+	.lpsc = DAVINCI_LPSC_PWM2,
+};
+
+static struct clk pwm3_clk = {
+	.name = "pwm3",
+	.parent = &pll1_aux_clk,
+	.lpsc = DM355_LPSC_PWM3,
+};
+
+static struct clk timer0_clk = {
+	.name = "timer0",
+	.parent = &pll1_aux_clk,
+	.lpsc = DAVINCI_LPSC_TIMER0,
+};
+
+static struct clk timer1_clk = {
+	.name = "timer1",
+	.parent = &pll1_aux_clk,
+	.lpsc = DAVINCI_LPSC_TIMER1,
+};
+
+static struct clk timer2_clk = {
+	.name = "timer2",
+	.parent = &pll1_aux_clk,
+	.lpsc = DAVINCI_LPSC_TIMER2,
+	.usecount = 1,              /* REVISIT: why cant' this be disabled? */
+};
+
+static struct clk timer3_clk = {
+	.name = "timer3",
+	.parent = &pll1_aux_clk,
+	.lpsc = DM355_LPSC_TIMER3,
+};
+
+static struct clk rto_clk = {
+	.name = "rto",
+	.parent = &pll1_aux_clk,
+	.lpsc = DM355_LPSC_RTO,
+};
+
+static struct clk usb_clk = {
+	.name = "usb",
+	.parent = &pll1_sysclk2,
+	.lpsc = DAVINCI_LPSC_USB,
+};
+
+static struct davinci_clk dm355_clks[] = {
+	CLK(NULL, "ref", &ref_clk),
+	CLK(NULL, "pll1", &pll1_clk),
+	CLK(NULL, "pll1_sysclk1", &pll1_sysclk1),
+	CLK(NULL, "pll1_sysclk2", &pll1_sysclk2),
+	CLK(NULL, "pll1_sysclk3", &pll1_sysclk3),
+	CLK(NULL, "pll1_sysclk4", &pll1_sysclk4),
+	CLK(NULL, "pll1_aux", &pll1_aux_clk),
+	CLK(NULL, "pll1_sysclkbp", &pll1_sysclkbp),
+	CLK(NULL, "vpss_dac", &vpss_dac_clk),
+	CLK(NULL, "vpss_master", &vpss_master_clk),
+	CLK(NULL, "vpss_slave", &vpss_slave_clk),
+	CLK(NULL, "clkout1", &clkout1_clk),
+	CLK(NULL, "clkout2", &clkout2_clk),
+	CLK(NULL, "pll2", &pll2_clk),
+	CLK(NULL, "pll2_sysclk1", &pll2_sysclk1),
+	CLK(NULL, "pll2_sysclkbp", &pll2_sysclkbp),
+	CLK(NULL, "clkout3", &clkout3_clk),
+	CLK(NULL, "arm", &arm_clk),
+	CLK(NULL, "mjcp", &mjcp_clk),
+	CLK(NULL, "uart0", &uart0_clk),
+	CLK(NULL, "uart1", &uart1_clk),
+	CLK(NULL, "uart2", &uart2_clk),
+	CLK("i2c_davinci.1", NULL, &i2c_clk),
+	CLK("soc-audio.0", NULL, &asp0_clk),
+	CLK("soc-audio.1", NULL, &asp1_clk),
+	CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
+	CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
+	CLK(NULL, "spi0", &spi0_clk),
+	CLK(NULL, "spi1", &spi1_clk),
+	CLK(NULL, "spi2", &spi2_clk),
+	CLK(NULL, "gpio", &gpio_clk),
+	CLK(NULL, "aemif", &aemif_clk),
+	CLK(NULL, "pwm0", &pwm0_clk),
+	CLK(NULL, "pwm1", &pwm1_clk),
+	CLK(NULL, "pwm2", &pwm2_clk),
+	CLK(NULL, "pwm3", &pwm3_clk),
+	CLK(NULL, "timer0", &timer0_clk),
+	CLK(NULL, "timer1", &timer1_clk),
+	CLK("watchdog", NULL, &timer2_clk),
+	CLK(NULL, "timer3", &timer3_clk),
+	CLK(NULL, "rto", &rto_clk),
+	CLK(NULL, "usb", &usb_clk),
+	CLK(NULL, NULL, NULL),
+};
+
+/*----------------------------------------------------------------------*/
+
+static u64 dm355_spi0_dma_mask = DMA_BIT_MASK(32);
+
+static struct resource dm355_spi0_resources[] = {
+	{
+		.start = 0x01c66000,
+		.end   = 0x01c667ff,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_DM355_SPINT0_1,
+		.flags = IORESOURCE_IRQ,
+	},
+	/* Not yet used, so not included:
+	 * IORESOURCE_IRQ:
+	 *  - IRQ_DM355_SPINT0_0
+	 * IORESOURCE_DMA:
+	 *  - DAVINCI_DMA_SPI_SPIX
+	 *  - DAVINCI_DMA_SPI_SPIR
+	 */
+};
+
+static struct platform_device dm355_spi0_device = {
+	.name = "spi_davinci",
+	.id = 0,
+	.dev = {
+		.dma_mask = &dm355_spi0_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.num_resources = ARRAY_SIZE(dm355_spi0_resources),
+	.resource = dm355_spi0_resources,
+};
+
+void __init dm355_init_spi0(unsigned chipselect_mask,
+		struct spi_board_info *info, unsigned len)
+{
+	/* for now, assume we need MISO */
+	davinci_cfg_reg(DM355_SPI0_SDI);
+
+	/* not all slaves will be wired up */
+	if (chipselect_mask & BIT(0))
+		davinci_cfg_reg(DM355_SPI0_SDENA0);
+	if (chipselect_mask & BIT(1))
+		davinci_cfg_reg(DM355_SPI0_SDENA1);
+
+	spi_register_board_info(info, len);
+
+	platform_device_register(&dm355_spi0_device);
+}
+
+/*----------------------------------------------------------------------*/
+
+#define PINMUX0		0x00
+#define PINMUX1		0x04
+#define PINMUX2		0x08
+#define PINMUX3		0x0c
+#define PINMUX4		0x10
+#define INTMUX		0x18
+#define EVTMUX		0x1c
+
+/*
+ * Device specific mux setup
+ *
+ *	soc	description	mux  mode   mode  mux	 dbg
+ *				reg  offset mask  mode
+ */
+static const struct mux_config dm355_pins[] = {
+#ifdef CONFIG_DAVINCI_MUX
+MUX_CFG(DM355,	MMCSD0,		4,   2,     1,	  0,	 false)
+
+MUX_CFG(DM355,	SD1_CLK,	3,   6,     1,	  1,	 false)
+MUX_CFG(DM355,	SD1_CMD,	3,   7,     1,	  1,	 false)
+MUX_CFG(DM355,	SD1_DATA3,	3,   8,     3,	  1,	 false)
+MUX_CFG(DM355,	SD1_DATA2,	3,   10,    3,	  1,	 false)
+MUX_CFG(DM355,	SD1_DATA1,	3,   12,    3,	  1,	 false)
+MUX_CFG(DM355,	SD1_DATA0,	3,   14,    3,	  1,	 false)
+
+MUX_CFG(DM355,	I2C_SDA,	3,   19,    1,	  1,	 false)
+MUX_CFG(DM355,	I2C_SCL,	3,   20,    1,	  1,	 false)
+
+MUX_CFG(DM355,	MCBSP0_BDX,	3,   0,     1,	  1,	 false)
+MUX_CFG(DM355,	MCBSP0_X,	3,   1,     1,	  1,	 false)
+MUX_CFG(DM355,	MCBSP0_BFSX,	3,   2,     1,	  1,	 false)
+MUX_CFG(DM355,	MCBSP0_BDR,	3,   3,     1,	  1,	 false)
+MUX_CFG(DM355,	MCBSP0_R,	3,   4,     1,	  1,	 false)
+MUX_CFG(DM355,	MCBSP0_BFSR,	3,   5,     1,	  1,	 false)
+
+MUX_CFG(DM355,	SPI0_SDI,	4,   1,     1,    0,	 false)
+MUX_CFG(DM355,	SPI0_SDENA0,	4,   0,     1,    0,	 false)
+MUX_CFG(DM355,	SPI0_SDENA1,	3,   28,    1,    1,	 false)
+
+INT_CFG(DM355,  INT_EDMA_CC,	      2,    1,    1,     false)
+INT_CFG(DM355,  INT_EDMA_TC0_ERR,     3,    1,    1,     false)
+INT_CFG(DM355,  INT_EDMA_TC1_ERR,     4,    1,    1,     false)
+
+EVT_CFG(DM355,  EVT8_ASP1_TX,	      0,    1,    0,     false)
+EVT_CFG(DM355,  EVT9_ASP1_RX,	      1,    1,    0,     false)
+EVT_CFG(DM355,  EVT26_MMC0_RX,	      2,    1,    0,     false)
+#endif
+};
+
+static u8 dm355_default_priorities[DAVINCI_N_AINTC_IRQ] = {
+	[IRQ_DM355_CCDC_VDINT0]		= 2,
+	[IRQ_DM355_CCDC_VDINT1]		= 6,
+	[IRQ_DM355_CCDC_VDINT2]		= 6,
+	[IRQ_DM355_IPIPE_HST]		= 6,
+	[IRQ_DM355_H3AINT]		= 6,
+	[IRQ_DM355_IPIPE_SDR]		= 6,
+	[IRQ_DM355_IPIPEIFINT]		= 6,
+	[IRQ_DM355_OSDINT]		= 7,
+	[IRQ_DM355_VENCINT]		= 6,
+	[IRQ_ASQINT]			= 6,
+	[IRQ_IMXINT]			= 6,
+	[IRQ_USBINT]			= 4,
+	[IRQ_DM355_RTOINT]		= 4,
+	[IRQ_DM355_UARTINT2]		= 7,
+	[IRQ_DM355_TINT6]		= 7,
+	[IRQ_CCINT0]			= 5,	/* dma */
+	[IRQ_CCERRINT]			= 5,	/* dma */
+	[IRQ_TCERRINT0]			= 5,	/* dma */
+	[IRQ_TCERRINT]			= 5,	/* dma */
+	[IRQ_DM355_SPINT2_1]		= 7,
+	[IRQ_DM355_TINT7]		= 4,
+	[IRQ_DM355_SDIOINT0]		= 7,
+	[IRQ_MBXINT]			= 7,
+	[IRQ_MBRINT]			= 7,
+	[IRQ_MMCINT]			= 7,
+	[IRQ_DM355_MMCINT1]		= 7,
+	[IRQ_DM355_PWMINT3]		= 7,
+	[IRQ_DDRINT]			= 7,
+	[IRQ_AEMIFINT]			= 7,
+	[IRQ_DM355_SDIOINT1]		= 4,
+	[IRQ_TINT0_TINT12]		= 2,	/* clockevent */
+	[IRQ_TINT0_TINT34]		= 2,	/* clocksource */
+	[IRQ_TINT1_TINT12]		= 7,	/* DSP timer */
+	[IRQ_TINT1_TINT34]		= 7,	/* system tick */
+	[IRQ_PWMINT0]			= 7,
+	[IRQ_PWMINT1]			= 7,
+	[IRQ_PWMINT2]			= 7,
+	[IRQ_I2C]			= 3,
+	[IRQ_UARTINT0]			= 3,
+	[IRQ_UARTINT1]			= 3,
+	[IRQ_DM355_SPINT0_0]		= 3,
+	[IRQ_DM355_SPINT0_1]		= 3,
+	[IRQ_DM355_GPIO0]		= 3,
+	[IRQ_DM355_GPIO1]		= 7,
+	[IRQ_DM355_GPIO2]		= 4,
+	[IRQ_DM355_GPIO3]		= 4,
+	[IRQ_DM355_GPIO4]		= 7,
+	[IRQ_DM355_GPIO5]		= 7,
+	[IRQ_DM355_GPIO6]		= 7,
+	[IRQ_DM355_GPIO7]		= 7,
+	[IRQ_DM355_GPIO8]		= 7,
+	[IRQ_DM355_GPIO9]		= 7,
+	[IRQ_DM355_GPIOBNK0]		= 7,
+	[IRQ_DM355_GPIOBNK1]		= 7,
+	[IRQ_DM355_GPIOBNK2]		= 7,
+	[IRQ_DM355_GPIOBNK3]		= 7,
+	[IRQ_DM355_GPIOBNK4]		= 7,
+	[IRQ_DM355_GPIOBNK5]		= 7,
+	[IRQ_DM355_GPIOBNK6]		= 7,
+	[IRQ_COMMTX]			= 7,
+	[IRQ_COMMRX]			= 7,
+	[IRQ_EMUINT]			= 7,
+};
+
+/*----------------------------------------------------------------------*/
+
+static const s8 dma_chan_dm355_no_event[] = {
+	12, 13, 24, 56, 57,
+	58, 59, 60, 61, 62,
+	63,
+	-1
+};
+
+static struct edma_soc_info dm355_edma_info = {
+	.n_channel	= 64,
+	.n_region	= 4,
+	.n_slot		= 128,
+	.n_tc		= 2,
+	.noevent	= dma_chan_dm355_no_event,
+};
+
+static struct resource edma_resources[] = {
+	{
+		.name	= "edma_cc",
+		.start	= 0x01c00000,
+		.end	= 0x01c00000 + SZ_64K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "edma_tc0",
+		.start	= 0x01c10000,
+		.end	= 0x01c10000 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "edma_tc1",
+		.start	= 0x01c10400,
+		.end	= 0x01c10400 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_CCINT0,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_CCERRINT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	/* not using (or muxing) TC*_ERR */
+};
+
+static struct platform_device dm355_edma_device = {
+	.name			= "edma",
+	.id			= -1,
+	.dev.platform_data	= &dm355_edma_info,
+	.num_resources		= ARRAY_SIZE(edma_resources),
+	.resource		= edma_resources,
+};
+
+/*----------------------------------------------------------------------*/
+
+static struct map_desc dm355_io_desc[] = {
+	{
+		.virtual	= IO_VIRT,
+		.pfn		= __phys_to_pfn(IO_PHYS),
+		.length		= IO_SIZE,
+		.type		= MT_DEVICE
+	},
+	{
+		.virtual	= SRAM_VIRT,
+		.pfn		= __phys_to_pfn(0x00010000),
+		.length		= SZ_32K,
+		/* MT_MEMORY_NONCACHED requires supersection alignment */
+		.type		= MT_DEVICE,
+	},
+};
+
+/* Contents of JTAG ID register used to identify exact cpu type */
+static struct davinci_id dm355_ids[] = {
+	{
+		.variant	= 0x0,
+		.part_no	= 0xb73b,
+		.manufacturer	= 0x00f,
+		.cpu_id		= DAVINCI_CPU_ID_DM355,
+		.name		= "dm355",
+	},
+};
+
+static void __iomem *dm355_psc_bases[] = {
+	IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE),
+};
+
+/*
+ * T0_BOT: Timer 0, bottom:  clockevent source for hrtimers
+ * T0_TOP: Timer 0, top   :  clocksource for generic timekeeping
+ * T1_BOT: Timer 1, bottom:  (used by DSP in TI DSPLink code)
+ * T1_TOP: Timer 1, top   :  <unused>
+ */
+struct davinci_timer_info dm355_timer_info = {
+	.timers		= davinci_timer_instance,
+	.clockevent_id	= T0_BOT,
+	.clocksource_id	= T0_TOP,
+};
+
+static struct plat_serial8250_port dm355_serial_platform_data[] = {
+	{
+		.mapbase	= DAVINCI_UART0_BASE,
+		.irq		= IRQ_UARTINT0,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+				  UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+	},
+	{
+		.mapbase	= DAVINCI_UART1_BASE,
+		.irq		= IRQ_UARTINT1,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+				  UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+	},
+	{
+		.mapbase	= DM355_UART2_BASE,
+		.irq		= IRQ_DM355_UARTINT2,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+				  UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+	},
+	{
+		.flags		= 0
+	},
+};
+
+static struct platform_device dm355_serial_device = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev			= {
+		.platform_data	= dm355_serial_platform_data,
+	},
+};
+
+static struct davinci_soc_info davinci_soc_info_dm355 = {
+	.io_desc		= dm355_io_desc,
+	.io_desc_num		= ARRAY_SIZE(dm355_io_desc),
+	.jtag_id_base		= IO_ADDRESS(0x01c40028),
+	.ids			= dm355_ids,
+	.ids_num		= ARRAY_SIZE(dm355_ids),
+	.cpu_clks		= dm355_clks,
+	.psc_bases		= dm355_psc_bases,
+	.psc_bases_num		= ARRAY_SIZE(dm355_psc_bases),
+	.pinmux_base		= IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE),
+	.pinmux_pins		= dm355_pins,
+	.pinmux_pins_num	= ARRAY_SIZE(dm355_pins),
+	.intc_base		= IO_ADDRESS(DAVINCI_ARM_INTC_BASE),
+	.intc_type		= DAVINCI_INTC_TYPE_AINTC,
+	.intc_irq_prios		= dm355_default_priorities,
+	.intc_irq_num		= DAVINCI_N_AINTC_IRQ,
+	.timer_info		= &dm355_timer_info,
+	.wdt_base		= IO_ADDRESS(DAVINCI_WDOG_BASE),
+	.gpio_base		= IO_ADDRESS(DAVINCI_GPIO_BASE),
+	.gpio_num		= 104,
+	.gpio_irq		= IRQ_DM355_GPIOBNK0,
+	.serial_dev		= &dm355_serial_device,
+	.sram_dma		= 0x00010000,
+	.sram_len		= SZ_32K,
+};
+
+void __init dm355_init(void)
+{
+	davinci_common_init(&davinci_soc_info_dm355);
+}
+
+static int __init dm355_init_devices(void)
+{
+	if (!cpu_is_davinci_dm355())
+		return 0;
+
+	davinci_cfg_reg(DM355_INT_EDMA_CC);
+	platform_device_register(&dm355_edma_device);
+	return 0;
+}
+postcore_initcall(dm355_init_devices);
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index d428ef1..fb5449b 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -11,7 +11,11 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/clk.h>
+#include <linux/serial_8250.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <asm/mach/map.h>
 
 #include <mach/dm644x.h>
 #include <mach/clock.h>
@@ -20,6 +24,9 @@
 #include <mach/irqs.h>
 #include <mach/psc.h>
 #include <mach/mux.h>
+#include <mach/time.h>
+#include <mach/serial.h>
+#include <mach/common.h>
 
 #include "clock.h"
 #include "mux.h"
@@ -312,7 +319,14 @@
 	CLK(NULL, NULL, NULL),
 };
 
-#if defined(CONFIG_TI_DAVINCI_EMAC) || defined(CONFIG_TI_DAVINCI_EMAC_MODULE)
+static struct emac_platform_data dm644x_emac_pdata = {
+	.ctrl_reg_offset	= DM644X_EMAC_CNTRL_OFFSET,
+	.ctrl_mod_reg_offset	= DM644X_EMAC_CNTRL_MOD_OFFSET,
+	.ctrl_ram_offset	= DM644X_EMAC_CNTRL_RAM_OFFSET,
+	.mdio_reg_offset	= DM644X_EMAC_MDIO_OFFSET,
+	.ctrl_ram_size		= DM644X_EMAC_CNTRL_RAM_SIZE,
+	.version		= EMAC_VERSION_1,
+};
 
 static struct resource dm644x_emac_resources[] = {
 	{
@@ -330,11 +344,15 @@
 static struct platform_device dm644x_emac_device = {
        .name		= "davinci_emac",
        .id		= 1,
+       .dev = {
+	       .platform_data	= &dm644x_emac_pdata,
+       },
        .num_resources	= ARRAY_SIZE(dm644x_emac_resources),
        .resource	= dm644x_emac_resources,
 };
 
-#endif
+#define PINMUX0		0x00
+#define PINMUX1		0x04
 
 /*
  * Device specific mux setup
@@ -343,6 +361,7 @@
  *				reg  offset mask  mode
  */
 static const struct mux_config dm644x_pins[] = {
+#ifdef CONFIG_DAVINCI_MUX
 MUX_CFG(DM644X, HDIREN,		0,   16,    1,	  1,	 true)
 MUX_CFG(DM644X, ATAEN,		0,   17,    1,	  1,	 true)
 MUX_CFG(DM644X, ATAEN_DISABLE,	0,   17,    1,	  0,	 true)
@@ -383,8 +402,76 @@
 
 MUX_CFG(DM644X, LOEEN,		0,   24,    1,	  1,	 true)
 MUX_CFG(DM644X, LFLDEN,		0,   25,    1,	  1,	 false)
+#endif
 };
 
+/* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */
+static u8 dm644x_default_priorities[DAVINCI_N_AINTC_IRQ] = {
+	[IRQ_VDINT0]		= 2,
+	[IRQ_VDINT1]		= 6,
+	[IRQ_VDINT2]		= 6,
+	[IRQ_HISTINT]		= 6,
+	[IRQ_H3AINT]		= 6,
+	[IRQ_PRVUINT]		= 6,
+	[IRQ_RSZINT]		= 6,
+	[7]			= 7,
+	[IRQ_VENCINT]		= 6,
+	[IRQ_ASQINT]		= 6,
+	[IRQ_IMXINT]		= 6,
+	[IRQ_VLCDINT]		= 6,
+	[IRQ_USBINT]		= 4,
+	[IRQ_EMACINT]		= 4,
+	[14]			= 7,
+	[15]			= 7,
+	[IRQ_CCINT0]		= 5,	/* dma */
+	[IRQ_CCERRINT]		= 5,	/* dma */
+	[IRQ_TCERRINT0]		= 5,	/* dma */
+	[IRQ_TCERRINT]		= 5,	/* dma */
+	[IRQ_PSCIN]		= 7,
+	[21]			= 7,
+	[IRQ_IDE]		= 4,
+	[23]			= 7,
+	[IRQ_MBXINT]		= 7,
+	[IRQ_MBRINT]		= 7,
+	[IRQ_MMCINT]		= 7,
+	[IRQ_SDIOINT]		= 7,
+	[28]			= 7,
+	[IRQ_DDRINT]		= 7,
+	[IRQ_AEMIFINT]		= 7,
+	[IRQ_VLQINT]		= 4,
+	[IRQ_TINT0_TINT12]	= 2,	/* clockevent */
+	[IRQ_TINT0_TINT34]	= 2,	/* clocksource */
+	[IRQ_TINT1_TINT12]	= 7,	/* DSP timer */
+	[IRQ_TINT1_TINT34]	= 7,	/* system tick */
+	[IRQ_PWMINT0]		= 7,
+	[IRQ_PWMINT1]		= 7,
+	[IRQ_PWMINT2]		= 7,
+	[IRQ_I2C]		= 3,
+	[IRQ_UARTINT0]		= 3,
+	[IRQ_UARTINT1]		= 3,
+	[IRQ_UARTINT2]		= 3,
+	[IRQ_SPINT0]		= 3,
+	[IRQ_SPINT1]		= 3,
+	[45]			= 7,
+	[IRQ_DSP2ARM0]		= 4,
+	[IRQ_DSP2ARM1]		= 4,
+	[IRQ_GPIO0]		= 7,
+	[IRQ_GPIO1]		= 7,
+	[IRQ_GPIO2]		= 7,
+	[IRQ_GPIO3]		= 7,
+	[IRQ_GPIO4]		= 7,
+	[IRQ_GPIO5]		= 7,
+	[IRQ_GPIO6]		= 7,
+	[IRQ_GPIO7]		= 7,
+	[IRQ_GPIOBNK0]		= 7,
+	[IRQ_GPIOBNK1]		= 7,
+	[IRQ_GPIOBNK2]		= 7,
+	[IRQ_GPIOBNK3]		= 7,
+	[IRQ_GPIOBNK4]		= 7,
+	[IRQ_COMMTX]		= 7,
+	[IRQ_COMMRX]		= 7,
+	[IRQ_EMUINT]		= 7,
+};
 
 /*----------------------------------------------------------------------*/
 
@@ -444,10 +531,118 @@
 };
 
 /*----------------------------------------------------------------------*/
+
+static struct map_desc dm644x_io_desc[] = {
+	{
+		.virtual	= IO_VIRT,
+		.pfn		= __phys_to_pfn(IO_PHYS),
+		.length		= IO_SIZE,
+		.type		= MT_DEVICE
+	},
+	{
+		.virtual	= SRAM_VIRT,
+		.pfn		= __phys_to_pfn(0x00008000),
+		.length		= SZ_16K,
+		/* MT_MEMORY_NONCACHED requires supersection alignment */
+		.type		= MT_DEVICE,
+	},
+};
+
+/* Contents of JTAG ID register used to identify exact cpu type */
+static struct davinci_id dm644x_ids[] = {
+	{
+		.variant	= 0x0,
+		.part_no	= 0xb700,
+		.manufacturer	= 0x017,
+		.cpu_id		= DAVINCI_CPU_ID_DM6446,
+		.name		= "dm6446",
+	},
+};
+
+static void __iomem *dm644x_psc_bases[] = {
+	IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE),
+};
+
+/*
+ * T0_BOT: Timer 0, bottom:  clockevent source for hrtimers
+ * T0_TOP: Timer 0, top   :  clocksource for generic timekeeping
+ * T1_BOT: Timer 1, bottom:  (used by DSP in TI DSPLink code)
+ * T1_TOP: Timer 1, top   :  <unused>
+ */
+struct davinci_timer_info dm644x_timer_info = {
+	.timers		= davinci_timer_instance,
+	.clockevent_id	= T0_BOT,
+	.clocksource_id	= T0_TOP,
+};
+
+static struct plat_serial8250_port dm644x_serial_platform_data[] = {
+	{
+		.mapbase	= DAVINCI_UART0_BASE,
+		.irq		= IRQ_UARTINT0,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+				  UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+	},
+	{
+		.mapbase	= DAVINCI_UART1_BASE,
+		.irq		= IRQ_UARTINT1,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+				  UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+	},
+	{
+		.mapbase	= DAVINCI_UART2_BASE,
+		.irq		= IRQ_UARTINT2,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+				  UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+	},
+	{
+		.flags		= 0
+	},
+};
+
+static struct platform_device dm644x_serial_device = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev			= {
+		.platform_data	= dm644x_serial_platform_data,
+	},
+};
+
+static struct davinci_soc_info davinci_soc_info_dm644x = {
+	.io_desc		= dm644x_io_desc,
+	.io_desc_num		= ARRAY_SIZE(dm644x_io_desc),
+	.jtag_id_base		= IO_ADDRESS(0x01c40028),
+	.ids			= dm644x_ids,
+	.ids_num		= ARRAY_SIZE(dm644x_ids),
+	.cpu_clks		= dm644x_clks,
+	.psc_bases		= dm644x_psc_bases,
+	.psc_bases_num		= ARRAY_SIZE(dm644x_psc_bases),
+	.pinmux_base		= IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE),
+	.pinmux_pins		= dm644x_pins,
+	.pinmux_pins_num	= ARRAY_SIZE(dm644x_pins),
+	.intc_base		= IO_ADDRESS(DAVINCI_ARM_INTC_BASE),
+	.intc_type		= DAVINCI_INTC_TYPE_AINTC,
+	.intc_irq_prios 	= dm644x_default_priorities,
+	.intc_irq_num		= DAVINCI_N_AINTC_IRQ,
+	.timer_info		= &dm644x_timer_info,
+	.wdt_base		= IO_ADDRESS(DAVINCI_WDOG_BASE),
+	.gpio_base		= IO_ADDRESS(DAVINCI_GPIO_BASE),
+	.gpio_num		= 71,
+	.gpio_irq		= IRQ_GPIOBNK0,
+	.serial_dev		= &dm644x_serial_device,
+	.emac_pdata		= &dm644x_emac_pdata,
+	.sram_dma		= 0x00008000,
+	.sram_len		= SZ_16K,
+};
+
 void __init dm644x_init(void)
 {
-	davinci_clk_init(dm644x_clks);
-	davinci_mux_register(dm644x_pins, ARRAY_SIZE(dm644x_pins));
+	davinci_common_init(&davinci_soc_info_dm644x);
 }
 
 static int __init dm644x_init_devices(void)
@@ -456,6 +651,7 @@
 		return 0;
 
 	platform_device_register(&dm644x_edma_device);
+	platform_device_register(&dm644x_emac_device);
 	return 0;
 }
 postcore_initcall(dm644x_init_devices);
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
new file mode 100644
index 0000000..334f071
--- /dev/null
+++ b/arch/arm/mach-davinci/dm646x.c
@@ -0,0 +1,636 @@
+/*
+ * TI DaVinci DM644x chip specific setup
+ *
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/serial_8250.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/dm646x.h>
+#include <mach/clock.h>
+#include <mach/cputype.h>
+#include <mach/edma.h>
+#include <mach/irqs.h>
+#include <mach/psc.h>
+#include <mach/mux.h>
+#include <mach/time.h>
+#include <mach/serial.h>
+#include <mach/common.h>
+
+#include "clock.h"
+#include "mux.h"
+
+/*
+ * Device specific clocks
+ */
+#define DM646X_REF_FREQ		27000000
+#define DM646X_AUX_FREQ		24000000
+
+static struct pll_data pll1_data = {
+	.num       = 1,
+	.phys_base = DAVINCI_PLL1_BASE,
+};
+
+static struct pll_data pll2_data = {
+	.num       = 2,
+	.phys_base = DAVINCI_PLL2_BASE,
+};
+
+static struct clk ref_clk = {
+	.name = "ref_clk",
+	.rate = DM646X_REF_FREQ,
+};
+
+static struct clk aux_clkin = {
+	.name = "aux_clkin",
+	.rate = DM646X_AUX_FREQ,
+};
+
+static struct clk pll1_clk = {
+	.name = "pll1",
+	.parent = &ref_clk,
+	.pll_data = &pll1_data,
+	.flags = CLK_PLL,
+};
+
+static struct clk pll1_sysclk1 = {
+	.name = "pll1_sysclk1",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL,
+	.div_reg = PLLDIV1,
+};
+
+static struct clk pll1_sysclk2 = {
+	.name = "pll1_sysclk2",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL,
+	.div_reg = PLLDIV2,
+};
+
+static struct clk pll1_sysclk3 = {
+	.name = "pll1_sysclk3",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL,
+	.div_reg = PLLDIV3,
+};
+
+static struct clk pll1_sysclk4 = {
+	.name = "pll1_sysclk4",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL,
+	.div_reg = PLLDIV4,
+};
+
+static struct clk pll1_sysclk5 = {
+	.name = "pll1_sysclk5",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL,
+	.div_reg = PLLDIV5,
+};
+
+static struct clk pll1_sysclk6 = {
+	.name = "pll1_sysclk6",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL,
+	.div_reg = PLLDIV6,
+};
+
+static struct clk pll1_sysclk8 = {
+	.name = "pll1_sysclk8",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL,
+	.div_reg = PLLDIV8,
+};
+
+static struct clk pll1_sysclk9 = {
+	.name = "pll1_sysclk9",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL,
+	.div_reg = PLLDIV9,
+};
+
+static struct clk pll1_sysclkbp = {
+	.name = "pll1_sysclkbp",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL | PRE_PLL,
+	.div_reg = BPDIV,
+};
+
+static struct clk pll1_aux_clk = {
+	.name = "pll1_aux_clk",
+	.parent = &pll1_clk,
+	.flags = CLK_PLL | PRE_PLL,
+};
+
+static struct clk pll2_clk = {
+	.name = "pll2_clk",
+	.parent = &ref_clk,
+	.pll_data = &pll2_data,
+	.flags = CLK_PLL,
+};
+
+static struct clk pll2_sysclk1 = {
+	.name = "pll2_sysclk1",
+	.parent = &pll2_clk,
+	.flags = CLK_PLL,
+	.div_reg = PLLDIV1,
+};
+
+static struct clk dsp_clk = {
+	.name = "dsp",
+	.parent = &pll1_sysclk1,
+	.lpsc = DM646X_LPSC_C64X_CPU,
+	.flags = PSC_DSP,
+	.usecount = 1,			/* REVISIT how to disable? */
+};
+
+static struct clk arm_clk = {
+	.name = "arm",
+	.parent = &pll1_sysclk2,
+	.lpsc = DM646X_LPSC_ARM,
+	.flags = ALWAYS_ENABLED,
+};
+
+static struct clk uart0_clk = {
+	.name = "uart0",
+	.parent = &aux_clkin,
+	.lpsc = DM646X_LPSC_UART0,
+};
+
+static struct clk uart1_clk = {
+	.name = "uart1",
+	.parent = &aux_clkin,
+	.lpsc = DM646X_LPSC_UART1,
+};
+
+static struct clk uart2_clk = {
+	.name = "uart2",
+	.parent = &aux_clkin,
+	.lpsc = DM646X_LPSC_UART2,
+};
+
+static struct clk i2c_clk = {
+	.name = "I2CCLK",
+	.parent = &pll1_sysclk3,
+	.lpsc = DM646X_LPSC_I2C,
+};
+
+static struct clk gpio_clk = {
+	.name = "gpio",
+	.parent = &pll1_sysclk3,
+	.lpsc = DM646X_LPSC_GPIO,
+};
+
+static struct clk aemif_clk = {
+	.name = "aemif",
+	.parent = &pll1_sysclk3,
+	.lpsc = DM646X_LPSC_AEMIF,
+	.flags = ALWAYS_ENABLED,
+};
+
+static struct clk emac_clk = {
+	.name = "emac",
+	.parent = &pll1_sysclk3,
+	.lpsc = DM646X_LPSC_EMAC,
+};
+
+static struct clk pwm0_clk = {
+	.name = "pwm0",
+	.parent = &pll1_sysclk3,
+	.lpsc = DM646X_LPSC_PWM0,
+	.usecount = 1,            /* REVIST: disabling hangs system */
+};
+
+static struct clk pwm1_clk = {
+	.name = "pwm1",
+	.parent = &pll1_sysclk3,
+	.lpsc = DM646X_LPSC_PWM1,
+	.usecount = 1,            /* REVIST: disabling hangs system */
+};
+
+static struct clk timer0_clk = {
+	.name = "timer0",
+	.parent = &pll1_sysclk3,
+	.lpsc = DM646X_LPSC_TIMER0,
+};
+
+static struct clk timer1_clk = {
+	.name = "timer1",
+	.parent = &pll1_sysclk3,
+	.lpsc = DM646X_LPSC_TIMER1,
+};
+
+static struct clk timer2_clk = {
+	.name = "timer2",
+	.parent = &pll1_sysclk3,
+	.flags = ALWAYS_ENABLED, /* no LPSC, always enabled; c.f. spruep9a */
+};
+
+static struct clk vpif0_clk = {
+	.name = "vpif0",
+	.parent = &ref_clk,
+	.lpsc = DM646X_LPSC_VPSSMSTR,
+	.flags = ALWAYS_ENABLED,
+};
+
+static struct clk vpif1_clk = {
+	.name = "vpif1",
+	.parent = &ref_clk,
+	.lpsc = DM646X_LPSC_VPSSSLV,
+	.flags = ALWAYS_ENABLED,
+};
+
+struct davinci_clk dm646x_clks[] = {
+	CLK(NULL, "ref", &ref_clk),
+	CLK(NULL, "aux", &aux_clkin),
+	CLK(NULL, "pll1", &pll1_clk),
+	CLK(NULL, "pll1_sysclk", &pll1_sysclk1),
+	CLK(NULL, "pll1_sysclk", &pll1_sysclk2),
+	CLK(NULL, "pll1_sysclk", &pll1_sysclk3),
+	CLK(NULL, "pll1_sysclk", &pll1_sysclk4),
+	CLK(NULL, "pll1_sysclk", &pll1_sysclk5),
+	CLK(NULL, "pll1_sysclk", &pll1_sysclk6),
+	CLK(NULL, "pll1_sysclk", &pll1_sysclk8),
+	CLK(NULL, "pll1_sysclk", &pll1_sysclk9),
+	CLK(NULL, "pll1_sysclk", &pll1_sysclkbp),
+	CLK(NULL, "pll1_aux", &pll1_aux_clk),
+	CLK(NULL, "pll2", &pll2_clk),
+	CLK(NULL, "pll2_sysclk1", &pll2_sysclk1),
+	CLK(NULL, "dsp", &dsp_clk),
+	CLK(NULL, "arm", &arm_clk),
+	CLK(NULL, "uart0", &uart0_clk),
+	CLK(NULL, "uart1", &uart1_clk),
+	CLK(NULL, "uart2", &uart2_clk),
+	CLK("i2c_davinci.1", NULL, &i2c_clk),
+	CLK(NULL, "gpio", &gpio_clk),
+	CLK(NULL, "aemif", &aemif_clk),
+	CLK("davinci_emac.1", NULL, &emac_clk),
+	CLK(NULL, "pwm0", &pwm0_clk),
+	CLK(NULL, "pwm1", &pwm1_clk),
+	CLK(NULL, "timer0", &timer0_clk),
+	CLK(NULL, "timer1", &timer1_clk),
+	CLK("watchdog", NULL, &timer2_clk),
+	CLK(NULL, "vpif0", &vpif0_clk),
+	CLK(NULL, "vpif1", &vpif1_clk),
+	CLK(NULL, NULL, NULL),
+};
+
+static struct emac_platform_data dm646x_emac_pdata = {
+	.ctrl_reg_offset	= DM646X_EMAC_CNTRL_OFFSET,
+	.ctrl_mod_reg_offset	= DM646X_EMAC_CNTRL_MOD_OFFSET,
+	.ctrl_ram_offset	= DM646X_EMAC_CNTRL_RAM_OFFSET,
+	.mdio_reg_offset	= DM646X_EMAC_MDIO_OFFSET,
+	.ctrl_ram_size		= DM646X_EMAC_CNTRL_RAM_SIZE,
+	.version		= EMAC_VERSION_2,
+};
+
+static struct resource dm646x_emac_resources[] = {
+	{
+		.start	= DM646X_EMAC_BASE,
+		.end	= DM646X_EMAC_BASE + 0x47ff,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_DM646X_EMACRXTHINT,
+		.end	= IRQ_DM646X_EMACRXTHINT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DM646X_EMACRXINT,
+		.end	= IRQ_DM646X_EMACRXINT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DM646X_EMACTXINT,
+		.end	= IRQ_DM646X_EMACTXINT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DM646X_EMACMISCINT,
+		.end	= IRQ_DM646X_EMACMISCINT,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device dm646x_emac_device = {
+	.name		= "davinci_emac",
+	.id		= 1,
+	.dev = {
+		.platform_data	= &dm646x_emac_pdata,
+	},
+	.num_resources	= ARRAY_SIZE(dm646x_emac_resources),
+	.resource	= dm646x_emac_resources,
+};
+
+#define PINMUX0		0x00
+#define PINMUX1		0x04
+
+/*
+ * Device specific mux setup
+ *
+ *	soc	description	mux  mode   mode  mux	 dbg
+ *				reg  offset mask  mode
+ */
+static const struct mux_config dm646x_pins[] = {
+#ifdef CONFIG_DAVINCI_MUX
+MUX_CFG(DM646X, ATAEN,		0,   0,     1,	  1,	 true)
+
+MUX_CFG(DM646X, AUDCK1,		0,   29,    1,	  0,	 false)
+
+MUX_CFG(DM646X, AUDCK0,		0,   28,    1,	  0,	 false)
+
+MUX_CFG(DM646X, CRGMUX,			0,   24,    7,    5,	 true)
+
+MUX_CFG(DM646X, STSOMUX_DISABLE,	0,   22,    3,    0,	 true)
+
+MUX_CFG(DM646X, STSIMUX_DISABLE,	0,   20,    3,    0,	 true)
+
+MUX_CFG(DM646X, PTSOMUX_DISABLE,	0,   18,    3,    0,	 true)
+
+MUX_CFG(DM646X, PTSIMUX_DISABLE,	0,   16,    3,    0,	 true)
+
+MUX_CFG(DM646X, STSOMUX,		0,   22,    3,    2,	 true)
+
+MUX_CFG(DM646X, STSIMUX,		0,   20,    3,    2,	 true)
+
+MUX_CFG(DM646X, PTSOMUX_PARALLEL,	0,   18,    3,    2,	 true)
+
+MUX_CFG(DM646X, PTSIMUX_PARALLEL,	0,   16,    3,    2,	 true)
+
+MUX_CFG(DM646X, PTSOMUX_SERIAL,		0,   18,    3,    3,	 true)
+
+MUX_CFG(DM646X, PTSIMUX_SERIAL,		0,   16,    3,    3,	 true)
+#endif
+};
+
+static u8 dm646x_default_priorities[DAVINCI_N_AINTC_IRQ] = {
+	[IRQ_DM646X_VP_VERTINT0]        = 7,
+	[IRQ_DM646X_VP_VERTINT1]        = 7,
+	[IRQ_DM646X_VP_VERTINT2]        = 7,
+	[IRQ_DM646X_VP_VERTINT3]        = 7,
+	[IRQ_DM646X_VP_ERRINT]          = 7,
+	[IRQ_DM646X_RESERVED_1]         = 7,
+	[IRQ_DM646X_RESERVED_2]         = 7,
+	[IRQ_DM646X_WDINT]              = 7,
+	[IRQ_DM646X_CRGENINT0]          = 7,
+	[IRQ_DM646X_CRGENINT1]          = 7,
+	[IRQ_DM646X_TSIFINT0]           = 7,
+	[IRQ_DM646X_TSIFINT1]           = 7,
+	[IRQ_DM646X_VDCEINT]            = 7,
+	[IRQ_DM646X_USBINT]             = 7,
+	[IRQ_DM646X_USBDMAINT]          = 7,
+	[IRQ_DM646X_PCIINT]             = 7,
+	[IRQ_CCINT0]                    = 7,    /* dma */
+	[IRQ_CCERRINT]                  = 7,    /* dma */
+	[IRQ_TCERRINT0]                 = 7,    /* dma */
+	[IRQ_TCERRINT]                  = 7,    /* dma */
+	[IRQ_DM646X_TCERRINT2]          = 7,
+	[IRQ_DM646X_TCERRINT3]          = 7,
+	[IRQ_DM646X_IDE]                = 7,
+	[IRQ_DM646X_HPIINT]             = 7,
+	[IRQ_DM646X_EMACRXTHINT]        = 7,
+	[IRQ_DM646X_EMACRXINT]          = 7,
+	[IRQ_DM646X_EMACTXINT]          = 7,
+	[IRQ_DM646X_EMACMISCINT]        = 7,
+	[IRQ_DM646X_MCASP0TXINT]        = 7,
+	[IRQ_DM646X_MCASP0RXINT]        = 7,
+	[IRQ_AEMIFINT]                  = 7,
+	[IRQ_DM646X_RESERVED_3]         = 7,
+	[IRQ_DM646X_MCASP1TXINT]        = 7,    /* clockevent */
+	[IRQ_TINT0_TINT34]              = 7,    /* clocksource */
+	[IRQ_TINT1_TINT12]              = 7,    /* DSP timer */
+	[IRQ_TINT1_TINT34]              = 7,    /* system tick */
+	[IRQ_PWMINT0]                   = 7,
+	[IRQ_PWMINT1]                   = 7,
+	[IRQ_DM646X_VLQINT]             = 7,
+	[IRQ_I2C]                       = 7,
+	[IRQ_UARTINT0]                  = 7,
+	[IRQ_UARTINT1]                  = 7,
+	[IRQ_DM646X_UARTINT2]           = 7,
+	[IRQ_DM646X_SPINT0]             = 7,
+	[IRQ_DM646X_SPINT1]             = 7,
+	[IRQ_DM646X_DSP2ARMINT]         = 7,
+	[IRQ_DM646X_RESERVED_4]         = 7,
+	[IRQ_DM646X_PSCINT]             = 7,
+	[IRQ_DM646X_GPIO0]              = 7,
+	[IRQ_DM646X_GPIO1]              = 7,
+	[IRQ_DM646X_GPIO2]              = 7,
+	[IRQ_DM646X_GPIO3]              = 7,
+	[IRQ_DM646X_GPIO4]              = 7,
+	[IRQ_DM646X_GPIO5]              = 7,
+	[IRQ_DM646X_GPIO6]              = 7,
+	[IRQ_DM646X_GPIO7]              = 7,
+	[IRQ_DM646X_GPIOBNK0]           = 7,
+	[IRQ_DM646X_GPIOBNK1]           = 7,
+	[IRQ_DM646X_GPIOBNK2]           = 7,
+	[IRQ_DM646X_DDRINT]             = 7,
+	[IRQ_DM646X_AEMIFINT]           = 7,
+	[IRQ_COMMTX]                    = 7,
+	[IRQ_COMMRX]                    = 7,
+	[IRQ_EMUINT]                    = 7,
+};
+
+/*----------------------------------------------------------------------*/
+
+static const s8 dma_chan_dm646x_no_event[] = {
+	 0,  1,  2,  3, 13,
+	14, 15, 24, 25, 26,
+	27, 30, 31, 54, 55,
+	56,
+	-1
+};
+
+static struct edma_soc_info dm646x_edma_info = {
+	.n_channel	= 64,
+	.n_region	= 6,	/* 0-1, 4-7 */
+	.n_slot		= 512,
+	.n_tc		= 4,
+	.noevent	= dma_chan_dm646x_no_event,
+};
+
+static struct resource edma_resources[] = {
+	{
+		.name	= "edma_cc",
+		.start	= 0x01c00000,
+		.end	= 0x01c00000 + SZ_64K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "edma_tc0",
+		.start	= 0x01c10000,
+		.end	= 0x01c10000 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "edma_tc1",
+		.start	= 0x01c10400,
+		.end	= 0x01c10400 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "edma_tc2",
+		.start	= 0x01c10800,
+		.end	= 0x01c10800 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "edma_tc3",
+		.start	= 0x01c10c00,
+		.end	= 0x01c10c00 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_CCINT0,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_CCERRINT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	/* not using TC*_ERR */
+};
+
+static struct platform_device dm646x_edma_device = {
+	.name			= "edma",
+	.id			= -1,
+	.dev.platform_data	= &dm646x_edma_info,
+	.num_resources		= ARRAY_SIZE(edma_resources),
+	.resource		= edma_resources,
+};
+
+/*----------------------------------------------------------------------*/
+
+static struct map_desc dm646x_io_desc[] = {
+	{
+		.virtual	= IO_VIRT,
+		.pfn		= __phys_to_pfn(IO_PHYS),
+		.length		= IO_SIZE,
+		.type		= MT_DEVICE
+	},
+	{
+		.virtual	= SRAM_VIRT,
+		.pfn		= __phys_to_pfn(0x00010000),
+		.length		= SZ_32K,
+		/* MT_MEMORY_NONCACHED requires supersection alignment */
+		.type		= MT_DEVICE,
+	},
+};
+
+/* Contents of JTAG ID register used to identify exact cpu type */
+static struct davinci_id dm646x_ids[] = {
+	{
+		.variant	= 0x0,
+		.part_no	= 0xb770,
+		.manufacturer	= 0x017,
+		.cpu_id		= DAVINCI_CPU_ID_DM6467,
+		.name		= "dm6467",
+	},
+};
+
+static void __iomem *dm646x_psc_bases[] = {
+	IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE),
+};
+
+/*
+ * T0_BOT: Timer 0, bottom:  clockevent source for hrtimers
+ * T0_TOP: Timer 0, top   :  clocksource for generic timekeeping
+ * T1_BOT: Timer 1, bottom:  (used by DSP in TI DSPLink code)
+ * T1_TOP: Timer 1, top   :  <unused>
+ */
+struct davinci_timer_info dm646x_timer_info = {
+	.timers		= davinci_timer_instance,
+	.clockevent_id	= T0_BOT,
+	.clocksource_id	= T0_TOP,
+};
+
+static struct plat_serial8250_port dm646x_serial_platform_data[] = {
+	{
+		.mapbase	= DAVINCI_UART0_BASE,
+		.irq		= IRQ_UARTINT0,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+				  UPF_IOREMAP,
+		.iotype		= UPIO_MEM32,
+		.regshift	= 2,
+	},
+	{
+		.mapbase	= DAVINCI_UART1_BASE,
+		.irq		= IRQ_UARTINT1,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+				  UPF_IOREMAP,
+		.iotype		= UPIO_MEM32,
+		.regshift	= 2,
+	},
+	{
+		.mapbase	= DAVINCI_UART2_BASE,
+		.irq		= IRQ_DM646X_UARTINT2,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+				  UPF_IOREMAP,
+		.iotype		= UPIO_MEM32,
+		.regshift	= 2,
+	},
+	{
+		.flags		= 0
+	},
+};
+
+static struct platform_device dm646x_serial_device = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev			= {
+		.platform_data	= dm646x_serial_platform_data,
+	},
+};
+
+static struct davinci_soc_info davinci_soc_info_dm646x = {
+	.io_desc		= dm646x_io_desc,
+	.io_desc_num		= ARRAY_SIZE(dm646x_io_desc),
+	.jtag_id_base		= IO_ADDRESS(0x01c40028),
+	.ids			= dm646x_ids,
+	.ids_num		= ARRAY_SIZE(dm646x_ids),
+	.cpu_clks		= dm646x_clks,
+	.psc_bases		= dm646x_psc_bases,
+	.psc_bases_num		= ARRAY_SIZE(dm646x_psc_bases),
+	.pinmux_base		= IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE),
+	.pinmux_pins		= dm646x_pins,
+	.pinmux_pins_num	= ARRAY_SIZE(dm646x_pins),
+	.intc_base		= IO_ADDRESS(DAVINCI_ARM_INTC_BASE),
+	.intc_type		= DAVINCI_INTC_TYPE_AINTC,
+	.intc_irq_prios		= dm646x_default_priorities,
+	.intc_irq_num		= DAVINCI_N_AINTC_IRQ,
+	.timer_info		= &dm646x_timer_info,
+	.wdt_base		= IO_ADDRESS(DAVINCI_WDOG_BASE),
+	.gpio_base		= IO_ADDRESS(DAVINCI_GPIO_BASE),
+	.gpio_num		= 43, /* Only 33 usable */
+	.gpio_irq		= IRQ_DM646X_GPIOBNK0,
+	.serial_dev		= &dm646x_serial_device,
+	.emac_pdata		= &dm646x_emac_pdata,
+	.sram_dma		= 0x10010000,
+	.sram_len		= SZ_32K,
+};
+
+void __init dm646x_init(void)
+{
+	davinci_common_init(&davinci_soc_info_dm646x);
+}
+
+static int __init dm646x_init_devices(void)
+{
+	if (!cpu_is_davinci_dm646x())
+		return 0;
+
+	platform_device_register(&dm646x_edma_device);
+	platform_device_register(&dm646x_emac_device);
+	return 0;
+}
+postcore_initcall(dm646x_init_devices);
diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c
index 1aba41c..1b65321 100644
--- a/arch/arm/mach-davinci/gpio.c
+++ b/arch/arm/mach-davinci/gpio.c
@@ -23,6 +23,7 @@
 #include <mach/cputype.h>
 #include <mach/irqs.h>
 #include <mach/hardware.h>
+#include <mach/common.h>
 #include <mach/gpio.h>
 
 #include <asm/mach/irq.h>
@@ -37,14 +38,13 @@
 
 static struct davinci_gpio chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
 
-static unsigned __initdata ngpio;
-
 /* create a non-inlined version */
 static struct gpio_controller __iomem * __init gpio2controller(unsigned gpio)
 {
 	return __gpio_to_controller(gpio);
 }
 
+static int __init davinci_gpio_irq_setup(void);
 
 /*--------------------------------------------------------------------------*/
 
@@ -115,23 +115,16 @@
 static int __init davinci_gpio_setup(void)
 {
 	int i, base;
+	unsigned ngpio;
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
 
-	/* The gpio banks conceptually expose a segmented bitmap,
+	/*
+	 * The gpio banks conceptually expose a segmented bitmap,
 	 * and "ngpio" is one more than the largest zero-based
 	 * bit index that's valid.
 	 */
-	if (cpu_is_davinci_dm355()) {		/* or dm335() */
-		ngpio = 104;
-	} else if (cpu_is_davinci_dm644x()) {	/* or dm337() */
-		ngpio = 71;
-	} else if (cpu_is_davinci_dm646x()) {
-		/* NOTE:  each bank has several "reserved" bits,
-		 * unusable as GPIOs.  Only 33 of the GPIO numbers
-		 * are usable, and we're not rejecting the others.
-		 */
-		ngpio = 43;
-	} else {
-		/* if cpu_is_davinci_dm643x() ngpio = 111 */
+	ngpio = soc_info->gpio_num;
+	if (ngpio == 0) {
 		pr_err("GPIO setup:  how many GPIOs?\n");
 		return -EINVAL;
 	}
@@ -157,6 +150,7 @@
 		gpiochip_add(&chips[i].chip);
 	}
 
+	davinci_gpio_irq_setup();
 	return 0;
 }
 pure_initcall(davinci_gpio_setup);
@@ -187,10 +181,15 @@
 {
 	struct gpio_controller *__iomem g = get_irq_chip_data(irq);
 	u32 mask = __gpio_mask(irq_to_gpio(irq));
+	unsigned status = irq_desc[irq].status;
 
-	if (irq_desc[irq].status & IRQ_TYPE_EDGE_FALLING)
+	status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
+	if (!status)
+		status = IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
+
+	if (status & IRQ_TYPE_EDGE_FALLING)
 		__raw_writel(mask, &g->set_falling);
-	if (irq_desc[irq].status & IRQ_TYPE_EDGE_RISING)
+	if (status & IRQ_TYPE_EDGE_RISING)
 		__raw_writel(mask, &g->set_rising);
 }
 
@@ -205,10 +204,13 @@
 	irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK;
 	irq_desc[irq].status |= trigger;
 
-	__raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
-		     ? &g->set_falling : &g->clr_falling);
-	__raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING)
-		     ? &g->set_rising : &g->clr_rising);
+	/* don't enable the IRQ if it's currently disabled */
+	if (irq_desc[irq].depth == 0) {
+		__raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
+			     ? &g->set_falling : &g->clr_falling);
+		__raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING)
+			     ? &g->set_rising : &g->clr_rising);
+	}
 	return 0;
 }
 
@@ -230,6 +232,7 @@
 		mask <<= 16;
 
 	/* temporarily mask (level sensitive) parent IRQ */
+	desc->chip->mask(irq);
 	desc->chip->ack(irq);
 	while (1) {
 		u32		status;
@@ -268,17 +271,15 @@
 static int __init davinci_gpio_irq_setup(void)
 {
 	unsigned	gpio, irq, bank;
-	unsigned	bank_irq;
 	struct clk	*clk;
 	u32		binten = 0;
+	unsigned	ngpio, bank_irq;
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
 
-	if (cpu_is_davinci_dm355()) {		/* or dm335() */
-		bank_irq = IRQ_DM355_GPIOBNK0;
-	} else if (cpu_is_davinci_dm644x()) {
-		bank_irq = IRQ_GPIOBNK0;
-	} else if (cpu_is_davinci_dm646x()) {
-		bank_irq = IRQ_DM646X_GPIOBNK0;
-	} else {
+	ngpio = soc_info->gpio_num;
+
+	bank_irq = soc_info->gpio_irq;
+	if (bank_irq == 0) {
 		printk(KERN_ERR "Don't know first GPIO bank IRQ.\n");
 		return -EINVAL;
 	}
@@ -318,11 +319,9 @@
 	/* BINTEN -- per-bank interrupt enable. genirq would also let these
 	 * bits be set/cleared dynamically.
 	 */
-	__raw_writel(binten, (void *__iomem)
-		     IO_ADDRESS(DAVINCI_GPIO_BASE + 0x08));
+	__raw_writel(binten, soc_info->gpio_base + 0x08);
 
 	printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0));
 
 	return 0;
 }
-arch_initcall(davinci_gpio_irq_setup);
diff --git a/arch/arm/mach-davinci/id.c b/arch/arm/mach-davinci/id.c
deleted file mode 100644
index 018b994..0000000
--- a/arch/arm/mach-davinci/id.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Davinci CPU identification code
- *
- * Copyright (C) 2006 Komal Shah <komal_shah802003@yahoo.com>
- *
- * Derived from OMAP1 CPU identification 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
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-
-#define JTAG_ID_BASE		IO_ADDRESS(0x01c40028)
-
-static unsigned int davinci_revision;
-
-struct davinci_id {
-	u8	variant;	/* JTAG ID bits 31:28 */
-	u16	part_no;	/* JTAG ID bits 27:12 */
-	u32	manufacturer;	/* JTAG ID bits 11:1 */
-	u32	type;		/* Cpu id bits [31:8], cpu class bits [7:0] */
-};
-
-/* Register values to detect the DaVinci version */
-static struct davinci_id davinci_ids[] __initdata = {
-	{
-		/* DM6446 */
-		.part_no      = 0xb700,
-		.variant      = 0x0,
-		.manufacturer = 0x017,
-		.type	      = 0x64460000,
-	},
-	{
-		/* DM646X */
-		.part_no      = 0xb770,
-		.variant      = 0x0,
-		.manufacturer = 0x017,
-		.type         = 0x64670000,
-	},
-	{
-		/* DM355 */
-		.part_no	= 0xb73b,
-		.variant	= 0x0,
-		.manufacturer	= 0x00f,
-		.type		= 0x03550000,
-	},
-};
-
-/*
- * Get Device Part No. from JTAG ID register
- */
-static u16 __init davinci_get_part_no(void)
-{
-	u32 dev_id, part_no;
-
-	dev_id = __raw_readl(JTAG_ID_BASE);
-
-	part_no = ((dev_id >> 12) & 0xffff);
-
-	return part_no;
-}
-
-/*
- * Get Device Revision from JTAG ID register
- */
-static u8 __init davinci_get_variant(void)
-{
-	u32 variant;
-
-	variant = __raw_readl(JTAG_ID_BASE);
-
-	variant = (variant >> 28) & 0xf;
-
-	return variant;
-}
-
-unsigned int davinci_rev(void)
-{
-	return davinci_revision >> 16;
-}
-EXPORT_SYMBOL(davinci_rev);
-
-void __init davinci_check_revision(void)
-{
-	int i;
-	u16 part_no;
-	u8 variant;
-
-	part_no = davinci_get_part_no();
-	variant = davinci_get_variant();
-
-	/* First check only the major version in a safe way */
-	for (i = 0; i < ARRAY_SIZE(davinci_ids); i++) {
-		if (part_no == (davinci_ids[i].part_no)) {
-			davinci_revision = davinci_ids[i].type;
-			break;
-		}
-	}
-
-	/* Check if we can find the dev revision */
-	for (i = 0; i < ARRAY_SIZE(davinci_ids); i++) {
-		if (part_no == davinci_ids[i].part_no &&
-		    variant == davinci_ids[i].variant) {
-			davinci_revision = davinci_ids[i].type;
-			break;
-		}
-	}
-
-	printk(KERN_INFO "DaVinci DM%04x variant 0x%x\n",
-	       davinci_rev(), variant);
-}
diff --git a/arch/arm/mach-davinci/include/mach/board-dm6446evm.h b/arch/arm/mach-davinci/include/mach/board-dm6446evm.h
deleted file mode 100644
index 3216f21..0000000
--- a/arch/arm/mach-davinci/include/mach/board-dm6446evm.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * DaVinci DM6446 EVM board specific headers
- *
- * 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 ifndef.
- */
-
-#ifndef _MACH_DAVINCI_DM6446EVM_H
-#define _MACH_DAVINCI_DM6446EVM_H
-
-#include <linux/types.h>
-
-int dm6446evm_eeprom_read(char *buf, off_t off, size_t count);
-int dm6446evm_eeprom_write(char *buf, off_t off, size_t count);
-
-#endif
diff --git a/arch/arm/mach-davinci/include/mach/common.h b/arch/arm/mach-davinci/include/mach/common.h
index 1917709..a1f03b6 100644
--- a/arch/arm/mach-davinci/include/mach/common.h
+++ b/arch/arm/mach-davinci/include/mach/common.h
@@ -17,7 +17,8 @@
 extern struct sys_timer davinci_timer;
 
 extern void davinci_irq_init(void);
-extern void davinci_map_common_io(void);
+extern void __iomem *davinci_intc_base;
+extern int davinci_intc_type;
 
 /* parameters describe VBUS sourcing for host mode */
 extern void setup_usb(unsigned mA, unsigned potpgt_msec);
@@ -25,4 +26,56 @@
 /* parameters describe VBUS sourcing for host mode */
 extern void setup_usb(unsigned mA, unsigned potpgt_msec);
 
+struct davinci_timer_instance {
+	void __iomem	*base;
+	u32		bottom_irq;
+	u32		top_irq;
+	unsigned long	cmp_off;
+	unsigned int	cmp_irq;
+};
+
+struct davinci_timer_info {
+	struct davinci_timer_instance	*timers;
+	unsigned int			clockevent_id;
+	unsigned int			clocksource_id;
+};
+
+/* SoC specific init support */
+struct davinci_soc_info {
+	struct map_desc			*io_desc;
+	unsigned long			io_desc_num;
+	u32				cpu_id;
+	u32				jtag_id;
+	void __iomem			*jtag_id_base;
+	struct davinci_id		*ids;
+	unsigned long			ids_num;
+	struct davinci_clk		*cpu_clks;
+	void __iomem			**psc_bases;
+	unsigned long			psc_bases_num;
+	void __iomem			*pinmux_base;
+	const struct mux_config		*pinmux_pins;
+	unsigned long			pinmux_pins_num;
+	void __iomem			*intc_base;
+	int				intc_type;
+	u8				*intc_irq_prios;
+	unsigned long			intc_irq_num;
+	struct davinci_timer_info	*timer_info;
+	void __iomem			*wdt_base;
+	void __iomem			*gpio_base;
+	unsigned			gpio_num;
+	unsigned			gpio_irq;
+	struct platform_device		*serial_dev;
+	struct emac_platform_data	*emac_pdata;
+	dma_addr_t			sram_dma;
+	unsigned			sram_len;
+};
+
+extern struct davinci_soc_info davinci_soc_info;
+
+extern void davinci_common_init(struct davinci_soc_info *soc_info);
+
+/* standard place to map on-chip SRAMs; they *may* support DMA */
+#define SRAM_VIRT	0xfffe0000
+#define SRAM_SIZE	SZ_128K
+
 #endif /* __ARCH_ARM_MACH_DAVINCI_COMMON_H */
diff --git a/arch/arm/mach-davinci/include/mach/cp_intc.h b/arch/arm/mach-davinci/include/mach/cp_intc.h
new file mode 100644
index 0000000..c4d27ee
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/cp_intc.h
@@ -0,0 +1,57 @@
+/*
+ * TI Common Platform Interrupt Controller (cp_intc) definitions
+ *
+ * Author: Steve Chen <schen@mvista.com>
+ * Copyright (C) 2008-2009, MontaVista Software, Inc. <source@mvista.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_HARDWARE_CP_INTC_H
+#define __ASM_HARDWARE_CP_INTC_H
+
+#define CP_INTC_REV			0x00
+#define CP_INTC_CTRL			0x04
+#define CP_INTC_HOST_CTRL		0x0C
+#define CP_INTC_GLOBAL_ENABLE		0x10
+#define CP_INTC_GLOBAL_NESTING_LEVEL	0x1C
+#define CP_INTC_SYS_STAT_IDX_SET	0x20
+#define CP_INTC_SYS_STAT_IDX_CLR	0x24
+#define CP_INTC_SYS_ENABLE_IDX_SET	0x28
+#define CP_INTC_SYS_ENABLE_IDX_CLR	0x2C
+#define CP_INTC_GLOBAL_WAKEUP_ENABLE	0x30
+#define CP_INTC_HOST_ENABLE_IDX_SET	0x34
+#define CP_INTC_HOST_ENABLE_IDX_CLR	0x38
+#define CP_INTC_PACING_PRESCALE 	0x40
+#define CP_INTC_VECTOR_BASE		0x50
+#define CP_INTC_VECTOR_SIZE		0x54
+#define CP_INTC_VECTOR_NULL		0x58
+#define CP_INTC_PRIO_IDX		0x80
+#define CP_INTC_PRIO_VECTOR		0x84
+#define CP_INTC_SECURE_ENABLE		0x90
+#define CP_INTC_SECURE_PRIO_IDX 	0x94
+#define CP_INTC_PACING_PARAM(n) 	(0x0100 + (n << 4))
+#define CP_INTC_PACING_DEC(n)		(0x0104 + (n << 4))
+#define CP_INTC_PACING_MAP(n)		(0x0108 + (n << 4))
+#define CP_INTC_SYS_RAW_STAT(n) 	(0x0200 + (n << 2))
+#define CP_INTC_SYS_STAT_CLR(n) 	(0x0280 + (n << 2))
+#define CP_INTC_SYS_ENABLE_SET(n)	(0x0300 + (n << 2))
+#define CP_INTC_SYS_ENABLE_CLR(n)	(0x0380 + (n << 2))
+#define CP_INTC_CHAN_MAP(n)		(0x0400 + (n << 2))
+#define CP_INTC_HOST_MAP(n)		(0x0800 + (n << 2))
+#define CP_INTC_HOST_PRIO_IDX(n)	(0x0900 + (n << 2))
+#define CP_INTC_SYS_POLARITY(n) 	(0x0D00 + (n << 2))
+#define CP_INTC_SYS_TYPE(n)		(0x0D80 + (n << 2))
+#define CP_INTC_WAKEUP_ENABLE(n)	(0x0E00 + (n << 2))
+#define CP_INTC_DEBUG_SELECT(n) 	(0x0F00 + (n << 2))
+#define CP_INTC_SYS_SECURE_ENABLE(n)	(0x1000 + (n << 2))
+#define CP_INTC_HOST_NESTING_LEVEL(n)	(0x1100 + (n << 2))
+#define CP_INTC_HOST_ENABLE(n)		(0x1500 + (n << 2))
+#define CP_INTC_HOST_PRIO_VECTOR(n)	(0x1600 + (n << 2))
+#define CP_INTC_VECTOR_ADDR(n)		(0x2000 + (n << 2))
+
+void __init cp_intc_init(void __iomem *base, unsigned short num_irq,
+			 u8 *irq_prio);
+
+#endif	/* __ASM_HARDWARE_CP_INTC_H */
diff --git a/arch/arm/mach-davinci/include/mach/cputype.h b/arch/arm/mach-davinci/include/mach/cputype.h
index 27cfb1b..d12a5ed 100644
--- a/arch/arm/mach-davinci/include/mach/cputype.h
+++ b/arch/arm/mach-davinci/include/mach/cputype.h
@@ -16,17 +16,30 @@
 #ifndef _ASM_ARCH_CPU_H
 #define _ASM_ARCH_CPU_H
 
-extern unsigned int davinci_rev(void);
+#include <mach/common.h>
 
-#define IS_DAVINCI_CPU(type, id)			\
-static inline int is_davinci_dm ##type(void)	        \
-{							\
-	return (davinci_rev() == (id)) ? 1 : 0;	        \
+struct davinci_id {
+	u8	variant;	/* JTAG ID bits 31:28 */
+	u16	part_no;	/* JTAG ID bits 27:12 */
+	u16	manufacturer;	/* JTAG ID bits 11:1 */
+	u32	cpu_id;
+	char	*name;
+};
+
+/* Can use lower 16 bits of cpu id  for a variant when required */
+#define	DAVINCI_CPU_ID_DM6446		0x64460000
+#define	DAVINCI_CPU_ID_DM6467		0x64670000
+#define	DAVINCI_CPU_ID_DM355		0x03550000
+
+#define IS_DAVINCI_CPU(type, id)					\
+static inline int is_davinci_ ##type(void)				\
+{									\
+	return (davinci_soc_info.cpu_id == (id));			\
 }
 
-IS_DAVINCI_CPU(644x, 0x6446)
-IS_DAVINCI_CPU(646x, 0x6467)
-IS_DAVINCI_CPU(355, 0x355)
+IS_DAVINCI_CPU(dm644x, DAVINCI_CPU_ID_DM6446)
+IS_DAVINCI_CPU(dm646x, DAVINCI_CPU_ID_DM6467)
+IS_DAVINCI_CPU(dm355, DAVINCI_CPU_ID_DM355)
 
 #ifdef CONFIG_ARCH_DAVINCI_DM644x
 #define cpu_is_davinci_dm644x() is_davinci_dm644x()
diff --git a/arch/arm/mach-davinci/include/mach/debug-macro.S b/arch/arm/mach-davinci/include/mach/debug-macro.S
index e6c0f0d..de3fc21 100644
--- a/arch/arm/mach-davinci/include/mach/debug-macro.S
+++ b/arch/arm/mach-davinci/include/mach/debug-macro.S
@@ -9,6 +9,16 @@
  * or implied.
  */
 
+/* Modifications
+ * Jan 2009	Chaithrika U S	Added senduart, busyuart, waituart
+ *				macros, based on debug-8250.S file
+ *				but using 32-bit accesses required for
+ *                              some davinci devices.
+ */
+
+#include <linux/serial_reg.h>
+#define UART_SHIFT	2
+
 		.macro addruart, rx
 		mrc	p15, 0, \rx, c1, c0
 		tst	\rx, #1			@ MMU enabled?
@@ -17,5 +27,22 @@
 		orr	\rx, \rx, #0x00c20000   @ UART 0
 		.endm
 
-#define UART_SHIFT	2
-#include <asm/hardware/debug-8250.S>
+		.macro	senduart,rd,rx
+		str	\rd, [\rx, #UART_TX << UART_SHIFT]
+		.endm
+
+		.macro	busyuart,rd,rx
+1002:		ldr	\rd, [\rx, #UART_LSR << UART_SHIFT]
+		and	\rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
+		teq	\rd, #UART_LSR_TEMT | UART_LSR_THRE
+		bne	1002b
+		.endm
+
+		.macro	waituart,rd,rx
+#ifdef FLOW_CONTROL
+1001:		ldr	\rd, [\rx, #UART_MSR << UART_SHIFT]
+		tst	\rd, #UART_MSR_CTS
+		beq	1001b
+#endif
+		.endm
+
diff --git a/arch/arm/mach-davinci/include/mach/dm355.h b/arch/arm/mach-davinci/include/mach/dm355.h
new file mode 100644
index 0000000..54903b7
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/dm355.h
@@ -0,0 +1,22 @@
+/*
+ * 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>
+
+struct spi_board_info;
+
+void __init dm355_init(void);
+void dm355_init_spi0(unsigned chipselect_mask,
+		struct spi_board_info *info, unsigned len);
+
+#endif /* __ASM_ARCH_DM355_H */
diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h
index 3dcb9f4..15d42b9 100644
--- a/arch/arm/mach-davinci/include/mach/dm644x.h
+++ b/arch/arm/mach-davinci/include/mach/dm644x.h
@@ -24,6 +24,7 @@
 
 #include <linux/platform_device.h>
 #include <mach/hardware.h>
+#include <mach/emac.h>
 
 #define DM644X_EMAC_BASE		(0x01C80000)
 #define DM644X_EMAC_CNTRL_OFFSET	(0x0000)
diff --git a/arch/arm/mach-davinci/include/mach/dm646x.h b/arch/arm/mach-davinci/include/mach/dm646x.h
new file mode 100644
index 0000000..1fc764c
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/dm646x.h
@@ -0,0 +1,26 @@
+/*
+ * 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/emac.h>
+
+#define DM646X_EMAC_BASE		(0x01C80000)
+#define DM646X_EMAC_CNTRL_OFFSET	(0x0000)
+#define DM646X_EMAC_CNTRL_MOD_OFFSET	(0x1000)
+#define DM646X_EMAC_CNTRL_RAM_OFFSET	(0x2000)
+#define DM646X_EMAC_MDIO_OFFSET		(0x4000)
+#define DM646X_EMAC_CNTRL_RAM_SIZE	(0x2000)
+
+void __init dm646x_init(void);
+
+#endif /* __ASM_ARCH_DM646X_H */
diff --git a/arch/arm/mach-davinci/include/mach/edma.h b/arch/arm/mach-davinci/include/mach/edma.h
index f6fc539..24a3792 100644
--- a/arch/arm/mach-davinci/include/mach/edma.h
+++ b/arch/arm/mach-davinci/include/mach/edma.h
@@ -208,10 +208,6 @@
 void edma_pause(unsigned channel);
 void edma_resume(unsigned channel);
 
-/* UNRELATED TO DMA */
-int davinci_alloc_iram(unsigned size);
-void davinci_free_iram(unsigned addr, unsigned size);
-
 /* platform_data for EDMA driver */
 struct edma_soc_info {
 
diff --git a/arch/arm/mach-davinci/include/mach/emac.h b/arch/arm/mach-davinci/include/mach/emac.h
new file mode 100644
index 0000000..beff4fb
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/emac.h
@@ -0,0 +1,36 @@
+/*
+ * TI DaVinci EMAC platform support
+ *
+ * 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 _MACH_DAVINCI_EMAC_H
+#define _MACH_DAVINCI_EMAC_H
+
+#include <linux/if_ether.h>
+#include <linux/memory.h>
+
+struct emac_platform_data {
+	char mac_addr[ETH_ALEN];
+	u32 ctrl_reg_offset;
+	u32 ctrl_mod_reg_offset;
+	u32 ctrl_ram_offset;
+	u32 mdio_reg_offset;
+	u32 ctrl_ram_size;
+	u32 phy_mask;
+	u32 mdio_max_freq;
+	u8 rmii_en;
+	u8 version;
+};
+
+enum {
+	EMAC_VERSION_1,	/* DM644x */
+	EMAC_VERSION_2,	/* DM646x */
+};
+
+void davinci_get_mac_addr(struct memory_accessor *mem_acc, void *context);
+#endif
diff --git a/arch/arm/mach-davinci/include/mach/entry-macro.S b/arch/arm/mach-davinci/include/mach/entry-macro.S
index 039b84f..fbdebc7 100644
--- a/arch/arm/mach-davinci/include/mach/entry-macro.S
+++ b/arch/arm/mach-davinci/include/mach/entry-macro.S
@@ -15,17 +15,36 @@
 		.endm
 
 		.macro  get_irqnr_preamble, base, tmp
-		ldr \base, =IO_ADDRESS(DAVINCI_ARM_INTC_BASE)
+		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
+		ldr \tmp, [\tmp]
+		cmp \tmp, #DAVINCI_INTC_TYPE_CP_INTC
+		beq 1001f
+#endif
+#if defined(CONFIG_AINTC)
 		ldr \tmp, [\base, #0x14]
-		mov \tmp, \tmp, lsr #2
+		movs \tmp, \tmp, lsr #2
 		sub \irqnr, \tmp, #1
-		cmp \tmp, #0
+		b 1002f
+#endif
+#if defined(CONFIG_CP_INTC)
+1001:		ldr \irqnr, [\base, #0x80] /* get irq number */
+		and \irqnr, \irqnr, #0xff  /* irq is in bits 0-9 */
+		mov \tmp, \irqnr, lsr #3
+		and \tmp, \tmp, #0xfc
+		add \tmp, \tmp, #0x280 /* get the register offset */
+		ldr \irqstat, [\base, \tmp] /* get the intc status */
+		cmp \irqstat, #0x0
+#endif
+1002:
 		.endm
 
 		.macro	irq_prio_table
diff --git a/arch/arm/mach-davinci/include/mach/gpio.h b/arch/arm/mach-davinci/include/mach/gpio.h
index efe3281..ae07455 100644
--- a/arch/arm/mach-davinci/include/mach/gpio.h
+++ b/arch/arm/mach-davinci/include/mach/gpio.h
@@ -17,6 +17,7 @@
 #include <asm-generic/gpio.h>
 
 #include <mach/irqs.h>
+#include <mach/common.h>
 
 #define DAVINCI_GPIO_BASE 0x01C67000
 
@@ -67,15 +68,16 @@
 __gpio_to_controller(unsigned gpio)
 {
 	void *__iomem ptr;
+	void __iomem *base = davinci_soc_info.gpio_base;
 
 	if (gpio < 32 * 1)
-		ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10);
+		ptr = base + 0x10;
 	else if (gpio < 32 * 2)
-		ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x38);
+		ptr = base + 0x38;
 	else if (gpio < 32 * 3)
-		ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x60);
+		ptr = base + 0x60;
 	else if (gpio < 32 * 4)
-		ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x88);
+		ptr = base + 0x88;
 	else
 		ptr = NULL;
 	return ptr;
@@ -142,13 +144,13 @@
 {
 	if (gpio >= DAVINCI_N_GPIO)
 		return -EINVAL;
-	return DAVINCI_N_AINTC_IRQ + gpio;
+	return davinci_soc_info.intc_irq_num + gpio;
 }
 
 static inline int irq_to_gpio(unsigned irq)
 {
 	/* caller guarantees gpio_to_irq() succeeded */
-	return irq - DAVINCI_N_AINTC_IRQ;
+	return irq - davinci_soc_info.intc_irq_num;
 }
 
 #endif				/* __DAVINCI_GPIO_H */
diff --git a/arch/arm/mach-davinci/include/mach/irqs.h b/arch/arm/mach-davinci/include/mach/irqs.h
index 1806607..bc5d6aa 100644
--- a/arch/arm/mach-davinci/include/mach/irqs.h
+++ b/arch/arm/mach-davinci/include/mach/irqs.h
@@ -30,6 +30,9 @@
 /* Base address */
 #define DAVINCI_ARM_INTC_BASE 0x01C48000
 
+#define DAVINCI_INTC_TYPE_AINTC		0
+#define DAVINCI_INTC_TYPE_CP_INTC	1
+
 /* Interrupt lines */
 #define IRQ_VDINT0       0
 #define IRQ_VDINT1       1
diff --git a/arch/arm/mach-davinci/include/mach/memory.h b/arch/arm/mach-davinci/include/mach/memory.h
index 86c25c7..c712c7c 100644
--- a/arch/arm/mach-davinci/include/mach/memory.h
+++ b/arch/arm/mach-davinci/include/mach/memory.h
@@ -21,7 +21,6 @@
  * Definitions
  **************************************************************************/
 #define DAVINCI_DDR_BASE    0x80000000
-#define DAVINCI_IRAM_BASE   0x00008000 /* ARM Internal RAM */
 
 #define PHYS_OFFSET DAVINCI_DDR_BASE
 
diff --git a/arch/arm/mach-davinci/include/mach/mmc.h b/arch/arm/mach-davinci/include/mach/mmc.h
new file mode 100644
index 0000000..5a85e24
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/mmc.h
@@ -0,0 +1,33 @@
+/*
+ *  Board-specific MMC configuration
+ */
+
+#ifndef _DAVINCI_MMC_H
+#define _DAVINCI_MMC_H
+
+#include <linux/types.h>
+#include <linux/mmc/host.h>
+
+struct davinci_mmc_config {
+	/* get_cd()/get_wp() may sleep */
+	int	(*get_cd)(int module);
+	int	(*get_ro)(int module);
+	/* wires == 0 is equivalent to wires == 4 (4-bit parallel) */
+	u8	wires;
+
+	u32     max_freq;
+
+	/* any additional host capabilities: OR'd in to mmc->f_caps */
+	u32     caps;
+
+	/* Version of the MMC/SD controller */
+	u8	version;
+};
+void davinci_setup_mmc(int module, struct davinci_mmc_config *config);
+
+enum {
+	MMC_CTLR_VERSION_1 = 0,	/* DM644x and DM355 */
+	MMC_CTLR_VERSION_2,	/* DA830 */
+};
+
+#endif
diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h
index bae22cb..2737845 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -19,16 +19,6 @@
 #ifndef __INC_MACH_MUX_H
 #define __INC_MACH_MUX_H
 
-/* System module registers */
-#define PINMUX0			0x00
-#define PINMUX1			0x04
-/* dm355 only */
-#define PINMUX2			0x08
-#define PINMUX3			0x0c
-#define PINMUX4			0x10
-#define INTMUX			0x18
-#define EVTMUX			0x1c
-
 struct mux_config {
 	const char *name;
 	const char *mux_reg_name;
@@ -168,15 +158,9 @@
 
 #ifdef CONFIG_DAVINCI_MUX
 /* setup pin muxing */
-extern void davinci_mux_init(void);
-extern int davinci_mux_register(const struct mux_config *pins,
-				unsigned long size);
 extern int davinci_cfg_reg(unsigned long reg_cfg);
 #else
 /* boot loader does it all (no warnings from CONFIG_DAVINCI_MUX_WARNINGS) */
-static inline void davinci_mux_init(void) {}
-static inline int davinci_mux_register(const struct mux_config *pins,
-				       unsigned long size) { return 0; }
 static inline int davinci_cfg_reg(unsigned long reg_cfg) { return 0; }
 #endif
 
diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h
index 55a90d4..ab8a258 100644
--- a/arch/arm/mach-davinci/include/mach/psc.h
+++ b/arch/arm/mach-davinci/include/mach/psc.h
@@ -27,6 +27,8 @@
 #ifndef __ASM_ARCH_PSC_H
 #define __ASM_ARCH_PSC_H
 
+#define	DAVINCI_PWR_SLEEP_CNTRL_BASE	0x01C41000
+
 /* Power and Sleep Controller (PSC) Domains */
 #define DAVINCI_GPSC_ARMDOMAIN      0
 #define DAVINCI_GPSC_DSPDOMAIN      1
@@ -116,8 +118,8 @@
 #define DM646X_LPSC_TIMER1         35
 #define DM646X_LPSC_ARM_INTC       45
 
-extern int davinci_psc_is_clk_active(unsigned int id);
-extern void davinci_psc_config(unsigned int domain, unsigned int id,
-			       char enable);
+extern int davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id);
+extern void davinci_psc_config(unsigned int domain, unsigned int ctlr,
+		unsigned int id, char enable);
 
 #endif /* __ASM_ARCH_PSC_H */
diff --git a/arch/arm/mach-davinci/include/mach/serial.h b/arch/arm/mach-davinci/include/mach/serial.h
index 632847d..794fa5c 100644
--- a/arch/arm/mach-davinci/include/mach/serial.h
+++ b/arch/arm/mach-davinci/include/mach/serial.h
@@ -18,8 +18,6 @@
 #define DAVINCI_UART1_BASE	(IO_PHYS + 0x20400)
 #define DAVINCI_UART2_BASE	(IO_PHYS + 0x20800)
 
-#define DM355_UART2_BASE	(IO_PHYS + 0x206000)
-
 /* DaVinci UART register offsets */
 #define UART_DAVINCI_PWREMU		0x0c
 #define UART_DM646X_SCR			0x10
@@ -30,6 +28,6 @@
 	unsigned int enabled_uarts;
 };
 
-extern void davinci_serial_init(struct davinci_uart_config *);
+extern int davinci_serial_init(struct davinci_uart_config *);
 
 #endif /* __ASM_ARCH_SERIAL_H */
diff --git a/arch/arm/mach-davinci/include/mach/sram.h b/arch/arm/mach-davinci/include/mach/sram.h
new file mode 100644
index 0000000..111f7cc
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/sram.h
@@ -0,0 +1,27 @@
+/*
+ * mach/sram.h - DaVinci simple SRAM allocator
+ *
+ * Copyright (C) 2009 David Brownell
+ *
+ * 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_SRAM_H
+#define __MACH_SRAM_H
+
+/* ARBITRARY:  SRAM allocations are multiples of this 2^N size */
+#define SRAM_GRANULARITY	512
+
+/*
+ * SRAM allocations return a CPU virtual address, or NULL on error.
+ * If a DMA address is requested and the SRAM supports DMA, its
+ * mapped address is also returned.
+ *
+ * Errors include SRAM memory not being available, and requesting
+ * DMA mapped SRAM on systems which don't allow that.
+ */
+extern void *sram_alloc(size_t len, dma_addr_t *dma);
+extern void sram_free(void *addr, size_t len);
+
+#endif /* __MACH_SRAM_H */
diff --git a/arch/arm/mach-davinci/include/mach/time.h b/arch/arm/mach-davinci/include/mach/time.h
new file mode 100644
index 0000000..1c971d8
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/time.h
@@ -0,0 +1,35 @@
+/*
+ * Local header file for DaVinci time code.
+ *
+ * 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 __ARCH_ARM_MACH_DAVINCI_TIME_H
+#define __ARCH_ARM_MACH_DAVINCI_TIME_H
+
+#define DAVINCI_TIMER0_BASE		(IO_PHYS + 0x21400)
+#define DAVINCI_TIMER1_BASE		(IO_PHYS + 0x21800)
+#define DAVINCI_WDOG_BASE		(IO_PHYS + 0x21C00)
+
+enum {
+	T0_BOT,
+	T0_TOP,
+	T1_BOT,
+	T1_TOP,
+	NUM_TIMERS
+};
+
+#define IS_TIMER1(id)		(id & 0x2)
+#define IS_TIMER0(id)		(!IS_TIMER1(id))
+#define IS_TIMER_TOP(id)	((id & 0x1))
+#define IS_TIMER_BOT(id)	(!IS_TIMER_TOP(id))
+
+#define ID_TO_TIMER(id)		(IS_TIMER1(id) != 0)
+
+extern struct davinci_timer_instance davinci_timer_instance[];
+
+#endif /* __ARCH_ARM_MACH_DAVINCI_TIME_H */
diff --git a/arch/arm/mach-davinci/include/mach/uncompress.h b/arch/arm/mach-davinci/include/mach/uncompress.h
index 8c165de..1e27475 100644
--- a/arch/arm/mach-davinci/include/mach/uncompress.h
+++ b/arch/arm/mach-davinci/include/mach/uncompress.h
@@ -13,11 +13,24 @@
 #include <linux/serial_reg.h>
 #include <mach/serial.h>
 
+#include <asm/mach-types.h>
+
+extern unsigned int __machine_arch_type;
+
+static u32 *uart;
+
+static u32 *get_uart_base(void)
+{
+	/* Add logic here for new platforms, using __macine_arch_type */
+	return (u32 *)DAVINCI_UART0_BASE;
+}
+
 /* PORT_16C550A, in polled non-fifo mode */
 
 static void putc(char c)
 {
-	volatile u32 *uart = (volatile void *) DAVINCI_UART0_BASE;
+	if (!uart)
+		uart = get_uart_base();
 
 	while (!(uart[UART_LSR] & UART_LSR_THRE))
 		barrier();
@@ -26,7 +39,9 @@
 
 static inline void flush(void)
 {
-	volatile u32 *uart = (volatile void *) DAVINCI_UART0_BASE;
+	if (!uart)
+		uart = get_uart_base();
+
 	while (!(uart[UART_LSR] & UART_LSR_THRE))
 		barrier();
 }
diff --git a/arch/arm/mach-davinci/io.c b/arch/arm/mach-davinci/io.c
index a548abb..49912b4 100644
--- a/arch/arm/mach-davinci/io.c
+++ b/arch/arm/mach-davinci/io.c
@@ -9,47 +9,9 @@
  */
 
 #include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/io.h>
 
 #include <asm/tlb.h>
-#include <asm/memory.h>
-
-#include <asm/mach/map.h>
-#include <mach/clock.h>
-
-extern void davinci_check_revision(void);
-
-/*
- * The machine specific code may provide the extra mapping besides the
- * default mapping provided here.
- */
-static struct map_desc davinci_io_desc[] __initdata = {
-	{
-		.virtual	= IO_VIRT,
-		.pfn		= __phys_to_pfn(IO_PHYS),
-		.length		= IO_SIZE,
-		.type		= MT_DEVICE
-	},
-};
-
-void __init davinci_map_common_io(void)
-{
-	iotable_init(davinci_io_desc, ARRAY_SIZE(davinci_io_desc));
-
-	/* Normally devicemaps_init() would flush caches and tlb after
-	 * mdesc->map_io(), but we must also do it here because of the CPU
-	 * revision check below.
-	 */
-	local_flush_tlb_all();
-	flush_cache_all();
-
-	/* We want to check CPU revision early for cpu_is_xxxx() macros.
-	 * IO space mapping must be initialized before we can do that.
-	 */
-	davinci_check_revision();
-}
 
 #define BETWEEN(p, st, sz)	((p) >= (st) && (p) < ((st) + (sz)))
 #define XLATE(p, pst, vst)	((void __iomem *)((p) - (pst) + (vst)))
diff --git a/arch/arm/mach-davinci/irq.c b/arch/arm/mach-davinci/irq.c
index 5a324c9..af92ffe 100644
--- a/arch/arm/mach-davinci/irq.c
+++ b/arch/arm/mach-davinci/irq.c
@@ -26,6 +26,7 @@
 
 #include <mach/hardware.h>
 #include <mach/cputype.h>
+#include <mach/common.h>
 #include <asm/mach/irq.h>
 
 #define IRQ_BIT(irq)		((irq) & 0x1f)
@@ -41,18 +42,14 @@
 #define IRQ_INTPRI0_REG_OFFSET	0x0030
 #define IRQ_INTPRI7_REG_OFFSET	0x004C
 
-const u8 *davinci_def_priorities;
-
-#define INTC_BASE IO_ADDRESS(DAVINCI_ARM_INTC_BASE)
-
 static inline unsigned int davinci_irq_readl(int offset)
 {
-	return __raw_readl(INTC_BASE + offset);
+	return __raw_readl(davinci_intc_base + offset);
 }
 
 static inline void davinci_irq_writel(unsigned long value, int offset)
 {
-	__raw_writel(value, INTC_BASE + offset);
+	__raw_writel(value, davinci_intc_base + offset);
 }
 
 /* Disable interrupt */
@@ -113,217 +110,11 @@
 	.unmask = davinci_unmask_irq,
 };
 
-/* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */
-static const u8 dm644x_default_priorities[DAVINCI_N_AINTC_IRQ] __initdata = {
-	[IRQ_VDINT0]		= 2,
-	[IRQ_VDINT1]		= 6,
-	[IRQ_VDINT2]		= 6,
-	[IRQ_HISTINT]		= 6,
-	[IRQ_H3AINT]		= 6,
-	[IRQ_PRVUINT]		= 6,
-	[IRQ_RSZINT]		= 6,
-	[7]			= 7,
-	[IRQ_VENCINT]		= 6,
-	[IRQ_ASQINT]		= 6,
-	[IRQ_IMXINT]		= 6,
-	[IRQ_VLCDINT]		= 6,
-	[IRQ_USBINT]		= 4,
-	[IRQ_EMACINT]		= 4,
-	[14]			= 7,
-	[15]			= 7,
-	[IRQ_CCINT0]		= 5,	/* dma */
-	[IRQ_CCERRINT]		= 5,	/* dma */
-	[IRQ_TCERRINT0]		= 5,	/* dma */
-	[IRQ_TCERRINT]		= 5,	/* dma */
-	[IRQ_PSCIN]		= 7,
-	[21]			= 7,
-	[IRQ_IDE]		= 4,
-	[23]			= 7,
-	[IRQ_MBXINT]		= 7,
-	[IRQ_MBRINT]		= 7,
-	[IRQ_MMCINT]		= 7,
-	[IRQ_SDIOINT]		= 7,
-	[28]			= 7,
-	[IRQ_DDRINT]		= 7,
-	[IRQ_AEMIFINT]		= 7,
-	[IRQ_VLQINT]		= 4,
-	[IRQ_TINT0_TINT12]	= 2,	/* clockevent */
-	[IRQ_TINT0_TINT34]	= 2,	/* clocksource */
-	[IRQ_TINT1_TINT12]	= 7,	/* DSP timer */
-	[IRQ_TINT1_TINT34]	= 7,	/* system tick */
-	[IRQ_PWMINT0]		= 7,
-	[IRQ_PWMINT1]		= 7,
-	[IRQ_PWMINT2]		= 7,
-	[IRQ_I2C]		= 3,
-	[IRQ_UARTINT0]		= 3,
-	[IRQ_UARTINT1]		= 3,
-	[IRQ_UARTINT2]		= 3,
-	[IRQ_SPINT0]		= 3,
-	[IRQ_SPINT1]		= 3,
-	[45]			= 7,
-	[IRQ_DSP2ARM0]		= 4,
-	[IRQ_DSP2ARM1]		= 4,
-	[IRQ_GPIO0]		= 7,
-	[IRQ_GPIO1]		= 7,
-	[IRQ_GPIO2]		= 7,
-	[IRQ_GPIO3]		= 7,
-	[IRQ_GPIO4]		= 7,
-	[IRQ_GPIO5]		= 7,
-	[IRQ_GPIO6]		= 7,
-	[IRQ_GPIO7]		= 7,
-	[IRQ_GPIOBNK0]		= 7,
-	[IRQ_GPIOBNK1]		= 7,
-	[IRQ_GPIOBNK2]		= 7,
-	[IRQ_GPIOBNK3]		= 7,
-	[IRQ_GPIOBNK4]		= 7,
-	[IRQ_COMMTX]		= 7,
-	[IRQ_COMMRX]		= 7,
-	[IRQ_EMUINT]		= 7,
-};
-
-static const u8 dm646x_default_priorities[DAVINCI_N_AINTC_IRQ] = {
-	[IRQ_DM646X_VP_VERTINT0]        = 7,
-	[IRQ_DM646X_VP_VERTINT1]        = 7,
-	[IRQ_DM646X_VP_VERTINT2]        = 7,
-	[IRQ_DM646X_VP_VERTINT3]        = 7,
-	[IRQ_DM646X_VP_ERRINT]          = 7,
-	[IRQ_DM646X_RESERVED_1]         = 7,
-	[IRQ_DM646X_RESERVED_2]         = 7,
-	[IRQ_DM646X_WDINT]              = 7,
-	[IRQ_DM646X_CRGENINT0]          = 7,
-	[IRQ_DM646X_CRGENINT1]          = 7,
-	[IRQ_DM646X_TSIFINT0]           = 7,
-	[IRQ_DM646X_TSIFINT1]           = 7,
-	[IRQ_DM646X_VDCEINT]            = 7,
-	[IRQ_DM646X_USBINT]             = 7,
-	[IRQ_DM646X_USBDMAINT]          = 7,
-	[IRQ_DM646X_PCIINT]             = 7,
-	[IRQ_CCINT0]                    = 7,    /* dma */
-	[IRQ_CCERRINT]                  = 7,    /* dma */
-	[IRQ_TCERRINT0]                 = 7,    /* dma */
-	[IRQ_TCERRINT]                  = 7,    /* dma */
-	[IRQ_DM646X_TCERRINT2]          = 7,
-	[IRQ_DM646X_TCERRINT3]          = 7,
-	[IRQ_DM646X_IDE]                = 7,
-	[IRQ_DM646X_HPIINT]             = 7,
-	[IRQ_DM646X_EMACRXTHINT]        = 7,
-	[IRQ_DM646X_EMACRXINT]          = 7,
-	[IRQ_DM646X_EMACTXINT]          = 7,
-	[IRQ_DM646X_EMACMISCINT]        = 7,
-	[IRQ_DM646X_MCASP0TXINT]        = 7,
-	[IRQ_DM646X_MCASP0RXINT]        = 7,
-	[IRQ_AEMIFINT]                  = 7,
-	[IRQ_DM646X_RESERVED_3]         = 7,
-	[IRQ_DM646X_MCASP1TXINT]        = 7,    /* clockevent */
-	[IRQ_TINT0_TINT34]              = 7,    /* clocksource */
-	[IRQ_TINT1_TINT12]              = 7,    /* DSP timer */
-	[IRQ_TINT1_TINT34]              = 7,    /* system tick */
-	[IRQ_PWMINT0]                   = 7,
-	[IRQ_PWMINT1]                   = 7,
-	[IRQ_DM646X_VLQINT]             = 7,
-	[IRQ_I2C]                       = 7,
-	[IRQ_UARTINT0]                  = 7,
-	[IRQ_UARTINT1]                  = 7,
-	[IRQ_DM646X_UARTINT2]           = 7,
-	[IRQ_DM646X_SPINT0]             = 7,
-	[IRQ_DM646X_SPINT1]             = 7,
-	[IRQ_DM646X_DSP2ARMINT]         = 7,
-	[IRQ_DM646X_RESERVED_4]         = 7,
-	[IRQ_DM646X_PSCINT]             = 7,
-	[IRQ_DM646X_GPIO0]              = 7,
-	[IRQ_DM646X_GPIO1]              = 7,
-	[IRQ_DM646X_GPIO2]              = 7,
-	[IRQ_DM646X_GPIO3]              = 7,
-	[IRQ_DM646X_GPIO4]              = 7,
-	[IRQ_DM646X_GPIO5]              = 7,
-	[IRQ_DM646X_GPIO6]              = 7,
-	[IRQ_DM646X_GPIO7]              = 7,
-	[IRQ_DM646X_GPIOBNK0]           = 7,
-	[IRQ_DM646X_GPIOBNK1]           = 7,
-	[IRQ_DM646X_GPIOBNK2]           = 7,
-	[IRQ_DM646X_DDRINT]             = 7,
-	[IRQ_DM646X_AEMIFINT]           = 7,
-	[IRQ_COMMTX]                    = 7,
-	[IRQ_COMMRX]                    = 7,
-	[IRQ_EMUINT]                    = 7,
-};
-
-static const u8 dm355_default_priorities[DAVINCI_N_AINTC_IRQ] = {
-	[IRQ_DM355_CCDC_VDINT0]		= 2,
-	[IRQ_DM355_CCDC_VDINT1]		= 6,
-	[IRQ_DM355_CCDC_VDINT2]		= 6,
-	[IRQ_DM355_IPIPE_HST]		= 6,
-	[IRQ_DM355_H3AINT]		= 6,
-	[IRQ_DM355_IPIPE_SDR]		= 6,
-	[IRQ_DM355_IPIPEIFINT]		= 6,
-	[IRQ_DM355_OSDINT]		= 7,
-	[IRQ_DM355_VENCINT]		= 6,
-	[IRQ_ASQINT]			= 6,
-	[IRQ_IMXINT]			= 6,
-	[IRQ_USBINT]			= 4,
-	[IRQ_DM355_RTOINT]		= 4,
-	[IRQ_DM355_UARTINT2]		= 7,
-	[IRQ_DM355_TINT6]		= 7,
-	[IRQ_CCINT0]			= 5,	/* dma */
-	[IRQ_CCERRINT]			= 5,	/* dma */
-	[IRQ_TCERRINT0]			= 5,	/* dma */
-	[IRQ_TCERRINT]			= 5,	/* dma */
-	[IRQ_DM355_SPINT2_1]		= 7,
-	[IRQ_DM355_TINT7]		= 4,
-	[IRQ_DM355_SDIOINT0]		= 7,
-	[IRQ_MBXINT]			= 7,
-	[IRQ_MBRINT]			= 7,
-	[IRQ_MMCINT]			= 7,
-	[IRQ_DM355_MMCINT1]		= 7,
-	[IRQ_DM355_PWMINT3]		= 7,
-	[IRQ_DDRINT]			= 7,
-	[IRQ_AEMIFINT]			= 7,
-	[IRQ_DM355_SDIOINT1]		= 4,
-	[IRQ_TINT0_TINT12]		= 2,	/* clockevent */
-	[IRQ_TINT0_TINT34]		= 2,	/* clocksource */
-	[IRQ_TINT1_TINT12]		= 7,	/* DSP timer */
-	[IRQ_TINT1_TINT34]		= 7,	/* system tick */
-	[IRQ_PWMINT0]			= 7,
-	[IRQ_PWMINT1]			= 7,
-	[IRQ_PWMINT2]			= 7,
-	[IRQ_I2C]			= 3,
-	[IRQ_UARTINT0]			= 3,
-	[IRQ_UARTINT1]			= 3,
-	[IRQ_DM355_SPINT0_0]		= 3,
-	[IRQ_DM355_SPINT0_1]		= 3,
-	[IRQ_DM355_GPIO0]		= 3,
-	[IRQ_DM355_GPIO1]		= 7,
-	[IRQ_DM355_GPIO2]		= 4,
-	[IRQ_DM355_GPIO3]		= 4,
-	[IRQ_DM355_GPIO4]		= 7,
-	[IRQ_DM355_GPIO5]		= 7,
-	[IRQ_DM355_GPIO6]		= 7,
-	[IRQ_DM355_GPIO7]		= 7,
-	[IRQ_DM355_GPIO8]		= 7,
-	[IRQ_DM355_GPIO9]		= 7,
-	[IRQ_DM355_GPIOBNK0]		= 7,
-	[IRQ_DM355_GPIOBNK1]		= 7,
-	[IRQ_DM355_GPIOBNK2]		= 7,
-	[IRQ_DM355_GPIOBNK3]		= 7,
-	[IRQ_DM355_GPIOBNK4]		= 7,
-	[IRQ_DM355_GPIOBNK5]		= 7,
-	[IRQ_DM355_GPIOBNK6]		= 7,
-	[IRQ_COMMTX]			= 7,
-	[IRQ_COMMRX]			= 7,
-	[IRQ_EMUINT]			= 7,
-};
-
 /* ARM Interrupt Controller Initialization */
 void __init davinci_irq_init(void)
 {
 	unsigned i;
-
-	if (cpu_is_davinci_dm644x())
-		davinci_def_priorities = dm644x_default_priorities;
-	else if (cpu_is_davinci_dm646x())
-		davinci_def_priorities = dm646x_default_priorities;
-	else if (cpu_is_davinci_dm355())
-		davinci_def_priorities = dm355_default_priorities;
+	const u8 *davinci_def_priorities = davinci_soc_info.intc_irq_prios;
 
 	/* Clear all interrupt requests */
 	davinci_irq_writel(~0x0, FIQ_REG0_OFFSET);
diff --git a/arch/arm/mach-davinci/mux.c b/arch/arm/mach-davinci/mux.c
index bbba0b2..d310f57 100644
--- a/arch/arm/mach-davinci/mux.c
+++ b/arch/arm/mach-davinci/mux.c
@@ -21,18 +21,7 @@
 
 #include <mach/hardware.h>
 #include <mach/mux.h>
-
-static const struct mux_config *mux_table;
-static unsigned long pin_table_sz;
-
-int __init davinci_mux_register(const struct mux_config *pins,
-				unsigned long size)
-{
-	mux_table = pins;
-	pin_table_sz = size;
-
-	return 0;
-}
+#include <mach/common.h>
 
 /*
  * Sets the DAVINCI MUX register based on the table
@@ -40,23 +29,24 @@
 int __init_or_module davinci_cfg_reg(const unsigned long index)
 {
 	static DEFINE_SPINLOCK(mux_spin_lock);
-	void __iomem *base = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE);
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
+	void __iomem *base = soc_info->pinmux_base;
 	unsigned long flags;
 	const struct mux_config *cfg;
 	unsigned int reg_orig = 0, reg = 0;
 	unsigned int mask, warn = 0;
 
-	if (!mux_table)
+	if (!soc_info->pinmux_pins)
 		BUG();
 
-	if (index >= pin_table_sz) {
+	if (index >= soc_info->pinmux_pins_num) {
 		printk(KERN_ERR "Invalid pin mux index: %lu (%lu)\n",
-		       index, pin_table_sz);
+		       index, soc_info->pinmux_pins_num);
 		dump_stack();
 		return -ENODEV;
 	}
 
-	cfg = &mux_table[index];
+	cfg = &soc_info->pinmux_pins[index];
 
 	if (cfg->name == NULL) {
 		printk(KERN_ERR "No entry for the specified index\n");
diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c
index 84171ab..a78b657 100644
--- a/arch/arm/mach-davinci/psc.c
+++ b/arch/arm/mach-davinci/psc.c
@@ -28,8 +28,6 @@
 #include <mach/psc.h>
 #include <mach/mux.h>
 
-#define DAVINCI_PWR_SLEEP_CNTRL_BASE 0x01C41000
-
 /* PSC register offsets */
 #define EPCPR		0x070
 #define PTCMD		0x120
@@ -42,22 +40,42 @@
 #define MDSTAT_STATE_MASK 0x1f
 
 /* Return nonzero iff the domain's clock is active */
-int __init davinci_psc_is_clk_active(unsigned int id)
+int __init davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id)
 {
-	void __iomem *psc_base = IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE);
-	u32 mdstat = __raw_readl(psc_base + MDSTAT + 4 * id);
+	void __iomem *psc_base;
+	u32 mdstat;
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+	if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) {
+		pr_warning("PSC: Bad psc data: 0x%x[%d]\n",
+				(int)soc_info->psc_bases, ctlr);
+		return 0;
+	}
+
+	psc_base = soc_info->psc_bases[ctlr];
+	mdstat = __raw_readl(psc_base + MDSTAT + 4 * id);
 
 	/* if clocked, state can be "Enable" or "SyncReset" */
 	return mdstat & BIT(12);
 }
 
 /* Enable or disable a PSC domain */
-void davinci_psc_config(unsigned int domain, unsigned int id, char enable)
+void davinci_psc_config(unsigned int domain, unsigned int ctlr,
+		unsigned int id, char enable)
 {
 	u32 epcpr, ptcmd, ptstat, pdstat, pdctl1, mdstat, mdctl;
-	void __iomem *psc_base = IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE);
+	void __iomem *psc_base;
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
 	u32 next_state = enable ? 0x3 : 0x2; /* 0x3 enables, 0x2 disables */
 
+	if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) {
+		pr_warning("PSC: Bad psc data: 0x%x[%d]\n",
+				(int)soc_info->psc_bases, ctlr);
+		return;
+	}
+
+	psc_base = soc_info->psc_bases[ctlr];
+
 	mdctl = __raw_readl(psc_base + MDCTL + 4 * id);
 	mdctl &= ~MDSTAT_STATE_MASK;
 	mdctl |= next_state;
diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c
index 6950757..c530c73 100644
--- a/arch/arm/mach-davinci/serial.c
+++ b/arch/arm/mach-davinci/serial.c
@@ -33,6 +33,8 @@
 #include <mach/serial.h>
 #include <mach/irqs.h>
 #include <mach/cputype.h>
+#include <mach/common.h>
+
 #include "clock.h"
 
 static inline unsigned int serial_read_reg(struct plat_serial8250_port *up,
@@ -49,44 +51,6 @@
 	__raw_writel(value, IO_ADDRESS(p->mapbase) + offset);
 }
 
-static struct plat_serial8250_port serial_platform_data[] = {
-	{
-		.mapbase	= DAVINCI_UART0_BASE,
-		.irq		= IRQ_UARTINT0,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
-				  UPF_IOREMAP,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-	},
-	{
-		.mapbase	= DAVINCI_UART1_BASE,
-		.irq		= IRQ_UARTINT1,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
-				  UPF_IOREMAP,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-	},
-	{
-		.mapbase	= DAVINCI_UART2_BASE,
-		.irq		= IRQ_UARTINT2,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
-				  UPF_IOREMAP,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-	},
-	{
-		.flags		= 0
-	},
-};
-
-static struct platform_device serial_device = {
-	.name			= "serial8250",
-	.id			= PLAT8250_DEV_PLATFORM,
-	.dev			= {
-		.platform_data	= serial_platform_data,
-	},
-};
-
 static void __init davinci_serial_reset(struct plat_serial8250_port *p)
 {
 	unsigned int pwremu = 0;
@@ -106,35 +70,22 @@
 				 UART_DM646X_SCR_TX_WATERMARK);
 }
 
-void __init davinci_serial_init(struct davinci_uart_config *info)
+int __init davinci_serial_init(struct davinci_uart_config *info)
 {
 	int i;
 	char name[16];
 	struct clk *uart_clk;
-	struct device *dev = &serial_device.dev;
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
+	struct device *dev = &soc_info->serial_dev->dev;
+	struct plat_serial8250_port *p = dev->platform_data;
 
 	/*
 	 * Make sure the serial ports are muxed on at this point.
-	 * You have to mux them off in device drivers later on
-	 * if not needed.
+	 * You have to mux them off in device drivers later on if not needed.
 	 */
-	for (i = 0; i < DAVINCI_MAX_NR_UARTS; i++) {
-		struct plat_serial8250_port *p = serial_platform_data + i;
-
-		if (!(info->enabled_uarts & (1 << i))) {
-			p->flags = 0;
+	for (i = 0; i < DAVINCI_MAX_NR_UARTS; i++, p++) {
+		if (!(info->enabled_uarts & (1 << i)))
 			continue;
-		}
-
-		if (cpu_is_davinci_dm646x())
-			p->iotype = UPIO_MEM32;
-
-		if (cpu_is_davinci_dm355()) {
-			if (i == 2) {
-				p->mapbase = (unsigned long)DM355_UART2_BASE;
-				p->irq = IRQ_DM355_UARTINT2;
-			}
-		}
 
 		sprintf(name, "uart%d", i);
 		uart_clk = clk_get(dev, name);
@@ -147,11 +98,6 @@
 			davinci_serial_reset(p);
 		}
 	}
-}
 
-static int __init davinci_init(void)
-{
-	return platform_device_register(&serial_device);
+	return platform_device_register(soc_info->serial_dev);
 }
-
-arch_initcall(davinci_init);
diff --git a/arch/arm/mach-davinci/sram.c b/arch/arm/mach-davinci/sram.c
new file mode 100644
index 0000000..db54b2a
--- /dev/null
+++ b/arch/arm/mach-davinci/sram.c
@@ -0,0 +1,74 @@
+/*
+ * mach-davinci/sram.c - DaVinci simple SRAM allocator
+ *
+ * Copyright (C) 2009 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.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/genalloc.h>
+
+#include <mach/common.h>
+#include <mach/memory.h>
+#include <mach/sram.h>
+
+
+static struct gen_pool *sram_pool;
+
+void *sram_alloc(size_t len, dma_addr_t *dma)
+{
+	unsigned long vaddr;
+	dma_addr_t dma_base = davinci_soc_info.sram_dma;
+
+	if (dma)
+		*dma = 0;
+	if (!sram_pool || (dma && !dma_base))
+		return NULL;
+
+	vaddr = gen_pool_alloc(sram_pool, len);
+	if (!vaddr)
+		return NULL;
+
+	if (dma)
+		*dma = dma_base + (vaddr - SRAM_VIRT);
+	return (void *)vaddr;
+
+}
+EXPORT_SYMBOL(sram_alloc);
+
+void sram_free(void *addr, size_t len)
+{
+	gen_pool_free(sram_pool, (unsigned long) addr, len);
+}
+EXPORT_SYMBOL(sram_free);
+
+
+/*
+ * REVISIT This supports CPU and DMA access to/from SRAM, but it
+ * doesn't (yet?) support some other notable uses of SRAM:  as TCM
+ * for data and/or instructions; and holding code needed to enter
+ * and exit suspend states (while DRAM can't be used).
+ */
+static int __init sram_init(void)
+{
+	unsigned len = davinci_soc_info.sram_len;
+	int status = 0;
+
+	if (len) {
+		len = min(len, SRAM_SIZE);
+		sram_pool = gen_pool_create(ilog2(SRAM_GRANULARITY), -1);
+		if (!sram_pool)
+			status = -ENOMEM;
+	}
+	if (sram_pool)
+		status = gen_pool_add(sram_pool, SRAM_VIRT, len, -1);
+	WARN_ON(status < 0);
+	return status;
+}
+core_initcall(sram_init);
+
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
index 494e01b..0884ca5 100644
--- a/arch/arm/mach-davinci/time.c
+++ b/arch/arm/mach-davinci/time.c
@@ -19,6 +19,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/device.h>
+#include <linux/platform_device.h>
 
 #include <mach/hardware.h>
 #include <asm/system.h>
@@ -28,52 +29,41 @@
 #include <asm/errno.h>
 #include <mach/io.h>
 #include <mach/cputype.h>
+#include <mach/time.h>
 #include "clock.h"
 
 static struct clock_event_device clockevent_davinci;
 static unsigned int davinci_clock_tick_rate;
 
-#define DAVINCI_TIMER0_BASE (IO_PHYS + 0x21400)
-#define DAVINCI_TIMER1_BASE (IO_PHYS + 0x21800)
-#define DAVINCI_WDOG_BASE   (IO_PHYS + 0x21C00)
-
-enum {
-	T0_BOT = 0, T0_TOP, T1_BOT, T1_TOP, NUM_TIMERS,
-};
-
-#define IS_TIMER1(id)    (id & 0x2)
-#define IS_TIMER0(id)    (!IS_TIMER1(id))
-#define IS_TIMER_TOP(id) ((id & 0x1))
-#define IS_TIMER_BOT(id) (!IS_TIMER_TOP(id))
-
-static int timer_irqs[NUM_TIMERS] = {
-	IRQ_TINT0_TINT12,
-	IRQ_TINT0_TINT34,
-	IRQ_TINT1_TINT12,
-	IRQ_TINT1_TINT34,
-};
-
 /*
  * This driver configures the 2 64-bit count-up timers as 4 independent
  * 32-bit count-up timers used as follows:
- *
- * T0_BOT: Timer 0, bottom:  clockevent source for hrtimers
- * T0_TOP: Timer 0, top   :  clocksource for generic timekeeping
- * T1_BOT: Timer 1, bottom:  (used by DSP in TI DSPLink code)
- * T1_TOP: Timer 1, top   :  <unused>
  */
-#define TID_CLOCKEVENT  T0_BOT
-#define TID_CLOCKSOURCE T0_TOP
+
+enum {
+	TID_CLOCKEVENT,
+	TID_CLOCKSOURCE,
+};
 
 /* Timer register offsets */
-#define PID12                        0x0
-#define TIM12                        0x10
-#define TIM34                        0x14
-#define PRD12                        0x18
-#define PRD34                        0x1c
-#define TCR                          0x20
-#define TGCR                         0x24
-#define WDTCR                        0x28
+#define PID12			0x0
+#define TIM12			0x10
+#define TIM34			0x14
+#define PRD12			0x18
+#define PRD34			0x1c
+#define TCR			0x20
+#define TGCR			0x24
+#define WDTCR			0x28
+
+/* Offsets of the 8 compare registers */
+#define	CMP12_0			0x60
+#define	CMP12_1			0x64
+#define	CMP12_2			0x68
+#define	CMP12_3			0x6c
+#define	CMP12_4			0x70
+#define	CMP12_5			0x74
+#define	CMP12_6			0x78
+#define	CMP12_7			0x7c
 
 /* Timer register bitfields */
 #define TCR_ENAMODE_DISABLE          0x0
@@ -105,6 +95,7 @@
 	unsigned int id;
 	unsigned long period;
 	unsigned long opts;
+	unsigned long flags;
 	void __iomem *base;
 	unsigned long tim_off;
 	unsigned long prd_off;
@@ -114,30 +105,58 @@
 static struct timer_s timers[];
 
 /* values for 'opts' field of struct timer_s */
-#define TIMER_OPTS_DISABLED   0x00
-#define TIMER_OPTS_ONESHOT    0x01
-#define TIMER_OPTS_PERIODIC   0x02
+#define TIMER_OPTS_DISABLED		0x01
+#define TIMER_OPTS_ONESHOT		0x02
+#define TIMER_OPTS_PERIODIC		0x04
+#define TIMER_OPTS_STATE_MASK		0x07
+
+#define TIMER_OPTS_USE_COMPARE		0x80000000
+#define USING_COMPARE(t)		((t)->opts & TIMER_OPTS_USE_COMPARE)
+
+static char *id_to_name[] = {
+	[T0_BOT]	= "timer0_0",
+	[T0_TOP]	= "timer0_1",
+	[T1_BOT]	= "timer1_0",
+	[T1_TOP]	= "timer1_1",
+};
 
 static int timer32_config(struct timer_s *t)
 {
-	u32 tcr = __raw_readl(t->base + TCR);
+	u32 tcr;
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
 
-	/* disable timer */
-	tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift);
-	__raw_writel(tcr, t->base + TCR);
+	if (USING_COMPARE(t)) {
+		struct davinci_timer_instance *dtip =
+				soc_info->timer_info->timers;
+		int event_timer = ID_TO_TIMER(timers[TID_CLOCKEVENT].id);
 
-	/* reset counter to zero, set new period */
-	__raw_writel(0, t->base + t->tim_off);
-	__raw_writel(t->period, t->base + t->prd_off);
+		/*
+		 * Next interrupt should be the current time reg value plus
+		 * the new period (using 32-bit unsigned addition/wrapping
+		 * to 0 on overflow).  This assumes that the clocksource
+		 * is setup to count to 2^32-1 before wrapping around to 0.
+		 */
+		__raw_writel(__raw_readl(t->base + t->tim_off) + t->period,
+			t->base + dtip[event_timer].cmp_off);
+	} else {
+		tcr = __raw_readl(t->base + TCR);
 
-	/* Set enable mode */
-	if (t->opts & TIMER_OPTS_ONESHOT) {
-		tcr |= TCR_ENAMODE_ONESHOT << t->enamode_shift;
-	} else if (t->opts & TIMER_OPTS_PERIODIC) {
-		tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift;
+		/* disable timer */
+		tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift);
+		__raw_writel(tcr, t->base + TCR);
+
+		/* reset counter to zero, set new period */
+		__raw_writel(0, t->base + t->tim_off);
+		__raw_writel(t->period, t->base + t->prd_off);
+
+		/* Set enable mode */
+		if (t->opts & TIMER_OPTS_ONESHOT)
+			tcr |= TCR_ENAMODE_ONESHOT << t->enamode_shift;
+		else if (t->opts & TIMER_OPTS_PERIODIC)
+			tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift;
+
+		__raw_writel(tcr, t->base + TCR);
 	}
-
-	__raw_writel(tcr, t->base + TCR);
 	return 0;
 }
 
@@ -182,13 +201,14 @@
 
 static void __init timer_init(void)
 {
-	u32 phys_bases[] = {DAVINCI_TIMER0_BASE, DAVINCI_TIMER1_BASE};
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
+	struct davinci_timer_instance *dtip = soc_info->timer_info->timers;
 	int i;
 
 	/* Global init of each 64-bit timer as a whole */
 	for(i=0; i<2; i++) {
 		u32 tgcr;
-		void __iomem *base = IO_ADDRESS(phys_bases[i]);
+		void __iomem *base = dtip[i].base;
 
 		/* Disabled, Internal clock source */
 		__raw_writel(0, base + TCR);
@@ -214,33 +234,33 @@
 	/* Init of each timer as a 32-bit timer */
 	for (i=0; i< ARRAY_SIZE(timers); i++) {
 		struct timer_s *t = &timers[i];
-		u32 phys_base;
+		int timer = ID_TO_TIMER(t->id);
+		u32 irq;
 
-		if (t->name) {
-			t->id = i;
-			phys_base = (IS_TIMER1(t->id) ?
-			       DAVINCI_TIMER1_BASE : DAVINCI_TIMER0_BASE);
-			t->base = IO_ADDRESS(phys_base);
+		t->base = dtip[timer].base;
 
-			if (IS_TIMER_BOT(t->id)) {
-				t->enamode_shift = 6;
-				t->tim_off = TIM12;
-				t->prd_off = PRD12;
-			} else {
-				t->enamode_shift = 22;
-				t->tim_off = TIM34;
-				t->prd_off = PRD34;
-			}
-
-			/* Register interrupt */
-			t->irqaction.name = t->name;
-			t->irqaction.dev_id = (void *)t;
-			if (t->irqaction.handler != NULL) {
-				setup_irq(timer_irqs[t->id], &t->irqaction);
-			}
-
-			timer32_config(&timers[i]);
+		if (IS_TIMER_BOT(t->id)) {
+			t->enamode_shift = 6;
+			t->tim_off = TIM12;
+			t->prd_off = PRD12;
+			irq = dtip[timer].bottom_irq;
+		} else {
+			t->enamode_shift = 22;
+			t->tim_off = TIM34;
+			t->prd_off = PRD34;
+			irq = dtip[timer].top_irq;
 		}
+
+		/* Register interrupt */
+		t->irqaction.name = t->name;
+		t->irqaction.dev_id = (void *)t;
+
+		if (t->irqaction.handler != NULL) {
+			irq = USING_COMPARE(t) ? dtip[i].cmp_irq : irq;
+			setup_irq(irq, &t->irqaction);
+		}
+
+		timer32_config(&timers[i]);
 	}
 }
 
@@ -255,7 +275,6 @@
 }
 
 static struct clocksource clocksource_davinci = {
-	.name		= "timer0_1",
 	.rating		= 300,
 	.read		= read_cycles,
 	.mask		= CLOCKSOURCE_MASK(32),
@@ -284,15 +303,18 @@
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC:
 		t->period = davinci_clock_tick_rate / (HZ);
-		t->opts = TIMER_OPTS_PERIODIC;
+		t->opts &= ~TIMER_OPTS_STATE_MASK;
+		t->opts |= TIMER_OPTS_PERIODIC;
 		timer32_config(t);
 		break;
 	case CLOCK_EVT_MODE_ONESHOT:
-		t->opts = TIMER_OPTS_ONESHOT;
+		t->opts &= ~TIMER_OPTS_STATE_MASK;
+		t->opts |= TIMER_OPTS_ONESHOT;
 		break;
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
-		t->opts = TIMER_OPTS_DISABLED;
+		t->opts &= ~TIMER_OPTS_STATE_MASK;
+		t->opts |= TIMER_OPTS_DISABLED;
 		break;
 	case CLOCK_EVT_MODE_RESUME:
 		break;
@@ -300,7 +322,6 @@
 }
 
 static struct clock_event_device clockevent_davinci = {
-	.name		= "timer0_0",
 	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 	.shift		= 32,
 	.set_next_event	= davinci_set_next_event,
@@ -311,10 +332,42 @@
 static void __init davinci_timer_init(void)
 {
 	struct clk *timer_clk;
-
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
+	unsigned int clockevent_id;
+	unsigned int clocksource_id;
 	static char err[] __initdata = KERN_ERR
 		"%s: can't register clocksource!\n";
 
+	clockevent_id = soc_info->timer_info->clockevent_id;
+	clocksource_id = soc_info->timer_info->clocksource_id;
+
+	timers[TID_CLOCKEVENT].id = clockevent_id;
+	timers[TID_CLOCKSOURCE].id = clocksource_id;
+
+	/*
+	 * If using same timer for both clock events & clocksource,
+	 * a compare register must be used to generate an event interrupt.
+	 * This is equivalent to a oneshot timer only (not periodic).
+	 */
+	if (clockevent_id == clocksource_id) {
+		struct davinci_timer_instance *dtip =
+				soc_info->timer_info->timers;
+		int event_timer = ID_TO_TIMER(clockevent_id);
+
+		/* Only bottom timers can use compare regs */
+		if (IS_TIMER_TOP(clockevent_id))
+			pr_warning("davinci_timer_init: Invalid use"
+				" of system timers.  Results unpredictable.\n");
+		else if ((dtip[event_timer].cmp_off == 0)
+				|| (dtip[event_timer].cmp_irq == 0))
+			pr_warning("davinci_timer_init:  Invalid timer instance"
+				" setup.  Results unpredictable.\n");
+		else {
+			timers[TID_CLOCKEVENT].opts |= TIMER_OPTS_USE_COMPARE;
+			clockevent_davinci.features = CLOCK_EVT_FEAT_ONESHOT;
+		}
+	}
+
 	/* init timer hw */
 	timer_init();
 
@@ -325,6 +378,7 @@
 	davinci_clock_tick_rate = clk_get_rate(timer_clk);
 
 	/* setup clocksource */
+	clocksource_davinci.name = id_to_name[clocksource_id];
 	clocksource_davinci.mult =
 		clocksource_khz2mult(davinci_clock_tick_rate/1000,
 				     clocksource_davinci.shift);
@@ -332,12 +386,12 @@
 		printk(err, clocksource_davinci.name);
 
 	/* setup clockevent */
+	clockevent_davinci.name = id_to_name[timers[TID_CLOCKEVENT].id];
 	clockevent_davinci.mult = div_sc(davinci_clock_tick_rate, NSEC_PER_SEC,
 					 clockevent_davinci.shift);
 	clockevent_davinci.max_delta_ns =
 		clockevent_delta2ns(0xfffffffe, &clockevent_davinci);
-	clockevent_davinci.min_delta_ns =
-		clockevent_delta2ns(1, &clockevent_davinci);
+	clockevent_davinci.min_delta_ns = 50000; /* 50 usec */
 
 	clockevent_davinci.cpumask = cpumask_of(0);
 	clockevents_register_device(&clockevent_davinci);
@@ -349,15 +403,14 @@
 
 
 /* reset board using watchdog timer */
-void davinci_watchdog_reset(void) {
+void davinci_watchdog_reset(void)
+{
 	u32 tgcr, wdtcr;
-	void __iomem *base = IO_ADDRESS(DAVINCI_WDOG_BASE);
-	struct device dev;
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
+	void __iomem *base = soc_info->wdt_base;
 	struct clk *wd_clk;
-	char *name = "watchdog";
 
-	dev_set_name(&dev, name);
-	wd_clk = clk_get(&dev, NULL);
+	wd_clk = clk_get(&davinci_wdt_device.dev, NULL);
 	if (WARN_ON(IS_ERR(wd_clk)))
 		return;
 	clk_enable(wd_clk);
diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig
index 56bddce..d7291c6 100644
--- a/arch/arm/mach-ep93xx/Kconfig
+++ b/arch/arm/mach-ep93xx/Kconfig
@@ -9,87 +9,135 @@
 
 comment "EP93xx Platforms"
 
+choice
+	prompt "EP93xx first SDRAM bank selection"
+	default EP93XX_SDCE3_SYNC_PHYS_OFFSET
+
+config EP93XX_SDCE3_SYNC_PHYS_OFFSET
+	bool "0x00000000 - SDCE3/SyncBoot"
+	help
+	  Select this option if you want support for EP93xx boards with the
+	  first SDRAM bank at 0x00000000
+
+config EP93XX_SDCE0_PHYS_OFFSET
+	bool "0xc0000000 - SDCEO"
+	help
+	  Select this option if you want support for EP93xx boards with the
+	  first SDRAM bank at 0xc0000000
+
+endchoice
+
 config MACH_ADSSPHERE
 	bool "Support ADS Sphere"
+	depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
 	help
 	  Say 'Y' here if you want your kernel to support the ADS
 	  Sphere board.
 
+config MACH_EDB93XX
+	bool
+
+config MACH_EDB9301
+	bool "Support Cirrus Logic EDB9301"
+	depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+	select MACH_EDB93XX
+	help
+	  Say 'Y' here if you want your kernel to support the Cirrus
+	  Logic EDB9301 Evaluation Board.
+
 config MACH_EDB9302
 	bool "Support Cirrus Logic EDB9302"
+	depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+	select MACH_EDB93XX
 	help
 	  Say 'Y' here if you want your kernel to support the Cirrus
 	  Logic EDB9302 Evaluation Board.
 
 config MACH_EDB9302A
 	bool "Support Cirrus Logic EDB9302A"
+	depends on EP93XX_SDCE0_PHYS_OFFSET
+	select MACH_EDB93XX
 	help
 	  Say 'Y' here if you want your kernel to support the Cirrus
 	  Logic EDB9302A Evaluation Board.
 
 config MACH_EDB9307
 	bool "Support Cirrus Logic EDB9307"
+	depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+	select MACH_EDB93XX
 	help
 	  Say 'Y' here if you want your kernel to support the Cirrus
 	  Logic EDB9307 Evaluation Board.
 
 config MACH_EDB9307A
 	bool "Support Cirrus Logic EDB9307A"
+	depends on EP93XX_SDCE0_PHYS_OFFSET
+	select MACH_EDB93XX
 	help
 	  Say 'Y' here if you want your kernel to support the Cirrus
 	  Logic EDB9307A Evaluation Board.
 
 config MACH_EDB9312
 	bool "Support Cirrus Logic EDB9312"
+	depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+	select MACH_EDB93XX
 	help
 	  Say 'Y' here if you want your kernel to support the Cirrus
 	  Logic EDB9312 Evaluation Board.
 
 config MACH_EDB9315
 	bool "Support Cirrus Logic EDB9315"
+	depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+	select MACH_EDB93XX
 	help
 	  Say 'Y' here if you want your kernel to support the Cirrus
 	  Logic EDB9315 Evaluation Board.
 
 config MACH_EDB9315A
 	bool "Support Cirrus Logic EDB9315A"
+	depends on EP93XX_SDCE0_PHYS_OFFSET
+	select MACH_EDB93XX
 	help
 	  Say 'Y' here if you want your kernel to support the Cirrus
 	  Logic EDB9315A Evaluation Board.
 
 config MACH_GESBC9312
+	depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
 	bool "Support Glomation GESBC-9312-sx"
 	help
 	  Say 'Y' here if you want your kernel to support the Glomation
 	  GESBC-9312-sx board.
 
 config MACH_MICRO9
-        bool
-        default n
+	bool
 
 config MACH_MICRO9H
-       bool "Support Contec Hypercontrol Micro9-H"
-       select MACH_MICRO9
-       help
-         Say 'Y' here if you want your kernel to support the
-         Contec Hypercontrol Micro9-H board.
+	bool "Support Contec Hypercontrol Micro9-H"
+	depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+	select MACH_MICRO9
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Contec Hypercontrol Micro9-H board.
 
 config MACH_MICRO9M
-       bool "Support Contec Hypercontrol Micro9-M"
-       select MACH_MICRO9
-       help
-         Say 'Y' here if you want your kernel to support the
-         Contec Hypercontrol Micro9-M board.
+	bool "Support Contec Hypercontrol Micro9-M"
+	depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+	select MACH_MICRO9
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Contec Hypercontrol Micro9-M board.
 
 config MACH_MICRO9L
-       bool "Support Contec Hypercontrol Micro9-L"
-       select MACH_MICRO9
-       help
-         Say 'Y' here if you want your kernel to support the
-         Contec Hypercontrol Micro9-L board.
+	bool "Support Contec Hypercontrol Micro9-L"
+	depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+	select MACH_MICRO9
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Contec Hypercontrol Micro9-L board.
 
 config MACH_TS72XX
 	bool "Support Technologic Systems TS-72xx SBC"
+	depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
 	help
 	  Say 'Y' here if you want your kernel to support the
 	  Technologic Systems TS-72xx board.
diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile
index 9522e20..eae6199 100644
--- a/arch/arm/mach-ep93xx/Makefile
+++ b/arch/arm/mach-ep93xx/Makefile
@@ -7,13 +7,7 @@
 obj-			:=
 
 obj-$(CONFIG_MACH_ADSSPHERE)	+= adssphere.o
-obj-$(CONFIG_MACH_EDB9302)	+= edb9302.o
-obj-$(CONFIG_MACH_EDB9302A)	+= edb9302a.o
-obj-$(CONFIG_MACH_EDB9307)	+= edb9307.o
-obj-$(CONFIG_MACH_EDB9307A)	+= edb9307a.o
-obj-$(CONFIG_MACH_EDB9312)	+= edb9312.o
-obj-$(CONFIG_MACH_EDB9315)	+= edb9315.o
-obj-$(CONFIG_MACH_EDB9315A)	+= edb9315a.o
+obj-$(CONFIG_MACH_EDB93XX)	+= edb93xx.o
 obj-$(CONFIG_MACH_GESBC9312)	+= gesbc9312.o
 obj-$(CONFIG_MACH_MICRO9)	+= micro9.o
 obj-$(CONFIG_MACH_TS72XX)	+= ts72xx.o
diff --git a/arch/arm/mach-ep93xx/Makefile.boot b/arch/arm/mach-ep93xx/Makefile.boot
index d5561ad..27a085a 100644
--- a/arch/arm/mach-ep93xx/Makefile.boot
+++ b/arch/arm/mach-ep93xx/Makefile.boot
@@ -1,2 +1,5 @@
-   zreladdr-y	:= 0x00008000
-params_phys-y	:= 0x00000100
+   zreladdr-$(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET)	:= 0x00008000
+params_phys-$(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET)	:= 0x00000100
+
+   zreladdr-$(CONFIG_EP93XX_SDCE0_PHYS_OFFSET)		:= 0xc0008000
+params_phys-$(CONFIG_EP93XX_SDCE0_PHYS_OFFSET)		:= 0xc0000100
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index b2eede5..6c4c163 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -72,58 +72,58 @@
 static struct clk clk_p;
 static struct clk clk_pll2;
 static struct clk clk_usb_host = {
-	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL,
-	.enable_mask	= EP93XX_SYSCON_CLOCK_USH_EN,
+	.enable_reg	= EP93XX_SYSCON_PWRCNT,
+	.enable_mask	= EP93XX_SYSCON_PWRCNT_USH_EN,
 };
 
 /* DMA Clocks */
 static struct clk clk_m2p0 = {
-	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL,
-	.enable_mask	= 0x00020000,
+	.enable_reg	= EP93XX_SYSCON_PWRCNT,
+	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P0,
 };
 static struct clk clk_m2p1 = {
-	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL,
-	.enable_mask	= 0x00010000,
+	.enable_reg	= EP93XX_SYSCON_PWRCNT,
+	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P1,
 };
 static struct clk clk_m2p2 = {
-	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL,
-	.enable_mask	= 0x00080000,
+	.enable_reg	= EP93XX_SYSCON_PWRCNT,
+	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P2,
 };
 static struct clk clk_m2p3 = {
-	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL,
-	.enable_mask	= 0x00040000,
+	.enable_reg	= EP93XX_SYSCON_PWRCNT,
+	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P3,
 };
 static struct clk clk_m2p4 = {
-	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL,
-	.enable_mask	= 0x00200000,
+	.enable_reg	= EP93XX_SYSCON_PWRCNT,
+	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P4,
 };
 static struct clk clk_m2p5 = {
-	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL,
-	.enable_mask	= 0x00100000,
+	.enable_reg	= EP93XX_SYSCON_PWRCNT,
+	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P5,
 };
 static struct clk clk_m2p6 = {
-	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL,
-	.enable_mask	= 0x00800000,
+	.enable_reg	= EP93XX_SYSCON_PWRCNT,
+	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P6,
 };
 static struct clk clk_m2p7 = {
-	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL,
-	.enable_mask	= 0x00400000,
+	.enable_reg	= EP93XX_SYSCON_PWRCNT,
+	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P7,
 };
 static struct clk clk_m2p8 = {
-	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL,
-	.enable_mask	= 0x02000000,
+	.enable_reg	= EP93XX_SYSCON_PWRCNT,
+	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P8,
 };
 static struct clk clk_m2p9 = {
-	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL,
-	.enable_mask	= 0x01000000,
+	.enable_reg	= EP93XX_SYSCON_PWRCNT,
+	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P9,
 };
 static struct clk clk_m2m0 = {
-	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL,
-	.enable_mask	= 0x04000000,
+	.enable_reg	= EP93XX_SYSCON_PWRCNT,
+	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2M0,
 };
 static struct clk clk_m2m1 = {
-	.enable_reg	= EP93XX_SYSCON_CLOCK_CONTROL,
-	.enable_mask	= 0x08000000,
+	.enable_reg	= EP93XX_SYSCON_PWRCNT,
+	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2M1,
 };
 
 #define INIT_CK(dev,con,ck)					\
@@ -138,7 +138,7 @@
 	INIT_CK(NULL, "hclk", &clk_h),
 	INIT_CK(NULL, "pclk", &clk_p),
 	INIT_CK(NULL, "pll2", &clk_pll2),
-	INIT_CK(NULL, "usb_host", &clk_usb_host),
+	INIT_CK("ep93xx-ohci", NULL, &clk_usb_host),
 	INIT_CK(NULL, "m2p0", &clk_m2p0),
 	INIT_CK(NULL, "m2p1", &clk_m2p1),
 	INIT_CK(NULL, "m2p2", &clk_m2p2),
@@ -186,8 +186,8 @@
 {
 	u32 value;
 
-	value = __raw_readl(EP93XX_SYSCON_CLOCK_CONTROL);
-	if (value & EP93XX_SYSCON_CLOCK_UARTBAUD)
+	value = __raw_readl(EP93XX_SYSCON_PWRCNT);
+	if (value & EP93XX_SYSCON_PWRCNT_UARTBAUD)
 		return EP93XX_EXT_CLK_RATE;
 	else
 		return EP93XX_EXT_CLK_RATE / 2;
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index ae24486..204dc5c 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -155,7 +155,7 @@
 static unsigned char gpio_int_enabled[3];
 static unsigned char gpio_int_type1[3];
 static unsigned char gpio_int_type2[3];
-static unsigned char gpio_int_debouce[3];
+static unsigned char gpio_int_debounce[3];
 
 /* Port ordering is: A B F */
 static const u8 int_type1_register_offset[3]	= { 0x90, 0xac, 0x4c };
@@ -192,11 +192,11 @@
 	int port_mask = 1 << (line & 7);
 
 	if (enable)
-		gpio_int_debouce[port] |= port_mask;
+		gpio_int_debounce[port] |= port_mask;
 	else
-		gpio_int_debouce[port] &= ~port_mask;
+		gpio_int_debounce[port] &= ~port_mask;
 
-	__raw_writeb(gpio_int_debouce[port],
+	__raw_writeb(gpio_int_debounce[port],
 		EP93XX_GPIO_REG(int_debounce_register_offset[port]));
 }
 EXPORT_SYMBOL(ep93xx_gpio_int_debounce);
@@ -362,8 +362,8 @@
 {
 	int gpio_irq;
 
-	vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK);
-	vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK);
+	vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0);
+	vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0);
 
 	for (gpio_irq = gpio_to_irq(0);
 	     gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) {
@@ -450,10 +450,19 @@
 };
 
 
+static struct resource ep93xx_rtc_resource[] = {
+	{
+		.start		= EP93XX_RTC_PHYS_BASE,
+		.end		= EP93XX_RTC_PHYS_BASE + 0x10c - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
 static struct platform_device ep93xx_rtc_device = {
-       .name           = "ep93xx-rtc",
-       .id             = -1,
-       .num_resources  = 0,
+	.name		= "ep93xx-rtc",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(ep93xx_rtc_resource),
+	.resource	= ep93xx_rtc_resource,
 };
 
 
diff --git a/arch/arm/mach-ep93xx/edb9302.c b/arch/arm/mach-ep93xx/edb9302.c
deleted file mode 100644
index 8bf8d7c..0000000
--- a/arch/arm/mach-ep93xx/edb9302.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/edb9302.c
- * Cirrus Logic EDB9302 support.
- *
- * Copyright (C) 2006 George Kashperko <george@chas.com.ua>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-static struct physmap_flash_data edb9302_flash_data = {
-	.width		= 2,
-};
-
-static struct resource edb9302_flash_resource = {
-	.start		= EP93XX_CS6_PHYS_BASE,
-	.end		= EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device edb9302_flash = {
-	.name		= "physmap-flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data	= &edb9302_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &edb9302_flash_resource,
-};
-
-static struct ep93xx_eth_data edb9302_eth_data = {
-	.phy_id		= 1,
-};
-
-static void __init edb9302_init_machine(void)
-{
-	ep93xx_init_devices();
-	platform_device_register(&edb9302_flash);
-
-	ep93xx_register_eth(&edb9302_eth_data, 1);
-}
-
-MACHINE_START(EDB9302, "Cirrus Logic EDB9302 Evaluation Board")
-	/* Maintainer: George Kashperko <george@chas.com.ua> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
-	.map_io		= ep93xx_map_io,
-	.init_irq	= ep93xx_init_irq,
-	.timer		= &ep93xx_timer,
-	.init_machine	= edb9302_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb9302a.c b/arch/arm/mach-ep93xx/edb9302a.c
deleted file mode 100644
index a352c57..0000000
--- a/arch/arm/mach-ep93xx/edb9302a.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/edb9302a.c
- * Cirrus Logic EDB9302A support.
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-static struct physmap_flash_data edb9302a_flash_data = {
-	.width		= 2,
-};
-
-static struct resource edb9302a_flash_resource = {
-	.start		= EP93XX_CS6_PHYS_BASE,
-	.end		= EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device edb9302a_flash = {
-	.name		= "physmap-flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data	= &edb9302a_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &edb9302a_flash_resource,
-};
-
-static struct ep93xx_eth_data edb9302a_eth_data = {
-	.phy_id		= 1,
-};
-
-static void __init edb9302a_init_machine(void)
-{
-	ep93xx_init_devices();
-	platform_device_register(&edb9302a_flash);
-
-	ep93xx_register_eth(&edb9302a_eth_data, 1);
-}
-
-MACHINE_START(EDB9302A, "Cirrus Logic EDB9302A Evaluation Board")
-	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-	.boot_params	= EP93XX_SDCE0_PHYS_BASE + 0x100,
-	.map_io		= ep93xx_map_io,
-	.init_irq	= ep93xx_init_irq,
-	.timer		= &ep93xx_timer,
-	.init_machine	= edb9302a_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb9307.c b/arch/arm/mach-ep93xx/edb9307.c
deleted file mode 100644
index 5ab22f6..0000000
--- a/arch/arm/mach-ep93xx/edb9307.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/edb9307.c
- * Cirrus Logic EDB9307 support.
- *
- * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-static struct physmap_flash_data edb9307_flash_data = {
-	.width		= 4,
-};
-
-static struct resource edb9307_flash_resource = {
-	.start		= EP93XX_CS6_PHYS_BASE,
-	.end		= EP93XX_CS6_PHYS_BASE + SZ_32M - 1,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device edb9307_flash = {
-	.name		= "physmap-flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data	= &edb9307_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &edb9307_flash_resource,
-};
-
-static struct ep93xx_eth_data edb9307_eth_data = {
-	.phy_id		= 1,
-};
-
-static void __init edb9307_init_machine(void)
-{
-	ep93xx_init_devices();
-	platform_device_register(&edb9307_flash);
-
-	ep93xx_register_eth(&edb9307_eth_data, 1);
-}
-
-MACHINE_START(EDB9307, "Cirrus Logic EDB9307 Evaluation Board")
-	/* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
-	.map_io		= ep93xx_map_io,
-	.init_irq	= ep93xx_init_irq,
-	.timer		= &ep93xx_timer,
-	.init_machine	= edb9307_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb9307a.c b/arch/arm/mach-ep93xx/edb9307a.c
deleted file mode 100644
index 6171167..0000000
--- a/arch/arm/mach-ep93xx/edb9307a.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/edb9307a.c
- * Cirrus Logic EDB9307A support.
- *
- * Copyright (C) 2008 H Hartley Sweeten <hsweeten@visionengravers.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-static struct physmap_flash_data edb9307a_flash_data = {
-	.width		= 2,
-};
-
-static struct resource edb9307a_flash_resource = {
-	.start		= EP93XX_CS6_PHYS_BASE,
-	.end		= EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device edb9307a_flash = {
-	.name		= "physmap-flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data	= &edb9307a_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &edb9307a_flash_resource,
-};
-
-static struct ep93xx_eth_data edb9307a_eth_data = {
-	.phy_id		= 1,
-};
-
-static struct i2c_board_info __initdata edb9307a_i2c_data[] = {
-	{
-		/* On-board battery backed RTC */
-		I2C_BOARD_INFO("isl1208", 0x6f),
-	},
-	/*
-	 * The I2C signals are also routed to the Expansion Connector (J4)
-	 */
-};
-
-static void __init edb9307a_init_machine(void)
-{
-	ep93xx_init_devices();
-	platform_device_register(&edb9307a_flash);
-
-	ep93xx_register_eth(&edb9307a_eth_data, 1);
-
-	ep93xx_init_i2c(edb9307a_i2c_data, ARRAY_SIZE(edb9307a_i2c_data));
-}
-
-MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board")
-	/* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-	.boot_params	= EP93XX_SDCE0_PHYS_BASE + 0x100,
-	.map_io		= ep93xx_map_io,
-	.init_irq	= ep93xx_init_irq,
-	.timer		= &ep93xx_timer,
-	.init_machine	= edb9307a_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb9312.c b/arch/arm/mach-ep93xx/edb9312.c
deleted file mode 100644
index d7179f6..0000000
--- a/arch/arm/mach-ep93xx/edb9312.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/edb9312.c
- * Cirrus Logic EDB9312 support.
- *
- * Copyright (C) 2006 Infosys Technologies Limited
- * 	Toufeeq Hussain	<toufeeq_hussain@infosys.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-static struct physmap_flash_data edb9312_flash_data = {
-	.width		= 4,
-};
-
-static struct resource edb9312_flash_resource = {
-	.start		= EP93XX_CS6_PHYS_BASE,
-	.end		= EP93XX_CS6_PHYS_BASE + SZ_32M - 1,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device edb9312_flash = {
-	.name		= "physmap-flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data	= &edb9312_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &edb9312_flash_resource,
-};
-
-static struct ep93xx_eth_data edb9312_eth_data = {
-	.phy_id		= 1,
-};
-
-static void __init edb9312_init_machine(void)
-{
-	ep93xx_init_devices();
-	platform_device_register(&edb9312_flash);
-
-	ep93xx_register_eth(&edb9312_eth_data, 1);
-}
-
-MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board")
-	/* Maintainer: Toufeeq Hussain <toufeeq_hussain@infosys.com> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
-	.map_io		= ep93xx_map_io,
-	.init_irq	= ep93xx_init_irq,
-	.timer		= &ep93xx_timer,
-	.init_machine	= edb9312_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb9315.c b/arch/arm/mach-ep93xx/edb9315.c
deleted file mode 100644
index 025af6e..0000000
--- a/arch/arm/mach-ep93xx/edb9315.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/edb9315.c
- * Cirrus Logic EDB9315 support.
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-static struct physmap_flash_data edb9315_flash_data = {
-	.width		= 4,
-};
-
-static struct resource edb9315_flash_resource = {
-	.start		= EP93XX_CS6_PHYS_BASE,
-	.end		= EP93XX_CS6_PHYS_BASE + SZ_32M - 1,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device edb9315_flash = {
-	.name		= "physmap-flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data	= &edb9315_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &edb9315_flash_resource,
-};
-
-static struct ep93xx_eth_data edb9315_eth_data = {
-	.phy_id		= 1,
-};
-
-static void __init edb9315_init_machine(void)
-{
-	ep93xx_init_devices();
-	platform_device_register(&edb9315_flash);
-
-	ep93xx_register_eth(&edb9315_eth_data, 1);
-}
-
-MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board")
-	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
-	.map_io		= ep93xx_map_io,
-	.init_irq	= ep93xx_init_irq,
-	.timer		= &ep93xx_timer,
-	.init_machine	= edb9315_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb9315a.c b/arch/arm/mach-ep93xx/edb9315a.c
deleted file mode 100644
index 4c9cc8a..0000000
--- a/arch/arm/mach-ep93xx/edb9315a.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/edb9315a.c
- * Cirrus Logic EDB9315A support.
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-static struct physmap_flash_data edb9315a_flash_data = {
-	.width		= 2,
-};
-
-static struct resource edb9315a_flash_resource = {
-	.start		= EP93XX_CS6_PHYS_BASE,
-	.end		= EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device edb9315a_flash = {
-	.name		= "physmap-flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data	= &edb9315a_flash_data,
-	},
-	.num_resources	= 1,
-	.resource	= &edb9315a_flash_resource,
-};
-
-static struct ep93xx_eth_data edb9315a_eth_data = {
-	.phy_id		= 1,
-};
-
-static void __init edb9315a_init_machine(void)
-{
-	ep93xx_init_devices();
-	platform_device_register(&edb9315a_flash);
-
-	ep93xx_register_eth(&edb9315a_eth_data, 1);
-}
-
-MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board")
-	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-	.boot_params	= EP93XX_SDCE0_PHYS_BASE + 0x100,
-	.map_io		= ep93xx_map_io,
-	.init_irq	= ep93xx_init_irq,
-	.timer		= &ep93xx_timer,
-	.init_machine	= edb9315a_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c
new file mode 100644
index 0000000..e9e45b9
--- /dev/null
+++ b/arch/arm/mach-ep93xx/edb93xx.c
@@ -0,0 +1,217 @@
+/*
+ * arch/arm/mach-ep93xx/edb93xx.c
+ * Cirrus Logic EDB93xx Development Board support.
+ *
+ * EDB93XX, EDB9301, EDB9307A
+ * Copyright (C) 2008-2009 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *
+ * EDB9302
+ * Copyright (C) 2006 George Kashperko <george@chas.com.ua>
+ *
+ * EDB9302A, EDB9315, EDB9315A
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * EDB9307
+ * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * EDB9312
+ * Copyright (C) 2006 Infosys Technologies Limited
+ *                    Toufeeq Hussain <toufeeq_hussain@infosys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+static struct physmap_flash_data edb93xx_flash_data;
+
+static struct resource edb93xx_flash_resource = {
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device edb93xx_flash = {
+	.name		= "physmap-flash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &edb93xx_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &edb93xx_flash_resource,
+};
+
+static void __init __edb93xx_register_flash(unsigned int width,
+			resource_size_t start, resource_size_t size)
+{
+	edb93xx_flash_data.width	= width;
+	edb93xx_flash_resource.start	= start;
+	edb93xx_flash_resource.end	= start + size - 1;
+
+	platform_device_register(&edb93xx_flash);
+}
+
+static void __init edb93xx_register_flash(void)
+{
+	if (machine_is_edb9307() || machine_is_edb9312() ||
+	    machine_is_edb9315()) {
+		__edb93xx_register_flash(4, EP93XX_CS6_PHYS_BASE, SZ_32M);
+	} else {
+		__edb93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_16M);
+	}
+}
+
+static struct ep93xx_eth_data edb93xx_eth_data = {
+	.phy_id		= 1,
+};
+
+static struct i2c_board_info __initdata edb93xxa_i2c_data[] = {
+	{
+		I2C_BOARD_INFO("isl1208", 0x6f),
+	},
+};
+
+static struct i2c_board_info __initdata edb93xx_i2c_data[] = {
+	{
+		I2C_BOARD_INFO("ds1337", 0x68),
+	},
+};
+
+static void __init edb93xx_register_i2c(void)
+{
+	if (machine_is_edb9302a() || machine_is_edb9307a() ||
+	    machine_is_edb9315a()) {
+		ep93xx_register_i2c(edb93xxa_i2c_data,
+				ARRAY_SIZE(edb93xxa_i2c_data));
+	} else if (machine_is_edb9307() || machine_is_edb9312() ||
+		   machine_is_edb9315()) {
+		ep93xx_register_i2c(edb93xx_i2c_data,
+				ARRAY_SIZE(edb93xx_i2c_data));
+	}
+}
+
+static void __init edb93xx_init_machine(void)
+{
+	ep93xx_init_devices();
+	edb93xx_register_flash();
+	ep93xx_register_eth(&edb93xx_eth_data, 1);
+	edb93xx_register_i2c();
+}
+
+
+#ifdef CONFIG_MACH_EDB9301
+MACHINE_START(EDB9301, "Cirrus Logic EDB9301 Evaluation Board")
+	/* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */
+	.phys_io	= EP93XX_APB_PHYS_BASE,
+	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
+	.map_io		= ep93xx_map_io,
+	.init_irq	= ep93xx_init_irq,
+	.timer		= &ep93xx_timer,
+	.init_machine	= edb93xx_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_EDB9302
+MACHINE_START(EDB9302, "Cirrus Logic EDB9302 Evaluation Board")
+	/* Maintainer: George Kashperko <george@chas.com.ua> */
+	.phys_io	= EP93XX_APB_PHYS_BASE,
+	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
+	.map_io		= ep93xx_map_io,
+	.init_irq	= ep93xx_init_irq,
+	.timer		= &ep93xx_timer,
+	.init_machine	= edb93xx_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_EDB9302A
+MACHINE_START(EDB9302A, "Cirrus Logic EDB9302A Evaluation Board")
+	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
+	.phys_io	= EP93XX_APB_PHYS_BASE,
+	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= EP93XX_SDCE0_PHYS_BASE + 0x100,
+	.map_io		= ep93xx_map_io,
+	.init_irq	= ep93xx_init_irq,
+	.timer		= &ep93xx_timer,
+	.init_machine	= edb93xx_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_EDB9307
+MACHINE_START(EDB9307, "Cirrus Logic EDB9307 Evaluation Board")
+	/* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */
+	.phys_io	= EP93XX_APB_PHYS_BASE,
+	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
+	.map_io		= ep93xx_map_io,
+	.init_irq	= ep93xx_init_irq,
+	.timer		= &ep93xx_timer,
+	.init_machine	= edb93xx_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_EDB9307A
+MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board")
+	/* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */
+	.phys_io	= EP93XX_APB_PHYS_BASE,
+	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= EP93XX_SDCE0_PHYS_BASE + 0x100,
+	.map_io		= ep93xx_map_io,
+	.init_irq	= ep93xx_init_irq,
+	.timer		= &ep93xx_timer,
+	.init_machine	= edb93xx_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_EDB9312
+MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board")
+	/* Maintainer: Toufeeq Hussain <toufeeq_hussain@infosys.com> */
+	.phys_io	= EP93XX_APB_PHYS_BASE,
+	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
+	.map_io		= ep93xx_map_io,
+	.init_irq	= ep93xx_init_irq,
+	.timer		= &ep93xx_timer,
+	.init_machine	= edb93xx_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_EDB9315
+MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board")
+	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
+	.phys_io	= EP93XX_APB_PHYS_BASE,
+	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
+	.map_io		= ep93xx_map_io,
+	.init_irq	= ep93xx_init_irq,
+	.timer		= &ep93xx_timer,
+	.init_machine	= edb93xx_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_EDB9315A
+MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board")
+	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
+	.phys_io	= EP93XX_APB_PHYS_BASE,
+	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= EP93XX_SDCE0_PHYS_BASE + 0x100,
+	.map_io		= ep93xx_map_io,
+	.init_irq	= ep93xx_init_irq,
+	.timer		= &ep93xx_timer,
+	.init_machine	= edb93xx_init_machine,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index 1732de7..967c079 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -147,13 +147,27 @@
 #define EP93XX_PWM_BASE			(EP93XX_APB_VIRT_BASE + 0x00110000)
 
 #define EP93XX_RTC_BASE			(EP93XX_APB_VIRT_BASE + 0x00120000)
+#define EP93XX_RTC_PHYS_BASE		(EP93XX_APB_PHYS_BASE + 0x00120000)
 
 #define EP93XX_SYSCON_BASE		(EP93XX_APB_VIRT_BASE + 0x00130000)
 #define EP93XX_SYSCON_REG(x)		(EP93XX_SYSCON_BASE + (x))
 #define EP93XX_SYSCON_POWER_STATE	EP93XX_SYSCON_REG(0x00)
-#define EP93XX_SYSCON_CLOCK_CONTROL	EP93XX_SYSCON_REG(0x04)
-#define EP93XX_SYSCON_CLOCK_UARTBAUD	0x20000000
-#define EP93XX_SYSCON_CLOCK_USH_EN	0x10000000
+#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_CLOCK_SET1	EP93XX_SYSCON_REG(0x20)
diff --git a/arch/arm/mach-ep93xx/include/mach/memory.h b/arch/arm/mach-ep93xx/include/mach/memory.h
index 5c80c3c..925b12e 100644
--- a/arch/arm/mach-ep93xx/include/mach/memory.h
+++ b/arch/arm/mach-ep93xx/include/mach/memory.h
@@ -5,6 +5,12 @@
 #ifndef __ASM_ARCH_MEMORY_H
 #define __ASM_ARCH_MEMORY_H
 
+#if defined(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET)
 #define PHYS_OFFSET		UL(0x00000000)
+#elif defined(CONFIG_EP93XX_SDCE0_PHYS_OFFSET)
+#define PHYS_OFFSET		UL(0xc0000000)
+#else
+#error "Kconfig bug: No EP93xx PHYS_OFFSET set"
+#endif
 
 #endif
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
deleted file mode 100644
index cddd194..0000000
--- a/arch/arm/mach-imx/Kconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-menu "IMX Implementations"
-	depends on ARCH_IMX
-
-config ARCH_MX1ADS
-	bool "mx1ads"
-	depends on ARCH_IMX
-	select ISA
-	help
-	  Say Y here if you are using the Motorola MX1ADS board
-
-endmenu
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
deleted file mode 100644
index b047c7e..0000000
--- a/arch/arm/mach-imx/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-# Object file lists.
-
-obj-y			+= irq.o time.o dma.o generic.o clock.o
-
-obj-$(CONFIG_CPU_FREQ_IMX)	+= cpufreq.o
-
-# Specific board support
-obj-$(CONFIG_ARCH_MX1ADS) += mx1ads.o
-
-# Support for blinky lights
-led-y := leds.o
-
-obj-$(CONFIG_LEDS)	+=  $(led-y)
-led-$(CONFIG_ARCH_MX1ADS) += leds-mx1ads.o
diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot
deleted file mode 100644
index fd72ce5..0000000
--- a/arch/arm/mach-imx/Makefile.boot
+++ /dev/null
@@ -1,2 +0,0 @@
-    zreladdr-$(CONFIG_ARCH_MX1ADS)	:= 0x08008000
-
diff --git a/arch/arm/mach-imx/clock.c b/arch/arm/mach-imx/clock.c
deleted file mode 100644
index cf332ae..0000000
--- a/arch/arm/mach-imx/clock.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- *  Copyright (C) 2008 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 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/device.h>
-#include <linux/list.h>
-#include <linux/math64.h>
-#include <linux/err.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-
-/*
- * Very simple approach: We can't disable clocks, so we do
- * not need refcounting
- */
-
-struct clk {
-	struct list_head node;
-	const char *name;
-	unsigned long (*get_rate)(void);
-};
-
-/*
- *  get the system pll clock in Hz
- *
- *                  mfi + mfn / (mfd +1)
- *  f = 2 * f_ref * --------------------
- *                        pd + 1
- */
-static unsigned long imx_decode_pll(unsigned int pll, u32 f_ref)
-{
-	unsigned long long ll;
-	unsigned long quot;
-
-	u32 mfi = (pll >> 10) & 0xf;
-	u32 mfn = pll & 0x3ff;
-	u32 mfd = (pll >> 16) & 0x3ff;
-	u32 pd =  (pll >> 26) & 0xf;
-
-	mfi = mfi <= 5 ? 5 : mfi;
-
-	ll = 2 * (unsigned long long)f_ref *
-		((mfi << 16) + (mfn << 16) / (mfd + 1));
-	quot = (pd + 1) * (1 << 16);
-	ll += quot / 2;
-	do_div(ll, quot);
-	return (unsigned long)ll;
-}
-
-static unsigned long imx_get_system_clk(void)
-{
-	u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512);
-
-	return imx_decode_pll(SPCTL0, f_ref);
-}
-
-static unsigned long imx_get_mcu_clk(void)
-{
-	return imx_decode_pll(MPCTL0, CLK32 * 512);
-}
-
-/*
- *  get peripheral clock 1 ( UART[12], Timer[12], PWM )
- */
-static unsigned long imx_get_perclk1(void)
-{
-	return imx_get_system_clk() / (((PCDR) & 0xf)+1);
-}
-
-/*
- *  get peripheral clock 2 ( LCD, SD, SPI[12] )
- */
-static unsigned long imx_get_perclk2(void)
-{
-	return imx_get_system_clk() / (((PCDR>>4) & 0xf)+1);
-}
-
-/*
- *  get peripheral clock 3 ( SSI )
- */
-static unsigned long imx_get_perclk3(void)
-{
-	return imx_get_system_clk() / (((PCDR>>16) & 0x7f)+1);
-}
-
-/*
- *  get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
- */
-static unsigned long imx_get_hclk(void)
-{
-	return imx_get_system_clk() / (((CSCR>>10) & 0xf)+1);
-}
-
-static struct clk clk_system_clk = {
-	.name = "system_clk",
-	.get_rate = imx_get_system_clk,
-};
-
-static struct clk clk_hclk = {
-	.name = "hclk",
-	.get_rate = imx_get_hclk,
-};
-
-static struct clk clk_mcu_clk = {
-	.name = "mcu_clk",
-	.get_rate = imx_get_mcu_clk,
-};
-
-static struct clk clk_perclk1 = {
-	.name = "perclk1",
-	.get_rate = imx_get_perclk1,
-};
-
-static struct clk clk_uart_clk = {
-	.name = "uart_clk",
-	.get_rate = imx_get_perclk1,
-};
-
-static struct clk clk_perclk2 = {
-	.name = "perclk2",
-	.get_rate = imx_get_perclk2,
-};
-
-static struct clk clk_perclk3 = {
-	.name = "perclk3",
-	.get_rate = imx_get_perclk3,
-};
-
-static struct clk *clks[] = {
-	&clk_perclk1,
-	&clk_perclk2,
-	&clk_perclk3,
-	&clk_system_clk,
-	&clk_hclk,
-	&clk_mcu_clk,
-	&clk_uart_clk,
-};
-
-static LIST_HEAD(clocks);
-static DEFINE_MUTEX(clocks_mutex);
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-	struct clk *p, *clk = ERR_PTR(-ENOENT);
-
-	mutex_lock(&clocks_mutex);
-	list_for_each_entry(p, &clocks, node) {
-		if (!strcmp(p->name, id)) {
-			clk = p;
-			goto found;
-		}
-	}
-
-found:
-	mutex_unlock(&clocks_mutex);
-
-	return clk;
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
-
-int clk_enable(struct clk *clk)
-{
-	return 0;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_disable);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
-	return clk->get_rate();
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-int imx_clocks_init(void)
-{
-	int i;
-
-	mutex_lock(&clocks_mutex);
-	for (i = 0; i < ARRAY_SIZE(clks); i++)
-		list_add(&clks[i]->node, &clocks);
-	mutex_unlock(&clocks_mutex);
-
-	return 0;
-}
-
diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c
deleted file mode 100644
index 434b4ca..0000000
--- a/arch/arm/mach-imx/cpufreq.c
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * cpu.c: clock scaling for the iMX
- *
- * Copyright (C) 2000 2001, The Delft University of Technology
- * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
- * Copyright (C) 2006 Inky Lung <ilung@cwlinux.com>
- * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
- *
- * Based on SA1100 version written by:
- * - Johan Pouwelse (J.A.Pouwelse@its.tudelft.nl): initial version
- * - Erik Mouw (J.A.K.Mouw@its.tudelft.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
- *
- */
-
-/*#define DEBUG*/
-
-#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 <asm/system.h>
-
-#include <mach/hardware.h>
-
-#include "generic.h"
-
-#ifndef __val2mfld
-#define __val2mfld(mask,val) (((mask)&~((mask)<<1))*(val)&(mask))
-#endif
-#ifndef __mfld2val
-#define __mfld2val(mask,val) (((val)&(mask))/((mask)&~((mask)<<1)))
-#endif
-
-#define CR_920T_CLOCK_MODE	0xC0000000
-#define CR_920T_FASTBUS_MODE	0x00000000
-#define CR_920T_ASYNC_MODE	0xC0000000
-
-static u32 mpctl0_at_boot;
-static u32 bclk_div_at_boot;
-
-static struct clk *system_clk, *mcu_clk;
-
-static void imx_set_async_mode(void)
-{
-	adjust_cr(CR_920T_CLOCK_MODE, CR_920T_ASYNC_MODE);
-}
-
-static void imx_set_fastbus_mode(void)
-{
-	adjust_cr(CR_920T_CLOCK_MODE, CR_920T_FASTBUS_MODE);
-}
-
-static void imx_set_mpctl0(u32 mpctl0)
-{
-	unsigned long flags;
-
-	if (mpctl0 == 0) {
-		local_irq_save(flags);
-		CSCR &= ~CSCR_MPEN;
-		local_irq_restore(flags);
-		return;
-	}
-
-	local_irq_save(flags);
-	MPCTL0 = mpctl0;
-	CSCR |= CSCR_MPEN;
-	local_irq_restore(flags);
-}
-
-/**
- * imx_compute_mpctl - compute new PLL parameters
- * @new_mpctl:	pointer to location assigned by new PLL control register value
- * @cur_mpctl:	current PLL control register parameters
- * @f_ref:	reference source frequency Hz
- * @freq:	required frequency in Hz
- * @relation:	is one of %CPUFREQ_RELATION_L (supremum)
- *		and %CPUFREQ_RELATION_H (infimum)
- */
-long imx_compute_mpctl(u32 *new_mpctl, u32 cur_mpctl, u32 f_ref, unsigned long freq, int relation)
-{
-        u32 mfi;
-        u32 mfn;
-        u32 mfd;
-        u32 pd;
-	unsigned long long ll;
-	long l;
-	long quot;
-
-	/* Fdppl=2*Fref*(MFI+MFN/(MFD+1))/(PD+1) */
-	/*  PD=<0,15>, MFD=<1,1023>, MFI=<5,15> MFN=<0,1022> */
-
-	if (cur_mpctl) {
-		mfd = ((cur_mpctl >> 16) & 0x3ff) + 1;
-		pd =  ((cur_mpctl >> 26) & 0xf) + 1;
-	} else {
-		pd=2; mfd=313;
-	}
-
-	/* pd=2; mfd=313; mfi=8; mfn=183; */
-	/* (MFI+MFN/(MFD)) = Fdppl / (2*Fref) * (PD); */
-
-	quot = (f_ref + (1 << 9)) >> 10;
-	l = (freq * pd + quot) / (2 * quot);
-	mfi = l >> 10;
-	mfn = ((l & ((1 << 10) - 1)) * mfd + (1 << 9)) >> 10;
-
-	mfd -= 1;
-	pd -= 1;
-
-	*new_mpctl = ((mfi & 0xf) << 10) | (mfn & 0x3ff) | ((mfd & 0x3ff) << 16)
-		| ((pd & 0xf) << 26);
-
-	ll = 2 * (unsigned long long)f_ref * ( (mfi<<16) + (mfn<<16) / (mfd+1) );
-	quot = (pd+1) * (1<<16);
-	ll += quot / 2;
-	do_div(ll, quot);
-	freq = ll;
-
-	pr_debug(KERN_DEBUG "imx: new PLL parameters pd=%d mfd=%d mfi=%d mfn=%d, freq=%ld\n",
-		pd, mfd, mfi, mfn, freq);
-
-	return freq;
-}
-
-
-static int imx_verify_speed(struct cpufreq_policy *policy)
-{
-	if (policy->cpu != 0)
-		return -EINVAL;
-
-	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
-
-	return 0;
-}
-
-static unsigned int imx_get_speed(unsigned int cpu)
-{
-	unsigned int freq;
-	unsigned int cr;
-	unsigned int cscr;
-	unsigned int bclk_div;
-
-	if (cpu)
-		return 0;
-
-	cscr = CSCR;
-	bclk_div = __mfld2val(CSCR_BCLK_DIV, cscr) + 1;
-	cr = get_cr();
-
-	if((cr & CR_920T_CLOCK_MODE) == CR_920T_FASTBUS_MODE) {
-		freq = clk_get_rate(system_clk);
-		freq = (freq + bclk_div/2) / bclk_div;
-	} else {
-		freq = clk_get_rate(mcu_clk);
-		if (cscr & CSCR_MPU_PRESC)
-			freq /= 2;
-	}
-
-	freq = (freq + 500) / 1000;
-
-	return freq;
-}
-
-static int imx_set_target(struct cpufreq_policy *policy,
-			  unsigned int target_freq,
-			  unsigned int relation)
-{
-	struct cpufreq_freqs freqs;
-	u32 mpctl0 = 0;
-	u32 cscr;
-	unsigned long flags;
-	long freq;
-	long sysclk;
-	unsigned int bclk_div = bclk_div_at_boot;
-
-	/*
-	 * Some governors do not respects CPU and policy lower limits
-	 * which leads to bad things (division by zero etc), ensure
-	 * that such things do not happen.
-	 */
-	if(target_freq < policy->cpuinfo.min_freq)
-		target_freq = policy->cpuinfo.min_freq;
-
-	if(target_freq < policy->min)
-		target_freq = policy->min;
-
-	freq = target_freq * 1000;
-
-	pr_debug(KERN_DEBUG "imx: requested frequency %ld Hz, mpctl0 at boot 0x%08x\n",
-			freq, mpctl0_at_boot);
-
-	sysclk = clk_get_rate(system_clk);
-
-	if (freq > sysclk / bclk_div_at_boot + 1000000) {
-		freq = imx_compute_mpctl(&mpctl0, mpctl0_at_boot, CLK32 * 512, freq, relation);
-		if (freq < 0) {
-			printk(KERN_WARNING "imx: target frequency %ld Hz cannot be set\n", freq);
-			return -EINVAL;
-		}
-	} else {
-		if(freq + 1000 < sysclk) {
-			if (relation == CPUFREQ_RELATION_L)
-				bclk_div = (sysclk - 1000) / freq;
-			else
-				bclk_div = (sysclk + freq + 1000) / freq;
-
-			if(bclk_div > 16)
-				bclk_div = 16;
-			if(bclk_div < bclk_div_at_boot)
-				bclk_div = bclk_div_at_boot;
-		}
-		freq = (sysclk + bclk_div / 2) / bclk_div;
-	}
-
-	freqs.old = imx_get_speed(0);
-	freqs.new = (freq + 500) / 1000;
-	freqs.cpu = 0;
-	freqs.flags = 0;
-
-	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-
-	local_irq_save(flags);
-
-	imx_set_fastbus_mode();
-
-	imx_set_mpctl0(mpctl0);
-
-	cscr = CSCR;
-	cscr &= ~CSCR_BCLK_DIV;
-	cscr |= __val2mfld(CSCR_BCLK_DIV, bclk_div - 1);
-	CSCR = cscr;
-
-	if(mpctl0) {
-		CSCR |= CSCR_MPLL_RESTART;
-
-		/* Wait until MPLL is stabilized */
-		while( CSCR & CSCR_MPLL_RESTART );
-
-		imx_set_async_mode();
-	}
-
-	local_irq_restore(flags);
-
-	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
-	pr_debug(KERN_INFO "imx: set frequency %ld Hz, running from %s\n",
-			freq, mpctl0? "MPLL": "SPLL");
-
-	return 0;
-}
-
-static int __init imx_cpufreq_driver_init(struct cpufreq_policy *policy)
-{
-	printk(KERN_INFO "i.MX cpu freq change driver v1.0\n");
-
-	if (policy->cpu != 0)
-		return -EINVAL;
-
-	policy->cur = policy->min = policy->max = imx_get_speed(0);
-	policy->cpuinfo.min_freq = 8000;
-	policy->cpuinfo.max_freq = 200000;
-	 /* Manual states, that PLL stabilizes in two CLK32 periods */
-	policy->cpuinfo.transition_latency = 4 * 1000000000LL / CLK32;
-	return 0;
-}
-
-static struct cpufreq_driver imx_driver = {
-	.flags		= CPUFREQ_STICKY,
-	.verify		= imx_verify_speed,
-	.target		= imx_set_target,
-	.get		= imx_get_speed,
-	.init		= imx_cpufreq_driver_init,
-	.name		= "imx",
-};
-
-static int __init imx_cpufreq_init(void)
-{
-	bclk_div_at_boot = __mfld2val(CSCR_BCLK_DIV, CSCR) + 1;
-	mpctl0_at_boot = 0;
-
-	system_clk = clk_get(NULL, "system_clk");
-	if (IS_ERR(system_clk))
-		return PTR_ERR(system_clk);
-
-	mcu_clk = clk_get(NULL, "mcu_clk");
-	if (IS_ERR(mcu_clk)) {
-		clk_put(system_clk);
-		return PTR_ERR(mcu_clk);
-	}
-
-	if((CSCR & CSCR_MPEN) &&
-	   ((get_cr() & CR_920T_CLOCK_MODE) != CR_920T_FASTBUS_MODE))
-		mpctl0_at_boot = MPCTL0;
-
-	return cpufreq_register_driver(&imx_driver);
-}
-
-arch_initcall(imx_cpufreq_init);
-
diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c
deleted file mode 100644
index 1536583..0000000
--- a/arch/arm/mach-imx/dma.c
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- *  linux/arch/arm/mach-imx/dma.c
- *
- *  imx DMA registration and IRQ dispatching
- *
- *  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.
- *
- *  2004-03-03 Sascha Hauer <sascha@saschahauer.de>
- *             initial version heavily inspired by
- *             linux/arch/arm/mach-pxa/dma.c
- *
- *  2005-04-17 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *             Changed to support scatter gather DMA
- *             by taking Russell's code from RiscPC
- *
- *  2006-05-31 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *             Corrected error handling code.
- *
- */
-
-#undef DEBUG
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-
-#include <asm/scatterlist.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <mach/dma.h>
-#include <mach/imx-dma.h>
-
-struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
-
-/*
- * imx_dma_sg_next - prepare next chunk for scatter-gather DMA emulation
- * @dma_ch: i.MX DMA channel number
- * @lastcount: number of bytes transferred during last transfer
- *
- * Functions prepares DMA controller for next sg data chunk transfer.
- * The @lastcount argument informs function about number of bytes transferred
- * during last block. Zero value can be used for @lastcount to setup DMA
- * for the first chunk.
- */
-static inline int imx_dma_sg_next(imx_dmach_t dma_ch, unsigned int lastcount)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-	unsigned int nextcount;
-	unsigned int nextaddr;
-
-	if (!imxdma->name) {
-		printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
-		       __func__, dma_ch);
-		return 0;
-	}
-
-	imxdma->resbytes -= lastcount;
-
-	if (!imxdma->sg) {
-		pr_debug("imxdma%d: no sg data\n", dma_ch);
-		return 0;
-	}
-
-	imxdma->sgbc += lastcount;
-	if ((imxdma->sgbc >= imxdma->sg->length) || !imxdma->resbytes) {
-		if ((imxdma->sgcount <= 1) || !imxdma->resbytes) {
-			pr_debug("imxdma%d: sg transfer limit reached\n",
-				 dma_ch);
-			imxdma->sgcount=0;
-			imxdma->sg = NULL;
-			return 0;
-		} else {
-			imxdma->sgcount--;
-			imxdma->sg++;
-			imxdma->sgbc = 0;
-		}
-	}
-	nextcount = imxdma->sg->length - imxdma->sgbc;
-	nextaddr = imxdma->sg->dma_address + imxdma->sgbc;
-
-	if(imxdma->resbytes < nextcount)
-		nextcount = imxdma->resbytes;
-
-	if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ)
-		DAR(dma_ch) = nextaddr;
-	else
-		SAR(dma_ch) = nextaddr;
-
-	CNTR(dma_ch) = nextcount;
-	pr_debug("imxdma%d: next sg chunk dst 0x%08x, src 0x%08x, size 0x%08x\n",
-		 dma_ch, DAR(dma_ch), SAR(dma_ch), CNTR(dma_ch));
-
-	return nextcount;
-}
-
-/*
- * imx_dma_setup_sg_base - scatter-gather DMA emulation
- * @dma_ch: i.MX DMA channel number
- * @sg: pointer to the scatter-gather list/vector
- * @sgcount: scatter-gather list hungs count
- *
- * Functions sets up i.MX DMA state for emulated scatter-gather transfer
- * and sets up channel registers to be ready for the first chunk
- */
-static int
-imx_dma_setup_sg_base(imx_dmach_t dma_ch,
-		      struct scatterlist *sg, unsigned int sgcount)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-
-	imxdma->sg = sg;
-	imxdma->sgcount = sgcount;
-	imxdma->sgbc = 0;
-	return imx_dma_sg_next(dma_ch, 0);
-}
-
-/**
- * imx_dma_setup_single - setup i.MX DMA channel for linear memory to/from device transfer
- * @dma_ch: 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
- *
- * The function setups DMA channel source and destination addresses for transfer
- * specified by provided parameters. The scatter-gather emulation is disabled,
- * because linear data block
- * form the physical address range is transferred.
- * Return value: if incorrect parameters are provided -%EINVAL.
- *		Zero indicates success.
- */
-int
-imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address,
-		     unsigned int dma_length, unsigned int dev_addr,
-		     unsigned int dmamode)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-
-	imxdma->sg = NULL;
-	imxdma->sgcount = 0;
-	imxdma->dma_mode = dmamode;
-	imxdma->resbytes = dma_length;
-
-	if (!dma_address) {
-		printk(KERN_ERR "imxdma%d: imx_dma_setup_single null address\n",
-		       dma_ch);
-		return -EINVAL;
-	}
-
-	if (!dma_length) {
-		printk(KERN_ERR "imxdma%d: imx_dma_setup_single zero length\n",
-		       dma_ch);
-		return -EINVAL;
-	}
-
-	if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) {
-		pr_debug("imxdma%d: mx_dma_setup_single2dev dma_addressg=0x%08x dma_length=%d dev_addr=0x%08x for read\n",
-			dma_ch, (unsigned int)dma_address, dma_length,
-			dev_addr);
-		SAR(dma_ch) = dev_addr;
-		DAR(dma_ch) = (unsigned int)dma_address;
-	} else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) {
-		pr_debug("imxdma%d: mx_dma_setup_single2dev dma_addressg=0x%08x dma_length=%d dev_addr=0x%08x for write\n",
-			dma_ch, (unsigned int)dma_address, dma_length,
-			dev_addr);
-		SAR(dma_ch) = (unsigned int)dma_address;
-		DAR(dma_ch) = dev_addr;
-	} else {
-		printk(KERN_ERR "imxdma%d: imx_dma_setup_single bad dmamode\n",
-		       dma_ch);
-		return -EINVAL;
-	}
-
-	CNTR(dma_ch) = dma_length;
-
-	return 0;
-}
-
-/**
- * imx_dma_setup_sg - setup i.MX DMA channel SG list to/from device transfer
- * @dma_ch: 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(dma_ch) holds transfer burst length in bytes, 0 means 64 bytes
- *
- * %RSSR(dma_ch) has to be set to the DMA request line source %DMA_REQ_xxx
- *
- * %CCR(dma_ch) 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(imx_dmach_t dma_ch,
-		 struct scatterlist *sg, unsigned int sgcount, unsigned int dma_length,
-		 unsigned int dev_addr, unsigned int dmamode)
-{
-	int res;
-	struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-
-	imxdma->sg = NULL;
-	imxdma->sgcount = 0;
-	imxdma->dma_mode = dmamode;
-	imxdma->resbytes = dma_length;
-
-	if (!sg || !sgcount) {
-		printk(KERN_ERR "imxdma%d: imx_dma_setup_sg epty sg list\n",
-		       dma_ch);
-		return -EINVAL;
-	}
-
-	if (!sg->length) {
-		printk(KERN_ERR "imxdma%d: imx_dma_setup_sg zero length\n",
-		       dma_ch);
-		return -EINVAL;
-	}
-
-	if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) {
-		pr_debug("imxdma%d: mx_dma_setup_sg2dev sg=%p sgcount=%d total length=%d dev_addr=0x%08x for read\n",
-			dma_ch, sg, sgcount, dma_length, dev_addr);
-		SAR(dma_ch) = dev_addr;
-	} else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) {
-		pr_debug("imxdma%d: mx_dma_setup_sg2dev sg=%p sgcount=%d total length=%d dev_addr=0x%08x for write\n",
-			dma_ch, sg, sgcount, dma_length, dev_addr);
-		DAR(dma_ch) = dev_addr;
-	} else {
-		printk(KERN_ERR "imxdma%d: imx_dma_setup_sg bad dmamode\n",
-		       dma_ch);
-		return -EINVAL;
-	}
-
-	res = imx_dma_setup_sg_base(dma_ch, sg, sgcount);
-	if (res <= 0) {
-		printk(KERN_ERR "imxdma%d: no sg chunk ready\n", dma_ch);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/**
- * imx_dma_setup_handlers - setup i.MX DMA channel end and error notification handlers
- * @dma_ch: 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(imx_dmach_t dma_ch,
-		       void (*irq_handler) (int, void *),
-		       void (*err_handler) (int, void *, int),
-		       void *data)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-	unsigned long flags;
-
-	if (!imxdma->name) {
-		printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
-		       __func__, dma_ch);
-		return -ENODEV;
-	}
-
-	local_irq_save(flags);
-	DISR = (1 << dma_ch);
-	imxdma->irq_handler = irq_handler;
-	imxdma->err_handler = err_handler;
-	imxdma->data = data;
-	local_irq_restore(flags);
-	return 0;
-}
-
-/**
- * imx_dma_enable - function to start i.MX DMA channel operation
- * @dma_ch: 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(dma_ch), %RSSR(dma_ch) and %CCR(dma_ch) has to
- * be set prior this function call by the channel user.
- */
-void imx_dma_enable(imx_dmach_t dma_ch)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-	unsigned long flags;
-
-	pr_debug("imxdma%d: imx_dma_enable\n", dma_ch);
-
-	if (!imxdma->name) {
-		printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
-		       __func__, dma_ch);
-		return;
-	}
-
-	local_irq_save(flags);
-	DISR = (1 << dma_ch);
-	DIMR &= ~(1 << dma_ch);
-	CCR(dma_ch) |= CCR_CEN;
-	local_irq_restore(flags);
-}
-
-/**
- * imx_dma_disable - stop, finish i.MX DMA channel operatin
- * @dma_ch: i.MX DMA channel number
- */
-void imx_dma_disable(imx_dmach_t dma_ch)
-{
-	unsigned long flags;
-
-	pr_debug("imxdma%d: imx_dma_disable\n", dma_ch);
-
-	local_irq_save(flags);
-	DIMR |= (1 << dma_ch);
-	CCR(dma_ch) &= ~CCR_CEN;
-	DISR = (1 << dma_ch);
-	local_irq_restore(flags);
-}
-
-/**
- * imx_dma_request - request/allocate specified channel number
- * @dma_ch: i.MX DMA channel number
- * @name: the driver/caller own non-%NULL identification
- */
-int imx_dma_request(imx_dmach_t dma_ch, const char *name)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-	unsigned long flags;
-
-	/* basic sanity checks */
-	if (!name)
-		return -EINVAL;
-
-	if (dma_ch >= IMX_DMA_CHANNELS) {
-		printk(KERN_CRIT "%s: called for  non-existed channel %d\n",
-		       __func__, dma_ch);
-		return -EINVAL;
-	}
-
-	local_irq_save(flags);
-	if (imxdma->name) {
-		local_irq_restore(flags);
-		return -ENODEV;
-	}
-
-	imxdma->name = name;
-	imxdma->irq_handler = NULL;
-	imxdma->err_handler = NULL;
-	imxdma->data = NULL;
-	imxdma->sg = NULL;
-	local_irq_restore(flags);
-	return 0;
-}
-
-/**
- * imx_dma_free - release previously acquired channel
- * @dma_ch: i.MX DMA channel number
- */
-void imx_dma_free(imx_dmach_t dma_ch)
-{
-	unsigned long flags;
-	struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-
-	if (!imxdma->name) {
-		printk(KERN_CRIT
-		       "%s: trying to free channel %d which is already freed\n",
-		       __func__, dma_ch);
-		return;
-	}
-
-	local_irq_save(flags);
-	/* Disable interrupts */
-	DIMR |= (1 << dma_ch);
-	CCR(dma_ch) &= ~CCR_CEN;
-	imxdma->name = NULL;
-	local_irq_restore(flags);
-}
-
-/**
- * imx_dma_request_by_prio - find and request some of free channels best suiting requested priority
- * @name: the driver/caller own non-%NULL identification
- * @prio: one of the hardware distinguished priority level:
- *        %DMA_PRIO_HIGH, %DMA_PRIO_MEDIUM, %DMA_PRIO_LOW
- *
- * This function tries to find 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.
- */
-imx_dmach_t imx_dma_request_by_prio(const char *name, 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;
-}
-
-static irqreturn_t dma_err_handler(int irq, void *dev_id)
-{
-	int i, disr = DISR;
-	struct imx_dma_channel *channel;
-	unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR;
-	int errcode;
-
-	DISR = disr & err_mask;
-	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
-		if(!(err_mask & (1 << i)))
-			continue;
-		channel = &imx_dma_channels[i];
-		errcode = 0;
-
-		if (DBTOSR & (1 << i)) {
-			DBTOSR = (1 << i);
-			errcode |= IMX_DMA_ERR_BURST;
-		}
-		if (DRTOSR & (1 << i)) {
-			DRTOSR = (1 << i);
-			errcode |= IMX_DMA_ERR_REQUEST;
-		}
-		if (DSESR & (1 << i)) {
-			DSESR = (1 << i);
-			errcode |= IMX_DMA_ERR_TRANSFER;
-		}
-		if (DBOSR & (1 << i)) {
-			DBOSR = (1 << i);
-			errcode |= IMX_DMA_ERR_BUFFER;
-		}
-
-		/*
-		 * The cleaning of @sg field would be questionable
-		 * there, because its value can help to compute
-		 * remaining/transferred bytes count in the handler
-		 */
-		/*imx_dma_channels[i].sg = NULL;*/
-
-		if (channel->name && channel->err_handler) {
-			channel->err_handler(i, channel->data, errcode);
-			continue;
-		}
-
-		imx_dma_channels[i].sg = NULL;
-
-		printk(KERN_WARNING
-		       "DMA timeout on channel %d (%s) -%s%s%s%s\n",
-		       i, channel->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 irqreturn_t dma_irq_handler(int irq, void *dev_id)
-{
-	int i, disr = DISR;
-
-	pr_debug("imxdma: dma_irq_handler called, disr=0x%08x\n",
-		     disr);
-
-	DISR = disr;
-	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
-		if (disr & (1 << i)) {
-			struct imx_dma_channel *channel = &imx_dma_channels[i];
-			if (channel->name) {
-				if (imx_dma_sg_next(i, CNTR(i))) {
-					CCR(i) &= ~CCR_CEN;
-					mb();
-					CCR(i) |= CCR_CEN;
-				} else {
-					if (channel->irq_handler)
-						channel->irq_handler(i,
-							channel->data);
-				}
-			} else {
-				/*
-				 * IRQ for an unregistered DMA channel:
-				 * let's clear the interrupts and disable it.
-				 */
-				printk(KERN_WARNING
-				       "spurious IRQ for DMA channel %d\n", i);
-			}
-		}
-	}
-	return IRQ_HANDLED;
-}
-
-static int __init imx_dma_init(void)
-{
-	int ret;
-	int i;
-
-	/* reset DMA module */
-	DCR = DCR_DRST;
-
-	ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);
-	if (ret) {
-		printk(KERN_CRIT "Wow!  Can't register IRQ for DMA\n");
-		return ret;
-	}
-
-	ret = request_irq(DMA_ERR, dma_err_handler, 0, "DMA", NULL);
-	if (ret) {
-		printk(KERN_CRIT "Wow!  Can't register ERRIRQ for DMA\n");
-		free_irq(DMA_INT, NULL);
-	}
-
-	/* enable DMA module */
-	DCR = DCR_DEN;
-
-	/* clear all interrupts */
-	DISR = (1 << IMX_DMA_CHANNELS) - 1;
-
-	/* enable interrupts */
-	DIMR = (1 << IMX_DMA_CHANNELS) - 1;
-
-	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);
-
-EXPORT_SYMBOL(imx_dma_setup_single);
-EXPORT_SYMBOL(imx_dma_setup_sg);
-EXPORT_SYMBOL(imx_dma_setup_handlers);
-EXPORT_SYMBOL(imx_dma_enable);
-EXPORT_SYMBOL(imx_dma_disable);
-EXPORT_SYMBOL(imx_dma_request);
-EXPORT_SYMBOL(imx_dma_free);
-EXPORT_SYMBOL(imx_dma_request_by_prio);
-EXPORT_SYMBOL(imx_dma_channels);
diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c
deleted file mode 100644
index 05f1739..0000000
--- a/arch/arm/mach-imx/generic.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- *  arch/arm/mach-imx/generic.c
- *
- *  author: Sascha Hauer
- *  Created: april 20th, 2004
- *  Copyright: Synertronixx GmbH
- *
- *  Common code for i.MX machines
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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/platform_device.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-
-#include <asm/errno.h>
-#include <mach/hardware.h>
-#include <mach/imx-regs.h>
-
-#include <asm/mach/map.h>
-#include <mach/mmc.h>
-#include <mach/gpio.h>
-
-unsigned long imx_gpio_alloc_map[(GPIO_PORT_MAX + 1) * 32 / BITS_PER_LONG];
-
-void imx_gpio_mode(int gpio_mode)
-{
-	unsigned int pin = gpio_mode & GPIO_PIN_MASK;
-	unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
-	unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> GPIO_OCR_SHIFT;
-	unsigned int tmp;
-
-	/* Pullup enable */
-	if(gpio_mode & GPIO_PUEN)
-		PUEN(port) |= (1<<pin);
-	else
-		PUEN(port) &= ~(1<<pin);
-
-	/* Data direction */
-	if(gpio_mode & GPIO_OUT)
-		DDIR(port) |= 1<<pin;
-	else
-		DDIR(port) &= ~(1<<pin);
-
-	/* Primary / alternate function */
-	if(gpio_mode & GPIO_AF)
-		GPR(port) |= (1<<pin);
-	else
-		GPR(port) &= ~(1<<pin);
-
-	/* use as gpio? */
-	if(gpio_mode &  GPIO_GIUS)
-		GIUS(port) |= (1<<pin);
-	else
-		GIUS(port) &= ~(1<<pin);
-
-	/* Output / input configuration */
-	/* FIXME: I'm not very sure about OCR and ICONF, someone
-	 * should have a look over it
-	 */
-	if(pin<16) {
-		tmp = OCR1(port);
-		tmp &= ~( 3<<(pin*2));
-		tmp |= (ocr << (pin*2));
-		OCR1(port) = tmp;
-
-		ICONFA1(port) &= ~( 3<<(pin*2));
-		ICONFA1(port) |= ((gpio_mode >> GPIO_AOUT_SHIFT) & 3) << (pin * 2);
-		ICONFB1(port) &= ~( 3<<(pin*2));
-		ICONFB1(port) |= ((gpio_mode >> GPIO_BOUT_SHIFT) & 3) << (pin * 2);
-	} else {
-		tmp = OCR2(port);
-		tmp &= ~( 3<<((pin-16)*2));
-		tmp |= (ocr << ((pin-16)*2));
-		OCR2(port) = tmp;
-
-		ICONFA2(port) &= ~( 3<<((pin-16)*2));
-		ICONFA2(port) |= ((gpio_mode >> GPIO_AOUT_SHIFT) & 3) << ((pin-16) * 2);
-		ICONFB2(port) &= ~( 3<<((pin-16)*2));
-		ICONFB2(port) |= ((gpio_mode >> GPIO_BOUT_SHIFT) & 3) << ((pin-16) * 2);
-	}
-}
-
-EXPORT_SYMBOL(imx_gpio_mode);
-
-int imx_gpio_request(unsigned gpio, const char *label)
-{
-	if(gpio >= (GPIO_PORT_MAX + 1) * 32) {
-		printk(KERN_ERR "imx_gpio: Attempt to request nonexistent GPIO %d for \"%s\"\n",
-			gpio, label ? label : "?");
-		return -EINVAL;
-	}
-
-	if(test_and_set_bit(gpio, imx_gpio_alloc_map)) {
-		printk(KERN_ERR "imx_gpio: GPIO %d already used. Allocation for \"%s\" failed\n",
-			gpio, label ? label : "?");
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-EXPORT_SYMBOL(imx_gpio_request);
-
-void imx_gpio_free(unsigned gpio)
-{
-	if(gpio >= (GPIO_PORT_MAX + 1) * 32)
-		return;
-
-	clear_bit(gpio, imx_gpio_alloc_map);
-}
-
-EXPORT_SYMBOL(imx_gpio_free);
-
-int imx_gpio_direction_input(unsigned gpio)
-{
-	imx_gpio_mode(gpio | GPIO_IN | GPIO_GIUS | GPIO_DR);
-	return 0;
-}
-
-EXPORT_SYMBOL(imx_gpio_direction_input);
-
-int imx_gpio_direction_output(unsigned gpio, int value)
-{
-	imx_gpio_set_value(gpio, value);
-	imx_gpio_mode(gpio | GPIO_OUT | GPIO_GIUS | GPIO_DR);
-	return 0;
-}
-
-EXPORT_SYMBOL(imx_gpio_direction_output);
-
-int imx_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
-				int alloc_mode, const char *label)
-{
-	const int *p = pin_list;
-	int i;
-	unsigned gpio;
-	unsigned mode;
-
-	for (i = 0; i < count; i++) {
-		gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK);
-		mode = *p & ~(GPIO_PIN_MASK | GPIO_PORT_MASK);
-
-		if (gpio >= (GPIO_PORT_MAX + 1) * 32)
-			goto setup_error;
-
-		if (alloc_mode & IMX_GPIO_ALLOC_MODE_RELEASE)
-			imx_gpio_free(gpio);
-		else if (!(alloc_mode & IMX_GPIO_ALLOC_MODE_NO_ALLOC))
-			if (imx_gpio_request(gpio, label))
-				if (!(alloc_mode & IMX_GPIO_ALLOC_MODE_TRY_ALLOC))
-					goto setup_error;
-
-		if (!(alloc_mode & (IMX_GPIO_ALLOC_MODE_ALLOC_ONLY |
-				    IMX_GPIO_ALLOC_MODE_RELEASE)))
-			imx_gpio_mode(gpio | mode);
-
-		p++;
-	}
-	return 0;
-
-setup_error:
-	if(alloc_mode & (IMX_GPIO_ALLOC_MODE_NO_ALLOC |
-		         IMX_GPIO_ALLOC_MODE_TRY_ALLOC))
-		return -EINVAL;
-
-	while (p != pin_list) {
-		p--;
-		gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK);
-		imx_gpio_free(gpio);
-	}
-
-	return -EINVAL;
-}
-
-EXPORT_SYMBOL(imx_gpio_setup_multiple_pins);
-
-void __imx_gpio_set_value(unsigned gpio, int value)
-{
-	imx_gpio_set_value_inline(gpio, value);
-}
-
-EXPORT_SYMBOL(__imx_gpio_set_value);
-
-int imx_gpio_to_irq(unsigned gpio)
-{
-	return IRQ_GPIOA(0) + gpio;
-}
-
-EXPORT_SYMBOL(imx_gpio_to_irq);
-
-int imx_irq_to_gpio(unsigned irq)
-{
-	if (irq < IRQ_GPIOA(0))
-		return -EINVAL;
-	return irq - IRQ_GPIOA(0);
-}
-
-EXPORT_SYMBOL(imx_irq_to_gpio);
-
-static struct resource imx_mmc_resources[] = {
-	[0] = {
-		.start	= 0x00214000,
-		.end	= 0x002140FF,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= (SDHC_INT),
-		.end	= (SDHC_INT),
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static u64 imxmmmc_dmamask = 0xffffffffUL;
-
-static struct platform_device imx_mmc_device = {
-	.name		= "imx-mmc",
-	.id		= 0,
-	.dev		= {
-		.dma_mask = &imxmmmc_dmamask,
-		.coherent_dma_mask = 0xffffffff,
-	},
-	.num_resources	= ARRAY_SIZE(imx_mmc_resources),
-	.resource	= imx_mmc_resources,
-};
-
-void __init imx_set_mmc_info(struct imxmmc_platform_data *info)
-{
-	imx_mmc_device.dev.platform_data = info;
-}
-
-static struct platform_device *devices[] __initdata = {
-	&imx_mmc_device,
-};
-
-static struct map_desc imx_io_desc[] __initdata = {
-	{
-		.virtual	= IMX_IO_BASE,
-		.pfn		= __phys_to_pfn(IMX_IO_PHYS),
-		.length		= IMX_IO_SIZE,
-		.type		= MT_DEVICE
-	}
-};
-
-void __init
-imx_map_io(void)
-{
-	iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc));
-}
-
-static int __init imx_init(void)
-{
-	return platform_add_devices(devices, ARRAY_SIZE(devices));
-}
-
-subsys_initcall(imx_init);
diff --git a/arch/arm/mach-imx/generic.h b/arch/arm/mach-imx/generic.h
deleted file mode 100644
index e91003e..0000000
--- a/arch/arm/mach-imx/generic.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *  linux/arch/arm/mach-imx/generic.h
- *
- * Author:	Sascha Hauer <sascha@saschahauer.de>
- * Copyright:	Synertronixx 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.
- */
-
-extern void __init imx_map_io(void);
-extern void __init imx_init_irq(void);
-
-struct sys_timer;
-extern struct sys_timer imx_timer;
diff --git a/arch/arm/mach-imx/include/mach/debug-macro.S b/arch/arm/mach-imx/include/mach/debug-macro.S
deleted file mode 100644
index 87802bbf..0000000
--- a/arch/arm/mach-imx/include/mach/debug-macro.S
+++ /dev/null
@@ -1,34 +0,0 @@
-/* arch/arm/mach-imx/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S 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.
- *
-*/
-
-		.macro	addruart,rx
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx, #0x00000000	@ physical
-		movne	\rx, #0xe0000000	@ virtual
-		orreq	\rx, \rx, #0x00200000	@ physical
-		orr	\rx, \rx, #0x00006000	@ UART1 offset
-		.endm
-
-		.macro	senduart,rd,rx
-		str	\rd, [\rx, #0x40]	@ TXDATA
-		.endm
-
-		.macro	waituart,rd,rx
-		.endm
-
-		.macro	busyuart,rd,rx
-1002:		ldr	\rd, [\rx, #0x98]	@ SR2
-		tst	\rd, #1 << 3		@ TXDC
-		beq	1002b			@ wait until transmit done
-		.endm
diff --git a/arch/arm/mach-imx/include/mach/dma.h b/arch/arm/mach-imx/include/mach/dma.h
deleted file mode 100644
index 621ff2c..0000000
--- a/arch/arm/mach-imx/include/mach/dma.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- *  linux/include/asm-arm/imxads/dma.h
- *
- *  Copyright (C) 1997,1998 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 program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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_DMA_H
-#define __ASM_ARCH_DMA_H
-
-typedef enum {
-	DMA_PRIO_HIGH = 0,
-	DMA_PRIO_MEDIUM = 1,
-	DMA_PRIO_LOW = 2
-} imx_dma_prio;
-
-#define DMA_REQ_UART3_T        2
-#define DMA_REQ_UART3_R        3
-#define DMA_REQ_SSI2_T         4
-#define DMA_REQ_SSI2_R         5
-#define DMA_REQ_CSI_STAT       6
-#define DMA_REQ_CSI_R          7
-#define DMA_REQ_MSHC           8
-#define DMA_REQ_DSPA_DCT_DOUT  9
-#define DMA_REQ_DSPA_DCT_DIN  10
-#define DMA_REQ_DSPA_MAC      11
-#define DMA_REQ_EXT           12
-#define DMA_REQ_SDHC          13
-#define DMA_REQ_SPI1_R        14
-#define DMA_REQ_SPI1_T        15
-#define DMA_REQ_SSI_T         16
-#define DMA_REQ_SSI_R         17
-#define DMA_REQ_ASP_DAC       18
-#define DMA_REQ_ASP_ADC       19
-#define DMA_REQ_USP_EP(x)    (20+(x))
-#define DMA_REQ_SPI2_R        26
-#define DMA_REQ_SPI2_T        27
-#define DMA_REQ_UART2_T       28
-#define DMA_REQ_UART2_R       29
-#define DMA_REQ_UART1_T       30
-#define DMA_REQ_UART1_R       31
-
-#endif				/* _ASM_ARCH_DMA_H */
diff --git a/arch/arm/mach-imx/include/mach/entry-macro.S b/arch/arm/mach-imx/include/mach/entry-macro.S
deleted file mode 100644
index e4db679..0000000
--- a/arch/arm/mach-imx/include/mach/entry-macro.S
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * arch/arm/mach-imx/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for iMX-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.
- */
-#include <mach/hardware.h>
-
-		.macro	disable_fiq
-		.endm
-
-		.macro	get_irqnr_preamble, base, tmp
-		.endm
-
-		.macro	arch_ret_to_user, tmp1, tmp2
-		.endm
-
-#define AITC_NIVECSR   0x40
-		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
-		ldr	\base, =IO_ADDRESS(IMX_AITC_BASE)
-		@ Load offset & priority of the highest priority
-		@ interrupt pending.
-		ldr	\irqstat, [\base, #AITC_NIVECSR]
-		@ Shift off the priority leaving the offset or
-		@ "interrupt number", use arithmetic shift to
-		@ transform illegal source (0xffff) as -1
-		mov	\irqnr, \irqstat, asr #16
-		adds	\tmp, \irqnr, #1
-		.endm
diff --git a/arch/arm/mach-imx/include/mach/gpio.h b/arch/arm/mach-imx/include/mach/gpio.h
deleted file mode 100644
index 6c2942f..0000000
--- a/arch/arm/mach-imx/include/mach/gpio.h
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef _IMX_GPIO_H
-
-#include <linux/kernel.h>
-#include <mach/hardware.h>
-#include <mach/imx-regs.h>
-
-#define IMX_GPIO_ALLOC_MODE_NORMAL	0
-#define IMX_GPIO_ALLOC_MODE_NO_ALLOC	1
-#define IMX_GPIO_ALLOC_MODE_TRY_ALLOC	2
-#define IMX_GPIO_ALLOC_MODE_ALLOC_ONLY	4
-#define IMX_GPIO_ALLOC_MODE_RELEASE	8
-
-extern int imx_gpio_request(unsigned gpio, const char *label);
-
-extern void imx_gpio_free(unsigned gpio);
-
-extern int imx_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
-					int alloc_mode, const char *label);
-
-extern int imx_gpio_direction_input(unsigned gpio);
-
-extern int imx_gpio_direction_output(unsigned gpio, int value);
-
-extern void __imx_gpio_set_value(unsigned gpio, int value);
-
-static inline int imx_gpio_get_value(unsigned gpio)
-{
-	return SSR(gpio >> GPIO_PORT_SHIFT) & (1 << (gpio & GPIO_PIN_MASK));
-}
-
-static inline void imx_gpio_set_value_inline(unsigned gpio, int value)
-{
-	unsigned long flags;
-
-	raw_local_irq_save(flags);
-	if(value)
-		DR(gpio >> GPIO_PORT_SHIFT) |= (1 << (gpio & GPIO_PIN_MASK));
-	else
-		DR(gpio >> GPIO_PORT_SHIFT) &= ~(1 << (gpio & GPIO_PIN_MASK));
-	raw_local_irq_restore(flags);
-}
-
-static inline void imx_gpio_set_value(unsigned gpio, int value)
-{
-	if(__builtin_constant_p(gpio))
-		imx_gpio_set_value_inline(gpio, value);
-	else
-		__imx_gpio_set_value(gpio, value);
-}
-
-extern int imx_gpio_to_irq(unsigned gpio);
-
-extern int imx_irq_to_gpio(unsigned irq);
-
-/*-------------------------------------------------------------------------*/
-
-/* Wrappers for "new style" GPIO calls. These calls i.MX specific versions
- * to allow future extension of GPIO logic.
- */
-
-static inline int gpio_request(unsigned gpio, const char *label)
-{
-	return imx_gpio_request(gpio, label);
-}
-
-static inline void gpio_free(unsigned gpio)
-{
-	might_sleep();
-
-	imx_gpio_free(gpio);
-}
-
-static inline  int gpio_direction_input(unsigned gpio)
-{
-	return imx_gpio_direction_input(gpio);
-}
-
-static inline int gpio_direction_output(unsigned gpio, int value)
-{
-	return imx_gpio_direction_output(gpio, value);
-}
-
-static inline int gpio_get_value(unsigned gpio)
-{
-	return imx_gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned gpio, int value)
-{
-	imx_gpio_set_value(gpio, value);
-}
-
-#include <asm-generic/gpio.h>		/* cansleep wrappers */
-
-static inline int gpio_to_irq(unsigned gpio)
-{
-	return imx_gpio_to_irq(gpio);
-}
-
-static inline int irq_to_gpio(unsigned irq)
-{
-	return imx_irq_to_gpio(irq);
-}
-
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/hardware.h b/arch/arm/mach-imx/include/mach/hardware.h
deleted file mode 100644
index c73e9e7..0000000
--- a/arch/arm/mach-imx/include/mach/hardware.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- *  arch/arm/mach-imx/include/mach/hardware.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_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-#include <asm/sizes.h>
-#include "imx-regs.h"
-
-#ifndef __ASSEMBLY__
-# define __REG(x)	(*((volatile u32 *)IO_ADDRESS(x)))
-
-# define __REG2(x,y)        (*(volatile u32 *)((u32)&__REG(x) + (y)))
-#endif
-
-/*
- * Memory map
- */
-
-#define IMX_IO_PHYS		0x00200000
-#define IMX_IO_SIZE		0x00100000
-#define IMX_IO_BASE		0xe0000000
-
-#define IMX_CS0_PHYS		0x10000000
-#define IMX_CS0_SIZE		0x02000000
-#define IMX_CS0_VIRT		0xe8000000
-
-#define IMX_CS1_PHYS		0x12000000
-#define IMX_CS1_SIZE		0x01000000
-#define IMX_CS1_VIRT		0xea000000
-
-#define IMX_CS2_PHYS		0x13000000
-#define IMX_CS2_SIZE		0x01000000
-#define IMX_CS2_VIRT		0xeb000000
-
-#define IMX_CS3_PHYS		0x14000000
-#define IMX_CS3_SIZE		0x01000000
-#define IMX_CS3_VIRT		0xec000000
-
-#define IMX_CS4_PHYS		0x15000000
-#define IMX_CS4_SIZE		0x01000000
-#define IMX_CS4_VIRT		0xed000000
-
-#define IMX_CS5_PHYS		0x16000000
-#define IMX_CS5_SIZE		0x01000000
-#define IMX_CS5_VIRT		0xee000000
-
-#define IMX_FB_VIRT		0xF1000000
-#define IMX_FB_SIZE		(256*1024)
-
-/* macro to get at IO space when running virtually */
-#define IO_ADDRESS(x) ((x) | IMX_IO_BASE)
-
-#ifndef __ASSEMBLY__
-/*
- * Handy routine to set GPIO functions
- */
-extern void imx_gpio_mode( int gpio_mode );
-
-#endif
-
-#define MAXIRQNUM                       62
-#define MAXFIQNUM                       62
-#define MAXSWINUM                       62
-
-/*
- * Use SDRAM for memory
- */
-#define MEM_SIZE		0x01000000
-
-#ifdef CONFIG_ARCH_MX1ADS
-#include "mx1ads.h"
-#endif
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/imx-dma.h b/arch/arm/mach-imx/include/mach/imx-dma.h
deleted file mode 100644
index bbe54df..0000000
--- a/arch/arm/mach-imx/include/mach/imx-dma.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- *  linux/include/asm-arm/imxads/dma.h
- *
- *  Copyright (C) 1997,1998 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 program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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 <mach/dma.h>
-
-#ifndef __ASM_ARCH_IMX_DMA_H
-#define __ASM_ARCH_IMX_DMA_H
-
-#define IMX_DMA_CHANNELS  11
-
-/*
- * 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
- * @sgbc: counter of processed bytes in the actual read/written chunk
- * @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 *data;
-	unsigned int  dma_mode;
-	struct scatterlist *sg;
-	unsigned int sgbc;
-	unsigned int sgcount;
-	unsigned int resbytes;
-	int dma_num;
-};
-
-extern struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
-
-#define IMX_DMA_ERR_BURST     1
-#define IMX_DMA_ERR_REQUEST   2
-#define IMX_DMA_ERR_TRANSFER  4
-#define IMX_DMA_ERR_BUFFER    8
-
-/* The type to distinguish channel numbers parameter from ordinal int type */
-typedef int imx_dmach_t;
-
-#define DMA_MODE_READ		0
-#define DMA_MODE_WRITE		1
-#define DMA_MODE_MASK		1
-
-int
-imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address,
-		unsigned int dma_length, unsigned int dev_addr, unsigned int dmamode);
-
-int
-imx_dma_setup_sg(imx_dmach_t dma_ch,
-		 struct scatterlist *sg, unsigned int sgcount, unsigned int dma_length,
-		 unsigned int dev_addr, unsigned int dmamode);
-
-int
-imx_dma_setup_handlers(imx_dmach_t dma_ch,
-		void (*irq_handler) (int, void *),
-		void (*err_handler) (int, void *, int), void *data);
-
-void imx_dma_enable(imx_dmach_t dma_ch);
-
-void imx_dma_disable(imx_dmach_t dma_ch);
-
-int imx_dma_request(imx_dmach_t dma_ch, const char *name);
-
-void imx_dma_free(imx_dmach_t dma_ch);
-
-imx_dmach_t imx_dma_request_by_prio(const char *name, imx_dma_prio prio);
-
-
-#endif	/* _ASM_ARCH_IMX_DMA_H */
diff --git a/arch/arm/mach-imx/include/mach/imx-regs.h b/arch/arm/mach-imx/include/mach/imx-regs.h
deleted file mode 100644
index 490297f..0000000
--- a/arch/arm/mach-imx/include/mach/imx-regs.h
+++ /dev/null
@@ -1,376 +0,0 @@
-#ifndef _IMX_REGS_H
-#define _IMX_REGS_H
-/* ------------------------------------------------------------------------
- *  Motorola IMX system registers
- * ------------------------------------------------------------------------
- *
- */
-
-/*
- *  Register BASEs, based on OFFSETs
- *
- */
-#define IMX_AIPI1_BASE             (0x00000 + IMX_IO_BASE)
-#define IMX_WDT_BASE               (0x01000 + IMX_IO_BASE)
-#define IMX_TIM1_BASE              (0x02000 + IMX_IO_BASE)
-#define IMX_TIM2_BASE              (0x03000 + IMX_IO_BASE)
-#define IMX_RTC_BASE               (0x04000 + IMX_IO_BASE)
-#define IMX_LCDC_BASE              (0x05000 + IMX_IO_BASE)
-#define IMX_UART1_BASE             (0x06000 + IMX_IO_BASE)
-#define IMX_UART2_BASE             (0x07000 + IMX_IO_BASE)
-#define IMX_PWM_BASE               (0x08000 + IMX_IO_BASE)
-#define IMX_DMAC_BASE              (0x09000 + IMX_IO_BASE)
-#define IMX_AIPI2_BASE             (0x10000 + IMX_IO_BASE)
-#define IMX_SIM_BASE               (0x11000 + IMX_IO_BASE)
-#define IMX_USBD_BASE              (0x12000 + IMX_IO_BASE)
-#define IMX_SPI1_BASE              (0x13000 + IMX_IO_BASE)
-#define IMX_MMC_BASE               (0x14000 + IMX_IO_BASE)
-#define IMX_ASP_BASE               (0x15000 + IMX_IO_BASE)
-#define IMX_BTA_BASE               (0x16000 + IMX_IO_BASE)
-#define IMX_I2C_BASE               (0x17000 + IMX_IO_BASE)
-#define IMX_SSI_BASE               (0x18000 + IMX_IO_BASE)
-#define IMX_SPI2_BASE              (0x19000 + IMX_IO_BASE)
-#define IMX_MSHC_BASE              (0x1A000 + IMX_IO_BASE)
-#define IMX_PLL_BASE               (0x1B000 + IMX_IO_BASE)
-#define IMX_GPIO_BASE              (0x1C000 + IMX_IO_BASE)
-#define IMX_EIM_BASE               (0x20000 + IMX_IO_BASE)
-#define IMX_SDRAMC_BASE            (0x21000 + IMX_IO_BASE)
-#define IMX_MMA_BASE               (0x22000 + IMX_IO_BASE)
-#define IMX_AITC_BASE              (0x23000 + IMX_IO_BASE)
-#define IMX_CSI_BASE               (0x24000 + IMX_IO_BASE)
-
-/* PLL registers */
-#define CSCR   __REG(IMX_PLL_BASE)        /* Clock Source Control Register */
-#define CSCR_SPLL_RESTART	(1<<22)
-#define CSCR_MPLL_RESTART	(1<<21)
-#define CSCR_SYSTEM_SEL		(1<<16)
-#define CSCR_BCLK_DIV		(0xf<<10)
-#define CSCR_MPU_PRESC		(1<<15)
-#define CSCR_SPEN		(1<<1)
-#define CSCR_MPEN		(1<<0)
-
-#define MPCTL0 __REG(IMX_PLL_BASE + 0x4)  /* MCU PLL Control Register 0 */
-#define MPCTL1 __REG(IMX_PLL_BASE + 0x8)  /* MCU PLL and System Clock Register 1 */
-#define SPCTL0 __REG(IMX_PLL_BASE + 0xc)  /* System PLL Control Register 0 */
-#define SPCTL1 __REG(IMX_PLL_BASE + 0x10) /* System PLL Control Register 1 */
-#define PCDR   __REG(IMX_PLL_BASE + 0x20) /* Peripheral Clock Divider Register */
-
-/*
- *  GPIO Module and I/O Multiplexer
- *  x = 0..3 for reg_A, reg_B, reg_C, reg_D
- */
-#define DDIR(x)    __REG2(IMX_GPIO_BASE + 0x00, ((x) & 3) << 8)
-#define OCR1(x)    __REG2(IMX_GPIO_BASE + 0x04, ((x) & 3) << 8)
-#define OCR2(x)    __REG2(IMX_GPIO_BASE + 0x08, ((x) & 3) << 8)
-#define ICONFA1(x) __REG2(IMX_GPIO_BASE + 0x0c, ((x) & 3) << 8)
-#define ICONFA2(x) __REG2(IMX_GPIO_BASE + 0x10, ((x) & 3) << 8)
-#define ICONFB1(x) __REG2(IMX_GPIO_BASE + 0x14, ((x) & 3) << 8)
-#define ICONFB2(x) __REG2(IMX_GPIO_BASE + 0x18, ((x) & 3) << 8)
-#define DR(x)      __REG2(IMX_GPIO_BASE + 0x1c, ((x) & 3) << 8)
-#define GIUS(x)    __REG2(IMX_GPIO_BASE + 0x20, ((x) & 3) << 8)
-#define SSR(x)     __REG2(IMX_GPIO_BASE + 0x24, ((x) & 3) << 8)
-#define ICR1(x)    __REG2(IMX_GPIO_BASE + 0x28, ((x) & 3) << 8)
-#define ICR2(x)    __REG2(IMX_GPIO_BASE + 0x2c, ((x) & 3) << 8)
-#define IMR(x)     __REG2(IMX_GPIO_BASE + 0x30, ((x) & 3) << 8)
-#define ISR(x)     __REG2(IMX_GPIO_BASE + 0x34, ((x) & 3) << 8)
-#define GPR(x)     __REG2(IMX_GPIO_BASE + 0x38, ((x) & 3) << 8)
-#define SWR(x)     __REG2(IMX_GPIO_BASE + 0x3c, ((x) & 3) << 8)
-#define PUEN(x)    __REG2(IMX_GPIO_BASE + 0x40, ((x) & 3) << 8)
-
-#define GPIO_PORT_MAX  3
-
-#define GPIO_PIN_MASK 0x1f
-#define GPIO_PORT_MASK (0x3 << 5)
-
-#define GPIO_PORT_SHIFT 5
-#define GPIO_PORTA (0<<5)
-#define GPIO_PORTB (1<<5)
-#define GPIO_PORTC (2<<5)
-#define GPIO_PORTD (3<<5)
-
-#define GPIO_OUT   (1<<7)
-#define GPIO_IN    (0<<7)
-#define GPIO_PUEN  (1<<8)
-
-#define GPIO_PF    (0<<9)
-#define GPIO_AF    (1<<9)
-
-#define GPIO_OCR_SHIFT 10
-#define GPIO_OCR_MASK (3<<10)
-#define GPIO_AIN   (0<<10)
-#define GPIO_BIN   (1<<10)
-#define GPIO_CIN   (2<<10)
-#define GPIO_DR    (3<<10)
-
-#define GPIO_AOUT_SHIFT 12
-#define GPIO_AOUT_MASK (3<<12)
-#define GPIO_AOUT     (0<<12)
-#define GPIO_AOUT_ISR (1<<12)
-#define GPIO_AOUT_0   (2<<12)
-#define GPIO_AOUT_1   (3<<12)
-
-#define GPIO_BOUT_SHIFT 14
-#define GPIO_BOUT_MASK (3<<14)
-#define GPIO_BOUT      (0<<14)
-#define GPIO_BOUT_ISR  (1<<14)
-#define GPIO_BOUT_0    (2<<14)
-#define GPIO_BOUT_1    (3<<14)
-
-#define GPIO_GIUS      (1<<16)
-
-/* assignements for GPIO alternate/primary functions */
-
-/* FIXME: This list is not completed. The correct directions are
- * missing on some (many) pins
- */
-#define PA0_AIN_SPI2_CLK     ( GPIO_GIUS | GPIO_PORTA | GPIO_OUT | 0 )
-#define PA0_AF_ETMTRACESYNC  ( GPIO_PORTA | GPIO_AF | 0 )
-#define PA1_AOUT_SPI2_RXD    ( GPIO_GIUS | GPIO_PORTA | GPIO_IN | 1 )
-#define PA1_PF_TIN           ( GPIO_PORTA | GPIO_PF | 1 )
-#define PA2_PF_PWM0          ( GPIO_PORTA | GPIO_OUT | GPIO_PF | 2 )
-#define PA3_PF_CSI_MCLK      ( GPIO_PORTA | GPIO_PF | 3 )
-#define PA4_PF_CSI_D0        ( GPIO_PORTA | GPIO_PF | 4 )
-#define PA5_PF_CSI_D1        ( GPIO_PORTA | GPIO_PF | 5 )
-#define PA6_PF_CSI_D2        ( GPIO_PORTA | GPIO_PF | 6 )
-#define PA7_PF_CSI_D3        ( GPIO_PORTA | GPIO_PF | 7 )
-#define PA8_PF_CSI_D4        ( GPIO_PORTA | GPIO_PF | 8 )
-#define PA9_PF_CSI_D5        ( GPIO_PORTA | GPIO_PF | 9 )
-#define PA10_PF_CSI_D6       ( GPIO_PORTA | GPIO_PF | 10 )
-#define PA11_PF_CSI_D7       ( GPIO_PORTA | GPIO_PF | 11 )
-#define PA12_PF_CSI_VSYNC    ( GPIO_PORTA | GPIO_PF | 12 )
-#define PA13_PF_CSI_HSYNC    ( GPIO_PORTA | GPIO_PF | 13 )
-#define PA14_PF_CSI_PIXCLK   ( GPIO_PORTA | GPIO_PF | 14 )
-#define PA15_PF_I2C_SDA      ( GPIO_PORTA | GPIO_OUT | GPIO_PF | 15 )
-#define PA16_PF_I2C_SCL      ( GPIO_PORTA | GPIO_OUT | GPIO_PF | 16 )
-#define PA17_AF_ETMTRACEPKT4 ( GPIO_PORTA | GPIO_AF | 17 )
-#define PA17_AIN_SPI2_SS     ( GPIO_GIUS | GPIO_PORTA | GPIO_OUT | 17 )
-#define PA18_AF_ETMTRACEPKT5 ( GPIO_PORTA | GPIO_AF | 18 )
-#define PA19_AF_ETMTRACEPKT6 ( GPIO_PORTA | GPIO_AF | 19 )
-#define PA20_AF_ETMTRACEPKT7 ( GPIO_PORTA | GPIO_AF | 20 )
-#define PA21_PF_A0           ( GPIO_PORTA | GPIO_PF | 21 )
-#define PA22_PF_CS4          ( GPIO_PORTA | GPIO_PF | 22 )
-#define PA23_PF_CS5          ( GPIO_PORTA | GPIO_PF | 23 )
-#define PA24_PF_A16          ( GPIO_PORTA | GPIO_PF | 24 )
-#define PA24_AF_ETMTRACEPKT0 ( GPIO_PORTA | GPIO_AF | 24 )
-#define PA25_PF_A17          ( GPIO_PORTA | GPIO_PF | 25 )
-#define PA25_AF_ETMTRACEPKT1 ( GPIO_PORTA | GPIO_AF | 25 )
-#define PA26_PF_A18          ( GPIO_PORTA | GPIO_PF | 26 )
-#define PA26_AF_ETMTRACEPKT2 ( GPIO_PORTA | GPIO_AF | 26 )
-#define PA27_PF_A19          ( GPIO_PORTA | GPIO_PF | 27 )
-#define PA27_AF_ETMTRACEPKT3 ( GPIO_PORTA | GPIO_AF | 27 )
-#define PA28_PF_A20          ( GPIO_PORTA | GPIO_PF | 28 )
-#define PA28_AF_ETMPIPESTAT0 ( GPIO_PORTA | GPIO_AF | 28 )
-#define PA29_PF_A21          ( GPIO_PORTA | GPIO_PF | 29 )
-#define PA29_AF_ETMPIPESTAT1 ( GPIO_PORTA | GPIO_AF | 29 )
-#define PA30_PF_A22          ( GPIO_PORTA | GPIO_PF | 30 )
-#define PA30_AF_ETMPIPESTAT2 ( GPIO_PORTA | GPIO_AF | 30 )
-#define PA31_PF_A23          ( GPIO_PORTA | GPIO_PF | 31 )
-#define PA31_AF_ETMTRACECLK  ( GPIO_PORTA | GPIO_AF | 31 )
-#define PB8_PF_SD_DAT0       ( GPIO_PORTB | GPIO_PF | GPIO_PUEN | 8 )
-#define PB8_AF_MS_PIO        ( GPIO_PORTB | GPIO_AF | 8 )
-#define PB9_PF_SD_DAT1       ( GPIO_PORTB | GPIO_PF | GPIO_PUEN  | 9 )
-#define PB9_AF_MS_PI1        ( GPIO_PORTB | GPIO_AF | 9 )
-#define PB10_PF_SD_DAT2      ( GPIO_PORTB | GPIO_PF | GPIO_PUEN  | 10 )
-#define PB10_AF_MS_SCLKI     ( GPIO_PORTB | GPIO_AF | 10 )
-#define PB11_PF_SD_DAT3      ( GPIO_PORTB | GPIO_PF | 11 )
-#define PB11_AF_MS_SDIO      ( GPIO_PORTB | GPIO_AF | 11 )
-#define PB12_PF_SD_CLK       ( GPIO_PORTB | GPIO_PF | 12 )
-#define PB12_AF_MS_SCLK0     ( GPIO_PORTB | GPIO_AF | 12 )
-#define PB13_PF_SD_CMD       ( GPIO_PORTB | GPIO_PF | GPIO_PUEN | 13 )
-#define PB13_AF_MS_BS        ( GPIO_PORTB | GPIO_AF | 13 )
-#define PB14_AF_SSI_RXFS     ( GPIO_PORTB | GPIO_AF | 14 )
-#define PB15_AF_SSI_RXCLK    ( GPIO_PORTB | GPIO_AF | 15 )
-#define PB16_AF_SSI_RXDAT    ( GPIO_PORTB | GPIO_IN | GPIO_AF | 16 )
-#define PB17_AF_SSI_TXDAT    ( GPIO_PORTB | GPIO_OUT | GPIO_AF | 17 )
-#define PB18_AF_SSI_TXFS     ( GPIO_PORTB | GPIO_AF | 18 )
-#define PB19_AF_SSI_TXCLK    ( GPIO_PORTB | GPIO_AF | 19 )
-#define PB20_PF_USBD_AFE     ( GPIO_PORTB | GPIO_PF | 20 )
-#define PB21_PF_USBD_OE      ( GPIO_PORTB | GPIO_PF | 21 )
-#define PB22_PFUSBD_RCV      ( GPIO_PORTB | GPIO_PF | 22 )
-#define PB23_PF_USBD_SUSPND  ( GPIO_PORTB | GPIO_PF | 23 )
-#define PB24_PF_USBD_VP      ( GPIO_PORTB | GPIO_PF | 24 )
-#define PB25_PF_USBD_VM      ( GPIO_PORTB | GPIO_PF | 25 )
-#define PB26_PF_USBD_VPO     ( GPIO_PORTB | GPIO_PF | 26 )
-#define PB27_PF_USBD_VMO     ( GPIO_PORTB | GPIO_PF | 27 )
-#define PB28_PF_UART2_CTS    ( GPIO_PORTB | GPIO_OUT | GPIO_PF | 28 )
-#define PB29_PF_UART2_RTS    ( GPIO_PORTB | GPIO_IN | GPIO_PF | 29 )
-#define PB30_PF_UART2_TXD    ( GPIO_PORTB | GPIO_OUT | GPIO_PF | 30 )
-#define PB31_PF_UART2_RXD    ( GPIO_PORTB | GPIO_IN | GPIO_PF | 31 )
-#define PC3_PF_SSI_RXFS      ( GPIO_PORTC | GPIO_PF | 3 )
-#define PC4_PF_SSI_RXCLK     ( GPIO_PORTC | GPIO_PF | 4 )
-#define PC5_PF_SSI_RXDAT     ( GPIO_PORTC | GPIO_IN | GPIO_PF | 5 )
-#define PC6_PF_SSI_TXDAT     ( GPIO_PORTC | GPIO_OUT | GPIO_PF | 6 )
-#define PC7_PF_SSI_TXFS      ( GPIO_PORTC | GPIO_PF | 7 )
-#define PC8_PF_SSI_TXCLK     ( GPIO_PORTC | GPIO_PF | 8 )
-#define PC9_PF_UART1_CTS     ( GPIO_PORTC | GPIO_OUT | GPIO_PF | 9 )
-#define PC10_PF_UART1_RTS    ( GPIO_PORTC | GPIO_IN | GPIO_PF | 10 )
-#define PC11_PF_UART1_TXD    ( GPIO_PORTC | GPIO_OUT | GPIO_PF | 11 )
-#define PC12_PF_UART1_RXD    ( GPIO_PORTC | GPIO_IN | GPIO_PF | 12 )
-#define PC13_PF_SPI1_SPI_RDY ( GPIO_PORTC | GPIO_PF | 13 )
-#define PC14_PF_SPI1_SCLK    ( GPIO_PORTC | GPIO_PF | 14 )
-#define PC15_PF_SPI1_SS      ( GPIO_PORTC | GPIO_PF | 15 )
-#define PC16_PF_SPI1_MISO    ( GPIO_PORTC | GPIO_PF | 16 )
-#define PC17_PF_SPI1_MOSI    ( GPIO_PORTC | GPIO_PF | 17 )
-#define PC24_BIN_UART3_RI    ( GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 24 )
-#define PC25_BIN_UART3_DSR   ( GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 25 )
-#define PC26_AOUT_UART3_DTR  ( GPIO_GIUS | GPIO_PORTC | GPIO_IN | 26 )
-#define PC27_BIN_UART3_DCD   ( GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 27 )
-#define PC28_BIN_UART3_CTS   ( GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 28 )
-#define PC29_AOUT_UART3_RTS  ( GPIO_GIUS | GPIO_PORTC | GPIO_IN | 29 )
-#define PC30_BIN_UART3_TX    ( GPIO_GIUS | GPIO_PORTC | GPIO_BIN | 30 )
-#define PC31_AOUT_UART3_RX   ( GPIO_GIUS | GPIO_PORTC | GPIO_IN | 31)
-#define PD6_PF_LSCLK         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 6 )
-#define PD7_PF_REV           ( GPIO_PORTD | GPIO_PF | 7 )
-#define PD7_AF_UART2_DTR     ( GPIO_GIUS | GPIO_PORTD | GPIO_IN | GPIO_AF | 7 )
-#define PD7_AIN_SPI2_SCLK    ( GPIO_GIUS | GPIO_PORTD | GPIO_AIN | 7 )
-#define PD8_PF_CLS           ( GPIO_PORTD | GPIO_PF | 8 )
-#define PD8_AF_UART2_DCD     ( GPIO_PORTD | GPIO_OUT | GPIO_AF | 8 )
-#define PD8_AIN_SPI2_SS      ( GPIO_GIUS | GPIO_PORTD | GPIO_AIN | 8 )
-#define PD9_PF_PS            ( GPIO_PORTD | GPIO_PF | 9 )
-#define PD9_AF_UART2_RI      ( GPIO_PORTD | GPIO_OUT | GPIO_AF | 9 )
-#define PD9_AOUT_SPI2_RXD    ( GPIO_GIUS | GPIO_PORTD | GPIO_IN | 9 )
-#define PD10_PF_SPL_SPR      ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 10 )
-#define PD10_AF_UART2_DSR    ( GPIO_PORTD | GPIO_OUT | GPIO_AF | 10 )
-#define PD10_AIN_SPI2_TXD    ( GPIO_GIUS | GPIO_PORTD | GPIO_OUT | 10 )
-#define PD11_PF_CONTRAST     ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 11 )
-#define PD12_PF_ACD_OE       ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 12 )
-#define PD13_PF_LP_HSYNC     ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 13 )
-#define PD14_PF_FLM_VSYNC    ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 14 )
-#define PD15_PF_LD0          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 15 )
-#define PD16_PF_LD1          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 16 )
-#define PD17_PF_LD2          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 17 )
-#define PD18_PF_LD3          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 18 )
-#define PD19_PF_LD4          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 19 )
-#define PD20_PF_LD5          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 20 )
-#define PD21_PF_LD6          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 21 )
-#define PD22_PF_LD7          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 22 )
-#define PD23_PF_LD8          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 23 )
-#define PD24_PF_LD9          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 24 )
-#define PD25_PF_LD10         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 25 )
-#define PD26_PF_LD11         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 26 )
-#define PD27_PF_LD12         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 27 )
-#define PD28_PF_LD13         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 28 )
-#define PD29_PF_LD14         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 29 )
-#define PD30_PF_LD15         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 30 )
-#define PD31_PF_TMR2OUT      ( GPIO_PORTD | GPIO_PF | 31 )
-#define PD31_BIN_SPI2_TXD    ( GPIO_GIUS | GPIO_PORTD | GPIO_BIN | 31 )
-
-/*
- * PWM controller
- */
-#define PWMC	__REG(IMX_PWM_BASE + 0x00)	/* PWM Control Register		*/
-#define PWMS	__REG(IMX_PWM_BASE + 0x04)	/* PWM Sample Register		*/
-#define PWMP	__REG(IMX_PWM_BASE + 0x08)	/* PWM Period Register		*/
-#define PWMCNT	__REG(IMX_PWM_BASE + 0x0C)	/* PWM Counter Register		*/
-
-#define PWMC_HCTR		(0x01<<18)		/* Halfword FIFO Data Swapping	*/
-#define PWMC_BCTR		(0x01<<17)		/* Byte FIFO Data Swapping	*/
-#define PWMC_SWR		(0x01<<16)		/* Software Reset		*/
-#define PWMC_CLKSRC		(0x01<<15)		/* Clock Source			*/
-#define PWMC_PRESCALER(x)	(((x-1) & 0x7F) << 8)	/* PRESCALER			*/
-#define PWMC_IRQ		(0x01<< 7)		/* Interrupt Request		*/
-#define PWMC_IRQEN		(0x01<< 6)		/* Interrupt Request Enable	*/
-#define PWMC_FIFOAV		(0x01<< 5)		/* FIFO Available		*/
-#define PWMC_EN			(0x01<< 4)		/* Enables/Disables the PWM	*/
-#define PWMC_REPEAT(x)		(((x) & 0x03) << 2)	/* Sample Repeats		*/
-#define PWMC_CLKSEL(x)		(((x) & 0x03) << 0)	/* Clock Selection		*/
-
-#define PWMS_SAMPLE(x)		((x) & 0xFFFF)		/* Contains a two-sample word	*/
-#define PWMP_PERIOD(x)		((x) & 0xFFFF)		/* Represents the PWM's period	*/
-#define PWMC_COUNTER(x)		((x) & 0xFFFF)		/* Represents the current count value	*/
-
-/*
- *  DMA Controller
- */
-#define DCR     __REG(IMX_DMAC_BASE +0x00)	/* DMA Control Register */
-#define DISR    __REG(IMX_DMAC_BASE +0x04)	/* DMA Interrupt status Register */
-#define DIMR    __REG(IMX_DMAC_BASE +0x08)	/* DMA Interrupt mask Register */
-#define DBTOSR  __REG(IMX_DMAC_BASE +0x0c)	/* DMA Burst timeout status Register */
-#define DRTOSR  __REG(IMX_DMAC_BASE +0x10)	/* DMA Request timeout Register */
-#define DSESR   __REG(IMX_DMAC_BASE +0x14)	/* DMA Transfer Error Status Register */
-#define DBOSR   __REG(IMX_DMAC_BASE +0x18)	/* DMA Buffer overflow status Register */
-#define DBTOCR  __REG(IMX_DMAC_BASE +0x1c)	/* DMA Burst timeout control Register */
-#define WSRA    __REG(IMX_DMAC_BASE +0x40)	/* W-Size Register A */
-#define XSRA    __REG(IMX_DMAC_BASE +0x44)	/* X-Size Register A */
-#define YSRA    __REG(IMX_DMAC_BASE +0x48)	/* Y-Size Register A */
-#define WSRB    __REG(IMX_DMAC_BASE +0x4c)	/* W-Size Register B */
-#define XSRB    __REG(IMX_DMAC_BASE +0x50)	/* X-Size Register B */
-#define YSRB    __REG(IMX_DMAC_BASE +0x54)	/* Y-Size Register B */
-#define SAR(x)  __REG2( IMX_DMAC_BASE + 0x80, (x) << 6)	/* Source Address Registers */
-#define DAR(x)  __REG2( IMX_DMAC_BASE + 0x84, (x) << 6)	/* Destination Address Registers */
-#define CNTR(x) __REG2( IMX_DMAC_BASE + 0x88, (x) << 6)	/* Count Registers */
-#define CCR(x)  __REG2( IMX_DMAC_BASE + 0x8c, (x) << 6)	/* Control Registers */
-#define RSSR(x) __REG2( IMX_DMAC_BASE + 0x90, (x) << 6)	/* Request source select Registers */
-#define BLR(x)  __REG2( IMX_DMAC_BASE + 0x94, (x) << 6)	/* Burst length Registers */
-#define RTOR(x) __REG2( IMX_DMAC_BASE + 0x98, (x) << 6)	/* Request timeout Registers */
-#define BUCR(x) __REG2( IMX_DMAC_BASE + 0x98, (x) << 6)	/* Bus Utilization 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_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)
-
-/*
- *  Interrupt controller
- */
-
-#define IMX_INTCNTL        __REG(IMX_AITC_BASE+0x00)
-#define INTCNTL_FIAD       (1<<19)
-#define INTCNTL_NIAD       (1<<20)
-
-#define IMX_NIMASK         __REG(IMX_AITC_BASE+0x04)
-#define IMX_INTENNUM       __REG(IMX_AITC_BASE+0x08)
-#define IMX_INTDISNUM      __REG(IMX_AITC_BASE+0x0c)
-#define IMX_INTENABLEH     __REG(IMX_AITC_BASE+0x10)
-#define IMX_INTENABLEL     __REG(IMX_AITC_BASE+0x14)
-
-/*
- *  General purpose timers
- */
-#define IMX_TCTL(x)        __REG( 0x00 + (x))
-#define TCTL_SWR           (1<<15)
-#define TCTL_FRR           (1<<8)
-#define TCTL_CAP_RIS       (1<<6)
-#define TCTL_CAP_FAL       (2<<6)
-#define TCTL_CAP_RIS_FAL   (3<<6)
-#define TCTL_OM            (1<<5)
-#define TCTL_IRQEN         (1<<4)
-#define TCTL_CLK_PCLK1     (1<<1)
-#define TCTL_CLK_PCLK1_16  (2<<1)
-#define TCTL_CLK_TIN       (3<<1)
-#define TCTL_CLK_32        (4<<1)
-#define TCTL_TEN           (1<<0)
-
-#define IMX_TPRER(x)       __REG( 0x04 + (x))
-#define IMX_TCMP(x)        __REG( 0x08 + (x))
-#define IMX_TCR(x)         __REG( 0x0C + (x))
-#define IMX_TCN(x)         __REG( 0x10 + (x))
-#define IMX_TSTAT(x)       __REG( 0x14 + (x))
-#define TSTAT_CAPT         (1<<1)
-#define TSTAT_COMP         (1<<0)
-
-#endif				// _IMX_REGS_H
diff --git a/arch/arm/mach-imx/include/mach/imx-uart.h b/arch/arm/mach-imx/include/mach/imx-uart.h
deleted file mode 100644
index d54eb1d..0000000
--- a/arch/arm/mach-imx/include/mach/imx-uart.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef ASMARM_ARCH_UART_H
-#define ASMARM_ARCH_UART_H
-
-#define IMXUART_HAVE_RTSCTS (1<<0)
-
-struct imxuart_platform_data {
-	int (*init)(struct platform_device *pdev);
-	void (*exit)(struct platform_device *pdev);
-	unsigned int flags;
-};
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/io.h b/arch/arm/mach-imx/include/mach/io.h
deleted file mode 100644
index 9e197ae..0000000
--- a/arch/arm/mach-imx/include/mach/io.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *  arch/arm/mach-imxads/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)
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/irqs.h b/arch/arm/mach-imx/include/mach/irqs.h
deleted file mode 100644
index 67812c5..0000000
--- a/arch/arm/mach-imx/include/mach/irqs.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- *  arch/arm/mach-imxads/include/mach/irqs.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 __ARM_IRQS_H__
-#define __ARM_IRQS_H__
-
-/* Use the imx definitions */
-#include <mach/hardware.h>
-
-/*
- *  IMX Interrupt numbers
- *
- */
-#define INT_SOFTINT                 0
-#define CSI_INT                     6
-#define DSPA_MAC_INT                7
-#define DSPA_INT                    8
-#define COMP_INT                    9
-#define MSHC_XINT                   10
-#define GPIO_INT_PORTA              11
-#define GPIO_INT_PORTB              12
-#define GPIO_INT_PORTC              13
-#define LCDC_INT                    14
-#define SIM_INT                     15
-#define SIM_DATA_INT                16
-#define RTC_INT                     17
-#define RTC_SAMINT                  18
-#define UART2_MINT_PFERR            19
-#define UART2_MINT_RTS              20
-#define UART2_MINT_DTR              21
-#define UART2_MINT_UARTC            22
-#define UART2_MINT_TX               23
-#define UART2_MINT_RX               24
-#define UART1_MINT_PFERR            25
-#define UART1_MINT_RTS              26
-#define UART1_MINT_DTR              27
-#define UART1_MINT_UARTC            28
-#define UART1_MINT_TX               29
-#define UART1_MINT_RX               30
-#define VOICE_DAC_INT               31
-#define VOICE_ADC_INT               32
-#define PEN_DATA_INT                33
-#define PWM_INT                     34
-#define SDHC_INT                    35
-#define I2C_INT                     39
-#define CSPI_INT                    41
-#define SSI_TX_INT                  42
-#define SSI_TX_ERR_INT              43
-#define SSI_RX_INT                  44
-#define SSI_RX_ERR_INT              45
-#define TOUCH_INT                   46
-#define USBD_INT0                   47
-#define USBD_INT1                   48
-#define USBD_INT2                   49
-#define USBD_INT3                   50
-#define USBD_INT4                   51
-#define USBD_INT5                   52
-#define USBD_INT6                   53
-#define BTSYS_INT                   55
-#define BTTIM_INT                   56
-#define BTWUI_INT                   57
-#define TIM2_INT                    58
-#define TIM1_INT                    59
-#define DMA_ERR                     60
-#define DMA_INT                     61
-#define GPIO_INT_PORTD              62
-
-#define IMX_IRQS                         (64)
-
-/* note: the IMX has four gpio ports (A-D), but only
- *       the following pins are connected to the outside
- *       world:
- *
- * PORT A: bits 0-31
- * PORT B: bits 8-31
- * PORT C: bits 3-17
- * PORT D: bits 6-31
- *
- * We map these interrupts straight on. As a result we have
- * several holes in the interrupt mapping. We do this for two
- * reasons:
- *   - mapping the interrupts without holes would get
- *     far more complicated
- *   - Motorola could well decide to bring some processor
- *     with more pins connected
- */
-
-#define IRQ_GPIOA(x)  (IMX_IRQS + x)
-#define IRQ_GPIOB(x)  (IRQ_GPIOA(32) + x)
-#define IRQ_GPIOC(x)  (IRQ_GPIOB(32) + x)
-#define IRQ_GPIOD(x)  (IRQ_GPIOC(32) + x)
-
-/* decode irq number to use with IMR(x), ISR(x) and friends */
-#define IRQ_TO_REG(irq) ((irq - IMX_IRQS) >> 5)
-
-/* all normal IRQs can be FIQs */
-#define FIQ_START	0
-/* switch betwean IRQ and FIQ */
-extern int imx_set_irq_fiq(unsigned int irq, unsigned int type);
-
-#define NR_IRQS (IRQ_GPIOD(32) + 1)
-#define IRQ_GPIO(x)
-#endif
diff --git a/arch/arm/mach-imx/include/mach/memory.h b/arch/arm/mach-imx/include/mach/memory.h
deleted file mode 100644
index a93df7c..0000000
--- a/arch/arm/mach-imx/include/mach/memory.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  arch/arm/mach-imx/include/mach/memory.h
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2002 Shane Nay (shane@minirl.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 __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-#define PHYS_OFFSET	UL(0x08000000)
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/mmc.h b/arch/arm/mach-imx/include/mach/mmc.h
deleted file mode 100644
index 4712f35..0000000
--- a/arch/arm/mach-imx/include/mach/mmc.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef ASMARM_ARCH_MMC_H
-#define ASMARM_ARCH_MMC_H
-
-#include <linux/mmc/host.h>
-
-struct device;
-
-struct imxmmc_platform_data {
-	int (*card_present)(struct device *);
-	int (*get_ro)(struct device *);
-};
-
-extern void imx_set_mmc_info(struct imxmmc_platform_data *info);
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/mx1ads.h b/arch/arm/mach-imx/include/mach/mx1ads.h
deleted file mode 100644
index def05d5..0000000
--- a/arch/arm/mach-imx/include/mach/mx1ads.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * arch/arm/mach-imx/include/mach/mx1ads.h
- *
- * Copyright (C) 2004 Robert Schwebel, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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_MX1ADS_H
-#define __ASM_ARCH_MX1ADS_H
-
-/* ------------------------------------------------------------------------ */
-/* Memory Map for the M9328MX1ADS (MX1ADS) Board                            */
-/* ------------------------------------------------------------------------ */
-
-#define MX1ADS_FLASH_PHYS		0x10000000
-#define MX1ADS_FLASH_SIZE		(16*1024*1024)
-
-#define IMX_FB_PHYS			(0x0C000000 - 0x40000)
-
-#define CLK32 32000
-
-#endif /* __ASM_ARCH_MX1ADS_H */
diff --git a/arch/arm/mach-imx/include/mach/spi_imx.h b/arch/arm/mach-imx/include/mach/spi_imx.h
deleted file mode 100644
index 4186430..0000000
--- a/arch/arm/mach-imx/include/mach/spi_imx.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * arch/arm/mach-imx/include/mach/spi_imx.h
- *
- * Copyright (C) 2006 SWAPP
- *	Andrea Paterniani <a.paterniani@swapp-eng.it>
- *
- * Initial version inspired by:
- *	linux-2.6.17-rc3-mm1/arch/arm/mach-pxa/include/mach/pxa2xx_spi.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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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 SPI_IMX_H_
-#define SPI_IMX_H_
-
-
-/*-------------------------------------------------------------------------*/
-/**
- * struct spi_imx_master - device.platform_data for SPI controller devices.
- * @num_chipselect: chipselects are used to distinguish individual
- *	SPI slaves, and are numbered from zero to num_chipselects - 1.
- *	each slave has a chipselect signal, but it's common that not
- *	every chipselect is connected to a slave.
- * @enable_dma: if true enables DMA driven transfers.
-*/
-struct spi_imx_master {
-	u8 num_chipselect;
-	u8 enable_dma:1;
-};
-/*-------------------------------------------------------------------------*/
-
-
-/*-------------------------------------------------------------------------*/
-/**
- * struct spi_imx_chip - spi_board_info.controller_data for SPI
- * slave devices, copied to spi_device.controller_data.
- * @enable_loopback : used for test purpouse to internally connect RX and TX
- *	sections.
- * @enable_dma : enables dma transfer (provided that controller driver has
- *	dma enabled too).
- * @ins_ss_pulse : enable /SS pulse insertion between SPI burst.
- * @bclk_wait : number of bclk waits between each bits_per_word SPI burst.
- * @cs_control : function pointer to board-specific function to assert/deassert
- *	I/O port to control HW generation of devices chip-select.
-*/
-struct spi_imx_chip {
-	u8	enable_loopback:1;
-	u8	enable_dma:1;
-	u8	ins_ss_pulse:1;
-	u16	bclk_wait:15;
-	void (*cs_control)(u32 control);
-};
-
-/* Chip-select state */
-#define SPI_CS_ASSERT			(1 << 0)
-#define SPI_CS_DEASSERT			(1 << 1)
-/*-------------------------------------------------------------------------*/
-
-
-#endif /* SPI_IMX_H_*/
diff --git a/arch/arm/mach-imx/include/mach/system.h b/arch/arm/mach-imx/include/mach/system.h
deleted file mode 100644
index 46d4ca9..0000000
--- a/arch/arm/mach-imx/include/mach/system.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- *  arch/arm/mach-imxads/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 void
-arch_idle(void)
-{
-	/*
-	 * This should do all the clock switching
-	 * and wait for interrupt tricks
-	 */
-	cpu_do_idle();
-}
-
-static inline void
-arch_reset(char mode, const char *cmd)
-{
-	cpu_reset(0);
-}
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/timex.h b/arch/arm/mach-imx/include/mach/timex.h
deleted file mode 100644
index e22ba78..0000000
--- a/arch/arm/mach-imx/include/mach/timex.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  linux/include/asm-arm/imx/timex.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_ARCH_TIMEX_H
-#define __ASM_ARCH_TIMEX_H
-
-#define CLOCK_TICK_RATE		(16000000)
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/uncompress.h b/arch/arm/mach-imx/include/mach/uncompress.h
deleted file mode 100644
index 70523e6..0000000
--- a/arch/arm/mach-imx/include/mach/uncompress.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- *  arch/arm/mach-imxads/include/mach/uncompress.h
- *
- *
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) Shane Nay (shane@minirl.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
- */
-
-#define UART(x) (*(volatile unsigned long *)(serial_port + (x)))
-
-#define UART1_BASE 0x206000
-#define UART2_BASE 0x207000
-#define USR2 0x98
-#define USR2_TXFE (1<<14)
-#define TXR  0x40
-#define UCR1 0x80
-#define UCR1_UARTEN 1
-
-/*
- * The following code assumes the serial port has already been
- * initialized by the bootloader.  We search for the first enabled
- * port in the most probable order.  If you didn't setup a port in
- * your bootloader then nothing will appear (which might be desired).
- *
- * This does not append a newline
- */
-static void putc(int c)
-{
-	unsigned long serial_port;
-
-	do {
-		serial_port = UART1_BASE;
-		if ( UART(UCR1) & UCR1_UARTEN )
-			break;
-		serial_port = UART2_BASE;
-		if ( UART(UCR1) & UCR1_UARTEN )
-			break;
-		return;
-	} while(0);
-
-	while (!(UART(USR2) & USR2_TXFE))
-		barrier();
-
-	UART(TXR) = c;
-}
-
-static inline void flush(void)
-{
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_setup()
-
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-imx/include/mach/vmalloc.h b/arch/arm/mach-imx/include/mach/vmalloc.h
deleted file mode 100644
index 7d7cb0b..0000000
--- a/arch/arm/mach-imx/include/mach/vmalloc.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *  arch/arm/mach-imx/include/mach/vmalloc.h
- *
- *  Copyright (C) 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 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
- */
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff --git a/arch/arm/mach-imx/irq.c b/arch/arm/mach-imx/irq.c
deleted file mode 100644
index 531b95d..0000000
--- a/arch/arm/mach-imx/irq.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- *  linux/arch/arm/mach-imx/irq.c
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2002 Shane Nay (shane@minirl.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
- *
- *  03/03/2004   Sascha Hauer <sascha@saschahauer.de>
- *               Copied from the motorola bsp package and added gpio demux
- *               interrupt handler
- */
-
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <asm/mach/irq.h>
-
-/*
- *
- * We simply use the ENABLE DISABLE registers inside of the IMX
- * to turn on/off specific interrupts.
- *
- */
-
-#define INTCNTL_OFF               0x00
-#define NIMASK_OFF                0x04
-#define INTENNUM_OFF              0x08
-#define INTDISNUM_OFF             0x0C
-#define INTENABLEH_OFF            0x10
-#define INTENABLEL_OFF            0x14
-#define INTTYPEH_OFF              0x18
-#define INTTYPEL_OFF              0x1C
-#define NIPRIORITY_OFF(x)         (0x20+4*(7-(x)))
-#define NIVECSR_OFF               0x40
-#define FIVECSR_OFF               0x44
-#define INTSRCH_OFF               0x48
-#define INTSRCL_OFF               0x4C
-#define INTFRCH_OFF               0x50
-#define INTFRCL_OFF               0x54
-#define NIPNDH_OFF                0x58
-#define NIPNDL_OFF                0x5C
-#define FIPNDH_OFF                0x60
-#define FIPNDL_OFF                0x64
-
-#define VA_AITC_BASE              IO_ADDRESS(IMX_AITC_BASE)
-#define IMX_AITC_INTCNTL         (VA_AITC_BASE + INTCNTL_OFF)
-#define IMX_AITC_NIMASK          (VA_AITC_BASE + NIMASK_OFF)
-#define IMX_AITC_INTENNUM        (VA_AITC_BASE + INTENNUM_OFF)
-#define IMX_AITC_INTDISNUM       (VA_AITC_BASE + INTDISNUM_OFF)
-#define IMX_AITC_INTENABLEH      (VA_AITC_BASE + INTENABLEH_OFF)
-#define IMX_AITC_INTENABLEL      (VA_AITC_BASE + INTENABLEL_OFF)
-#define IMX_AITC_INTTYPEH        (VA_AITC_BASE + INTTYPEH_OFF)
-#define IMX_AITC_INTTYPEL        (VA_AITC_BASE + INTTYPEL_OFF)
-#define IMX_AITC_NIPRIORITY(x)   (VA_AITC_BASE + NIPRIORITY_OFF(x))
-#define IMX_AITC_NIVECSR         (VA_AITC_BASE + NIVECSR_OFF)
-#define IMX_AITC_FIVECSR         (VA_AITC_BASE + FIVECSR_OFF)
-#define IMX_AITC_INTSRCH         (VA_AITC_BASE + INTSRCH_OFF)
-#define IMX_AITC_INTSRCL         (VA_AITC_BASE + INTSRCL_OFF)
-#define IMX_AITC_INTFRCH         (VA_AITC_BASE + INTFRCH_OFF)
-#define IMX_AITC_INTFRCL         (VA_AITC_BASE + INTFRCL_OFF)
-#define IMX_AITC_NIPNDH          (VA_AITC_BASE + NIPNDH_OFF)
-#define IMX_AITC_NIPNDL          (VA_AITC_BASE + NIPNDL_OFF)
-#define IMX_AITC_FIPNDH          (VA_AITC_BASE + FIPNDH_OFF)
-#define IMX_AITC_FIPNDL          (VA_AITC_BASE + FIPNDL_OFF)
-
-#if 0
-#define DEBUG_IRQ(fmt...)	printk(fmt)
-#else
-#define DEBUG_IRQ(fmt...)	do { } while (0)
-#endif
-
-static void
-imx_mask_irq(unsigned int irq)
-{
-	__raw_writel(irq, IMX_AITC_INTDISNUM);
-}
-
-static void
-imx_unmask_irq(unsigned int irq)
-{
-	__raw_writel(irq, IMX_AITC_INTENNUM);
-}
-
-#ifdef CONFIG_FIQ
-int imx_set_irq_fiq(unsigned int irq, unsigned int type)
-{
-	unsigned int irqt;
-
-	if (irq >= IMX_IRQS)
-		return -EINVAL;
-
-	if (irq < IMX_IRQS / 2) {
-		irqt = __raw_readl(IMX_AITC_INTTYPEL) & ~(1 << irq);
-		__raw_writel(irqt | (!!type << irq), IMX_AITC_INTTYPEL);
-	} else {
-		irq -= IMX_IRQS / 2;
-		irqt = __raw_readl(IMX_AITC_INTTYPEH) & ~(1 << irq);
-		__raw_writel(irqt | (!!type << irq), IMX_AITC_INTTYPEH);
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(imx_set_irq_fiq);
-#endif /* CONFIG_FIQ */
-
-static int
-imx_gpio_irq_type(unsigned int _irq, unsigned int type)
-{
-	unsigned int irq_type = 0, irq, reg, bit;
-
-	irq = _irq - IRQ_GPIOA(0);
-	reg = irq >> 5;
-	bit = 1 << (irq % 32);
-
-	if (type == IRQ_TYPE_PROBE) {
-		/* Don't mess with enabled GPIOs using preconfigured edges or
-		   GPIOs set to alternate function during probe */
-		/* TODO: support probe */
-//              if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) &
-//                  GPIO_bit(gpio))
-//                      return 0;
-//              if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2)))
-//                      return 0;
-//              type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
-	}
-
-	GIUS(reg) |= bit;
-	DDIR(reg) &= ~(bit);
-
-	DEBUG_IRQ("setting type of irq %d to ", _irq);
-
-	if (type & IRQ_TYPE_EDGE_RISING) {
-		DEBUG_IRQ("rising edges\n");
-		irq_type = 0x0;
-	}
-	if (type & IRQ_TYPE_EDGE_FALLING) {
-		DEBUG_IRQ("falling edges\n");
-		irq_type = 0x1;
-	}
-	if (type & IRQ_TYPE_LEVEL_LOW) {
-		DEBUG_IRQ("low level\n");
-		irq_type = 0x3;
-	}
-	if (type & IRQ_TYPE_LEVEL_HIGH) {
-		DEBUG_IRQ("high level\n");
-		irq_type = 0x2;
-	}
-
-	if (irq % 32 < 16) {
-		ICR1(reg) = (ICR1(reg) & ~(0x3 << ((irq % 16) * 2))) |
-		    (irq_type << ((irq % 16) * 2));
-	} else {
-		ICR2(reg) = (ICR2(reg) & ~(0x3 << ((irq % 16) * 2))) |
-		    (irq_type << ((irq % 16) * 2));
-	}
-
-	return 0;
-
-}
-
-static void
-imx_gpio_ack_irq(unsigned int irq)
-{
-	DEBUG_IRQ("%s: irq %d\n", __func__, irq);
-	ISR(IRQ_TO_REG(irq)) = 1 << ((irq - IRQ_GPIOA(0)) % 32);
-}
-
-static void
-imx_gpio_mask_irq(unsigned int irq)
-{
-	DEBUG_IRQ("%s: irq %d\n", __func__, irq);
-	IMR(IRQ_TO_REG(irq)) &= ~( 1 << ((irq - IRQ_GPIOA(0)) % 32));
-}
-
-static void
-imx_gpio_unmask_irq(unsigned int irq)
-{
-	DEBUG_IRQ("%s: irq %d\n", __func__, irq);
-	IMR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32);
-}
-
-static void
-imx_gpio_handler(unsigned int mask, unsigned int irq,
-                 struct irq_desc *desc)
-{
-	while (mask) {
-		if (mask & 1) {
-			DEBUG_IRQ("handling irq %d\n", irq);
-			generic_handle_irq(irq);
-		}
-		irq++;
-		mask >>= 1;
-	}
-}
-
-static void
-imx_gpioa_demux_handler(unsigned int irq_unused, struct irq_desc *desc)
-{
-	unsigned int mask, irq;
-
-	mask = ISR(0);
-	irq = IRQ_GPIOA(0);
-	imx_gpio_handler(mask, irq, desc);
-}
-
-static void
-imx_gpiob_demux_handler(unsigned int irq_unused, struct irq_desc *desc)
-{
-	unsigned int mask, irq;
-
-	mask = ISR(1);
-	irq = IRQ_GPIOB(0);
-	imx_gpio_handler(mask, irq, desc);
-}
-
-static void
-imx_gpioc_demux_handler(unsigned int irq_unused, struct irq_desc *desc)
-{
-	unsigned int mask, irq;
-
-	mask = ISR(2);
-	irq = IRQ_GPIOC(0);
-	imx_gpio_handler(mask, irq, desc);
-}
-
-static void
-imx_gpiod_demux_handler(unsigned int irq_unused, struct irq_desc *desc)
-{
-	unsigned int mask, irq;
-
-	mask = ISR(3);
-	irq = IRQ_GPIOD(0);
-	imx_gpio_handler(mask, irq, desc);
-}
-
-static struct irq_chip imx_internal_chip = {
-	.name = "MPU",
-	.ack = imx_mask_irq,
-	.mask = imx_mask_irq,
-	.unmask = imx_unmask_irq,
-};
-
-static struct irq_chip imx_gpio_chip = {
-	.name = "GPIO",
-	.ack = imx_gpio_ack_irq,
-	.mask = imx_gpio_mask_irq,
-	.unmask = imx_gpio_unmask_irq,
-	.set_type = imx_gpio_irq_type,
-};
-
-void __init
-imx_init_irq(void)
-{
-	unsigned int irq;
-
-	DEBUG_IRQ("Initializing imx interrupts\n");
-
-	/* Disable all interrupts initially. */
-	/* Do not rely on the bootloader. */
-	__raw_writel(0, IMX_AITC_INTENABLEH);
-	__raw_writel(0, IMX_AITC_INTENABLEL);
-
-	/* Mask all GPIO interrupts as well */
-	IMR(0) = 0;
-	IMR(1) = 0;
-	IMR(2) = 0;
-	IMR(3) = 0;
-
-	for (irq = 0; irq < IMX_IRQS; irq++) {
-		set_irq_chip(irq, &imx_internal_chip);
-		set_irq_handler(irq, handle_level_irq);
-		set_irq_flags(irq, IRQF_VALID);
-	}
-
-	for (irq = IRQ_GPIOA(0); irq < IRQ_GPIOD(32); irq++) {
-		set_irq_chip(irq, &imx_gpio_chip);
-		set_irq_handler(irq, handle_edge_irq);
-		set_irq_flags(irq, IRQF_VALID);
-	}
-
-	set_irq_chained_handler(GPIO_INT_PORTA, imx_gpioa_demux_handler);
-	set_irq_chained_handler(GPIO_INT_PORTB, imx_gpiob_demux_handler);
-	set_irq_chained_handler(GPIO_INT_PORTC, imx_gpioc_demux_handler);
-	set_irq_chained_handler(GPIO_INT_PORTD, imx_gpiod_demux_handler);
-
-	/* Release masking of interrupts according to priority */
-	__raw_writel(-1, IMX_AITC_NIMASK);
-
-#ifdef CONFIG_FIQ
-	/* Initialize FIQ */
-	init_FIQ();
-#endif
-}
diff --git a/arch/arm/mach-imx/leds-mx1ads.c b/arch/arm/mach-imx/leds-mx1ads.c
deleted file mode 100644
index 1d48f27..0000000
--- a/arch/arm/mach-imx/leds-mx1ads.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * linux/arch/arm/mach-imx/leds-mx1ads.c
- *
- * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
- *
- * Original (leds-footbridge.c) by 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.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <mach/hardware.h>
-#include <asm/system.h>
-#include <asm/leds.h>
-#include "leds.h"
-
-/*
- * The MX1ADS Board has only one usable LED,
- * so select only the timer led or the
- * cpu usage led
- */
-void
-mx1ads_leds_event(led_event_t ledevt)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch (ledevt) {
-#ifdef CONFIG_LEDS_CPU
-	case led_idle_start:
-		DR(0) &= ~(1<<2);
-		break;
-
-	case led_idle_end:
-		DR(0) |= 1<<2;
-		break;
-#endif
-
-#ifdef CONFIG_LEDS_TIMER
-	case led_timer:
-		DR(0) ^= 1<<2;
-#endif
-	default:
-		break;
-	}
-	local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-imx/leds.c b/arch/arm/mach-imx/leds.c
deleted file mode 100644
index cf30803..0000000
--- a/arch/arm/mach-imx/leds.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * linux/arch/arm/mach-imx/leds.c
- *
- * Copyright (C) 2004 Sascha Hauer <sascha@saschahauer.de>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include "leds.h"
-
-static int __init
-leds_init(void)
-{
-	if (machine_is_mx1ads()) {
-		leds_event = mx1ads_leds_event;
-	}
-
-	return 0;
-}
-
-__initcall(leds_init);
diff --git a/arch/arm/mach-imx/leds.h b/arch/arm/mach-imx/leds.h
deleted file mode 100644
index 49dc1c1..0000000
--- a/arch/arm/mach-imx/leds.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * arch/arm/mach-imx/leds.h
- *
- * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
- *
- * blinky lights for IMX-based systems
- *
- */
-extern void mx1ads_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c
deleted file mode 100644
index 87fa1ff..0000000
--- a/arch/arm/mach-imx/mx1ads.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * arch/arm/mach-imx/mx1ads.c
- *
- * Initially based on:
- *	linux-2.6.7-imx/arch/arm/mach-imx/scb9328.c
- *	Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
- *
- * 2004 (c) MontaVista Software, Inc.
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <asm/system.h>
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-
-#include <asm/mach/map.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/arch.h>
-#include <mach/mmc.h>
-#include <mach/imx-uart.h>
-#include <linux/interrupt.h>
-#include "generic.h"
-
-static struct resource cs89x0_resources[] = {
-	[0] = {
-		.start	= IMX_CS4_PHYS + 0x300,
-		.end	= IMX_CS4_PHYS + 0x300 + 16,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_GPIOC(17),
-		.end	= IRQ_GPIOC(17),
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device cs89x0_device = {
-	.name		= "cirrus-cs89x0",
-	.num_resources	= ARRAY_SIZE(cs89x0_resources),
-	.resource	= cs89x0_resources,
-};
-
-static struct imxuart_platform_data uart_pdata = {
-	.flags = IMXUART_HAVE_RTSCTS,
-};
-
-static struct resource imx_uart1_resources[] = {
-	[0] = {
-		.start	= 0x00206000,
-		.end	= 0x002060FF,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= (UART1_MINT_RX),
-		.end	= (UART1_MINT_RX),
-		.flags	= IORESOURCE_IRQ,
-	},
-	[2] = {
-		.start	= (UART1_MINT_TX),
-		.end	= (UART1_MINT_TX),
-		.flags	= IORESOURCE_IRQ,
-	},
-	[3] = {
-		.start	= UART1_MINT_RTS,
-		.end	= UART1_MINT_RTS,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device imx_uart1_device = {
-	.name		= "imx-uart",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(imx_uart1_resources),
-	.resource	= imx_uart1_resources,
-	.dev = {
-		.platform_data = &uart_pdata,
-	}
-};
-
-static struct resource imx_uart2_resources[] = {
-	[0] = {
-		.start	= 0x00207000,
-		.end	= 0x002070FF,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= (UART2_MINT_RX),
-		.end	= (UART2_MINT_RX),
-		.flags	= IORESOURCE_IRQ,
-	},
-	[2] = {
-		.start	= (UART2_MINT_TX),
-		.end	= (UART2_MINT_TX),
-		.flags	= IORESOURCE_IRQ,
-	},
-	[3] = {
-		.start	= UART2_MINT_RTS,
-		.end	= UART2_MINT_RTS,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device imx_uart2_device = {
-	.name		= "imx-uart",
-	.id		= 1,
-	.num_resources	= ARRAY_SIZE(imx_uart2_resources),
-	.resource	= imx_uart2_resources,
-	.dev = {
-		.platform_data = &uart_pdata,
-	}
-};
-
-static struct platform_device *devices[] __initdata = {
-	&cs89x0_device,
-	&imx_uart1_device,
-	&imx_uart2_device,
-};
-
-#if defined(CONFIG_MMC_IMX) || defined(CONFIG_MMC_IMX_MODULE)
-static int mx1ads_mmc_card_present(struct device *dev)
-{
-	/* MMC/SD Card Detect is PB 20 on MX1ADS V1.0.7 */
-	return (SSR(1) & (1 << 20) ? 0 : 1);
-}
-
-static struct imxmmc_platform_data mx1ads_mmc_info = {
-       .card_present = mx1ads_mmc_card_present,
-};
-#endif
-
-static void __init
-mx1ads_init(void)
-{
-#ifdef CONFIG_LEDS
-	imx_gpio_mode(GPIO_PORTA | GPIO_OUT | 2);
-#endif
-#if defined(CONFIG_MMC_IMX) || defined(CONFIG_MMC_IMX_MODULE)
-	/* SD/MMC card detect */
-	imx_gpio_mode(GPIO_PORTB | GPIO_GIUS | GPIO_IN | 20);
-	imx_set_mmc_info(&mx1ads_mmc_info);
-#endif
-
-	imx_gpio_mode(PC9_PF_UART1_CTS);
-	imx_gpio_mode(PC10_PF_UART1_RTS);
-	imx_gpio_mode(PC11_PF_UART1_TXD);
-	imx_gpio_mode(PC12_PF_UART1_RXD);
-
-	imx_gpio_mode(PB28_PF_UART2_CTS);
-	imx_gpio_mode(PB29_PF_UART2_RTS);
-	imx_gpio_mode(PB30_PF_UART2_TXD);
-	imx_gpio_mode(PB31_PF_UART2_RXD);
-
-	platform_add_devices(devices, ARRAY_SIZE(devices));
-}
-
-static void __init
-mx1ads_map_io(void)
-{
-	imx_map_io();
-}
-
-MACHINE_START(MX1ADS, "Motorola MX1ADS")
-	/* Maintainer: Sascha Hauer, Pengutronix */
-	.phys_io	= 0x00200000,
-	.io_pg_offst	= ((0xe0000000) >> 18) & 0xfffc,
-	.boot_params	= 0x08000100,
-	.map_io		= mx1ads_map_io,
-	.init_irq	= imx_init_irq,
-	.timer		= &imx_timer,
-	.init_machine	= mx1ads_init,
-MACHINE_END
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
deleted file mode 100644
index 5aef18b..0000000
--- a/arch/arm/mach-imx/time.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- *  linux/arch/arm/mach-imx/time.c
- *
- *  Copyright (C) 2000-2001 Deep Blue Solutions
- *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
- *  Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.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/sched.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/time.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/irq.h>
-#include <asm/mach/time.h>
-
-/* Use timer 1 as system timer */
-#define TIMER_BASE IMX_TIM1_BASE
-
-static struct clock_event_device clockevent_imx;
-static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
-
-/*
- * IRQ handler for the timer
- */
-static irqreturn_t
-imx_timer_interrupt(int irq, void *dev_id)
-{
-	struct clock_event_device *evt = &clockevent_imx;
-	uint32_t tstat;
-	irqreturn_t ret = IRQ_NONE;
-
-	/* clear the interrupt */
-	tstat = IMX_TSTAT(TIMER_BASE);
-	IMX_TSTAT(TIMER_BASE) = 0;
-
-	if (tstat & TSTAT_COMP) {
-		evt->event_handler(evt);
-		ret = IRQ_HANDLED;
-	}
-
-	return ret;
-}
-
-static struct irqaction imx_timer_irq = {
-	.name		= "i.MX Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-	.handler	= imx_timer_interrupt,
-};
-
-/*
- * Set up timer hardware into expected mode and state.
- */
-static void __init imx_timer_hardware_init(void)
-{
-	/*
-	 * Initialise to a known state (all timers off, and timing reset)
-	 */
-	IMX_TCTL(TIMER_BASE) = 0;
-	IMX_TPRER(TIMER_BASE) = 0;
-
-	IMX_TCTL(TIMER_BASE) = TCTL_FRR | TCTL_CLK_PCLK1 | TCTL_TEN;
-}
-
-cycle_t imx_get_cycles(struct clocksource *cs)
-{
-	return IMX_TCN(TIMER_BASE);
-}
-
-static struct clocksource clocksource_imx = {
-	.name 		= "imx_timer1",
-	.rating		= 200,
-	.read		= imx_get_cycles,
-	.mask		= 0xFFFFFFFF,
-	.shift 		= 20,
-	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static int __init imx_clocksource_init(unsigned long rate)
-{
-	clocksource_imx.mult =
-		clocksource_hz2mult(rate, clocksource_imx.shift);
-	clocksource_register(&clocksource_imx);
-
-	return 0;
-}
-
-static int imx_set_next_event(unsigned long evt,
-				  struct clock_event_device *unused)
-{
-	unsigned long tcmp;
-
-	tcmp = IMX_TCN(TIMER_BASE) + evt;
-	IMX_TCMP(TIMER_BASE) = tcmp;
-
-	return (int32_t)(tcmp - IMX_TCN(TIMER_BASE)) < 0 ? -ETIME : 0;
-}
-
-#ifdef DEBUG
-static const char *clock_event_mode_label[]={
-	[CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
-	[CLOCK_EVT_MODE_ONESHOT]  = "CLOCK_EVT_MODE_ONESHOT",
-	[CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
-	[CLOCK_EVT_MODE_UNUSED]   = "CLOCK_EVT_MODE_UNUSED"
-};
-#endif /*DEBUG*/
-
-static void imx_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
-{
-	unsigned long flags;
-
-	/*
-	 * The timer interrupt generation is disabled at least
-	 * for enough time to call imx_set_next_event()
-	 */
-	local_irq_save(flags);
-	/* Disable interrupt in GPT module */
-	IMX_TCTL(TIMER_BASE) &= ~TCTL_IRQEN;
-	if (mode != clockevent_mode) {
-		/* Set event time into far-far future */
-		IMX_TCMP(TIMER_BASE) = IMX_TCN(TIMER_BASE) - 3;
-		/* Clear pending interrupt */
-		IMX_TSTAT(TIMER_BASE) &= ~TSTAT_COMP;
-	}
-
-#ifdef DEBUG
-	printk(KERN_INFO "imx_set_mode: changing mode from %s to %s\n",
-		clock_event_mode_label[clockevent_mode], clock_event_mode_label[mode]);
-#endif /*DEBUG*/
-
-	/* Remember timer mode */
-	clockevent_mode = mode;
-	local_irq_restore(flags);
-
-	switch (mode) {
-	case CLOCK_EVT_MODE_PERIODIC:
-		printk(KERN_ERR "imx_set_mode: Periodic mode is not supported for i.MX\n");
-		break;
-	case CLOCK_EVT_MODE_ONESHOT:
-		/*
-		 * Do not put overhead of interrupt enable/disable into
-		 * imx_set_next_event(), the core has about 4 minutes
-		 * to call imx_set_next_event() or shutdown clock after
-		 * mode switching
-		 */
-		local_irq_save(flags);
-		IMX_TCTL(TIMER_BASE) |= TCTL_IRQEN;
-		local_irq_restore(flags);
-		break;
-	case CLOCK_EVT_MODE_SHUTDOWN:
-	case CLOCK_EVT_MODE_UNUSED:
-	case CLOCK_EVT_MODE_RESUME:
-		/* Left event sources disabled, no more interrupts appears */
-		break;
-	}
-}
-
-static struct clock_event_device clockevent_imx = {
-	.name		= "imx_timer1",
-	.features	= CLOCK_EVT_FEAT_ONESHOT,
-	.shift		= 32,
-	.set_mode	= imx_set_mode,
-	.set_next_event	= imx_set_next_event,
-	.rating		= 200,
-};
-
-static int __init imx_clockevent_init(unsigned long rate)
-{
-	clockevent_imx.mult = div_sc(rate, NSEC_PER_SEC,
-					clockevent_imx.shift);
-	clockevent_imx.max_delta_ns =
-		clockevent_delta2ns(0xfffffffe, &clockevent_imx);
-	clockevent_imx.min_delta_ns =
-		clockevent_delta2ns(0xf, &clockevent_imx);
-
-	clockevent_imx.cpumask = cpumask_of(0);
-
-	clockevents_register_device(&clockevent_imx);
-
-	return 0;
-}
-
-extern int imx_clocks_init(void);
-
-static void __init imx_timer_init(void)
-{
-	struct clk *clk;
-	unsigned long rate;
-
-	imx_clocks_init();
-
-	clk = clk_get(NULL, "perclk1");
-	clk_enable(clk);
-	rate = clk_get_rate(clk);
-
-	imx_timer_hardware_init();
-	imx_clocksource_init(rate);
-
-	imx_clockevent_init(rate);
-
-	/*
-	 * Make irqs happen for the system timer
-	 */
-	setup_irq(TIM1_INT, &imx_timer_irq);
-}
-
-struct sys_timer imx_timer = {
-	.init		= imx_timer_init,
-};
diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
index 2c5a02b..264f4d5 100644
--- a/arch/arm/mach-ixp4xx/Kconfig
+++ b/arch/arm/mach-ixp4xx/Kconfig
@@ -78,6 +78,12 @@
 	  IXDP465 Development Platform (Also known as BMP).
 	  For more information on this platform, see <file:Documentation/arm/IXP4xx>.
 
+config MACH_GORAMO_MLR
+	bool "GORAMO Multi Link Router"
+	help
+	  Say 'Y' here if you want your kernel to support GORAMO
+	  MultiLink router.
+
 config MACH_KIXRP435
 	bool "KIXRP435"
 	help
diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
index 2e6bbf9..47d1f60 100644
--- a/arch/arm/mach-ixp4xx/Makefile
+++ b/arch/arm/mach-ixp4xx/Makefile
@@ -30,6 +30,7 @@
 obj-$(CONFIG_MACH_GATEWAY7001)	+= gateway7001-setup.o
 obj-$(CONFIG_MACH_WG302V2)	+= wg302v2-setup.o
 obj-$(CONFIG_MACH_FSG)		+= fsg-setup.o
+obj-$(CONFIG_MACH_GORAMO_MLR)	+= goramo_mlr.o
 
 obj-$(CONFIG_PCI)		+= $(obj-pci-$(CONFIG_PCI)) common-pci.o
 obj-$(CONFIG_IXP4XX_QMGR)	+= ixp4xx_qmgr.o
diff --git a/arch/arm/mach-ixp4xx/goramo_mlr.c b/arch/arm/mach-ixp4xx/goramo_mlr.c
new file mode 100644
index 0000000..a733b8f
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/goramo_mlr.c
@@ -0,0 +1,507 @@
+/*
+ * Goramo MultiLink router platform code
+ * Copyright (C) 2006-2009 Krzysztof Halasa <khc@pm.waw.pl>
+ */
+
+#include <linux/delay.h>
+#include <linux/hdlc.h>
+#include <linux/i2c-gpio.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#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>
+
+#define xgpio_irq(n)		(IRQ_IXP4XX_GPIO ## n)
+#define gpio_irq(n)		xgpio_irq(n)
+
+#define SLOT_ETHA		0x0B	/* IDSEL = AD21 */
+#define SLOT_ETHB		0x0C	/* IDSEL = AD20 */
+#define SLOT_MPCI		0x0D	/* IDSEL = AD19 */
+#define SLOT_NEC		0x0E	/* IDSEL = AD18 */
+
+#define IRQ_ETHA		IRQ_IXP4XX_GPIO4
+#define IRQ_ETHB		IRQ_IXP4XX_GPIO5
+#define IRQ_NEC			IRQ_IXP4XX_GPIO3
+#define IRQ_MPCI		IRQ_IXP4XX_GPIO12
+
+/* GPIO lines */
+#define GPIO_SCL		0
+#define GPIO_SDA		1
+#define GPIO_STR		2
+#define GPIO_HSS0_DCD_N		6
+#define GPIO_HSS1_DCD_N		7
+#define GPIO_HSS0_CTS_N		10
+#define GPIO_HSS1_CTS_N		11
+#define GPIO_HSS1_RTS_N		13
+#define GPIO_HSS0_RTS_N		14
+
+/* Control outputs from 74HC4094 */
+#define CONTROL_HSS0_CLK_INT	0
+#define CONTROL_HSS1_CLK_INT	1
+#define CONTROL_HSS0_DTR_N	2
+#define CONTROL_HSS1_DTR_N	3
+#define CONTROL_EXT		4
+#define CONTROL_AUTO_RESET	5
+#define CONTROL_PCI_RESET_N	6
+#define CONTROL_EEPROM_WC_N	7
+
+/* offsets from start of flash ROM = 0x50000000 */
+#define CFG_ETH0_ADDRESS	0x40 /* 6 bytes */
+#define CFG_ETH1_ADDRESS	0x46 /* 6 bytes */
+#define CFG_REV			0x4C /* u32 */
+#define CFG_SDRAM_SIZE		0x50 /* u32 */
+#define CFG_SDRAM_CONF		0x54 /* u32 */
+#define CFG_SDRAM_MODE		0x58 /* u32 */
+#define CFG_SDRAM_REFRESH	0x5C /* u32 */
+
+#define CFG_HW_BITS		0x60 /* u32 */
+#define  CFG_HW_USB_PORTS	0x00000007 /* 0 = no NEC chip, 1-5 = ports # */
+#define  CFG_HW_HAS_PCI_SLOT	0x00000008
+#define  CFG_HW_HAS_ETH0	0x00000010
+#define  CFG_HW_HAS_ETH1	0x00000020
+#define  CFG_HW_HAS_HSS0	0x00000040
+#define  CFG_HW_HAS_HSS1	0x00000080
+#define  CFG_HW_HAS_UART0	0x00000100
+#define  CFG_HW_HAS_UART1	0x00000200
+#define  CFG_HW_HAS_EEPROM	0x00000400
+
+#define FLASH_CMD_READ_ARRAY	0xFF
+#define FLASH_CMD_READ_ID	0x90
+#define FLASH_SER_OFF		0x102 /* 0x81 in 16-bit mode */
+
+static u32 hw_bits = 0xFFFFFFFD;    /* assume all hardware present */;
+static u8 control_value;
+
+static void set_scl(u8 value)
+{
+	gpio_line_set(GPIO_SCL, !!value);
+	udelay(3);
+}
+
+static void set_sda(u8 value)
+{
+	gpio_line_set(GPIO_SDA, !!value);
+	udelay(3);
+}
+
+static void set_str(u8 value)
+{
+	gpio_line_set(GPIO_STR, !!value);
+	udelay(3);
+}
+
+static inline void set_control(int line, int value)
+{
+	if (value)
+		control_value |=  (1 << line);
+	else
+		control_value &= ~(1 << line);
+}
+
+
+static void output_control(void)
+{
+	int i;
+
+	gpio_line_config(GPIO_SCL, IXP4XX_GPIO_OUT);
+	gpio_line_config(GPIO_SDA, IXP4XX_GPIO_OUT);
+
+	for (i = 0; i < 8; i++) {
+		set_scl(0);
+		set_sda(control_value & (0x80 >> i)); /* MSB first */
+		set_scl(1);	/* active edge */
+	}
+
+	set_str(1);
+	set_str(0);
+
+	set_scl(0);
+	set_sda(1);		/* Be ready for START */
+	set_scl(1);
+}
+
+
+static void (*set_carrier_cb_tab[2])(void *pdev, int carrier);
+
+static int hss_set_clock(int port, unsigned int clock_type)
+{
+	int ctrl_int = port ? CONTROL_HSS1_CLK_INT : CONTROL_HSS0_CLK_INT;
+
+	switch (clock_type) {
+	case CLOCK_DEFAULT:
+	case CLOCK_EXT:
+		set_control(ctrl_int, 0);
+		output_control();
+		return CLOCK_EXT;
+
+	case CLOCK_INT:
+		set_control(ctrl_int, 1);
+		output_control();
+		return CLOCK_INT;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static irqreturn_t hss_dcd_irq(int irq, void *pdev)
+{
+	int i, port = (irq == gpio_irq(GPIO_HSS1_DCD_N));
+	gpio_line_get(port ? GPIO_HSS1_DCD_N : GPIO_HSS0_DCD_N, &i);
+	set_carrier_cb_tab[port](pdev, !i);
+	return IRQ_HANDLED;
+}
+
+
+static int hss_open(int port, void *pdev,
+		    void (*set_carrier_cb)(void *pdev, int carrier))
+{
+	int i, irq;
+
+	if (!port)
+		irq = gpio_irq(GPIO_HSS0_DCD_N);
+	else
+		irq = gpio_irq(GPIO_HSS1_DCD_N);
+
+	gpio_line_get(port ? GPIO_HSS1_DCD_N : GPIO_HSS0_DCD_N, &i);
+	set_carrier_cb(pdev, !i);
+
+	set_carrier_cb_tab[!!port] = set_carrier_cb;
+
+	if ((i = request_irq(irq, hss_dcd_irq, 0, "IXP4xx HSS", pdev)) != 0) {
+		printk(KERN_ERR "ixp4xx_hss: failed to request IRQ%i (%i)\n",
+		       irq, i);
+		return i;
+	}
+
+	set_control(port ? CONTROL_HSS1_DTR_N : CONTROL_HSS0_DTR_N, 0);
+	output_control();
+	gpio_line_set(port ? GPIO_HSS1_RTS_N : GPIO_HSS0_RTS_N, 0);
+	return 0;
+}
+
+static void hss_close(int port, void *pdev)
+{
+	free_irq(port ? gpio_irq(GPIO_HSS1_DCD_N) : gpio_irq(GPIO_HSS0_DCD_N),
+		 pdev);
+	set_carrier_cb_tab[!!port] = NULL; /* catch bugs */
+
+	set_control(port ? CONTROL_HSS1_DTR_N : CONTROL_HSS0_DTR_N, 1);
+	output_control();
+	gpio_line_set(port ? GPIO_HSS1_RTS_N : GPIO_HSS0_RTS_N, 1);
+}
+
+
+/* Flash memory */
+static struct flash_platform_data flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 2,
+};
+
+static struct resource flash_resource = {
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device device_flash = {
+	.name		= "IXP4XX-Flash",
+	.id		= 0,
+	.dev		= { .platform_data = &flash_data },
+	.num_resources	= 1,
+	.resource	= &flash_resource,
+};
+
+
+/* I^2C interface */
+static struct i2c_gpio_platform_data i2c_data = {
+	.sda_pin	= GPIO_SDA,
+	.scl_pin	= GPIO_SCL,
+};
+
+static struct platform_device device_i2c = {
+	.name		= "i2c-gpio",
+	.id		= 0,
+	.dev		= { .platform_data = &i2c_data },
+};
+
+
+/* IXP425 2 UART ports */
+static struct resource uart_resources[] = {
+	{
+		.start		= IXP4XX_UART1_BASE_PHYS,
+		.end		= IXP4XX_UART1_BASE_PHYS + 0x0fff,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= IXP4XX_UART2_BASE_PHYS,
+		.end		= IXP4XX_UART2_BASE_PHYS + 0x0fff,
+		.flags		= IORESOURCE_MEM,
+	}
+};
+
+static struct plat_serial8250_port uart_data[] = {
+	{
+		.mapbase	= IXP4XX_UART1_BASE_PHYS,
+		.membase	= (char __iomem *)IXP4XX_UART1_BASE_VIRT +
+			REG_OFFSET,
+		.irq		= IRQ_IXP4XX_UART1,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= IXP4XX_UART_XTAL,
+	},
+	{
+		.mapbase	= IXP4XX_UART2_BASE_PHYS,
+		.membase	= (char __iomem *)IXP4XX_UART2_BASE_VIRT +
+			REG_OFFSET,
+		.irq		= IRQ_IXP4XX_UART2,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= IXP4XX_UART_XTAL,
+	},
+	{ },
+};
+
+static struct platform_device device_uarts = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev.platform_data	= uart_data,
+	.num_resources		= 2,
+	.resource		= uart_resources,
+};
+
+
+/* Built-in 10/100 Ethernet MAC interfaces */
+static struct eth_plat_info eth_plat[] = {
+	{
+		.phy		= 0,
+		.rxq		= 3,
+		.txreadyq	= 32,
+	}, {
+		.phy		= 1,
+		.rxq		= 4,
+		.txreadyq	= 33,
+	}
+};
+
+static struct platform_device device_eth_tab[] = {
+	{
+		.name			= "ixp4xx_eth",
+		.id			= IXP4XX_ETH_NPEB,
+		.dev.platform_data	= eth_plat,
+	}, {
+		.name			= "ixp4xx_eth",
+		.id			= IXP4XX_ETH_NPEC,
+		.dev.platform_data	= eth_plat + 1,
+	}
+};
+
+
+/* IXP425 2 synchronous serial ports */
+static struct hss_plat_info hss_plat[] = {
+	{
+		.set_clock	= hss_set_clock,
+		.open		= hss_open,
+		.close		= hss_close,
+		.txreadyq	= 34,
+	}, {
+		.set_clock	= hss_set_clock,
+		.open		= hss_open,
+		.close		= hss_close,
+		.txreadyq	= 35,
+	}
+};
+
+static struct platform_device device_hss_tab[] = {
+	{
+		.name			= "ixp4xx_hss",
+		.id			= 0,
+		.dev.platform_data	= hss_plat,
+	}, {
+		.name			= "ixp4xx_hss",
+		.id			= 1,
+		.dev.platform_data	= hss_plat + 1,
+	}
+};
+
+
+static struct platform_device *device_tab[6] __initdata = {
+	&device_flash,		/* index 0 */
+};
+
+static inline u8 __init flash_readb(u8 __iomem *flash, u32 addr)
+{
+#ifdef __ARMEB__
+	return __raw_readb(flash + addr);
+#else
+	return __raw_readb(flash + (addr ^ 3));
+#endif
+}
+
+static inline u16 __init flash_readw(u8 __iomem *flash, u32 addr)
+{
+#ifdef __ARMEB__
+	return __raw_readw(flash + addr);
+#else
+	return __raw_readw(flash + (addr ^ 2));
+#endif
+}
+
+static void __init gmlr_init(void)
+{
+	u8 __iomem *flash;
+	int i, devices = 1; /* flash */
+
+	ixp4xx_sys_init();
+
+	if ((flash = ioremap(IXP4XX_EXP_BUS_BASE_PHYS, 0x80)) == NULL)
+		printk(KERN_ERR "goramo-mlr: unable to access system"
+		       " configuration data\n");
+	else {
+		system_rev = __raw_readl(flash + CFG_REV);
+		hw_bits = __raw_readl(flash + CFG_HW_BITS);
+
+		for (i = 0; i < ETH_ALEN; i++) {
+			eth_plat[0].hwaddr[i] =
+				flash_readb(flash, CFG_ETH0_ADDRESS + i);
+			eth_plat[1].hwaddr[i] =
+				flash_readb(flash, CFG_ETH1_ADDRESS + i);
+		}
+
+		__raw_writew(FLASH_CMD_READ_ID, flash);
+		system_serial_high = flash_readw(flash, FLASH_SER_OFF);
+		system_serial_high <<= 16;
+		system_serial_high |= flash_readw(flash, FLASH_SER_OFF + 2);
+		system_serial_low = flash_readw(flash, FLASH_SER_OFF + 4);
+		system_serial_low <<= 16;
+		system_serial_low |= flash_readw(flash, FLASH_SER_OFF + 6);
+		__raw_writew(FLASH_CMD_READ_ARRAY, flash);
+
+		iounmap(flash);
+	}
+
+	switch (hw_bits & (CFG_HW_HAS_UART0 | CFG_HW_HAS_UART1)) {
+	case CFG_HW_HAS_UART0:
+		memset(&uart_data[1], 0, sizeof(uart_data[1]));
+		device_uarts.num_resources = 1;
+		break;
+
+	case CFG_HW_HAS_UART1:
+		device_uarts.dev.platform_data = &uart_data[1];
+		device_uarts.resource = &uart_resources[1];
+		device_uarts.num_resources = 1;
+		break;
+	}
+	if (hw_bits & (CFG_HW_HAS_UART0 | CFG_HW_HAS_UART1))
+		device_tab[devices++] = &device_uarts; /* max index 1 */
+
+	if (hw_bits & CFG_HW_HAS_ETH0)
+		device_tab[devices++] = &device_eth_tab[0]; /* max index 2 */
+	if (hw_bits & CFG_HW_HAS_ETH1)
+		device_tab[devices++] = &device_eth_tab[1]; /* max index 3 */
+
+	if (hw_bits & CFG_HW_HAS_HSS0)
+		device_tab[devices++] = &device_hss_tab[0]; /* max index 4 */
+	if (hw_bits & CFG_HW_HAS_HSS1)
+		device_tab[devices++] = &device_hss_tab[1]; /* max index 5 */
+
+	if (hw_bits & CFG_HW_HAS_EEPROM)
+		device_tab[devices++] = &device_i2c; /* max index 6 */
+
+	gpio_line_config(GPIO_SCL, IXP4XX_GPIO_OUT);
+	gpio_line_config(GPIO_SDA, IXP4XX_GPIO_OUT);
+	gpio_line_config(GPIO_STR, IXP4XX_GPIO_OUT);
+	gpio_line_config(GPIO_HSS0_RTS_N, IXP4XX_GPIO_OUT);
+	gpio_line_config(GPIO_HSS1_RTS_N, IXP4XX_GPIO_OUT);
+	gpio_line_config(GPIO_HSS0_DCD_N, IXP4XX_GPIO_IN);
+	gpio_line_config(GPIO_HSS1_DCD_N, IXP4XX_GPIO_IN);
+	set_irq_type(gpio_irq(GPIO_HSS0_DCD_N), IRQ_TYPE_EDGE_BOTH);
+	set_irq_type(gpio_irq(GPIO_HSS1_DCD_N), IRQ_TYPE_EDGE_BOTH);
+
+	set_control(CONTROL_HSS0_DTR_N, 1);
+	set_control(CONTROL_HSS1_DTR_N, 1);
+	set_control(CONTROL_EEPROM_WC_N, 1);
+	set_control(CONTROL_PCI_RESET_N, 1);
+	output_control();
+
+	msleep(1);	      /* Wait for PCI devices to initialize */
+
+	flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
+	flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
+
+	platform_add_devices(device_tab, devices);
+}
+
+
+#ifdef CONFIG_PCI
+static void __init gmlr_pci_preinit(void)
+{
+	set_irq_type(IRQ_ETHA, IRQ_TYPE_LEVEL_LOW);
+	set_irq_type(IRQ_ETHB, IRQ_TYPE_LEVEL_LOW);
+	set_irq_type(IRQ_NEC, IRQ_TYPE_LEVEL_LOW);
+	set_irq_type(IRQ_MPCI, IRQ_TYPE_LEVEL_LOW);
+	ixp4xx_pci_preinit();
+}
+
+static void __init gmlr_pci_postinit(void)
+{
+	if ((hw_bits & CFG_HW_USB_PORTS) >= 2 &&
+	    (hw_bits & CFG_HW_USB_PORTS) < 5) {
+		/* need to adjust number of USB ports on NEC chip */
+		u32 value, addr = BIT(32 - SLOT_NEC) | 0xE0;
+		if (!ixp4xx_pci_read(addr, NP_CMD_CONFIGREAD, &value)) {
+			value &= ~7;
+			value |= (hw_bits & CFG_HW_USB_PORTS);
+			ixp4xx_pci_write(addr, NP_CMD_CONFIGWRITE, value);
+		}
+	}
+}
+
+static int __init gmlr_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	switch(slot) {
+	case SLOT_ETHA:	return IRQ_ETHA;
+	case SLOT_ETHB:	return IRQ_ETHB;
+	case SLOT_NEC:	return IRQ_NEC;
+	default:	return IRQ_MPCI;
+	}
+}
+
+static struct hw_pci gmlr_hw_pci __initdata = {
+	.nr_controllers = 1,
+	.preinit	= gmlr_pci_preinit,
+	.postinit	= gmlr_pci_postinit,
+	.swizzle	= pci_std_swizzle,
+	.setup		= ixp4xx_setup,
+	.scan		= ixp4xx_scan_bus,
+	.map_irq	= gmlr_map_irq,
+};
+
+static int __init gmlr_pci_init(void)
+{
+	if (machine_is_goramo_mlr() &&
+	    (hw_bits & (CFG_HW_USB_PORTS | CFG_HW_HAS_PCI_SLOT)))
+		pci_common_init(&gmlr_hw_pci);
+	return 0;
+}
+
+subsys_initcall(gmlr_pci_init);
+#endif /* CONFIG_PCI */
+
+
+MACHINE_START(GORAMO_MLR, "MultiLink")
+	/* Maintainer: Krzysztof Halasa */
+	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
+	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
+	.map_io		= ixp4xx_map_io,
+	.init_irq	= ixp4xx_init_irq,
+	.timer		= &ixp4xx_timer,
+	.boot_params	= 0x0100,
+	.init_machine	= gmlr_init,
+MACHINE_END
diff --git a/arch/arm/mach-ixp4xx/include/mach/cpu.h b/arch/arm/mach-ixp4xx/include/mach/cpu.h
index def7773..b2ef65d 100644
--- a/arch/arm/mach-ixp4xx/include/mach/cpu.h
+++ b/arch/arm/mach-ixp4xx/include/mach/cpu.h
@@ -26,6 +26,8 @@
 #define IXP46X_PROCESSOR_ID_VALUE	0x69054200 /* including IXP455 */
 #define IXP46X_PROCESSOR_ID_MASK	0xfffffff0
 
+#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \
+				IXP42X_PROCESSOR_ID_VALUE)
 #define cpu_is_ixp42x()	((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \
 			 IXP42X_PROCESSOR_ID_VALUE)
 #define cpu_is_ixp43x()	((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \
@@ -35,8 +37,11 @@
 
 static inline u32 ixp4xx_read_feature_bits(void)
 {
-	unsigned int val = ~*IXP4XX_EXP_CFG2;
+	u32 val = ~*IXP4XX_EXP_CFG2;
 
+	if (cpu_is_ixp42x_rev_a0())
+		return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP |
+					       IXP4XX_FEATURE_AES);
 	if (cpu_is_ixp42x())
 		return val & IXP42X_FEATURE_MASK;
 	if (cpu_is_ixp43x())
diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
index 0cbe6ce..9e7cad2 100644
--- a/arch/arm/mach-ixp4xx/include/mach/qmgr.h
+++ b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
@@ -15,7 +15,7 @@
 #define DEBUG_QMGR	0
 
 #define HALF_QUEUES	32
-#define QUEUES		64	/* only 32 lower queues currently supported */
+#define QUEUES		64
 #define MAX_QUEUE_LENGTH 4	/* in dwords */
 
 #define QUEUE_STAT1_EMPTY		1 /* queue status bits */
@@ -110,48 +110,95 @@
 	return val;
 }
 
-static inline int qmgr_get_stat1(unsigned int queue)
+static inline int __qmgr_get_stat1(unsigned int queue)
 {
 	extern struct qmgr_regs __iomem *qmgr_regs;
 	return (__raw_readl(&qmgr_regs->stat1[queue >> 3])
 		>> ((queue & 7) << 2)) & 0xF;
 }
 
-static inline int qmgr_get_stat2(unsigned int queue)
+static inline int __qmgr_get_stat2(unsigned int queue)
 {
 	extern struct qmgr_regs __iomem *qmgr_regs;
+	BUG_ON(queue >= HALF_QUEUES);
 	return (__raw_readl(&qmgr_regs->stat2[queue >> 4])
 		>> ((queue & 0xF) << 1)) & 0x3;
 }
 
+/**
+ * qmgr_stat_empty() - checks if a hardware queue is empty
+ * @queue:	queue number
+ *
+ * Returns non-zero value if the queue is empty.
+ */
 static inline int qmgr_stat_empty(unsigned int queue)
 {
-	return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY);
+	BUG_ON(queue >= HALF_QUEUES);
+	return __qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY;
 }
 
-static inline int qmgr_stat_nearly_empty(unsigned int queue)
+/**
+ * qmgr_stat_below_low_watermark() - checks if a queue is below low watermark
+ * @queue:	queue number
+ *
+ * Returns non-zero value if the queue is below low watermark.
+ */
+static inline int qmgr_stat_below_low_watermark(unsigned int queue)
 {
-	return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY);
+	extern struct qmgr_regs __iomem *qmgr_regs;
+	if (queue >= HALF_QUEUES)
+		return (__raw_readl(&qmgr_regs->statne_h) >>
+			(queue - HALF_QUEUES)) & 0x01;
+	return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY;
 }
 
-static inline int qmgr_stat_nearly_full(unsigned int queue)
+/**
+ * qmgr_stat_above_high_watermark() - checks if a queue is above high watermark
+ * @queue:	queue number
+ *
+ * Returns non-zero value if the queue is above high watermark
+ */
+static inline int qmgr_stat_above_high_watermark(unsigned int queue)
 {
-	return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL);
+	BUG_ON(queue >= HALF_QUEUES);
+	return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL;
 }
 
+/**
+ * qmgr_stat_full() - checks if a hardware queue is full
+ * @queue:	queue number
+ *
+ * Returns non-zero value if the queue is full.
+ */
 static inline int qmgr_stat_full(unsigned int queue)
 {
-	return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_FULL);
+	extern struct qmgr_regs __iomem *qmgr_regs;
+	if (queue >= HALF_QUEUES)
+		return (__raw_readl(&qmgr_regs->statf_h) >>
+			(queue - HALF_QUEUES)) & 0x01;
+	return __qmgr_get_stat1(queue) & QUEUE_STAT1_FULL;
 }
 
+/**
+ * qmgr_stat_underflow() - checks if a hardware queue experienced underflow
+ * @queue:	queue number
+ *
+ * Returns non-zero value if the queue experienced underflow.
+ */
 static inline int qmgr_stat_underflow(unsigned int queue)
 {
-	return !!(qmgr_get_stat2(queue) & QUEUE_STAT2_UNDERFLOW);
+	return __qmgr_get_stat2(queue) & QUEUE_STAT2_UNDERFLOW;
 }
 
+/**
+ * qmgr_stat_overflow() - checks if a hardware queue experienced overflow
+ * @queue:	queue number
+ *
+ * Returns non-zero value if the queue experienced overflow.
+ */
 static inline int qmgr_stat_overflow(unsigned int queue)
 {
-	return !!(qmgr_get_stat2(queue) & QUEUE_STAT2_OVERFLOW);
+	return __qmgr_get_stat2(queue) & QUEUE_STAT2_OVERFLOW;
 }
 
 #endif
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_npe.c b/arch/arm/mach-ixp4xx/ixp4xx_npe.c
index 7bb8e77..47ac69c 100644
--- a/arch/arm/mach-ixp4xx/ixp4xx_npe.c
+++ b/arch/arm/mach-ixp4xx/ixp4xx_npe.c
@@ -386,15 +386,6 @@
 	/* reset the NPE */
 	ixp4xx_write_feature_bits(val &
 				  ~(IXP4XX_FEATURE_RESET_NPEA << npe->id));
-	for (i = 0; i < MAX_RETRIES; i++) {
-		if (!(ixp4xx_read_feature_bits() &
-		      (IXP4XX_FEATURE_RESET_NPEA << npe->id)))
-			break;	/* reset completed */
-		udelay(1);
-	}
-	if (i == MAX_RETRIES)
-		return -ETIMEDOUT;
-
 	/* deassert reset */
 	ixp4xx_write_feature_bits(val |
 				  (IXP4XX_FEATURE_RESET_NPEA << npe->id));
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
index bfddc73..bfdbe4b 100644
--- a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
+++ b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
@@ -18,8 +18,8 @@
 static struct resource *mem_res;
 static spinlock_t qmgr_lock;
 static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
-static void (*irq_handlers[HALF_QUEUES])(void *pdev);
-static void *irq_pdevs[HALF_QUEUES];
+static void (*irq_handlers[QUEUES])(void *pdev);
+static void *irq_pdevs[QUEUES];
 
 #if DEBUG_QMGR
 char qmgr_queue_descs[QUEUES][32];
@@ -28,51 +28,112 @@
 void qmgr_set_irq(unsigned int queue, int src,
 		  void (*handler)(void *pdev), void *pdev)
 {
-	u32 __iomem *reg = &qmgr_regs->irqsrc[queue / 8]; /* 8 queues / u32 */
-	int bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
 	unsigned long flags;
 
-	src &= 7;
 	spin_lock_irqsave(&qmgr_lock, flags);
-	__raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
+	if (queue < HALF_QUEUES) {
+		u32 __iomem *reg;
+		int bit;
+		BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL);
+		reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */
+		bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
+		__raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit),
+			     reg);
+	} else
+		/* IRQ source for queues 32-63 is fixed */
+		BUG_ON(src != QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY);
+
 	irq_handlers[queue] = handler;
 	irq_pdevs[queue] = pdev;
 	spin_unlock_irqrestore(&qmgr_lock, flags);
 }
 
 
-static irqreturn_t qmgr_irq1(int irq, void *pdev)
+static irqreturn_t qmgr_irq1_a0(int irq, void *pdev)
 {
-	int i;
-	u32 val = __raw_readl(&qmgr_regs->irqstat[0]);
-	__raw_writel(val, &qmgr_regs->irqstat[0]); /* ACK */
+	int i, ret = 0;
+	u32 en_bitmap, src, stat;
 
-	for (i = 0; i < HALF_QUEUES; i++)
-		if (val & (1 << i))
+	/* ACK - it may clear any bits so don't rely on it */
+	__raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]);
+
+	en_bitmap = qmgr_regs->irqen[0];
+	while (en_bitmap) {
+		i = __fls(en_bitmap); /* number of the last "low" queue */
+		en_bitmap &= ~BIT(i);
+		src = qmgr_regs->irqsrc[i >> 3];
+		stat = qmgr_regs->stat1[i >> 3];
+		if (src & 4) /* the IRQ condition is inverted */
+			stat = ~stat;
+		if (stat & BIT(src & 3)) {
 			irq_handlers[i](irq_pdevs[i]);
+			ret = IRQ_HANDLED;
+		}
+	}
+	return ret;
+}
 
-	return val ? IRQ_HANDLED : 0;
+
+static irqreturn_t qmgr_irq2_a0(int irq, void *pdev)
+{
+	int i, ret = 0;
+	u32 req_bitmap;
+
+	/* ACK - it may clear any bits so don't rely on it */
+	__raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[1]);
+
+	req_bitmap = qmgr_regs->irqen[1] & qmgr_regs->statne_h;
+	while (req_bitmap) {
+		i = __fls(req_bitmap); /* number of the last "high" queue */
+		req_bitmap &= ~BIT(i);
+		irq_handlers[HALF_QUEUES + i](irq_pdevs[HALF_QUEUES + i]);
+		ret = IRQ_HANDLED;
+	}
+	return ret;
+}
+
+
+static irqreturn_t qmgr_irq(int irq, void *pdev)
+{
+	int i, half = (irq == IRQ_IXP4XX_QM1 ? 0 : 1);
+	u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[half]);
+
+	if (!req_bitmap)
+		return 0;
+	__raw_writel(req_bitmap, &qmgr_regs->irqstat[half]); /* ACK */
+
+	while (req_bitmap) {
+		i = __fls(req_bitmap); /* number of the last queue */
+		req_bitmap &= ~BIT(i);
+		i += half * HALF_QUEUES;
+		irq_handlers[i](irq_pdevs[i]);
+	}
+	return IRQ_HANDLED;
 }
 
 
 void qmgr_enable_irq(unsigned int queue)
 {
 	unsigned long flags;
+	int half = queue / 32;
+	u32 mask = 1 << (queue & (HALF_QUEUES - 1));
 
 	spin_lock_irqsave(&qmgr_lock, flags);
-	__raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | (1 << queue),
-		     &qmgr_regs->irqen[0]);
+	__raw_writel(__raw_readl(&qmgr_regs->irqen[half]) | mask,
+		     &qmgr_regs->irqen[half]);
 	spin_unlock_irqrestore(&qmgr_lock, flags);
 }
 
 void qmgr_disable_irq(unsigned int queue)
 {
 	unsigned long flags;
+	int half = queue / 32;
+	u32 mask = 1 << (queue & (HALF_QUEUES - 1));
 
 	spin_lock_irqsave(&qmgr_lock, flags);
-	__raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue),
-		     &qmgr_regs->irqen[0]);
-	__raw_writel(1 << queue, &qmgr_regs->irqstat[0]); /* clear */
+	__raw_writel(__raw_readl(&qmgr_regs->irqen[half]) & ~mask,
+		     &qmgr_regs->irqen[half]);
+	__raw_writel(mask, &qmgr_regs->irqstat[half]); /* clear */
 	spin_unlock_irqrestore(&qmgr_lock, flags);
 }
 
@@ -98,8 +159,7 @@
 	u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
 	int err;
 
-	if (queue >= HALF_QUEUES)
-		return -ERANGE;
+	BUG_ON(queue >= QUEUES);
 
 	if ((nearly_empty_watermark | nearly_full_watermark) & ~7)
 		return -EINVAL;
@@ -180,7 +240,7 @@
 {
 	u32 cfg, addr, mask[4];
 
-	BUG_ON(queue >= HALF_QUEUES); /* not in valid range */
+	BUG_ON(queue >= QUEUES); /* not in valid range */
 
 	spin_lock_irq(&qmgr_lock);
 	cfg = __raw_readl(&qmgr_regs->sram[queue]);
@@ -224,6 +284,8 @@
 static int qmgr_init(void)
 {
 	int i, err;
+	irq_handler_t handler1, handler2;
+
 	mem_res = request_mem_region(IXP4XX_QMGR_BASE_PHYS,
 				     IXP4XX_QMGR_REGION_SIZE,
 				     "IXP4xx Queue Manager");
@@ -247,23 +309,42 @@
 		__raw_writel(0, &qmgr_regs->irqen[i]);
 	}
 
+	__raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h);
+	__raw_writel(0, &qmgr_regs->statf_h);
+
 	for (i = 0; i < QUEUES; i++)
 		__raw_writel(0, &qmgr_regs->sram[i]);
 
-	err = request_irq(IRQ_IXP4XX_QM1, qmgr_irq1, 0,
-			  "IXP4xx Queue Manager", NULL);
+	if (cpu_is_ixp42x_rev_a0()) {
+		handler1 = qmgr_irq1_a0;
+		handler2 = qmgr_irq2_a0;
+	} else
+		handler1 = handler2 = qmgr_irq;
+
+	err = request_irq(IRQ_IXP4XX_QM1, handler1, 0, "IXP4xx Queue Manager",
+			  NULL);
 	if (err) {
-		printk(KERN_ERR "qmgr: failed to request IRQ%i\n",
-		       IRQ_IXP4XX_QM1);
+		printk(KERN_ERR "qmgr: failed to request IRQ%i (%i)\n",
+		       IRQ_IXP4XX_QM1, err);
 		goto error_irq;
 	}
 
+	err = request_irq(IRQ_IXP4XX_QM2, handler2, 0, "IXP4xx Queue Manager",
+			  NULL);
+	if (err) {
+		printk(KERN_ERR "qmgr: failed to request IRQ%i (%i)\n",
+		       IRQ_IXP4XX_QM2, err);
+		goto error_irq2;
+	}
+
 	used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
 	spin_lock_init(&qmgr_lock);
 
 	printk(KERN_INFO "IXP4xx Queue Manager initialized.\n");
 	return 0;
 
+error_irq2:
+	free_irq(IRQ_IXP4XX_QM1, NULL);
 error_irq:
 	iounmap(qmgr_regs);
 error_map:
@@ -274,7 +355,9 @@
 static void qmgr_remove(void)
 {
 	free_irq(IRQ_IXP4XX_QM1, NULL);
+	free_irq(IRQ_IXP4XX_QM2, NULL);
 	synchronize_irq(IRQ_IXP4XX_QM1);
+	synchronize_irq(IRQ_IXP4XX_QM2);
 	iounmap(qmgr_regs);
 	release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
 }
diff --git a/arch/arm/mach-kirkwood/Kconfig b/arch/arm/mach-kirkwood/Kconfig
index b5421cc..25100f7 100644
--- a/arch/arm/mach-kirkwood/Kconfig
+++ b/arch/arm/mach-kirkwood/Kconfig
@@ -20,6 +20,12 @@
 	  Say 'Y' here if you want your kernel to support the
 	  Marvell RD-88F6281 Reference Board.
 
+config MACH_MV88F6281GTW_GE
+	bool "Marvell 88F6281 GTW GE Board"
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Marvell 88F6281 GTW GE Board.
+
 config MACH_SHEEVAPLUG
 	bool "Marvell SheevaPlug Reference Board"
 	help
diff --git a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile
index 8f03c9b..9dd680e 100644
--- a/arch/arm/mach-kirkwood/Makefile
+++ b/arch/arm/mach-kirkwood/Makefile
@@ -3,5 +3,8 @@
 obj-$(CONFIG_MACH_DB88F6281_BP)		+= db88f6281-bp-setup.o
 obj-$(CONFIG_MACH_RD88F6192_NAS)	+= rd88f6192-nas-setup.o
 obj-$(CONFIG_MACH_RD88F6281)		+= rd88f6281-setup.o
+obj-$(CONFIG_MACH_MV88F6281GTW_GE)	+= mv88f6281gtw_ge-setup.o
 obj-$(CONFIG_MACH_SHEEVAPLUG)		+= sheevaplug-setup.o
 obj-$(CONFIG_MACH_TS219)		+= ts219-setup.o
+
+obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
diff --git a/arch/arm/mach-kirkwood/addr-map.c b/arch/arm/mach-kirkwood/addr-map.c
index 5db4f0b..1da5d1c 100644
--- a/arch/arm/mach-kirkwood/addr-map.c
+++ b/arch/arm/mach-kirkwood/addr-map.c
@@ -20,6 +20,7 @@
  */
 #define TARGET_DDR		0
 #define TARGET_DEV_BUS		1
+#define TARGET_SRAM		3
 #define TARGET_PCIE		4
 #define ATTR_DEV_SPI_ROM	0x1e
 #define ATTR_DEV_BOOT		0x1d
@@ -30,6 +31,7 @@
 #define ATTR_DEV_CS0		0x3e
 #define ATTR_PCIE_IO		0xe0
 #define ATTR_PCIE_MEM		0xe8
+#define ATTR_SRAM		0x01
 
 /*
  * Helpers to get DDR bank info
@@ -48,7 +50,6 @@
 
 
 struct mbus_dram_target_info kirkwood_mbus_dram_info;
-static int __initdata win_alloc_count;
 
 static int __init cpu_win_can_remap(int win)
 {
@@ -112,7 +113,11 @@
 	setup_cpu_win(2, KIRKWOOD_NAND_MEM_PHYS_BASE, KIRKWOOD_NAND_MEM_SIZE,
 		      TARGET_DEV_BUS, ATTR_DEV_NAND, -1);
 
-	win_alloc_count = 3;
+	/*
+	 * Setup window for SRAM.
+	 */
+	setup_cpu_win(3, KIRKWOOD_SRAM_PHYS_BASE, KIRKWOOD_SRAM_SIZE,
+		      TARGET_SRAM, ATTR_SRAM, -1);
 
 	/*
 	 * Setup MBUS dram target info.
@@ -140,8 +145,3 @@
 	}
 	kirkwood_mbus_dram_info.num_cs = cs;
 }
-
-void __init kirkwood_setup_sram_win(u32 base, u32 size)
-{
-	setup_cpu_win(win_alloc_count++, base, size, 0x03, 0x00, -1);
-}
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index be1ca28..0f69198 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -16,6 +16,7 @@
 #include <linux/mv643xx_eth.h>
 #include <linux/mv643xx_i2c.h>
 #include <linux/ata_platform.h>
+#include <linux/mtd/nand.h>
 #include <linux/spi/orion_spi.h>
 #include <net/dsa.h>
 #include <asm/page.h>
@@ -29,6 +30,7 @@
 #include <plat/mvsdio.h>
 #include <plat/mv_xor.h>
 #include <plat/orion_nand.h>
+#include <plat/orion_wdt.h>
 #include <plat/time.h>
 #include "common.h"
 
@@ -54,6 +56,13 @@
 	iotable_init(kirkwood_io_desc, ARRAY_SIZE(kirkwood_io_desc));
 }
 
+/*
+ * Default clock control bits.  Any bit _not_ set in this variable
+ * will be cleared from the hardware after platform devices have been
+ * registered.  Some reserved bits must be set to 1.
+ */
+unsigned int kirkwood_clk_ctrl = CGC_DUNIT | CGC_RESERVED;
+	
 
 /*****************************************************************************
  * EHCI
@@ -95,6 +104,7 @@
 
 void __init kirkwood_ehci_init(void)
 {
+	kirkwood_clk_ctrl |= CGC_USB0;
 	platform_device_register(&kirkwood_ehci);
 }
 
@@ -151,6 +161,7 @@
 
 void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data)
 {
+	kirkwood_clk_ctrl |= CGC_GE0;
 	eth_data->shared = &kirkwood_ge00_shared;
 	kirkwood_ge00.dev.platform_data = eth_data;
 
@@ -212,6 +223,7 @@
 
 void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data)
 {
+	kirkwood_clk_ctrl |= CGC_GE1;
 	eth_data->shared = &kirkwood_ge01_shared;
 	kirkwood_ge01.dev.platform_data = eth_data;
 
@@ -258,6 +270,43 @@
 
 
 /*****************************************************************************
+ * NAND flash
+ ****************************************************************************/
+static struct resource kirkwood_nand_resource = {
+	.flags		= IORESOURCE_MEM,
+	.start		= KIRKWOOD_NAND_MEM_PHYS_BASE,
+	.end		= KIRKWOOD_NAND_MEM_PHYS_BASE +
+				KIRKWOOD_NAND_MEM_SIZE - 1,
+};
+
+static struct orion_nand_data kirkwood_nand_data = {
+	.cle		= 0,
+	.ale		= 1,
+	.width		= 8,
+};
+
+static struct platform_device kirkwood_nand_flash = {
+	.name		= "orion_nand",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &kirkwood_nand_data,
+	},
+	.resource	= &kirkwood_nand_resource,
+	.num_resources	= 1,
+};
+
+void __init kirkwood_nand_init(struct mtd_partition *parts, int nr_parts,
+			       int chip_delay)
+{
+	kirkwood_clk_ctrl |= CGC_RUNIT;
+	kirkwood_nand_data.parts = parts;
+	kirkwood_nand_data.nr_parts = nr_parts;
+	kirkwood_nand_data.chip_delay = chip_delay;
+	platform_device_register(&kirkwood_nand_flash);
+}
+
+
+/*****************************************************************************
  * SoC RTC
  ****************************************************************************/
 static struct resource kirkwood_rtc_resource = {
@@ -301,6 +350,9 @@
 
 void __init kirkwood_sata_init(struct mv_sata_platform_data *sata_data)
 {
+	kirkwood_clk_ctrl |= CGC_SATA0;
+	if (sata_data->n_ports > 1)
+		kirkwood_clk_ctrl |= CGC_SATA1;
 	sata_data->dram = &kirkwood_mbus_dram_info;
 	kirkwood_sata.dev.platform_data = sata_data;
 	platform_device_register(&kirkwood_sata);
@@ -346,6 +398,7 @@
 	else
 		mvsdio_data->clock = 200000000;
 	mvsdio_data->dram = &kirkwood_mbus_dram_info;
+	kirkwood_clk_ctrl |= CGC_SDIO;
 	kirkwood_sdio.dev.platform_data = mvsdio_data;
 	platform_device_register(&kirkwood_sdio);
 }
@@ -377,6 +430,7 @@
 
 void __init kirkwood_spi_init()
 {
+	kirkwood_clk_ctrl |= CGC_RUNIT;
 	platform_device_register(&kirkwood_spi);
 }
 
@@ -507,6 +561,43 @@
 
 
 /*****************************************************************************
+ * Cryptographic Engines and Security Accelerator (CESA)
+ ****************************************************************************/
+
+static struct resource kirkwood_crypto_res[] = {
+	{
+		.name   = "regs",
+		.start  = CRYPTO_PHYS_BASE,
+		.end    = CRYPTO_PHYS_BASE + 0xffff,
+		.flags  = IORESOURCE_MEM,
+	}, {
+		.name   = "sram",
+		.start  = KIRKWOOD_SRAM_PHYS_BASE,
+		.end    = KIRKWOOD_SRAM_PHYS_BASE + KIRKWOOD_SRAM_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}, {
+		.name   = "crypto interrupt",
+		.start  = IRQ_KIRKWOOD_CRYPTO,
+		.end    = IRQ_KIRKWOOD_CRYPTO,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device kirkwood_crypto_device = {
+	.name           = "mv_crypto",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(kirkwood_crypto_res),
+	.resource       = kirkwood_crypto_res,
+};
+
+void __init kirkwood_crypto_init(void)
+{
+	kirkwood_clk_ctrl |= CGC_CRYPTO;
+	platform_device_register(&kirkwood_crypto_device);
+}
+
+
+/*****************************************************************************
  * XOR
  ****************************************************************************/
 static struct mv_xor_platform_shared_data kirkwood_xor_shared_data = {
@@ -597,6 +688,7 @@
 
 static void __init kirkwood_xor0_init(void)
 {
+	kirkwood_clk_ctrl |= CGC_XOR0;
 	platform_device_register(&kirkwood_xor0_shared);
 
 	/*
@@ -695,6 +787,7 @@
 
 static void __init kirkwood_xor1_init(void)
 {
+	kirkwood_clk_ctrl |= CGC_XOR1;
 	platform_device_register(&kirkwood_xor1_shared);
 
 	/*
@@ -713,6 +806,29 @@
 
 
 /*****************************************************************************
+ * Watchdog
+ ****************************************************************************/
+static struct orion_wdt_platform_data kirkwood_wdt_data = {
+	.tclk		= 0,
+};
+
+static struct platform_device kirkwood_wdt_device = {
+	.name		= "orion_wdt",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &kirkwood_wdt_data,
+	},
+	.num_resources	= 0,
+};
+
+static void __init kirkwood_wdt_init(void)
+{
+	kirkwood_wdt_data.tclk = kirkwood_tclk;
+	platform_device_register(&kirkwood_wdt_device);
+}
+
+
+/*****************************************************************************
  * Time handling
  ****************************************************************************/
 int kirkwood_tclk;
@@ -804,6 +920,49 @@
 
 	/* internal devices that every board has */
 	kirkwood_rtc_init();
+	kirkwood_wdt_init();
 	kirkwood_xor0_init();
 	kirkwood_xor1_init();
+	kirkwood_crypto_init();
 }
+
+static int __init kirkwood_clock_gate(void)
+{
+	unsigned int curr = readl(CLOCK_GATING_CTRL);
+
+	printk(KERN_DEBUG "Gating clock of unused units\n");
+	printk(KERN_DEBUG "before: 0x%08x\n", curr);
+
+	/* Make sure those units are accessible */
+	writel(curr | CGC_SATA0 | CGC_SATA1 | CGC_PEX0, CLOCK_GATING_CTRL);
+
+	/* For SATA: first shutdown the phy */
+	if (!(kirkwood_clk_ctrl & CGC_SATA0)) {
+		/* Disable PLL and IVREF */
+		writel(readl(SATA0_PHY_MODE_2) & ~0xf, SATA0_PHY_MODE_2);
+		/* Disable PHY */
+		writel(readl(SATA0_IF_CTRL) | 0x200, SATA0_IF_CTRL);
+	}
+	if (!(kirkwood_clk_ctrl & CGC_SATA1)) {
+		/* Disable PLL and IVREF */
+		writel(readl(SATA1_PHY_MODE_2) & ~0xf, SATA1_PHY_MODE_2);
+		/* Disable PHY */
+		writel(readl(SATA1_IF_CTRL) | 0x200, SATA1_IF_CTRL);
+	}
+	
+	/* For PCIe: first shutdown the phy */
+	if (!(kirkwood_clk_ctrl & CGC_PEX0)) {
+		writel(readl(PCIE_LINK_CTRL) | 0x10, PCIE_LINK_CTRL);
+		while (1)
+			if (readl(PCIE_STATUS) & 0x1)
+				break;
+		writel(readl(PCIE_LINK_CTRL) & ~0x10, PCIE_LINK_CTRL);
+	}
+
+	/* Now gate clock the required units */
+	writel(kirkwood_clk_ctrl, CLOCK_GATING_CTRL);
+	printk(KERN_DEBUG " after: 0x%08x\n", readl(CLOCK_GATING_CTRL));
+
+	return 0;
+}
+late_initcall(kirkwood_clock_gate);
diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h
index 6ee8840..d7de434 100644
--- a/arch/arm/mach-kirkwood/common.h
+++ b/arch/arm/mach-kirkwood/common.h
@@ -15,6 +15,7 @@
 struct mv643xx_eth_platform_data;
 struct mv_sata_platform_data;
 struct mvsdio_platform_data;
+struct mtd_partition;
 
 /*
  * Basic Kirkwood init functions used early by machine-setup.
@@ -25,7 +26,6 @@
 
 extern struct mbus_dram_target_info kirkwood_mbus_dram_info;
 void kirkwood_setup_cpu_mbus(void);
-void kirkwood_setup_sram_win(u32 base, u32 size);
 
 void kirkwood_pcie_id(u32 *dev, u32 *rev);
 
@@ -40,9 +40,11 @@
 void kirkwood_i2c_init(void);
 void kirkwood_uart0_init(void);
 void kirkwood_uart1_init(void);
+void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay);
 
 extern int kirkwood_tclk;
 extern struct sys_timer kirkwood_timer;
 
+#define ARRAY_AND_SIZE(x)	(x), ARRAY_SIZE(x)
 
 #endif
diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c
new file mode 100644
index 0000000..f68d33f
--- /dev/null
+++ b/arch/arm/mach-kirkwood/cpuidle.c
@@ -0,0 +1,96 @@
+/*
+ * arch/arm/mach-kirkwood/cpuidle.c
+ *
+ * CPU idle Marvell Kirkwood SoCs
+ *
+ * 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.
+ *
+ * The cpu idle uses wait-for-interrupt and DDR self refresh in order
+ * to implement two idle states -
+ * #1 wait-for-interrupt
+ * #2 wait-for-interrupt and DDR self refresh
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/cpuidle.h>
+#include <linux/io.h>
+#include <asm/proc-fns.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_state *state)
+{
+	struct timeval before, after;
+	int idle_time;
+
+	local_irq_disable();
+	do_gettimeofday(&before);
+	if (state == &dev->states[0])
+		/* Wait for interrupt state */
+		cpu_do_idle();
+	else if (state == &dev->states[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);
+	return idle_time;
+}
+
+/* Initialize CPU idle by registering the idle states */
+static int kirkwood_init_cpuidle(void)
+{
+	struct cpuidle_device *device;
+
+	cpuidle_register_driver(&kirkwood_idle_driver);
+
+	device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id());
+	device->state_count = KIRKWOOD_MAX_STATES;
+
+	/* Wait for interrupt state */
+	device->states[0].enter = kirkwood_enter_idle;
+	device->states[0].exit_latency = 1;
+	device->states[0].target_residency = 10000;
+	device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+	strcpy(device->states[0].name, "WFI");
+	strcpy(device->states[0].desc, "Wait for interrupt");
+
+	/* Wait for interrupt and DDR self refresh state */
+	device->states[1].enter = kirkwood_enter_idle;
+	device->states[1].exit_latency = 10;
+	device->states[1].target_residency = 10000;
+	device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+	strcpy(device->states[1].name, "DDR SR");
+	strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
+
+	if (cpuidle_register_device(device)) {
+		printk(KERN_ERR "kirkwood_init_cpuidle: Failed registering\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+device_initcall(kirkwood_init_cpuidle);
diff --git a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c
index 5505d58..39bdf4b 100644
--- a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c
+++ b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c
@@ -11,14 +11,12 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/kirkwood.h>
-#include <plat/orion_nand.h>
 #include <plat/mvsdio.h>
 #include "common.h"
 #include "mpp.h"
@@ -39,32 +37,6 @@
 	},
 };
 
-static struct resource db88f6281_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-	.start		= KIRKWOOD_NAND_MEM_PHYS_BASE,
-	.end		= KIRKWOOD_NAND_MEM_PHYS_BASE +
-			  KIRKWOOD_NAND_MEM_SIZE - 1,
-};
-
-static struct orion_nand_data db88f6281_nand_data = {
-	.parts		= db88f6281_nand_parts,
-	.nr_parts	= ARRAY_SIZE(db88f6281_nand_parts),
-	.cle		= 0,
-	.ale		= 1,
-	.width		= 8,
-	.chip_delay	= 25,
-};
-
-static struct platform_device db88f6281_nand_flash = {
-	.name		= "orion_nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &db88f6281_nand_data,
-	},
-	.resource	= &db88f6281_nand_resource,
-	.num_resources	= 1,
-};
-
 static struct mv643xx_eth_platform_data db88f6281_ge00_data = {
 	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
 };
@@ -92,13 +64,12 @@
 	kirkwood_init();
 	kirkwood_mpp_conf(db88f6281_mpp_config);
 
+	kirkwood_nand_init(ARRAY_AND_SIZE(db88f6281_nand_parts), 25);
 	kirkwood_ehci_init();
 	kirkwood_ge00_init(&db88f6281_ge00_data);
 	kirkwood_sata_init(&db88f6281_sata_data);
 	kirkwood_uart0_init();
 	kirkwood_sdio_init(&db88f6281_mvsdio_data);
-	
-	platform_device_register(&db88f6281_nand_flash);
 }
 
 static int __init db88f6281_pci_init(void)
diff --git a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h
index 4f7029f..9e80d92 100644
--- a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h
+++ b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h
@@ -17,12 +17,15 @@
 #define CPU_RESET		0x00000002
 
 #define RSTOUTn_MASK		(BRIDGE_VIRT_BASE | 0x0108)
+#define WDT_RESET_OUT_EN	0x00000002
 #define SOFT_RESET_OUT_EN	0x00000004
 
 #define SYSTEM_SOFT_RESET	(BRIDGE_VIRT_BASE | 0x010c)
 #define SOFT_RESET		0x00000001
 
 #define BRIDGE_CAUSE		(BRIDGE_VIRT_BASE | 0x0110)
+#define WDT_INT_REQ		0x0008
+
 #define BRIDGE_MASK		(BRIDGE_VIRT_BASE | 0x0114)
 #define BRIDGE_INT_TIMER0	0x0002
 #define BRIDGE_INT_TIMER1	0x0004
@@ -39,4 +42,22 @@
 #define L2_CONFIG_REG		(BRIDGE_VIRT_BASE | 0x0128)
 #define L2_WRITETHROUGH		0x00000010
 
+#define CLOCK_GATING_CTRL	(BRIDGE_VIRT_BASE | 0x11c)
+#define CGC_GE0			(1 << 0)
+#define CGC_PEX0		(1 << 2)
+#define CGC_USB0		(1 << 3)
+#define CGC_SDIO		(1 << 4)
+#define CGC_TSU			(1 << 5)
+#define CGC_DUNIT		(1 << 6)
+#define CGC_RUNIT		(1 << 7)
+#define CGC_XOR0		(1 << 8)
+#define CGC_AUDIO		(1 << 9)
+#define CGC_SATA0		(1 << 14)
+#define CGC_SATA1		(1 << 15)
+#define CGC_XOR1		(1 << 16)
+#define CGC_CRYPTO		(1 << 17)
+#define CGC_GE1			(1 << 19)
+#define CGC_TDM			(1 << 20)
+#define CGC_RESERVED		((1 << 18) | (0x6 << 21))
+
 #endif
diff --git a/arch/arm/mach-kirkwood/include/mach/io.h b/arch/arm/mach-kirkwood/include/mach/io.h
index be07be0..a643a84 100644
--- a/arch/arm/mach-kirkwood/include/mach/io.h
+++ b/arch/arm/mach-kirkwood/include/mach/io.h
@@ -19,6 +19,31 @@
 					+ KIRKWOOD_PCIE_IO_VIRT_BASE);
 }
 
+static inline void __iomem *
+__arch_ioremap(unsigned long paddr, size_t size, unsigned int mtype)
+{
+	void __iomem *retval;
+	unsigned long offs = paddr - KIRKWOOD_REGS_PHYS_BASE;
+	if (mtype == MT_DEVICE && size && offs < KIRKWOOD_REGS_SIZE &&
+	    size <= KIRKWOOD_REGS_SIZE && offs + size <= KIRKWOOD_REGS_SIZE) {
+		retval = (void __iomem *)KIRKWOOD_REGS_VIRT_BASE + offs;
+	} else {
+		retval = __arm_ioremap(paddr, size, mtype);
+	}
+
+	return retval;
+}
+
+static inline void
+__arch_iounmap(void __iomem *addr)
+{
+	if (addr < (void __iomem *)KIRKWOOD_REGS_VIRT_BASE ||
+	    addr >= (void __iomem *)(KIRKWOOD_REGS_VIRT_BASE + KIRKWOOD_REGS_SIZE))
+		__iounmap(addr);
+}
+
+#define __arch_ioremap(p, s, m)	__arch_ioremap(p, s, m)
+#define __arch_iounmap(a)	__arch_iounmap(a)
 #define __io(a)			__io(a)
 #define __mem_pci(a)		(a)
 
diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
index b3e1395..07af858 100644
--- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h
+++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
@@ -20,16 +20,18 @@
  * f1000000	on-chip peripheral registers
  * f2000000	PCIe I/O space
  * f3000000	NAND controller address window
+ * f4000000	Security Accelerator SRAM
  *
  * virt		phys		size
  * fee00000	f1000000	1M	on-chip peripheral registers
  * fef00000	f2000000	1M	PCIe I/O space
  */
 
+#define KIRKWOOD_SRAM_PHYS_BASE		0xf4000000
+#define KIRKWOOD_SRAM_SIZE		SZ_2K
+
 #define KIRKWOOD_NAND_MEM_PHYS_BASE	0xf3000000
-#define KIRKWOOD_NAND_MEM_SIZE		SZ_64K /* 1K is sufficient, but 64K
-						* is the minimal window size
-						*/
+#define KIRKWOOD_NAND_MEM_SIZE		SZ_1K
 
 #define KIRKWOOD_PCIE_IO_PHYS_BASE	0xf2000000
 #define KIRKWOOD_PCIE_IO_VIRT_BASE	0xfef00000
@@ -48,6 +50,7 @@
  */
 #define DDR_VIRT_BASE		(KIRKWOOD_REGS_VIRT_BASE | 0x00000)
 #define  DDR_WINDOW_CPU_BASE	(DDR_VIRT_BASE | 0x1500)
+#define DDR_OPERATION_BASE	(DDR_VIRT_BASE | 0x1418)
 
 #define DEV_BUS_PHYS_BASE	(KIRKWOOD_REGS_PHYS_BASE | 0x10000)
 #define DEV_BUS_VIRT_BASE	(KIRKWOOD_REGS_VIRT_BASE | 0x10000)
@@ -63,7 +66,11 @@
 
 #define BRIDGE_VIRT_BASE	(KIRKWOOD_REGS_VIRT_BASE | 0x20000)
 
+#define CRYPTO_PHYS_BASE	(KIRKWOOD_REGS_PHYS_BASE | 0x30000)
+
 #define PCIE_VIRT_BASE		(KIRKWOOD_REGS_VIRT_BASE | 0x40000)
+#define PCIE_LINK_CTRL		(PCIE_VIRT_BASE | 0x70)
+#define PCIE_STATUS		(PCIE_VIRT_BASE | 0x1a04)
 
 #define USB_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0x50000)
 
@@ -80,6 +87,11 @@
 #define GE01_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0x74000)
 
 #define SATA_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0x80000)
+#define SATA_VIRT_BASE		(KIRKWOOD_REGS_VIRT_BASE | 0x80000)
+#define SATA0_IF_CTRL		(SATA_VIRT_BASE | 0x2050)
+#define SATA0_PHY_MODE_2	(SATA_VIRT_BASE | 0x2330)
+#define SATA1_IF_CTRL		(SATA_VIRT_BASE | 0x4050)
+#define SATA1_PHY_MODE_2	(SATA_VIRT_BASE | 0x4330)
 
 #define SDIO_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0x90000)
 
diff --git a/arch/arm/mach-kirkwood/mpp.c b/arch/arm/mach-kirkwood/mpp.c
index 63c4493..a5900f6 100644
--- a/arch/arm/mach-kirkwood/mpp.c
+++ b/arch/arm/mach-kirkwood/mpp.c
@@ -48,6 +48,9 @@
 	if (!variant_mask)
 		return;
 
+	/* Initialize gpiolib. */
+	orion_gpio_init();
+
 	printk(KERN_DEBUG "initial MPP regs:");
 	for (i = 0; i < MPP_NR_REGS; i++) {
 		mpp_ctrl[i] = readl(MPP_CTRL(i));
diff --git a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c
new file mode 100644
index 0000000..0358f45
--- /dev/null
+++ b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c
@@ -0,0 +1,173 @@
+/*
+ * arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c
+ *
+ * Marvell 88F6281 GTW GE Board Setup
+ *
+ * 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/pci.h>
+#include <linux/irq.h>
+#include <linux/mtd/physmap.h>
+#include <linux/timer.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/ethtool.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/orion_spi.h>
+#include <net/dsa.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/pci.h>
+#include <mach/kirkwood.h>
+#include "common.h"
+#include "mpp.h"
+
+static struct mv643xx_eth_platform_data mv88f6281gtw_ge_ge00_data = {
+	.phy_addr	= MV643XX_ETH_PHY_NONE,
+	.speed		= SPEED_1000,
+	.duplex		= DUPLEX_FULL,
+};
+
+static struct dsa_chip_data mv88f6281gtw_ge_switch_chip_data = {
+	.port_names[0]	= "lan1",
+	.port_names[1]	= "lan2",
+	.port_names[2]	= "lan3",
+	.port_names[3]	= "lan4",
+	.port_names[4]	= "wan",
+	.port_names[5]	= "cpu",
+};
+
+static struct dsa_platform_data mv88f6281gtw_ge_switch_plat_data = {
+	.nr_chips	= 1,
+	.chip		= &mv88f6281gtw_ge_switch_chip_data,
+};
+
+static const struct flash_platform_data mv88f6281gtw_ge_spi_slave_data = {
+	.type		= "mx25l12805d",
+};
+
+static struct spi_board_info __initdata mv88f6281gtw_ge_spi_slave_info[] = {
+	{
+		.modalias	= "m25p80",
+		.platform_data	= &mv88f6281gtw_ge_spi_slave_data,
+		.irq		= -1,
+		.max_speed_hz	= 50000000,
+		.bus_num	= 0,
+		.chip_select	= 0,
+	},
+};
+
+static struct gpio_keys_button mv88f6281gtw_ge_button_pins[] = {
+	{
+		.code		= KEY_RESTART,
+		.gpio		= 47,
+		.desc		= "SWR Button",
+		.active_low	= 1,
+	}, {
+		.code		= KEY_F1,
+		.gpio		= 46,
+		.desc		= "WPS Button(F1)",
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_platform_data mv88f6281gtw_ge_button_data = {
+	.buttons	= mv88f6281gtw_ge_button_pins,
+	.nbuttons	= ARRAY_SIZE(mv88f6281gtw_ge_button_pins),
+};
+
+static struct platform_device mv88f6281gtw_ge_buttons = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.num_resources	= 0,
+	.dev		= {
+		.platform_data	= &mv88f6281gtw_ge_button_data,
+	},
+};
+
+static struct gpio_led mv88f6281gtw_ge_led_pins[] = {
+	{
+		.name		= "gtw:green:Status",
+		.gpio		= 20,
+		.active_low	= 0,
+	}, {
+		.name		= "gtw:red:Status",
+		.gpio		= 21,
+		.active_low	= 0,
+	}, {
+		.name		= "gtw:green:USB",
+		.gpio		= 12,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_led_platform_data mv88f6281gtw_ge_led_data = {
+	.leds		= mv88f6281gtw_ge_led_pins,
+	.num_leds	= ARRAY_SIZE(mv88f6281gtw_ge_led_pins),
+};
+
+static struct platform_device mv88f6281gtw_ge_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &mv88f6281gtw_ge_led_data,
+	},
+};
+
+static unsigned int mv88f6281gtw_ge_mpp_config[] __initdata = {
+	MPP12_GPO,	/* Status#_USB pin  */
+	MPP20_GPIO,	/* Status#_GLED pin */
+	MPP21_GPIO,	/* Status#_RLED pin */
+	MPP46_GPIO,	/* WPS_Switch pin   */
+	MPP47_GPIO,	/* SW_Init pin      */
+	0
+};
+
+static void __init mv88f6281gtw_ge_init(void)
+{
+	/*
+	 * Basic setup. Needs to be called early.
+	 */
+	kirkwood_init();
+	kirkwood_mpp_conf(mv88f6281gtw_ge_mpp_config);
+
+	kirkwood_ehci_init();
+	kirkwood_ge00_init(&mv88f6281gtw_ge_ge00_data);
+	kirkwood_ge00_switch_init(&mv88f6281gtw_ge_switch_plat_data, NO_IRQ);
+	spi_register_board_info(mv88f6281gtw_ge_spi_slave_info,
+				ARRAY_SIZE(mv88f6281gtw_ge_spi_slave_info));
+	kirkwood_spi_init();
+	kirkwood_uart0_init();
+	platform_device_register(&mv88f6281gtw_ge_leds);
+	platform_device_register(&mv88f6281gtw_ge_buttons);
+}
+
+static int __init mv88f6281gtw_ge_pci_init(void)
+{
+	if (machine_is_mv88f6281gtw_ge())
+		kirkwood_pcie_init();
+
+	return 0;
+}
+subsys_initcall(mv88f6281gtw_ge_pci_init);
+
+MACHINE_START(MV88F6281GTW_GE, "Marvell 88F6281 GTW GE Board")
+	/* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
+	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
+	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= 0x00000100,
+	.init_machine	= mv88f6281gtw_ge_init,
+	.map_io		= kirkwood_map_io,
+	.init_irq	= kirkwood_init_irq,
+	.timer		= &kirkwood_timer,
+MACHINE_END
diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c
index 73fccac..d90b9aa 100644
--- a/arch/arm/mach-kirkwood/pcie.c
+++ b/arch/arm/mach-kirkwood/pcie.c
@@ -14,6 +14,7 @@
 #include <asm/irq.h>
 #include <asm/mach/pci.h>
 #include <plat/pcie.h>
+#include <mach/bridge-regs.h>
 #include "common.h"
 
 
@@ -95,6 +96,7 @@
 static int kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
 {
 	struct resource *res;
+	extern unsigned int kirkwood_clk_ctrl;
 
 	/*
 	 * Generic PCIe unit setup.
@@ -133,6 +135,8 @@
 	sys->resource[2] = NULL;
 	sys->io_offset = 0;
 
+	kirkwood_clk_ctrl |= CGC_PEX0;
+
 	return 1;
 }
 
diff --git a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
index 2f0e4ef..8bf4153 100644
--- a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
+++ b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
@@ -11,8 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/spi/flash.h>
diff --git a/arch/arm/mach-kirkwood/rd88f6281-setup.c b/arch/arm/mach-kirkwood/rd88f6281-setup.c
index 31e996d..31708dd 100644
--- a/arch/arm/mach-kirkwood/rd88f6281-setup.c
+++ b/arch/arm/mach-kirkwood/rd88f6281-setup.c
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
-#include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
@@ -22,7 +21,6 @@
 #include <asm/mach/arch.h>
 #include <mach/kirkwood.h>
 #include <plat/mvsdio.h>
-#include <plat/orion_nand.h>
 #include "common.h"
 #include "mpp.h"
 
@@ -42,32 +40,6 @@
 	},
 };
 
-static struct resource rd88f6281_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-	.start		= KIRKWOOD_NAND_MEM_PHYS_BASE,
-	.end		= KIRKWOOD_NAND_MEM_PHYS_BASE +
-			  KIRKWOOD_NAND_MEM_SIZE - 1,
-};
-
-static struct orion_nand_data rd88f6281_nand_data = {
-	.parts		= rd88f6281_nand_parts,
-	.nr_parts	= ARRAY_SIZE(rd88f6281_nand_parts),
-	.cle		= 0,
-	.ale		= 1,
-	.width		= 8,
-	.chip_delay	= 25,
-};
-
-static struct platform_device rd88f6281_nand_flash = {
-	.name		= "orion_nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &rd88f6281_nand_data,
-	},
-	.resource	= &rd88f6281_nand_resource,
-	.num_resources	= 1,
-};
-
 static struct mv643xx_eth_platform_data rd88f6281_ge00_data = {
 	.phy_addr	= MV643XX_ETH_PHY_NONE,
 	.speed		= SPEED_1000,
@@ -114,6 +86,7 @@
 	kirkwood_init();
 	kirkwood_mpp_conf(rd88f6281_mpp_config);
 
+	kirkwood_nand_init(ARRAY_AND_SIZE(rd88f6281_nand_parts), 25);
 	kirkwood_ehci_init();
 
 	kirkwood_ge00_init(&rd88f6281_ge00_data);
@@ -129,8 +102,6 @@
 	kirkwood_sata_init(&rd88f6281_sata_data);
 	kirkwood_sdio_init(&rd88f6281_mvsdio_data);
 	kirkwood_uart0_init();
-
-	platform_device_register(&rd88f6281_nand_flash);
 }
 
 static int __init rd88f6281_pci_init(void)
diff --git a/arch/arm/mach-kirkwood/sheevaplug-setup.c b/arch/arm/mach-kirkwood/sheevaplug-setup.c
index 831e4a5..c7319ee 100644
--- a/arch/arm/mach-kirkwood/sheevaplug-setup.c
+++ b/arch/arm/mach-kirkwood/sheevaplug-setup.c
@@ -11,7 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/gpio.h>
@@ -20,7 +19,6 @@
 #include <asm/mach/arch.h>
 #include <mach/kirkwood.h>
 #include <plat/mvsdio.h>
-#include <plat/orion_nand.h>
 #include "common.h"
 #include "mpp.h"
 
@@ -40,38 +38,12 @@
 	},
 };
 
-static struct resource sheevaplug_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-	.start		= KIRKWOOD_NAND_MEM_PHYS_BASE,
-	.end		= KIRKWOOD_NAND_MEM_PHYS_BASE +
-			  KIRKWOOD_NAND_MEM_SIZE - 1,
-};
-
-static struct orion_nand_data sheevaplug_nand_data = {
-	.parts		= sheevaplug_nand_parts,
-	.nr_parts	= ARRAY_SIZE(sheevaplug_nand_parts),
-	.cle		= 0,
-	.ale		= 1,
-	.width		= 8,
-	.chip_delay	= 25,
-};
-
-static struct platform_device sheevaplug_nand_flash = {
-	.name		= "orion_nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &sheevaplug_nand_data,
-	},
-	.resource	= &sheevaplug_nand_resource,
-	.num_resources	= 1,
-};
-
 static struct mv643xx_eth_platform_data sheevaplug_ge00_data = {
 	.phy_addr	= MV643XX_ETH_PHY_ADDR(0),
 };
 
 static struct mvsdio_platform_data sheevaplug_mvsdio_data = {
-	// unfortunately the CD signal has not been connected */
+	/* unfortunately the CD signal has not been connected */
 };
 
 static struct gpio_led sheevaplug_led_pins[] = {
@@ -111,6 +83,7 @@
 	kirkwood_mpp_conf(sheevaplug_mpp_config);
 
 	kirkwood_uart0_init();
+	kirkwood_nand_init(ARRAY_AND_SIZE(sheevaplug_nand_parts), 25);
 
 	if (gpio_request(29, "USB Power Enable") != 0 ||
 	    gpio_direction_output(29, 1) != 0)
@@ -120,7 +93,6 @@
 	kirkwood_ge00_init(&sheevaplug_ge00_data);
 	kirkwood_sdio_init(&sheevaplug_mvsdio_data);
 
-	platform_device_register(&sheevaplug_nand_flash);
 	platform_device_register(&sheevaplug_leds);
 }
 
diff --git a/arch/arm/mach-mmp/include/mach/irqs.h b/arch/arm/mach-mmp/include/mach/irqs.h
index e83e45e..16295cf 100644
--- a/arch/arm/mach-mmp/include/mach/irqs.h
+++ b/arch/arm/mach-mmp/include/mach/irqs.h
@@ -52,6 +52,7 @@
 /*
  * Interrupt numbers for PXA910
  */
+#define IRQ_PXA910_NONE			(-1)
 #define IRQ_PXA910_AIRQ			0
 #define IRQ_PXA910_SSP3			1
 #define IRQ_PXA910_SSP2			2
diff --git a/arch/arm/mach-mmp/include/mach/mfp-pxa168.h b/arch/arm/mach-mmp/include/mach/mfp-pxa168.h
index 2e91464..3b216bf 100644
--- a/arch/arm/mach-mmp/include/mach/mfp-pxa168.h
+++ b/arch/arm/mach-mmp/include/mach/mfp-pxa168.h
@@ -253,6 +253,10 @@
 #define GPIO58_LCD_PCLK_WR	MFP_CFG(GPIO58, AF1)
 #define GPIO85_LCD_VSYNC	MFP_CFG(GPIO85, AF1)
 
+/* I2C */
+#define GPIO105_CI2C_SDA	MFP_CFG(GPIO105, AF1)
+#define GPIO106_CI2C_SCL	MFP_CFG(GPIO106, AF1)
+
 /* I2S */
 #define GPIO113_I2S_MCLK	MFP_CFG(GPIO113,AF6)
 #define GPIO114_I2S_FRM		MFP_CFG(GPIO114,AF1)
@@ -260,4 +264,27 @@
 #define GPIO116_I2S_RXD		MFP_CFG(GPIO116,AF2)
 #define GPIO117_I2S_TXD		MFP_CFG(GPIO117,AF2)
 
+/* PWM */
+#define GPIO96_PWM3_OUT		MFP_CFG(GPIO96, AF1)
+#define GPIO97_PWM2_OUT		MFP_CFG(GPIO97, AF1)
+#define GPIO98_PWM1_OUT		MFP_CFG(GPIO98, AF1)
+#define GPIO104_PWM4_OUT	MFP_CFG(GPIO104, AF1)
+#define GPIO106_PWM2_OUT	MFP_CFG(GPIO106, AF2)
+#define GPIO74_PWM4_OUT		MFP_CFG(GPIO74, AF2)
+#define GPIO75_PWM3_OUT		MFP_CFG(GPIO75, AF2)
+#define GPIO76_PWM2_OUT		MFP_CFG(GPIO76, AF2)
+#define GPIO77_PWM1_OUT		MFP_CFG(GPIO77, AF2)
+#define GPIO82_PWM4_OUT		MFP_CFG(GPIO82, AF2)
+#define GPIO83_PWM3_OUT		MFP_CFG(GPIO83, AF2)
+#define GPIO84_PWM2_OUT		MFP_CFG(GPIO84, AF2)
+#define GPIO85_PWM1_OUT		MFP_CFG(GPIO85, AF2)
+#define GPIO84_PWM1_OUT		MFP_CFG(GPIO84, AF4)
+#define GPIO122_PWM3_OUT	MFP_CFG(GPIO122, AF3)
+#define GPIO123_PWM1_OUT	MFP_CFG(GPIO123, AF1)
+#define GPIO124_PWM2_OUT	MFP_CFG(GPIO124, AF1)
+#define GPIO125_PWM3_OUT	MFP_CFG(GPIO125, AF1)
+#define GPIO126_PWM4_OUT	MFP_CFG(GPIO126, AF1)
+#define GPIO86_PWM1_OUT		MFP_CFG(GPIO86, AF2)
+#define GPIO86_PWM2_OUT		MFP_CFG(GPIO86, AF3)
+
 #endif /* __ASM_MACH_MFP_PXA168_H */
diff --git a/arch/arm/mach-mmp/include/mach/mfp-pxa910.h b/arch/arm/mach-mmp/include/mach/mfp-pxa910.h
index d97de36..bf1189f 100644
--- a/arch/arm/mach-mmp/include/mach/mfp-pxa910.h
+++ b/arch/arm/mach-mmp/include/mach/mfp-pxa910.h
@@ -159,4 +159,12 @@
 #define MMC1_CD_MMC1_CD		MFP_CFG_DRV(MMC1_CD, AF0, MEDIUM)
 #define MMC1_WP_MMC1_WP		MFP_CFG_DRV(MMC1_WP, AF0, MEDIUM)
 
+/* PWM */
+#define GPIO27 PWM3 AF2		MFP_CFG(GPIO27, AF2)
+#define GPIO51_PWM2_OUT		MFP_CFG(GPIO51, AF2)
+#define GPIO117_PWM1_OUT	MFP_CFG(GPIO117, AF2)
+#define GPIO118_PWM2_OUT	MFP_CFG(GPIO118, AF2)
+#define GPIO119_PWM3_OUT	MFP_CFG(GPIO119, AF2)
+#define GPIO120_PWM4_OUT	MFP_CFG(GPIO120, AF2)
+
 #endif /* __ASM_MACH MFP_PXA910_H */
diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h b/arch/arm/mach-mmp/include/mach/pxa168.h
index ef0a8a2..6bf1f0e 100644
--- a/arch/arm/mach-mmp/include/mach/pxa168.h
+++ b/arch/arm/mach-mmp/include/mach/pxa168.h
@@ -1,10 +1,18 @@
 #ifndef __ASM_MACH_PXA168_H
 #define __ASM_MACH_PXA168_H
 
+#include <linux/i2c.h>
 #include <mach/devices.h>
+#include <plat/i2c.h>
 
 extern struct pxa_device_desc pxa168_device_uart1;
 extern struct pxa_device_desc pxa168_device_uart2;
+extern struct pxa_device_desc pxa168_device_twsi0;
+extern struct pxa_device_desc pxa168_device_twsi1;
+extern struct pxa_device_desc pxa168_device_pwm1;
+extern struct pxa_device_desc pxa168_device_pwm2;
+extern struct pxa_device_desc pxa168_device_pwm3;
+extern struct pxa_device_desc pxa168_device_pwm4;
 
 static inline int pxa168_add_uart(int id)
 {
@@ -20,4 +28,40 @@
 
 	return pxa_register_device(d, NULL, 0);
 }
+
+static inline int pxa168_add_twsi(int id, struct i2c_pxa_platform_data *data,
+				  struct i2c_board_info *info, unsigned size)
+{
+	struct pxa_device_desc *d = NULL;
+	int ret;
+
+	switch (id) {
+	case 0: d = &pxa168_device_twsi0; break;
+	case 1: d = &pxa168_device_twsi1; break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = i2c_register_board_info(id, info, size);
+	if (ret)
+		return ret;
+
+	return pxa_register_device(d, data, sizeof(*data));
+}
+
+static inline int pxa168_add_pwm(int id)
+{
+	struct pxa_device_desc *d = NULL;
+
+	switch (id) {
+	case 1: d = &pxa168_device_pwm1; break;
+	case 2: d = &pxa168_device_pwm2; break;
+	case 3: d = &pxa168_device_pwm3; break;
+	case 4: d = &pxa168_device_pwm4; break;
+	default:
+		return -EINVAL;
+	}
+
+	return pxa_register_device(d, NULL, 0);
+}
 #endif /* __ASM_MACH_PXA168_H */
diff --git a/arch/arm/mach-mmp/include/mach/pxa910.h b/arch/arm/mach-mmp/include/mach/pxa910.h
index b7aeaf5..6ae1ed7 100644
--- a/arch/arm/mach-mmp/include/mach/pxa910.h
+++ b/arch/arm/mach-mmp/include/mach/pxa910.h
@@ -1,10 +1,18 @@
 #ifndef __ASM_MACH_PXA910_H
 #define __ASM_MACH_PXA910_H
 
+#include <linux/i2c.h>
 #include <mach/devices.h>
+#include <plat/i2c.h>
 
 extern struct pxa_device_desc pxa910_device_uart1;
 extern struct pxa_device_desc pxa910_device_uart2;
+extern struct pxa_device_desc pxa910_device_twsi0;
+extern struct pxa_device_desc pxa910_device_twsi1;
+extern struct pxa_device_desc pxa910_device_pwm1;
+extern struct pxa_device_desc pxa910_device_pwm2;
+extern struct pxa_device_desc pxa910_device_pwm3;
+extern struct pxa_device_desc pxa910_device_pwm4;
 
 static inline int pxa910_add_uart(int id)
 {
@@ -20,4 +28,40 @@
 
 	return pxa_register_device(d, NULL, 0);
 }
+
+static inline int pxa910_add_twsi(int id, struct i2c_pxa_platform_data *data,
+				  struct i2c_board_info *info, unsigned size)
+{
+	struct pxa_device_desc *d = NULL;
+	int ret;
+
+	switch (id) {
+	case 0: d = &pxa910_device_twsi0; break;
+	case 1: d = &pxa910_device_twsi1; break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = i2c_register_board_info(id, info, size);
+	if (ret)
+		return ret;
+
+	return pxa_register_device(d, data, sizeof(*data));
+}
+
+static inline int pxa910_add_pwm(int id)
+{
+	struct pxa_device_desc *d = NULL;
+
+	switch (id) {
+	case 1: d = &pxa910_device_pwm1; break;
+	case 2: d = &pxa910_device_pwm2; break;
+	case 3: d = &pxa910_device_pwm3; break;
+	case 4: d = &pxa910_device_pwm4; break;
+	default:
+		return -EINVAL;
+	}
+
+	return pxa_register_device(d, NULL, 0);
+}
 #endif /* __ASM_MACH_PXA910_H */
diff --git a/arch/arm/mach-mmp/include/mach/regs-apbc.h b/arch/arm/mach-mmp/include/mach/regs-apbc.h
index c6b8c9d..98ccbee 100644
--- a/arch/arm/mach-mmp/include/mach/regs-apbc.h
+++ b/arch/arm/mach-mmp/include/mach/regs-apbc.h
@@ -22,8 +22,10 @@
 #define APBC_PXA168_UART1	APBC_REG(0x000)
 #define APBC_PXA168_UART2	APBC_REG(0x004)
 #define APBC_PXA168_GPIO	APBC_REG(0x008)
-#define APBC_PXA168_PWM0	APBC_REG(0x00c)
-#define APBC_PXA168_PWM1	APBC_REG(0x010)
+#define APBC_PXA168_PWM1	APBC_REG(0x00c)
+#define APBC_PXA168_PWM2	APBC_REG(0x010)
+#define APBC_PXA168_PWM3	APBC_REG(0x014)
+#define APBC_PXA168_PWM4	APBC_REG(0x018)
 #define APBC_PXA168_SSP1	APBC_REG(0x01c)
 #define APBC_PXA168_SSP2	APBC_REG(0x020)
 #define APBC_PXA168_RTC		APBC_REG(0x028)
@@ -48,10 +50,10 @@
 #define APBC_PXA910_UART0	APBC_REG(0x000)
 #define APBC_PXA910_UART1	APBC_REG(0x004)
 #define APBC_PXA910_GPIO	APBC_REG(0x008)
-#define APBC_PXA910_PWM0	APBC_REG(0x00c)
-#define APBC_PXA910_PWM1	APBC_REG(0x010)
-#define APBC_PXA910_PWM2	APBC_REG(0x014)
-#define APBC_PXA910_PWM3	APBC_REG(0x018)
+#define APBC_PXA910_PWM1	APBC_REG(0x00c)
+#define APBC_PXA910_PWM2	APBC_REG(0x010)
+#define APBC_PXA910_PWM3	APBC_REG(0x014)
+#define APBC_PXA910_PWM4	APBC_REG(0x018)
 #define APBC_PXA910_SSP1	APBC_REG(0x01c)
 #define APBC_PXA910_SSP2	APBC_REG(0x020)
 #define APBC_PXA910_IPC		APBC_REG(0x024)
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index ae92446..71b1ae3 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -65,11 +65,23 @@
 /* APB peripheral clocks */
 static APBC_CLK(uart1, PXA168_UART1, 1, 14745600);
 static APBC_CLK(uart2, PXA168_UART2, 1, 14745600);
+static APBC_CLK(twsi0, PXA168_TWSI0, 1, 33000000);
+static APBC_CLK(twsi1, PXA168_TWSI1, 1, 33000000);
+static APBC_CLK(pwm1, PXA168_PWM1, 1, 13000000);
+static APBC_CLK(pwm2, PXA168_PWM2, 1, 13000000);
+static APBC_CLK(pwm3, PXA168_PWM3, 1, 13000000);
+static APBC_CLK(pwm4, PXA168_PWM4, 1, 13000000);
 
 /* device and clock bindings */
 static struct clk_lookup pxa168_clkregs[] = {
 	INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
 	INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL),
+	INIT_CLKREG(&clk_twsi0, "pxa2xx-i2c.0", NULL),
+	INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.1", NULL),
+	INIT_CLKREG(&clk_pwm1, "pxa168-pwm.0", NULL),
+	INIT_CLKREG(&clk_pwm2, "pxa168-pwm.1", NULL),
+	INIT_CLKREG(&clk_pwm3, "pxa168-pwm.2", NULL),
+	INIT_CLKREG(&clk_pwm4, "pxa168-pwm.3", NULL),
 };
 
 static int __init pxa168_init(void)
@@ -109,3 +121,9 @@
 /* on-chip devices */
 PXA168_DEVICE(uart1, "pxa2xx-uart", 0, UART1, 0xd4017000, 0x30, 21, 22);
 PXA168_DEVICE(uart2, "pxa2xx-uart", 1, UART2, 0xd4018000, 0x30, 23, 24);
+PXA168_DEVICE(twsi0, "pxa2xx-i2c", 0, TWSI0, 0xd4011000, 0x28);
+PXA168_DEVICE(twsi1, "pxa2xx-i2c", 1, TWSI1, 0xd4025000, 0x28);
+PXA168_DEVICE(pwm1, "pxa168-pwm", 0, NONE, 0xd401a000, 0x10);
+PXA168_DEVICE(pwm2, "pxa168-pwm", 1, NONE, 0xd401a400, 0x10);
+PXA168_DEVICE(pwm3, "pxa168-pwm", 2, NONE, 0xd401a800, 0x10);
+PXA168_DEVICE(pwm4, "pxa168-pwm", 3, NONE, 0xd401ac00, 0x10);
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index 453f8f7..5882ca6 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -103,11 +103,23 @@
 /* APB peripheral clocks */
 static APBC_CLK(uart1, PXA910_UART0, 1, 14745600);
 static APBC_CLK(uart2, PXA910_UART1, 1, 14745600);
+static APBC_CLK(twsi0, PXA168_TWSI0, 1, 33000000);
+static APBC_CLK(twsi1, PXA168_TWSI1, 1, 33000000);
+static APBC_CLK(pwm1, PXA910_PWM1, 1, 13000000);
+static APBC_CLK(pwm2, PXA910_PWM2, 1, 13000000);
+static APBC_CLK(pwm3, PXA910_PWM3, 1, 13000000);
+static APBC_CLK(pwm4, PXA910_PWM4, 1, 13000000);
 
 /* device and clock bindings */
 static struct clk_lookup pxa910_clkregs[] = {
 	INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
 	INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL),
+	INIT_CLKREG(&clk_twsi0, "pxa2xx-i2c.0", NULL),
+	INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.1", NULL),
+	INIT_CLKREG(&clk_pwm1, "pxa910-pwm.0", NULL),
+	INIT_CLKREG(&clk_pwm2, "pxa910-pwm.1", NULL),
+	INIT_CLKREG(&clk_pwm3, "pxa910-pwm.2", NULL),
+	INIT_CLKREG(&clk_pwm4, "pxa910-pwm.3", NULL),
 };
 
 static int __init pxa910_init(void)
@@ -156,3 +168,9 @@
  */
 PXA910_DEVICE(uart1, "pxa2xx-uart", 0, UART2, 0xd4017000, 0x30, 21, 22);
 PXA910_DEVICE(uart2, "pxa2xx-uart", 1, UART3, 0xd4018000, 0x30, 23, 24);
+PXA910_DEVICE(twsi0, "pxa2xx-i2c", 0, TWSI0, 0xd4011000, 0x28);
+PXA910_DEVICE(twsi1, "pxa2xx-i2c", 1, TWSI1, 0xd4025000, 0x28);
+PXA910_DEVICE(pwm1, "pxa910-pwm", 0, NONE, 0xd401a000, 0x10);
+PXA910_DEVICE(pwm2, "pxa910-pwm", 1, NONE, 0xd401a400, 0x10);
+PXA910_DEVICE(pwm3, "pxa910-pwm", 2, NONE, 0xd401a800, 0x10);
+PXA910_DEVICE(pwm4, "pxa910-pwm", 3, NONE, 0xd401ac00, 0x10);
diff --git a/arch/arm/mach-mv78xx0/irq.c b/arch/arm/mach-mv78xx0/irq.c
index f289b0e..22b4ff8 100644
--- a/arch/arm/mach-mv78xx0/irq.c
+++ b/arch/arm/mach-mv78xx0/irq.c
@@ -28,6 +28,9 @@
 {
 	int i;
 
+	/* Initialize gpiolib. */
+	orion_gpio_init();
+
 	orion_irq_init(0, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF));
 	orion_irq_init(32, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF));
 	orion_irq_init(64, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_ERR_OFF));
diff --git a/arch/arm/mach-mx1/generic.c b/arch/arm/mach-mx1/generic.c
index 0dec6f3..7622c9b 100644
--- a/arch/arm/mach-mx1/generic.c
+++ b/arch/arm/mach-mx1/generic.c
@@ -26,6 +26,7 @@
 
 #include <asm/mach/map.h>
 
+#include <mach/common.h>
 #include <mach/hardware.h>
 
 static struct map_desc imx_io_desc[] __initdata = {
@@ -37,7 +38,9 @@
 	}
 };
 
-void __init mxc_map_io(void)
+void __init mx1_map_io(void)
 {
+	mxc_set_cpu_type(MXC_CPU_MX1);
+
 	iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc));
 }
diff --git a/arch/arm/mach-mx1/mx1ads.c b/arch/arm/mach-mx1/mx1ads.c
index e54057f..e5b0c0a 100644
--- a/arch/arm/mach-mx1/mx1ads.c
+++ b/arch/arm/mach-mx1/mx1ads.c
@@ -12,77 +12,56 @@
  * warranty of any kind, whether express or implied.
  */
 
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
 #include <linux/i2c.h>
 #include <linux/i2c/pcf857x.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 
-#include <mach/irqs.h>
-#include <mach/hardware.h>
 #include <mach/common.h>
-#include <mach/imx-uart.h>
-#include <mach/irqs.h>
+#include <mach/hardware.h>
 #include <mach/i2c.h>
+#include <mach/imx-uart.h>
 #include <mach/iomux.h>
+#include <mach/irqs.h>
+
 #include "devices.h"
 
-/*
- * UARTs platform data
- */
-static int mxc_uart1_pins[] = {
+static int mx1ads_pins[] = {
+	/* UART1 */
 	PC9_PF_UART1_CTS,
 	PC10_PF_UART1_RTS,
 	PC11_PF_UART1_TXD,
 	PC12_PF_UART1_RXD,
-};
-
-static int uart1_mxc_init(struct platform_device *pdev)
-{
-	return mxc_gpio_setup_multiple_pins(mxc_uart1_pins,
-			ARRAY_SIZE(mxc_uart1_pins), "UART1");
-}
-
-static int uart1_mxc_exit(struct platform_device *pdev)
-{
-	mxc_gpio_release_multiple_pins(mxc_uart1_pins,
-			ARRAY_SIZE(mxc_uart1_pins));
-	return 0;
-}
-
-static int mxc_uart2_pins[] = {
+	/* UART2 */
 	PB28_PF_UART2_CTS,
 	PB29_PF_UART2_RTS,
 	PB30_PF_UART2_TXD,
 	PB31_PF_UART2_RXD,
+	/* I2C */
+	PA15_PF_I2C_SDA,
+	PA16_PF_I2C_SCL,
+	/* SPI */
+	PC13_PF_SPI1_SPI_RDY,
+	PC14_PF_SPI1_SCLK,
+	PC15_PF_SPI1_SS,
+	PC16_PF_SPI1_MISO,
+	PC17_PF_SPI1_MOSI,
 };
 
-static int uart2_mxc_init(struct platform_device *pdev)
-{
-	return mxc_gpio_setup_multiple_pins(mxc_uart2_pins,
-			ARRAY_SIZE(mxc_uart2_pins), "UART2");
-}
-
-static int uart2_mxc_exit(struct platform_device *pdev)
-{
-	mxc_gpio_release_multiple_pins(mxc_uart2_pins,
-			ARRAY_SIZE(mxc_uart2_pins));
-	return 0;
-}
+/*
+ * UARTs platform data
+ */
 
 static struct imxuart_platform_data uart_pdata[] = {
 	{
-		.init = uart1_mxc_init,
-		.exit = uart1_mxc_exit,
 		.flags = IMXUART_HAVE_RTSCTS,
 	}, {
-		.init = uart2_mxc_init,
-		.exit = uart2_mxc_exit,
 		.flags = IMXUART_HAVE_RTSCTS,
 	},
 };
@@ -111,24 +90,6 @@
 /*
  * I2C
  */
-
-static int i2c_pins[] = {
-	PA15_PF_I2C_SDA,
-	PA16_PF_I2C_SCL,
-};
-
-static int i2c_init(struct device *dev)
-{
-	return mxc_gpio_setup_multiple_pins(i2c_pins,
-			ARRAY_SIZE(i2c_pins), "I2C");
-}
-
-static void i2c_exit(struct device *dev)
-{
-	mxc_gpio_release_multiple_pins(i2c_pins,
-			ARRAY_SIZE(i2c_pins));
-}
-
 static struct pcf857x_platform_data pcf857x_data[] = {
 	{
 		.gpio_base = 4 * 32,
@@ -139,8 +100,6 @@
 
 static struct imxi2c_platform_data mx1ads_i2c_data = {
 	.bitrate = 100000,
-	.init = i2c_init,
-	.exit = i2c_exit,
 };
 
 static struct i2c_board_info mx1ads_i2c_devices[] = {
@@ -160,6 +119,9 @@
  */
 static void __init mx1ads_init(void)
 {
+	mxc_gpio_setup_multiple_pins(mx1ads_pins,
+		ARRAY_SIZE(mx1ads_pins), "mx1ads");
+
 	/* UART */
 	mxc_register_device(&imx_uart1_device, &uart_pdata[0]);
 	mxc_register_device(&imx_uart2_device, &uart_pdata[1]);
@@ -188,7 +150,7 @@
 	.phys_io	= IMX_IO_PHYS,
 	.io_pg_offst	= (IMX_IO_BASE >> 18) & 0xfffc,
 	.boot_params	= PHYS_OFFSET + 0x100,
-	.map_io		= mxc_map_io,
+	.map_io		= mx1_map_io,
 	.init_irq	= mxc_init_irq,
 	.timer		= &mx1ads_timer,
 	.init_machine	= mx1ads_init,
@@ -198,7 +160,7 @@
 	.phys_io	= IMX_IO_PHYS,
 	.io_pg_offst	= (IMX_IO_BASE >> 18) & 0xfffc,
 	.boot_params	= PHYS_OFFSET + 0x100,
-	.map_io		= mxc_map_io,
+	.map_io		= mx1_map_io,
 	.init_irq	= mxc_init_irq,
 	.timer		= &mx1ads_timer,
 	.init_machine	= mx1ads_init,
diff --git a/arch/arm/mach-mx1/scb9328.c b/arch/arm/mach-mx1/scb9328.c
index 0e71f3f..20e0b5b 100644
--- a/arch/arm/mach-mx1/scb9328.c
+++ b/arch/arm/mach-mx1/scb9328.c
@@ -153,7 +153,7 @@
 	.phys_io	= 0x00200000,
 	.io_pg_offst	= ((0xe0200000) >> 18) & 0xfffc,
 	.boot_params	= 0x08000100,
-	.map_io		= mxc_map_io,
+	.map_io		= mx1_map_io,
 	.init_irq	= mxc_init_irq,
 	.timer		= &scb9328_timer,
 	.init_machine	= scb9328_init,
diff --git a/arch/arm/mach-mx2/Kconfig b/arch/arm/mach-mx2/Kconfig
index 42a7888..c77da58 100644
--- a/arch/arm/mach-mx2/Kconfig
+++ b/arch/arm/mach-mx2/Kconfig
@@ -18,6 +18,13 @@
 
 comment "MX2 platforms:"
 
+config MACH_MX21ADS
+	bool "MX21ADS platform"
+	depends on MACH_MX21
+	help
+	  Include support for MX21ADS platform. This includes specific
+	  configurations for the board and its peripherals.
+
 config MACH_MX27ADS
 	bool "MX27ADS platform"
 	depends on MACH_MX27
@@ -46,4 +53,18 @@
 
 endchoice
 
+config MACH_MX27_3DS
+	bool "MX27PDK platform"
+	depends on MACH_MX27
+	help
+	  Include support for MX27PDK platform. This includes specific
+	  configurations for the board and its peripherals.
+
+config MACH_MX27LITE
+	bool "LogicPD MX27 LITEKIT platform"
+	depends on MACH_MX27
+	help
+	  Include support for MX27 LITEKIT platform. This includes specific
+	  configurations for the board and its peripherals.
+
 endif
diff --git a/arch/arm/mach-mx2/Makefile b/arch/arm/mach-mx2/Makefile
index 950649a..b9b1cca 100644
--- a/arch/arm/mach-mx2/Makefile
+++ b/arch/arm/mach-mx2/Makefile
@@ -11,6 +11,10 @@
 obj-$(CONFIG_MACH_MX27) += cpu_imx27.o
 obj-$(CONFIG_MACH_MX27) += clock_imx27.o
 
+obj-$(CONFIG_MACH_MX21ADS) += mx21ads.o
 obj-$(CONFIG_MACH_MX27ADS) += mx27ads.o
 obj-$(CONFIG_MACH_PCM038) += pcm038.o
 obj-$(CONFIG_MACH_PCM970_BASEBOARD) += pcm970-baseboard.o
+obj-$(CONFIG_MACH_MX27_3DS) += mx27pdk.o
+obj-$(CONFIG_MACH_MX27LITE) += mx27lite.o
+
diff --git a/arch/arm/mach-mx2/clock_imx21.c b/arch/arm/mach-mx2/clock_imx21.c
index e4b08ca..0850fb8 100644
--- a/arch/arm/mach-mx2/clock_imx21.c
+++ b/arch/arm/mach-mx2/clock_imx21.c
@@ -48,6 +48,25 @@
 	__raw_writel(reg, clk->enable_reg);
 }
 
+static unsigned long _clk_generic_round_rate(struct clk *clk,
+			unsigned long rate,
+			u32 max_divisor)
+{
+	u32 div;
+	unsigned long parent_rate;
+
+	parent_rate = clk_get_rate(clk->parent);
+
+	div = parent_rate / rate;
+	if (parent_rate % rate)
+		div++;
+
+	if (div > max_divisor)
+		div = max_divisor;
+
+	return parent_rate / div;
+}
+
 static int _clk_spll_enable(struct clk *clk)
 {
 	u32 reg;
@@ -78,19 +97,7 @@
 static unsigned long _clk_perclkx_round_rate(struct clk *clk,
 					     unsigned long rate)
 {
-	u32 div;
-	unsigned long parent_rate;
-
-	parent_rate = clk_get_rate(clk->parent);
-
-	div = parent_rate / rate;
-	if (parent_rate % rate)
-		div++;
-
-	if (div > 64)
-		div = 64;
-
-	return parent_rate / div;
+	return _clk_generic_round_rate(clk, rate, 64);
 }
 
 static int _clk_perclkx_set_rate(struct clk *clk, unsigned long rate)
@@ -130,6 +137,32 @@
 	return parent_rate / (usb_pdf + 1U);
 }
 
+static unsigned long _clk_usb_round_rate(struct clk *clk,
+					     unsigned long rate)
+{
+	return _clk_generic_round_rate(clk, rate, 8);
+}
+
+static int _clk_usb_set_rate(struct clk *clk, unsigned long rate)
+{
+	u32 reg;
+	u32 div;
+	unsigned long parent_rate;
+
+	parent_rate = clk_get_rate(clk->parent);
+
+	div = parent_rate / rate;
+	if (div > 8 || div < 1 || ((parent_rate / div) != rate))
+		return -EINVAL;
+	div--;
+
+	reg = CSCR() & ~CCM_CSCR_USB_MASK;
+	reg |= div << CCM_CSCR_USB_OFFSET;
+	__raw_writel(reg, CCM_CSCR);
+
+	return 0;
+}
+
 static unsigned long _clk_ssix_recalc(struct clk *clk, unsigned long pdf)
 {
 	unsigned long parent_rate;
@@ -595,11 +628,14 @@
 static struct clk usb_clk[] = {
 	{
 		.parent = &spll_clk,
+		.secondary = &usb_clk[1],
 		.get_rate = _clk_usb_recalc,
 		.enable = _clk_enable,
 		.enable_reg = CCM_PCCR_USBOTG_REG,
 		.enable_shift = CCM_PCCR_USBOTG_OFFSET,
 		.disable = _clk_disable,
+		.round_rate = _clk_usb_round_rate,
+		.set_rate = _clk_usb_set_rate,
 	}, {
 		.parent = &hclk_clk,
 		.enable = _clk_enable,
@@ -768,18 +804,7 @@
 
 static unsigned long _clk_clko_round_rate(struct clk *clk, unsigned long rate)
 {
-	u32 div;
-	unsigned long parent_rate;
-
-	parent_rate = clk_get_rate(clk->parent);
-	div = parent_rate / rate;
-	if (parent_rate % rate)
-		div++;
-
-	if (div > 8)
-		div = 8;
-
-	return parent_rate / div;
+	return _clk_generic_round_rate(clk, rate, 8);
 }
 
 static int _clk_clko_set_rate(struct clk *clk, unsigned long rate)
@@ -921,7 +946,7 @@
 	_REGISTER_CLOCK(NULL, "cspi3", cspi_clk[2])
 	_REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk[0])
 	_REGISTER_CLOCK(NULL, "csi", csi_clk[0])
-	_REGISTER_CLOCK(NULL, "usb", usb_clk[0])
+	_REGISTER_CLOCK("imx21-hcd.0", NULL, usb_clk[0])
 	_REGISTER_CLOCK(NULL, "ssi1", ssi_clk[0])
 	_REGISTER_CLOCK(NULL, "ssi2", ssi_clk[1])
 	_REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
diff --git a/arch/arm/mach-mx2/generic.c b/arch/arm/mach-mx2/generic.c
index bd51dd0..169372f 100644
--- a/arch/arm/mach-mx2/generic.c
+++ b/arch/arm/mach-mx2/generic.c
@@ -69,7 +69,17 @@
  * system startup to create static physical to virtual
  * memory map for the IO modules.
  */
-void __init mxc_map_io(void)
+void __init mx21_map_io(void)
 {
+	mxc_set_cpu_type(MXC_CPU_MX21);
+
 	iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
 }
+
+void __init mx27_map_io(void)
+{
+	mxc_set_cpu_type(MXC_CPU_MX27);
+
+	iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
+}
+
diff --git a/arch/arm/mach-mx2/mx21ads.c b/arch/arm/mach-mx2/mx21ads.c
new file mode 100644
index 0000000..a5ee461
--- /dev/null
+++ b/arch/arm/mach-mx2/mx21ads.c
@@ -0,0 +1,286 @@
+/*
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *  Copyright 2006-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 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/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/physmap.h>
+#include <linux/gpio.h>
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include <mach/imx-uart.h>
+#include <mach/imxfb.h>
+#include <mach/iomux.h>
+#include <mach/mxc_nand.h>
+#include <mach/mmc.h>
+#include <mach/board-mx21ads.h>
+
+#include "devices.h"
+
+static unsigned int mx21ads_pins[] = {
+
+	/* CS8900A */
+	(GPIO_PORTE | GPIO_GPIO | GPIO_IN | 11),
+
+	/* UART1 */
+	PE12_PF_UART1_TXD,
+	PE13_PF_UART1_RXD,
+	PE14_PF_UART1_CTS,
+	PE15_PF_UART1_RTS,
+
+	/* UART3 (IrDA) - only TXD and RXD */
+	PE8_PF_UART3_TXD,
+	PE9_PF_UART3_RXD,
+
+	/* UART4 */
+	PB26_AF_UART4_RTS,
+	PB28_AF_UART4_TXD,
+	PB29_AF_UART4_CTS,
+	PB31_AF_UART4_RXD,
+
+	/* LCDC */
+	PA5_PF_LSCLK,
+	PA6_PF_LD0,
+	PA7_PF_LD1,
+	PA8_PF_LD2,
+	PA9_PF_LD3,
+	PA10_PF_LD4,
+	PA11_PF_LD5,
+	PA12_PF_LD6,
+	PA13_PF_LD7,
+	PA14_PF_LD8,
+	PA15_PF_LD9,
+	PA16_PF_LD10,
+	PA17_PF_LD11,
+	PA18_PF_LD12,
+	PA19_PF_LD13,
+	PA20_PF_LD14,
+	PA21_PF_LD15,
+	PA22_PF_LD16,
+	PA24_PF_REV,     /* Sharp panel dedicated signal */
+	PA25_PF_CLS,     /* Sharp panel dedicated signal */
+	PA26_PF_PS,      /* Sharp panel dedicated signal */
+	PA27_PF_SPL_SPR, /* Sharp panel dedicated signal */
+	PA28_PF_HSYNC,
+	PA29_PF_VSYNC,
+	PA30_PF_CONTRAST,
+	PA31_PF_OE_ACD,
+
+	/* MMC/SDHC */
+	PE18_PF_SD1_D0,
+	PE19_PF_SD1_D1,
+	PE20_PF_SD1_D2,
+	PE21_PF_SD1_D3,
+	PE22_PF_SD1_CMD,
+	PE23_PF_SD1_CLK,
+
+	/* NFC */
+	PF0_PF_NRFB,
+	PF1_PF_NFCE,
+	PF2_PF_NFWP,
+	PF3_PF_NFCLE,
+	PF4_PF_NFALE,
+	PF5_PF_NFRE,
+	PF6_PF_NFWE,
+	PF7_PF_NFIO0,
+	PF8_PF_NFIO1,
+	PF9_PF_NFIO2,
+	PF10_PF_NFIO3,
+	PF11_PF_NFIO4,
+	PF12_PF_NFIO5,
+	PF13_PF_NFIO6,
+	PF14_PF_NFIO7,
+};
+
+/* ADS's NOR flash: 2x AM29BDS128HE9VKI on 32-bit bus */
+static struct physmap_flash_data mx21ads_flash_data = {
+	.width = 4,
+};
+
+static struct resource mx21ads_flash_resource = {
+	.start = CS0_BASE_ADDR,
+	.end = CS0_BASE_ADDR + 0x02000000 - 1,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct platform_device mx21ads_nor_mtd_device = {
+	.name = "physmap-flash",
+	.id = 0,
+	.dev = {
+		.platform_data = &mx21ads_flash_data,
+	},
+	.num_resources = 1,
+	.resource = &mx21ads_flash_resource,
+};
+
+static struct imxuart_platform_data uart_pdata = {
+	.flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct imxuart_platform_data uart_norts_pdata = {
+};
+
+
+static int mx21ads_fb_init(struct platform_device *pdev)
+{
+	u16 tmp;
+
+	tmp = __raw_readw(MX21ADS_IO_REG);
+	tmp |= MX21ADS_IO_LCDON;
+	__raw_writew(tmp, MX21ADS_IO_REG);
+	return 0;
+}
+
+static void mx21ads_fb_exit(struct platform_device *pdev)
+{
+	u16 tmp;
+
+	tmp = __raw_readw(MX21ADS_IO_REG);
+	tmp &= ~MX21ADS_IO_LCDON;
+	__raw_writew(tmp, MX21ADS_IO_REG);
+}
+
+/*
+ * Connected is a portrait Sharp-QVGA display
+ * of type: LQ035Q7DB02
+ */
+static struct imx_fb_platform_data mx21ads_fb_data = {
+	.pixclock       = 188679, /* in ps */
+	.xres           = 240,
+	.yres           = 320,
+
+	.bpp            = 16,
+	.hsync_len      = 2,
+	.left_margin    = 6,
+	.right_margin   = 16,
+
+	.vsync_len      = 1,
+	.upper_margin   = 8,
+	.lower_margin   = 10,
+	.fixed_screen_cpu = 0,
+
+	.pcr            = 0xFB108BC7,
+	.pwmr           = 0x00A901ff,
+	.lscr1          = 0x00120300,
+	.dmacr          = 0x00020008,
+
+	.init = mx21ads_fb_init,
+	.exit = mx21ads_fb_exit,
+};
+
+static int mx21ads_sdhc_get_ro(struct device *dev)
+{
+	return (__raw_readw(MX21ADS_IO_REG) & MX21ADS_IO_SD_WP) ? 1 : 0;
+}
+
+static int mx21ads_sdhc_init(struct device *dev, irq_handler_t detect_irq,
+	void *data)
+{
+	int ret;
+
+	ret = request_irq(IRQ_GPIOD(25), detect_irq,
+		IRQF_TRIGGER_FALLING, "mmc-detect", data);
+	if (ret)
+		goto out;
+	return 0;
+out:
+	return ret;
+}
+
+static void mx21ads_sdhc_exit(struct device *dev, void *data)
+{
+	free_irq(IRQ_GPIOD(25), data);
+}
+
+static struct imxmmc_platform_data mx21ads_sdhc_pdata = {
+	.ocr_avail = MMC_VDD_29_30 | MMC_VDD_30_31, /* 3.0V */
+	.get_ro = mx21ads_sdhc_get_ro,
+	.init = mx21ads_sdhc_init,
+	.exit = mx21ads_sdhc_exit,
+};
+
+static struct mxc_nand_platform_data mx21ads_nand_board_info = {
+	.width = 1,
+	.hw_ecc = 1,
+};
+
+static struct map_desc mx21ads_io_desc[] __initdata = {
+	/*
+	 * Memory-mapped I/O on MX21ADS Base board:
+	 *   - CS8900A Ethernet controller
+	 *   - ST16C2552CJ UART
+	 *   - CPU and Base board version
+	 *   - Base board I/O register
+	 */
+	{
+		.virtual = MX21ADS_MMIO_BASE_ADDR,
+		.pfn = __phys_to_pfn(CS1_BASE_ADDR),
+		.length = MX21ADS_MMIO_SIZE,
+		.type = MT_DEVICE,
+	},
+};
+
+static void __init mx21ads_map_io(void)
+{
+	mx21_map_io();
+	iotable_init(mx21ads_io_desc, ARRAY_SIZE(mx21ads_io_desc));
+}
+
+static struct platform_device *platform_devices[] __initdata = {
+	&mx21ads_nor_mtd_device,
+};
+
+static void __init mx21ads_board_init(void)
+{
+	mxc_gpio_setup_multiple_pins(mx21ads_pins, ARRAY_SIZE(mx21ads_pins),
+			"mx21ads");
+
+	mxc_register_device(&mxc_uart_device0, &uart_pdata);
+	mxc_register_device(&mxc_uart_device2, &uart_norts_pdata);
+	mxc_register_device(&mxc_uart_device3, &uart_pdata);
+	mxc_register_device(&mxc_fb_device, &mx21ads_fb_data);
+	mxc_register_device(&mxc_sdhc_device0, &mx21ads_sdhc_pdata);
+	mxc_register_device(&mxc_nand_device, &mx21ads_nand_board_info);
+
+	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
+
+static void __init mx21ads_timer_init(void)
+{
+	mx21_clocks_init(32768, 26000000);
+}
+
+static struct sys_timer mx21ads_timer = {
+	.init	= mx21ads_timer_init,
+};
+
+MACHINE_START(MX21ADS, "Freescale i.MX21ADS")
+	/* maintainer: Freescale Semiconductor, Inc. */
+	.phys_io        = AIPI_BASE_ADDR,
+	.io_pg_offst    = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+	.boot_params    = PHYS_OFFSET + 0x100,
+	.map_io         = mx21ads_map_io,
+	.init_irq       = mxc_init_irq,
+	.init_machine   = mx21ads_board_init,
+	.timer          = &mx21ads_timer,
+MACHINE_END
diff --git a/arch/arm/mach-mx2/mx27ads.c b/arch/arm/mach-mx2/mx27ads.c
index 4a3b097..02dadda 100644
--- a/arch/arm/mach-mx2/mx27ads.c
+++ b/arch/arm/mach-mx2/mx27ads.c
@@ -23,6 +23,8 @@
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -33,9 +35,117 @@
 #include <mach/imx-uart.h>
 #include <mach/iomux.h>
 #include <mach/board-mx27ads.h>
+#include <mach/mxc_nand.h>
+#include <mach/i2c.h>
+#include <mach/imxfb.h>
+#include <mach/mmc.h>
 
 #include "devices.h"
 
+static unsigned int mx27ads_pins[] = {
+	/* UART0 */
+	PE12_PF_UART1_TXD,
+	PE13_PF_UART1_RXD,
+	PE14_PF_UART1_CTS,
+	PE15_PF_UART1_RTS,
+	/* UART1 */
+	PE3_PF_UART2_CTS,
+	PE4_PF_UART2_RTS,
+	PE6_PF_UART2_TXD,
+	PE7_PF_UART2_RXD,
+	/* UART2 */
+	PE8_PF_UART3_TXD,
+	PE9_PF_UART3_RXD,
+	PE10_PF_UART3_CTS,
+	PE11_PF_UART3_RTS,
+	/* UART3 */
+	PB26_AF_UART4_RTS,
+	PB28_AF_UART4_TXD,
+	PB29_AF_UART4_CTS,
+	PB31_AF_UART4_RXD,
+	/* UART4 */
+	PB18_AF_UART5_TXD,
+	PB19_AF_UART5_RXD,
+	PB20_AF_UART5_CTS,
+	PB21_AF_UART5_RTS,
+	/* UART5 */
+	PB10_AF_UART6_TXD,
+	PB12_AF_UART6_CTS,
+	PB11_AF_UART6_RXD,
+	PB13_AF_UART6_RTS,
+	/* FEC */
+	PD0_AIN_FEC_TXD0,
+	PD1_AIN_FEC_TXD1,
+	PD2_AIN_FEC_TXD2,
+	PD3_AIN_FEC_TXD3,
+	PD4_AOUT_FEC_RX_ER,
+	PD5_AOUT_FEC_RXD1,
+	PD6_AOUT_FEC_RXD2,
+	PD7_AOUT_FEC_RXD3,
+	PD8_AF_FEC_MDIO,
+	PD9_AIN_FEC_MDC,
+	PD10_AOUT_FEC_CRS,
+	PD11_AOUT_FEC_TX_CLK,
+	PD12_AOUT_FEC_RXD0,
+	PD13_AOUT_FEC_RX_DV,
+	PD14_AOUT_FEC_RX_CLK,
+	PD15_AOUT_FEC_COL,
+	PD16_AIN_FEC_TX_ER,
+	PF23_AIN_FEC_TX_EN,
+	/* I2C2 */
+	PC5_PF_I2C2_SDA,
+	PC6_PF_I2C2_SCL,
+	/* FB */
+	PA5_PF_LSCLK,
+	PA6_PF_LD0,
+	PA7_PF_LD1,
+	PA8_PF_LD2,
+	PA9_PF_LD3,
+	PA10_PF_LD4,
+	PA11_PF_LD5,
+	PA12_PF_LD6,
+	PA13_PF_LD7,
+	PA14_PF_LD8,
+	PA15_PF_LD9,
+	PA16_PF_LD10,
+	PA17_PF_LD11,
+	PA18_PF_LD12,
+	PA19_PF_LD13,
+	PA20_PF_LD14,
+	PA21_PF_LD15,
+	PA22_PF_LD16,
+	PA23_PF_LD17,
+	PA24_PF_REV,
+	PA25_PF_CLS,
+	PA26_PF_PS,
+	PA27_PF_SPL_SPR,
+	PA28_PF_HSYNC,
+	PA29_PF_VSYNC,
+	PA30_PF_CONTRAST,
+	PA31_PF_OE_ACD,
+	/* OWIRE */
+	PE16_AF_OWIRE,
+	/* SDHC1*/
+	PE18_PF_SD1_D0,
+	PE19_PF_SD1_D1,
+	PE20_PF_SD1_D2,
+	PE21_PF_SD1_D3,
+	PE22_PF_SD1_CMD,
+	PE23_PF_SD1_CLK,
+	/* SDHC2*/
+	PB4_PF_SD2_D0,
+	PB5_PF_SD2_D1,
+	PB6_PF_SD2_D2,
+	PB7_PF_SD2_D3,
+	PB8_PF_SD2_CMD,
+	PB9_PF_SD2_CLK,
+};
+
+static struct mxc_nand_platform_data mx27ads_nand_board_info = {
+	.width = 1,
+	.hw_ecc = 1,
+};
+
 /* ADS's NOR flash */
 static struct physmap_flash_data mx27ads_flash_data = {
 	.width = 2,
@@ -58,189 +168,113 @@
 	.resource = &mx27ads_flash_resource,
 };
 
-static int mxc_uart0_pins[] = {
-	PE12_PF_UART1_TXD,
-	PE13_PF_UART1_RXD,
-	PE14_PF_UART1_CTS,
-	PE15_PF_UART1_RTS
+static struct imxi2c_platform_data mx27ads_i2c_data = {
+	.bitrate = 100000,
 };
 
-static int uart_mxc_port0_init(struct platform_device *pdev)
-{
-	return mxc_gpio_setup_multiple_pins(mxc_uart0_pins,
-			ARRAY_SIZE(mxc_uart0_pins), "UART0");
-}
-
-static int uart_mxc_port0_exit(struct platform_device *pdev)
-{
-	mxc_gpio_release_multiple_pins(mxc_uart0_pins,
-			ARRAY_SIZE(mxc_uart0_pins));
-	return 0;
-}
-
-static int mxc_uart1_pins[] = {
-	PE3_PF_UART2_CTS,
-	PE4_PF_UART2_RTS,
-	PE6_PF_UART2_TXD,
-	PE7_PF_UART2_RXD
+static struct i2c_board_info mx27ads_i2c_devices[] = {
 };
 
-static int uart_mxc_port1_init(struct platform_device *pdev)
+void lcd_power(int on)
 {
-	return mxc_gpio_setup_multiple_pins(mxc_uart1_pins,
-			ARRAY_SIZE(mxc_uart1_pins), "UART1");
+	if (on)
+		__raw_writew(PBC_BCTRL1_LCDON, PBC_BCTRL1_SET_REG);
+	else
+		__raw_writew(PBC_BCTRL1_LCDON, PBC_BCTRL1_CLEAR_REG);
 }
 
-static int uart_mxc_port1_exit(struct platform_device *pdev)
-{
-	mxc_gpio_release_multiple_pins(mxc_uart1_pins,
-			ARRAY_SIZE(mxc_uart1_pins));
-	return 0;
-}
+static struct imx_fb_platform_data mx27ads_fb_data = {
+	.pixclock	= 188679,
+	.xres		= 240,
+	.yres		= 320,
 
-static int mxc_uart2_pins[] = {
-	PE8_PF_UART3_TXD,
-	PE9_PF_UART3_RXD,
-	PE10_PF_UART3_CTS,
-	PE11_PF_UART3_RTS
+	.bpp		= 16,
+	.hsync_len	= 1,
+	.left_margin	= 9,
+	.right_margin	= 16,
+
+	.vsync_len	= 1,
+	.upper_margin	= 7,
+	.lower_margin	= 9,
+	.fixed_screen_cpu = 0,
+
+	/*
+	 * - HSYNC active high
+	 * - VSYNC active high
+	 * - clk notenabled while idle
+	 * - clock inverted
+	 * - data not inverted
+	 * - data enable low active
+	 * - enable sharp mode
+	 */
+	.pcr		= 0xFB008BC0,
+	.pwmr		= 0x00A903FF,
+	.lscr1		= 0x00120300,
+	.dmacr		= 0x00020010,
+
+	.lcd_power	= lcd_power,
 };
 
-static int uart_mxc_port2_init(struct platform_device *pdev)
+static int mx27ads_sdhc1_init(struct device *dev, irq_handler_t detect_irq,
+			      void *data)
 {
-	return mxc_gpio_setup_multiple_pins(mxc_uart2_pins,
-			ARRAY_SIZE(mxc_uart2_pins), "UART2");
+	return request_irq(IRQ_GPIOE(21), detect_irq, IRQF_TRIGGER_RISING,
+			   "sdhc1-card-detect", data);
 }
 
-static int uart_mxc_port2_exit(struct platform_device *pdev)
+static int mx27ads_sdhc2_init(struct device *dev, irq_handler_t detect_irq,
+			      void *data)
 {
-	mxc_gpio_release_multiple_pins(mxc_uart2_pins,
-			ARRAY_SIZE(mxc_uart2_pins));
-	return 0;
+	return request_irq(IRQ_GPIOB(7), detect_irq, IRQF_TRIGGER_RISING,
+			   "sdhc2-card-detect", data);
 }
 
-static int mxc_uart3_pins[] = {
-	PB26_AF_UART4_RTS,
-	PB28_AF_UART4_TXD,
-	PB29_AF_UART4_CTS,
-	PB31_AF_UART4_RXD
+static void mx27ads_sdhc1_exit(struct device *dev, void *data)
+{
+	free_irq(IRQ_GPIOE(21), data);
+}
+
+static void mx27ads_sdhc2_exit(struct device *dev, void *data)
+{
+	free_irq(IRQ_GPIOB(7), data);
+}
+
+static struct imxmmc_platform_data sdhc1_pdata = {
+	.init = mx27ads_sdhc1_init,
+	.exit = mx27ads_sdhc1_exit,
 };
 
-static int uart_mxc_port3_init(struct platform_device *pdev)
-{
-	return mxc_gpio_setup_multiple_pins(mxc_uart3_pins,
-			ARRAY_SIZE(mxc_uart3_pins), "UART3");
-}
-
-static int uart_mxc_port3_exit(struct platform_device *pdev)
-{
-	mxc_gpio_release_multiple_pins(mxc_uart3_pins,
-			ARRAY_SIZE(mxc_uart3_pins));
-	return 0;
-}
-
-static int mxc_uart4_pins[] = {
-	PB18_AF_UART5_TXD,
-	PB19_AF_UART5_RXD,
-	PB20_AF_UART5_CTS,
-	PB21_AF_UART5_RTS
+static struct imxmmc_platform_data sdhc2_pdata = {
+	.init = mx27ads_sdhc2_init,
+	.exit = mx27ads_sdhc2_exit,
 };
 
-static int uart_mxc_port4_init(struct platform_device *pdev)
-{
-	return mxc_gpio_setup_multiple_pins(mxc_uart4_pins,
-			ARRAY_SIZE(mxc_uart4_pins), "UART4");
-}
-
-static int uart_mxc_port4_exit(struct platform_device *pdev)
-{
-	mxc_gpio_release_multiple_pins(mxc_uart4_pins,
-			ARRAY_SIZE(mxc_uart4_pins));
-	return 0;
-}
-
-static int mxc_uart5_pins[] = {
-	PB10_AF_UART6_TXD,
-	PB12_AF_UART6_CTS,
-	PB11_AF_UART6_RXD,
-	PB13_AF_UART6_RTS
-};
-
-static int uart_mxc_port5_init(struct platform_device *pdev)
-{
-	return mxc_gpio_setup_multiple_pins(mxc_uart5_pins,
-			ARRAY_SIZE(mxc_uart5_pins), "UART5");
-}
-
-static int uart_mxc_port5_exit(struct platform_device *pdev)
-{
-	mxc_gpio_release_multiple_pins(mxc_uart5_pins,
-			ARRAY_SIZE(mxc_uart5_pins));
-	return 0;
-}
-
 static struct platform_device *platform_devices[] __initdata = {
 	&mx27ads_nor_mtd_device,
 	&mxc_fec_device,
+	&mxc_w1_master_device,
 };
 
-static int mxc_fec_pins[] = {
-	PD0_AIN_FEC_TXD0,
-	PD1_AIN_FEC_TXD1,
-	PD2_AIN_FEC_TXD2,
-	PD3_AIN_FEC_TXD3,
-	PD4_AOUT_FEC_RX_ER,
-	PD5_AOUT_FEC_RXD1,
-	PD6_AOUT_FEC_RXD2,
-	PD7_AOUT_FEC_RXD3,
-	PD8_AF_FEC_MDIO,
-	PD9_AIN_FEC_MDC,
-	PD10_AOUT_FEC_CRS,
-	PD11_AOUT_FEC_TX_CLK,
-	PD12_AOUT_FEC_RXD0,
-	PD13_AOUT_FEC_RX_DV,
-	PD14_AOUT_FEC_RX_CLK,
-	PD15_AOUT_FEC_COL,
-	PD16_AIN_FEC_TX_ER,
-	PF23_AIN_FEC_TX_EN
-};
-
-static void gpio_fec_active(void)
-{
-	mxc_gpio_setup_multiple_pins(mxc_fec_pins,
-			ARRAY_SIZE(mxc_fec_pins), "FEC");
-}
-
 static struct imxuart_platform_data uart_pdata[] = {
 	{
-		.init = uart_mxc_port0_init,
-		.exit = uart_mxc_port0_exit,
 		.flags = IMXUART_HAVE_RTSCTS,
 	}, {
-		.init = uart_mxc_port1_init,
-		.exit = uart_mxc_port1_exit,
 		.flags = IMXUART_HAVE_RTSCTS,
 	}, {
-		.init = uart_mxc_port2_init,
-		.exit = uart_mxc_port2_exit,
 		.flags = IMXUART_HAVE_RTSCTS,
 	}, {
-		.init = uart_mxc_port3_init,
-		.exit = uart_mxc_port3_exit,
 		.flags = IMXUART_HAVE_RTSCTS,
 	}, {
-		.init = uart_mxc_port4_init,
-		.exit = uart_mxc_port4_exit,
 		.flags = IMXUART_HAVE_RTSCTS,
 	}, {
-		.init = uart_mxc_port5_init,
-		.exit = uart_mxc_port5_exit,
 		.flags = IMXUART_HAVE_RTSCTS,
 	},
 };
 
 static void __init mx27ads_board_init(void)
 {
-	gpio_fec_active();
+	mxc_gpio_setup_multiple_pins(mx27ads_pins, ARRAY_SIZE(mx27ads_pins),
+			"mx27ads");
 
 	mxc_register_device(&mxc_uart_device0, &uart_pdata[0]);
 	mxc_register_device(&mxc_uart_device1, &uart_pdata[1]);
@@ -248,6 +282,15 @@
 	mxc_register_device(&mxc_uart_device3, &uart_pdata[3]);
 	mxc_register_device(&mxc_uart_device4, &uart_pdata[4]);
 	mxc_register_device(&mxc_uart_device5, &uart_pdata[5]);
+	mxc_register_device(&mxc_nand_device, &mx27ads_nand_board_info);
+
+	/* only the i2c master 1 is used on this CPU card */
+	i2c_register_board_info(1, mx27ads_i2c_devices,
+				ARRAY_SIZE(mx27ads_i2c_devices));
+	mxc_register_device(&mxc_i2c_device1, &mx27ads_i2c_data);
+	mxc_register_device(&mxc_fb_device, &mx27ads_fb_data);
+	mxc_register_device(&mxc_sdhc_device0, &sdhc1_pdata);
+	mxc_register_device(&mxc_sdhc_device1, &sdhc2_pdata);
 
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 }
@@ -277,7 +320,7 @@
 
 static void __init mx27ads_map_io(void)
 {
-	mxc_map_io();
+	mx27_map_io();
 	iotable_init(mx27ads_io_desc, ARRAY_SIZE(mx27ads_io_desc));
 }
 
diff --git a/arch/arm/mach-mx2/mx27lite.c b/arch/arm/mach-mx2/mx27lite.c
new file mode 100644
index 0000000..3ae11cb
--- /dev/null
+++ b/arch/arm/mach-mx2/mx27lite.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2007 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix
+ * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
+ * Copyright 2009 Daniel Schaeffer (daniel.schaeffer@timesys.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/platform_device.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux.h>
+#include <mach/board-mx27lite.h>
+
+#include "devices.h"
+
+static unsigned int mx27lite_pins[] = {
+	/* UART1 */
+	PE12_PF_UART1_TXD,
+	PE13_PF_UART1_RXD,
+	PE14_PF_UART1_CTS,
+	PE15_PF_UART1_RTS,
+	/* FEC */
+	PD0_AIN_FEC_TXD0,
+	PD1_AIN_FEC_TXD1,
+	PD2_AIN_FEC_TXD2,
+	PD3_AIN_FEC_TXD3,
+	PD4_AOUT_FEC_RX_ER,
+	PD5_AOUT_FEC_RXD1,
+	PD6_AOUT_FEC_RXD2,
+	PD7_AOUT_FEC_RXD3,
+	PD8_AF_FEC_MDIO,
+	PD9_AIN_FEC_MDC,
+	PD10_AOUT_FEC_CRS,
+	PD11_AOUT_FEC_TX_CLK,
+	PD12_AOUT_FEC_RXD0,
+	PD13_AOUT_FEC_RX_DV,
+	PD14_AOUT_FEC_RX_CLK,
+	PD15_AOUT_FEC_COL,
+	PD16_AIN_FEC_TX_ER,
+	PF23_AIN_FEC_TX_EN,
+};
+
+static struct imxuart_platform_data uart_pdata = {
+	.flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct platform_device *platform_devices[] __initdata = {
+	&mxc_fec_device,
+};
+
+static void __init mx27lite_init(void)
+{
+	mxc_gpio_setup_multiple_pins(mx27lite_pins, ARRAY_SIZE(mx27lite_pins),
+		"imx27lite");
+	mxc_register_device(&mxc_uart_device0, &uart_pdata);
+	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
+
+static void __init mx27lite_timer_init(void)
+{
+	mx27_clocks_init(26000000);
+}
+
+static struct sys_timer mx27lite_timer = {
+	.init	= mx27lite_timer_init,
+};
+
+MACHINE_START(IMX27LITE, "LogicPD i.MX27LITE")
+	.phys_io        = AIPI_BASE_ADDR,
+	.io_pg_offst    = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+	.boot_params    = PHYS_OFFSET + 0x100,
+	.map_io         = mx27_map_io,
+	.init_irq       = mxc_init_irq,
+	.init_machine   = mx27lite_init,
+	.timer          = &mx27lite_timer,
+MACHINE_END
diff --git a/arch/arm/mach-mx2/mx27pdk.c b/arch/arm/mach-mx2/mx27pdk.c
new file mode 100644
index 0000000..1d9238c
--- /dev/null
+++ b/arch/arm/mach-mx2/mx27pdk.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Author: Fabio Estevam <fabio.estevam@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/platform_device.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux.h>
+#include <mach/board-mx27pdk.h>
+
+#include "devices.h"
+
+static unsigned int mx27pdk_pins[] = {
+	/* UART1 */
+	PE12_PF_UART1_TXD,
+	PE13_PF_UART1_RXD,
+	PE14_PF_UART1_CTS,
+	PE15_PF_UART1_RTS,
+	/* FEC */
+	PD0_AIN_FEC_TXD0,
+	PD1_AIN_FEC_TXD1,
+	PD2_AIN_FEC_TXD2,
+	PD3_AIN_FEC_TXD3,
+	PD4_AOUT_FEC_RX_ER,
+	PD5_AOUT_FEC_RXD1,
+	PD6_AOUT_FEC_RXD2,
+	PD7_AOUT_FEC_RXD3,
+	PD8_AF_FEC_MDIO,
+	PD9_AIN_FEC_MDC,
+	PD10_AOUT_FEC_CRS,
+	PD11_AOUT_FEC_TX_CLK,
+	PD12_AOUT_FEC_RXD0,
+	PD13_AOUT_FEC_RX_DV,
+	PD14_AOUT_FEC_RX_CLK,
+	PD15_AOUT_FEC_COL,
+	PD16_AIN_FEC_TX_ER,
+	PF23_AIN_FEC_TX_EN,
+};
+
+static struct imxuart_platform_data uart_pdata = {
+	.flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct platform_device *platform_devices[] __initdata = {
+	&mxc_fec_device,
+};
+
+static void __init mx27pdk_init(void)
+{
+	mxc_gpio_setup_multiple_pins(mx27pdk_pins, ARRAY_SIZE(mx27pdk_pins),
+		"mx27pdk");
+	mxc_register_device(&mxc_uart_device0, &uart_pdata);
+	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
+
+static void __init mx27pdk_timer_init(void)
+{
+	mx27_clocks_init(26000000);
+}
+
+static struct sys_timer mx27pdk_timer = {
+	.init	= mx27pdk_timer_init,
+};
+
+MACHINE_START(MX27_3DS, "Freescale MX27PDK")
+	/* maintainer: Freescale Semiconductor, Inc. */
+	.phys_io        = AIPI_BASE_ADDR,
+	.io_pg_offst    = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+	.boot_params    = PHYS_OFFSET + 0x100,
+	.map_io         = mx27_map_io,
+	.init_irq       = mxc_init_irq,
+	.init_machine   = mx27pdk_init,
+	.timer          = &mx27pdk_timer,
+MACHINE_END
diff --git a/arch/arm/mach-mx2/pcm038.c b/arch/arm/mach-mx2/pcm038.c
index aa4eaa6..a4628d0 100644
--- a/arch/arm/mach-mx2/pcm038.c
+++ b/arch/arm/mach-mx2/pcm038.c
@@ -17,28 +17,84 @@
  * MA 02110-1301, USA.
  */
 
-#include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/plat-ram.h>
-#include <linux/io.h>
 #include <linux/i2c.h>
 #include <linux/i2c/at24.h>
+#include <linux/io.h>
+#include <linux/mtd/plat-ram.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
 
-#include <asm/mach/arch.h>
 #include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include <mach/board-pcm038.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
-#include <mach/iomux.h>
-#ifdef CONFIG_I2C_IMX
 #include <mach/i2c.h>
-#endif
-#include <asm/mach/time.h>
+#include <mach/iomux.h>
 #include <mach/imx-uart.h>
-#include <mach/board-pcm038.h>
 #include <mach/mxc_nand.h>
 
 #include "devices.h"
 
+static int pcm038_pins[] = {
+	/* UART1 */
+	PE12_PF_UART1_TXD,
+	PE13_PF_UART1_RXD,
+	PE14_PF_UART1_CTS,
+	PE15_PF_UART1_RTS,
+	/* UART2 */
+	PE3_PF_UART2_CTS,
+	PE4_PF_UART2_RTS,
+	PE6_PF_UART2_TXD,
+	PE7_PF_UART2_RXD,
+	/* UART3 */
+	PE8_PF_UART3_TXD,
+	PE9_PF_UART3_RXD,
+	PE10_PF_UART3_CTS,
+	PE11_PF_UART3_RTS,
+	/* FEC */
+	PD0_AIN_FEC_TXD0,
+	PD1_AIN_FEC_TXD1,
+	PD2_AIN_FEC_TXD2,
+	PD3_AIN_FEC_TXD3,
+	PD4_AOUT_FEC_RX_ER,
+	PD5_AOUT_FEC_RXD1,
+	PD6_AOUT_FEC_RXD2,
+	PD7_AOUT_FEC_RXD3,
+	PD8_AF_FEC_MDIO,
+	PD9_AIN_FEC_MDC,
+	PD10_AOUT_FEC_CRS,
+	PD11_AOUT_FEC_TX_CLK,
+	PD12_AOUT_FEC_RXD0,
+	PD13_AOUT_FEC_RX_DV,
+	PD14_AOUT_FEC_RX_CLK,
+	PD15_AOUT_FEC_COL,
+	PD16_AIN_FEC_TX_ER,
+	PF23_AIN_FEC_TX_EN,
+	/* I2C2 */
+	PC5_PF_I2C2_SDA,
+	PC6_PF_I2C2_SCL,
+	/* SPI1 */
+	PD25_PF_CSPI1_RDY,
+	PD27_PF_CSPI1_SS1,
+	PD28_PF_CSPI1_SS0,
+	PD29_PF_CSPI1_SCLK,
+	PD30_PF_CSPI1_MISO,
+	PD31_PF_CSPI1_MOSI,
+	/* SSI1 */
+	PC20_PF_SSI1_FS,
+	PC21_PF_SSI1_RXD,
+	PC22_PF_SSI1_TXD,
+	PC23_PF_SSI1_CLK,
+	/* SSI4 */
+	PC16_PF_SSI4_FS,
+	PC17_PF_SSI4_RXD,
+	PC18_PF_SSI4_TXD,
+	PC19_PF_SSI4_CLK,
+};
+
 /*
  * Phytec's PCM038 comes with 2MiB battery buffered SRAM,
  * 16 bit width
@@ -88,107 +144,16 @@
 	.resource = &pcm038_flash_resource,
 };
 
-static int mxc_uart0_pins[] = {
-	PE12_PF_UART1_TXD,
-	PE13_PF_UART1_RXD,
-	PE14_PF_UART1_CTS,
-	PE15_PF_UART1_RTS
-};
-
-static int uart_mxc_port0_init(struct platform_device *pdev)
-{
-	return mxc_gpio_setup_multiple_pins(mxc_uart0_pins,
-			ARRAY_SIZE(mxc_uart0_pins), "UART0");
-}
-
-static int uart_mxc_port0_exit(struct platform_device *pdev)
-{
-	mxc_gpio_release_multiple_pins(mxc_uart0_pins,
-			ARRAY_SIZE(mxc_uart0_pins));
-	return 0;
-}
-
-static int mxc_uart1_pins[] = {
-	PE3_PF_UART2_CTS,
-	PE4_PF_UART2_RTS,
-	PE6_PF_UART2_TXD,
-	PE7_PF_UART2_RXD
-};
-
-static int uart_mxc_port1_init(struct platform_device *pdev)
-{
-	return mxc_gpio_setup_multiple_pins(mxc_uart1_pins,
-			ARRAY_SIZE(mxc_uart1_pins), "UART1");
-}
-
-static int uart_mxc_port1_exit(struct platform_device *pdev)
-{
-	mxc_gpio_release_multiple_pins(mxc_uart1_pins,
-			ARRAY_SIZE(mxc_uart1_pins));
-	return 0;
-}
-
-static int mxc_uart2_pins[] = { PE8_PF_UART3_TXD,
-				PE9_PF_UART3_RXD,
-				PE10_PF_UART3_CTS,
-				PE11_PF_UART3_RTS };
-
-static int uart_mxc_port2_init(struct platform_device *pdev)
-{
-	return mxc_gpio_setup_multiple_pins(mxc_uart2_pins,
-			ARRAY_SIZE(mxc_uart2_pins), "UART2");
-}
-
-static int uart_mxc_port2_exit(struct platform_device *pdev)
-{
-	mxc_gpio_release_multiple_pins(mxc_uart2_pins,
-			ARRAY_SIZE(mxc_uart2_pins));
-	return 0;
-}
-
 static struct imxuart_platform_data uart_pdata[] = {
 	{
-		.init = uart_mxc_port0_init,
-		.exit = uart_mxc_port0_exit,
 		.flags = IMXUART_HAVE_RTSCTS,
 	}, {
-		.init = uart_mxc_port1_init,
-		.exit = uart_mxc_port1_exit,
 		.flags = IMXUART_HAVE_RTSCTS,
 	}, {
-		.init = uart_mxc_port2_init,
-		.exit = uart_mxc_port2_exit,
 		.flags = IMXUART_HAVE_RTSCTS,
 	},
 };
 
-static int mxc_fec_pins[] = {
-	PD0_AIN_FEC_TXD0,
-	PD1_AIN_FEC_TXD1,
-	PD2_AIN_FEC_TXD2,
-	PD3_AIN_FEC_TXD3,
-	PD4_AOUT_FEC_RX_ER,
-	PD5_AOUT_FEC_RXD1,
-	PD6_AOUT_FEC_RXD2,
-	PD7_AOUT_FEC_RXD3,
-	PD8_AF_FEC_MDIO,
-	PD9_AIN_FEC_MDC,
-	PD10_AOUT_FEC_CRS,
-	PD11_AOUT_FEC_TX_CLK,
-	PD12_AOUT_FEC_RXD0,
-	PD13_AOUT_FEC_RX_DV,
-	PD14_AOUT_FEC_RX_CLK,
-	PD15_AOUT_FEC_COL,
-	PD16_AIN_FEC_TX_ER,
-	PF23_AIN_FEC_TX_EN
-};
-
-static void gpio_fec_active(void)
-{
-	mxc_gpio_setup_multiple_pins(mxc_fec_pins,
-			ARRAY_SIZE(mxc_fec_pins), "FEC");
-}
-
 static struct mxc_nand_platform_data pcm038_nand_board_info = {
 	.width = 1,
 	.hw_ecc = 1,
@@ -210,27 +175,8 @@
 	__raw_writel(0x22220a00, CSCR_A(1));
 }
 
-#ifdef CONFIG_I2C_IMX
-static int mxc_i2c1_pins[] = {
-	PC5_PF_I2C2_SDA,
-	PC6_PF_I2C2_SCL
-};
-
-static int pcm038_i2c_1_init(struct device *dev)
-{
-	return mxc_gpio_setup_multiple_pins(mxc_i2c1_pins, ARRAY_SIZE(mxc_i2c1_pins),
-			"I2C1");
-}
-
-static void pcm038_i2c_1_exit(struct device *dev)
-{
-	mxc_gpio_release_multiple_pins(mxc_i2c1_pins, ARRAY_SIZE(mxc_i2c1_pins));
-}
-
 static struct imxi2c_platform_data pcm038_i2c_1_data = {
 	.bitrate = 100000,
-	.init = pcm038_i2c_1_init,
-	.exit = pcm038_i2c_1_exit,
 };
 
 static struct at24_platform_data board_eeprom = {
@@ -253,11 +199,12 @@
 		.type = "lm75"
 	}
 };
-#endif
 
 static void __init pcm038_init(void)
 {
-	gpio_fec_active();
+	mxc_gpio_setup_multiple_pins(pcm038_pins, ARRAY_SIZE(pcm038_pins),
+			"PCM038");
+
 	pcm038_init_sram();
 
 	mxc_register_device(&mxc_uart_device0, &uart_pdata[0]);
@@ -267,13 +214,11 @@
 	mxc_gpio_mode(PE16_AF_OWIRE);
 	mxc_register_device(&mxc_nand_device, &pcm038_nand_board_info);
 
-#ifdef CONFIG_I2C_IMX
 	/* only the i2c master 1 is used on this CPU card */
 	i2c_register_board_info(1, pcm038_i2c_devices,
 				ARRAY_SIZE(pcm038_i2c_devices));
 
 	mxc_register_device(&mxc_i2c_device1, &pcm038_i2c_1_data);
-#endif
 
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 
@@ -295,7 +240,7 @@
 	.phys_io        = AIPI_BASE_ADDR,
 	.io_pg_offst    = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = PHYS_OFFSET + 0x100,
-	.map_io         = mxc_map_io,
+	.map_io         = mx27_map_io,
 	.init_irq       = mxc_init_irq,
 	.init_machine   = pcm038_init,
 	.timer          = &pcm038_timer,
diff --git a/arch/arm/mach-mx2/pcm970-baseboard.c b/arch/arm/mach-mx2/pcm970-baseboard.c
index bf4e520..6a3acaf 100644
--- a/arch/arm/mach-mx2/pcm970-baseboard.c
+++ b/arch/arm/mach-mx2/pcm970-baseboard.c
@@ -16,71 +16,107 @@
  * MA 02110-1301, USA.
  */
 
-#include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/irq.h>
+#include <linux/platform_device.h>
 
 #include <asm/mach/arch.h>
 
-#include <mach/hardware.h>
 #include <mach/common.h>
-#include <mach/mmc.h>
-#include <mach/imxfb.h>
 #include <mach/iomux.h>
+#include <mach/imxfb.h>
+#include <mach/hardware.h>
+#include <mach/mmc.h>
 
 #include "devices.h"
 
-static int pcm970_sdhc2_get_ro(struct device *dev)
-{
-	return gpio_get_value(GPIO_PORTC + 28);
-}
-
-static int pcm970_sdhc2_pins[] = {
+static int pcm970_pins[] = {
+	/* SDHC */
 	PB4_PF_SD2_D0,
 	PB5_PF_SD2_D1,
 	PB6_PF_SD2_D2,
 	PB7_PF_SD2_D3,
 	PB8_PF_SD2_CMD,
 	PB9_PF_SD2_CLK,
+	GPIO_PORTC | 28 | GPIO_GPIO | GPIO_IN, /* card detect */
+	/* display */
+	PA5_PF_LSCLK,
+	PA6_PF_LD0,
+	PA7_PF_LD1,
+	PA8_PF_LD2,
+	PA9_PF_LD3,
+	PA10_PF_LD4,
+	PA11_PF_LD5,
+	PA12_PF_LD6,
+	PA13_PF_LD7,
+	PA14_PF_LD8,
+	PA15_PF_LD9,
+	PA16_PF_LD10,
+	PA17_PF_LD11,
+	PA18_PF_LD12,
+	PA19_PF_LD13,
+	PA20_PF_LD14,
+	PA21_PF_LD15,
+	PA22_PF_LD16,
+	PA23_PF_LD17,
+	PA24_PF_REV,
+	PA25_PF_CLS,
+	PA26_PF_PS,
+	PA27_PF_SPL_SPR,
+	PA28_PF_HSYNC,
+	PA29_PF_VSYNC,
+	PA30_PF_CONTRAST,
+	PA31_PF_OE_ACD,
+	/*
+	 * it seems the data line misses a pullup, so we must enable
+	 * the internal pullup as a local workaround
+	 */
+	PD17_PF_I2C_DATA | GPIO_PUEN,
+	PD18_PF_I2C_CLK,
+	/* Camera */
+	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,
 };
 
+static int pcm970_sdhc2_get_ro(struct device *dev)
+{
+	return gpio_get_value(GPIO_PORTC + 28);
+}
+
 static int pcm970_sdhc2_init(struct device *dev, irq_handler_t detect_irq, void *data)
 {
 	int ret;
 
-	ret = mxc_gpio_setup_multiple_pins(pcm970_sdhc2_pins,
-		ARRAY_SIZE(pcm970_sdhc2_pins), "sdhc2");
-	if(ret)
-		return ret;
-
-	ret = request_irq(IRQ_GPIOC(29), detect_irq, 0,
+	ret = request_irq(IRQ_GPIOC(29), detect_irq, IRQF_TRIGGER_FALLING,
 				"imx-mmc-detect", data);
 	if (ret)
-		goto out_release_gpio;
-
-	set_irq_type(IRQ_GPIOC(29), IRQF_TRIGGER_FALLING);
+		return ret;
 
 	ret = gpio_request(GPIO_PORTC + 28, "imx-mmc-ro");
-	if (ret)
-		goto out_release_gpio;
+	if (ret) {
+		free_irq(IRQ_GPIOC(29), data);
+		return ret;
+	}
 
-	mxc_gpio_mode((GPIO_PORTC | 28) | GPIO_GPIO | GPIO_IN);
 	gpio_direction_input(GPIO_PORTC + 28);
 
 	return 0;
-
-out_release_gpio:
-	mxc_gpio_release_multiple_pins(pcm970_sdhc2_pins,
-			ARRAY_SIZE(pcm970_sdhc2_pins));
-	return ret;
 }
 
 static void pcm970_sdhc2_exit(struct device *dev, void *data)
 {
 	free_irq(IRQ_GPIOC(29), data);
 	gpio_free(GPIO_PORTC + 28);
-	mxc_gpio_release_multiple_pins(pcm970_sdhc2_pins,
-			ARRAY_SIZE(pcm970_sdhc2_pins));
 }
 
 static struct imxmmc_platform_data sdhc_pdata = {
@@ -89,29 +125,6 @@
 	.exit = pcm970_sdhc2_exit,
 };
 
-static int mxc_fb_pins[] = {
-	PA5_PF_LSCLK,	PA6_PF_LD0,	PA7_PF_LD1,	PA8_PF_LD2,
-	PA9_PF_LD3,	PA10_PF_LD4,	PA11_PF_LD5,	PA12_PF_LD6,
-	PA13_PF_LD7,	PA14_PF_LD8,	PA15_PF_LD9,	PA16_PF_LD10,
-	PA17_PF_LD11,	PA18_PF_LD12,	PA19_PF_LD13,	PA20_PF_LD14,
-	PA21_PF_LD15,	PA22_PF_LD16,	PA23_PF_LD17,	PA24_PF_REV,
-	PA25_PF_CLS,	PA26_PF_PS,	PA27_PF_SPL_SPR, PA28_PF_HSYNC,
-	PA29_PF_VSYNC,	PA30_PF_CONTRAST, PA31_PF_OE_ACD
-};
-
-static int pcm038_fb_init(struct platform_device *pdev)
-{
-	return mxc_gpio_setup_multiple_pins(mxc_fb_pins,
-			ARRAY_SIZE(mxc_fb_pins), "FB");
-}
-
-static int pcm038_fb_exit(struct platform_device *pdev)
-{
-	mxc_gpio_release_multiple_pins(mxc_fb_pins, ARRAY_SIZE(mxc_fb_pins));
-
-	return 0;
-}
-
 /*
  * Connected is a portrait Sharp-QVGA display
  * of type: LQ035Q7DH06
@@ -144,9 +157,6 @@
 	.pwmr		= 0x00A903FF,
 	.lscr1		= 0x00120300,
 	.dmacr		= 0x00020010,
-
-	.init = pcm038_fb_init,
-	.exit = pcm038_fb_exit,
 };
 
 /*
@@ -157,6 +167,9 @@
  */
 void __init pcm970_baseboard_init(void)
 {
+	mxc_gpio_setup_multiple_pins(pcm970_pins, ARRAY_SIZE(pcm970_pins),
+			"PCM970");
+
 	mxc_register_device(&mxc_fb_device, &pcm038_fb_data);
 	mxc_register_device(&mxc_sdhc_device1, &sdhc_pdata);
 }
diff --git a/arch/arm/mach-mx3/Kconfig b/arch/arm/mach-mx3/Kconfig
index 194b842..17a21a2 100644
--- a/arch/arm/mach-mx3/Kconfig
+++ b/arch/arm/mach-mx3/Kconfig
@@ -1,10 +1,12 @@
 if ARCH_MX3
 
 config ARCH_MX31
+	select ARCH_HAS_RNGA
 	bool
 
 config ARCH_MX35
 	bool
+	select ARCH_MXC_IOMUX_V3
 
 comment "MX3 platforms:"
 
@@ -37,7 +39,6 @@
 config MACH_MX31LITE
 	bool "Support MX31 LITEKIT (LogicPD)"
 	select ARCH_MX31
-	default n
 	help
 	  Include support for MX31 LITEKIT platform. This includes specific
 	  configurations for the board and its peripherals.
@@ -45,7 +46,6 @@
 config MACH_MX31_3DS
 	bool "Support MX31PDK (3DS)"
 	select ARCH_MX31
-	default n
 	help
 	  Include support for MX31PDK (3DS) platform. This includes specific
 	  configurations for the board and its peripherals.
@@ -53,17 +53,43 @@
 config MACH_MX31MOBOARD
 	bool "Support mx31moboard platforms (EPFL Mobots group)"
 	select ARCH_MX31
-	default n
 	help
 	  Include support for mx31moboard platform. This includes specific
 	  configurations for the board and its peripherals.
 
+config MACH_MX31LILLY
+	bool "Support MX31 LILLY-1131 platforms (INCO startec)"
+	select ARCH_MX31
+	help
+	  Include support for mx31 based LILLY1131 modules. This includes
+	  specific configurations for the board and its peripherals.
+
 config MACH_QONG
 	bool "Support Dave/DENX QongEVB-LITE platform"
 	select ARCH_MX31
-	default n
 	help
 	  Include support for Dave/DENX QongEVB-LITE platform. This includes
 	  specific configurations for the board and its peripherals.
 
+config MACH_PCM043
+	bool "Support Phytec pcm043 (i.MX35) platforms"
+	select ARCH_MX35
+	help
+	  Include support for Phytec pcm043 platform. This includes
+	  specific configurations for the board and its peripherals.
+
+config MACH_ARMADILLO5X0
+	bool "Support Atmark Armadillo-500 Development Base Board"
+	select ARCH_MX31
+	help
+	  Include support for Atmark Armadillo-500 platform. This includes
+	  specific configurations for the board and its peripherals.
+
+config MACH_MX35_3DS
+	bool "Support MX35PDK platform"
+	select ARCH_MX35
+	default n
+	help
+	  Include support for MX35PDK platform. This includes specific
+	  configurations for the board and its peripherals.
 endif
diff --git a/arch/arm/mach-mx3/Makefile b/arch/arm/mach-mx3/Makefile
index 272c8a9..0322696 100644
--- a/arch/arm/mach-mx3/Makefile
+++ b/arch/arm/mach-mx3/Makefile
@@ -8,9 +8,13 @@
 obj-$(CONFIG_ARCH_MX31)		+= clock.o iomux.o
 obj-$(CONFIG_ARCH_MX35)		+= clock-imx35.o
 obj-$(CONFIG_MACH_MX31ADS)	+= mx31ads.o
+obj-$(CONFIG_MACH_MX31LILLY)	+= mx31lilly.o mx31lilly-db.o
 obj-$(CONFIG_MACH_MX31LITE)	+= mx31lite.o
 obj-$(CONFIG_MACH_PCM037)	+= pcm037.o
 obj-$(CONFIG_MACH_MX31_3DS)	+= mx31pdk.o
 obj-$(CONFIG_MACH_MX31MOBOARD)	+= mx31moboard.o mx31moboard-devboard.o \
 				   mx31moboard-marxbot.o
 obj-$(CONFIG_MACH_QONG)		+= qong.o
+obj-$(CONFIG_MACH_PCM043)	+= pcm043.o
+obj-$(CONFIG_MACH_ARMADILLO5X0) += armadillo5x0.o
+obj-$(CONFIG_MACH_MX35_3DS)	+= mx35pdk.o
diff --git a/arch/arm/mach-mx3/armadillo5x0.c b/arch/arm/mach-mx3/armadillo5x0.c
new file mode 100644
index 0000000..54118109
--- /dev/null
+++ b/arch/arm/mach-mx3/armadillo5x0.c
@@ -0,0 +1,295 @@
+/*
+ * armadillo5x0.c
+ *
+ * Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ * updates in http://alberdroid.blogspot.com/
+ *
+ * Based on Atmark Techno, Inc. armadillo 500 BSP 2008
+ * Based on mx31ads.c and pcm037.c Great Work!
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/types.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/smsc911x.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/memory.h>
+#include <asm/mach/map.h>
+
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx3.h>
+#include <mach/board-armadillo5x0.h>
+#include <mach/mmc.h>
+#include <mach/ipu.h>
+#include <mach/mx3fb.h>
+
+#include "devices.h"
+
+static int armadillo5x0_pins[] = {
+	/* UART1 */
+	MX31_PIN_CTS1__CTS1,
+	MX31_PIN_RTS1__RTS1,
+	MX31_PIN_TXD1__TXD1,
+	MX31_PIN_RXD1__RXD1,
+	/* UART2 */
+	MX31_PIN_CTS2__CTS2,
+	MX31_PIN_RTS2__RTS2,
+	MX31_PIN_TXD2__TXD2,
+	MX31_PIN_RXD2__RXD2,
+	/* LAN9118_IRQ */
+	IOMUX_MODE(MX31_PIN_GPIO1_0, IOMUX_CONFIG_GPIO),
+	/* SDHC1 */
+	MX31_PIN_SD1_DATA3__SD1_DATA3,
+	MX31_PIN_SD1_DATA2__SD1_DATA2,
+	MX31_PIN_SD1_DATA1__SD1_DATA1,
+	MX31_PIN_SD1_DATA0__SD1_DATA0,
+	MX31_PIN_SD1_CLK__SD1_CLK,
+	MX31_PIN_SD1_CMD__SD1_CMD,
+	/* Framebuffer */
+	MX31_PIN_LD0__LD0,
+	MX31_PIN_LD1__LD1,
+	MX31_PIN_LD2__LD2,
+	MX31_PIN_LD3__LD3,
+	MX31_PIN_LD4__LD4,
+	MX31_PIN_LD5__LD5,
+	MX31_PIN_LD6__LD6,
+	MX31_PIN_LD7__LD7,
+	MX31_PIN_LD8__LD8,
+	MX31_PIN_LD9__LD9,
+	MX31_PIN_LD10__LD10,
+	MX31_PIN_LD11__LD11,
+	MX31_PIN_LD12__LD12,
+	MX31_PIN_LD13__LD13,
+	MX31_PIN_LD14__LD14,
+	MX31_PIN_LD15__LD15,
+	MX31_PIN_LD16__LD16,
+	MX31_PIN_LD17__LD17,
+	MX31_PIN_VSYNC3__VSYNC3,
+	MX31_PIN_HSYNC__HSYNC,
+	MX31_PIN_FPSHIFT__FPSHIFT,
+	MX31_PIN_DRDY0__DRDY0,
+	IOMUX_MODE(MX31_PIN_LCS1, IOMUX_CONFIG_GPIO), /*ADV7125_PSAVE*/
+
+};
+
+/*
+ * FB support
+ */
+static const struct fb_videomode fb_modedb[] = {
+	{	/* 640x480 @ 60 Hz */
+		.name		= "CRT-VGA",
+		.refresh	= 60,
+		.xres		= 640,
+		.yres		= 480,
+		.pixclock	= 39721,
+		.left_margin	= 35,
+		.right_margin	= 115,
+		.upper_margin	= 43,
+		.lower_margin	= 1,
+		.hsync_len	= 10,
+		.vsync_len	= 1,
+		.sync		= FB_SYNC_OE_ACT_HIGH,
+		.vmode		= FB_VMODE_NONINTERLACED,
+		.flag		= 0,
+	}, {/* 800x600 @ 56 Hz */
+		.name		= "CRT-SVGA",
+		.refresh	= 56,
+		.xres		= 800,
+		.yres		= 600,
+		.pixclock	= 30000,
+		.left_margin	= 30,
+		.right_margin	= 108,
+		.upper_margin	= 13,
+		.lower_margin	= 10,
+		.hsync_len	= 10,
+		.vsync_len	= 1,
+		.sync		= FB_SYNC_OE_ACT_HIGH | FB_SYNC_HOR_HIGH_ACT |
+				  FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED,
+		.flag		= 0,
+	},
+};
+
+static struct ipu_platform_data mx3_ipu_data = {
+	.irq_base = MXC_IPU_IRQ_START,
+};
+
+static struct mx3fb_platform_data mx3fb_pdata = {
+	.dma_dev	= &mx3_ipu.dev,
+	.name		= "CRT-VGA",
+	.mode		= fb_modedb,
+	.num_modes	= ARRAY_SIZE(fb_modedb),
+};
+
+/*
+ * SDHC 1
+ * MMC support
+ */
+static int armadillo5x0_sdhc1_get_ro(struct device *dev)
+{
+	return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_ATA_RESET_B));
+}
+
+static int armadillo5x0_sdhc1_init(struct device *dev,
+				   irq_handler_t detect_irq, void *data)
+{
+	int ret;
+	int gpio_det, gpio_wp;
+
+	gpio_det = IOMUX_TO_GPIO(MX31_PIN_ATA_DMACK);
+	gpio_wp = IOMUX_TO_GPIO(MX31_PIN_ATA_RESET_B);
+
+	ret = gpio_request(gpio_det, "sdhc-card-detect");
+	if (ret)
+		return ret;
+
+	gpio_direction_input(gpio_det);
+
+	ret = gpio_request(gpio_wp, "sdhc-write-protect");
+	if (ret)
+		goto err_gpio_free;
+
+	gpio_direction_input(gpio_wp);
+
+	/* When supported the trigger type have to be BOTH */
+	ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_ATA_DMACK), detect_irq,
+			  IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+			  "sdhc-detect", data);
+
+	if (ret)
+		goto err_gpio_free_2;
+
+	return 0;
+
+err_gpio_free_2:
+	gpio_free(gpio_wp);
+
+err_gpio_free:
+	gpio_free(gpio_det);
+
+	return ret;
+
+}
+
+static void armadillo5x0_sdhc1_exit(struct device *dev, void *data)
+{
+	free_irq(IOMUX_TO_IRQ(MX31_PIN_ATA_DMACK), data);
+	gpio_free(IOMUX_TO_GPIO(MX31_PIN_ATA_DMACK));
+	gpio_free(IOMUX_TO_GPIO(MX31_PIN_ATA_RESET_B));
+}
+
+static struct imxmmc_platform_data sdhc_pdata = {
+	.get_ro = armadillo5x0_sdhc1_get_ro,
+	.init = armadillo5x0_sdhc1_init,
+	.exit = armadillo5x0_sdhc1_exit,
+};
+
+/*
+ * SMSC 9118
+ * Network support
+ */
+static struct resource armadillo5x0_smc911x_resources[] = {
+	{
+		.start	= CS3_BASE_ADDR,
+		.end	= CS3_BASE_ADDR + SZ_32M - 1,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IOMUX_TO_IRQ(MX31_PIN_GPIO1_0),
+		.end	= IOMUX_TO_IRQ(MX31_PIN_GPIO1_0),
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+	},
+};
+
+static struct smsc911x_platform_config smsc911x_info = {
+	.flags		= SMSC911X_USE_32BIT,
+	.irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
+};
+
+static struct platform_device armadillo5x0_smc911x_device = {
+	.name           = "smsc911x",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(armadillo5x0_smc911x_resources),
+	.resource       = armadillo5x0_smc911x_resources,
+	.dev            = {
+		.platform_data = &smsc911x_info,
+	},
+};
+
+/* UART device data */
+static struct imxuart_platform_data uart_pdata = {
+	.flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct platform_device *devices[] __initdata = {
+	&armadillo5x0_smc911x_device,
+};
+
+/*
+ * Perform board specific initializations
+ */
+static void __init armadillo5x0_init(void)
+{
+	mxc_iomux_setup_multiple_pins(armadillo5x0_pins,
+			ARRAY_SIZE(armadillo5x0_pins), "armadillo5x0");
+
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+
+	/* Register UART */
+	mxc_register_device(&mxc_uart_device0, &uart_pdata);
+	mxc_register_device(&mxc_uart_device1, &uart_pdata);
+
+	/* SMSC9118 IRQ pin */
+	gpio_direction_input(MX31_PIN_GPIO1_0);
+
+	/* Register SDHC */
+	mxc_register_device(&mxcsdhc_device0, &sdhc_pdata);
+
+	/* Register FB */
+	mxc_register_device(&mx3_ipu, &mx3_ipu_data);
+	mxc_register_device(&mx3_fb, &mx3fb_pdata);
+}
+
+static void __init armadillo5x0_timer_init(void)
+{
+	mx31_clocks_init(26000000);
+}
+
+static struct sys_timer armadillo5x0_timer = {
+	.init	= armadillo5x0_timer_init,
+};
+
+MACHINE_START(ARMADILLO5X0, "Armadillo-500")
+	/* Maintainer: Alberto Panizzo  */
+	.phys_io	= AIPS1_BASE_ADDR,
+	.io_pg_offst	= ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+	.boot_params	= PHYS_OFFSET + 0x00000100,
+	.map_io		= mx31_map_io,
+	.init_irq	= mxc_init_irq,
+	.timer		= &armadillo5x0_timer,
+	.init_machine	= armadillo5x0_init,
+MACHINE_END
diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-mx3/clock-imx35.c
index 3c1e06f..577ee83 100644
--- a/arch/arm/mach-mx3/clock-imx35.c
+++ b/arch/arm/mach-mx3/clock-imx35.c
@@ -147,34 +147,16 @@
 	{ .arm = 0, .ahb = 0, .sel = 0},
 };
 
-static struct arm_ahb_div clk_automotive[] = {
-	{ .arm = 1, .ahb = 3, .sel = 0},
-	{ .arm = 1, .ahb = 2, .sel = 1},
-	{ .arm = 2, .ahb = 1, .sel = 1},
-	{ .arm = 0, .ahb = 0, .sel = 0},
-	{ .arm = 1, .ahb = 6, .sel = 0},
-	{ .arm = 1, .ahb = 4, .sel = 1},
-	{ .arm = 2, .ahb = 2, .sel = 1},
-	{ .arm = 0, .ahb = 0, .sel = 0},
-};
-
 static unsigned long get_rate_arm(void)
 {
 	unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0);
 	struct arm_ahb_div *aad;
 	unsigned long fref = get_rate_mpll();
 
-	if (pdr0 & 1) {
-		/* consumer path */
-		aad = &clk_consumer[(pdr0 >> 16) & 0xf];
-		if (aad->sel)
-			fref = fref * 2 / 3;
-	} else {
-		/* auto path */
-		aad = &clk_automotive[(pdr0 >> 9) & 0x7];
-		if (aad->sel)
-			fref = fref * 3 / 4;
-	}
+	aad = &clk_consumer[(pdr0 >> 16) & 0xf];
+	if (aad->sel)
+		fref = fref * 2 / 3;
+
 	return fref / aad->arm;
 }
 
@@ -184,12 +166,7 @@
 	struct arm_ahb_div *aad;
 	unsigned long fref = get_rate_mpll();
 
-	if (pdr0 & 1)
-		/* consumer path */
-		aad = &clk_consumer[(pdr0 >> 16) & 0xf];
-	else
-		/* auto path */
-		aad = &clk_automotive[(pdr0 >> 9) & 0x7];
+	aad = &clk_consumer[(pdr0 >> 16) & 0xf];
 
 	return fref / aad->ahb;
 }
@@ -430,7 +407,8 @@
 	_REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk)
 	_REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_clk)
 	_REGISTER_CLOCK(NULL, "iomuxc", iomuxc_clk)
-	_REGISTER_CLOCK(NULL, "ipu", ipu_clk)
+	_REGISTER_CLOCK("ipu-core", NULL, ipu_clk)
+	_REGISTER_CLOCK("mx3_sdc_fb", NULL, ipu_clk)
 	_REGISTER_CLOCK(NULL, "kpp", kpp_clk)
 	_REGISTER_CLOCK(NULL, "mlb", mlb_clk)
 	_REGISTER_CLOCK(NULL, "mshc", mshc_clk)
@@ -462,8 +440,6 @@
 	int i;
 	unsigned int ll = 0;
 
-	mxc_set_cpu_type(MXC_CPU_MX35);
-
 #ifdef CONFIG_DEBUG_LL_CONSOLE
 	ll = (3 << 16);
 #endif
diff --git a/arch/arm/mach-mx3/clock.c b/arch/arm/mach-mx3/clock.c
index a68fcf9..8b14239 100644
--- a/arch/arm/mach-mx3/clock.c
+++ b/arch/arm/mach-mx3/clock.c
@@ -483,7 +483,7 @@
 DEFINE_CLOCK(mpeg4_clk,   0, MXC_CCM_CGR1,  0, NULL, NULL, &ahb_clk);
 DEFINE_CLOCK(mstick1_clk, 0, MXC_CCM_CGR1,  2, mstick1_get_rate, NULL, &usb_pll_clk);
 DEFINE_CLOCK(mstick2_clk, 1, MXC_CCM_CGR1,  4, mstick2_get_rate, NULL, &usb_pll_clk);
-DEFINE_CLOCK1(csi_clk,    0, MXC_CCM_CGR1,  6, csi, NULL, &ahb_clk);
+DEFINE_CLOCK1(csi_clk,    0, MXC_CCM_CGR1,  6, csi, NULL, &serial_pll_clk);
 DEFINE_CLOCK(rtc_clk,     0, MXC_CCM_CGR1,  8, NULL, NULL, &ipg_clk);
 DEFINE_CLOCK(wdog_clk,    0, MXC_CCM_CGR1, 10, NULL, NULL, &ipg_clk);
 DEFINE_CLOCK(pwm_clk,     0, MXC_CCM_CGR1, 12, NULL, NULL, &perclk_clk);
@@ -566,13 +566,18 @@
 	u32 reg;
 	int i;
 
-	mxc_set_cpu_type(MXC_CPU_MX31);
-
 	ckih_rate = fref;
 
 	for (i = 0; i < ARRAY_SIZE(lookups); i++)
 		clkdev_add(&lookups[i]);
 
+	/* change the csi_clk parent if necessary */
+	reg = __raw_readl(MXC_CCM_CCMR);
+	if (!(reg & MXC_CCM_CCMR_CSCS))
+		if (clk_set_parent(&csi_clk, &usb_pll_clk))
+			pr_err("%s: error changing csi_clk parent\n", __func__);
+
+
 	/* Turn off all possible clocks */
 	__raw_writel((3 << 4), MXC_CCM_CGR0);
 	__raw_writel(0, MXC_CCM_CGR1);
@@ -581,6 +586,12 @@
 					   MX32, but still required to be set */
 		     MXC_CCM_CGR2);
 
+	/*
+	 * Before turning off usb_pll make sure ipg_per_clk is generated
+	 * by ipg_clk and not usb_pll.
+	 */
+	__raw_writel(__raw_readl(MXC_CCM_CCMR) | (1 << 24), MXC_CCM_CCMR);
+
 	usb_pll_disable(&usb_pll_clk);
 
 	pr_info("Clock input source is %ld\n", clk_get_rate(&ckih_clk));
diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c
index 380be0c..d927edd 100644
--- a/arch/arm/mach-mx3/devices.c
+++ b/arch/arm/mach-mx3/devices.c
@@ -17,13 +17,17 @@
  * Boston, MA  02110-1301, USA.
  */
 
+#include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/serial.h>
 #include <linux/gpio.h>
+#include <linux/dma-mapping.h>
 #include <mach/hardware.h>
 #include <mach/irqs.h>
+#include <mach/common.h>
 #include <mach/imx-uart.h>
+#include <mach/mx3_camera.h>
 
 #include "devices.h"
 
@@ -283,6 +287,21 @@
 	.num_resources = ARRAY_SIZE(mxcsdhc1_resources),
 	.resource = mxcsdhc1_resources,
 };
+
+static struct resource rnga_resources[] = {
+	{
+		.start = RNGA_BASE_ADDR,
+		.end = RNGA_BASE_ADDR + 0x28,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device mxc_rnga_device = {
+	.name = "mxc_rnga",
+	.id = -1,
+	.num_resources = 1,
+	.resource = rnga_resources,
+};
 #endif /* CONFIG_ARCH_MX31 */
 
 /* i.MX31 Image Processing Unit */
@@ -329,10 +348,54 @@
 	.num_resources	= ARRAY_SIZE(fb_resources),
 	.resource	= fb_resources,
 	.dev		= {
-		.coherent_dma_mask = 0xffffffff,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
        },
 };
 
+static struct resource camera_resources[] = {
+	{
+		.start	= IPU_CTRL_BASE_ADDR + 0x60,
+		.end	= IPU_CTRL_BASE_ADDR + 0x87,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device mx3_camera = {
+	.name		= "mx3-camera",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(camera_resources),
+	.resource	= camera_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource otg_resources[] = {
+	{
+		.start	= OTG_BASE_ADDR,
+		.end	= OTG_BASE_ADDR + 0x1ff,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= MXC_INT_USB3,
+		.end	= MXC_INT_USB3,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static u64 otg_dmamask = DMA_BIT_MASK(32);
+
+/* OTG gadget device */
+struct platform_device mxc_otg_udc_device = {
+	.name		= "fsl-usb2-udc",
+	.id		= -1,
+	.dev		= {
+		.dma_mask		= &otg_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= otg_resources,
+	.num_resources	= ARRAY_SIZE(otg_resources),
+};
+
 #ifdef CONFIG_ARCH_MX35
 static struct resource mxc_fec_resources[] = {
 	{
@@ -359,6 +422,7 @@
 	if (cpu_is_mx31()) {
 		mxc_nand_resources[0].start = MX31_NFC_BASE_ADDR;
 		mxc_nand_resources[0].end = MX31_NFC_BASE_ADDR + 0xfff;
+		mxc_register_device(&mxc_rnga_device, NULL);
 	}
 	if (cpu_is_mx35()) {
 		mxc_nand_resources[0].start = MX35_NFC_BASE_ADDR;
diff --git a/arch/arm/mach-mx3/devices.h b/arch/arm/mach-mx3/devices.h
index 88c04b2..ffd494d 100644
--- a/arch/arm/mach-mx3/devices.h
+++ b/arch/arm/mach-mx3/devices.h
@@ -11,6 +11,10 @@
 extern struct platform_device mxc_i2c_device2;
 extern struct platform_device mx3_ipu;
 extern struct platform_device mx3_fb;
+extern struct platform_device mx3_camera;
 extern struct platform_device mxc_fec_device;
 extern struct platform_device mxcsdhc_device0;
 extern struct platform_device mxcsdhc_device1;
+extern struct platform_device mxc_otg_udc_device;
+extern struct platform_device mxc_rnga_device;
+
diff --git a/arch/arm/mach-mx3/iomux.c b/arch/arm/mach-mx3/iomux.c
index 40ffc5a..c66ccbc 100644
--- a/arch/arm/mach-mx3/iomux.c
+++ b/arch/arm/mach-mx3/iomux.c
@@ -21,7 +21,6 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/io.h>
-#include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
@@ -94,15 +93,13 @@
 EXPORT_SYMBOL(mxc_iomux_set_pad);
 
 /*
- * setups a single pin:
+ * allocs a single pin:
  * 	- reserves the pin so that it is not claimed by another driver
  * 	- setups the iomux according to the configuration
- * 	- if the pin is configured as a GPIO, we claim it through kernel gpiolib
  */
-int mxc_iomux_setup_pin(const unsigned int pin, const char *label)
+int mxc_iomux_alloc_pin(const unsigned int pin, const char *label)
 {
 	unsigned pad = pin & IOMUX_PADNUM_MASK;
-	unsigned gpio;
 
 	if (pad >= (PIN_MAX + 1)) {
 		printk(KERN_ERR "mxc_iomux: Attempt to request nonexistant pin %u for \"%s\"\n",
@@ -113,19 +110,13 @@
 	if (test_and_set_bit(pad, mxc_pin_alloc_map)) {
 		printk(KERN_ERR "mxc_iomux: pin %u already used. Allocation for \"%s\" failed\n",
 			pad, label ? label : "?");
-		return -EINVAL;
+		return -EBUSY;
 	}
 	mxc_iomux_mode(pin);
 
-	/* if we have a gpio, we can allocate it */
-	gpio = (pin & IOMUX_GPIONUM_MASK) >> IOMUX_GPIONUM_SHIFT;
-	if (gpio < (GPIO_PORT_MAX + 1) * 32)
-		if (gpio_request(gpio, label))
-			return -EINVAL;
-
 	return 0;
 }
-EXPORT_SYMBOL(mxc_iomux_setup_pin);
+EXPORT_SYMBOL(mxc_iomux_alloc_pin);
 
 int mxc_iomux_setup_multiple_pins(unsigned int *pin_list, unsigned count,
 		const char *label)
@@ -135,7 +126,8 @@
 	int ret = -EINVAL;
 
 	for (i = 0; i < count; i++) {
-		if (mxc_iomux_setup_pin(*p, label))
+		ret = mxc_iomux_alloc_pin(*p, label);
+		if (ret)
 			goto setup_error;
 		p++;
 	}
@@ -150,14 +142,9 @@
 void mxc_iomux_release_pin(const unsigned int pin)
 {
 	unsigned pad = pin & IOMUX_PADNUM_MASK;
-	unsigned gpio;
 
 	if (pad < (PIN_MAX + 1))
 		clear_bit(pad, mxc_pin_alloc_map);
-
-	gpio = (pin & IOMUX_GPIONUM_MASK) >> IOMUX_GPIONUM_SHIFT;
-	if (gpio < (GPIO_PORT_MAX + 1) * 32)
-		gpio_free(gpio);
 }
 EXPORT_SYMBOL(mxc_iomux_release_pin);
 
diff --git a/arch/arm/mach-mx3/mm.c b/arch/arm/mach-mx3/mm.c
index 9e1459c..1f5fdd4 100644
--- a/arch/arm/mach-mx3/mm.c
+++ b/arch/arm/mach-mx3/mm.c
@@ -72,8 +72,17 @@
  * system startup to create static physical to virtual memory mappings
  * for the IO modules.
  */
-void __init mxc_map_io(void)
+void __init mx31_map_io(void)
 {
+	mxc_set_cpu_type(MXC_CPU_MX31);
+
+	iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
+}
+
+void __init mx35_map_io(void)
+{
+	mxc_set_cpu_type(MXC_CPU_MX35);
+
 	iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
 }
 
diff --git a/arch/arm/mach-mx3/mx31ads.c b/arch/arm/mach-mx3/mx31ads.c
index a6d6efe..30e2767 100644
--- a/arch/arm/mach-mx3/mx31ads.c
+++ b/arch/arm/mach-mx3/mx31ads.c
@@ -187,7 +187,7 @@
 	/*
 	 * Configure INT line as GPIO input
 	 */
-	mxc_iomux_setup_pin(IOMUX_MODE(MX31_PIN_GPIO1_4, IOMUX_CONFIG_GPIO), "expio");
+	mxc_iomux_alloc_pin(IOMUX_MODE(MX31_PIN_GPIO1_4, IOMUX_CONFIG_GPIO), "expio");
 
 	/* disable the interrupt and clear the status */
 	__raw_writew(0xFFFF, PBC_INTMASK_CLEAR_REG);
@@ -511,7 +511,7 @@
  */
 static void __init mx31ads_map_io(void)
 {
-	mxc_map_io();
+	mx31_map_io();
 	iotable_init(mx31ads_io_desc, ARRAY_SIZE(mx31ads_io_desc));
 }
 
diff --git a/arch/arm/mach-mx3/mx31lilly-db.c b/arch/arm/mach-mx3/mx31lilly-db.c
new file mode 100644
index 0000000..3b3a78f
--- /dev/null
+++ b/arch/arm/mach-mx3/mx31lilly-db.c
@@ -0,0 +1,216 @@
+/*
+ *  LILLY-1131 development board support
+ *
+ *    Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ *  based on code for other MX31 boards,
+ *
+ *    Copyright 2005-2007 Freescale Semiconductor
+ *    Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ *    Copyright (C) 2009 Valentin Longchamp, EPFL Mobots group
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/init.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx3.h>
+#include <mach/board-mx31lilly.h>
+#include <mach/mmc.h>
+#include <mach/mx3fb.h>
+#include <mach/ipu.h>
+
+#include "devices.h"
+
+/*
+ * This file contains board-specific initialization routines for the
+ * LILLY-1131 development board. If you design an own baseboard for the
+ * module, use this file as base for support code.
+ */
+
+static unsigned int lilly_db_board_pins[] __initdata = {
+	MX31_PIN_CTS1__CTS1,
+	MX31_PIN_RTS1__RTS1,
+	MX31_PIN_TXD1__TXD1,
+	MX31_PIN_RXD1__RXD1,
+	MX31_PIN_CTS2__CTS2,
+	MX31_PIN_RTS2__RTS2,
+	MX31_PIN_TXD2__TXD2,
+	MX31_PIN_RXD2__RXD2,
+	MX31_PIN_CSPI3_MOSI__RXD3,
+	MX31_PIN_CSPI3_MISO__TXD3,
+	MX31_PIN_CSPI3_SCLK__RTS3,
+	MX31_PIN_CSPI3_SPI_RDY__CTS3,
+	MX31_PIN_SD1_DATA3__SD1_DATA3,
+	MX31_PIN_SD1_DATA2__SD1_DATA2,
+	MX31_PIN_SD1_DATA1__SD1_DATA1,
+	MX31_PIN_SD1_DATA0__SD1_DATA0,
+	MX31_PIN_SD1_CLK__SD1_CLK,
+	MX31_PIN_SD1_CMD__SD1_CMD,
+	MX31_PIN_LD0__LD0,
+	MX31_PIN_LD1__LD1,
+	MX31_PIN_LD2__LD2,
+	MX31_PIN_LD3__LD3,
+	MX31_PIN_LD4__LD4,
+	MX31_PIN_LD5__LD5,
+	MX31_PIN_LD6__LD6,
+	MX31_PIN_LD7__LD7,
+	MX31_PIN_LD8__LD8,
+	MX31_PIN_LD9__LD9,
+	MX31_PIN_LD10__LD10,
+	MX31_PIN_LD11__LD11,
+	MX31_PIN_LD12__LD12,
+	MX31_PIN_LD13__LD13,
+	MX31_PIN_LD14__LD14,
+	MX31_PIN_LD15__LD15,
+	MX31_PIN_LD16__LD16,
+	MX31_PIN_LD17__LD17,
+	MX31_PIN_VSYNC3__VSYNC3,
+	MX31_PIN_HSYNC__HSYNC,
+	MX31_PIN_FPSHIFT__FPSHIFT,
+	MX31_PIN_DRDY0__DRDY0,
+	MX31_PIN_CONTRAST__CONTRAST,
+};
+
+/* UART */
+static struct imxuart_platform_data uart_pdata __initdata = {
+	.flags = IMXUART_HAVE_RTSCTS,
+};
+
+/* MMC support */
+
+static int mxc_mmc1_get_ro(struct device *dev)
+{
+	return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_LCS0));
+}
+
+static int gpio_det, gpio_wp;
+
+static int mxc_mmc1_init(struct device *dev,
+			 irq_handler_t detect_irq, void *data)
+{
+	int ret;
+
+	gpio_det = IOMUX_TO_GPIO(MX31_PIN_GPIO1_1);
+	gpio_wp = IOMUX_TO_GPIO(MX31_PIN_LCS0);
+
+	ret = gpio_request(gpio_det, "MMC detect");
+	if (ret)
+		return ret;
+
+	ret = gpio_request(gpio_wp, "MMC w/p");
+	if (ret)
+		goto exit_free_det;
+
+	gpio_direction_input(gpio_det);
+	gpio_direction_input(gpio_wp);
+
+	ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_GPIO1_1), detect_irq,
+			  IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+			  "MMC detect", data);
+	if (ret)
+		goto exit_free_wp;
+
+	return 0;
+
+exit_free_wp:
+	gpio_free(gpio_wp);
+
+exit_free_det:
+	gpio_free(gpio_det);
+
+	return ret;
+}
+
+static void mxc_mmc1_exit(struct device *dev, void *data)
+{
+	gpio_free(gpio_det);
+	gpio_free(gpio_wp);
+	free_irq(IOMUX_TO_IRQ(MX31_PIN_GPIO1_1), data);
+}
+
+static struct imxmmc_platform_data mmc_pdata = {
+	.get_ro	= mxc_mmc1_get_ro,
+	.init	= mxc_mmc1_init,
+	.exit	= mxc_mmc1_exit,
+};
+
+/* Framebuffer support */
+static struct ipu_platform_data ipu_data __initdata = {
+	.irq_base = MXC_IPU_IRQ_START,
+};
+
+static const struct fb_videomode fb_modedb = {
+	/* 640x480 TFT panel (IPS-056T) */
+	.name	   	= "CRT-VGA",
+	.refresh	= 64,
+	.xres		= 640,
+	.yres		= 480,
+	.pixclock	= 30000,
+	.left_margin	= 200,
+	.right_margin	= 2,
+	.upper_margin	= 2,
+	.lower_margin	= 2,
+	.hsync_len	= 3,
+	.vsync_len	= 1,
+	.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH,
+	.vmode		= FB_VMODE_NONINTERLACED,
+	.flag		= 0,
+};
+
+static struct mx3fb_platform_data fb_pdata __initdata = {
+	.dma_dev	= &mx3_ipu.dev,
+	.name		= "CRT-VGA",
+	.mode		= &fb_modedb,
+	.num_modes	= 1,
+};
+
+#define LCD_VCC_EN_GPIO	 (7)
+
+static void __init mx31lilly_init_fb(void)
+{
+	if (gpio_request(LCD_VCC_EN_GPIO, "LCD enable") != 0) {
+		printk(KERN_WARNING "unable to request LCD_VCC_EN pin.\n");
+		return;
+	}
+
+	mxc_register_device(&mx3_ipu, &ipu_data);
+	mxc_register_device(&mx3_fb, &fb_pdata);
+	gpio_direction_output(LCD_VCC_EN_GPIO, 1);
+}
+
+void __init mx31lilly_db_init(void)
+{
+	mxc_iomux_setup_multiple_pins(lilly_db_board_pins,
+					ARRAY_SIZE(lilly_db_board_pins),
+					"development board pins");
+	mxc_register_device(&mxc_uart_device0, &uart_pdata);
+	mxc_register_device(&mxc_uart_device1, &uart_pdata);
+	mxc_register_device(&mxc_uart_device2, &uart_pdata);
+	mxc_register_device(&mxcsdhc_device0, &mmc_pdata);
+	mx31lilly_init_fb();
+}
+
diff --git a/arch/arm/mach-mx3/mx31lilly.c b/arch/arm/mach-mx3/mx31lilly.c
new file mode 100644
index 0000000..6ab2f16
--- /dev/null
+++ b/arch/arm/mach-mx3/mx31lilly.c
@@ -0,0 +1,155 @@
+/*
+ *  LILLY-1131 module support
+ *
+ *    Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ *  based on code for other MX31 boards,
+ *
+ *    Copyright 2005-2007 Freescale Semiconductor
+ *    Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ *    Copyright (C) 2009 Valentin Longchamp, EPFL Mobots group
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/smsc911x.h>
+#include <linux/mtd/physmap.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/iomux-mx3.h>
+#include <mach/board-mx31lilly.h>
+
+#include "devices.h"
+
+/*
+ * This file contains module-specific initialization routines for LILLY-1131.
+ * Initialization of peripherals found on the baseboard is implemented in the
+ * appropriate baseboard support code.
+ */
+
+/* SMSC ethernet support */
+
+static struct resource smsc91x_resources[] = {
+	{
+		.start	= CS4_BASE_ADDR,
+		.end	= CS4_BASE_ADDR + 0xffff,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IOMUX_TO_IRQ(MX31_PIN_GPIO1_0),
+		.end	= IOMUX_TO_IRQ(MX31_PIN_GPIO1_0),
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_FALLING,
+	}
+};
+
+static struct smsc911x_platform_config smsc911x_config = {
+	.phy_interface	= PHY_INTERFACE_MODE_MII,
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type	= SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+	.flags		= SMSC911X_USE_32BIT |
+			  SMSC911X_SAVE_MAC_ADDRESS |
+			  SMSC911X_FORCE_INTERNAL_PHY,
+};
+
+static struct platform_device smsc91x_device = {
+	.name		= "smsc911x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(smsc91x_resources),
+	.resource	= smsc91x_resources,
+	.dev		= {
+		.platform_data = &smsc911x_config,
+	}
+};
+
+/* NOR flash */
+static struct physmap_flash_data nor_flash_data = {
+	.width  = 2,
+};
+
+static struct resource nor_flash_resource = {
+	.start	= 0xa0000000,
+	.end	= 0xa1ffffff,
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct platform_device physmap_flash_device = {
+	.name	= "physmap-flash",
+	.id	= 0,
+	.dev	= {
+		.platform_data  = &nor_flash_data,
+	},
+	.resource = &nor_flash_resource,
+	.num_resources = 1,
+};
+
+static struct platform_device *devices[] __initdata = {
+	&smsc91x_device,
+	&physmap_flash_device,
+	&mxc_i2c_device1,
+};
+
+static int mx31lilly_baseboard;
+core_param(mx31lilly_baseboard, mx31lilly_baseboard, int, 0444);
+
+static void __init mx31lilly_board_init(void)
+{
+	switch (mx31lilly_baseboard) {
+	case MX31LILLY_NOBOARD:
+		break;
+	case MX31LILLY_DB:
+		mx31lilly_db_init();
+		break;
+	default:
+		printk(KERN_ERR "Illegal mx31lilly_baseboard type %d\n",
+			mx31lilly_baseboard);
+	}
+
+	mxc_iomux_alloc_pin(MX31_PIN_CS4__CS4, "Ethernet CS");
+	mxc_iomux_alloc_pin(MX31_PIN_CSPI2_MOSI__SCL, "I2C SCL");
+	mxc_iomux_alloc_pin(MX31_PIN_CSPI2_MISO__SDA, "I2C SDA");
+
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+static void __init mx31lilly_timer_init(void)
+{
+	mx31_clocks_init(26000000);
+}
+
+static struct sys_timer mx31lilly_timer = {
+	.init	= mx31lilly_timer_init,
+};
+
+MACHINE_START(LILLY1131, "INCO startec LILLY-1131")
+	.phys_io	= AIPS1_BASE_ADDR,
+	.io_pg_offst	= ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+	.boot_params	= PHYS_OFFSET + 0x100,
+	.map_io		= mx31_map_io,
+	.init_irq	= mxc_init_irq,
+	.init_machine	= mx31lilly_board_init,
+	.timer		= &mx31lilly_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-mx3/mx31lite.c b/arch/arm/mach-mx3/mx31lite.c
index 894d98c..86fe70f 100644
--- a/arch/arm/mach-mx3/mx31lite.c
+++ b/arch/arm/mach-mx3/mx31lite.c
@@ -22,6 +22,9 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/memory.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/smsc911x.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -32,11 +35,64 @@
 #include <asm/page.h>
 #include <asm/setup.h>
 #include <mach/board-mx31lite.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx3.h>
+#include <mach/irqs.h>
+#include <mach/mxc_nand.h>
+#include "devices.h"
 
 /*
  * This file contains the board-specific initialization routines.
  */
 
+static unsigned int mx31lite_pins[] = {
+	/* UART1 */
+	MX31_PIN_CTS1__CTS1,
+	MX31_PIN_RTS1__RTS1,
+	MX31_PIN_TXD1__TXD1,
+	MX31_PIN_RXD1__RXD1,
+	/* LAN9117 IRQ pin */
+	IOMUX_MODE(MX31_PIN_SFS6, IOMUX_CONFIG_GPIO),
+};
+
+static struct imxuart_platform_data uart_pdata = {
+	.flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct mxc_nand_platform_data mx31lite_nand_board_info = {
+	.width = 1,
+	.hw_ecc = 1,
+};
+
+static struct smsc911x_platform_config smsc911x_config = {
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type	= SMSC911X_IRQ_TYPE_PUSH_PULL,
+	.flags		= SMSC911X_USE_16BIT,
+};
+
+static struct resource smsc911x_resources[] = {
+	[0] = {
+		.start		= CS4_BASE_ADDR,
+		.end		= CS4_BASE_ADDR + 0x100,
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start		= IOMUX_TO_IRQ(MX31_PIN_SFS6),
+		.end		= IOMUX_TO_IRQ(MX31_PIN_SFS6),
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smsc911x_device = {
+	.name		= "smsc911x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(smsc911x_resources),
+	.resource	= smsc911x_resources,
+	.dev		= {
+		.platform_data = &smsc911x_config,
+	},
+};
+
 /*
  * This structure defines the MX31 memory map.
  */
@@ -59,7 +115,7 @@
  */
 void __init mx31lite_map_io(void)
 {
-	mxc_map_io();
+	mx31_map_io();
 	iotable_init(mx31lite_io_desc, ARRAY_SIZE(mx31lite_io_desc));
 }
 
@@ -68,6 +124,22 @@
  */
 static void __init mxc_board_init(void)
 {
+	int ret;
+
+	mxc_iomux_setup_multiple_pins(mx31lite_pins, ARRAY_SIZE(mx31lite_pins),
+				      "mx31lite");
+
+	mxc_register_device(&mxc_uart_device0, &uart_pdata);
+	mxc_register_device(&mxc_nand_device, &mx31lite_nand_board_info);
+
+	/* SMSC9117 IRQ pin */
+	ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_SFS6), "sms9117-irq");
+	if (ret)
+		pr_warning("could not get LAN irq gpio\n");
+	else {
+		gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_SFS6));
+		platform_device_register(&smsc911x_device);
+	}
 }
 
 static void __init mx31lite_timer_init(void)
diff --git a/arch/arm/mach-mx3/mx31moboard-devboard.c b/arch/arm/mach-mx3/mx31moboard-devboard.c
index d080b4a..4704405 100644
--- a/arch/arm/mach-mx3/mx31moboard-devboard.c
+++ b/arch/arm/mach-mx3/mx31moboard-devboard.c
@@ -16,33 +16,142 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/types.h>
+#include <linux/fsl_devices.h>
+#include <linux/gpio.h>
 #include <linux/init.h>
-
+#include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/types.h>
 
-#include <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
+#include <mach/hardware.h>
+#include <mach/mmc.h>
 
 #include "devices.h"
 
+static unsigned int devboard_pins[] = {
+	/* UART1 */
+	MX31_PIN_CTS2__CTS2, MX31_PIN_RTS2__RTS2,
+	MX31_PIN_TXD2__TXD2, MX31_PIN_RXD2__RXD2,
+	/* SDHC2 */
+	MX31_PIN_PC_PWRON__SD2_DATA3, MX31_PIN_PC_VS1__SD2_DATA2,
+	MX31_PIN_PC_READY__SD2_DATA1, MX31_PIN_PC_WAIT_B__SD2_DATA0,
+	MX31_PIN_PC_CD2_B__SD2_CLK, MX31_PIN_PC_CD1_B__SD2_CMD,
+	MX31_PIN_ATA_DIOR__GPIO3_28, MX31_PIN_ATA_DIOW__GPIO3_29,
+	/* USB OTG */
+	MX31_PIN_USBOTG_DATA0__USBOTG_DATA0,
+	MX31_PIN_USBOTG_DATA1__USBOTG_DATA1,
+	MX31_PIN_USBOTG_DATA2__USBOTG_DATA2,
+	MX31_PIN_USBOTG_DATA3__USBOTG_DATA3,
+	MX31_PIN_USBOTG_DATA4__USBOTG_DATA4,
+	MX31_PIN_USBOTG_DATA5__USBOTG_DATA5,
+	MX31_PIN_USBOTG_DATA6__USBOTG_DATA6,
+	MX31_PIN_USBOTG_DATA7__USBOTG_DATA7,
+	MX31_PIN_USBOTG_CLK__USBOTG_CLK, MX31_PIN_USBOTG_DIR__USBOTG_DIR,
+	MX31_PIN_USBOTG_NXT__USBOTG_NXT, MX31_PIN_USBOTG_STP__USBOTG_STP,
+	MX31_PIN_USB_OC__GPIO1_30,
+};
+
 static struct imxuart_platform_data uart_pdata = {
 	.flags = IMXUART_HAVE_RTSCTS,
 };
 
-static int mxc_uart1_pins[] = {
-	MX31_PIN_CTS2__CTS2, MX31_PIN_RTS2__RTS2,
-	MX31_PIN_TXD2__TXD2, MX31_PIN_RXD2__RXD2,
+#define SDHC2_CD IOMUX_TO_GPIO(MX31_PIN_ATA_DIOR)
+#define SDHC2_WP IOMUX_TO_GPIO(MX31_PIN_ATA_DIOW)
+
+static int devboard_sdhc2_get_ro(struct device *dev)
+{
+	return gpio_get_value(SDHC2_WP);
+}
+
+static int devboard_sdhc2_init(struct device *dev, irq_handler_t detect_irq,
+		void *data)
+{
+	int ret;
+
+	ret = gpio_request(SDHC2_CD, "sdhc-detect");
+	if (ret)
+		return ret;
+
+	gpio_direction_input(SDHC2_CD);
+
+	ret = gpio_request(SDHC2_WP, "sdhc-wp");
+	if (ret)
+		goto err_gpio_free;
+	gpio_direction_input(SDHC2_WP);
+
+	ret = request_irq(gpio_to_irq(SDHC2_CD), detect_irq,
+		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+		"sdhc2-card-detect", data);
+	if (ret)
+		goto err_gpio_free_2;
+
+	return 0;
+
+err_gpio_free_2:
+	gpio_free(SDHC2_WP);
+err_gpio_free:
+	gpio_free(SDHC2_CD);
+
+	return ret;
+}
+
+static void devboard_sdhc2_exit(struct device *dev, void *data)
+{
+	free_irq(gpio_to_irq(SDHC2_CD), data);
+	gpio_free(SDHC2_WP);
+	gpio_free(SDHC2_CD);
+}
+
+static struct imxmmc_platform_data sdhc2_pdata = {
+	.get_ro	= devboard_sdhc2_get_ro,
+	.init	= devboard_sdhc2_init,
+	.exit	= devboard_sdhc2_exit,
 };
 
+static struct fsl_usb2_platform_data usb_pdata = {
+	.operating_mode	= FSL_USB2_DR_DEVICE,
+	.phy_mode	= FSL_USB2_PHY_ULPI,
+};
+
+#define OTG_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST)
+#define OTG_EN_B IOMUX_TO_GPIO(MX31_PIN_USB_OC)
+
+static void devboard_usbotg_init(void)
+{
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, OTG_PAD_CFG);
+
+	gpio_request(OTG_EN_B, "usb-udc-en");
+	gpio_direction_output(OTG_EN_B, 0);
+}
+
 /*
  * system init for baseboard usage. Will be called by mx31moboard init.
  */
 void __init mx31moboard_devboard_init(void)
 {
 	printk(KERN_INFO "Initializing mx31devboard peripherals\n");
-	mxc_iomux_setup_multiple_pins(mxc_uart1_pins, ARRAY_SIZE(mxc_uart1_pins), "uart1");
+
+	mxc_iomux_setup_multiple_pins(devboard_pins, ARRAY_SIZE(devboard_pins),
+		"devboard");
+
 	mxc_register_device(&mxc_uart_device1, &uart_pdata);
+
+	mxc_register_device(&mxcsdhc_device1, &sdhc2_pdata);
+
+	devboard_usbotg_init();
+	mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
 }
diff --git a/arch/arm/mach-mx3/mx31moboard-marxbot.c b/arch/arm/mach-mx3/mx31moboard-marxbot.c
index 9ef9566..641c3d6 100644
--- a/arch/arm/mach-mx3/mx31moboard-marxbot.c
+++ b/arch/arm/mach-mx3/mx31moboard-marxbot.c
@@ -16,22 +16,144 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/types.h>
+#include <linux/fsl_devices.h>
+#include <linux/gpio.h>
 #include <linux/init.h>
-
+#include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/types.h>
 
-#include <mach/hardware.h>
 #include <mach/common.h>
+#include <mach/hardware.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
+#include <mach/mmc.h>
 
 #include "devices.h"
 
+static unsigned int marxbot_pins[] = {
+	/* SDHC2 */
+	MX31_PIN_PC_PWRON__SD2_DATA3, MX31_PIN_PC_VS1__SD2_DATA2,
+	MX31_PIN_PC_READY__SD2_DATA1, MX31_PIN_PC_WAIT_B__SD2_DATA0,
+	MX31_PIN_PC_CD2_B__SD2_CLK, MX31_PIN_PC_CD1_B__SD2_CMD,
+	MX31_PIN_ATA_DIOR__GPIO3_28, MX31_PIN_ATA_DIOW__GPIO3_29,
+	/* CSI */
+	MX31_PIN_CSI_D4__CSI_D4, MX31_PIN_CSI_D5__CSI_D5,
+	MX31_PIN_CSI_D6__CSI_D6, MX31_PIN_CSI_D7__CSI_D7,
+	MX31_PIN_CSI_D8__CSI_D8, MX31_PIN_CSI_D9__CSI_D9,
+	MX31_PIN_CSI_D10__CSI_D10, MX31_PIN_CSI_D11__CSI_D11,
+	MX31_PIN_CSI_D12__CSI_D12, MX31_PIN_CSI_D13__CSI_D13,
+	MX31_PIN_CSI_D14__CSI_D14, MX31_PIN_CSI_D15__CSI_D15,
+	MX31_PIN_CSI_HSYNC__CSI_HSYNC, MX31_PIN_CSI_MCLK__CSI_MCLK,
+	MX31_PIN_CSI_PIXCLK__CSI_PIXCLK, MX31_PIN_CSI_VSYNC__CSI_VSYNC,
+	MX31_PIN_GPIO3_0__GPIO3_0, MX31_PIN_GPIO3_1__GPIO3_1,
+	MX31_PIN_TXD2__GPIO1_28,
+	/* USB OTG */
+	MX31_PIN_USBOTG_DATA0__USBOTG_DATA0,
+	MX31_PIN_USBOTG_DATA1__USBOTG_DATA1,
+	MX31_PIN_USBOTG_DATA2__USBOTG_DATA2,
+	MX31_PIN_USBOTG_DATA3__USBOTG_DATA3,
+	MX31_PIN_USBOTG_DATA4__USBOTG_DATA4,
+	MX31_PIN_USBOTG_DATA5__USBOTG_DATA5,
+	MX31_PIN_USBOTG_DATA6__USBOTG_DATA6,
+	MX31_PIN_USBOTG_DATA7__USBOTG_DATA7,
+	MX31_PIN_USBOTG_CLK__USBOTG_CLK, MX31_PIN_USBOTG_DIR__USBOTG_DIR,
+	MX31_PIN_USBOTG_NXT__USBOTG_NXT, MX31_PIN_USBOTG_STP__USBOTG_STP,
+	MX31_PIN_USB_OC__GPIO1_30,
+};
+
+#define SDHC2_CD IOMUX_TO_GPIO(MX31_PIN_ATA_DIOR)
+#define SDHC2_WP IOMUX_TO_GPIO(MX31_PIN_ATA_DIOW)
+
+static int marxbot_sdhc2_get_ro(struct device *dev)
+{
+	return gpio_get_value(SDHC2_WP);
+}
+
+static int marxbot_sdhc2_init(struct device *dev, irq_handler_t detect_irq,
+		void *data)
+{
+	int ret;
+
+	ret = gpio_request(SDHC2_CD, "sdhc-detect");
+	if (ret)
+		return ret;
+
+	gpio_direction_input(SDHC2_CD);
+
+	ret = gpio_request(SDHC2_WP, "sdhc-wp");
+	if (ret)
+		goto err_gpio_free;
+	gpio_direction_input(SDHC2_WP);
+
+	ret = request_irq(gpio_to_irq(SDHC2_CD), detect_irq,
+		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+		"sdhc2-card-detect", data);
+	if (ret)
+		goto err_gpio_free_2;
+
+	return 0;
+
+err_gpio_free_2:
+	gpio_free(SDHC2_WP);
+err_gpio_free:
+	gpio_free(SDHC2_CD);
+
+	return ret;
+}
+
+static void marxbot_sdhc2_exit(struct device *dev, void *data)
+{
+	free_irq(gpio_to_irq(SDHC2_CD), data);
+	gpio_free(SDHC2_WP);
+	gpio_free(SDHC2_CD);
+}
+
+static struct imxmmc_platform_data sdhc2_pdata = {
+	.get_ro	= marxbot_sdhc2_get_ro,
+	.init	= marxbot_sdhc2_init,
+	.exit	= marxbot_sdhc2_exit,
+};
+
+static struct fsl_usb2_platform_data usb_pdata = {
+	.operating_mode	= FSL_USB2_DR_DEVICE,
+	.phy_mode	= FSL_USB2_PHY_ULPI,
+};
+
+#define OTG_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST)
+#define OTG_EN_B IOMUX_TO_GPIO(MX31_PIN_USB_OC)
+
+static void marxbot_usbotg_init(void)
+{
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, OTG_PAD_CFG);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, OTG_PAD_CFG);
+
+	gpio_request(OTG_EN_B, "usb-udc-en");
+	gpio_direction_output(OTG_EN_B, 0);
+}
+
 /*
  * system init for baseboard usage. Will be called by mx31moboard init.
  */
 void __init mx31moboard_marxbot_init(void)
 {
 	printk(KERN_INFO "Initializing mx31marxbot peripherals\n");
+
+	mxc_iomux_setup_multiple_pins(marxbot_pins, ARRAY_SIZE(marxbot_pins),
+		"marxbot");
+
+	mxc_register_device(&mxcsdhc_device1, &sdhc2_pdata);
+
+	marxbot_usbotg_init();
+	mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
 }
diff --git a/arch/arm/mach-mx3/mx31moboard.c b/arch/arm/mach-mx3/mx31moboard.c
index 34c2a1b..a17f2e4 100644
--- a/arch/arm/mach-mx3/mx31moboard.c
+++ b/arch/arm/mach-mx3/mx31moboard.c
@@ -16,26 +16,47 @@
  * 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/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/memory.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/partitions.h>
-#include <linux/memory.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/mach/map.h>
+#include <mach/board-mx31moboard.h>
 #include <mach/common.h>
+#include <mach/hardware.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
-#include <mach/board-mx31moboard.h>
+#include <mach/i2c.h>
+#include <mach/mmc.h>
 
 #include "devices.h"
 
+static unsigned int moboard_pins[] = {
+	/* UART0 */
+	MX31_PIN_CTS1__CTS1, MX31_PIN_RTS1__RTS1,
+	MX31_PIN_TXD1__TXD1, MX31_PIN_RXD1__RXD1,
+	/* UART4 */
+	MX31_PIN_PC_RST__CTS5, MX31_PIN_PC_VS2__RTS5,
+	MX31_PIN_PC_BVD2__TXD5, MX31_PIN_PC_BVD1__RXD5,
+	/* I2C0 */
+	MX31_PIN_I2C_DAT__I2C1_SDA, MX31_PIN_I2C_CLK__I2C1_SCL,
+	/* I2C1 */
+	MX31_PIN_DCD_DTE1__I2C2_SDA, MX31_PIN_RI_DTE1__I2C2_SCL,
+	/* SDHC1 */
+	MX31_PIN_SD1_DATA3__SD1_DATA3, MX31_PIN_SD1_DATA2__SD1_DATA2,
+	MX31_PIN_SD1_DATA1__SD1_DATA1, MX31_PIN_SD1_DATA0__SD1_DATA0,
+	MX31_PIN_SD1_CLK__SD1_CLK, MX31_PIN_SD1_CMD__SD1_CMD,
+	MX31_PIN_ATA_CS0__GPIO3_26, MX31_PIN_ATA_CS1__GPIO3_27,
+};
+
 static struct physmap_flash_data mx31moboard_flash_data = {
 	.width  	= 2,
 };
@@ -60,17 +81,69 @@
 	.flags = IMXUART_HAVE_RTSCTS,
 };
 
-static struct platform_device *devices[] __initdata = {
-	&mx31moboard_flash,
+static struct imxi2c_platform_data moboard_i2c0_pdata = {
+	.bitrate = 400000,
 };
 
-static int mxc_uart0_pins[] = {
-	MX31_PIN_CTS1__CTS1, MX31_PIN_RTS1__RTS1,
-	MX31_PIN_TXD1__TXD1, MX31_PIN_RXD1__RXD1,
+static struct imxi2c_platform_data moboard_i2c1_pdata = {
+	.bitrate = 100000,
 };
-static int mxc_uart4_pins[] = {
-	MX31_PIN_PC_RST__CTS5, MX31_PIN_PC_VS2__RTS5,
-	MX31_PIN_PC_BVD2__TXD5, MX31_PIN_PC_BVD1__RXD5,
+
+#define SDHC1_CD IOMUX_TO_GPIO(MX31_PIN_ATA_CS0)
+#define SDHC1_WP IOMUX_TO_GPIO(MX31_PIN_ATA_CS1)
+
+static int moboard_sdhc1_get_ro(struct device *dev)
+{
+	return gpio_get_value(SDHC1_WP);
+}
+
+static int moboard_sdhc1_init(struct device *dev, irq_handler_t detect_irq,
+		void *data)
+{
+	int ret;
+
+	ret = gpio_request(SDHC1_CD, "sdhc-detect");
+	if (ret)
+		return ret;
+
+	gpio_direction_input(SDHC1_CD);
+
+	ret = gpio_request(SDHC1_WP, "sdhc-wp");
+	if (ret)
+		goto err_gpio_free;
+	gpio_direction_input(SDHC1_WP);
+
+	ret = request_irq(gpio_to_irq(SDHC1_CD), detect_irq,
+		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+		"sdhc1-card-detect", data);
+	if (ret)
+		goto err_gpio_free_2;
+
+	return 0;
+
+err_gpio_free_2:
+	gpio_free(SDHC1_WP);
+err_gpio_free:
+	gpio_free(SDHC1_CD);
+
+	return ret;
+}
+
+static void moboard_sdhc1_exit(struct device *dev, void *data)
+{
+	free_irq(gpio_to_irq(SDHC1_CD), data);
+	gpio_free(SDHC1_WP);
+	gpio_free(SDHC1_CD);
+}
+
+static struct imxmmc_platform_data sdhc1_pdata = {
+	.get_ro	= moboard_sdhc1_get_ro,
+	.init	= moboard_sdhc1_init,
+	.exit	= moboard_sdhc1_exit,
+};
+
+static struct platform_device *devices[] __initdata = {
+	&mx31moboard_flash,
 };
 
 static int mx31moboard_baseboard;
@@ -81,14 +154,19 @@
  */
 static void __init mxc_board_init(void)
 {
+	mxc_iomux_setup_multiple_pins(moboard_pins, ARRAY_SIZE(moboard_pins),
+		"moboard");
+
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 
-	mxc_iomux_setup_multiple_pins(mxc_uart0_pins, ARRAY_SIZE(mxc_uart0_pins), "uart0");
 	mxc_register_device(&mxc_uart_device0, &uart_pdata);
-
-	mxc_iomux_setup_multiple_pins(mxc_uart4_pins, ARRAY_SIZE(mxc_uart4_pins), "uart4");
 	mxc_register_device(&mxc_uart_device4, &uart_pdata);
 
+	mxc_register_device(&mxc_i2c_device0, &moboard_i2c0_pdata);
+	mxc_register_device(&mxc_i2c_device1, &moboard_i2c1_pdata);
+
+	mxc_register_device(&mxcsdhc_device0, &sdhc1_pdata);
+
 	switch (mx31moboard_baseboard) {
 	case MX31NOBOARD:
 		break;
@@ -99,7 +177,8 @@
 		mx31moboard_marxbot_init();
 		break;
 	default:
-		printk(KERN_ERR "Illegal mx31moboard_baseboard type %d\n", mx31moboard_baseboard);
+		printk(KERN_ERR "Illegal mx31moboard_baseboard type %d\n",
+			mx31moboard_baseboard);
 	}
 }
 
@@ -117,7 +196,7 @@
 	.phys_io	= AIPS1_BASE_ADDR,
 	.io_pg_offst	= ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = PHYS_OFFSET + 0x100,
-	.map_io         = mxc_map_io,
+	.map_io         = mx31_map_io,
 	.init_irq       = mxc_init_irq,
 	.init_machine   = mxc_board_init,
 	.timer          = &mx31moboard_timer,
diff --git a/arch/arm/mach-mx3/mx31pdk.c b/arch/arm/mach-mx3/mx31pdk.c
index bc63f17..c19838d 100644
--- a/arch/arm/mach-mx3/mx31pdk.c
+++ b/arch/arm/mach-mx3/mx31pdk.c
@@ -20,6 +20,9 @@
 #include <linux/init.h>
 #include <linux/clk.h>
 #include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/smsc911x.h>
+#include <linux/platform_device.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -41,21 +44,192 @@
  * @ingroup System
  */
 
+static int mx31pdk_pins[] = {
+	/* UART1 */
+	MX31_PIN_CTS1__CTS1,
+	MX31_PIN_RTS1__RTS1,
+	MX31_PIN_TXD1__TXD1,
+	MX31_PIN_RXD1__RXD1,
+	IOMUX_MODE(MX31_PIN_GPIO1_1, IOMUX_CONFIG_GPIO),
+};
+
 static struct imxuart_platform_data uart_pdata = {
 	.flags = IMXUART_HAVE_RTSCTS,
 };
 
-static int uart_pins[] = {
-	MX31_PIN_CTS1__CTS1,
-	MX31_PIN_RTS1__RTS1,
-	MX31_PIN_TXD1__TXD1,
-	MX31_PIN_RXD1__RXD1
+/*
+ * Support for the SMSC9217 on the Debug board.
+ */
+
+static struct smsc911x_platform_config smsc911x_config = {
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type	= SMSC911X_IRQ_TYPE_PUSH_PULL,
+	.flags		= SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY,
+	.phy_interface	= PHY_INTERFACE_MODE_MII,
 };
 
-static inline void mxc_init_imx_uart(void)
+static struct resource smsc911x_resources[] = {
+	{
+		.start		= LAN9217_BASE_ADDR,
+		.end		= LAN9217_BASE_ADDR + 0xff,
+		.flags		= IORESOURCE_MEM,
+	}, {
+		.start		= EXPIO_INT_ENET,
+		.end		= EXPIO_INT_ENET,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smsc911x_device = {
+	.name		= "smsc911x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(smsc911x_resources),
+	.resource	= smsc911x_resources,
+	.dev		= {
+		.platform_data = &smsc911x_config,
+	},
+};
+
+/*
+ * Routines for the CPLD on the debug board. It contains a CPLD handling
+ * LEDs, switches, interrupts for Ethernet.
+ */
+
+static void mx31pdk_expio_irq_handler(uint32_t irq, struct irq_desc *desc)
 {
-	mxc_iomux_setup_multiple_pins(uart_pins, ARRAY_SIZE(uart_pins), "uart-0");
-	mxc_register_device(&mxc_uart_device0, &uart_pdata);
+	uint32_t imr_val;
+	uint32_t int_valid;
+	uint32_t expio_irq;
+
+	imr_val = __raw_readw(CPLD_INT_MASK_REG);
+	int_valid = __raw_readw(CPLD_INT_STATUS_REG) & ~imr_val;
+
+	expio_irq = MXC_EXP_IO_BASE;
+	for (; int_valid != 0; int_valid >>= 1, expio_irq++) {
+		if ((int_valid & 1) == 0)
+			continue;
+		generic_handle_irq(expio_irq);
+	}
+}
+
+/*
+ * Disable an expio pin's interrupt by setting the bit in the imr.
+ * @param irq           an expio virtual irq number
+ */
+static void expio_mask_irq(uint32_t irq)
+{
+	uint16_t reg;
+	uint32_t expio = MXC_IRQ_TO_EXPIO(irq);
+
+	/* mask the interrupt */
+	reg = __raw_readw(CPLD_INT_MASK_REG);
+	reg |= 1 << expio;
+	__raw_writew(reg, CPLD_INT_MASK_REG);
+}
+
+/*
+ * Acknowledge an expanded io pin's interrupt by clearing the bit in the isr.
+ * @param irq           an expanded io virtual irq number
+ */
+static void expio_ack_irq(uint32_t irq)
+{
+	uint32_t expio = MXC_IRQ_TO_EXPIO(irq);
+
+	/* clear the interrupt status */
+	__raw_writew(1 << expio, CPLD_INT_RESET_REG);
+	__raw_writew(0, CPLD_INT_RESET_REG);
+	/* mask the interrupt */
+	expio_mask_irq(irq);
+}
+
+/*
+ * Enable a expio pin's interrupt by clearing the bit in the imr.
+ * @param irq           a expio virtual irq number
+ */
+static void expio_unmask_irq(uint32_t irq)
+{
+	uint16_t reg;
+	uint32_t expio = MXC_IRQ_TO_EXPIO(irq);
+
+	/* unmask the interrupt */
+	reg = __raw_readw(CPLD_INT_MASK_REG);
+	reg &= ~(1 << expio);
+	__raw_writew(reg, CPLD_INT_MASK_REG);
+}
+
+static struct irq_chip expio_irq_chip = {
+	.ack = expio_ack_irq,
+	.mask = expio_mask_irq,
+	.unmask = expio_unmask_irq,
+};
+
+static int __init mx31pdk_init_expio(void)
+{
+	int i;
+	int ret;
+
+	/* Check if there's a debug board connected */
+	if ((__raw_readw(CPLD_MAGIC_NUMBER1_REG) != 0xAAAA) ||
+	    (__raw_readw(CPLD_MAGIC_NUMBER2_REG) != 0x5555) ||
+	    (__raw_readw(CPLD_MAGIC_NUMBER3_REG) != 0xCAFE)) {
+		/* No Debug board found */
+		return -ENODEV;
+	}
+
+	pr_info("i.MX31PDK Debug board detected, rev = 0x%04X\n",
+		__raw_readw(CPLD_CODE_VER_REG));
+
+	/*
+	 * Configure INT line as GPIO input
+	 */
+	ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO1_1), "sms9217-irq");
+	if (ret)
+		pr_warning("could not get LAN irq gpio\n");
+	else
+		gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO1_1));
+
+	/* Disable the interrupts and clear the status */
+	__raw_writew(0, CPLD_INT_MASK_REG);
+	__raw_writew(0xFFFF, CPLD_INT_RESET_REG);
+	__raw_writew(0, CPLD_INT_RESET_REG);
+	__raw_writew(0x1F, CPLD_INT_MASK_REG);
+	for (i = MXC_EXP_IO_BASE;
+	     i < (MXC_EXP_IO_BASE + MXC_MAX_EXP_IO_LINES);
+	     i++) {
+		set_irq_chip(i, &expio_irq_chip);
+		set_irq_handler(i, handle_level_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+	set_irq_type(EXPIO_PARENT_INT, IRQ_TYPE_LEVEL_LOW);
+	set_irq_chained_handler(EXPIO_PARENT_INT, mx31pdk_expio_irq_handler);
+
+	return 0;
+}
+
+/*
+ * This structure defines the MX31 memory map.
+ */
+static struct map_desc mx31pdk_io_desc[] __initdata = {
+	{
+		.virtual = SPBA0_BASE_ADDR_VIRT,
+		.pfn = __phys_to_pfn(SPBA0_BASE_ADDR),
+		.length = SPBA0_SIZE,
+		.type = MT_DEVICE_NONSHARED,
+	}, {
+		.virtual = CS5_BASE_ADDR_VIRT,
+		.pfn = __phys_to_pfn(CS5_BASE_ADDR),
+		.length = CS5_SIZE,
+		.type = MT_DEVICE,
+	},
+};
+
+/*
+ * Set up static virtual mappings.
+ */
+static void __init mx31pdk_map_io(void)
+{
+	mx31_map_io();
+	iotable_init(mx31pdk_io_desc, ARRAY_SIZE(mx31pdk_io_desc));
 }
 
 /*!
@@ -63,7 +237,13 @@
  */
 static void __init mxc_board_init(void)
 {
-	mxc_init_imx_uart();
+	mxc_iomux_setup_multiple_pins(mx31pdk_pins, ARRAY_SIZE(mx31pdk_pins),
+				      "mx31pdk");
+
+	mxc_register_device(&mxc_uart_device0, &uart_pdata);
+
+	if (!mx31pdk_init_expio())
+		platform_device_register(&smsc911x_device);
 }
 
 static void __init mx31pdk_timer_init(void)
@@ -84,7 +264,7 @@
 	.phys_io	= AIPS1_BASE_ADDR,
 	.io_pg_offst	= ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = PHYS_OFFSET + 0x100,
-	.map_io         = mxc_map_io,
+	.map_io         = mx31pdk_map_io,
 	.init_irq       = mxc_init_irq,
 	.init_machine   = mxc_board_init,
 	.timer          = &mx31pdk_timer,
diff --git a/arch/arm/mach-mx3/mx35pdk.c b/arch/arm/mach-mx3/mx35pdk.c
new file mode 100644
index 0000000..6d15374
--- /dev/null
+++ b/arch/arm/mach-mx3/mx35pdk.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Author: Fabio Estevam <fabio.estevam@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/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/memory.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx35.h>
+
+#include "devices.h"
+
+static struct imxuart_platform_data uart_pdata = {
+	.flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct platform_device *devices[] __initdata = {
+	&mxc_fec_device,
+};
+
+static struct pad_desc mx35pdk_pads[] = {
+	/* UART1 */
+	MX35_PAD_CTS1__UART1_CTS,
+	MX35_PAD_RTS1__UART1_RTS,
+	MX35_PAD_TXD1__UART1_TXD_MUX,
+	MX35_PAD_RXD1__UART1_RXD_MUX,
+	/* FEC */
+	MX35_PAD_FEC_TX_CLK__FEC_TX_CLK,
+	MX35_PAD_FEC_RX_CLK__FEC_RX_CLK,
+	MX35_PAD_FEC_RX_DV__FEC_RX_DV,
+	MX35_PAD_FEC_COL__FEC_COL,
+	MX35_PAD_FEC_RDATA0__FEC_RDATA_0,
+	MX35_PAD_FEC_TDATA0__FEC_TDATA_0,
+	MX35_PAD_FEC_TX_EN__FEC_TX_EN,
+	MX35_PAD_FEC_MDC__FEC_MDC,
+	MX35_PAD_FEC_MDIO__FEC_MDIO,
+	MX35_PAD_FEC_TX_ERR__FEC_TX_ERR,
+	MX35_PAD_FEC_RX_ERR__FEC_RX_ERR,
+	MX35_PAD_FEC_CRS__FEC_CRS,
+	MX35_PAD_FEC_RDATA1__FEC_RDATA_1,
+	MX35_PAD_FEC_TDATA1__FEC_TDATA_1,
+	MX35_PAD_FEC_RDATA2__FEC_RDATA_2,
+	MX35_PAD_FEC_TDATA2__FEC_TDATA_2,
+	MX35_PAD_FEC_RDATA3__FEC_RDATA_3,
+	MX35_PAD_FEC_TDATA3__FEC_TDATA_3,
+};
+
+/*
+ * Board specific initialization.
+ */
+static void __init mxc_board_init(void)
+{
+	mxc_iomux_v3_setup_multiple_pads(mx35pdk_pads, ARRAY_SIZE(mx35pdk_pads));
+
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+
+	mxc_register_device(&mxc_uart_device0, &uart_pdata);
+}
+
+static void __init mx35pdk_timer_init(void)
+{
+	mx35_clocks_init();
+}
+
+struct sys_timer mx35pdk_timer = {
+	.init	= mx35pdk_timer_init,
+};
+
+MACHINE_START(MX35_3DS, "Freescale MX35PDK")
+	/* Maintainer: Freescale Semiconductor, Inc */
+	.phys_io	= AIPS1_BASE_ADDR,
+	.io_pg_offst	= ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+	.boot_params    = PHYS_OFFSET + 0x100,
+	.map_io         = mx35_map_io,
+	.init_irq       = mxc_init_irq,
+	.init_machine   = mxc_board_init,
+	.timer          = &mx35pdk_timer,
+MACHINE_END
diff --git a/arch/arm/mach-mx3/pcm037.c b/arch/arm/mach-mx3/pcm037.c
index b5227d8..c6f61a1 100644
--- a/arch/arm/mach-mx3/pcm037.c
+++ b/arch/arm/mach-mx3/pcm037.c
@@ -28,6 +28,10 @@
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
 #include <linux/i2c/at24.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/irq.h>
+#include <linux/fsl_devices.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -37,7 +41,9 @@
 #include <mach/common.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
+#include <mach/ipu.h>
 #include <mach/board-pcm037.h>
+#include <mach/mx3fb.h>
 #include <mach/mxc_nand.h>
 #include <mach/mmc.h>
 #ifdef CONFIG_I2C_IMX
@@ -46,6 +52,76 @@
 
 #include "devices.h"
 
+static unsigned int pcm037_pins[] = {
+	/* I2C */
+	MX31_PIN_CSPI2_MOSI__SCL,
+	MX31_PIN_CSPI2_MISO__SDA,
+	/* SDHC1 */
+	MX31_PIN_SD1_DATA3__SD1_DATA3,
+	MX31_PIN_SD1_DATA2__SD1_DATA2,
+	MX31_PIN_SD1_DATA1__SD1_DATA1,
+	MX31_PIN_SD1_DATA0__SD1_DATA0,
+	MX31_PIN_SD1_CLK__SD1_CLK,
+	MX31_PIN_SD1_CMD__SD1_CMD,
+	IOMUX_MODE(MX31_PIN_SCK6, IOMUX_CONFIG_GPIO), /* card detect */
+	IOMUX_MODE(MX31_PIN_SFS6, IOMUX_CONFIG_GPIO), /* write protect */
+	/* SPI1 */
+	MX31_PIN_CSPI1_MOSI__MOSI,
+	MX31_PIN_CSPI1_MISO__MISO,
+	MX31_PIN_CSPI1_SCLK__SCLK,
+	MX31_PIN_CSPI1_SPI_RDY__SPI_RDY,
+	MX31_PIN_CSPI1_SS0__SS0,
+	MX31_PIN_CSPI1_SS1__SS1,
+	MX31_PIN_CSPI1_SS2__SS2,
+	/* UART1 */
+	MX31_PIN_CTS1__CTS1,
+	MX31_PIN_RTS1__RTS1,
+	MX31_PIN_TXD1__TXD1,
+	MX31_PIN_RXD1__RXD1,
+	/* UART2 */
+	MX31_PIN_TXD2__TXD2,
+	MX31_PIN_RXD2__RXD2,
+	MX31_PIN_CTS2__CTS2,
+	MX31_PIN_RTS2__RTS2,
+	/* UART3 */
+	MX31_PIN_CSPI3_MOSI__RXD3,
+	MX31_PIN_CSPI3_MISO__TXD3,
+	MX31_PIN_CSPI3_SCLK__RTS3,
+	MX31_PIN_CSPI3_SPI_RDY__CTS3,
+	/* LAN9217 irq pin */
+	IOMUX_MODE(MX31_PIN_GPIO3_1, IOMUX_CONFIG_GPIO),
+	/* Onewire */
+	MX31_PIN_BATT_LINE__OWIRE,
+	/* Framebuffer */
+	MX31_PIN_LD0__LD0,
+	MX31_PIN_LD1__LD1,
+	MX31_PIN_LD2__LD2,
+	MX31_PIN_LD3__LD3,
+	MX31_PIN_LD4__LD4,
+	MX31_PIN_LD5__LD5,
+	MX31_PIN_LD6__LD6,
+	MX31_PIN_LD7__LD7,
+	MX31_PIN_LD8__LD8,
+	MX31_PIN_LD9__LD9,
+	MX31_PIN_LD10__LD10,
+	MX31_PIN_LD11__LD11,
+	MX31_PIN_LD12__LD12,
+	MX31_PIN_LD13__LD13,
+	MX31_PIN_LD14__LD14,
+	MX31_PIN_LD15__LD15,
+	MX31_PIN_LD16__LD16,
+	MX31_PIN_LD17__LD17,
+	MX31_PIN_VSYNC3__VSYNC3,
+	MX31_PIN_HSYNC__HSYNC,
+	MX31_PIN_FPSHIFT__FPSHIFT,
+	MX31_PIN_DRDY0__DRDY0,
+	MX31_PIN_D3_REV__D3_REV,
+	MX31_PIN_CONTRAST__CONTRAST,
+	MX31_PIN_D3_SPL__D3_SPL,
+	MX31_PIN_D3_CLS__D3_CLS,
+	MX31_PIN_LCS0__GPI03_23,
+};
+
 static struct physmap_flash_data pcm037_flash_data = {
 	.width  = 2,
 };
@@ -56,6 +132,54 @@
 	.flags	= IORESOURCE_MEM,
 };
 
+static int usbotg_pins[] = {
+	MX31_PIN_USBOTG_DATA0__USBOTG_DATA0,
+	MX31_PIN_USBOTG_DATA1__USBOTG_DATA1,
+	MX31_PIN_USBOTG_DATA2__USBOTG_DATA2,
+	MX31_PIN_USBOTG_DATA3__USBOTG_DATA3,
+	MX31_PIN_USBOTG_DATA4__USBOTG_DATA4,
+	MX31_PIN_USBOTG_DATA5__USBOTG_DATA5,
+	MX31_PIN_USBOTG_DATA6__USBOTG_DATA6,
+	MX31_PIN_USBOTG_DATA7__USBOTG_DATA7,
+	MX31_PIN_USBOTG_CLK__USBOTG_CLK,
+	MX31_PIN_USBOTG_DIR__USBOTG_DIR,
+	MX31_PIN_USBOTG_NXT__USBOTG_NXT,
+	MX31_PIN_USBOTG_STP__USBOTG_STP,
+};
+
+/* USB OTG HS port */
+static int __init gpio_usbotg_hs_activate(void)
+{
+	int ret = mxc_iomux_setup_multiple_pins(usbotg_pins,
+					ARRAY_SIZE(usbotg_pins), "usbotg");
+
+	if (ret < 0) {
+		printk(KERN_ERR "Cannot set up OTG pins\n");
+		return ret;
+	}
+
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK,   PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR,   PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT,   PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+	mxc_iomux_set_pad(MX31_PIN_USBOTG_STP,   PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+
+	return 0;
+}
+
+/* OTG config */
+static struct fsl_usb2_platform_data usb_pdata = {
+	.operating_mode	= FSL_USB2_DR_DEVICE,
+	.phy_mode	= FSL_USB2_PHY_ULPI,
+};
+
 static struct platform_device pcm037_flash = {
 	.name	= "physmap-flash",
 	.id	= 0,
@@ -127,26 +251,8 @@
 };
 
 #ifdef CONFIG_I2C_IMX
-static int i2c_1_pins[] = {
-	MX31_PIN_CSPI2_MOSI__SCL,
-	MX31_PIN_CSPI2_MISO__SDA,
-};
-
-static int pcm037_i2c_1_init(struct device *dev)
-{
-	return mxc_iomux_setup_multiple_pins(i2c_1_pins, ARRAY_SIZE(i2c_1_pins),
-			"i2c-1");
-}
-
-static void pcm037_i2c_1_exit(struct device *dev)
-{
-	mxc_iomux_release_multiple_pins(i2c_1_pins, ARRAY_SIZE(i2c_1_pins));
-}
-
 static struct imxi2c_platform_data pcm037_i2c_1_data = {
 	.bitrate = 100000,
-	.init = pcm037_i2c_1_init,
-	.exit = pcm037_i2c_1_exit,
 };
 
 static struct at24_platform_data board_eeprom = {
@@ -166,48 +272,119 @@
 };
 #endif
 
-static int sdhc1_pins[] = {
-	MX31_PIN_SD1_DATA3__SD1_DATA3,
-	MX31_PIN_SD1_DATA2__SD1_DATA2,
-	MX31_PIN_SD1_DATA1__SD1_DATA1,
-	MX31_PIN_SD1_DATA0__SD1_DATA0,
-	MX31_PIN_SD1_CLK__SD1_CLK,
-	MX31_PIN_SD1_CMD__SD1_CMD,
-};
-
-static int pcm970_sdhc1_init(struct device *dev, irq_handler_t h, void *data)
+/* Not connected by default */
+#ifdef PCM970_SDHC_RW_SWITCH
+static int pcm970_sdhc1_get_ro(struct device *dev)
 {
-	return mxc_iomux_setup_multiple_pins(sdhc1_pins, ARRAY_SIZE(sdhc1_pins),
-				"sdhc-1");
+	return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_SFS6));
+}
+#endif
+
+#define SDHC1_GPIO_WP	IOMUX_TO_GPIO(MX31_PIN_SFS6)
+#define SDHC1_GPIO_DET	IOMUX_TO_GPIO(MX31_PIN_SCK6)
+
+static int pcm970_sdhc1_init(struct device *dev, irq_handler_t detect_irq,
+		void *data)
+{
+	int ret;
+
+	ret = gpio_request(SDHC1_GPIO_DET, "sdhc-detect");
+	if (ret)
+		return ret;
+
+	gpio_direction_input(SDHC1_GPIO_DET);
+
+#ifdef PCM970_SDHC_RW_SWITCH
+	ret = gpio_request(SDHC1_GPIO_WP, "sdhc-wp");
+	if (ret)
+		goto err_gpio_free;
+	gpio_direction_input(SDHC1_GPIO_WP);
+#endif
+
+	ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_SCK6), detect_irq,
+			IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+				"sdhc-detect", data);
+	if (ret)
+		goto err_gpio_free_2;
+
+	return 0;
+
+err_gpio_free_2:
+#ifdef PCM970_SDHC_RW_SWITCH
+	gpio_free(SDHC1_GPIO_WP);
+err_gpio_free:
+#endif
+	gpio_free(SDHC1_GPIO_DET);
+
+	return ret;
 }
 
 static void pcm970_sdhc1_exit(struct device *dev, void *data)
 {
-	mxc_iomux_release_multiple_pins(sdhc1_pins, ARRAY_SIZE(sdhc1_pins));
+	free_irq(IOMUX_TO_IRQ(MX31_PIN_SCK6), data);
+	gpio_free(SDHC1_GPIO_DET);
+	gpio_free(SDHC1_GPIO_WP);
 }
 
-/* No card and rw detection at the moment */
 static struct imxmmc_platform_data sdhc_pdata = {
+#ifdef PCM970_SDHC_RW_SWITCH
+	.get_ro = pcm970_sdhc1_get_ro,
+#endif
 	.init = pcm970_sdhc1_init,
 	.exit = pcm970_sdhc1_exit,
 };
 
 static struct platform_device *devices[] __initdata = {
 	&pcm037_flash,
-	&pcm037_eth,
 	&pcm037_sram_device,
 };
 
-static int uart0_pins[] = {
-	MX31_PIN_CTS1__CTS1,
-	MX31_PIN_RTS1__RTS1,
-	MX31_PIN_TXD1__TXD1,
-	MX31_PIN_RXD1__RXD1
+static struct ipu_platform_data mx3_ipu_data = {
+	.irq_base = MXC_IPU_IRQ_START,
 };
 
-static int uart2_pins[] = {
-	MX31_PIN_CSPI3_MOSI__RXD3,
-	MX31_PIN_CSPI3_MISO__TXD3
+static const struct fb_videomode fb_modedb[] = {
+	{
+		/* 240x320 @ 60 Hz Sharp */
+		.name		= "Sharp-LQ035Q7DH06-QVGA",
+		.refresh	= 60,
+		.xres		= 240,
+		.yres		= 320,
+		.pixclock	= 185925,
+		.left_margin	= 9,
+		.right_margin	= 16,
+		.upper_margin	= 7,
+		.lower_margin	= 9,
+		.hsync_len	= 1,
+		.vsync_len	= 1,
+		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE |
+				  FB_SYNC_CLK_INVERT | FB_SYNC_CLK_IDLE_EN,
+		.vmode		= FB_VMODE_NONINTERLACED,
+		.flag		= 0,
+	}, {
+		/* 240x320 @ 60 Hz */
+		.name		= "TX090",
+		.refresh	= 60,
+		.xres		= 240,
+		.yres		= 320,
+		.pixclock	= 38255,
+		.left_margin	= 144,
+		.right_margin	= 0,
+		.upper_margin	= 7,
+		.lower_margin	= 40,
+		.hsync_len	= 96,
+		.vsync_len	= 1,
+		.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH,
+		.vmode		= FB_VMODE_NONINTERLACED,
+		.flag		= 0,
+	},
+};
+
+static struct mx3fb_platform_data mx3fb_pdata = {
+	.dma_dev	= &mx3_ipu.dev,
+	.name		= "Sharp-LQ035Q7DH06-QVGA",
+	.mode		= fb_modedb,
+	.num_modes	= ARRAY_SIZE(fb_modedb),
 };
 
 /*
@@ -215,21 +392,28 @@
  */
 static void __init mxc_board_init(void)
 {
+	int ret;
+
+	mxc_iomux_setup_multiple_pins(pcm037_pins, ARRAY_SIZE(pcm037_pins),
+			"pcm037");
+
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 
-	mxc_iomux_setup_multiple_pins(uart0_pins, ARRAY_SIZE(uart0_pins), "uart-0");
 	mxc_register_device(&mxc_uart_device0, &uart_pdata);
-
-	mxc_iomux_setup_multiple_pins(uart2_pins, ARRAY_SIZE(uart2_pins), "uart-2");
+	mxc_register_device(&mxc_uart_device1, &uart_pdata);
 	mxc_register_device(&mxc_uart_device2, &uart_pdata);
 
-	mxc_iomux_setup_pin(MX31_PIN_BATT_LINE__OWIRE, "batt-0wire");
 	mxc_register_device(&mxc_w1_master_device, NULL);
 
 	/* LAN9217 IRQ pin */
-	if (!mxc_iomux_setup_pin(IOMUX_MODE(MX31_PIN_GPIO3_1, IOMUX_CONFIG_GPIO),
-				"pcm037-eth"))
+	ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1), "lan9217-irq");
+	if (ret)
+		pr_warning("could not get LAN irq gpio\n");
+	else {
 		gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1));
+		platform_device_register(&pcm037_eth);
+	}
+
 
 #ifdef CONFIG_I2C_IMX
 	i2c_register_board_info(1, pcm037_i2c_devices,
@@ -239,6 +423,10 @@
 #endif
 	mxc_register_device(&mxc_nand_device, &pcm037_nand_board_info);
 	mxc_register_device(&mxcsdhc_device0, &sdhc_pdata);
+	mxc_register_device(&mx3_ipu, &mx3_ipu_data);
+	mxc_register_device(&mx3_fb, &mx3fb_pdata);
+	if (!gpio_usbotg_hs_activate())
+		mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
 }
 
 static void __init pcm037_timer_init(void)
@@ -255,7 +443,7 @@
 	.phys_io	= AIPS1_BASE_ADDR,
 	.io_pg_offst	= ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = PHYS_OFFSET + 0x100,
-	.map_io         = mxc_map_io,
+	.map_io         = mx31_map_io,
 	.init_irq       = mxc_init_irq,
 	.init_machine   = mxc_board_init,
 	.timer          = &pcm037_timer,
diff --git a/arch/arm/mach-mx3/pcm043.c b/arch/arm/mach-mx3/pcm043.c
new file mode 100644
index 0000000..8d27c32
--- /dev/null
+++ b/arch/arm/mach-mx3/pcm043.c
@@ -0,0 +1,252 @@
+/*
+ *  Copyright (C) 2009 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/init.h>
+
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/plat-ram.h>
+#include <linux/memory.h>
+#include <linux/gpio.h>
+#include <linux/smc911x.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE
+#include <mach/i2c.h>
+#endif
+#include <mach/iomux-mx35.h>
+#include <mach/ipu.h>
+#include <mach/mx3fb.h>
+
+#include "devices.h"
+
+static const struct fb_videomode fb_modedb[] = {
+	{
+		/* 240x320 @ 60 Hz */
+		.name		= "Sharp-LQ035Q7",
+		.refresh	= 60,
+		.xres		= 240,
+		.yres		= 320,
+		.pixclock	= 185925,
+		.left_margin	= 9,
+		.right_margin	= 16,
+		.upper_margin	= 7,
+		.lower_margin	= 9,
+		.hsync_len	= 1,
+		.vsync_len	= 1,
+		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE | FB_SYNC_CLK_INVERT | FB_SYNC_CLK_IDLE_EN,
+		.vmode		= FB_VMODE_NONINTERLACED,
+		.flag		= 0,
+	}, {
+		/* 240x320 @ 60 Hz */
+		.name		= "TX090",
+		.refresh	= 60,
+		.xres		= 240,
+		.yres		= 320,
+		.pixclock	= 38255,
+		.left_margin	= 144,
+		.right_margin	= 0,
+		.upper_margin	= 7,
+		.lower_margin	= 40,
+		.hsync_len	= 96,
+		.vsync_len	= 1,
+		.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH,
+		.vmode		= FB_VMODE_NONINTERLACED,
+		.flag		= 0,
+	},
+};
+
+static struct ipu_platform_data mx3_ipu_data = {
+	.irq_base = MXC_IPU_IRQ_START,
+};
+
+static struct mx3fb_platform_data mx3fb_pdata = {
+	.dma_dev	= &mx3_ipu.dev,
+	.name		= "Sharp-LQ035Q7",
+	.mode		= fb_modedb,
+	.num_modes	= ARRAY_SIZE(fb_modedb),
+};
+
+static struct physmap_flash_data pcm043_flash_data = {
+	.width  = 2,
+};
+
+static struct resource pcm043_flash_resource = {
+	.start	= 0xa0000000,
+	.end	= 0xa1ffffff,
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct platform_device pcm043_flash = {
+	.name	= "physmap-flash",
+	.id	= 0,
+	.dev	= {
+		.platform_data  = &pcm043_flash_data,
+	},
+	.resource = &pcm043_flash_resource,
+	.num_resources = 1,
+};
+
+static struct imxuart_platform_data uart_pdata = {
+	.flags = IMXUART_HAVE_RTSCTS,
+};
+
+#if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE
+static struct imxi2c_platform_data pcm043_i2c_1_data = {
+	.bitrate = 50000,
+};
+
+static struct at24_platform_data board_eeprom = {
+	.byte_len = 4096,
+	.page_size = 32,
+	.flags = AT24_FLAG_ADDR16,
+};
+
+static struct i2c_board_info pcm043_i2c_devices[] = {
+       {
+		I2C_BOARD_INFO("at24", 0x52), /* E0=0, E1=1, E2=0 */
+		.platform_data = &board_eeprom,
+	}, {
+		I2C_BOARD_INFO("rtc-pcf8563", 0x51),
+		.type = "pcf8563",
+	}
+};
+#endif
+
+static struct platform_device *devices[] __initdata = {
+	&pcm043_flash,
+	&mxc_fec_device,
+};
+
+static struct pad_desc pcm043_pads[] = {
+	/* UART1 */
+	MX35_PAD_CTS1__UART1_CTS,
+	MX35_PAD_RTS1__UART1_RTS,
+	MX35_PAD_TXD1__UART1_TXD_MUX,
+	MX35_PAD_RXD1__UART1_RXD_MUX,
+	/* UART2 */
+	MX35_PAD_CTS2__UART2_CTS,
+	MX35_PAD_RTS2__UART2_RTS,
+	MX35_PAD_TXD2__UART2_TXD_MUX,
+	MX35_PAD_RXD2__UART2_RXD_MUX,
+	/* FEC */
+	MX35_PAD_FEC_TX_CLK__FEC_TX_CLK,
+	MX35_PAD_FEC_RX_CLK__FEC_RX_CLK,
+	MX35_PAD_FEC_RX_DV__FEC_RX_DV,
+	MX35_PAD_FEC_COL__FEC_COL,
+	MX35_PAD_FEC_RDATA0__FEC_RDATA_0,
+	MX35_PAD_FEC_TDATA0__FEC_TDATA_0,
+	MX35_PAD_FEC_TX_EN__FEC_TX_EN,
+	MX35_PAD_FEC_MDC__FEC_MDC,
+	MX35_PAD_FEC_MDIO__FEC_MDIO,
+	MX35_PAD_FEC_TX_ERR__FEC_TX_ERR,
+	MX35_PAD_FEC_RX_ERR__FEC_RX_ERR,
+	MX35_PAD_FEC_CRS__FEC_CRS,
+	MX35_PAD_FEC_RDATA1__FEC_RDATA_1,
+	MX35_PAD_FEC_TDATA1__FEC_TDATA_1,
+	MX35_PAD_FEC_RDATA2__FEC_RDATA_2,
+	MX35_PAD_FEC_TDATA2__FEC_TDATA_2,
+	MX35_PAD_FEC_RDATA3__FEC_RDATA_3,
+	MX35_PAD_FEC_TDATA3__FEC_TDATA_3,
+	/* 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,
+	MX35_PAD_D3_SPL__IPU_DISPB_D3_SPL
+};
+
+/*
+ * Board specific initialization.
+ */
+static void __init mxc_board_init(void)
+{
+	mxc_iomux_v3_setup_multiple_pads(pcm043_pads, ARRAY_SIZE(pcm043_pads));
+
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+
+	mxc_register_device(&mxc_uart_device0, &uart_pdata);
+
+	mxc_register_device(&mxc_uart_device1, &uart_pdata);
+
+#if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE
+	i2c_register_board_info(0, pcm043_i2c_devices,
+			ARRAY_SIZE(pcm043_i2c_devices));
+
+	mxc_register_device(&mxc_i2c_device0, &pcm043_i2c_1_data);
+#endif
+
+	mxc_register_device(&mx3_ipu, &mx3_ipu_data);
+	mxc_register_device(&mx3_fb, &mx3fb_pdata);
+}
+
+static void __init pcm043_timer_init(void)
+{
+	mx35_clocks_init();
+}
+
+struct sys_timer pcm043_timer = {
+	.init	= pcm043_timer_init,
+};
+
+MACHINE_START(PCM043, "Phytec Phycore pcm043")
+	/* Maintainer: Pengutronix */
+	.phys_io	= AIPS1_BASE_ADDR,
+	.io_pg_offst	= ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+	.boot_params    = PHYS_OFFSET + 0x100,
+	.map_io         = mx35_map_io,
+	.init_irq       = mxc_init_irq,
+	.init_machine   = mxc_board_init,
+	.timer          = &pcm043_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-mx3/qong.c b/arch/arm/mach-mx3/qong.c
index 5a01e48..82b31c4 100644
--- a/arch/arm/mach-mx3/qong.c
+++ b/arch/arm/mach-mx3/qong.c
@@ -279,7 +279,7 @@
 	.phys_io        = AIPS1_BASE_ADDR,
 	.io_pg_offst    = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = PHYS_OFFSET + 0x100,
-	.map_io         = mxc_map_io,
+	.map_io         = mx31_map_io,
 	.init_irq       = mxc_init_irq,
 	.init_machine   = mxc_board_init,
 	.timer          = &qong_timer,
diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c
index 79df60c..43da8bb 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);
+	vic_init(__io(io_p2v(NETX_PA_VIC)), 0, ~0, 0);
 
 	for (irq = NETX_IRQ_HIF_CHAINED(0); irq <= NETX_IRQ_HIF_LAST; irq++) {
 		set_irq_chip(irq, &netx_hif_chip);
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index cd8de89..55ecc01 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -46,7 +46,6 @@
 config MACH_OMAP_H3
 	bool "TI H3 Support"
 	depends on ARCH_OMAP1 && ARCH_OMAP16XX
-#	select GPIOEXPANDER_OMAP
     	help
 	  TI OMAP 1710 H3 board support. Say Y here if you have such
 	  a board.
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 1bda8f5..6867cd3 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -13,6 +13,10 @@
 # Power Management
 obj-$(CONFIG_PM) += pm.o sleep.o
 
+# DSP
+obj-$(CONFIG_OMAP_MBOX_FWK)	+= mailbox_mach.o
+mailbox_mach-objs		:= mailbox.o
+
 led-y := leds.o
 
 # Specific board support
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index d1ed136..e70fc7c 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -33,8 +33,11 @@
 #include <mach/common.h>
 #include <mach/dsp_common.h>
 #include <mach/omapfb.h>
+#include <mach/hwa742.h>
 #include <mach/lcd_mipid.h>
 #include <mach/mmc.h>
+#include <mach/usb.h>
+#include <mach/clock.h>
 
 #define ADS7846_PENDOWN_GPIO	15
 
@@ -162,6 +165,15 @@
 	},
 };
 
+static struct hwa742_platform_data nokia770_hwa742_platform_data = {
+	.te_connected		= 1,
+};
+
+static void 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 */
 
@@ -370,6 +382,7 @@
 	omap_serial_init();
 	omap_register_i2c_bus(1, 100, NULL, 0);
 	omap_dsp_init();
+	hwa742_dev_init();
 	ads7846_dev_init();
 	mipid_dev_init();
 	omap_usb_init(&nokia770_usb_config);
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
index 336e51d..436eed2 100644
--- a/arch/arm/mach-omap1/clock.c
+++ b/arch/arm/mach-omap1/clock.c
@@ -776,7 +776,7 @@
 	arm_idlect1_mask = ~0;
 
 	for (c = omap_clks; c < omap_clks + ARRAY_SIZE(omap_clks); c++)
-		clk_init_one(c->lk.clk);
+		clk_preinit(c->lk.clk);
 
 	cpu_mask = 0;
 	if (cpu_is_omap16xx())
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
index 9774c1f..5218943 100644
--- a/arch/arm/mach-omap1/pm.c
+++ b/arch/arm/mach-omap1/pm.c
@@ -53,11 +53,12 @@
 #include <mach/clock.h>
 #include <mach/sram.h>
 #include <mach/tc.h>
-#include <mach/pm.h>
 #include <mach/mux.h>
 #include <mach/dma.h>
 #include <mach/dmtimer.h>
 
+#include "pm.h"
+
 static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
 static unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE];
 static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
@@ -101,7 +102,7 @@
  * going idle we continue to do idle even if we get
  * a clock tick interrupt . .
  */
-void omap_pm_idle(void)
+void omap1_pm_idle(void)
 {
 	extern __u32 arm_idlect1_mask;
 	__u32 use_idlect1 = arm_idlect1_mask;
@@ -222,7 +223,7 @@
 #define EN_APICK	6	/* ARM_IDLECT2 */
 #define DSP_EN		1	/* ARM_RSTCT1 */
 
-void omap_pm_suspend(void)
+void omap1_pm_suspend(void)
 {
 	unsigned long arg0 = 0, arg1 = 0;
 
@@ -610,7 +611,7 @@
 	{
 	case PM_SUSPEND_STANDBY:
 	case PM_SUSPEND_MEM:
-		omap_pm_suspend();
+		omap1_pm_suspend();
 		break;
 	default:
 		return -EINVAL;
@@ -683,7 +684,7 @@
 		return -ENODEV;
 	}
 
-	pm_idle = omap_pm_idle;
+	pm_idle = omap1_pm_idle;
 
 	if (cpu_is_omap730())
 		setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq);
diff --git a/arch/arm/mach-omap1/pm.h b/arch/arm/mach-omap1/pm.h
new file mode 100644
index 0000000..9ed5e2c
--- /dev/null
+++ b/arch/arm/mach-omap1/pm.h
@@ -0,0 +1,280 @@
+/*
+ * arch/arm/mach-omap1/pm.h
+ *
+ * Header file for OMAP1 Power Management Routines
+ *
+ * Author: MontaVista Software, Inc.
+ *	   support@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ * Cleanup 2004 for Linux 2.6 by Dirk Behme <dirk.behme@de.bosch.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.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP1_PM_H
+#define __ARCH_ARM_MACH_OMAP1_PM_H
+
+/*
+ * ----------------------------------------------------------------------------
+ * Register and offset definitions to be used in PM assembler code
+ * ----------------------------------------------------------------------------
+ */
+#define CLKGEN_REG_ASM_BASE		IO_ADDRESS(0xfffece00)
+#define ARM_IDLECT1_ASM_OFFSET		0x04
+#define ARM_IDLECT2_ASM_OFFSET		0x08
+
+#define TCMIF_ASM_BASE			IO_ADDRESS(0xfffecc00)
+#define EMIFS_CONFIG_ASM_OFFSET		0x0c
+#define EMIFF_SDRAM_CONFIG_ASM_OFFSET	0x20
+
+/*
+ * ----------------------------------------------------------------------------
+ * Power management bitmasks
+ * ----------------------------------------------------------------------------
+ */
+#define IDLE_WAIT_CYCLES		0x00000fff
+#define PERIPHERAL_ENABLE		0x2
+
+#define SELF_REFRESH_MODE		0x0c000001
+#define IDLE_EMIFS_REQUEST		0xc
+#define MODEM_32K_EN			0x1
+#define PER_EN				0x1
+
+#define CPU_SUSPEND_SIZE		200
+#define ULPD_LOW_PWR_EN			0x0001
+#define ULPD_DEEP_SLEEP_TRANSITION_EN	0x0010
+#define ULPD_SETUP_ANALOG_CELL_3_VAL	0
+#define ULPD_POWER_CTRL_REG_VAL		0x0219
+
+#define DSP_IDLE_DELAY			10
+#define DSP_IDLE			0x0040
+#define DSP_RST				0x0004
+#define DSP_ENABLE			0x0002
+#define SUFFICIENT_DSP_RESET_TIME	1000
+#define DEFAULT_MPUI_CONFIG		0x05cf
+#define ENABLE_XORCLK			0x2
+#define DSP_CLOCK_ENABLE		0x2000
+#define DSP_IDLE_MODE			0x2
+#define TC_IDLE_REQUEST			(0x0000000c)
+
+#define IRQ_LEVEL2			(1<<0)
+#define IRQ_KEYBOARD			(1<<1)
+#define IRQ_UART2			(1<<15)
+
+#define PDE_BIT				0x08
+#define PWD_EN_BIT			0x04
+#define EN_PERCK_BIT			0x04
+
+#define OMAP1510_DEEP_SLEEP_REQUEST	0x0ec7
+#define OMAP1510_BIG_SLEEP_REQUEST	0x0cc5
+#define OMAP1510_IDLE_LOOP_REQUEST	0x0c00
+#define OMAP1510_IDLE_CLOCK_DOMAINS	0x2
+
+/* Both big sleep and deep sleep use same values. Difference is in ULPD. */
+#define OMAP1610_IDLECT1_SLEEP_VAL	0x13c7
+#define OMAP1610_IDLECT2_SLEEP_VAL	0x09c7
+#define OMAP1610_IDLECT3_VAL		0x3f
+#define OMAP1610_IDLECT3_SLEEP_ORMASK	0x2c
+#define OMAP1610_IDLECT3		0xfffece24
+#define OMAP1610_IDLE_LOOP_REQUEST	0x0400
+
+#define OMAP730_IDLECT1_SLEEP_VAL	0x16c7
+#define OMAP730_IDLECT2_SLEEP_VAL	0x09c7
+#define OMAP730_IDLECT3_VAL		0x3f
+#define OMAP730_IDLECT3		0xfffece24
+#define OMAP730_IDLE_LOOP_REQUEST	0x0C00
+
+#if     !defined(CONFIG_ARCH_OMAP730) && \
+	!defined(CONFIG_ARCH_OMAP15XX) && \
+	!defined(CONFIG_ARCH_OMAP16XX)
+#warning "Power management for this processor not implemented yet"
+#endif
+
+#ifndef __ASSEMBLER__
+
+#include <linux/clk.h>
+
+extern struct kset power_subsys;
+
+extern void prevent_idle_sleep(void);
+extern void allow_idle_sleep(void);
+
+extern void omap1_pm_idle(void);
+extern void omap1_pm_suspend(void);
+
+extern void omap730_cpu_suspend(unsigned short, unsigned short);
+extern void omap1510_cpu_suspend(unsigned short, unsigned short);
+extern void omap1610_cpu_suspend(unsigned short, unsigned short);
+extern void omap730_idle_loop_suspend(void);
+extern void omap1510_idle_loop_suspend(void);
+extern void omap1610_idle_loop_suspend(void);
+
+extern unsigned int omap730_cpu_suspend_sz;
+extern unsigned int omap1510_cpu_suspend_sz;
+extern unsigned int omap1610_cpu_suspend_sz;
+extern unsigned int omap730_idle_loop_suspend_sz;
+extern unsigned int omap1510_idle_loop_suspend_sz;
+extern unsigned int omap1610_idle_loop_suspend_sz;
+
+#ifdef CONFIG_OMAP_SERIAL_WAKE
+extern void omap_serial_wake_trigger(int enable);
+#else
+#define omap_serial_wakeup_init()	{}
+#define omap_serial_wake_trigger(x)	{}
+#endif	/* CONFIG_OMAP_SERIAL_WAKE */
+
+#define ARM_SAVE(x) arm_sleep_save[ARM_SLEEP_SAVE_##x] = omap_readl(x)
+#define ARM_RESTORE(x) omap_writel((arm_sleep_save[ARM_SLEEP_SAVE_##x]), (x))
+#define ARM_SHOW(x) arm_sleep_save[ARM_SLEEP_SAVE_##x]
+
+#define DSP_SAVE(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x] = __raw_readw(x)
+#define DSP_RESTORE(x) __raw_writew((dsp_sleep_save[DSP_SLEEP_SAVE_##x]), (x))
+#define DSP_SHOW(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x]
+
+#define ULPD_SAVE(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] = omap_readw(x)
+#define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x))
+#define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]
+
+#define MPUI730_SAVE(x) mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x] = omap_readl(x)
+#define MPUI730_RESTORE(x) omap_writel((mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x]), (x))
+#define MPUI730_SHOW(x) mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x]
+
+#define MPUI1510_SAVE(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x] = omap_readl(x)
+#define MPUI1510_RESTORE(x) omap_writel((mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]), (x))
+#define MPUI1510_SHOW(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]
+
+#define MPUI1610_SAVE(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x] = omap_readl(x)
+#define MPUI1610_RESTORE(x) omap_writel((mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]), (x))
+#define MPUI1610_SHOW(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]
+
+/*
+ * List of global OMAP registers to preserve.
+ * More ones like CP and general purpose register values are preserved
+ * with the stack pointer in sleep.S.
+ */
+
+enum arm_save_state {
+	ARM_SLEEP_SAVE_START = 0,
+	/*
+	 * MPU control registers 32 bits
+	 */
+	ARM_SLEEP_SAVE_ARM_CKCTL,
+	ARM_SLEEP_SAVE_ARM_IDLECT1,
+	ARM_SLEEP_SAVE_ARM_IDLECT2,
+	ARM_SLEEP_SAVE_ARM_IDLECT3,
+	ARM_SLEEP_SAVE_ARM_EWUPCT,
+	ARM_SLEEP_SAVE_ARM_RSTCT1,
+	ARM_SLEEP_SAVE_ARM_RSTCT2,
+	ARM_SLEEP_SAVE_ARM_SYSST,
+	ARM_SLEEP_SAVE_SIZE
+};
+
+enum dsp_save_state {
+	DSP_SLEEP_SAVE_START = 0,
+	/*
+	 * DSP registers 16 bits
+	 */
+	DSP_SLEEP_SAVE_DSP_IDLECT2,
+	DSP_SLEEP_SAVE_SIZE
+};
+
+enum ulpd_save_state {
+	ULPD_SLEEP_SAVE_START = 0,
+	/*
+	 * ULPD registers 16 bits
+	 */
+	ULPD_SLEEP_SAVE_ULPD_IT_STATUS,
+	ULPD_SLEEP_SAVE_ULPD_CLOCK_CTRL,
+	ULPD_SLEEP_SAVE_ULPD_SOFT_REQ,
+	ULPD_SLEEP_SAVE_ULPD_STATUS_REQ,
+	ULPD_SLEEP_SAVE_ULPD_DPLL_CTRL,
+	ULPD_SLEEP_SAVE_ULPD_POWER_CTRL,
+	ULPD_SLEEP_SAVE_SIZE
+};
+
+enum mpui1510_save_state {
+	MPUI1510_SLEEP_SAVE_START = 0,
+	/*
+	 * MPUI registers 32 bits
+	 */
+	MPUI1510_SLEEP_SAVE_MPUI_CTRL,
+	MPUI1510_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
+	MPUI1510_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
+	MPUI1510_SLEEP_SAVE_MPUI_DSP_STATUS,
+	MPUI1510_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
+	MPUI1510_SLEEP_SAVE_EMIFS_CONFIG,
+	MPUI1510_SLEEP_SAVE_OMAP_IH1_MIR,
+	MPUI1510_SLEEP_SAVE_OMAP_IH2_MIR,
+#if defined(CONFIG_ARCH_OMAP15XX)
+	MPUI1510_SLEEP_SAVE_SIZE
+#else
+	MPUI1510_SLEEP_SAVE_SIZE = 0
+#endif
+};
+
+enum mpui730_save_state {
+	MPUI730_SLEEP_SAVE_START = 0,
+	/*
+	 * MPUI registers 32 bits
+	 */
+	MPUI730_SLEEP_SAVE_MPUI_CTRL,
+	MPUI730_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
+	MPUI730_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
+	MPUI730_SLEEP_SAVE_MPUI_DSP_STATUS,
+	MPUI730_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
+	MPUI730_SLEEP_SAVE_EMIFS_CONFIG,
+	MPUI730_SLEEP_SAVE_OMAP_IH1_MIR,
+	MPUI730_SLEEP_SAVE_OMAP_IH2_0_MIR,
+	MPUI730_SLEEP_SAVE_OMAP_IH2_1_MIR,
+#if defined(CONFIG_ARCH_OMAP730)
+	MPUI730_SLEEP_SAVE_SIZE
+#else
+	MPUI730_SLEEP_SAVE_SIZE = 0
+#endif
+};
+
+enum mpui1610_save_state {
+	MPUI1610_SLEEP_SAVE_START = 0,
+	/*
+	 * MPUI registers 32 bits
+	 */
+	MPUI1610_SLEEP_SAVE_MPUI_CTRL,
+	MPUI1610_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
+	MPUI1610_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
+	MPUI1610_SLEEP_SAVE_MPUI_DSP_STATUS,
+	MPUI1610_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
+	MPUI1610_SLEEP_SAVE_EMIFS_CONFIG,
+	MPUI1610_SLEEP_SAVE_OMAP_IH1_MIR,
+	MPUI1610_SLEEP_SAVE_OMAP_IH2_0_MIR,
+	MPUI1610_SLEEP_SAVE_OMAP_IH2_1_MIR,
+	MPUI1610_SLEEP_SAVE_OMAP_IH2_2_MIR,
+	MPUI1610_SLEEP_SAVE_OMAP_IH2_3_MIR,
+#if defined(CONFIG_ARCH_OMAP16XX)
+	MPUI1610_SLEEP_SAVE_SIZE
+#else
+	MPUI1610_SLEEP_SAVE_SIZE = 0
+#endif
+};
+
+#endif /* ASSEMBLER */
+#endif /* __ASM_ARCH_OMAP_PM_H */
diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c
index 842090b..f754cee 100644
--- a/arch/arm/mach-omap1/serial.c
+++ b/arch/arm/mach-omap1/serial.c
@@ -26,9 +26,6 @@
 #include <mach/mux.h>
 #include <mach/gpio.h>
 #include <mach/fpga.h>
-#ifdef CONFIG_PM
-#include <mach/pm.h>
-#endif
 
 static struct clk * uart1_ck;
 static struct clk * uart2_ck;
diff --git a/arch/arm/mach-omap1/sleep.S b/arch/arm/mach-omap1/sleep.S
index f3eac93..22e8568 100644
--- a/arch/arm/mach-omap1/sleep.S
+++ b/arch/arm/mach-omap1/sleep.S
@@ -35,7 +35,7 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <mach/io.h>
-#include <mach/pm.h>
+#include "pm.h"
 
 		.text
 
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 64ab386..a755eb5 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -25,7 +25,7 @@
 	select ARCH_OMAP_OTG
 
 comment "OMAP Board Type"
-	depends on ARCH_OMAP2 || ARCH_OMAP3
+	depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4
 
 config MACH_OMAP_GENERIC
 	bool "Generic OMAP board"
@@ -56,6 +56,10 @@
 	bool "Gumstix Overo board"
 	depends on ARCH_OMAP3 && ARCH_OMAP34XX
 
+config MACH_OMAP3EVM
+	bool "OMAP 3530 EVM board"
+	depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
 config MACH_OMAP3_PANDORA
 	bool "OMAP3 Pandora"
 	depends on ARCH_OMAP3 && ARCH_OMAP34XX
@@ -67,3 +71,11 @@
 config MACH_NOKIA_RX51
 	bool "Nokia RX-51 board"
 	depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP_ZOOM2
+	bool "OMAP3 Zoom2 board"
+	depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP_4430SDP
+	bool "OMAP 4430 SDP board"
+	depends on ARCH_OMAP4
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index c49d9bf..735bae5 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -3,12 +3,21 @@
 #
 
 # Common support
-obj-y := irq.o id.o io.o sdrc.o control.o prcm.o clock.o mux.o \
-		devices.o serial.o gpmc.o timer-gp.o powerdomain.o \
-		clockdomain.o
+obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o
+
+omap-2-3-common				= irq.o sdrc.o
+prcm-common				= prcm.o powerdomain.o
+clock-common				= clock.o clockdomain.o
+
+obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common)
+obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(clock-common)
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
+# SMP support ONLY available for OMAP4
+obj-$(CONFIG_SMP)			+= omap-smp.o omap-headsmp.o
+obj-$(CONFIG_LOCAL_TIMERS)		+= timer-mpu.o
+
 # Functions loaded to SRAM
 obj-$(CONFIG_ARCH_OMAP2420)		+= sram242x.o
 obj-$(CONFIG_ARCH_OMAP2430)		+= sram243x.o
@@ -20,14 +29,21 @@
 
 # Power Management
 ifeq ($(CONFIG_PM),y)
-obj-y					+= pm.o
+obj-$(CONFIG_ARCH_OMAP2)		+= pm24xx.o
 obj-$(CONFIG_ARCH_OMAP24XX)		+= sleep24xx.o
+obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o
+obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
 endif
 
 # Clock framework
 obj-$(CONFIG_ARCH_OMAP2)		+= clock24xx.o
 obj-$(CONFIG_ARCH_OMAP3)		+= clock34xx.o
 
+iommu-y					+= iommu2.o
+iommu-$(CONFIG_ARCH_OMAP3)		+= omap3-iommu.o
+
+obj-$(CONFIG_OMAP_IOMMU)		+= $(iommu-y)
+
 # Specific board support
 obj-$(CONFIG_MACH_OMAP_GENERIC)		+= board-generic.o
 obj-$(CONFIG_MACH_OMAP_H4)		+= board-h4.o
@@ -40,6 +56,8 @@
 					   mmc-twl4030.o
 obj-$(CONFIG_MACH_OVERO)		+= board-overo.o \
 					   mmc-twl4030.o
+obj-$(CONFIG_MACH_OMAP3EVM)		+= board-omap3evm.o \
+					   mmc-twl4030.o
 obj-$(CONFIG_MACH_OMAP3_PANDORA)	+= board-omap3pandora.o \
 					   mmc-twl4030.o
 obj-$(CONFIG_MACH_OMAP_3430SDP)		+= board-3430sdp.o \
@@ -48,8 +66,17 @@
 obj-$(CONFIG_MACH_NOKIA_RX51)		+= board-rx51.o \
 					   board-rx51-peripherals.o \
 					   mmc-twl4030.o
+obj-$(CONFIG_MACH_OMAP_ZOOM2)		+= board-zoom2.o \
+					   mmc-twl4030.o \
+					   board-zoom-debugboard.o
+
+obj-$(CONFIG_MACH_OMAP_4430SDP)		+= board-4430sdp.o
 
 # Platform specific device init code
-ifeq ($(CONFIG_USB_MUSB_SOC),y)
 obj-y					+= usb-musb.o
-endif
+
+onenand-$(CONFIG_MTD_ONENAND_OMAP2)	:= gpmc-onenand.o
+obj-y					+= $(onenand-m) $(onenand-y)
+
+smc91x-$(CONFIG_SMC91X)			:= gpmc-smc91x.o
+obj-y					+= $(smc91x-m) $(smc91x-y)
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 2214365..9c3fdcd 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -36,14 +36,12 @@
 #include <mach/common.h>
 #include <mach/gpmc.h>
 #include <mach/usb.h>
+#include <mach/gpmc-smc91x.h>
 
 #include "mmc-twl4030.h"
 
 #define SDP2430_CS0_BASE	0x04000000
-#define	SDP2430_FLASH_CS	0
-#define	SDP2430_SMC91X_CS	5
-
-#define SDP2430_ETHR_GPIO_IRQ		149
+#define SECONDARY_LCD_GPIO		147
 
 static struct mtd_partition sdp2430_partitions[] = {
 	/* bootloader (U-Boot, etc) in first sector */
@@ -99,100 +97,53 @@
 	.resource	= &sdp2430_flash_resource,
 };
 
-static struct resource sdp2430_smc91x_resources[] = {
-	[0] = {
-		.start	= SDP2430_CS0_BASE,
-		.end	= SDP2430_CS0_BASE + SZ_64M - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= OMAP_GPIO_IRQ(SDP2430_ETHR_GPIO_IRQ),
-		.end	= OMAP_GPIO_IRQ(SDP2430_ETHR_GPIO_IRQ),
-		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-	},
-};
-
-static struct platform_device sdp2430_smc91x_device = {
-	.name		= "smc91x",
+static struct platform_device sdp2430_lcd_device = {
+	.name		= "sdp2430_lcd",
 	.id		= -1,
-	.num_resources	= ARRAY_SIZE(sdp2430_smc91x_resources),
-	.resource	= sdp2430_smc91x_resources,
 };
 
 static struct platform_device *sdp2430_devices[] __initdata = {
-	&sdp2430_smc91x_device,
 	&sdp2430_flash_device,
+	&sdp2430_lcd_device,
 };
 
-static inline void __init sdp2430_init_smc91x(void)
+static struct omap_lcd_config sdp2430_lcd_config __initdata = {
+	.ctrl_name	= "internal",
+};
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91x_MODULE)
+
+static struct omap_smc91x_platform_data board_smc91x_data = {
+	.cs		= 5,
+	.gpio_irq	= 149,
+	.flags		= GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 |
+				IORESOURCE_IRQ_LOWLEVEL,
+
+};
+
+static void __init board_smc91x_init(void)
 {
-	int eth_cs;
-	unsigned long cs_mem_base;
-	unsigned int rate;
-	struct clk *gpmc_fck;
+	if (omap_rev() > OMAP3430_REV_ES1_0)
+		board_smc91x_data.gpio_irq = 6;
+	else
+		board_smc91x_data.gpio_irq = 29;
 
-	eth_cs = SDP2430_SMC91X_CS;
-
-	gpmc_fck = clk_get(NULL, "gpmc_fck");	/* Always on ENABLE_ON_INIT */
-	if (IS_ERR(gpmc_fck)) {
-		WARN_ON(1);
-		return;
-	}
-
-	clk_enable(gpmc_fck);
-	rate = clk_get_rate(gpmc_fck);
-
-	/* Make sure CS1 timings are correct, for 2430 always muxed */
-	gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1, 0x00011200);
-
-	if (rate >= 160000000) {
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f01);
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080803);
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1c0b1c0a);
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
-	} else if (rate >= 130000000) {
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
-	} else { /* rate = 100000000 */
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x031A1F1F);
-		gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2);
-	}
-
-	if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
-		printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
-		goto out;
-	}
-
-	sdp2430_smc91x_resources[0].start = cs_mem_base + 0x300;
-	sdp2430_smc91x_resources[0].end = cs_mem_base + 0x30f;
-	udelay(100);
-
-	if (gpio_request(SDP2430_ETHR_GPIO_IRQ, "SMC91x irq") < 0) {
-		printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
-			SDP2430_ETHR_GPIO_IRQ);
-		gpmc_cs_free(eth_cs);
-		goto out;
-	}
-	gpio_direction_input(SDP2430_ETHR_GPIO_IRQ);
-
-out:
-	clk_disable(gpmc_fck);
-	clk_put(gpmc_fck);
+	gpmc_smc91x_init(&board_smc91x_data);
 }
 
+#else
+
+static inline void board_smc91x_init(void)
+{
+}
+
+#endif
+
 static void __init omap_2430sdp_init_irq(void)
 {
 	omap2_init_common_hw(NULL);
 	omap_init_irq();
 	omap_gpio_init();
-	sdp2430_init_smc91x();
 }
 
 static struct omap_uart_config sdp2430_uart_config __initdata = {
@@ -201,6 +152,7 @@
 
 static struct omap_board_config_kernel sdp2430_config[] = {
 	{OMAP_TAG_UART, &sdp2430_uart_config},
+	{OMAP_TAG_LCD, &sdp2430_lcd_config},
 };
 
 
@@ -248,6 +200,8 @@
 
 static void __init omap_2430sdp_init(void)
 {
+	int ret;
+
 	omap2430_i2c_init();
 
 	platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices));
@@ -256,6 +210,12 @@
 	omap_serial_init();
 	twl4030_mmc_init(mmc);
 	usb_musb_init();
+	board_smc91x_init();
+
+	/* Turn off secondary LCD backlight */
+	ret = gpio_request(SECONDARY_LCD_GPIO, "Secondary LCD backlight");
+	if (ret == 0)
+		gpio_direction_output(SECONDARY_LCD_GPIO, 0);
 }
 
 static void __init omap_2430sdp_map_io(void)
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index ed92749..496a90e 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -39,15 +39,13 @@
 
 #include <mach/control.h>
 #include <mach/keypad.h>
+#include <mach/gpmc-smc91x.h>
 
+#include "sdram-qimonda-hyb18m512160af-6.h"
 #include "mmc-twl4030.h"
 
 #define CONFIG_DISABLE_HFCLK 1
 
-#define SDP3430_ETHR_GPIO_IRQ_SDPV1	29
-#define SDP3430_ETHR_GPIO_IRQ_SDPV2	6
-#define SDP3430_SMC91X_CS		3
-
 #define SDP3430_TS_GPIO_IRQ_SDPV1	3
 #define SDP3430_TS_GPIO_IRQ_SDPV2	2
 
@@ -56,24 +54,6 @@
 
 #define TWL4030_MSECURE_GPIO 22
 
-static struct resource sdp3430_smc91x_resources[] = {
-	[0] = {
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= 0,
-		.end	= 0,
-		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-	},
-};
-
-static struct platform_device sdp3430_smc91x_device = {
-	.name		= "smc91x",
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(sdp3430_smc91x_resources),
-	.resource	= sdp3430_smc91x_resources,
-};
-
 static int sdp3430_keymap[] = {
 	KEY(0, 0, KEY_LEFT),
 	KEY(0, 1, KEY_RIGHT),
@@ -184,48 +164,14 @@
 };
 
 static struct platform_device *sdp3430_devices[] __initdata = {
-	&sdp3430_smc91x_device,
 	&sdp3430_lcd_device,
 };
 
-static inline void __init sdp3430_init_smc91x(void)
-{
-	int eth_cs;
-	unsigned long cs_mem_base;
-	int eth_gpio = 0;
-
-	eth_cs = SDP3430_SMC91X_CS;
-
-	if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
-		printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
-		return;
-	}
-
-	sdp3430_smc91x_resources[0].start = cs_mem_base + 0x300;
-	sdp3430_smc91x_resources[0].end = cs_mem_base + 0x30f;
-	udelay(100);
-
-	if (omap_rev() > OMAP3430_REV_ES1_0)
-		eth_gpio = SDP3430_ETHR_GPIO_IRQ_SDPV2;
-	else
-		eth_gpio = SDP3430_ETHR_GPIO_IRQ_SDPV1;
-
-	sdp3430_smc91x_resources[1].start = gpio_to_irq(eth_gpio);
-
-	if (gpio_request(eth_gpio, "SMC91x irq") < 0) {
-		printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
-			eth_gpio);
-		return;
-	}
-	gpio_direction_input(eth_gpio);
-}
-
 static void __init omap_3430sdp_init_irq(void)
 {
-	omap2_init_common_hw(NULL);
+	omap2_init_common_hw(hyb18m512160af6_sdrc_params);
 	omap_init_irq();
 	omap_gpio_init();
-	sdp3430_init_smc91x();
 }
 
 static struct omap_uart_config sdp3430_uart_config __initdata = {
@@ -506,6 +452,32 @@
 	return 0;
 }
 
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+
+static struct omap_smc91x_platform_data board_smc91x_data = {
+	.cs		= 3,
+	.flags		= GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 |
+				IORESOURCE_IRQ_LOWLEVEL,
+};
+
+static void __init board_smc91x_init(void)
+{
+	if (omap_rev() > OMAP3430_REV_ES1_0)
+		board_smc91x_data.gpio_irq = 6;
+	else
+		board_smc91x_data.gpio_irq = 29;
+
+	gpmc_smc91x_init(&board_smc91x_data);
+}
+
+#else
+
+static inline void board_smc91x_init(void)
+{
+}
+
+#endif
+
 static void __init omap_3430sdp_init(void)
 {
 	omap3430_i2c_init();
@@ -522,6 +494,7 @@
 	ads7846_dev_init();
 	omap_serial_init();
 	usb_musb_init();
+	board_smc91x_init();
 }
 
 static void __init omap_3430sdp_map_io(void)
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
new file mode 100644
index 0000000..57e477b
--- /dev/null
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -0,0 +1,94 @@
+/*
+ * Board support file for OMAP4430 SDP.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * Author: Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * Based on mach-omap2/board-3430sdp.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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/board.h>
+#include <mach/common.h>
+#include <mach/control.h>
+#include <mach/timer-gp.h>
+#include <asm/hardware/gic.h>
+
+static struct platform_device sdp4430_lcd_device = {
+	.name		= "sdp4430_lcd",
+	.id		= -1,
+};
+
+static struct platform_device *sdp4430_devices[] __initdata = {
+	&sdp4430_lcd_device,
+};
+
+static struct omap_uart_config sdp4430_uart_config __initdata = {
+	.enabled_uarts	= (1 << 0) | (1 << 1) | (1 << 2),
+};
+
+static struct omap_lcd_config sdp4430_lcd_config __initdata = {
+	.ctrl_name	= "internal",
+};
+
+static struct omap_board_config_kernel sdp4430_config[] __initdata = {
+	{ OMAP_TAG_UART,	&sdp4430_uart_config },
+	{ OMAP_TAG_LCD,		&sdp4430_lcd_config },
+};
+
+static void __init gic_init_irq(void)
+{
+	gic_dist_init(0, IO_ADDRESS(OMAP44XX_GIC_DIST_BASE), 29);
+	gic_cpu_init(0, IO_ADDRESS(OMAP44XX_GIC_CPU_BASE));
+}
+
+static void __init omap_4430sdp_init_irq(void)
+{
+	omap2_init_common_hw(NULL);
+#ifdef CONFIG_OMAP_32K_TIMER
+	omap2_gp_clockevent_set_gptimer(1);
+#endif
+	gic_init_irq();
+	omap_gpio_init();
+}
+
+
+static void __init omap_4430sdp_init(void)
+{
+	platform_add_devices(sdp4430_devices, ARRAY_SIZE(sdp4430_devices));
+	omap_board_config = sdp4430_config;
+	omap_board_config_size = ARRAY_SIZE(sdp4430_config);
+	omap_serial_init();
+}
+
+static void __init omap_4430sdp_map_io(void)
+{
+	omap2_set_globals_443x();
+	omap2_map_common_io();
+}
+
+MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board")
+	/* Maintainer: Santosh Shilimkar - Texas Instruments Inc */
+	.phys_io	= 0x48000000,
+	.io_pg_offst	= ((0xd8000000) >> 18) & 0xfffc,
+	.boot_params	= 0x80000100,
+	.map_io		= omap_4430sdp_map_io,
+	.init_irq	= omap_4430sdp_init_irq,
+	.init_machine	= omap_4430sdp_init,
+	.timer		= &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index da57b0f..d8bc0a7 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -16,11 +16,13 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/input.h>
+#include <linux/gpio_keys.h>
 #include <linux/workqueue.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
+#include <linux/regulator/machine.h>
 #include <linux/i2c/twl4030.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
@@ -39,6 +41,7 @@
 #include <asm/delay.h>
 #include <mach/control.h>
 #include <mach/usb.h>
+#include <mach/keypad.h>
 
 #include "mmc-twl4030.h"
 
@@ -77,8 +80,163 @@
 	},
 };
 
-static struct platform_device *ldp_devices[] __initdata = {
-	&ldp_smsc911x_device,
+static int ldp_twl4030_keymap[] = {
+	KEY(0, 0, KEY_1),
+	KEY(1, 0, KEY_2),
+	KEY(2, 0, KEY_3),
+	KEY(0, 1, KEY_4),
+	KEY(1, 1, KEY_5),
+	KEY(2, 1, KEY_6),
+	KEY(3, 1, KEY_F5),
+	KEY(0, 2, KEY_7),
+	KEY(1, 2, KEY_8),
+	KEY(2, 2, KEY_9),
+	KEY(3, 2, KEY_F6),
+	KEY(0, 3, KEY_F7),
+	KEY(1, 3, KEY_0),
+	KEY(2, 3, KEY_F8),
+	PERSISTENT_KEY(4, 5),
+	KEY(4, 4, KEY_VOLUMEUP),
+	KEY(5, 5, KEY_VOLUMEDOWN),
+	0
+};
+
+static struct twl4030_keypad_data ldp_kp_twl4030_data = {
+	.rows		= 6,
+	.cols		= 6,
+	.keymap		= ldp_twl4030_keymap,
+	.keymapsize	= ARRAY_SIZE(ldp_twl4030_keymap),
+	.rep		= 1,
+};
+
+static struct gpio_keys_button ldp_gpio_keys_buttons[] = {
+	[0] = {
+		.code			= KEY_ENTER,
+		.gpio			= 101,
+		.desc			= "enter sw",
+		.active_low		= 1,
+		.debounce_interval	= 30,
+	},
+	[1] = {
+		.code			= KEY_F1,
+		.gpio			= 102,
+		.desc			= "func 1",
+		.active_low		= 1,
+		.debounce_interval	= 30,
+	},
+	[2] = {
+		.code			= KEY_F2,
+		.gpio			= 103,
+		.desc			= "func 2",
+		.active_low		= 1,
+		.debounce_interval	= 30,
+	},
+	[3] = {
+		.code			= KEY_F3,
+		.gpio			= 104,
+		.desc			= "func 3",
+		.active_low		= 1,
+		.debounce_interval 	= 30,
+	},
+	[4] = {
+		.code			= KEY_F4,
+		.gpio			= 105,
+		.desc			= "func 4",
+		.active_low		= 1,
+		.debounce_interval	= 30,
+	},
+	[5] = {
+		.code			= KEY_LEFT,
+		.gpio			= 106,
+		.desc			= "left sw",
+		.active_low		= 1,
+		.debounce_interval	= 30,
+	},
+	[6] = {
+		.code			= KEY_RIGHT,
+		.gpio			= 107,
+		.desc			= "right sw",
+		.active_low		= 1,
+		.debounce_interval	= 30,
+	},
+	[7] = {
+		.code			= KEY_UP,
+		.gpio			= 108,
+		.desc			= "up sw",
+		.active_low		= 1,
+		.debounce_interval	= 30,
+	},
+	[8] = {
+		.code			= KEY_DOWN,
+		.gpio			= 109,
+		.desc			= "down sw",
+		.active_low		= 1,
+		.debounce_interval	= 30,
+	},
+};
+
+static struct gpio_keys_platform_data ldp_gpio_keys = {
+	.buttons		= ldp_gpio_keys_buttons,
+	.nbuttons		= ARRAY_SIZE(ldp_gpio_keys_buttons),
+	.rep			= 1,
+};
+
+static struct platform_device ldp_gpio_keys_device = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &ldp_gpio_keys,
+	},
+};
+
+static int ts_gpio;
+
+/**
+ * @brief ads7846_dev_init : Requests & sets GPIO line for pen-irq
+ *
+ * @return - void. If request gpio fails then Flag KERN_ERR.
+ */
+static void ads7846_dev_init(void)
+{
+	if (gpio_request(ts_gpio, "ads7846 irq") < 0) {
+		printk(KERN_ERR "can't get ads746 pen down GPIO\n");
+		return;
+	}
+
+	gpio_direction_input(ts_gpio);
+	omap_set_gpio_debounce(ts_gpio, 1);
+	omap_set_gpio_debounce_time(ts_gpio, 0xa);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+	return !gpio_get_value(ts_gpio);
+}
+
+static struct ads7846_platform_data tsc2046_config __initdata = {
+	.get_pendown_state	= ads7846_get_pendown_state,
+	.keep_vref_on		= 1,
+};
+
+static struct omap2_mcspi_device_config tsc2046_mcspi_config = {
+	.turbo_mode	= 0,
+	.single_channel	= 1,	/* 0: slave, 1: master */
+};
+
+static struct spi_board_info ldp_spi_board_info[] __initdata = {
+	[0] = {
+		/*
+		 * TSC2046 operates at a max freqency of 2MHz, so
+		 * operate slightly below at 1.5MHz
+		 */
+		.modalias		= "ads7846",
+		.bus_num		= 1,
+		.chip_select		= 0,
+		.max_speed_hz		= 1500000,
+		.controller_data	= &tsc2046_mcspi_config,
+		.irq			= 0,
+		.platform_data		= &tsc2046_config,
+	},
 };
 
 static inline void __init ldp_init_smsc911x(void)
@@ -122,8 +280,22 @@
 	.enabled_uarts	= ((1 << 0) | (1 << 1) | (1 << 2)),
 };
 
+static struct platform_device ldp_lcd_device = {
+	.name		= "ldp_lcd",
+	.id		= -1,
+};
+
+static struct omap_lcd_config ldp_lcd_config __initdata = {
+	.ctrl_name	= "internal",
+};
+
 static struct omap_board_config_kernel ldp_config[] __initdata = {
 	{ OMAP_TAG_UART,	&ldp_uart_config },
+	{ OMAP_TAG_LCD,		&ldp_lcd_config },
+};
+
+static struct twl4030_usb_data ldp_usb_data = {
+	.usb_mode	= T2_USB_MODE_ULPI,
 };
 
 static struct twl4030_gpio_platform_data ldp_gpio_data = {
@@ -132,12 +304,39 @@
 	.irq_end	= TWL4030_GPIO_IRQ_END,
 };
 
+static struct twl4030_madc_platform_data ldp_madc_data = {
+	.irq_line	= 1,
+};
+
+static struct regulator_consumer_supply ldp_vmmc1_supply = {
+	.supply			= "vmmc",
+};
+
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data ldp_vmmc1 = {
+	.constraints = {
+		.min_uV			= 1850000,
+		.max_uV			= 3150000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE
+					| REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &ldp_vmmc1_supply,
+};
+
 static struct twl4030_platform_data ldp_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
+	.madc		= &ldp_madc_data,
+	.usb		= &ldp_usb_data,
+	.vmmc1		= &ldp_vmmc1,
 	.gpio		= &ldp_gpio_data,
+	.keypad		= &ldp_kp_twl4030_data,
 };
 
 static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = {
@@ -168,15 +367,29 @@
 	{}	/* Terminator */
 };
 
+static struct platform_device *ldp_devices[] __initdata = {
+	&ldp_smsc911x_device,
+	&ldp_lcd_device,
+	&ldp_gpio_keys_device,
+};
+
 static void __init omap_ldp_init(void)
 {
 	omap_i2c_init();
 	platform_add_devices(ldp_devices, ARRAY_SIZE(ldp_devices));
 	omap_board_config = ldp_config;
 	omap_board_config_size = ARRAY_SIZE(ldp_config);
+	ts_gpio = 54;
+	ldp_spi_board_info[0].irq = gpio_to_irq(ts_gpio);
+	spi_register_board_info(ldp_spi_board_info,
+				ARRAY_SIZE(ldp_spi_board_info));
+	ads7846_dev_init();
 	omap_serial_init();
-	twl4030_mmc_init(mmc);
 	usb_musb_init();
+
+	twl4030_mmc_init(mmc);
+	/* link regulators to MMC adapters */
+	ldp_vmmc1_supply.dev = mmc[0].dev;
 }
 
 static void __init omap_ldp_map_io(void)
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 3a7a29d..991ac9c 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -28,6 +28,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
 
+#include <linux/regulator/machine.h>
 #include <linux/i2c/twl4030.h>
 
 #include <mach/hardware.h>
@@ -105,6 +106,8 @@
 	.resource	= &omap3beagle_nand_resource,
 };
 
+#include "sdram-micron-mt46h32m32lf-6.h"
+
 static struct omap_uart_config omap3_beagle_uart_config __initdata = {
 	.enabled_uarts	= ((1 << 0) | (1 << 1) | (1 << 2)),
 };
@@ -118,6 +121,23 @@
 	{}	/* Terminator */
 };
 
+static struct platform_device omap3_beagle_lcd_device = {
+	.name		= "omap3beagle_lcd",
+	.id		= -1,
+};
+
+static struct omap_lcd_config omap3_beagle_lcd_config __initdata = {
+	.ctrl_name	= "internal",
+};
+
+static struct regulator_consumer_supply beagle_vmmc1_supply = {
+	.supply			= "vmmc",
+};
+
+static struct regulator_consumer_supply beagle_vsim_supply = {
+	.supply			= "vmmc_aux",
+};
+
 static struct gpio_led gpio_leds[];
 
 static int beagle_twl_gpio_setup(struct device *dev,
@@ -128,6 +148,10 @@
 	mmc[0].gpio_cd = gpio + 0;
 	twl4030_mmc_init(mmc);
 
+	/* link regulators to MMC adapters */
+	beagle_vmmc1_supply.dev = mmc[0].dev;
+	beagle_vsim_supply.dev = mmc[0].dev;
+
 	/* REVISIT: need ehci-omap hooks for external VBUS
 	 * power switch and overcurrent detect
 	 */
@@ -156,12 +180,85 @@
 	.setup		= beagle_twl_gpio_setup,
 };
 
+static struct regulator_consumer_supply beagle_vdac_supply = {
+	.supply		= "vdac",
+	.dev		= &omap3_beagle_lcd_device.dev,
+};
+
+static struct regulator_consumer_supply beagle_vdvi_supply = {
+	.supply		= "vdvi",
+	.dev		= &omap3_beagle_lcd_device.dev,
+};
+
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data beagle_vmmc1 = {
+	.constraints = {
+		.min_uV			= 1850000,
+		.max_uV			= 3150000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE
+					| REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &beagle_vmmc1_supply,
+};
+
+/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */
+static struct regulator_init_data beagle_vsim = {
+	.constraints = {
+		.min_uV			= 1800000,
+		.max_uV			= 3000000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE
+					| REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &beagle_vsim_supply,
+};
+
+/* VDAC for DSS driving S-Video (8 mA unloaded, max 65 mA) */
+static struct regulator_init_data beagle_vdac = {
+	.constraints = {
+		.min_uV			= 1800000,
+		.max_uV			= 1800000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &beagle_vdac_supply,
+};
+
+/* VPLL2 for digital video outputs */
+static struct regulator_init_data beagle_vpll2 = {
+	.constraints = {
+		.name			= "VDVI",
+		.min_uV			= 1800000,
+		.max_uV			= 1800000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &beagle_vdvi_supply,
+};
+
 static struct twl4030_platform_data beagle_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
 	.gpio		= &beagle_gpio_data,
+	.vmmc1		= &beagle_vmmc1,
+	.vsim		= &beagle_vsim,
+	.vdac		= &beagle_vdac,
+	.vpll2		= &beagle_vpll2,
 };
 
 static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
@@ -185,7 +282,7 @@
 
 static void __init omap3_beagle_init_irq(void)
 {
-	omap2_init_common_hw(NULL);
+	omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
 	omap_init_irq();
 #ifdef CONFIG_OMAP_32K_TIMER
 	omap2_gp_clockevent_set_gptimer(12);
@@ -193,15 +290,6 @@
 	omap_gpio_init();
 }
 
-static struct platform_device omap3_beagle_lcd_device = {
-	.name		= "omap3beagle_lcd",
-	.id		= -1,
-};
-
-static struct omap_lcd_config omap3_beagle_lcd_config __initdata = {
-	.ctrl_name	= "internal",
-};
-
 static struct gpio_led gpio_leds[] = {
 	{
 		.name			= "beagleboard::usr0",
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
new file mode 100644
index 0000000..d3cc145
--- /dev/null
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -0,0 +1,329 @@
+/*
+ * linux/arch/arm/mach-omap2/board-omap3evm.c
+ *
+ * Copyright (C) 2008 Texas Instruments
+ *
+ * Modified from mach-omap2/board-3430sdp.c
+ *
+ * Initial code: Syed Mohammed Khasim
+ *
+ * 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/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/board.h>
+#include <mach/mux.h>
+#include <mach/usb.h>
+#include <mach/common.h>
+#include <mach/mcspi.h>
+#include <mach/keypad.h>
+
+#include "sdram-micron-mt46h32m32lf-6.h"
+#include "mmc-twl4030.h"
+
+#define OMAP3_EVM_TS_GPIO	175
+
+#define OMAP3EVM_ETHR_START	0x2c000000
+#define OMAP3EVM_ETHR_SIZE	1024
+#define OMAP3EVM_ETHR_GPIO_IRQ	176
+#define OMAP3EVM_SMC911X_CS	5
+
+static struct resource omap3evm_smc911x_resources[] = {
+	[0] =	{
+		.start	= OMAP3EVM_ETHR_START,
+		.end	= (OMAP3EVM_ETHR_START + OMAP3EVM_ETHR_SIZE - 1),
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] =	{
+		.start	= OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
+		.end	= OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device omap3evm_smc911x_device = {
+	.name		= "smc911x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(omap3evm_smc911x_resources),
+	.resource	= &omap3evm_smc911x_resources[0],
+};
+
+static inline void __init omap3evm_init_smc911x(void)
+{
+	int eth_cs;
+	struct clk *l3ck;
+	unsigned int rate;
+
+	eth_cs = OMAP3EVM_SMC911X_CS;
+
+	l3ck = clk_get(NULL, "l3_ck");
+	if (IS_ERR(l3ck))
+		rate = 100000000;
+	else
+		rate = clk_get_rate(l3ck);
+
+	if (gpio_request(OMAP3EVM_ETHR_GPIO_IRQ, "SMC911x irq") < 0) {
+		printk(KERN_ERR "Failed to request GPIO%d for smc911x IRQ\n",
+			OMAP3EVM_ETHR_GPIO_IRQ);
+		return;
+	}
+
+	gpio_direction_input(OMAP3EVM_ETHR_GPIO_IRQ);
+}
+
+static struct omap_uart_config omap3_evm_uart_config __initdata = {
+	.enabled_uarts	= ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct twl4030_hsmmc_info mmc[] = {
+	{
+		.mmc		= 1,
+		.wires		= 4,
+		.gpio_cd	= -EINVAL,
+		.gpio_wp	= 63,
+	},
+	{}	/* Terminator */
+};
+
+static struct gpio_led gpio_leds[] = {
+	{
+		.name			= "omap3evm::ledb",
+		/* normally not visible (board underside) */
+		.default_trigger	= "default-on",
+		.gpio			= -EINVAL,	/* gets replaced */
+		.active_low		= true,
+	},
+};
+
+static struct gpio_led_platform_data gpio_led_info = {
+	.leds		= gpio_leds,
+	.num_leds	= ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device leds_gpio = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &gpio_led_info,
+	},
+};
+
+
+static int omap3evm_twl_gpio_setup(struct device *dev,
+		unsigned gpio, unsigned ngpio)
+{
+	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
+	omap_cfg_reg(L8_34XX_GPIO63);
+	mmc[0].gpio_cd = gpio + 0;
+	twl4030_mmc_init(mmc);
+
+	/*
+	 * Most GPIOs are for USB OTG.  Some are mostly sent to
+	 * the P2 connector; notably LEDA for the LCD backlight.
+	 */
+
+	/* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
+	gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
+
+	platform_device_register(&leds_gpio);
+
+	return 0;
+}
+
+static struct twl4030_gpio_platform_data omap3evm_gpio_data = {
+	.gpio_base	= OMAP_MAX_GPIO_LINES,
+	.irq_base	= TWL4030_GPIO_IRQ_BASE,
+	.irq_end	= TWL4030_GPIO_IRQ_END,
+	.use_leds	= true,
+	.setup		= omap3evm_twl_gpio_setup,
+};
+
+static struct twl4030_usb_data omap3evm_usb_data = {
+	.usb_mode	= T2_USB_MODE_ULPI,
+};
+
+static int omap3evm_keymap[] = {
+	KEY(0, 0, KEY_LEFT),
+	KEY(0, 1, KEY_RIGHT),
+	KEY(0, 2, KEY_A),
+	KEY(0, 3, KEY_B),
+	KEY(1, 0, KEY_DOWN),
+	KEY(1, 1, KEY_UP),
+	KEY(1, 2, KEY_E),
+	KEY(1, 3, KEY_F),
+	KEY(2, 0, KEY_ENTER),
+	KEY(2, 1, KEY_I),
+	KEY(2, 2, KEY_J),
+	KEY(2, 3, KEY_K),
+	KEY(3, 0, KEY_M),
+	KEY(3, 1, KEY_N),
+	KEY(3, 2, KEY_O),
+	KEY(3, 3, KEY_P)
+};
+
+static struct twl4030_keypad_data omap3evm_kp_data = {
+	.rows		= 4,
+	.cols		= 4,
+	.keymap		= omap3evm_keymap,
+	.keymapsize	= ARRAY_SIZE(omap3evm_keymap),
+	.rep		= 1,
+};
+
+static struct twl4030_madc_platform_data omap3evm_madc_data = {
+	.irq_line	= 1,
+};
+
+static struct twl4030_platform_data omap3evm_twldata = {
+	.irq_base	= TWL4030_IRQ_BASE,
+	.irq_end	= TWL4030_IRQ_END,
+
+	/* platform_data for children goes here */
+	.keypad		= &omap3evm_kp_data,
+	.madc		= &omap3evm_madc_data,
+	.usb		= &omap3evm_usb_data,
+	.gpio		= &omap3evm_gpio_data,
+};
+
+static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
+	{
+		I2C_BOARD_INFO("twl4030", 0x48),
+		.flags = I2C_CLIENT_WAKE,
+		.irq = INT_34XX_SYS_NIRQ,
+		.platform_data = &omap3evm_twldata,
+	},
+};
+
+static int __init omap3_evm_i2c_init(void)
+{
+	omap_register_i2c_bus(1, 2600, omap3evm_i2c_boardinfo,
+			ARRAY_SIZE(omap3evm_i2c_boardinfo));
+	omap_register_i2c_bus(2, 400, NULL, 0);
+	omap_register_i2c_bus(3, 400, NULL, 0);
+	return 0;
+}
+
+static struct platform_device omap3_evm_lcd_device = {
+	.name		= "omap3evm_lcd",
+	.id		= -1,
+};
+
+static struct omap_lcd_config omap3_evm_lcd_config __initdata = {
+	.ctrl_name	= "internal",
+};
+
+static void ads7846_dev_init(void)
+{
+	if (gpio_request(OMAP3_EVM_TS_GPIO, "ADS7846 pendown") < 0)
+		printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
+
+	gpio_direction_input(OMAP3_EVM_TS_GPIO);
+
+	omap_set_gpio_debounce(OMAP3_EVM_TS_GPIO, 1);
+	omap_set_gpio_debounce_time(OMAP3_EVM_TS_GPIO, 0xa);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+	return !gpio_get_value(OMAP3_EVM_TS_GPIO);
+}
+
+struct ads7846_platform_data ads7846_config = {
+	.x_max			= 0x0fff,
+	.y_max			= 0x0fff,
+	.x_plate_ohms		= 180,
+	.pressure_max		= 255,
+	.debounce_max		= 10,
+	.debounce_tol		= 3,
+	.debounce_rep		= 1,
+	.get_pendown_state	= ads7846_get_pendown_state,
+	.keep_vref_on		= 1,
+	.settle_delay_usecs	= 150,
+};
+
+static struct omap2_mcspi_device_config ads7846_mcspi_config = {
+	.turbo_mode	= 0,
+	.single_channel	= 1,	/* 0: slave, 1: master */
+};
+
+struct spi_board_info omap3evm_spi_board_info[] = {
+	[0] = {
+		.modalias		= "ads7846",
+		.bus_num		= 1,
+		.chip_select		= 0,
+		.max_speed_hz		= 1500000,
+		.controller_data	= &ads7846_mcspi_config,
+		.irq			= OMAP_GPIO_IRQ(OMAP3_EVM_TS_GPIO),
+		.platform_data		= &ads7846_config,
+	},
+};
+
+static void __init omap3_evm_init_irq(void)
+{
+	omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
+	omap_init_irq();
+	omap_gpio_init();
+	omap3evm_init_smc911x();
+}
+
+static struct omap_board_config_kernel omap3_evm_config[] __initdata = {
+	{ OMAP_TAG_UART,	&omap3_evm_uart_config },
+	{ OMAP_TAG_LCD,		&omap3_evm_lcd_config },
+};
+
+static struct platform_device *omap3_evm_devices[] __initdata = {
+	&omap3_evm_lcd_device,
+	&omap3evm_smc911x_device,
+};
+
+static void __init omap3_evm_init(void)
+{
+	omap3_evm_i2c_init();
+
+	platform_add_devices(omap3_evm_devices, ARRAY_SIZE(omap3_evm_devices));
+	omap_board_config = omap3_evm_config;
+	omap_board_config_size = ARRAY_SIZE(omap3_evm_config);
+
+	spi_register_board_info(omap3evm_spi_board_info,
+				ARRAY_SIZE(omap3evm_spi_board_info));
+
+	omap_serial_init();
+	usb_musb_init();
+	ads7846_dev_init();
+}
+
+static void __init omap3_evm_map_io(void)
+{
+	omap2_set_globals_343x();
+	omap2_map_common_io();
+}
+
+MACHINE_START(OMAP3EVM, "OMAP3 EVM")
+	/* Maintainer: Syed Mohammed Khasim - Texas Instruments */
+	.phys_io	= 0x48000000,
+	.io_pg_offst	= ((0xd8000000) >> 18) & 0xfffc,
+	.boot_params	= 0x80000100,
+	.map_io		= omap3_evm_map_io,
+	.init_irq	= omap3_evm_init_irq,
+	.init_machine	= omap3_evm_init,
+	.timer		= &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index 402f09c..e32aa23 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -23,7 +23,11 @@
 
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
+#include <linux/regulator/machine.h>
 #include <linux/i2c/twl4030.h>
+#include <linux/leds.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -35,11 +39,154 @@
 #include <mach/hardware.h>
 #include <mach/mcspi.h>
 #include <mach/usb.h>
+#include <mach/keypad.h>
 
+#include "sdram-micron-mt46h32m32lf-6.h"
 #include "mmc-twl4030.h"
 
 #define OMAP3_PANDORA_TS_GPIO		94
 
+/* hardware debounce: (value + 1) * 31us */
+#define GPIO_DEBOUNCE_TIME		127
+
+static struct gpio_led pandora_gpio_leds[] = {
+	{
+		.name			= "pandora::sd1",
+		.default_trigger	= "mmc0",
+		.gpio			= 128,
+	}, {
+		.name			= "pandora::sd2",
+		.default_trigger	= "mmc1",
+		.gpio			= 129,
+	}, {
+		.name			= "pandora::bluetooth",
+		.gpio			= 158,
+	}, {
+		.name			= "pandora::wifi",
+		.gpio			= 159,
+	},
+};
+
+static struct gpio_led_platform_data pandora_gpio_led_data = {
+	.leds		= pandora_gpio_leds,
+	.num_leds	= ARRAY_SIZE(pandora_gpio_leds),
+};
+
+static struct platform_device pandora_leds_gpio = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &pandora_gpio_led_data,
+	},
+};
+
+#define GPIO_BUTTON(gpio_num, ev_type, ev_code, act_low, descr)	\
+{								\
+	.gpio		= gpio_num,				\
+	.type		= ev_type,				\
+	.code		= ev_code,				\
+	.active_low	= act_low,				\
+	.desc		= "btn " descr,				\
+}
+
+#define GPIO_BUTTON_LOW(gpio_num, event_code, description)	\
+	GPIO_BUTTON(gpio_num, EV_KEY, event_code, 1, description)
+
+static struct gpio_keys_button pandora_gpio_keys[] = {
+	GPIO_BUTTON_LOW(110,	KEY_UP,		"up"),
+	GPIO_BUTTON_LOW(103,	KEY_DOWN,	"down"),
+	GPIO_BUTTON_LOW(96,	KEY_LEFT,	"left"),
+	GPIO_BUTTON_LOW(98,	KEY_RIGHT,	"right"),
+	GPIO_BUTTON_LOW(111,	BTN_A,		"a"),
+	GPIO_BUTTON_LOW(106,	BTN_B,		"b"),
+	GPIO_BUTTON_LOW(109,	BTN_X,		"x"),
+	GPIO_BUTTON_LOW(101,	BTN_Y,		"y"),
+	GPIO_BUTTON_LOW(102,	BTN_TL,		"l"),
+	GPIO_BUTTON_LOW(97,	BTN_TL2,	"l2"),
+	GPIO_BUTTON_LOW(105,	BTN_TR,		"r"),
+	GPIO_BUTTON_LOW(107,	BTN_TR2,	"r2"),
+	GPIO_BUTTON_LOW(104,	KEY_LEFTCTRL,	"ctrl"),
+	GPIO_BUTTON_LOW(99,	KEY_MENU,	"menu"),
+	GPIO_BUTTON_LOW(176,	KEY_COFFEE,	"hold"),
+	GPIO_BUTTON(100, EV_KEY, KEY_LEFTALT, 0, "alt"),
+	GPIO_BUTTON(108, EV_SW, SW_LID, 1, "lid"),
+};
+
+static struct gpio_keys_platform_data pandora_gpio_key_info = {
+	.buttons	= pandora_gpio_keys,
+	.nbuttons	= ARRAY_SIZE(pandora_gpio_keys),
+};
+
+static struct platform_device pandora_keys_gpio = {
+	.name	= "gpio-keys",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &pandora_gpio_key_info,
+	},
+};
+
+static void __init pandora_keys_gpio_init(void)
+{
+	/* set debounce time for GPIO banks 4 and 6 */
+	omap_set_gpio_debounce_time(32 * 3, GPIO_DEBOUNCE_TIME);
+	omap_set_gpio_debounce_time(32 * 5, GPIO_DEBOUNCE_TIME);
+}
+
+static int pandora_keypad_map[] = {
+	/* col, row, code */
+	KEY(0, 0, KEY_9),
+	KEY(0, 1, KEY_0),
+	KEY(0, 2, KEY_BACKSPACE),
+	KEY(0, 3, KEY_O),
+	KEY(0, 4, KEY_P),
+	KEY(0, 5, KEY_K),
+	KEY(0, 6, KEY_L),
+	KEY(0, 7, KEY_ENTER),
+	KEY(1, 0, KEY_8),
+	KEY(1, 1, KEY_7),
+	KEY(1, 2, KEY_6),
+	KEY(1, 3, KEY_5),
+	KEY(1, 4, KEY_4),
+	KEY(1, 5, KEY_3),
+	KEY(1, 6, KEY_2),
+	KEY(1, 7, KEY_1),
+	KEY(2, 0, KEY_I),
+	KEY(2, 1, KEY_U),
+	KEY(2, 2, KEY_Y),
+	KEY(2, 3, KEY_T),
+	KEY(2, 4, KEY_R),
+	KEY(2, 5, KEY_E),
+	KEY(2, 6, KEY_W),
+	KEY(2, 7, KEY_Q),
+	KEY(3, 0, KEY_J),
+	KEY(3, 1, KEY_H),
+	KEY(3, 2, KEY_G),
+	KEY(3, 3, KEY_F),
+	KEY(3, 4, KEY_D),
+	KEY(3, 5, KEY_S),
+	KEY(3, 6, KEY_A),
+	KEY(3, 7, KEY_LEFTSHIFT),
+	KEY(4, 0, KEY_N),
+	KEY(4, 1, KEY_B),
+	KEY(4, 2, KEY_V),
+	KEY(4, 3, KEY_C),
+	KEY(4, 4, KEY_X),
+	KEY(4, 5, KEY_Z),
+	KEY(4, 6, KEY_DOT),
+	KEY(4, 7, KEY_COMMA),
+	KEY(5, 0, KEY_M),
+	KEY(5, 1, KEY_SPACE),
+	KEY(5, 2, KEY_FN),
+};
+
+static struct twl4030_keypad_data pandora_kp_data = {
+	.rows		= 8,
+	.cols		= 6,
+	.keymap		= pandora_keypad_map,
+	.keymapsize	= ARRAY_SIZE(pandora_keypad_map),
+	.rep		= 1,
+};
+
 static struct twl4030_hsmmc_info omap3pandora_mmc[] = {
 	{
 		.mmc		= 1,
@@ -69,6 +216,14 @@
 	.enabled_uarts	= (1 << 2), /* UART3 */
 };
 
+static struct regulator_consumer_supply pandora_vmmc1_supply = {
+	.supply			= "vmmc",
+};
+
+static struct regulator_consumer_supply pandora_vmmc2_supply = {
+	.supply			= "vmmc",
+};
+
 static int omap3pandora_twl_gpio_setup(struct device *dev,
 		unsigned gpio, unsigned ngpio)
 {
@@ -77,6 +232,10 @@
 	omap3pandora_mmc[1].gpio_cd = gpio + 1;
 	twl4030_mmc_init(omap3pandora_mmc);
 
+	/* link regulators to MMC adapters */
+	pandora_vmmc1_supply.dev = omap3pandora_mmc[0].dev;
+	pandora_vmmc2_supply.dev = omap3pandora_mmc[1].dev;
+
 	return 0;
 }
 
@@ -87,6 +246,36 @@
 	.setup		= omap3pandora_twl_gpio_setup,
 };
 
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data pandora_vmmc1 = {
+	.constraints = {
+		.min_uV			= 1850000,
+		.max_uV			= 3150000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE
+					| REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &pandora_vmmc1_supply,
+};
+
+/* VMMC2 for MMC2 pins CMD, CLK, DAT0..DAT3 (max 100 mA) */
+static struct regulator_init_data pandora_vmmc2 = {
+	.constraints = {
+		.min_uV			= 1850000,
+		.max_uV			= 3150000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE
+					| REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &pandora_vmmc2_supply,
+};
+
 static struct twl4030_usb_data omap3pandora_usb_data = {
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
@@ -96,6 +285,9 @@
 	.irq_end	= TWL4030_IRQ_END,
 	.gpio		= &omap3pandora_gpio_data,
 	.usb		= &omap3pandora_usb_data,
+	.vmmc1		= &pandora_vmmc1,
+	.vmmc2		= &pandora_vmmc2,
+	.keypad		= &pandora_kp_data,
 };
 
 static struct i2c_board_info __initdata omap3pandora_i2c_boardinfo[] = {
@@ -118,7 +310,7 @@
 
 static void __init omap3pandora_init_irq(void)
 {
-	omap2_init_common_hw(NULL);
+	omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
 	omap_init_irq();
 	omap_gpio_init();
 }
@@ -188,6 +380,8 @@
 
 static struct platform_device *omap3pandora_devices[] __initdata = {
 	&omap3pandora_lcd_device,
+	&pandora_leds_gpio,
+	&pandora_keys_gpio,
 };
 
 static void __init omap3pandora_init(void)
@@ -201,6 +395,7 @@
 	spi_register_board_info(omap3pandora_spi_board_info,
 			ARRAY_SIZE(omap3pandora_spi_board_info));
 	omap3pandora_ads7846_init();
+	pandora_keys_gpio_init();
 	usb_musb_init();
 }
 
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index b1f23be..dff5528 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/i2c/twl4030.h>
+#include <linux/regulator/machine.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -45,6 +46,7 @@
 #include <mach/nand.h>
 #include <mach/usb.h>
 
+#include "sdram-micron-mt46h32m32lf-6.h"
 #include "mmc-twl4030.h"
 
 #define OVERO_GPIO_BT_XGATE	15
@@ -271,21 +273,76 @@
 	.enabled_uarts	= ((1 << 0) | (1 << 1) | (1 << 2)),
 };
 
+static struct twl4030_hsmmc_info mmc[] = {
+	{
+		.mmc		= 1,
+		.wires		= 4,
+		.gpio_cd	= -EINVAL,
+		.gpio_wp	= -EINVAL,
+	},
+	{
+		.mmc		= 2,
+		.wires		= 4,
+		.gpio_cd	= -EINVAL,
+		.gpio_wp	= -EINVAL,
+		.transceiver	= true,
+		.ocr_mask	= 0x00100000,	/* 3.3V */
+	},
+	{}	/* Terminator */
+};
+
+static struct regulator_consumer_supply overo_vmmc1_supply = {
+	.supply			= "vmmc",
+};
+
+static int overo_twl_gpio_setup(struct device *dev,
+		unsigned gpio, unsigned ngpio)
+{
+	twl4030_mmc_init(mmc);
+
+	overo_vmmc1_supply.dev = mmc[0].dev;
+
+	return 0;
+}
+
 static struct twl4030_gpio_platform_data overo_gpio_data = {
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
 	.irq_end	= TWL4030_GPIO_IRQ_END,
+	.setup		= overo_twl_gpio_setup,
 };
 
+static struct twl4030_usb_data overo_usb_data = {
+	.usb_mode	= T2_USB_MODE_ULPI,
+};
+
+static struct regulator_init_data overo_vmmc1 = {
+	.constraints = {
+		.min_uV			= 1850000,
+		.max_uV			= 3150000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE
+					| REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &overo_vmmc1_supply,
+};
+
+/* mmc2 (WLAN) and Bluetooth don't use twl4030 regulators */
+
 static struct twl4030_platform_data overo_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 	.gpio		= &overo_gpio_data,
+	.usb		= &overo_usb_data,
+	.vmmc1		= &overo_vmmc1,
 };
 
 static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
 	{
-		I2C_BOARD_INFO("twl4030", 0x48),
+		I2C_BOARD_INFO("tps65950", 0x48),
 		.flags = I2C_CLIENT_WAKE,
 		.irq = INT_34XX_SYS_NIRQ,
 		.platform_data = &overo_twldata,
@@ -303,7 +360,7 @@
 
 static void __init overo_init_irq(void)
 {
-	omap2_init_common_hw(NULL);
+	omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
 	omap_init_irq();
 	omap_gpio_init();
 }
@@ -326,23 +383,6 @@
 	&overo_lcd_device,
 };
 
-static struct twl4030_hsmmc_info mmc[] __initdata = {
-	{
-		.mmc		= 1,
-		.wires		= 4,
-		.gpio_cd	= -EINVAL,
-		.gpio_wp	= -EINVAL,
-	},
-	{
-		.mmc		= 2,
-		.wires		= 4,
-		.gpio_cd	= -EINVAL,
-		.gpio_wp	= -EINVAL,
-		.transceiver	= true,
-	},
-	{}	/* Terminator */
-};
-
 static void __init overo_init(void)
 {
 	overo_i2c_init();
@@ -350,7 +390,6 @@
 	omap_board_config = overo_config;
 	omap_board_config_size = ARRAY_SIZE(overo_config);
 	omap_serial_init();
-	twl4030_mmc_init(mmc);
 	overo_flash_init();
 	usb_musb_init();
 	overo_ads7846_init();
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index a738172..da93b86 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -27,30 +27,13 @@
 #include <mach/dma.h>
 #include <mach/gpmc.h>
 #include <mach/keypad.h>
+#include <mach/onenand.h>
+#include <mach/gpmc-smc91x.h>
 
 #include "mmc-twl4030.h"
 
-
-#define SMC91X_CS			1
-#define SMC91X_GPIO_IRQ			54
-#define SMC91X_GPIO_RESET		164
-#define SMC91X_GPIO_PWRDWN		86
-
-static struct resource rx51_smc91x_resources[] = {
-	[0] = {
-		.flags		= IORESOURCE_MEM,
-	},
-	[1] = {
-		.flags		= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
-	},
-};
-
-static struct platform_device rx51_smc91x_device = {
-	.name		= "smc91x",
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(rx51_smc91x_resources),
-	.resource	= rx51_smc91x_resources,
-};
+#define SYSTEM_REV_B_USES_VAUX3	0x1699
+#define SYSTEM_REV_S_USES_VAUX3 0x8
 
 static int rx51_keymap[] = {
 	KEY(0, 0, KEY_Q),
@@ -107,98 +90,6 @@
 	.rep		= 1,
 };
 
-static struct platform_device *rx51_peripherals_devices[] = {
-	&rx51_smc91x_device,
-};
-
-/*
- * Timings are taken from smsc-lan91c96-ms.pdf
- */
-static int smc91x_init_gpmc(int cs)
-{
-	struct gpmc_timings t;
-	const int t2_r = 45;		/* t2 in Figure 12.10 */
-	const int t2_w = 30;		/* t2 in Figure 12.11 */
-	const int t3 = 15;		/* t3 in Figure 12.10 */
-	const int t5_r = 0;		/* t5 in Figure 12.10 */
-	const int t6_r = 45;		/* t6 in Figure 12.10 */
-	const int t6_w = 0;		/* t6 in Figure 12.11 */
-	const int t7_w = 15;		/* t7 in Figure 12.11 */
-	const int t15 = 12;		/* t15 in Figure 12.2 */
-	const int t20 = 185;		/* t20 in Figure 12.2 */
-
-	memset(&t, 0, sizeof(t));
-
-	t.cs_on = t15;
-	t.cs_rd_off = t3 + t2_r + t5_r;	/* Figure 12.10 */
-	t.cs_wr_off = t3 + t2_w + t6_w;	/* Figure 12.11 */
-	t.adv_on = t3;			/* Figure 12.10 */
-	t.adv_rd_off = t3 + t2_r;	/* Figure 12.10 */
-	t.adv_wr_off = t3 + t2_w;	/* Figure 12.11 */
-	t.oe_off = t3 + t2_r + t5_r;	/* Figure 12.10 */
-	t.oe_on = t.oe_off - t6_r;	/* Figure 12.10 */
-	t.we_off = t3 + t2_w + t6_w;	/* Figure 12.11 */
-	t.we_on = t.we_off - t7_w;	/* Figure 12.11 */
-	t.rd_cycle = t20;		/* Figure 12.2 */
-	t.wr_cycle = t20;		/* Figure 12.4 */
-	t.access = t3 + t2_r + t5_r;	/* Figure 12.10 */
-	t.wr_access = t3 + t2_w + t6_w;	/* Figure 12.11 */
-
-	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, GPMC_CONFIG1_DEVICESIZE_16);
-
-	return gpmc_cs_set_timings(cs, &t);
-}
-
-static void __init rx51_init_smc91x(void)
-{
-	unsigned long cs_mem_base;
-	int ret;
-
-	omap_cfg_reg(U8_34XX_GPIO54_DOWN);
-	omap_cfg_reg(G25_34XX_GPIO86_OUT);
-	omap_cfg_reg(H19_34XX_GPIO164_OUT);
-
-	if (gpmc_cs_request(SMC91X_CS, SZ_16M, &cs_mem_base) < 0) {
-		printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
-		return;
-	}
-
-	rx51_smc91x_resources[0].start = cs_mem_base + 0x300;
-	rx51_smc91x_resources[0].end = cs_mem_base + 0x30f;
-
-	smc91x_init_gpmc(SMC91X_CS);
-
-	if (gpio_request(SMC91X_GPIO_IRQ, "SMC91X irq") < 0)
-		goto free1;
-
-	gpio_direction_input(SMC91X_GPIO_IRQ);
-	rx51_smc91x_resources[1].start = gpio_to_irq(SMC91X_GPIO_IRQ);
-
-	ret = gpio_request(SMC91X_GPIO_PWRDWN, "SMC91X powerdown");
-	if (ret)
-		goto free2;
-	gpio_direction_output(SMC91X_GPIO_PWRDWN, 0);
-
-	ret = gpio_request(SMC91X_GPIO_RESET, "SMC91X reset");
-	if (ret)
-		goto free3;
-	gpio_direction_output(SMC91X_GPIO_RESET, 0);
-	gpio_set_value(SMC91X_GPIO_RESET, 1);
-	msleep(100);
-	gpio_set_value(SMC91X_GPIO_RESET, 0);
-
-	return;
-
-free3:
-	gpio_free(SMC91X_GPIO_PWRDWN);
-free2:
-	gpio_free(SMC91X_GPIO_IRQ);
-free1:
-	gpmc_cs_free(SMC91X_CS);
-
-	printk(KERN_ERR "Could not initialize smc91x\n");
-}
-
 static struct twl4030_madc_platform_data rx51_madc_data = {
 	.irq_line		= 1,
 };
@@ -259,7 +150,7 @@
 };
 
 /* VAUX3 - adds more power to VIO_18 rail */
-static struct regulator_init_data rx51_vaux3 = {
+static struct regulator_init_data rx51_vaux3_cam = {
 	.constraints = {
 		.name			= "VCAM_DIG_18",
 		.min_uV			= 1800000,
@@ -272,6 +163,22 @@
 	},
 };
 
+static struct regulator_init_data rx51_vaux3_mmc = {
+	.constraints = {
+		.name			= "VMMC2_30",
+		.min_uV			= 2800000,
+		.max_uV			= 3000000,
+		.apply_uV		= true,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE
+					| REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &rx51_vmmc2_supply,
+};
+
 static struct regulator_init_data rx51_vaux4 = {
 	.constraints = {
 		.name			= "VCAM_ANA_28",
@@ -382,10 +289,8 @@
 
 	.vaux1			= &rx51_vaux1,
 	.vaux2			= &rx51_vaux2,
-	.vaux3			= &rx51_vaux3,
 	.vaux4			= &rx51_vaux4,
 	.vmmc1			= &rx51_vmmc1,
-	.vmmc2			= &rx51_vmmc2,
 	.vsim			= &rx51_vsim,
 	.vdac			= &rx51_vdac,
 };
@@ -401,6 +306,13 @@
 
 static int __init rx51_i2c_init(void)
 {
+	if ((system_rev >= SYSTEM_REV_S_USES_VAUX3 && system_rev < 0x100) ||
+	    system_rev >= SYSTEM_REV_B_USES_VAUX3)
+		rx51_twldata.vaux3 = &rx51_vaux3_mmc;
+	else {
+		rx51_twldata.vaux3 = &rx51_vaux3_cam;
+		rx51_twldata.vmmc2 = &rx51_vmmc2;
+	}
 	omap_register_i2c_bus(1, 2600, rx51_peripherals_i2c_board_info_1,
 			ARRAY_SIZE(rx51_peripherals_i2c_board_info_1));
 	omap_register_i2c_bus(2, 100, NULL, 0);
@@ -408,12 +320,94 @@
 	return 0;
 }
 
+#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
+	defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
+
+static struct mtd_partition onenand_partitions[] = {
+	{
+		.name           = "bootloader",
+		.offset         = 0,
+		.size           = 0x20000,
+		.mask_flags     = MTD_WRITEABLE,	/* Force read-only */
+	},
+	{
+		.name           = "config",
+		.offset         = MTDPART_OFS_APPEND,
+		.size           = 0x60000,
+	},
+	{
+		.name           = "log",
+		.offset         = MTDPART_OFS_APPEND,
+		.size           = 0x40000,
+	},
+	{
+		.name           = "kernel",
+		.offset         = MTDPART_OFS_APPEND,
+		.size           = 0x200000,
+	},
+	{
+		.name           = "initfs",
+		.offset         = MTDPART_OFS_APPEND,
+		.size           = 0x200000,
+	},
+	{
+		.name           = "rootfs",
+		.offset         = MTDPART_OFS_APPEND,
+		.size           = MTDPART_SIZ_FULL,
+	},
+};
+
+static struct omap_onenand_platform_data board_onenand_data = {
+	.cs		= 0,
+	.gpio_irq	= 65,
+	.parts		= onenand_partitions,
+	.nr_parts	= ARRAY_SIZE(onenand_partitions),
+};
+
+static void __init board_onenand_init(void)
+{
+	gpmc_onenand_init(&board_onenand_data);
+}
+
+#else
+
+static inline void board_onenand_init(void)
+{
+}
+
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+
+static struct omap_smc91x_platform_data board_smc91x_data = {
+	.cs		= 1,
+	.gpio_irq	= 54,
+	.gpio_pwrdwn	= 86,
+	.gpio_reset	= 164,
+	.flags		= GPMC_TIMINGS_SMC91C96 | IORESOURCE_IRQ_HIGHLEVEL,
+};
+
+static void __init board_smc91x_init(void)
+{
+	omap_cfg_reg(U8_34XX_GPIO54_DOWN);
+	omap_cfg_reg(G25_34XX_GPIO86_OUT);
+	omap_cfg_reg(H19_34XX_GPIO164_OUT);
+
+	gpmc_smc91x_init(&board_smc91x_data);
+}
+
+#else
+
+static inline void board_smc91x_init(void)
+{
+}
+
+#endif
 
 void __init rx51_peripherals_init(void)
 {
-	platform_add_devices(rx51_peripherals_devices,
-				ARRAY_SIZE(rx51_peripherals_devices));
 	rx51_i2c_init();
-	rx51_init_smc91x();
+	board_onenand_init();
+	board_smc91x_init();
 }
 
diff --git a/arch/arm/mach-omap2/board-zoom-debugboard.c b/arch/arm/mach-omap2/board-zoom-debugboard.c
new file mode 100644
index 0000000..bac5c43
--- /dev/null
+++ b/arch/arm/mach-omap2/board-zoom-debugboard.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2009 Texas Instruments Inc.
+ * Mikkel Christensen <mlc@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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/serial_8250.h>
+#include <linux/smsc911x.h>
+
+#include <mach/gpmc.h>
+
+#define ZOOM2_SMSC911X_CS	7
+#define ZOOM2_SMSC911X_GPIO	158
+#define ZOOM2_QUADUART_CS	3
+#define ZOOM2_QUADUART_GPIO	102
+#define QUART_CLK		1843200
+#define DEBUG_BASE		0x08000000
+#define ZOOM2_ETHR_START	DEBUG_BASE
+
+static struct resource zoom2_smsc911x_resources[] = {
+	[0] = {
+		.start	= ZOOM2_ETHR_START,
+		.end	= ZOOM2_ETHR_START + SZ_4K,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+	},
+};
+
+static struct smsc911x_platform_config zoom2_smsc911x_config = {
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type	= SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+	.flags		= SMSC911X_USE_32BIT,
+	.phy_interface	= PHY_INTERFACE_MODE_MII,
+};
+
+static struct platform_device zoom2_smsc911x_device = {
+	.name		= "smsc911x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(zoom2_smsc911x_resources),
+	.resource	= zoom2_smsc911x_resources,
+	.dev		= {
+		.platform_data = &zoom2_smsc911x_config,
+	},
+};
+
+static inline void __init zoom2_init_smsc911x(void)
+{
+	int eth_cs;
+	unsigned long cs_mem_base;
+	int eth_gpio = 0;
+
+	eth_cs = ZOOM2_SMSC911X_CS;
+
+	if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
+		printk(KERN_ERR "Failed to request GPMC mem for smsc911x\n");
+		return;
+	}
+
+	zoom2_smsc911x_resources[0].start = cs_mem_base + 0x0;
+	zoom2_smsc911x_resources[0].end   = cs_mem_base + 0xff;
+
+	eth_gpio = ZOOM2_SMSC911X_GPIO;
+
+	zoom2_smsc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
+
+	if (gpio_request(eth_gpio, "smsc911x irq") < 0) {
+		printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
+				eth_gpio);
+		return;
+	}
+	gpio_direction_input(eth_gpio);
+}
+
+static struct plat_serial8250_port serial_platform_data[] = {
+	{
+		.mapbase	= 0x10000000,
+		.irq		= OMAP_GPIO_IRQ(102),
+		.flags		= UPF_BOOT_AUTOCONF|UPF_IOREMAP|UPF_SHARE_IRQ,
+		.iotype		= UPIO_MEM,
+		.regshift	= 1,
+		.uartclk	= QUART_CLK,
+	}, {
+		.flags		= 0
+	}
+};
+
+static struct platform_device zoom2_debugboard_serial_device = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM1,
+	.dev			= {
+		.platform_data	= serial_platform_data,
+	},
+};
+
+static inline void __init zoom2_init_quaduart(void)
+{
+	int quart_cs;
+	unsigned long cs_mem_base;
+	int quart_gpio = 0;
+
+	quart_cs = ZOOM2_QUADUART_CS;
+
+	if (gpmc_cs_request(quart_cs, SZ_1M, &cs_mem_base) < 0) {
+		printk(KERN_ERR "Failed to request GPMC mem"
+				"for Quad UART(TL16CP754C)\n");
+		return;
+	}
+
+	quart_gpio = ZOOM2_QUADUART_GPIO;
+
+	if (gpio_request(quart_gpio, "TL16CP754C GPIO") < 0) {
+		printk(KERN_ERR "Failed to request GPIO%d for TL16CP754C\n",
+								quart_gpio);
+		return;
+	}
+	gpio_direction_input(quart_gpio);
+}
+
+static inline int omap_zoom2_debugboard_detect(void)
+{
+	int debug_board_detect = 0;
+
+	debug_board_detect = ZOOM2_SMSC911X_GPIO;
+
+	if (gpio_request(debug_board_detect, "Zoom2 debug board detect") < 0) {
+		printk(KERN_ERR "Failed to request GPIO%d for Zoom2 debug"
+		"board detect\n", debug_board_detect);
+		return 0;
+	}
+	gpio_direction_input(debug_board_detect);
+
+	if (!gpio_get_value(debug_board_detect)) {
+		gpio_free(debug_board_detect);
+		return 0;
+	}
+	return 1;
+}
+
+static struct platform_device *zoom2_devices[] __initdata = {
+	&zoom2_smsc911x_device,
+	&zoom2_debugboard_serial_device,
+};
+
+int __init omap_zoom2_debugboard_init(void)
+{
+	if (!omap_zoom2_debugboard_detect())
+		return 0;
+
+	zoom2_init_smsc911x();
+	zoom2_init_quaduart();
+	return platform_add_devices(zoom2_devices, ARRAY_SIZE(zoom2_devices));
+}
diff --git a/arch/arm/mach-omap2/board-zoom2.c b/arch/arm/mach-omap2/board-zoom2.c
new file mode 100644
index 0000000..bcc0f76
--- /dev/null
+++ b/arch/arm/mach-omap2/board-zoom2.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2009 Texas Instruments Inc.
+ * Mikkel Christensen <mlc@ti.com>
+ *
+ * Modified from mach-omap2/board-ldp.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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/i2c/twl4030.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/common.h>
+#include <mach/usb.h>
+
+#include "mmc-twl4030.h"
+
+static void __init omap_zoom2_init_irq(void)
+{
+	omap2_init_common_hw(NULL);
+	omap_init_irq();
+	omap_gpio_init();
+}
+
+static struct omap_uart_config zoom2_uart_config __initdata = {
+	.enabled_uarts	= ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_board_config_kernel zoom2_config[] __initdata = {
+	{ OMAP_TAG_UART,	&zoom2_uart_config },
+};
+
+static struct twl4030_gpio_platform_data zoom2_gpio_data = {
+	.gpio_base	= OMAP_MAX_GPIO_LINES,
+	.irq_base	= TWL4030_GPIO_IRQ_BASE,
+	.irq_end	= TWL4030_GPIO_IRQ_END,
+};
+
+static struct twl4030_platform_data zoom2_twldata = {
+	.irq_base	= TWL4030_IRQ_BASE,
+	.irq_end	= TWL4030_IRQ_END,
+
+	/* platform_data for children goes here */
+	.gpio		= &zoom2_gpio_data,
+};
+
+static struct i2c_board_info __initdata zoom2_i2c_boardinfo[] = {
+	{
+		I2C_BOARD_INFO("twl4030", 0x48),
+		.flags		= I2C_CLIENT_WAKE,
+		.irq		= INT_34XX_SYS_NIRQ,
+		.platform_data	= &zoom2_twldata,
+	},
+};
+
+static int __init omap_i2c_init(void)
+{
+	omap_register_i2c_bus(1, 2600, zoom2_i2c_boardinfo,
+			ARRAY_SIZE(zoom2_i2c_boardinfo));
+	omap_register_i2c_bus(2, 400, NULL, 0);
+	omap_register_i2c_bus(3, 400, NULL, 0);
+	return 0;
+}
+
+static struct twl4030_hsmmc_info mmc[] __initdata = {
+	{
+		.mmc		= 1,
+		.wires		= 4,
+		.gpio_cd	= -EINVAL,
+		.gpio_wp	= -EINVAL,
+	},
+	{}	/* Terminator */
+};
+
+extern int __init omap_zoom2_debugboard_init(void);
+
+static void __init omap_zoom2_init(void)
+{
+	omap_i2c_init();
+	omap_board_config = zoom2_config;
+	omap_board_config_size = ARRAY_SIZE(zoom2_config);
+	omap_serial_init();
+	omap_zoom2_debugboard_init();
+	twl4030_mmc_init(mmc);
+	usb_musb_init();
+}
+
+static void __init omap_zoom2_map_io(void)
+{
+	omap2_set_globals_343x();
+	omap2_map_common_io();
+}
+
+MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board")
+	.phys_io	= 0x48000000,
+	.io_pg_offst	= ((0xd8000000) >> 18) & 0xfffc,
+	.boot_params	= 0x80000100,
+	.map_io		= omap_zoom2_map_io,
+	.init_irq	= omap_zoom2_init_irq,
+	.init_machine	= omap_zoom2_init,
+	.timer		= &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 4247a15..ba528f8 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -91,9 +91,9 @@
 		return;
 
 	prm_write_mod_reg(OMAP24XX_VALID_CONFIG, OMAP24XX_GR_MOD,
-		OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET);
+		OMAP2_PRCM_CLKCFG_CTRL_OFFSET);
 	/* OCP barrier */
-	prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET);
+	prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP2_PRCM_CLKCFG_CTRL_OFFSET);
 }
 
 /*
@@ -547,8 +547,8 @@
 	const struct clksel_rate *clkr;
 	u32 last_div = 0;
 
-	printk(KERN_INFO "clock: clksel_round_rate_div: %s target_rate %ld\n",
-	       clk->name, target_rate);
+	pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n",
+		 clk->name, target_rate);
 
 	*new_div = 1;
 
@@ -562,7 +562,7 @@
 
 		/* Sanity check */
 		if (clkr->div <= last_div)
-			printk(KERN_ERR "clock: clksel_rate table not sorted "
+			pr_err("clock: clksel_rate table not sorted "
 			       "for clock %s", clk->name);
 
 		last_div = clkr->div;
@@ -574,7 +574,7 @@
 	}
 
 	if (!clkr->div) {
-		printk(KERN_ERR "clock: Could not find divisor for target "
+		pr_err("clock: Could not find divisor for target "
 		       "rate %ld for clock %s parent %s\n", target_rate,
 		       clk->name, clk->parent->name);
 		return ~0;
@@ -582,8 +582,8 @@
 
 	*new_div = clkr->div;
 
-	printk(KERN_INFO "clock: new_div = %d, new_rate = %ld\n", *new_div,
-	       (clk->parent->rate / clkr->div));
+	pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div,
+		 (clk->parent->rate / clkr->div));
 
 	return (clk->parent->rate / clkr->div);
 }
@@ -1035,7 +1035,7 @@
 	if ((regval32 & (1 << clk->enable_bit)) == v)
 		return;
 
-	printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name);
+	printk(KERN_DEBUG "Disabling unused clock \"%s\"\n", clk->name);
 	if (cpu_is_omap34xx()) {
 		omap2_clk_enable(clk);
 		omap2_clk_disable(clk);
diff --git a/arch/arm/mach-omap2/clock24xx.c b/arch/arm/mach-omap2/clock24xx.c
index e4cef33..44de027 100644
--- a/arch/arm/mach-omap2/clock24xx.c
+++ b/arch/arm/mach-omap2/clock24xx.c
@@ -233,6 +233,8 @@
 static struct clk *vclk;
 static struct clk *sclk;
 
+static void __iomem *prcm_clksrc_ctrl;
+
 /*-------------------------------------------------------------------------
  * Omap24xx specific clock functions
  *-------------------------------------------------------------------------*/
@@ -269,10 +271,9 @@
 {
 	u32 pcc;
 
-	pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
+	pcc = __raw_readl(prcm_clksrc_ctrl);
 
-	__raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK,
-		      OMAP24XX_PRCM_CLKSRC_CTRL);
+	__raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK, prcm_clksrc_ctrl);
 
 	return 0;
 }
@@ -281,10 +282,9 @@
 {
 	u32 pcc;
 
-	pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
+	pcc = __raw_readl(prcm_clksrc_ctrl);
 
-	__raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK,
-		      OMAP24XX_PRCM_CLKSRC_CTRL);
+	__raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK, prcm_clksrc_ctrl);
 }
 
 static const struct clkops clkops_oscck = {
@@ -654,7 +654,7 @@
 {
 	u32 div;
 
-	div = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
+	div = __raw_readl(prcm_clksrc_ctrl);
 	div &= OMAP_SYSCLKDIV_MASK;
 	div >>= OMAP_SYSCLKDIV_SHIFT;
 
@@ -714,15 +714,18 @@
 	struct omap_clk *c;
 	u32 clkrate;
 
-	if (cpu_is_omap242x())
+	if (cpu_is_omap242x()) {
+		prcm_clksrc_ctrl = OMAP2420_PRCM_CLKSRC_CTRL;
 		cpu_mask = RATE_IN_242X;
-	else if (cpu_is_omap2430())
+	} else if (cpu_is_omap2430()) {
+		prcm_clksrc_ctrl = OMAP2430_PRCM_CLKSRC_CTRL;
 		cpu_mask = RATE_IN_243X;
+	}
 
 	clk_init(&omap2_clk_functions);
 
 	for (c = omap24xx_clks; c < omap24xx_clks + ARRAY_SIZE(omap24xx_clks); c++)
-		clk_init_one(c->lk.clk);
+		clk_preinit(c->lk.clk);
 
 	osc_ck.rate = omap2_osc_clk_recalc(&osc_ck);
 	propagate_rate(&osc_ck);
diff --git a/arch/arm/mach-omap2/clock24xx.h b/arch/arm/mach-omap2/clock24xx.h
index 88c5acb..458f00c 100644
--- a/arch/arm/mach-omap2/clock24xx.h
+++ b/arch/arm/mach-omap2/clock24xx.h
@@ -24,6 +24,17 @@
 #include "cm-regbits-24xx.h"
 #include "sdrc.h"
 
+/* REVISIT: These should be set dynamically for CONFIG_MULTI_OMAP2 */
+#ifdef CONFIG_ARCH_OMAP2420
+#define OMAP_CM_REGADDR			OMAP2420_CM_REGADDR
+#define OMAP24XX_PRCM_CLKOUT_CTRL	OMAP2420_PRCM_CLKOUT_CTRL
+#define OMAP24XX_PRCM_CLKEMUL_CTRL	OMAP2420_PRCM_CLKEMUL_CTRL
+#else
+#define OMAP_CM_REGADDR			OMAP2430_CM_REGADDR
+#define OMAP24XX_PRCM_CLKOUT_CTRL	OMAP2430_PRCM_CLKOUT_CTRL
+#define OMAP24XX_PRCM_CLKEMUL_CTRL	OMAP2430_PRCM_CLKEMUL_CTRL
+#endif
+
 static unsigned long omap2_table_mpu_recalc(struct clk *clk);
 static int omap2_select_table_rate(struct clk *clk, unsigned long rate);
 static long omap2_round_to_table_rate(struct clk *clk, unsigned long rate);
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
index ba05aa4..9e43fe5 100644
--- a/arch/arm/mach-omap2/clock34xx.c
+++ b/arch/arm/mach-omap2/clock34xx.c
@@ -129,6 +129,9 @@
 	CLK(NULL,	"sgx_fck",	&sgx_fck,	CK_3430ES2),
 	CLK(NULL,	"sgx_ick",	&sgx_ick,	CK_3430ES2),
 	CLK(NULL,	"d2d_26m_fck",	&d2d_26m_fck,	CK_3430ES1),
+	CLK(NULL,	"modem_fck",	&modem_fck,	CK_343X),
+	CLK(NULL,	"sad2d_ick",	&sad2d_ick,	CK_343X),
+	CLK(NULL,	"mad2d_ick",	&mad2d_ick,	CK_343X),
 	CLK(NULL,	"gpt10_fck",	&gpt10_fck,	CK_343X),
 	CLK(NULL,	"gpt11_fck",	&gpt11_fck,	CK_343X),
 	CLK(NULL,	"cpefuse_fck",	&cpefuse_fck,	CK_3430ES2),
@@ -281,6 +284,8 @@
 
 #define MAX_DPLL_WAIT_TRIES		1000000
 
+#define MIN_SDRC_DLL_LOCK_FREQ		83000000
+
 /**
  * omap3_dpll_recalc - recalculate DPLL rate
  * @clk: DPLL struct clk
@@ -703,6 +708,7 @@
 static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate)
 {
 	u32 new_div = 0;
+	u32 unlock_dll = 0;
 	unsigned long validrate, sdrcrate;
 	struct omap_sdrc_params *sp;
 
@@ -729,17 +735,22 @@
 	if (!sp)
 		return -EINVAL;
 
-	pr_info("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate,
-		validrate);
-	pr_info("clock: SDRC timing params used: %08x %08x %08x\n",
-		sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb);
+	if (sdrcrate < MIN_SDRC_DLL_LOCK_FREQ) {
+		pr_debug("clock: will unlock SDRC DLL\n");
+		unlock_dll = 1;
+	}
+
+	pr_debug("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate,
+		 validrate);
+	pr_debug("clock: SDRC timing params used: %08x %08x %08x\n",
+		 sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb);
 
 	/* REVISIT: SRAM code doesn't support other M2 divisors yet */
 	WARN_ON(new_div != 1 && new_div != 2);
 
 	/* REVISIT: Add SDRC_MR changing to this code also */
 	omap3_configure_core_dpll(sp->rfr_ctrl, sp->actim_ctrla,
-				  sp->actim_ctrlb, new_div);
+				  sp->actim_ctrlb, new_div, unlock_dll);
 
 	return 0;
 }
@@ -956,7 +967,7 @@
 	clk_init(&omap2_clk_functions);
 
 	for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++)
-		clk_init_one(c->lk.clk);
+		clk_preinit(c->lk.clk);
 
 	for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++)
 		if (c->cpu & cpu_clkflg) {
diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h
index 017a30e..e433aec 100644
--- a/arch/arm/mach-omap2/clock34xx.h
+++ b/arch/arm/mach-omap2/clock34xx.h
@@ -27,6 +27,8 @@
 #include "prm.h"
 #include "prm-regbits-34xx.h"
 
+#define OMAP_CM_REGADDR		OMAP34XX_CM_REGADDR
+
 static unsigned long omap3_dpll_recalc(struct clk *clk);
 static unsigned long omap3_clkoutx2_recalc(struct clk *clk);
 static void omap3_dpll_allow_idle(struct clk *clk);
@@ -1228,6 +1230,37 @@
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk modem_fck = {
+	.name		= "modem_fck",
+	.ops		= &clkops_omap2_dflt_wait,
+	.parent		= &sys_ck,
+	.init		= &omap2_init_clk_clkdm,
+	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+	.enable_bit	= OMAP3430_EN_MODEM_SHIFT,
+	.clkdm_name	= "d2d_clkdm",
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk sad2d_ick = {
+	.name		= "sad2d_ick",
+	.ops		= &clkops_omap2_dflt_wait,
+	.parent		= &l3_ick,
+	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+	.enable_bit	= OMAP3430_EN_SAD2D_SHIFT,
+	.clkdm_name	= "d2d_clkdm",
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk mad2d_ick = {
+	.name		= "mad2d_ick",
+	.ops		= &clkops_omap2_dflt_wait,
+	.parent		= &l3_ick,
+	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
+	.enable_bit	= OMAP3430_EN_MAD2D_SHIFT,
+	.clkdm_name	= "d2d_clkdm",
+	.recalc		= &followparent_recalc,
+};
+
 static const struct clksel omap343x_gpt_clksel[] = {
 	{ .parent = &omap_32k_fck, .rates = gpt_32k_rates },
 	{ .parent = &sys_ck,	   .rates = gpt_sys_rates },
@@ -1945,8 +1978,6 @@
 	.recalc		= &omap2_clksel_recalc,
 };
 
-/* XXX MDM_INTC_ICK, SAD2D_ICK ?? */
-
 /* SECURITY_L4_ICK2 based clocks */
 
 static struct clk security_l4_ick2 = {
diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h
index 281d5da..fe319ae 100644
--- a/arch/arm/mach-omap2/clockdomains.h
+++ b/arch/arm/mach-omap2/clockdomains.h
@@ -195,7 +195,7 @@
 static struct clockdomain d2d_clkdm = {
 	.name		= "d2d_clkdm",
 	.pwrdm		= { .name = "core_pwrdm" },
-	.flags		= CLKDM_CAN_HWSUP,
+	.flags		= CLKDM_CAN_HWSUP_SWSUP,
 	.clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_D2D_MASK,
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 };
diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index 6f3f5a3..6923deb 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -145,6 +145,8 @@
 #define OMAP3430_CLKACTIVITY_MPU_MASK			(1 << 0)
 
 /* CM_FCLKEN1_CORE specific bits */
+#define OMAP3430_EN_MODEM				(1 << 31)
+#define OMAP3430_EN_MODEM_SHIFT				31
 
 /* CM_ICLKEN1_CORE specific bits */
 #define OMAP3430_EN_ICR					(1 << 29)
@@ -161,6 +163,8 @@
 #define OMAP3430_EN_MAILBOXES_SHIFT			7
 #define OMAP3430_EN_OMAPCTRL				(1 << 6)
 #define OMAP3430_EN_OMAPCTRL_SHIFT			6
+#define OMAP3430_EN_SAD2D				(1 << 3)
+#define OMAP3430_EN_SAD2D_SHIFT				3
 #define OMAP3430_EN_SDRC				(1 << 1)
 #define OMAP3430_EN_SDRC_SHIFT				1
 
@@ -176,6 +180,10 @@
 #define OMAP3430_EN_DES1				(1 << 0)
 #define OMAP3430_EN_DES1_SHIFT				0
 
+/* CM_ICLKEN3_CORE */
+#define OMAP3430_EN_MAD2D_SHIFT				3
+#define OMAP3430_EN_MAD2D				(1 << 3)
+
 /* CM_FCLKEN3_CORE specific bits */
 #define OMAP3430ES2_EN_TS_SHIFT				1
 #define OMAP3430ES2_EN_TS_MASK				(1 << 1)
@@ -231,6 +239,8 @@
 #define OMAP3430ES2_ST_CPEFUSE_MASK			(1 << 0)
 
 /* CM_AUTOIDLE1_CORE */
+#define OMAP3430_AUTO_MODEM				(1 << 31)
+#define OMAP3430_AUTO_MODEM_SHIFT			31
 #define OMAP3430ES2_AUTO_MMC3				(1 << 30)
 #define OMAP3430ES2_AUTO_MMC3_SHIFT			30
 #define OMAP3430ES2_AUTO_ICR				(1 << 29)
@@ -287,6 +297,8 @@
 #define OMAP3430_AUTO_HSOTGUSB_SHIFT			4
 #define OMAP3430ES1_AUTO_D2D				(1 << 3)
 #define OMAP3430ES1_AUTO_D2D_SHIFT			3
+#define OMAP3430_AUTO_SAD2D				(1 << 3)
+#define OMAP3430_AUTO_SAD2D_SHIFT			3
 #define OMAP3430_AUTO_SSI				(1 << 0)
 #define OMAP3430_AUTO_SSI_SHIFT				0
 
@@ -308,6 +320,8 @@
 #define	OMAP3430ES2_AUTO_USBTLL				(1 << 2)
 #define OMAP3430ES2_AUTO_USBTLL_SHIFT			2
 #define OMAP3430ES2_AUTO_USBTLL_MASK			(1 << 2)
+#define OMAP3430_AUTO_MAD2D_SHIFT			3
+#define OMAP3430_AUTO_MAD2D				(1 << 3)
 
 /* CM_CLKSEL_CORE */
 #define OMAP3430_CLKSEL_SSI_SHIFT			8
diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h
index 65fdf78..1d3c93b 100644
--- a/arch/arm/mach-omap2/cm.h
+++ b/arch/arm/mach-omap2/cm.h
@@ -16,17 +16,12 @@
 
 #include "prcm-common.h"
 
-#ifndef __ASSEMBLER__
-#define OMAP_CM_REGADDR(module, reg)					\
-			IO_ADDRESS(OMAP2_CM_BASE + (module) + (reg))
-#else
 #define OMAP2420_CM_REGADDR(module, reg)				\
 			IO_ADDRESS(OMAP2420_CM_BASE + (module) + (reg))
 #define OMAP2430_CM_REGADDR(module, reg)				\
 			IO_ADDRESS(OMAP2430_CM_BASE + (module) + (reg))
 #define OMAP34XX_CM_REGADDR(module, reg)				\
 			IO_ADDRESS(OMAP3430_CM_BASE + (module) + (reg))
-#endif
 
 /*
  * Architecture-specific global CM registers
@@ -38,6 +33,7 @@
 #define OMAP3430_CM_SYSCONFIG		OMAP_CM_REGADDR(OCP_MOD, 0x0010)
 #define OMAP3430_CM_POLCTRL		OMAP_CM_REGADDR(OCP_MOD, 0x009c)
 
+#define OMAP3_CM_CLKOUT_CTRL_OFFSET	0x0070
 #define OMAP3430_CM_CLKOUT_CTRL		OMAP_CM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
 
 /*
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
new file mode 100644
index 0000000..2fd22f9
--- /dev/null
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -0,0 +1,330 @@
+/*
+ * linux/arch/arm/mach-omap2/gpmc-onenand.c
+ *
+ * Copyright (C) 2006 - 2009 Nokia Corporation
+ * Contacts:	Juha Yrjola
+ *		Tony Lindgren
+ *
+ * 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/platform_device.h>
+#include <linux/mtd/onenand_regs.h>
+#include <linux/io.h>
+
+#include <asm/mach/flash.h>
+
+#include <mach/onenand.h>
+#include <mach/board.h>
+#include <mach/gpmc.h>
+
+static struct omap_onenand_platform_data *gpmc_onenand_data;
+
+static struct platform_device gpmc_onenand_device = {
+	.name		= "omap2-onenand",
+	.id		= -1,
+};
+
+static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
+{
+	struct gpmc_timings t;
+
+	const int t_cer = 15;
+	const int t_avdp = 12;
+	const int t_aavdh = 7;
+	const int t_ce = 76;
+	const int t_aa = 76;
+	const int t_oe = 20;
+	const int t_cez = 20; /* max of t_cez, t_oez */
+	const int t_ds = 30;
+	const int t_wpl = 40;
+	const int t_wph = 30;
+
+	memset(&t, 0, sizeof(t));
+	t.sync_clk = 0;
+	t.cs_on = 0;
+	t.adv_on = 0;
+
+	/* Read */
+	t.adv_rd_off = gpmc_round_ns_to_ticks(max_t(int, t_avdp, t_cer));
+	t.oe_on  = t.adv_rd_off + gpmc_round_ns_to_ticks(t_aavdh);
+	t.access = t.adv_on + gpmc_round_ns_to_ticks(t_aa);
+	t.access = max_t(int, t.access, t.cs_on + gpmc_round_ns_to_ticks(t_ce));
+	t.access = max_t(int, t.access, t.oe_on + gpmc_round_ns_to_ticks(t_oe));
+	t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
+	t.cs_rd_off = t.oe_off;
+	t.rd_cycle  = t.cs_rd_off + gpmc_round_ns_to_ticks(t_cez);
+
+	/* Write */
+	t.adv_wr_off = t.adv_rd_off;
+	t.we_on  = t.oe_on;
+	if (cpu_is_omap34xx()) {
+		t.wr_data_mux_bus = t.we_on;
+		t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
+	}
+	t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
+	t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
+	t.wr_cycle  = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
+
+	/* Configure GPMC for asynchronous read */
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
+			  GPMC_CONFIG1_DEVICESIZE_16 |
+			  GPMC_CONFIG1_MUXADDDATA);
+
+	return gpmc_cs_set_timings(cs, &t);
+}
+
+static void set_onenand_cfg(void __iomem *onenand_base, int latency,
+				int sync_read, int sync_write, int hf)
+{
+	u32 reg;
+
+	reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
+	reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
+	reg |=	(latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
+		ONENAND_SYS_CFG1_BL_16;
+	if (sync_read)
+		reg |= ONENAND_SYS_CFG1_SYNC_READ;
+	else
+		reg &= ~ONENAND_SYS_CFG1_SYNC_READ;
+	if (sync_write)
+		reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
+	else
+		reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
+	if (hf)
+		reg |= ONENAND_SYS_CFG1_HF;
+	else
+		reg &= ~ONENAND_SYS_CFG1_HF;
+	writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
+}
+
+static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
+					void __iomem *onenand_base,
+					int freq)
+{
+	struct gpmc_timings t;
+	const int t_cer  = 15;
+	const int t_avdp = 12;
+	const int t_cez  = 20; /* max of t_cez, t_oez */
+	const int t_ds   = 30;
+	const int t_wpl  = 40;
+	const int t_wph  = 30;
+	int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
+	int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
+	int first_time = 0, hf = 0, sync_read = 0, sync_write = 0;
+	int err, ticks_cez;
+	int cs = cfg->cs;
+	u32 reg;
+
+	if (cfg->flags & ONENAND_SYNC_READ) {
+		sync_read = 1;
+	} else if (cfg->flags & ONENAND_SYNC_READWRITE) {
+		sync_read = 1;
+		sync_write = 1;
+	}
+
+	if (!freq) {
+		/* Very first call freq is not known */
+		err = omap2_onenand_set_async_mode(cs, onenand_base);
+		if (err)
+			return err;
+		reg = readw(onenand_base + ONENAND_REG_VERSION_ID);
+		switch ((reg >> 4) & 0xf) {
+		case 0:
+			freq = 40;
+			break;
+		case 1:
+			freq = 54;
+			break;
+		case 2:
+			freq = 66;
+			break;
+		case 3:
+			freq = 83;
+			break;
+		case 4:
+			freq = 104;
+			break;
+		default:
+			freq = 54;
+			break;
+		}
+		first_time = 1;
+	}
+
+	switch (freq) {
+	case 83:
+		min_gpmc_clk_period = 12; /* 83 MHz */
+		t_ces   = 5;
+		t_avds  = 4;
+		t_avdh  = 2;
+		t_ach   = 6;
+		t_aavdh = 6;
+		t_rdyo  = 9;
+		break;
+	case 66:
+		min_gpmc_clk_period = 15; /* 66 MHz */
+		t_ces   = 6;
+		t_avds  = 5;
+		t_avdh  = 2;
+		t_ach   = 6;
+		t_aavdh = 6;
+		t_rdyo  = 11;
+		break;
+	default:
+		min_gpmc_clk_period = 18; /* 54 MHz */
+		t_ces   = 7;
+		t_avds  = 7;
+		t_avdh  = 7;
+		t_ach   = 9;
+		t_aavdh = 7;
+		t_rdyo  = 15;
+		sync_write = 0;
+		break;
+	}
+
+	tick_ns = gpmc_ticks_to_ns(1);
+	div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period);
+	gpmc_clk_ns = gpmc_ticks_to_ns(div);
+	if (gpmc_clk_ns < 15) /* >66Mhz */
+		hf = 1;
+	if (hf)
+		latency = 6;
+	else if (gpmc_clk_ns >= 25) /* 40 MHz*/
+		latency = 3;
+	else
+		latency = 4;
+
+	if (first_time)
+		set_onenand_cfg(onenand_base, latency,
+					sync_read, sync_write, hf);
+
+	if (div == 1) {
+		reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
+		reg |= (1 << 7);
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
+		reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
+		reg |= (1 << 7);
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
+		reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
+		reg |= (1 << 7);
+		reg |= (1 << 23);
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
+	} else {
+		reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
+		reg &= ~(1 << 7);
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
+		reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
+		reg &= ~(1 << 7);
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
+		reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
+		reg &= ~(1 << 7);
+		reg &= ~(1 << 23);
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
+	}
+
+	/* Set synchronous read timings */
+	memset(&t, 0, sizeof(t));
+	t.sync_clk = min_gpmc_clk_period;
+	t.cs_on = 0;
+	t.adv_on = 0;
+	fclk_offset_ns = gpmc_round_ns_to_ticks(max_t(int, t_ces, t_avds));
+	fclk_offset = gpmc_ns_to_ticks(fclk_offset_ns);
+	t.page_burst_access = gpmc_clk_ns;
+
+	/* Read */
+	t.adv_rd_off = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_avdh));
+	t.oe_on = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_ach));
+	t.access = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div);
+	t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
+	t.cs_rd_off = t.oe_off;
+	ticks_cez = ((gpmc_ns_to_ticks(t_cez) + div - 1) / div) * div;
+	t.rd_cycle = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div +
+		     ticks_cez);
+
+	/* Write */
+	if (sync_write) {
+		t.adv_wr_off = t.adv_rd_off;
+		t.we_on  = 0;
+		t.we_off = t.cs_rd_off;
+		t.cs_wr_off = t.cs_rd_off;
+		t.wr_cycle  = t.rd_cycle;
+		if (cpu_is_omap34xx()) {
+			t.wr_data_mux_bus = gpmc_ticks_to_ns(fclk_offset +
+					gpmc_ns_to_ticks(min_gpmc_clk_period +
+					t_rdyo));
+			t.wr_access = t.access;
+		}
+	} else {
+		t.adv_wr_off = gpmc_round_ns_to_ticks(max_t(int,
+							t_avdp, t_cer));
+		t.we_on  = t.adv_wr_off + gpmc_round_ns_to_ticks(t_aavdh);
+		t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
+		t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
+		t.wr_cycle  = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
+		if (cpu_is_omap34xx()) {
+			t.wr_data_mux_bus = t.we_on;
+			t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
+		}
+	}
+
+	/* Configure GPMC for synchronous read */
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
+			  GPMC_CONFIG1_WRAPBURST_SUPP |
+			  GPMC_CONFIG1_READMULTIPLE_SUPP |
+			  (sync_read ? GPMC_CONFIG1_READTYPE_SYNC : 0) |
+			  (sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) |
+			  (sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) |
+			  GPMC_CONFIG1_CLKACTIVATIONTIME(fclk_offset) |
+			  GPMC_CONFIG1_PAGE_LEN(2) |
+			  (cpu_is_omap34xx() ? 0 :
+				(GPMC_CONFIG1_WAIT_READ_MON |
+				 GPMC_CONFIG1_WAIT_PIN_SEL(0))) |
+			  GPMC_CONFIG1_DEVICESIZE_16 |
+			  GPMC_CONFIG1_DEVICETYPE_NOR |
+			  GPMC_CONFIG1_MUXADDDATA);
+
+	err = gpmc_cs_set_timings(cs, &t);
+	if (err)
+		return err;
+
+	set_onenand_cfg(onenand_base, latency, sync_read, sync_write, hf);
+
+	return 0;
+}
+
+static int gpmc_onenand_setup(void __iomem *onenand_base, int freq)
+{
+	struct device *dev = &gpmc_onenand_device.dev;
+
+	/* Set sync timings in GPMC */
+	if (omap2_onenand_set_sync_mode(gpmc_onenand_data, onenand_base,
+			freq) < 0) {
+		dev_err(dev, "Unable to set synchronous mode\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
+{
+	gpmc_onenand_data = _onenand_data;
+	gpmc_onenand_data->onenand_setup = gpmc_onenand_setup;
+	gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;
+
+	if (cpu_is_omap24xx() &&
+			(gpmc_onenand_data->flags & ONENAND_SYNC_READWRITE)) {
+		printk(KERN_ERR "Onenand using only SYNC_READ on 24xx\n");
+		gpmc_onenand_data->flags &= ~ONENAND_SYNC_READWRITE;
+		gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
+	}
+
+	if (platform_device_register(&gpmc_onenand_device) < 0) {
+		printk(KERN_ERR "Unable to register OneNAND device\n");
+		return;
+	}
+}
diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c
new file mode 100644
index 0000000..df99d31
--- /dev/null
+++ b/arch/arm/mach-omap2/gpmc-smc91x.c
@@ -0,0 +1,189 @@
+/*
+ * linux/arch/arm/mach-omap2/gpmc-smc91x.c
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Contact:	Tony Lindgren
+ *
+ * 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/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/smc91x.h>
+
+#include <mach/board.h>
+#include <mach/gpmc.h>
+#include <mach/gpmc-smc91x.h>
+
+static struct omap_smc91x_platform_data *gpmc_cfg;
+
+static struct resource gpmc_smc91x_resources[] = {
+	[0] = {
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct smc91x_platdata gpmc_smc91x_info = {
+	.flags  = SMC91X_USE_16BIT | SMC91X_NOWAIT | SMC91X_IO_SHIFT_0,
+};
+
+static struct platform_device gpmc_smc91x_device = {
+	.name		= "smc91x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(gpmc_smc91x_resources),
+	.resource	= gpmc_smc91x_resources,
+	.dev		= {
+		.platform_data = &gpmc_smc91x_info,
+	},
+};
+
+/*
+ * Set the gpmc timings for smc91c96. The timings are taken
+ * from the data sheet available at:
+ * http://www.smsc.com/main/catalog/lan91c96.html
+ * REVISIT: Level shifters can add at least to the access latency.
+ */
+static int smc91c96_gpmc_retime(void)
+{
+	struct gpmc_timings t;
+	const int t3 = 10;	/* Figure 12.2 read and 12.4 write */
+	const int t4_r = 20;	/* Figure 12.2 read */
+	const int t4_w = 5;	/* Figure 12.4 write */
+	const int t5 = 25;	/* Figure 12.2 read */
+	const int t6 = 15;	/* Figure 12.2 read */
+	const int t7 = 5;	/* Figure 12.4 write */
+	const int t8 = 5;	/* Figure 12.4 write */
+	const int t20 = 185;	/* Figure 12.2 read and 12.4 write */
+	u32 l;
+
+	memset(&t, 0, sizeof(t));
+
+	/* Read timings */
+	t.cs_on = 0;
+	t.adv_on = t.cs_on;
+	t.oe_on = t.adv_on + t3;
+	t.access = t.oe_on + t5;
+	t.oe_off = t.access;
+	t.adv_rd_off = t.oe_off + max(t4_r, t6);
+	t.cs_rd_off = t.oe_off;
+	t.rd_cycle = t20 - t.oe_on;
+
+	/* Write timings */
+	t.we_on = t.adv_on + t3;
+
+	if (cpu_is_omap34xx() && (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)) {
+		t.wr_data_mux_bus = t.we_on;
+		t.we_off = t.wr_data_mux_bus + t7;
+	} else
+		t.we_off = t.we_on + t7;
+	if (cpu_is_omap34xx())
+		t.wr_access = t.we_off;
+	t.adv_wr_off = t.we_off + max(t4_w, t8);
+	t.cs_wr_off = t.we_off + t4_w;
+	t.wr_cycle = t20 - t.we_on;
+
+	l = GPMC_CONFIG1_DEVICESIZE_16;
+	if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
+		l |= GPMC_CONFIG1_MUXADDDATA;
+	if (gpmc_cfg->flags & GPMC_READ_MON)
+		l |= GPMC_CONFIG1_WAIT_READ_MON;
+	if (gpmc_cfg->flags & GPMC_WRITE_MON)
+		l |= GPMC_CONFIG1_WAIT_WRITE_MON;
+	if (gpmc_cfg->wait_pin)
+		l |= GPMC_CONFIG1_WAIT_PIN_SEL(gpmc_cfg->wait_pin);
+	gpmc_cs_write_reg(gpmc_cfg->cs, GPMC_CS_CONFIG1, l);
+
+	/*
+	 * FIXME: Calculate the address and data bus muxed timings.
+	 * Note that at least adv_rd_off needs to be changed according
+	 * to omap3430 TRM Figure 11-11. Are the sdp boards using the
+	 * FPGA in between smc91x and omap as the timings are different
+	 * from above?
+	 */
+	if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
+		return 0;
+
+	return gpmc_cs_set_timings(gpmc_cfg->cs, &t);
+}
+
+/*
+ * Initialize smc91x device connected to the GPMC. Note that we
+ * assume that pin multiplexing is done in the board-*.c file,
+ * or in the bootloader.
+ */
+void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
+{
+	unsigned long cs_mem_base;
+	int ret;
+
+	gpmc_cfg = board_data;
+
+	if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96)
+		gpmc_cfg->retime = smc91c96_gpmc_retime;
+
+	if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
+		printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
+		return;
+	}
+
+	gpmc_smc91x_resources[0].start = cs_mem_base + 0x300;
+	gpmc_smc91x_resources[0].end = cs_mem_base + 0x30f;
+	gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
+
+	if (gpmc_cfg->retime) {
+		ret = gpmc_cfg->retime();
+		if (ret != 0)
+			goto free1;
+	}
+
+	if (gpio_request(gpmc_cfg->gpio_irq, "SMC91X irq") < 0)
+		goto free1;
+
+	gpio_direction_input(gpmc_cfg->gpio_irq);
+	gpmc_smc91x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
+
+	if (gpmc_cfg->gpio_pwrdwn) {
+		ret = gpio_request(gpmc_cfg->gpio_pwrdwn, "SMC91X powerdown");
+		if (ret)
+			goto free2;
+		gpio_direction_output(gpmc_cfg->gpio_pwrdwn, 0);
+	}
+
+	if (gpmc_cfg->gpio_reset) {
+		ret = gpio_request(gpmc_cfg->gpio_reset, "SMC91X reset");
+		if (ret)
+			goto free3;
+
+		gpio_direction_output(gpmc_cfg->gpio_reset, 0);
+		gpio_set_value(gpmc_cfg->gpio_reset, 1);
+		msleep(100);
+		gpio_set_value(gpmc_cfg->gpio_reset, 0);
+	}
+
+	if (platform_device_register(&gpmc_smc91x_device) < 0) {
+		printk(KERN_ERR "Unable to register smc91x device\n");
+		gpio_free(gpmc_cfg->gpio_reset);
+		goto free3;
+	}
+
+	return;
+
+free3:
+	if (gpmc_cfg->gpio_pwrdwn)
+		gpio_free(gpmc_cfg->gpio_pwrdwn);
+free2:
+	gpio_free(gpmc_cfg->gpio_irq);
+free1:
+	gpmc_cs_free(gpmc_cfg->cs);
+
+	printk(KERN_ERR "Could not initialize smc91x\n");
+}
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 2249049..f91934b 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -5,6 +5,9 @@
  *
  * Author: Juha Yrjola
  *
+ * 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 version 2 as
  * published by the Free Software Foundation.
@@ -424,6 +427,9 @@
 	} else if (cpu_is_omap34xx()) {
 		ck = "gpmc_fck";
 		l = OMAP34XX_GPMC_BASE;
+	} else if (cpu_is_omap44xx()) {
+		ck = "gpmc_fck";
+		l = OMAP44XX_GPMC_BASE;
 	}
 
 	gpmc_l3_clk = clk_get(NULL, ck);
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 34b5914..458990e 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -6,6 +6,9 @@
  * Copyright (C) 2005 Nokia Corporation
  * Written by Tony Lindgren <tony@atomide.com>
  *
+ * 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 version 2 as
  * published by the Free Software Foundation.
@@ -200,7 +203,10 @@
 		omap24xx_check_revision();
 	else if (cpu_is_omap34xx())
 		omap34xx_check_revision();
-	else
+	else if (cpu_is_omap44xx()) {
+		printk(KERN_INFO "FIXME: CPU revision = OMAP4430\n");
+		return;
+	} else
 		pr_err("OMAP revision unknown, please fix!\n");
 
 	/*
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 916fcd3..32afd94 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -4,12 +4,14 @@
  * OMAP2 I/O mapping code
  *
  * Copyright (C) 2005 Nokia Corporation
- * Copyright (C) 2007 Texas Instruments
+ * Copyright (C) 2007-2009 Texas Instruments
  *
  * Author:
  *	Juha Yrjola <juha.yrjola@nokia.com>
  *	Syed Khasim <x0khasim@ti.com>
  *
+ * 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 version 2 as
  * published by the Free Software Foundation.
@@ -30,6 +32,7 @@
 #include <mach/sdrc.h>
 #include <mach/gpmc.h>
 
+#ifndef CONFIG_ARCH_OMAP4	/* FIXME: Remove this once clkdev is ready */
 #include "clock.h"
 
 #include <mach/powerdomain.h>
@@ -38,7 +41,7 @@
 
 #include <mach/clockdomain.h>
 #include "clockdomains.h"
-
+#endif
 /*
  * The machine specific code may provide the extra mapping besides the
  * default mapping provided here.
@@ -166,6 +169,46 @@
 	},
 };
 #endif
+#ifdef	CONFIG_ARCH_OMAP4
+static struct map_desc omap44xx_io_desc[] __initdata = {
+	{
+		.virtual	= L3_44XX_VIRT,
+		.pfn		= __phys_to_pfn(L3_44XX_PHYS),
+		.length		= L3_44XX_SIZE,
+		.type		= MT_DEVICE,
+	},
+	{
+		.virtual	= L4_44XX_VIRT,
+		.pfn		= __phys_to_pfn(L4_44XX_PHYS),
+		.length		= L4_44XX_SIZE,
+		.type		= MT_DEVICE,
+	},
+	{
+		.virtual	= L4_WK_44XX_VIRT,
+		.pfn		= __phys_to_pfn(L4_WK_44XX_PHYS),
+		.length		= L4_WK_44XX_SIZE,
+		.type		= MT_DEVICE,
+	},
+	{
+		.virtual	= OMAP44XX_GPMC_VIRT,
+		.pfn		= __phys_to_pfn(OMAP44XX_GPMC_PHYS),
+		.length		= OMAP44XX_GPMC_SIZE,
+		.type		= MT_DEVICE,
+	},
+	{
+		.virtual	= L4_PER_44XX_VIRT,
+		.pfn		= __phys_to_pfn(L4_PER_44XX_PHYS),
+		.length		= L4_PER_44XX_SIZE,
+		.type		= MT_DEVICE,
+	},
+	{
+		.virtual	= L4_EMU_44XX_VIRT,
+		.pfn		= __phys_to_pfn(L4_EMU_44XX_PHYS),
+		.length		= L4_EMU_44XX_SIZE,
+		.type		= MT_DEVICE,
+	},
+};
+#endif
 
 void __init omap2_map_common_io(void)
 {
@@ -183,6 +226,9 @@
 	iotable_init(omap34xx_io_desc, ARRAY_SIZE(omap34xx_io_desc));
 #endif
 
+#if defined(CONFIG_ARCH_OMAP4)
+	iotable_init(omap44xx_io_desc, ARRAY_SIZE(omap44xx_io_desc));
+#endif
 	/* Normally devicemaps_init() would flush caches and tlb after
 	 * mdesc->map_io(), but we must also do it here because of the CPU
 	 * revision check below.
@@ -198,9 +244,11 @@
 void __init omap2_init_common_hw(struct omap_sdrc_params *sp)
 {
 	omap2_mux_init();
+#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once the clkdev is ready */
 	pwrdm_init(powerdomains_omap);
 	clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps);
 	omap2_clk_init();
 	omap2_sdrc_init(sp);
+#endif
 	gpmc_init();
 }
diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c
new file mode 100644
index 0000000..015f22a
--- /dev/null
+++ b/arch/arm/mach-omap2/iommu2.c
@@ -0,0 +1,323 @@
+/*
+ * omap iommu: omap2/3 architecture specific functions
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>,
+ *		Paul Mundt and Toshihiro Kobayashi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/stringify.h>
+
+#include <mach/iommu.h>
+
+/*
+ * omap2 architecture specific register bit definitions
+ */
+#define IOMMU_ARCH_VERSION	0x00000011
+
+/* SYSCONF */
+#define MMU_SYS_IDLE_SHIFT	3
+#define MMU_SYS_IDLE_FORCE	(0 << MMU_SYS_IDLE_SHIFT)
+#define MMU_SYS_IDLE_NONE	(1 << MMU_SYS_IDLE_SHIFT)
+#define MMU_SYS_IDLE_SMART	(2 << MMU_SYS_IDLE_SHIFT)
+#define MMU_SYS_IDLE_MASK	(3 << MMU_SYS_IDLE_SHIFT)
+
+#define MMU_SYS_SOFTRESET	(1 << 1)
+#define MMU_SYS_AUTOIDLE	1
+
+/* SYSSTATUS */
+#define MMU_SYS_RESETDONE	1
+
+/* IRQSTATUS & IRQENABLE */
+#define MMU_IRQ_MULTIHITFAULT	(1 << 4)
+#define MMU_IRQ_TABLEWALKFAULT	(1 << 3)
+#define MMU_IRQ_EMUMISS		(1 << 2)
+#define MMU_IRQ_TRANSLATIONFAULT	(1 << 1)
+#define MMU_IRQ_TLBMISS		(1 << 0)
+#define MMU_IRQ_MASK	\
+	(MMU_IRQ_MULTIHITFAULT | MMU_IRQ_TABLEWALKFAULT | MMU_IRQ_EMUMISS | \
+	 MMU_IRQ_TRANSLATIONFAULT)
+
+/* MMU_CNTL */
+#define MMU_CNTL_SHIFT		1
+#define MMU_CNTL_MASK		(7 << MMU_CNTL_SHIFT)
+#define MMU_CNTL_EML_TLB	(1 << 3)
+#define MMU_CNTL_TWL_EN		(1 << 2)
+#define MMU_CNTL_MMU_EN		(1 << 1)
+
+#define get_cam_va_mask(pgsz)				\
+	(((pgsz) == MMU_CAM_PGSZ_16M) ? 0xff000000 :	\
+	 ((pgsz) == MMU_CAM_PGSZ_1M)  ? 0xfff00000 :	\
+	 ((pgsz) == MMU_CAM_PGSZ_64K) ? 0xffff0000 :	\
+	 ((pgsz) == MMU_CAM_PGSZ_4K)  ? 0xfffff000 : 0)
+
+static int omap2_iommu_enable(struct iommu *obj)
+{
+	u32 l, pa;
+	unsigned long timeout;
+
+	if (!obj->iopgd || !IS_ALIGNED((u32)obj->iopgd,  SZ_16K))
+		return -EINVAL;
+
+	pa = virt_to_phys(obj->iopgd);
+	if (!IS_ALIGNED(pa, SZ_16K))
+		return -EINVAL;
+
+	iommu_write_reg(obj, MMU_SYS_SOFTRESET, MMU_SYSCONFIG);
+
+	timeout = jiffies + msecs_to_jiffies(20);
+	do {
+		l = iommu_read_reg(obj, MMU_SYSSTATUS);
+		if (l & MMU_SYS_RESETDONE)
+			break;
+	} while (time_after(jiffies, timeout));
+
+	if (!(l & MMU_SYS_RESETDONE)) {
+		dev_err(obj->dev, "can't take mmu out of reset\n");
+		return -ENODEV;
+	}
+
+	l = iommu_read_reg(obj, MMU_REVISION);
+	dev_info(obj->dev, "%s: version %d.%d\n", obj->name,
+		 (l >> 4) & 0xf, l & 0xf);
+
+	l = iommu_read_reg(obj, MMU_SYSCONFIG);
+	l &= ~MMU_SYS_IDLE_MASK;
+	l |= (MMU_SYS_IDLE_SMART | MMU_SYS_AUTOIDLE);
+	iommu_write_reg(obj, l, MMU_SYSCONFIG);
+
+	iommu_write_reg(obj, MMU_IRQ_MASK, MMU_IRQENABLE);
+	iommu_write_reg(obj, pa, MMU_TTB);
+
+	l = iommu_read_reg(obj, MMU_CNTL);
+	l &= ~MMU_CNTL_MASK;
+	l |= (MMU_CNTL_MMU_EN | MMU_CNTL_TWL_EN);
+	iommu_write_reg(obj, l, MMU_CNTL);
+
+	return 0;
+}
+
+static void omap2_iommu_disable(struct iommu *obj)
+{
+	u32 l = iommu_read_reg(obj, MMU_CNTL);
+
+	l &= ~MMU_CNTL_MASK;
+	iommu_write_reg(obj, l, MMU_CNTL);
+	iommu_write_reg(obj, MMU_SYS_IDLE_FORCE, MMU_SYSCONFIG);
+
+	dev_dbg(obj->dev, "%s is shutting down\n", obj->name);
+}
+
+static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra)
+{
+	int i;
+	u32 stat, da;
+	const char *err_msg[] =	{
+		"tlb miss",
+		"translation fault",
+		"emulation miss",
+		"table walk fault",
+		"multi hit fault",
+	};
+
+	stat = iommu_read_reg(obj, MMU_IRQSTATUS);
+	stat &= MMU_IRQ_MASK;
+	if (!stat)
+		return 0;
+
+	da = iommu_read_reg(obj, MMU_FAULT_AD);
+	*ra = da;
+
+	dev_err(obj->dev, "%s:\tda:%08x ", __func__, da);
+
+	for (i = 0; i < ARRAY_SIZE(err_msg); i++) {
+		if (stat & (1 << i))
+			printk("%s ", err_msg[i]);
+	}
+	printk("\n");
+
+	iommu_write_reg(obj, stat, MMU_IRQSTATUS);
+	return stat;
+}
+
+static void omap2_tlb_read_cr(struct iommu *obj, struct cr_regs *cr)
+{
+	cr->cam = iommu_read_reg(obj, MMU_READ_CAM);
+	cr->ram = iommu_read_reg(obj, MMU_READ_RAM);
+}
+
+static void omap2_tlb_load_cr(struct iommu *obj, struct cr_regs *cr)
+{
+	iommu_write_reg(obj, cr->cam | MMU_CAM_V, MMU_CAM);
+	iommu_write_reg(obj, cr->ram, MMU_RAM);
+}
+
+static u32 omap2_cr_to_virt(struct cr_regs *cr)
+{
+	u32 page_size = cr->cam & MMU_CAM_PGSZ_MASK;
+	u32 mask = get_cam_va_mask(cr->cam & page_size);
+
+	return cr->cam & mask;
+}
+
+static struct cr_regs *omap2_alloc_cr(struct iommu *obj, struct iotlb_entry *e)
+{
+	struct cr_regs *cr;
+
+	if (e->da & ~(get_cam_va_mask(e->pgsz))) {
+		dev_err(obj->dev, "%s:\twrong alignment: %08x\n", __func__,
+			e->da);
+		return ERR_PTR(-EINVAL);
+	}
+
+	cr = kmalloc(sizeof(*cr), GFP_KERNEL);
+	if (!cr)
+		return ERR_PTR(-ENOMEM);
+
+	cr->cam = (e->da & MMU_CAM_VATAG_MASK) | e->prsvd | e->pgsz;
+	cr->ram = e->pa | e->endian | e->elsz | e->mixed;
+
+	return cr;
+}
+
+static inline int omap2_cr_valid(struct cr_regs *cr)
+{
+	return cr->cam & MMU_CAM_V;
+}
+
+static u32 omap2_get_pte_attr(struct iotlb_entry *e)
+{
+	u32 attr;
+
+	attr = e->mixed << 5;
+	attr |= e->endian;
+	attr |= e->elsz >> 3;
+	attr <<= ((e->pgsz & MMU_CAM_PGSZ_4K) ? 0 : 6);
+
+	return attr;
+}
+
+static ssize_t omap2_dump_cr(struct iommu *obj, struct cr_regs *cr, char *buf)
+{
+	char *p = buf;
+
+	/* FIXME: Need more detail analysis of cam/ram */
+	p += sprintf(p, "%08x %08x\n", cr->cam, cr->ram);
+
+	return p - buf;
+}
+
+#define pr_reg(name)							\
+	p += sprintf(p, "%20s: %08x\n",					\
+		     __stringify(name), iommu_read_reg(obj, MMU_##name));
+
+static ssize_t omap2_iommu_dump_ctx(struct iommu *obj, char *buf)
+{
+	char *p = buf;
+
+	pr_reg(REVISION);
+	pr_reg(SYSCONFIG);
+	pr_reg(SYSSTATUS);
+	pr_reg(IRQSTATUS);
+	pr_reg(IRQENABLE);
+	pr_reg(WALKING_ST);
+	pr_reg(CNTL);
+	pr_reg(FAULT_AD);
+	pr_reg(TTB);
+	pr_reg(LOCK);
+	pr_reg(LD_TLB);
+	pr_reg(CAM);
+	pr_reg(RAM);
+	pr_reg(GFLUSH);
+	pr_reg(FLUSH_ENTRY);
+	pr_reg(READ_CAM);
+	pr_reg(READ_RAM);
+	pr_reg(EMU_FAULT_AD);
+
+	return p - buf;
+}
+
+static void omap2_iommu_save_ctx(struct iommu *obj)
+{
+	int i;
+	u32 *p = obj->ctx;
+
+	for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) {
+		p[i] = iommu_read_reg(obj, i * sizeof(u32));
+		dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]);
+	}
+
+	BUG_ON(p[0] != IOMMU_ARCH_VERSION);
+}
+
+static void omap2_iommu_restore_ctx(struct iommu *obj)
+{
+	int i;
+	u32 *p = obj->ctx;
+
+	for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) {
+		iommu_write_reg(obj, p[i], i * sizeof(u32));
+		dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]);
+	}
+
+	BUG_ON(p[0] != IOMMU_ARCH_VERSION);
+}
+
+static void omap2_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
+{
+	e->da		= cr->cam & MMU_CAM_VATAG_MASK;
+	e->pa		= cr->ram & MMU_RAM_PADDR_MASK;
+	e->valid	= cr->cam & MMU_CAM_V;
+	e->pgsz		= cr->cam & MMU_CAM_PGSZ_MASK;
+	e->endian	= cr->ram & MMU_RAM_ENDIAN_MASK;
+	e->elsz		= cr->ram & MMU_RAM_ELSZ_MASK;
+	e->mixed	= cr->ram & MMU_RAM_MIXED;
+}
+
+static const struct iommu_functions omap2_iommu_ops = {
+	.version	= IOMMU_ARCH_VERSION,
+
+	.enable		= omap2_iommu_enable,
+	.disable	= omap2_iommu_disable,
+	.fault_isr	= omap2_iommu_fault_isr,
+
+	.tlb_read_cr	= omap2_tlb_read_cr,
+	.tlb_load_cr	= omap2_tlb_load_cr,
+
+	.cr_to_e	= omap2_cr_to_e,
+	.cr_to_virt	= omap2_cr_to_virt,
+	.alloc_cr	= omap2_alloc_cr,
+	.cr_valid	= omap2_cr_valid,
+	.dump_cr	= omap2_dump_cr,
+
+	.get_pte_attr	= omap2_get_pte_attr,
+
+	.save_ctx	= omap2_iommu_save_ctx,
+	.restore_ctx	= omap2_iommu_restore_ctx,
+	.dump_ctx	= omap2_iommu_dump_ctx,
+};
+
+static int __init omap2_iommu_init(void)
+{
+	return install_iommu_arch(&omap2_iommu_ops);
+}
+module_init(omap2_iommu_init);
+
+static void __exit omap2_iommu_exit(void)
+{
+	uninstall_iommu_arch(&omap2_iommu_ops);
+}
+module_exit(omap2_iommu_exit);
+
+MODULE_AUTHOR("Hiroshi DOYU, Paul Mundt and Toshihiro Kobayashi");
+MODULE_DESCRIPTION("omap iommu: omap2/3 architecture specific functions");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 998c5c4..b828638 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -28,7 +28,6 @@
 #define INTC_MIR_CLEAR0		0x0088
 #define INTC_MIR_SET0		0x008c
 #define INTC_PENDING_IRQ0	0x0098
-
 /* Number of IRQ state bits in each MIR register */
 #define IRQ_BITS_PER_REG	32
 
@@ -134,7 +133,6 @@
 	.ack	= omap_mask_ack_irq,
 	.mask	= omap_mask_irq,
 	.unmask	= omap_unmask_irq,
-	.disable = omap_mask_irq,
 };
 
 static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
@@ -157,6 +155,22 @@
 	intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
 }
 
+int omap_irq_pending(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
+		struct omap_irq_bank *bank = irq_banks + i;
+		int irq;
+
+		for (irq = 0; irq < bank->nr_irqs; irq += 32)
+			if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
+					       ((irq >> 5) << 5)))
+				return 1;
+	}
+	return 0;
+}
+
 void __init omap_init_irq(void)
 {
 	unsigned long nr_of_irqs = 0;
diff --git a/arch/arm/mach-omap2/mmc-twl4030.c b/arch/arm/mach-omap2/mmc-twl4030.c
index dc40b3e..9756a87 100644
--- a/arch/arm/mach-omap2/mmc-twl4030.c
+++ b/arch/arm/mach-omap2/mmc-twl4030.c
@@ -16,8 +16,8 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
-#include <linux/i2c/twl4030.h>
-#include <linux/regulator/machine.h>
+#include <linux/mmc/host.h>
+#include <linux/regulator/consumer.h>
 
 #include <mach/hardware.h>
 #include <mach/control.h>
@@ -26,32 +26,10 @@
 
 #include "mmc-twl4030.h"
 
-#if defined(CONFIG_TWL4030_CORE) && \
+
+#if defined(CONFIG_REGULATOR) && \
 	(defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE))
 
-#define LDO_CLR			0x00
-#define VSEL_S2_CLR		0x40
-
-#define VMMC1_DEV_GRP		0x27
-#define VMMC1_CLR		0x00
-#define VMMC1_315V		0x03
-#define VMMC1_300V		0x02
-#define VMMC1_285V		0x01
-#define VMMC1_185V		0x00
-#define VMMC1_DEDICATED		0x2A
-
-#define VMMC2_DEV_GRP		0x2B
-#define VMMC2_CLR		0x40
-#define VMMC2_315V		0x0c
-#define VMMC2_300V		0x0b
-#define VMMC2_285V		0x0a
-#define VMMC2_280V		0x09
-#define VMMC2_260V		0x08
-#define VMMC2_185V		0x06
-#define VMMC2_DEDICATED		0x2E
-
-#define VMMC_DEV_GRP_P1		0x20
-
 static u16 control_pbias_offset;
 static u16 control_devconf1_offset;
 
@@ -59,19 +37,16 @@
 
 static struct twl_mmc_controller {
 	struct omap_mmc_platform_data	*mmc;
-	u8		twl_vmmc_dev_grp;
-	u8		twl_mmc_dedicated;
-	char		name[HSMMC_NAME_LEN + 1];
-} hsmmc[OMAP34XX_NR_MMC] = {
-	{
-		.twl_vmmc_dev_grp		= VMMC1_DEV_GRP,
-		.twl_mmc_dedicated		= VMMC1_DEDICATED,
-	},
-	{
-		.twl_vmmc_dev_grp		= VMMC2_DEV_GRP,
-		.twl_mmc_dedicated		= VMMC2_DEDICATED,
-	},
-};
+	/* Vcc == configured supply
+	 * Vcc_alt == optional
+	 *   -	MMC1, supply for DAT4..DAT7
+	 *   -	MMC2/MMC2, external level shifter voltage supply, for
+	 *	chip (SDIO, eMMC, etc) or transceiver (MMC2 only)
+	 */
+	struct regulator		*vcc;
+	struct regulator		*vcc_aux;
+	char				name[HSMMC_NAME_LEN + 1];
+} hsmmc[OMAP34XX_NR_MMC];
 
 static int twl_mmc_card_detect(int irq)
 {
@@ -117,16 +92,60 @@
 	int ret = 0;
 	int i;
 
-	ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd");
-	if (ret)
-		goto done;
-	ret = gpio_direction_input(mmc->slots[0].switch_pin);
-	if (ret)
-		goto err;
+	/* MMC/SD/SDIO doesn't require a card detect switch */
+	if (gpio_is_valid(mmc->slots[0].switch_pin)) {
+		ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd");
+		if (ret)
+			goto done;
+		ret = gpio_direction_input(mmc->slots[0].switch_pin);
+		if (ret)
+			goto err;
+	}
 
+	/* require at least main regulator */
 	for (i = 0; i < ARRAY_SIZE(hsmmc); i++) {
 		if (hsmmc[i].name == mmc->slots[0].name) {
+			struct regulator *reg;
+
 			hsmmc[i].mmc = mmc;
+
+			reg = regulator_get(dev, "vmmc");
+			if (IS_ERR(reg)) {
+				dev_dbg(dev, "vmmc regulator missing\n");
+				/* HACK: until fixed.c regulator is usable,
+				 * we don't require a main regulator
+				 * for MMC2 or MMC3
+				 */
+				if (i != 0)
+					break;
+				ret = PTR_ERR(reg);
+				goto err;
+			}
+			hsmmc[i].vcc = reg;
+			mmc->slots[0].ocr_mask = mmc_regulator_get_ocrmask(reg);
+
+			/* allow an aux regulator */
+			reg = regulator_get(dev, "vmmc_aux");
+			hsmmc[i].vcc_aux = IS_ERR(reg) ? NULL : reg;
+
+			/* UGLY HACK:  workaround regulator framework bugs.
+			 * When the bootloader leaves a supply active, it's
+			 * initialized with zero usecount ... and we can't
+			 * disable it without first enabling it.  Until the
+			 * framework is fixed, we need a workaround like this
+			 * (which is safe for MMC, but not in general).
+			 */
+			if (regulator_is_enabled(hsmmc[i].vcc) > 0) {
+				regulator_enable(hsmmc[i].vcc);
+				regulator_disable(hsmmc[i].vcc);
+			}
+			if (hsmmc[i].vcc_aux) {
+				if (regulator_is_enabled(reg) > 0) {
+					regulator_enable(reg);
+					regulator_disable(reg);
+				}
+			}
+
 			break;
 		}
 	}
@@ -173,96 +192,6 @@
 #define twl_mmc_resume	NULL
 #endif
 
-/*
- * Sets the MMC voltage in twl4030
- */
-
-#define MMC1_OCR	(MMC_VDD_165_195 \
-		|MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31|MMC_VDD_31_32)
-#define MMC2_OCR	(MMC_VDD_165_195 \
-		|MMC_VDD_25_26|MMC_VDD_26_27|MMC_VDD_27_28 \
-		|MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31|MMC_VDD_31_32)
-
-static int twl_mmc_set_voltage(struct twl_mmc_controller *c, int vdd)
-{
-	int ret;
-	u8 vmmc = 0, dev_grp_val;
-
-	if (!vdd)
-		goto doit;
-
-	if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) {
-		/* VMMC1:  max 220 mA.  And for 8-bit mode,
-		 * VSIM:  max 50 mA
-		 */
-		switch (1 << vdd) {
-		case MMC_VDD_165_195:
-			vmmc = VMMC1_185V;
-			/* and VSIM_180V */
-			break;
-		case MMC_VDD_28_29:
-			vmmc = VMMC1_285V;
-			/* and VSIM_280V */
-			break;
-		case MMC_VDD_29_30:
-		case MMC_VDD_30_31:
-			vmmc = VMMC1_300V;
-			/* and VSIM_300V */
-			break;
-		case MMC_VDD_31_32:
-			vmmc = VMMC1_315V;
-			/* error if VSIM needed */
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else if (c->twl_vmmc_dev_grp == VMMC2_DEV_GRP) {
-		/* VMMC2:  max 100 mA */
-		switch (1 << vdd) {
-		case MMC_VDD_165_195:
-			vmmc = VMMC2_185V;
-			break;
-		case MMC_VDD_25_26:
-		case MMC_VDD_26_27:
-			vmmc = VMMC2_260V;
-			break;
-		case MMC_VDD_27_28:
-			vmmc = VMMC2_280V;
-			break;
-		case MMC_VDD_28_29:
-			vmmc = VMMC2_285V;
-			break;
-		case MMC_VDD_29_30:
-		case MMC_VDD_30_31:
-			vmmc = VMMC2_300V;
-			break;
-		case MMC_VDD_31_32:
-			vmmc = VMMC2_315V;
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else {
-		return -EINVAL;
-	}
-
-doit:
-	if (vdd)
-		dev_grp_val = VMMC_DEV_GRP_P1;	/* Power up */
-	else
-		dev_grp_val = LDO_CLR;		/* Power down */
-
-	ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
-					dev_grp_val, c->twl_vmmc_dev_grp);
-	if (ret || !vdd)
-		return ret;
-
-	ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
-					vmmc, c->twl_mmc_dedicated);
-
-	return ret;
-}
-
 static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
 				int vdd)
 {
@@ -273,11 +202,13 @@
 
 	/*
 	 * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the
-	 * card using the same TWL VMMC1 supply (hsmmc[0]); OMAP has both
+	 * card with Vcc regulator (from twl4030 or whatever).  OMAP has both
 	 * 1.8V and 3.0V modes, controlled by the PBIAS register.
 	 *
 	 * In 8-bit modes, OMAP VMMC1A (for DAT4..7) needs a supply, which
 	 * is most naturally TWL VSIM; those pins also use PBIAS.
+	 *
+	 * FIXME handle VMMC1A as needed ...
 	 */
 	if (power_on) {
 		if (cpu_is_omap2430()) {
@@ -300,7 +231,7 @@
 		reg &= ~OMAP2_PBIASLITEPWRDNZ0;
 		omap_ctrl_writel(reg, control_pbias_offset);
 
-		ret = twl_mmc_set_voltage(c, vdd);
+		ret = mmc_regulator_set_ocr(c->vcc, vdd);
 
 		/* 100ms delay required for PBIAS configuration */
 		msleep(100);
@@ -316,7 +247,7 @@
 		reg &= ~OMAP2_PBIASLITEPWRDNZ0;
 		omap_ctrl_writel(reg, control_pbias_offset);
 
-		ret = twl_mmc_set_voltage(c, 0);
+		ret = mmc_regulator_set_ocr(c->vcc, 0);
 
 		/* 100ms delay required for PBIAS configuration */
 		msleep(100);
@@ -329,19 +260,33 @@
 	return ret;
 }
 
-static int twl_mmc2_set_power(struct device *dev, int slot, int power_on, int vdd)
+static int twl_mmc23_set_power(struct device *dev, int slot, int power_on, int vdd)
 {
-	int ret;
+	int ret = 0;
 	struct twl_mmc_controller *c = &hsmmc[1];
 	struct omap_mmc_platform_data *mmc = dev->platform_data;
 
+	/* If we don't see a Vcc regulator, assume it's a fixed
+	 * voltage always-on regulator.
+	 */
+	if (!c->vcc)
+		return 0;
+
 	/*
-	 * Assume TWL VMMC2 (hsmmc[1]) is used only to power the card ... OMAP
+	 * Assume Vcc regulator is used only to power the card ... OMAP
 	 * VDDS is used to power the pins, optionally with a transceiver to
 	 * support cards using voltages other than VDDS (1.8V nominal).  When a
 	 * transceiver is used, DAT3..7 are muxed as transceiver control pins.
+	 *
+	 * In some cases this regulator won't support enable/disable;
+	 * e.g. it's a fixed rail for a WLAN chip.
+	 *
+	 * In other cases vcc_aux switches interface power.  Example, for
+	 * eMMC cards it represents VccQ.  Sometimes transceivers or SDIO
+	 * chips/cards need an interface voltage rail too.
 	 */
 	if (power_on) {
+		/* only MMC2 supports a CLKIN */
 		if (mmc->slots[0].internal_clock) {
 			u32 reg;
 
@@ -349,24 +294,23 @@
 			reg |= OMAP2_MMCSDIO2ADPCLKISEL;
 			omap_ctrl_writel(reg, control_devconf1_offset);
 		}
-		ret = twl_mmc_set_voltage(c, vdd);
+		ret = mmc_regulator_set_ocr(c->vcc, vdd);
+		/* enable interface voltage rail, if needed */
+		if (ret == 0 && c->vcc_aux) {
+			ret = regulator_enable(c->vcc_aux);
+			if (ret < 0)
+				ret = mmc_regulator_set_ocr(c->vcc, 0);
+		}
 	} else {
-		ret = twl_mmc_set_voltage(c, 0);
+		if (c->vcc_aux && (ret = regulator_is_enabled(c->vcc_aux)) > 0)
+			ret = regulator_disable(c->vcc_aux);
+		if (ret == 0)
+			ret = mmc_regulator_set_ocr(c->vcc, 0);
 	}
 
 	return ret;
 }
 
-static int twl_mmc3_set_power(struct device *dev, int slot, int power_on,
-		int vdd)
-{
-	/*
-	 * Assume MMC3 has self-powered device connected, for example on-board
-	 * chip with external power source.
-	 */
-	return 0;
-}
-
 static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata;
 
 void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
@@ -412,10 +356,10 @@
 		mmc->slots[0].wires = c->wires;
 		mmc->slots[0].internal_clock = !c->ext_clock;
 		mmc->dma_mask = 0xffffffff;
+		mmc->init = twl_mmc_late_init;
 
-		/* note: twl4030 card detect GPIOs normally switch VMMCx ... */
+		/* note: twl4030 card detect GPIOs can disable VMMCx ... */
 		if (gpio_is_valid(c->gpio_cd)) {
-			mmc->init = twl_mmc_late_init;
 			mmc->cleanup = twl_mmc_cleanup;
 			mmc->suspend = twl_mmc_suspend;
 			mmc->resume = twl_mmc_resume;
@@ -439,26 +383,28 @@
 		} else
 			mmc->slots[0].gpio_wp = -EINVAL;
 
-		/* NOTE:  we assume OMAP's MMC1 and MMC2 use
-		 * the TWL4030's VMMC1 and VMMC2, respectively;
-		 * and that MMC3 device has it's own power source.
+		/* NOTE:  MMC slots should have a Vcc regulator set up.
+		 * This may be from a TWL4030-family chip, another
+		 * controllable regulator, or a fixed supply.
+		 *
+		 * temporary HACK: ocr_mask instead of fixed supply
 		 */
+		mmc->slots[0].ocr_mask = c->ocr_mask;
 
 		switch (c->mmc) {
 		case 1:
+			/* on-chip level shifting via PBIAS0/PBIAS1 */
 			mmc->slots[0].set_power = twl_mmc1_set_power;
-			mmc->slots[0].ocr_mask = MMC1_OCR;
 			break;
 		case 2:
-			mmc->slots[0].set_power = twl_mmc2_set_power;
-			if (c->transceiver)
-				mmc->slots[0].ocr_mask = MMC2_OCR;
-			else
-				mmc->slots[0].ocr_mask = MMC_VDD_165_195;
-			break;
+			if (c->ext_clock)
+				c->transceiver = 1;
+			if (c->transceiver && c->wires > 4)
+				c->wires = 4;
+			/* FALLTHROUGH */
 		case 3:
-			mmc->slots[0].set_power = twl_mmc3_set_power;
-			mmc->slots[0].ocr_mask = MMC_VDD_165_195;
+			/* off-chip level shifting, or none */
+			mmc->slots[0].set_power = twl_mmc23_set_power;
 			break;
 		default:
 			pr_err("MMC%d configuration not supported!\n", c->mmc);
diff --git a/arch/arm/mach-omap2/mmc-twl4030.h b/arch/arm/mach-omap2/mmc-twl4030.h
index ea59e86..3807c45 100644
--- a/arch/arm/mach-omap2/mmc-twl4030.h
+++ b/arch/arm/mach-omap2/mmc-twl4030.h
@@ -16,9 +16,10 @@
 	int	gpio_wp;	/* or -EINVAL */
 	char	*name;		/* or NULL for default */
 	struct device *dev;	/* returned: pointer to mmc adapter */
+	int	ocr_mask;	/* temporary HACK */
 };
 
-#if	defined(CONFIG_TWL4030_CORE) && \
+#if defined(CONFIG_REGULATOR) && \
 	(defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
 	 defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE))
 
diff --git a/arch/arm/mach-omap2/omap-headsmp.S b/arch/arm/mach-omap2/omap-headsmp.S
new file mode 100644
index 0000000..4afadba
--- /dev/null
+++ b/arch/arm/mach-omap2/omap-headsmp.S
@@ -0,0 +1,46 @@
+/*
+ * Secondary CPU startup routine source file.
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Author:
+ *      Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * Interface functions needed for the SMP. This file is based on arm
+ * realview smp platform.
+ * 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+/* Physical address needed since MMU not enabled yet on secondary core */
+#define OMAP4_AUX_CORE_BOOT1_PA			0x48281804
+
+	__INIT
+
+/*
+ * OMAP4 specific entry point for secondary CPU to jump from ROM
+ * code.  This routine also provides a holding flag into which
+ * secondary core is held until we're ready for it to initialise.
+ * The primary core will update the this flag using a hardware
+ * register AuxCoreBoot1.
+ */
+ENTRY(omap_secondary_startup)
+	mrc	p15, 0, r0, c0, c0, 5
+	and	r0, r0, #0x0f
+hold:	ldr	r1, =OMAP4_AUX_CORE_BOOT1_PA	@ read from AuxCoreBoot1
+	ldr	r2, [r1]
+	cmp	r2, r0
+	bne	hold
+
+	/*
+	 * we've been released from the cpu_release,secondary_stack
+	 * should now contain the SVC stack for this core
+	 */
+	b	secondary_startup
+
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
new file mode 100644
index 0000000..8fe8d23
--- /dev/null
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -0,0 +1,178 @@
+/*
+ * OMAP4 SMP source file. It contains platform specific fucntions
+ * needed for the linux smp kernel.
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Author:
+ *      Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * Platform file needed for the OMAP4 SMP. This file is based on arm
+ * realview smp platform.
+ * * Copyright (c) 2002 ARM Limited.
+ *
+ * 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/device.h>
+#include <linux/jiffies.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+
+#include <asm/localtimer.h>
+#include <asm/smp_scu.h>
+#include <mach/hardware.h>
+
+/* Registers used for communicating startup information */
+#define OMAP4_AUXCOREBOOT_REG0		(OMAP44XX_VA_WKUPGEN_BASE + 0x800)
+#define OMAP4_AUXCOREBOOT_REG1		(OMAP44XX_VA_WKUPGEN_BASE + 0x804)
+
+/* SCU base address */
+static void __iomem *scu_base = OMAP44XX_VA_SCU_BASE;
+
+/*
+ * Use SCU config register to count number of cores
+ */
+static inline unsigned int get_core_count(void)
+{
+	if (scu_base)
+		return scu_get_core_count(scu_base);
+	return 1;
+}
+
+static DEFINE_SPINLOCK(boot_lock);
+
+void __cpuinit platform_secondary_init(unsigned int cpu)
+{
+	trace_hardirqs_off();
+
+	/*
+	 * If any interrupts are already enabled for the primary
+	 * core (e.g. timer irq), then they will not have been enabled
+	 * for us: do so
+	 */
+
+	gic_cpu_init(0, IO_ADDRESS(OMAP44XX_GIC_CPU_BASE));
+
+	/*
+	 * Synchronise with the boot thread.
+	 */
+	spin_lock(&boot_lock);
+	spin_unlock(&boot_lock);
+}
+
+int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	unsigned long timeout;
+
+	/*
+	 * Set synchronisation state between this boot processor
+	 * and the secondary one
+	 */
+	spin_lock(&boot_lock);
+
+	/*
+	 * Update the AuxCoreBoot1 with boot state for secondary core.
+	 * omap_secondary_startup() routine will hold the secondary core till
+	 * the AuxCoreBoot1 register is updated with cpu state
+	 * A barrier is added to ensure that write buffer is drained
+	 */
+	__raw_writel(cpu, OMAP4_AUXCOREBOOT_REG1);
+	smp_wmb();
+
+	timeout = jiffies + (1 * HZ);
+	while (time_before(jiffies, timeout))
+		;
+
+	/*
+	 * Now the secondary core is starting up let it run its
+	 * calibrations, then wait for it to finish
+	 */
+	spin_unlock(&boot_lock);
+
+	return 0;
+}
+
+static void __init wakeup_secondary(void)
+{
+	/*
+	 * Write the address of secondary startup routine into the
+	 * AuxCoreBoot0 where ROM code will jump and start executing
+	 * on secondary core once out of WFE
+	 * A barrier is added to ensure that write buffer is drained
+	 */
+	__raw_writel(virt_to_phys(omap_secondary_startup),	   \
+					OMAP4_AUXCOREBOOT_REG0);
+	smp_wmb();
+
+	/*
+	 * Send a 'sev' to wake the secondary core from WFE.
+	 */
+	set_event();
+	mb();
+}
+
+/*
+ * 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)
+{
+	unsigned int i, ncores = get_core_count();
+
+	for (i = 0; i < ncores; i++)
+		set_cpu_possible(i, true);
+}
+
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+	unsigned int ncores = get_core_count();
+	unsigned int cpu = smp_processor_id();
+	int i;
+
+	/* sanity check */
+	if (ncores == 0) {
+		printk(KERN_ERR
+		       "OMAP4: strange core count of 0? Default to 1\n");
+		ncores = 1;
+	}
+
+	if (ncores > NR_CPUS) {
+		printk(KERN_WARNING
+		       "OMAP4: no. of cores (%d) greater than configured "
+		       "maximum of %d - clipping\n",
+		       ncores, NR_CPUS);
+		ncores = NR_CPUS;
+	}
+	smp_store_cpu_info(cpu);
+
+	/*
+	 * are we trying to boot more cores than exist?
+	 */
+	if (max_cpus > ncores)
+		max_cpus = ncores;
+
+	/*
+	 * Initialise the present map, which describes the set of CPUs
+	 * actually populated at the present time.
+	 */
+	for (i = 0; i < max_cpus; i++)
+		set_cpu_present(i, true);
+
+	if (max_cpus > 1) {
+		/*
+		 * Enable the local timer or broadcast device for the
+		 * boot CPU, but only if we have more than one CPU.
+		 */
+		percpu_timer_setup();
+
+		/*
+		 * Initialise the SCU and wake up the secondary core using
+		 * wakeup_secondary().
+		 */
+		scu_enable(scu_base);
+		wakeup_secondary();
+	}
+}
diff --git a/arch/arm/mach-omap2/omap3-iommu.c b/arch/arm/mach-omap2/omap3-iommu.c
new file mode 100644
index 0000000..194189c
--- /dev/null
+++ b/arch/arm/mach-omap2/omap3-iommu.c
@@ -0,0 +1,105 @@
+/*
+ * omap iommu: omap3 device registration
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@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.
+ */
+
+#include <linux/platform_device.h>
+
+#include <mach/iommu.h>
+
+#define OMAP3_MMU1_BASE	0x480bd400
+#define OMAP3_MMU2_BASE	0x5d000000
+#define OMAP3_MMU1_IRQ	24
+#define OMAP3_MMU2_IRQ	28
+
+
+static unsigned long iommu_base[] __initdata = {
+	OMAP3_MMU1_BASE,
+	OMAP3_MMU2_BASE,
+};
+
+static int iommu_irq[] __initdata = {
+	OMAP3_MMU1_IRQ,
+	OMAP3_MMU2_IRQ,
+};
+
+static const struct iommu_platform_data omap3_iommu_pdata[] __initconst = {
+	{
+		.name = "isp",
+		.nr_tlb_entries = 8,
+		.clk_name = "cam_ick",
+	},
+#if defined(CONFIG_MPU_BRIDGE_IOMMU)
+	{
+		.name = "iva2",
+		.nr_tlb_entries = 32,
+		.clk_name = "iva2_ck",
+	},
+#endif
+};
+#define NR_IOMMU_DEVICES ARRAY_SIZE(omap3_iommu_pdata)
+
+static struct platform_device *omap3_iommu_pdev[NR_IOMMU_DEVICES];
+
+static int __init omap3_iommu_init(void)
+{
+	int i, err;
+
+	for (i = 0; i < NR_IOMMU_DEVICES; i++) {
+		struct platform_device *pdev;
+		struct resource res[2];
+
+		pdev = platform_device_alloc("omap-iommu", i);
+		if (!pdev) {
+			err = -ENOMEM;
+			goto err_out;
+		}
+
+		memset(res, 0,  sizeof(res));
+		res[0].start = iommu_base[i];
+		res[0].end = iommu_base[i] + MMU_REG_SIZE - 1;
+		res[0].flags = IORESOURCE_MEM;
+		res[1].start = res[1].end = iommu_irq[i];
+		res[1].flags = IORESOURCE_IRQ;
+
+		err = platform_device_add_resources(pdev, res,
+						    ARRAY_SIZE(res));
+		if (err)
+			goto err_out;
+		err = platform_device_add_data(pdev, &omap3_iommu_pdata[i],
+					       sizeof(omap3_iommu_pdata[0]));
+		if (err)
+			goto err_out;
+		err = platform_device_add(pdev);
+		if (err)
+			goto err_out;
+		omap3_iommu_pdev[i] = pdev;
+	}
+	return 0;
+
+err_out:
+	while (i--)
+		platform_device_put(omap3_iommu_pdev[i]);
+	return err;
+}
+module_init(omap3_iommu_init);
+
+static void __exit omap3_iommu_exit(void)
+{
+	int i;
+
+	for (i = 0; i < NR_IOMMU_DEVICES; i++)
+		platform_device_unregister(omap3_iommu_pdev[i]);
+}
+module_exit(omap3_iommu_exit);
+
+MODULE_AUTHOR("Hiroshi DOYU");
+MODULE_DESCRIPTION("omap iommu: omap3 device registration");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
new file mode 100644
index 0000000..6cc375a
--- /dev/null
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -0,0 +1,152 @@
+/*
+ * OMAP Power Management debug routines
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Written by:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Tony Lindgren
+ * Juha Yrjola
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ * Jouni Hogander
+ *
+ * Based on pm.c for omap2
+ *
+ * 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/timer.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/clock.h>
+#include <mach/board.h>
+
+#include "prm.h"
+#include "cm.h"
+#include "pm.h"
+
+int omap2_pm_debug;
+
+#define DUMP_PRM_MOD_REG(mod, reg)    \
+	regs[reg_count].name = #mod "." #reg; \
+	regs[reg_count++].val = prm_read_mod_reg(mod, reg)
+#define DUMP_CM_MOD_REG(mod, reg)     \
+	regs[reg_count].name = #mod "." #reg; \
+	regs[reg_count++].val = cm_read_mod_reg(mod, reg)
+#define DUMP_PRM_REG(reg) \
+	regs[reg_count].name = #reg; \
+	regs[reg_count++].val = __raw_readl(reg)
+#define DUMP_CM_REG(reg) \
+	regs[reg_count].name = #reg; \
+	regs[reg_count++].val = __raw_readl(reg)
+#define DUMP_INTC_REG(reg, off) \
+	regs[reg_count].name = #reg; \
+	regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off)))
+
+void omap2_pm_dump(int mode, int resume, unsigned int us)
+{
+	struct reg {
+		const char *name;
+		u32 val;
+	} regs[32];
+	int reg_count = 0, i;
+	const char *s1 = NULL, *s2 = NULL;
+
+	if (!resume) {
+#if 0
+		/* MPU */
+		DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET);
+		DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL);
+		DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL);
+		DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST);
+		DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP);
+#endif
+#if 0
+		/* INTC */
+		DUMP_INTC_REG(INTC_MIR0, 0x0084);
+		DUMP_INTC_REG(INTC_MIR1, 0x00a4);
+		DUMP_INTC_REG(INTC_MIR2, 0x00c4);
+#endif
+#if 0
+		DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1);
+		if (cpu_is_omap24xx()) {
+			DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+			DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
+					OMAP2_PRCM_CLKEMUL_CTRL_OFFSET);
+			DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
+					OMAP2_PRCM_CLKSRC_CTRL_OFFSET);
+		}
+		DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN);
+		DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1);
+		DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2);
+		DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN);
+		DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN);
+		DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE);
+		DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST);
+#endif
+#if 0
+		/* DSP */
+		if (cpu_is_omap24xx()) {
+			DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN);
+			DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN);
+			DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST);
+			DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+			DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL);
+			DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
+			DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL);
+			DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST);
+			DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL);
+			DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST);
+		}
+#endif
+	} else {
+		DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1);
+		if (cpu_is_omap24xx())
+			DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2);
+		DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST);
+		DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+#if 1
+		DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098);
+		DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8);
+		DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8);
+#endif
+	}
+
+	switch (mode) {
+	case 0:
+		s1 = "full";
+		s2 = "retention";
+		break;
+	case 1:
+		s1 = "MPU";
+		s2 = "retention";
+		break;
+	case 2:
+		s1 = "MPU";
+		s2 = "idle";
+		break;
+	}
+
+	if (!resume)
+#ifdef CONFIG_NO_HZ
+		printk(KERN_INFO
+		       "--- Going to %s %s (next timer after %u ms)\n", s1, s2,
+		       jiffies_to_msecs(get_next_timer_interrupt(jiffies) -
+					jiffies));
+#else
+		printk(KERN_INFO "--- Going to %s %s\n", s1, s2);
+#endif
+	else
+		printk(KERN_INFO "--- Woke up (slept for %u.%03u ms)\n",
+			us / 1000, us % 1000);
+
+	for (i = 0; i < reg_count; i++)
+		printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val);
+}
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
deleted file mode 100644
index ea8ceae..0000000
--- a/arch/arm/mach-omap2/pm.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/pm.c
- *
- * OMAP2 Power Management Routines
- *
- * Copyright (C) 2006 Nokia Corporation
- * Tony Lindgren <tony@atomide.com>
- *
- * Copyright (C) 2005 Texas Instruments, Inc.
- * Richard Woodruff <r-woodruff2@ti.com>
- *
- * Based on pm.c for omap1
- *
- * 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/suspend.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/interrupt.h>
-#include <linux/sysfs.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/atomic.h>
-#include <asm/mach/time.h>
-#include <asm/mach/irq.h>
-
-#include <mach/irqs.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
-#include <mach/pm.h>
-
-static struct clk *vclk;
-static void (*omap2_sram_idle)(void);
-static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
-static void (*saved_idle)(void);
-
-extern void __init pmdomain_init(void);
-extern void pmdomain_set_autoidle(void);
-
-static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE];
-
-void omap2_pm_idle(void)
-{
-	local_irq_disable();
-	local_fiq_disable();
-	if (need_resched()) {
-		local_fiq_enable();
-		local_irq_enable();
-		return;
-	}
-
-	omap2_sram_idle();
-	local_fiq_enable();
-	local_irq_enable();
-}
-
-static int omap2_pm_prepare(void)
-{
-	/* We cannot sleep in idle until we have resumed */
-	saved_idle = pm_idle;
-	pm_idle = NULL;
-	return 0;
-}
-
-static int omap2_pm_suspend(void)
-{
-	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_finish(void)
-{
-	pm_idle = saved_idle;
-}
-
-static struct platform_suspend_ops omap_pm_ops = {
-	.prepare	= omap2_pm_prepare,
-	.enter		= omap2_pm_enter,
-	.finish		= omap2_pm_finish,
-	.valid		= suspend_valid_only_mem,
-};
-
-static int __init omap2_pm_init(void)
-{
-	return 0;
-}
-
-__initcall(omap2_pm_init);
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
new file mode 100644
index 0000000..f7b3baf
--- /dev/null
+++ b/arch/arm/mach-omap2/pm.h
@@ -0,0 +1,38 @@
+/*
+ * OMAP2/3 Power Management Routines
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Jouni Hogander
+ *
+ * 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_OMAP2_PM_H
+#define __ARCH_ARM_MACH_OMAP2_PM_H
+
+extern int omap2_pm_init(void);
+extern int omap3_pm_init(void);
+
+#ifdef CONFIG_PM_DEBUG
+extern void omap2_pm_dump(int mode, int resume, unsigned int us);
+extern int omap2_pm_debug;
+#else
+#define omap2_pm_dump(mode, resume, us)		do {} while (0);
+#define omap2_pm_debug				0
+#endif /* CONFIG_PM_DEBUG */
+
+extern void omap24xx_idle_loop_suspend(void);
+
+extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl,
+					void __iomem *sdrc_power);
+extern void omap34xx_cpu_suspend(u32 *addr, int save_state);
+extern void save_secure_ram_context(u32 *addr);
+
+extern unsigned int omap24xx_idle_loop_suspend_sz;
+extern unsigned int omap34xx_suspend_sz;
+extern unsigned int save_secure_ram_context_sz;
+extern unsigned int omap24xx_cpu_suspend_sz;
+extern unsigned int omap34xx_cpu_suspend_sz;
+
+#endif
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
new file mode 100644
index 0000000..db10255
--- /dev/null
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -0,0 +1,549 @@
+/*
+ * OMAP2 Power Management Routines
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Written by:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Tony Lindgren
+ * Juha Yrjola
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ *
+ * Based on pm.c for omap1
+ *
+ * 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/suspend.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#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>
+
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/irqs.h>
+#include <mach/clock.h>
+#include <mach/sram.h>
+#include <mach/control.h>
+#include <mach/mux.h>
+#include <mach/dma.h>
+#include <mach/board.h>
+
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "cm.h"
+#include "cm-regbits-24xx.h"
+#include "sdrc.h"
+#include "pm.h"
+
+#include <mach/powerdomain.h>
+#include <mach/clockdomain.h>
+
+static void (*omap2_sram_idle)(void);
+static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
+				  void __iomem *sdrc_power);
+
+static struct powerdomain *mpu_pwrdm;
+static struct powerdomain *core_pwrdm;
+
+static struct clockdomain *dsp_clkdm;
+static struct clockdomain *gfx_clkdm;
+
+static struct clk *osc_ck, *emul_ck;
+
+static int omap2_fclks_active(void)
+{
+	u32 f1, f2;
+
+	f1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+	f2 = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+
+	/* Ignore UART clocks.  These are handled by UART core (serial.c) */
+	f1 &= ~(OMAP24XX_EN_UART1 | OMAP24XX_EN_UART2);
+	f2 &= ~OMAP24XX_EN_UART3;
+
+	if (f1 | f2)
+		return 1;
+	return 0;
+}
+
+static void omap2_enter_full_retention(void)
+{
+	u32 l;
+	struct timespec ts_preidle, ts_postidle, ts_idle;
+
+	/* There is 1 reference hold for all children of the oscillator
+	 * clock, the following will remove it. If no one else uses the
+	 * oscillator itself it will be disabled if/when we enter retention
+	 * mode.
+	 */
+	clk_disable(osc_ck);
+
+	/* Clear old wake-up events */
+	/* REVISIT: These write to reserved bits? */
+	prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+	prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+	prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
+
+	/*
+	 * Set MPU powerdomain's next power state to RETENTION;
+	 * preserve logic state during retention
+	 */
+	pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
+	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
+
+	/* Workaround to kill USB */
+	l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
+	omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);
+
+	omap2_gpio_prepare_for_retention();
+
+	if (omap2_pm_debug) {
+		omap2_pm_dump(0, 0, 0);
+		getnstimeofday(&ts_preidle);
+	}
+
+	/* One last check for pending IRQs to avoid extra latency due
+	 * to sleeping unnecessarily. */
+	if (omap_irq_pending())
+		goto no_sleep;
+
+	omap_uart_prepare_idle(0);
+	omap_uart_prepare_idle(1);
+	omap_uart_prepare_idle(2);
+
+	/* Jump to SRAM suspend code */
+	omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL),
+			   OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
+			   OMAP_SDRC_REGADDR(SDRC_POWER));
+
+	omap_uart_resume_idle(2);
+	omap_uart_resume_idle(1);
+	omap_uart_resume_idle(0);
+
+no_sleep:
+	if (omap2_pm_debug) {
+		unsigned long long tmp;
+
+		getnstimeofday(&ts_postidle);
+		ts_idle = timespec_sub(ts_postidle, ts_preidle);
+		tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
+		omap2_pm_dump(0, 1, tmp);
+	}
+	omap2_gpio_resume_after_retention();
+
+	clk_enable(osc_ck);
+
+	/* clear CORE wake-up events */
+	prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+	prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+
+	/* wakeup domain events - bit 1: GPT1, bit5 GPIO */
+	prm_clear_mod_reg_bits(0x4 | 0x1, WKUP_MOD, PM_WKST);
+
+	/* MPU domain wake events */
+	l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+	if (l & 0x01)
+		prm_write_mod_reg(0x01, OCP_MOD,
+				  OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+	if (l & 0x20)
+		prm_write_mod_reg(0x20, OCP_MOD,
+				  OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+
+	/* Mask future PRCM-to-MPU interrupts */
+	prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+}
+
+static int omap2_i2c_active(void)
+{
+	u32 l;
+
+	l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+	return l & (OMAP2420_EN_I2C2 | OMAP2420_EN_I2C1);
+}
+
+static int sti_console_enabled;
+
+static int omap2_allow_mpu_retention(void)
+{
+	u32 l;
+
+	/* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */
+	l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+	if (l & (OMAP2420_EN_MMC | OMAP24XX_EN_UART2 |
+		 OMAP24XX_EN_UART1 | OMAP24XX_EN_MCSPI2 |
+		 OMAP24XX_EN_MCSPI1 | OMAP24XX_EN_DSS1))
+		return 0;
+	/* Check for UART3. */
+	l = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+	if (l & OMAP24XX_EN_UART3)
+		return 0;
+	if (sti_console_enabled)
+		return 0;
+
+	return 1;
+}
+
+static void omap2_enter_mpu_retention(void)
+{
+	int only_idle = 0;
+	struct timespec ts_preidle, ts_postidle, ts_idle;
+
+	/* Putting MPU into the WFI state while a transfer is active
+	 * seems to cause the I2C block to timeout. Why? Good question. */
+	if (omap2_i2c_active())
+		return;
+
+	/* The peripherals seem not to be able to wake up the MPU when
+	 * it is in retention mode. */
+	if (omap2_allow_mpu_retention()) {
+		/* REVISIT: These write to reserved bits? */
+		prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+		prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+		prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
+
+		/* Try to enter MPU retention */
+		prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
+				  OMAP_LOGICRETSTATE,
+				  MPU_MOD, PM_PWSTCTRL);
+	} else {
+		/* Block MPU retention */
+
+		prm_write_mod_reg(OMAP_LOGICRETSTATE, MPU_MOD, PM_PWSTCTRL);
+		only_idle = 1;
+	}
+
+	if (omap2_pm_debug) {
+		omap2_pm_dump(only_idle ? 2 : 1, 0, 0);
+		getnstimeofday(&ts_preidle);
+	}
+
+	omap2_sram_idle();
+
+	if (omap2_pm_debug) {
+		unsigned long long tmp;
+
+		getnstimeofday(&ts_postidle);
+		ts_idle = timespec_sub(ts_postidle, ts_preidle);
+		tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
+		omap2_pm_dump(only_idle ? 2 : 1, 1, tmp);
+	}
+}
+
+static int omap2_can_sleep(void)
+{
+	if (omap2_fclks_active())
+		return 0;
+	if (osc_ck->usecount > 1)
+		return 0;
+	if (omap_dma_running())
+		return 0;
+
+	return 1;
+}
+
+static void omap2_pm_idle(void)
+{
+	local_irq_disable();
+	local_fiq_disable();
+
+	if (!omap2_can_sleep()) {
+		if (omap_irq_pending())
+			goto out;
+		omap2_enter_mpu_retention();
+		goto out;
+	}
+
+	if (omap_irq_pending())
+		goto out;
+
+	omap2_enter_full_retention();
+
+out:
+	local_fiq_enable();
+	local_irq_enable();
+}
+
+static int omap2_pm_prepare(void)
+{
+	/* We cannot sleep in idle until we have resumed */
+	disable_hlt();
+	return 0;
+}
+
+static int omap2_pm_suspend(void)
+{
+	u32 wken_wkup, mir1;
+
+	wken_wkup = prm_read_mod_reg(WKUP_MOD, PM_WKEN);
+	prm_write_mod_reg(wken_wkup & ~OMAP24XX_EN_GPT1, WKUP_MOD, PM_WKEN);
+
+	/* Mask GPT1 */
+	mir1 = omap_readl(0x480fe0a4);
+	omap_writel(1 << 5, 0x480fe0ac);
+
+	omap_uart_prepare_suspend();
+	omap2_enter_full_retention();
+
+	omap_writel(mir1, 0x480fe0a4);
+	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_finish(void)
+{
+	enable_hlt();
+}
+
+static struct platform_suspend_ops omap_pm_ops = {
+	.prepare	= omap2_pm_prepare,
+	.enter		= omap2_pm_enter,
+	.finish		= omap2_pm_finish,
+	.valid		= suspend_valid_only_mem,
+};
+
+static int _pm_clkdm_enable_hwsup(struct clockdomain *clkdm)
+{
+	omap2_clkdm_allow_idle(clkdm);
+	return 0;
+}
+
+static void __init prcm_setup_regs(void)
+{
+	int i, num_mem_banks;
+	struct powerdomain *pwrdm;
+
+	/* Enable autoidle */
+	prm_write_mod_reg(OMAP24XX_AUTOIDLE, OCP_MOD,
+			  OMAP2_PRCM_SYSCONFIG_OFFSET);
+
+	/* Set all domain wakeup dependencies */
+	prm_write_mod_reg(OMAP_EN_WKUP_MASK, MPU_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, OMAP24XX_DSP_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, CORE_MOD, PM_WKDEP);
+	if (cpu_is_omap2430())
+		prm_write_mod_reg(0, OMAP2430_MDM_MOD, PM_WKDEP);
+
+	/*
+	 * Set CORE powerdomain memory banks to retain their contents
+	 * during RETENTION
+	 */
+	num_mem_banks = pwrdm_get_mem_bank_count(core_pwrdm);
+	for (i = 0; i < num_mem_banks; i++)
+		pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);
+
+	/* Set CORE powerdomain's next power state to RETENTION */
+	pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
+
+	/*
+	 * Set MPU powerdomain's next power state to RETENTION;
+	 * preserve logic state during retention
+	 */
+	pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
+	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
+
+	/* Force-power down DSP, GFX powerdomains */
+
+	pwrdm = clkdm_get_pwrdm(dsp_clkdm);
+	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
+	omap2_clkdm_sleep(dsp_clkdm);
+
+	pwrdm = clkdm_get_pwrdm(gfx_clkdm);
+	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
+	omap2_clkdm_sleep(gfx_clkdm);
+
+	/* Enable clockdomain hardware-supervised control for all clkdms */
+	clkdm_for_each(_pm_clkdm_enable_hwsup);
+
+	/* Enable clock autoidle for all domains */
+	cm_write_mod_reg(OMAP24XX_AUTO_CAM |
+			 OMAP24XX_AUTO_MAILBOXES |
+			 OMAP24XX_AUTO_WDT4 |
+			 OMAP2420_AUTO_WDT3 |
+			 OMAP24XX_AUTO_MSPRO |
+			 OMAP2420_AUTO_MMC |
+			 OMAP24XX_AUTO_FAC |
+			 OMAP2420_AUTO_EAC |
+			 OMAP24XX_AUTO_HDQ |
+			 OMAP24XX_AUTO_UART2 |
+			 OMAP24XX_AUTO_UART1 |
+			 OMAP24XX_AUTO_I2C2 |
+			 OMAP24XX_AUTO_I2C1 |
+			 OMAP24XX_AUTO_MCSPI2 |
+			 OMAP24XX_AUTO_MCSPI1 |
+			 OMAP24XX_AUTO_MCBSP2 |
+			 OMAP24XX_AUTO_MCBSP1 |
+			 OMAP24XX_AUTO_GPT12 |
+			 OMAP24XX_AUTO_GPT11 |
+			 OMAP24XX_AUTO_GPT10 |
+			 OMAP24XX_AUTO_GPT9 |
+			 OMAP24XX_AUTO_GPT8 |
+			 OMAP24XX_AUTO_GPT7 |
+			 OMAP24XX_AUTO_GPT6 |
+			 OMAP24XX_AUTO_GPT5 |
+			 OMAP24XX_AUTO_GPT4 |
+			 OMAP24XX_AUTO_GPT3 |
+			 OMAP24XX_AUTO_GPT2 |
+			 OMAP2420_AUTO_VLYNQ |
+			 OMAP24XX_AUTO_DSS,
+			 CORE_MOD, CM_AUTOIDLE1);
+	cm_write_mod_reg(OMAP24XX_AUTO_UART3 |
+			 OMAP24XX_AUTO_SSI |
+			 OMAP24XX_AUTO_USB,
+			 CORE_MOD, CM_AUTOIDLE2);
+	cm_write_mod_reg(OMAP24XX_AUTO_SDRC |
+			 OMAP24XX_AUTO_GPMC |
+			 OMAP24XX_AUTO_SDMA,
+			 CORE_MOD, CM_AUTOIDLE3);
+	cm_write_mod_reg(OMAP24XX_AUTO_PKA |
+			 OMAP24XX_AUTO_AES |
+			 OMAP24XX_AUTO_RNG |
+			 OMAP24XX_AUTO_SHA |
+			 OMAP24XX_AUTO_DES,
+			 CORE_MOD, OMAP24XX_CM_AUTOIDLE4);
+
+	cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI, OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+
+	/* Put DPLL and both APLLs into autoidle mode */
+	cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) |
+			 (0x03 << OMAP24XX_AUTO_96M_SHIFT) |
+			 (0x03 << OMAP24XX_AUTO_54M_SHIFT),
+			 PLL_MOD, CM_AUTOIDLE);
+
+	cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL |
+			 OMAP24XX_AUTO_WDT1 |
+			 OMAP24XX_AUTO_MPU_WDT |
+			 OMAP24XX_AUTO_GPIOS |
+			 OMAP24XX_AUTO_32KSYNC |
+			 OMAP24XX_AUTO_GPT1,
+			 WKUP_MOD, CM_AUTOIDLE);
+
+	/* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
+	 * stabilisation */
+	prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
+			  OMAP2_PRCM_CLKSSETUP_OFFSET);
+
+	/* Configure automatic voltage transition */
+	prm_write_mod_reg(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
+			  OMAP2_PRCM_VOLTSETUP_OFFSET);
+	prm_write_mod_reg(OMAP24XX_AUTO_EXTVOLT |
+			  (0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) |
+			  OMAP24XX_MEMRETCTRL |
+			  (0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) |
+			  (0x0 << OMAP24XX_VOLT_LEVEL_SHIFT),
+			  OMAP24XX_GR_MOD, OMAP2_PRCM_VOLTCTRL_OFFSET);
+
+	/* Enable wake-up events */
+	prm_write_mod_reg(OMAP24XX_EN_GPIOS | OMAP24XX_EN_GPT1,
+			  WKUP_MOD, PM_WKEN);
+}
+
+int __init omap2_pm_init(void)
+{
+	u32 l;
+
+	if (!cpu_is_omap24xx())
+		return -ENODEV;
+
+	printk(KERN_INFO "Power Management for OMAP2 initializing\n");
+	l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET);
+	printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
+
+	/* Look up important powerdomains, clockdomains */
+
+	mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+	if (!mpu_pwrdm)
+		pr_err("PM: mpu_pwrdm not found\n");
+
+	core_pwrdm = pwrdm_lookup("core_pwrdm");
+	if (!core_pwrdm)
+		pr_err("PM: core_pwrdm not found\n");
+
+	dsp_clkdm = clkdm_lookup("dsp_clkdm");
+	if (!dsp_clkdm)
+		pr_err("PM: mpu_clkdm not found\n");
+
+	gfx_clkdm = clkdm_lookup("gfx_clkdm");
+	if (!gfx_clkdm)
+		pr_err("PM: gfx_clkdm not found\n");
+
+
+	osc_ck = clk_get(NULL, "osc_ck");
+	if (IS_ERR(osc_ck)) {
+		printk(KERN_ERR "could not get osc_ck\n");
+		return -ENODEV;
+	}
+
+	if (cpu_is_omap242x()) {
+		emul_ck = clk_get(NULL, "emul_ck");
+		if (IS_ERR(emul_ck)) {
+			printk(KERN_ERR "could not get emul_ck\n");
+			clk_put(osc_ck);
+			return -ENODEV;
+		}
+	}
+
+	prcm_setup_regs();
+
+	/* Hack to prevent MPU retention when STI console is enabled. */
+	{
+		const struct omap_sti_console_config *sti;
+
+		sti = omap_get_config(OMAP_TAG_STI_CONSOLE,
+				      struct omap_sti_console_config);
+		if (sti != NULL && sti->enable)
+			sti_console_enabled = 1;
+	}
+
+	/*
+	 * We copy the assembler sleep/wakeup routines to SRAM.
+	 * These routines need to be in SRAM as that's the only
+	 * memory the MPU can see when it wakes up.
+	 */
+	if (cpu_is_omap24xx()) {
+		omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
+						 omap24xx_idle_loop_suspend_sz);
+
+		omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
+						    omap24xx_cpu_suspend_sz);
+	}
+
+	suspend_set_ops(&omap_pm_ops);
+	pm_idle = omap2_pm_idle;
+
+	return 0;
+}
+
+late_initcall(omap2_pm_init);
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
new file mode 100644
index 0000000..841d4c5
--- /dev/null
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -0,0 +1,710 @@
+/*
+ * OMAP3 Power Management Routines
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ * Jouni Hogander
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * Based on pm.c for omap1
+ *
+ * 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/pm.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+
+#include <mach/sram.h>
+#include <mach/clockdomain.h>
+#include <mach/powerdomain.h>
+#include <mach/control.h>
+#include <mach/serial.h>
+
+#include "cm.h"
+#include "cm-regbits-34xx.h"
+#include "prm-regbits-34xx.h"
+
+#include "prm.h"
+#include "pm.h"
+
+struct power_state {
+	struct powerdomain *pwrdm;
+	u32 next_state;
+	u32 saved_state;
+	struct list_head node;
+};
+
+static LIST_HEAD(pwrst_list);
+
+static void (*_omap_sram_idle)(u32 *addr, int save_state);
+
+static struct powerdomain *mpu_pwrdm;
+
+/* PRCM Interrupt Handler for wakeups */
+static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
+{
+	u32 wkst, irqstatus_mpu;
+	u32 fclk, iclk;
+
+	/* WKUP */
+	wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST);
+	if (wkst) {
+		iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
+		fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
+		cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_ICLKEN);
+		cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_FCLKEN);
+		prm_write_mod_reg(wkst, WKUP_MOD, PM_WKST);
+		while (prm_read_mod_reg(WKUP_MOD, PM_WKST))
+			cpu_relax();
+		cm_write_mod_reg(iclk, WKUP_MOD, CM_ICLKEN);
+		cm_write_mod_reg(fclk, WKUP_MOD, CM_FCLKEN);
+	}
+
+	/* CORE */
+	wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+	if (wkst) {
+		iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
+		fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+		cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN1);
+		cm_set_mod_reg_bits(wkst, CORE_MOD, CM_FCLKEN1);
+		prm_write_mod_reg(wkst, CORE_MOD, PM_WKST1);
+		while (prm_read_mod_reg(CORE_MOD, PM_WKST1))
+			cpu_relax();
+		cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN1);
+		cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1);
+	}
+	wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
+	if (wkst) {
+		iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
+		fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+		cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN3);
+		cm_set_mod_reg_bits(wkst, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+		prm_write_mod_reg(wkst, CORE_MOD, OMAP3430ES2_PM_WKST3);
+		while (prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3))
+			cpu_relax();
+		cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN3);
+		cm_write_mod_reg(fclk, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+	}
+
+	/* PER */
+	wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
+	if (wkst) {
+		iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
+		fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
+		cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_ICLKEN);
+		cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_FCLKEN);
+		prm_write_mod_reg(wkst, OMAP3430_PER_MOD, PM_WKST);
+		while (prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST))
+			cpu_relax();
+		cm_write_mod_reg(iclk, OMAP3430_PER_MOD, CM_ICLKEN);
+		cm_write_mod_reg(fclk, OMAP3430_PER_MOD, CM_FCLKEN);
+	}
+
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		/* USBHOST */
+		wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
+		if (wkst) {
+			iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+					       CM_ICLKEN);
+			fclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+					       CM_FCLKEN);
+			cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
+					    CM_ICLKEN);
+			cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
+					    CM_FCLKEN);
+			prm_write_mod_reg(wkst, OMAP3430ES2_USBHOST_MOD,
+					  PM_WKST);
+			while (prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+						PM_WKST))
+				cpu_relax();
+			cm_write_mod_reg(iclk, OMAP3430ES2_USBHOST_MOD,
+					 CM_ICLKEN);
+			cm_write_mod_reg(fclk, OMAP3430ES2_USBHOST_MOD,
+					 CM_FCLKEN);
+		}
+	}
+
+	irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
+					 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+	prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
+			  OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+
+	while (prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET))
+		cpu_relax();
+
+	return IRQ_HANDLED;
+}
+
+static void omap_sram_idle(void)
+{
+	/* Variable to tell what needs to be saved and restored
+	 * in omap_sram_idle*/
+	/* save_state = 0 => Nothing to save and restored */
+	/* save_state = 1 => Only L1 and logic lost */
+	/* save_state = 2 => Only L2 lost */
+	/* save_state = 3 => L1, L2 and logic lost */
+	int save_state = 0, mpu_next_state;
+
+	if (!_omap_sram_idle)
+		return;
+
+	mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
+	switch (mpu_next_state) {
+	case PWRDM_POWER_RET:
+		/* No need to save context */
+		save_state = 0;
+		break;
+	default:
+		/* Invalid state */
+		printk(KERN_ERR "Invalid mpu state in sram_idle\n");
+		return;
+	}
+	omap2_gpio_prepare_for_retention();
+	omap_uart_prepare_idle(0);
+	omap_uart_prepare_idle(1);
+	omap_uart_prepare_idle(2);
+
+	_omap_sram_idle(NULL, save_state);
+	cpu_init();
+
+	omap_uart_resume_idle(2);
+	omap_uart_resume_idle(1);
+	omap_uart_resume_idle(0);
+	omap2_gpio_resume_after_retention();
+}
+
+/*
+ * Check if functional clocks are enabled before entering
+ * sleep. This function could be behind CONFIG_PM_DEBUG
+ * when all drivers are configuring their sysconfig registers
+ * properly and using their clocks properly.
+ */
+static int omap3_fclks_active(void)
+{
+	u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0,
+		fck_cam = 0, fck_per = 0, fck_usbhost = 0;
+
+	fck_core1 = cm_read_mod_reg(CORE_MOD,
+				    CM_FCLKEN1);
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		fck_core3 = cm_read_mod_reg(CORE_MOD,
+					    OMAP3430ES2_CM_FCLKEN3);
+		fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD,
+					  CM_FCLKEN);
+		fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+					      CM_FCLKEN);
+	} else
+		fck_sgx = cm_read_mod_reg(GFX_MOD,
+					  OMAP3430ES2_CM_FCLKEN3);
+	fck_dss = cm_read_mod_reg(OMAP3430_DSS_MOD,
+				  CM_FCLKEN);
+	fck_cam = cm_read_mod_reg(OMAP3430_CAM_MOD,
+				  CM_FCLKEN);
+	fck_per = cm_read_mod_reg(OMAP3430_PER_MOD,
+				  CM_FCLKEN);
+
+	/* Ignore UART clocks.  These are handled by UART core (serial.c) */
+	fck_core1 &= ~(OMAP3430_EN_UART1 | OMAP3430_EN_UART2);
+	fck_per &= ~OMAP3430_EN_UART3;
+
+	if (fck_core1 | fck_core3 | fck_sgx | fck_dss |
+	    fck_cam | fck_per | fck_usbhost)
+		return 1;
+	return 0;
+}
+
+static int omap3_can_sleep(void)
+{
+	if (!omap_uart_can_sleep())
+		return 0;
+	if (omap3_fclks_active())
+		return 0;
+	return 1;
+}
+
+/* This sets pwrdm state (other than mpu & core. Currently only ON &
+ * RET are supported. Function is assuming that clkdm doesn't have
+ * hw_sup mode enabled. */
+static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
+{
+	u32 cur_state;
+	int sleep_switch = 0;
+	int ret = 0;
+
+	if (pwrdm == NULL || IS_ERR(pwrdm))
+		return -EINVAL;
+
+	while (!(pwrdm->pwrsts & (1 << state))) {
+		if (state == PWRDM_POWER_OFF)
+			return ret;
+		state--;
+	}
+
+	cur_state = pwrdm_read_next_pwrst(pwrdm);
+	if (cur_state == state)
+		return ret;
+
+	if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
+		omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
+		sleep_switch = 1;
+		pwrdm_wait_transition(pwrdm);
+	}
+
+	ret = pwrdm_set_next_pwrst(pwrdm, state);
+	if (ret) {
+		printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
+		       pwrdm->name);
+		goto err;
+	}
+
+	if (sleep_switch) {
+		omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+		pwrdm_wait_transition(pwrdm);
+	}
+
+err:
+	return ret;
+}
+
+static void omap3_pm_idle(void)
+{
+	local_irq_disable();
+	local_fiq_disable();
+
+	if (!omap3_can_sleep())
+		goto out;
+
+	if (omap_irq_pending())
+		goto out;
+
+	omap_sram_idle();
+
+out:
+	local_fiq_enable();
+	local_irq_enable();
+}
+
+static int omap3_pm_prepare(void)
+{
+	disable_hlt();
+	return 0;
+}
+
+static int omap3_pm_suspend(void)
+{
+	struct power_state *pwrst;
+	int state, ret = 0;
+
+	/* Read current next_pwrsts */
+	list_for_each_entry(pwrst, &pwrst_list, node)
+		pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
+	/* Set ones wanted by suspend */
+	list_for_each_entry(pwrst, &pwrst_list, node) {
+		if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
+			goto restore;
+		if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
+			goto restore;
+	}
+
+	omap_uart_prepare_suspend();
+	omap_sram_idle();
+
+restore:
+	/* Restore next_pwrsts */
+	list_for_each_entry(pwrst, &pwrst_list, node) {
+		set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
+		state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
+		if (state > pwrst->next_state) {
+			printk(KERN_INFO "Powerdomain (%s) didn't enter "
+			       "target state %d\n",
+			       pwrst->pwrdm->name, pwrst->next_state);
+			ret = -1;
+		}
+	}
+	if (ret)
+		printk(KERN_ERR "Could not enter target state in pm_suspend\n");
+	else
+		printk(KERN_INFO "Successfully put all powerdomains "
+		       "to target state\n");
+
+	return ret;
+}
+
+static int omap3_pm_enter(suspend_state_t state)
+{
+	int ret = 0;
+
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		ret = omap3_pm_suspend();
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void omap3_pm_finish(void)
+{
+	enable_hlt();
+}
+
+static struct platform_suspend_ops omap_pm_ops = {
+	.prepare	= omap3_pm_prepare,
+	.enter		= omap3_pm_enter,
+	.finish		= omap3_pm_finish,
+	.valid		= suspend_valid_only_mem,
+};
+
+
+/**
+ * omap3_iva_idle(): ensure IVA is in idle so it can be put into
+ *                   retention
+ *
+ * In cases where IVA2 is activated by bootcode, it may prevent
+ * full-chip retention or off-mode because it is not idle.  This
+ * function forces the IVA2 into idle state so it can go
+ * into retention/off and thus allow full-chip retention/off.
+ *
+ **/
+static void __init omap3_iva_idle(void)
+{
+	/* ensure IVA2 clock is disabled */
+	cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
+
+	/* if no clock activity, nothing else to do */
+	if (!(cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) &
+	      OMAP3430_CLKACTIVITY_IVA2_MASK))
+		return;
+
+	/* Reset IVA2 */
+	prm_write_mod_reg(OMAP3430_RST1_IVA2 |
+			  OMAP3430_RST2_IVA2 |
+			  OMAP3430_RST3_IVA2,
+			  OMAP3430_IVA2_MOD, RM_RSTCTRL);
+
+	/* Enable IVA2 clock */
+	cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2,
+			 OMAP3430_IVA2_MOD, CM_FCLKEN);
+
+	/* Set IVA2 boot mode to 'idle' */
+	omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE,
+			 OMAP343X_CONTROL_IVA2_BOOTMOD);
+
+	/* Un-reset IVA2 */
+	prm_write_mod_reg(0, OMAP3430_IVA2_MOD, RM_RSTCTRL);
+
+	/* Disable IVA2 clock */
+	cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
+
+	/* Reset IVA2 */
+	prm_write_mod_reg(OMAP3430_RST1_IVA2 |
+			  OMAP3430_RST2_IVA2 |
+			  OMAP3430_RST3_IVA2,
+			  OMAP3430_IVA2_MOD, RM_RSTCTRL);
+}
+
+static void __init omap3_d2d_idle(void)
+{
+	u16 mask, padconf;
+
+	/* In a stand alone OMAP3430 where there is not a stacked
+	 * modem for the D2D Idle Ack and D2D MStandby must be pulled
+	 * high. S CONTROL_PADCONF_SAD2D_IDLEACK and
+	 * CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. */
+	mask = (1 << 4) | (1 << 3); /* pull-up, enabled */
+	padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY);
+	padconf |= mask;
+	omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY);
+
+	padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK);
+	padconf |= mask;
+	omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK);
+
+	/* reset modem */
+	prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
+			  OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
+			  CORE_MOD, RM_RSTCTRL);
+	prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL);
+}
+
+static void __init prcm_setup_regs(void)
+{
+	/* XXX Reset all wkdeps. This should be done when initializing
+	 * powerdomains */
+	prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
+	prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP);
+		prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
+	} else
+		prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
+
+	/*
+	 * Enable interface clock autoidle for all modules.
+	 * Note that in the long run this should be done by clockfw
+	 */
+	cm_write_mod_reg(
+		OMAP3430_AUTO_MODEM |
+		OMAP3430ES2_AUTO_MMC3 |
+		OMAP3430ES2_AUTO_ICR |
+		OMAP3430_AUTO_AES2 |
+		OMAP3430_AUTO_SHA12 |
+		OMAP3430_AUTO_DES2 |
+		OMAP3430_AUTO_MMC2 |
+		OMAP3430_AUTO_MMC1 |
+		OMAP3430_AUTO_MSPRO |
+		OMAP3430_AUTO_HDQ |
+		OMAP3430_AUTO_MCSPI4 |
+		OMAP3430_AUTO_MCSPI3 |
+		OMAP3430_AUTO_MCSPI2 |
+		OMAP3430_AUTO_MCSPI1 |
+		OMAP3430_AUTO_I2C3 |
+		OMAP3430_AUTO_I2C2 |
+		OMAP3430_AUTO_I2C1 |
+		OMAP3430_AUTO_UART2 |
+		OMAP3430_AUTO_UART1 |
+		OMAP3430_AUTO_GPT11 |
+		OMAP3430_AUTO_GPT10 |
+		OMAP3430_AUTO_MCBSP5 |
+		OMAP3430_AUTO_MCBSP1 |
+		OMAP3430ES1_AUTO_FAC | /* This is es1 only */
+		OMAP3430_AUTO_MAILBOXES |
+		OMAP3430_AUTO_OMAPCTRL |
+		OMAP3430ES1_AUTO_FSHOSTUSB |
+		OMAP3430_AUTO_HSOTGUSB |
+		OMAP3430_AUTO_SAD2D |
+		OMAP3430_AUTO_SSI,
+		CORE_MOD, CM_AUTOIDLE1);
+
+	cm_write_mod_reg(
+		OMAP3430_AUTO_PKA |
+		OMAP3430_AUTO_AES1 |
+		OMAP3430_AUTO_RNG |
+		OMAP3430_AUTO_SHA11 |
+		OMAP3430_AUTO_DES1,
+		CORE_MOD, CM_AUTOIDLE2);
+
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		cm_write_mod_reg(
+			OMAP3430_AUTO_MAD2D |
+			OMAP3430ES2_AUTO_USBTLL,
+			CORE_MOD, CM_AUTOIDLE3);
+	}
+
+	cm_write_mod_reg(
+		OMAP3430_AUTO_WDT2 |
+		OMAP3430_AUTO_WDT1 |
+		OMAP3430_AUTO_GPIO1 |
+		OMAP3430_AUTO_32KSYNC |
+		OMAP3430_AUTO_GPT12 |
+		OMAP3430_AUTO_GPT1 ,
+		WKUP_MOD, CM_AUTOIDLE);
+
+	cm_write_mod_reg(
+		OMAP3430_AUTO_DSS,
+		OMAP3430_DSS_MOD,
+		CM_AUTOIDLE);
+
+	cm_write_mod_reg(
+		OMAP3430_AUTO_CAM,
+		OMAP3430_CAM_MOD,
+		CM_AUTOIDLE);
+
+	cm_write_mod_reg(
+		OMAP3430_AUTO_GPIO6 |
+		OMAP3430_AUTO_GPIO5 |
+		OMAP3430_AUTO_GPIO4 |
+		OMAP3430_AUTO_GPIO3 |
+		OMAP3430_AUTO_GPIO2 |
+		OMAP3430_AUTO_WDT3 |
+		OMAP3430_AUTO_UART3 |
+		OMAP3430_AUTO_GPT9 |
+		OMAP3430_AUTO_GPT8 |
+		OMAP3430_AUTO_GPT7 |
+		OMAP3430_AUTO_GPT6 |
+		OMAP3430_AUTO_GPT5 |
+		OMAP3430_AUTO_GPT4 |
+		OMAP3430_AUTO_GPT3 |
+		OMAP3430_AUTO_GPT2 |
+		OMAP3430_AUTO_MCBSP4 |
+		OMAP3430_AUTO_MCBSP3 |
+		OMAP3430_AUTO_MCBSP2,
+		OMAP3430_PER_MOD,
+		CM_AUTOIDLE);
+
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		cm_write_mod_reg(
+			OMAP3430ES2_AUTO_USBHOST,
+			OMAP3430ES2_USBHOST_MOD,
+			CM_AUTOIDLE);
+	}
+
+	/*
+	 * Set all plls to autoidle. This is needed until autoidle is
+	 * enabled by clockfw
+	 */
+	cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
+			 OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
+	cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT,
+			 MPU_MOD,
+			 CM_AUTOIDLE2);
+	cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) |
+			 (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT),
+			 PLL_MOD,
+			 CM_AUTOIDLE);
+	cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT,
+			 PLL_MOD,
+			 CM_AUTOIDLE2);
+
+	/*
+	 * Enable control of expternal oscillator through
+	 * sys_clkreq. In the long run clock framework should
+	 * take care of this.
+	 */
+	prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK,
+			     1 << OMAP_AUTOEXTCLKMODE_SHIFT,
+			     OMAP3430_GR_MOD,
+			     OMAP3_PRM_CLKSRC_CTRL_OFFSET);
+
+	/* setup wakup source */
+	prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 |
+			  OMAP3430_EN_GPT1 | OMAP3430_EN_GPT12,
+			  WKUP_MOD, PM_WKEN);
+	/* No need to write EN_IO, that is always enabled */
+	prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1 |
+			  OMAP3430_EN_GPT12,
+			  WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
+	/* For some reason IO doesn't generate wakeup event even if
+	 * it is selected to mpu wakeup goup */
+	prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
+			  OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+
+	/* Don't attach IVA interrupts */
+	prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
+	prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
+	prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
+	prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
+
+	/* Clear any pending 'reset' flags */
+	prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
+	prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
+	prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST);
+	prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST);
+	prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST);
+	prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST);
+	prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST);
+
+	/* Clear any pending PRCM interrupts */
+	prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+
+	omap3_iva_idle();
+	omap3_d2d_idle();
+}
+
+static int __init pwrdms_setup(struct powerdomain *pwrdm)
+{
+	struct power_state *pwrst;
+
+	if (!pwrdm->pwrsts)
+		return 0;
+
+	pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL);
+	if (!pwrst)
+		return -ENOMEM;
+	pwrst->pwrdm = pwrdm;
+	pwrst->next_state = PWRDM_POWER_RET;
+	list_add(&pwrst->node, &pwrst_list);
+
+	if (pwrdm_has_hdwr_sar(pwrdm))
+		pwrdm_enable_hdwr_sar(pwrdm);
+
+	return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+}
+
+/*
+ * 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)
+{
+	if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
+		omap2_clkdm_allow_idle(clkdm);
+	else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
+		 atomic_read(&clkdm->usecount) == 0)
+		omap2_clkdm_sleep(clkdm);
+	return 0;
+}
+
+int __init omap3_pm_init(void)
+{
+	struct power_state *pwrst, *tmp;
+	int ret;
+
+	if (!cpu_is_omap34xx())
+		return -ENODEV;
+
+	printk(KERN_ERR "Power Management for TI OMAP3.\n");
+
+	/* XXX prcm_setup_regs needs to be before enabling hw
+	 * supervised mode for powerdomains */
+	prcm_setup_regs();
+
+	ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
+			  (irq_handler_t)prcm_interrupt_handler,
+			  IRQF_DISABLED, "prcm", NULL);
+	if (ret) {
+		printk(KERN_ERR "request_irq failed to register for 0x%x\n",
+		       INT_34XX_PRCM_MPU_IRQ);
+		goto err1;
+	}
+
+	ret = pwrdm_for_each(pwrdms_setup);
+	if (ret) {
+		printk(KERN_ERR "Failed to setup powerdomains\n");
+		goto err2;
+	}
+
+	(void) clkdm_for_each(clkdms_setup);
+
+	mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+	if (mpu_pwrdm == NULL) {
+		printk(KERN_ERR "Failed to get mpu_pwrdm\n");
+		goto err2;
+	}
+
+	_omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
+					 omap34xx_cpu_suspend_sz);
+
+	suspend_set_ops(&omap_pm_ops);
+
+	pm_idle = omap3_pm_idle;
+
+err1:
+	return ret;
+err2:
+	free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
+	list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
+		list_del(&pwrst->node);
+		kfree(pwrst);
+	}
+	return ret;
+}
+
+late_initcall(omap3_pm_init);
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index 812d50e..cb1ae84 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -276,6 +276,8 @@
 /* CM_FCLKEN_WKUP, CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */
 #define OMAP3430_EN_GPIO1				(1 << 3)
 #define OMAP3430_EN_GPIO1_SHIFT				3
+#define OMAP3430_EN_GPT12				(1 << 1)
+#define OMAP3430_EN_GPT12_SHIFT				1
 #define OMAP3430_EN_GPT1				(1 << 0)
 #define OMAP3430_EN_GPT1_SHIFT				0
 
diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h
index 826d326..9937e28 100644
--- a/arch/arm/mach-omap2/prm.h
+++ b/arch/arm/mach-omap2/prm.h
@@ -16,17 +16,12 @@
 
 #include "prcm-common.h"
 
-#ifndef __ASSEMBLER__
-#define OMAP_PRM_REGADDR(module, reg)					\
-			IO_ADDRESS(OMAP2_PRM_BASE + (module) + (reg))
-#else
 #define OMAP2420_PRM_REGADDR(module, reg)				\
 			IO_ADDRESS(OMAP2420_PRM_BASE + (module) + (reg))
 #define OMAP2430_PRM_REGADDR(module, reg)				\
 			IO_ADDRESS(OMAP2430_PRM_BASE + (module) + (reg))
 #define OMAP34XX_PRM_REGADDR(module, reg)				\
 			IO_ADDRESS(OMAP3430_PRM_BASE + (module) + (reg))
-#endif
 
 /*
  * Architecture-specific global PRM registers
@@ -38,80 +33,132 @@
  *
  */
 
-/* Global 24xx registers in GR_MOD (Same as OCP_MOD for 24xx) */
-#define OMAP24XX_PRCM_VOLTCTRL_OFFSET		0x0050
-#define OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET	0x0080
+#define OMAP2_PRCM_REVISION_OFFSET	0x0000
+#define OMAP2420_PRCM_REVISION		OMAP2420_PRM_REGADDR(OCP_MOD, 0x0000)
+#define OMAP2_PRCM_SYSCONFIG_OFFSET	0x0010
+#define OMAP2420_PRCM_SYSCONFIG		OMAP2420_PRM_REGADDR(OCP_MOD, 0x0010)
 
-/* 242x GR_MOD registers, use these only for assembly code */
-#define OMAP242X_PRCM_VOLTCTRL		OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD,	\
-						OMAP24XX_PRCM_VOLTCTRL_OFFSET)
-#define OMAP242X_PRCM_CLKCFG_CTRL	OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD,	\
-						OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET)
+#define OMAP2_PRCM_IRQSTATUS_MPU_OFFSET	0x0018
+#define OMAP2420_PRCM_IRQSTATUS_MPU	OMAP2420_PRM_REGADDR(OCP_MOD, 0x0018)
+#define OMAP2_PRCM_IRQENABLE_MPU_OFFSET	0x001c
+#define OMAP2420_PRCM_IRQENABLE_MPU	OMAP2420_PRM_REGADDR(OCP_MOD, 0x001c)
 
-/* 243x GR_MOD registers, use these only for assembly code */
-#define OMAP243X_PRCM_VOLTCTRL		OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD,	\
-						OMAP24XX_PRCM_VOLTCTRL_OFFSET)
-#define OMAP243X_PRCM_CLKCFG_CTRL	OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD,	\
-						OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET)
+#define OMAP2_PRCM_VOLTCTRL_OFFSET	0x0050
+#define OMAP2420_PRCM_VOLTCTRL		OMAP2420_PRM_REGADDR(OCP_MOD, 0x0050)
+#define OMAP2_PRCM_VOLTST_OFFSET	0x0054
+#define OMAP2420_PRCM_VOLTST		OMAP2420_PRM_REGADDR(OCP_MOD, 0x0054)
+#define OMAP2_PRCM_CLKSRC_CTRL_OFFSET	0x0060
+#define OMAP2420_PRCM_CLKSRC_CTRL	OMAP2420_PRM_REGADDR(OCP_MOD, 0x0060)
+#define OMAP2_PRCM_CLKOUT_CTRL_OFFSET	0x0070
+#define OMAP2420_PRCM_CLKOUT_CTRL	OMAP2420_PRM_REGADDR(OCP_MOD, 0x0070)
+#define OMAP2_PRCM_CLKEMUL_CTRL_OFFSET	0x0078
+#define OMAP2420_PRCM_CLKEMUL_CTRL	OMAP2420_PRM_REGADDR(OCP_MOD, 0x0078)
+#define OMAP2_PRCM_CLKCFG_CTRL_OFFSET	0x0080
+#define OMAP2420_PRCM_CLKCFG_CTRL	OMAP2420_PRM_REGADDR(OCP_MOD, 0x0080)
+#define OMAP2_PRCM_CLKCFG_STATUS_OFFSET	0x0084
+#define OMAP2420_PRCM_CLKCFG_STATUS	OMAP2420_PRM_REGADDR(OCP_MOD, 0x0084)
+#define OMAP2_PRCM_VOLTSETUP_OFFSET	0x0090
+#define OMAP2420_PRCM_VOLTSETUP		OMAP2420_PRM_REGADDR(OCP_MOD, 0x0090)
+#define OMAP2_PRCM_CLKSSETUP_OFFSET	0x0094
+#define OMAP2420_PRCM_CLKSSETUP		OMAP2420_PRM_REGADDR(OCP_MOD, 0x0094)
+#define OMAP2_PRCM_POLCTRL_OFFSET	0x0098
+#define OMAP2420_PRCM_POLCTRL		OMAP2420_PRM_REGADDR(OCP_MOD, 0x0098)
 
-/* These will disappear */
-#define OMAP24XX_PRCM_REVISION		OMAP_PRM_REGADDR(OCP_MOD, 0x0000)
-#define OMAP24XX_PRCM_SYSCONFIG		OMAP_PRM_REGADDR(OCP_MOD, 0x0010)
+#define OMAP2430_PRCM_REVISION		OMAP2430_PRM_REGADDR(OCP_MOD, 0x0000)
+#define OMAP2430_PRCM_SYSCONFIG		OMAP2430_PRM_REGADDR(OCP_MOD, 0x0010)
 
-#define OMAP24XX_PRCM_IRQSTATUS_MPU	OMAP_PRM_REGADDR(OCP_MOD, 0x0018)
-#define OMAP24XX_PRCM_IRQENABLE_MPU	OMAP_PRM_REGADDR(OCP_MOD, 0x001c)
+#define OMAP2430_PRCM_IRQSTATUS_MPU	OMAP2430_PRM_REGADDR(OCP_MOD, 0x0018)
+#define OMAP2430_PRCM_IRQENABLE_MPU	OMAP2430_PRM_REGADDR(OCP_MOD, 0x001c)
 
-#define OMAP24XX_PRCM_VOLTST		OMAP_PRM_REGADDR(OCP_MOD, 0x0054)
-#define OMAP24XX_PRCM_CLKSRC_CTRL	OMAP_PRM_REGADDR(OCP_MOD, 0x0060)
-#define OMAP24XX_PRCM_CLKOUT_CTRL	OMAP_PRM_REGADDR(OCP_MOD, 0x0070)
-#define OMAP24XX_PRCM_CLKEMUL_CTRL	OMAP_PRM_REGADDR(OCP_MOD, 0x0078)
-#define OMAP24XX_PRCM_CLKCFG_CTRL	OMAP_PRM_REGADDR(OCP_MOD, 0x0080)
-#define OMAP24XX_PRCM_CLKCFG_STATUS	OMAP_PRM_REGADDR(OCP_MOD, 0x0084)
-#define OMAP24XX_PRCM_VOLTSETUP		OMAP_PRM_REGADDR(OCP_MOD, 0x0090)
-#define OMAP24XX_PRCM_CLKSSETUP		OMAP_PRM_REGADDR(OCP_MOD, 0x0094)
-#define OMAP24XX_PRCM_POLCTRL		OMAP_PRM_REGADDR(OCP_MOD, 0x0098)
+#define OMAP2430_PRCM_VOLTCTRL		OMAP2430_PRM_REGADDR(OCP_MOD, 0x0050)
+#define OMAP2430_PRCM_VOLTST		OMAP2430_PRM_REGADDR(OCP_MOD, 0x0054)
+#define OMAP2430_PRCM_CLKSRC_CTRL	OMAP2430_PRM_REGADDR(OCP_MOD, 0x0060)
+#define OMAP2430_PRCM_CLKOUT_CTRL	OMAP2430_PRM_REGADDR(OCP_MOD, 0x0070)
+#define OMAP2430_PRCM_CLKEMUL_CTRL	OMAP2430_PRM_REGADDR(OCP_MOD, 0x0078)
+#define OMAP2430_PRCM_CLKCFG_CTRL	OMAP2430_PRM_REGADDR(OCP_MOD, 0x0080)
+#define OMAP2430_PRCM_CLKCFG_STATUS	OMAP2430_PRM_REGADDR(OCP_MOD, 0x0084)
+#define OMAP2430_PRCM_VOLTSETUP		OMAP2430_PRM_REGADDR(OCP_MOD, 0x0090)
+#define OMAP2430_PRCM_CLKSSETUP		OMAP2430_PRM_REGADDR(OCP_MOD, 0x0094)
+#define OMAP2430_PRCM_POLCTRL		OMAP2430_PRM_REGADDR(OCP_MOD, 0x0098)
 
-#define OMAP3430_PRM_REVISION		OMAP_PRM_REGADDR(OCP_MOD, 0x0004)
-#define OMAP3430_PRM_SYSCONFIG		OMAP_PRM_REGADDR(OCP_MOD, 0x0014)
+#define OMAP3_PRM_REVISION_OFFSET	0x0004
+#define OMAP3430_PRM_REVISION		OMAP34XX_PRM_REGADDR(OCP_MOD, 0x0004)
+#define OMAP3_PRM_SYSCONFIG_OFFSET	0x0014
+#define OMAP3430_PRM_SYSCONFIG		OMAP34XX_PRM_REGADDR(OCP_MOD, 0x0014)
 
-#define OMAP3430_PRM_IRQSTATUS_MPU	OMAP_PRM_REGADDR(OCP_MOD, 0x0018)
-#define OMAP3430_PRM_IRQENABLE_MPU	OMAP_PRM_REGADDR(OCP_MOD, 0x001c)
+#define OMAP3_PRM_IRQSTATUS_MPU_OFFSET	0x0018
+#define OMAP3430_PRM_IRQSTATUS_MPU	OMAP34XX_PRM_REGADDR(OCP_MOD, 0x0018)
+#define OMAP3_PRM_IRQENABLE_MPU_OFFSET	0x001c
+#define OMAP3430_PRM_IRQENABLE_MPU	OMAP34XX_PRM_REGADDR(OCP_MOD, 0x001c)
 
 
-#define OMAP3430_PRM_VC_SMPS_SA		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0020)
-#define OMAP3430_PRM_VC_SMPS_VOL_RA	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0024)
-#define OMAP3430_PRM_VC_SMPS_CMD_RA	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0028)
-#define OMAP3430_PRM_VC_CMD_VAL_0	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x002c)
-#define OMAP3430_PRM_VC_CMD_VAL_1	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0030)
-#define OMAP3430_PRM_VC_CH_CONF		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0034)
-#define OMAP3430_PRM_VC_I2C_CFG		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0038)
-#define OMAP3430_PRM_VC_BYPASS_VAL	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x003c)
-#define OMAP3430_PRM_RSTCTRL		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0050)
-#define OMAP3430_PRM_RSTTIME		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0054)
-#define OMAP3430_PRM_RSTST		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0058)
-#define OMAP3430_PRM_VOLTCTRL		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0060)
-#define OMAP3430_PRM_SRAM_PCHARGE	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0064)
-#define OMAP3430_PRM_CLKSRC_CTRL	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0070)
-#define OMAP3430_PRM_VOLTSETUP1		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0090)
-#define OMAP3430_PRM_VOLTOFFSET		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0094)
-#define OMAP3430_PRM_CLKSETUP		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0098)
-#define OMAP3430_PRM_POLCTRL		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x009c)
-#define OMAP3430_PRM_VOLTSETUP2		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00a0)
-#define OMAP3430_PRM_VP1_CONFIG		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b0)
-#define OMAP3430_PRM_VP1_VSTEPMIN	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b4)
-#define OMAP3430_PRM_VP1_VSTEPMAX	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b8)
-#define OMAP3430_PRM_VP1_VLIMITTO	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00bc)
-#define OMAP3430_PRM_VP1_VOLTAGE	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c0)
-#define OMAP3430_PRM_VP1_STATUS		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c4)
-#define OMAP3430_PRM_VP2_CONFIG		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d0)
-#define OMAP3430_PRM_VP2_VSTEPMIN	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d4)
-#define OMAP3430_PRM_VP2_VSTEPMAX	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d8)
-#define OMAP3430_PRM_VP2_VLIMITTO	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00dc)
-#define OMAP3430_PRM_VP2_VOLTAGE	OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e0)
-#define OMAP3430_PRM_VP2_STATUS		OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e4)
+#define OMAP3_PRM_VC_SMPS_SA_OFFSET	0x0020
+#define OMAP3430_PRM_VC_SMPS_SA		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0020)
+#define OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET	0x0024
+#define OMAP3430_PRM_VC_SMPS_VOL_RA	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0024)
+#define OMAP3_PRM_VC_SMPS_CMD_RA_OFFSET	0x0028
+#define OMAP3430_PRM_VC_SMPS_CMD_RA	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0028)
+#define OMAP3_PRM_VC_CMD_VAL_0_OFFSET	0x002c
+#define OMAP3430_PRM_VC_CMD_VAL_0	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x002c)
+#define OMAP3_PRM_VC_CMD_VAL_1_OFFSET	0x0030
+#define OMAP3430_PRM_VC_CMD_VAL_1	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0030)
+#define OMAP3_PRM_VC_CH_CONF_OFFSET	0x0034
+#define OMAP3430_PRM_VC_CH_CONF		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0034)
+#define OMAP3_PRM_VC_I2C_CFG_OFFSET	0x0038
+#define OMAP3430_PRM_VC_I2C_CFG		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0038)
+#define OMAP3_PRM_VC_BYPASS_VAL_OFFSET	0x003c
+#define OMAP3430_PRM_VC_BYPASS_VAL	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x003c)
+#define OMAP3_PRM_RSTCTRL_OFFSET	0x0050
+#define OMAP3430_PRM_RSTCTRL		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0050)
+#define OMAP3_PRM_RSTTIME_OFFSET	0x0054
+#define OMAP3430_PRM_RSTTIME		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0054)
+#define OMAP3_PRM_RSTST_OFFSET	0x0058
+#define OMAP3430_PRM_RSTST		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0058)
+#define OMAP3_PRM_VOLTCTRL_OFFSET	0x0060
+#define OMAP3430_PRM_VOLTCTRL		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0060)
+#define OMAP3_PRM_SRAM_PCHARGE_OFFSET	0x0064
+#define OMAP3430_PRM_SRAM_PCHARGE	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0064)
+#define OMAP3_PRM_CLKSRC_CTRL_OFFSET	0x0070
+#define OMAP3430_PRM_CLKSRC_CTRL	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0070)
+#define OMAP3_PRM_VOLTSETUP1_OFFSET	0x0090
+#define OMAP3430_PRM_VOLTSETUP1		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0090)
+#define OMAP3_PRM_VOLTOFFSET_OFFSET	0x0094
+#define OMAP3430_PRM_VOLTOFFSET		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0094)
+#define OMAP3_PRM_CLKSETUP_OFFSET	0x0098
+#define OMAP3430_PRM_CLKSETUP		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0098)
+#define OMAP3_PRM_POLCTRL_OFFSET	0x009c
+#define OMAP3430_PRM_POLCTRL		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x009c)
+#define OMAP3_PRM_VOLTSETUP2_OFFSET	0x00a0
+#define OMAP3430_PRM_VOLTSETUP2		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00a0)
+#define OMAP3_PRM_VP1_CONFIG_OFFSET	0x00b0
+#define OMAP3430_PRM_VP1_CONFIG		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b0)
+#define OMAP3_PRM_VP1_VSTEPMIN_OFFSET	0x00b4
+#define OMAP3430_PRM_VP1_VSTEPMIN	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b4)
+#define OMAP3_PRM_VP1_VSTEPMAX_OFFSET	0x00b8
+#define OMAP3430_PRM_VP1_VSTEPMAX	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b8)
+#define OMAP3_PRM_VP1_VLIMITTO_OFFSET	0x00bc
+#define OMAP3430_PRM_VP1_VLIMITTO	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00bc)
+#define OMAP3_PRM_VP1_VOLTAGE_OFFSET	0x00c0
+#define OMAP3430_PRM_VP1_VOLTAGE	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c0)
+#define OMAP3_PRM_VP1_STATUS_OFFSET	0x00c4
+#define OMAP3430_PRM_VP1_STATUS		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c4)
+#define OMAP3_PRM_VP2_CONFIG_OFFSET	0x00d0
+#define OMAP3430_PRM_VP2_CONFIG		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d0)
+#define OMAP3_PRM_VP2_VSTEPMIN_OFFSET	0x00d4
+#define OMAP3430_PRM_VP2_VSTEPMIN	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d4)
+#define OMAP3_PRM_VP2_VSTEPMAX_OFFSET	0x00d8
+#define OMAP3430_PRM_VP2_VSTEPMAX	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d8)
+#define OMAP3_PRM_VP2_VLIMITTO_OFFSET	0x00dc
+#define OMAP3430_PRM_VP2_VLIMITTO	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00dc)
+#define OMAP3_PRM_VP2_VOLTAGE_OFFSET	0x00e0
+#define OMAP3430_PRM_VP2_VOLTAGE	OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e0)
+#define OMAP3_PRM_VP2_STATUS_OFFSET	0x00e4
+#define OMAP3430_PRM_VP2_STATUS		OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e4)
 
-#define OMAP3430_PRM_CLKSEL		OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0040)
-#define OMAP3430_PRM_CLKOUT_CTRL	OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
+#define OMAP3_PRM_CLKSEL_OFFSET	0x0040
+#define OMAP3430_PRM_CLKSEL		OMAP34XX_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0040)
+#define OMAP3_PRM_CLKOUT_CTRL_OFFSET	0x0070
+#define OMAP3430_PRM_CLKOUT_CTRL	OMAP34XX_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
 
 /*
  * Module specific PRM registers from PRM_BASE + domain offset
@@ -156,9 +203,11 @@
 
 #define OMAP3430_PM_MPUGRPSEL				0x00a4
 #define OMAP3430_PM_MPUGRPSEL1				OMAP3430_PM_MPUGRPSEL
+#define OMAP3430ES2_PM_MPUGRPSEL3			0x00f8
 
 #define OMAP3430_PM_IVAGRPSEL				0x00a8
 #define OMAP3430_PM_IVAGRPSEL1				OMAP3430_PM_IVAGRPSEL
+#define OMAP3430ES2_PM_IVAGRPSEL3			0x00f4
 
 #define OMAP3430_PM_PREPWSTST				0x00e8
 
diff --git a/arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h b/arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h
new file mode 100644
index 0000000..02e1c2d
--- /dev/null
+++ b/arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h
@@ -0,0 +1,55 @@
+/*
+ * SDRC register values for the Micron MT46H32M32LF-6
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Paul Walmsley
+ *
+ * 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_OMAP2_SDRAM_MICRON_MT46H32M32LF
+#define ARCH_ARM_MACH_OMAP2_SDRAM_MICRON_MT46H32M32LF
+
+#include <mach/sdrc.h>
+
+/* Micron MT46H32M32LF-6 */
+/* XXX Using ARE = 0x1 (no autorefresh burst) -- can this be changed? */
+static struct omap_sdrc_params mt46h32m32lf6_sdrc_params[] = {
+	[0] = {
+		.rate	     = 166000000,
+		.actim_ctrla = 0x9a9db4c6,
+		.actim_ctrlb = 0x00011217,
+		.rfr_ctrl    = 0x0004dc01,
+		.mr	     = 0x00000032,
+	},
+	[1] = {
+		.rate	     = 165941176,
+		.actim_ctrla = 0x9a9db4c6,
+		.actim_ctrlb = 0x00011217,
+		.rfr_ctrl    = 0x0004dc01,
+		.mr	     = 0x00000032,
+	},
+	[2] = {
+		.rate	     = 83000000,
+		.actim_ctrla = 0x51512283,
+		.actim_ctrlb = 0x0001120c,
+		.rfr_ctrl    = 0x00025501,
+		.mr	     = 0x00000032,
+	},
+	[3] = {
+		.rate	     = 82970588,
+		.actim_ctrla = 0x51512283,
+		.actim_ctrlb = 0x0001120c,
+		.rfr_ctrl    = 0x00025501,
+		.mr	     = 0x00000032,
+	},
+	[4] = {
+		.rate	     = 0
+	},
+};
+
+#endif
diff --git a/arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h b/arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h
new file mode 100644
index 0000000..3751d29
--- /dev/null
+++ b/arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h
@@ -0,0 +1,54 @@
+/*
+ * SDRC register values for the Qimonda HYB18M512160AF-6
+ *
+ * Copyright (C) 2008-2009 Texas Instruments, Inc.
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Paul Walmsley
+ *
+ * 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_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6
+#define ARCH_ARM_MACH_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6
+
+#include <mach/sdrc.h>
+
+/* Qimonda HYB18M512160AF-6 */
+static struct omap_sdrc_params hyb18m512160af6_sdrc_params[] = {
+	[0] = {
+		.rate	     = 166000000,
+		.actim_ctrla = 0x629db4c6,
+		.actim_ctrlb = 0x00012214,
+		.rfr_ctrl    = 0x0004dc01,
+		.mr	     = 0x00000032,
+	},
+	[1] = {
+		.rate	     = 165941176,
+		.actim_ctrla = 0x629db4c6,
+		.actim_ctrlb = 0x00012214,
+		.rfr_ctrl    = 0x0004dc01,
+		.mr	     = 0x00000032,
+	},
+	[2] = {
+		.rate	     = 83000000,
+		.actim_ctrla = 0x31512283,
+		.actim_ctrlb = 0x0001220a,
+		.rfr_ctrl    = 0x00025501,
+		.mr	     = 0x00000022,
+	},
+	[3] = {
+		.rate	     = 82970588,
+		.actim_ctrla = 0x31512283,
+		.actim_ctrlb = 0x0001220a,
+		.rfr_ctrl    = 0x00025501,
+		.mr	     = 0x00000022,
+	},
+	[4] = {
+		.rate	     = 0
+	},
+};
+
+#endif
diff --git a/arch/arm/mach-omap2/sdrc.c b/arch/arm/mach-omap2/sdrc.c
index 2a30060..2045441 100644
--- a/arch/arm/mach-omap2/sdrc.c
+++ b/arch/arm/mach-omap2/sdrc.c
@@ -37,6 +37,10 @@
 void __iomem *omap2_sdrc_base;
 void __iomem *omap2_sms_base;
 
+/* SDRC_POWER register bits */
+#define SDRC_POWER_EXTCLKDIS_SHIFT		3
+#define SDRC_POWER_PWDENA_SHIFT			2
+#define SDRC_POWER_PAGEPOLICY_SHIFT		0
 
 /**
  * omap2_sdrc_get_params - return SDRC register values for a given clock rate
@@ -56,9 +60,12 @@
 {
 	struct omap_sdrc_params *sp;
 
+	if (!sdrc_init_params)
+		return NULL;
+
 	sp = sdrc_init_params;
 
-	while (sp->rate != r)
+	while (sp->rate && sp->rate != r)
 		sp++;
 
 	if (!sp->rate)
@@ -74,7 +81,14 @@
 	omap2_sms_base = omap2_globals->sms;
 }
 
-/* turn on smart idle modes for SDRAM scheduler and controller */
+/**
+ * omap2_sdrc_init - initialize SMS, SDRC devices on boot
+ * @sp: pointer to a null-terminated list of struct omap_sdrc_params
+ *
+ * Turn on smart idle modes for SDRAM scheduler and controller.
+ * Program a known-good configuration for the SDRC to deal with buggy
+ * bootloaders.
+ */
 void __init omap2_sdrc_init(struct omap_sdrc_params *sp)
 {
 	u32 l;
@@ -90,4 +104,10 @@
 	sdrc_write_reg(l, SDRC_SYSCONFIG);
 
 	sdrc_init_params = sp;
+
+	/* XXX Enable SRFRONIDLEREQ here also? */
+	l = (1 << SDRC_POWER_EXTCLKDIS_SHIFT) |
+		(1 << SDRC_POWER_PWDENA_SHIFT) |
+		(1 << SDRC_POWER_PAGEPOLICY_SHIFT);
+	sdrc_write_reg(l, SDRC_POWER);
 }
diff --git a/arch/arm/mach-omap2/sdrc2xxx.c b/arch/arm/mach-omap2/sdrc2xxx.c
index 0afdad5..feaec7e 100644
--- a/arch/arm/mach-omap2/sdrc2xxx.c
+++ b/arch/arm/mach-omap2/sdrc2xxx.c
@@ -99,7 +99,10 @@
 	m_type = omap2xxx_sdrc_get_type();
 
 	local_irq_save(flags);
-	__raw_writel(0xffff, OMAP24XX_PRCM_VOLTSETUP);
+	if (cpu_is_omap2420())
+		__raw_writel(0xffff, OMAP2420_PRCM_VOLTSETUP);
+	else
+		__raw_writel(0xffff, OMAP2430_PRCM_VOLTSETUP);
 	omap2_sram_reprogram_sdrc(level, dll_ctrl, m_type);
 	curr_perf_level = level;
 	local_irq_restore(flags);
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 4dcf39c2..b094c15 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -6,8 +6,13 @@
  * Copyright (C) 2005-2008 Nokia Corporation
  * Author: Paul Mundt <paul.mundt@nokia.com>
  *
+ * Major rework for PM support by Kevin Hilman
+ *
  * Based off of arch/arm/mach-omap/omap1/serial.c
  *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com
+ *
  * This file is subject to the terms and conditions of the GNU General Public
  * License. See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -21,9 +26,50 @@
 
 #include <mach/common.h>
 #include <mach/board.h>
+#include <mach/clock.h>
+#include <mach/control.h>
 
-static struct clk *uart_ick[OMAP_MAX_NR_PORTS];
-static struct clk *uart_fck[OMAP_MAX_NR_PORTS];
+#include "prm.h"
+#include "pm.h"
+#include "prm-regbits-34xx.h"
+
+#define UART_OMAP_WER		0x17	/* Wake-up enable register */
+
+#define DEFAULT_TIMEOUT (5 * HZ)
+
+struct omap_uart_state {
+	int num;
+	int can_sleep;
+	struct timer_list timer;
+	u32 timeout;
+
+	void __iomem *wk_st;
+	void __iomem *wk_en;
+	u32 wk_mask;
+	u32 padconf;
+
+	struct clk *ick;
+	struct clk *fck;
+	int clocked;
+
+	struct plat_serial8250_port *p;
+	struct list_head node;
+
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
+	int context_valid;
+
+	/* Registers to be saved/restored for OFF-mode */
+	u16 dll;
+	u16 dlh;
+	u16 ier;
+	u16 sysc;
+	u16 scr;
+	u16 wer;
+#endif
+};
+
+static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS];
+static LIST_HEAD(uart_list);
 
 static struct plat_serial8250_port serial_platform_data[] = {
 	{
@@ -74,33 +120,369 @@
  * properly. Note that the TX watermark initialization may not be needed
  * once the 8250.c watermark handling code is merged.
  */
-static inline void __init omap_serial_reset(struct plat_serial8250_port *p)
+static inline void __init omap_uart_reset(struct omap_uart_state *uart)
 {
+	struct plat_serial8250_port *p = uart->p;
+
 	serial_write_reg(p, UART_OMAP_MDR1, 0x07);
 	serial_write_reg(p, UART_OMAP_SCR, 0x08);
 	serial_write_reg(p, UART_OMAP_MDR1, 0x00);
 	serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
 }
 
-void omap_serial_enable_clocks(int enable)
+#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
+
+static int enable_off_mode; /* to be removed by full off-mode patches */
+
+static void omap_uart_save_context(struct omap_uart_state *uart)
 {
-	int i;
-	for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
-		if (uart_ick[i] && uart_fck[i]) {
-			if (enable) {
-				clk_enable(uart_ick[i]);
-				clk_enable(uart_fck[i]);
-			} else {
-				clk_disable(uart_ick[i]);
-				clk_disable(uart_fck[i]);
-			}
+	u16 lcr = 0;
+	struct plat_serial8250_port *p = uart->p;
+
+	if (!enable_off_mode)
+		return;
+
+	lcr = serial_read_reg(p, UART_LCR);
+	serial_write_reg(p, UART_LCR, 0xBF);
+	uart->dll = serial_read_reg(p, UART_DLL);
+	uart->dlh = serial_read_reg(p, UART_DLM);
+	serial_write_reg(p, UART_LCR, lcr);
+	uart->ier = serial_read_reg(p, UART_IER);
+	uart->sysc = serial_read_reg(p, UART_OMAP_SYSC);
+	uart->scr = serial_read_reg(p, UART_OMAP_SCR);
+	uart->wer = serial_read_reg(p, UART_OMAP_WER);
+
+	uart->context_valid = 1;
+}
+
+static void omap_uart_restore_context(struct omap_uart_state *uart)
+{
+	u16 efr = 0;
+	struct plat_serial8250_port *p = uart->p;
+
+	if (!enable_off_mode)
+		return;
+
+	if (!uart->context_valid)
+		return;
+
+	uart->context_valid = 0;
+
+	serial_write_reg(p, UART_OMAP_MDR1, 0x7);
+	serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+	efr = serial_read_reg(p, UART_EFR);
+	serial_write_reg(p, UART_EFR, UART_EFR_ECB);
+	serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
+	serial_write_reg(p, UART_IER, 0x0);
+	serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+	serial_write_reg(p, UART_DLL, uart->dll);
+	serial_write_reg(p, UART_DLM, uart->dlh);
+	serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
+	serial_write_reg(p, UART_IER, uart->ier);
+	serial_write_reg(p, UART_FCR, 0xA1);
+	serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+	serial_write_reg(p, UART_EFR, efr);
+	serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
+	serial_write_reg(p, UART_OMAP_SCR, uart->scr);
+	serial_write_reg(p, UART_OMAP_WER, uart->wer);
+	serial_write_reg(p, UART_OMAP_SYSC, uart->sysc);
+	serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */
+}
+#else
+static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
+static inline void omap_uart_restore_context(struct omap_uart_state *uart) {}
+#endif /* CONFIG_PM && CONFIG_ARCH_OMAP3 */
+
+static inline void omap_uart_enable_clocks(struct omap_uart_state *uart)
+{
+	if (uart->clocked)
+		return;
+
+	clk_enable(uart->ick);
+	clk_enable(uart->fck);
+	uart->clocked = 1;
+	omap_uart_restore_context(uart);
+}
+
+#ifdef CONFIG_PM
+
+static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
+{
+	if (!uart->clocked)
+		return;
+
+	omap_uart_save_context(uart);
+	uart->clocked = 0;
+	clk_disable(uart->ick);
+	clk_disable(uart->fck);
+}
+
+static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
+					  int enable)
+{
+	struct plat_serial8250_port *p = uart->p;
+	u16 sysc;
+
+	sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7;
+	if (enable)
+		sysc |= 0x2 << 3;
+	else
+		sysc |= 0x1 << 3;
+
+	serial_write_reg(p, UART_OMAP_SYSC, sysc);
+}
+
+static void omap_uart_block_sleep(struct omap_uart_state *uart)
+{
+	omap_uart_enable_clocks(uart);
+
+	omap_uart_smart_idle_enable(uart, 0);
+	uart->can_sleep = 0;
+	if (uart->timeout)
+		mod_timer(&uart->timer, jiffies + uart->timeout);
+	else
+		del_timer(&uart->timer);
+}
+
+static void omap_uart_allow_sleep(struct omap_uart_state *uart)
+{
+	if (!uart->clocked)
+		return;
+
+	omap_uart_smart_idle_enable(uart, 1);
+	uart->can_sleep = 1;
+	del_timer(&uart->timer);
+}
+
+static void omap_uart_idle_timer(unsigned long data)
+{
+	struct omap_uart_state *uart = (struct omap_uart_state *)data;
+
+	omap_uart_allow_sleep(uart);
+}
+
+void omap_uart_prepare_idle(int num)
+{
+	struct omap_uart_state *uart;
+
+	list_for_each_entry(uart, &uart_list, node) {
+		if (num == uart->num && uart->can_sleep) {
+			omap_uart_disable_clocks(uart);
+			return;
 		}
 	}
 }
 
+void omap_uart_resume_idle(int num)
+{
+	struct omap_uart_state *uart;
+
+	list_for_each_entry(uart, &uart_list, node) {
+		if (num == uart->num) {
+			omap_uart_enable_clocks(uart);
+
+			/* Check for IO pad wakeup */
+			if (cpu_is_omap34xx() && uart->padconf) {
+				u16 p = omap_ctrl_readw(uart->padconf);
+
+				if (p & OMAP3_PADCONF_WAKEUPEVENT0)
+					omap_uart_block_sleep(uart);
+			}
+
+			/* Check for normal UART wakeup */
+			if (__raw_readl(uart->wk_st) & uart->wk_mask)
+				omap_uart_block_sleep(uart);
+
+			return;
+		}
+	}
+}
+
+void omap_uart_prepare_suspend(void)
+{
+	struct omap_uart_state *uart;
+
+	list_for_each_entry(uart, &uart_list, node) {
+		omap_uart_allow_sleep(uart);
+	}
+}
+
+int omap_uart_can_sleep(void)
+{
+	struct omap_uart_state *uart;
+	int can_sleep = 1;
+
+	list_for_each_entry(uart, &uart_list, node) {
+		if (!uart->clocked)
+			continue;
+
+		if (!uart->can_sleep) {
+			can_sleep = 0;
+			continue;
+		}
+
+		/* This UART can now safely sleep. */
+		omap_uart_allow_sleep(uart);
+	}
+
+	return can_sleep;
+}
+
+/**
+ * omap_uart_interrupt()
+ *
+ * This handler is used only to detect that *any* UART interrupt has
+ * occurred.  It does _nothing_ to handle the interrupt.  Rather,
+ * any UART interrupt will trigger the inactivity timer so the
+ * UART will not idle or sleep for its timeout period.
+ *
+ **/
+static irqreturn_t omap_uart_interrupt(int irq, void *dev_id)
+{
+	struct omap_uart_state *uart = dev_id;
+
+	omap_uart_block_sleep(uart);
+
+	return IRQ_NONE;
+}
+
+static u32 sleep_timeout = DEFAULT_TIMEOUT;
+
+static void omap_uart_idle_init(struct omap_uart_state *uart)
+{
+	u32 v;
+	struct plat_serial8250_port *p = uart->p;
+	int ret;
+
+	uart->can_sleep = 0;
+	uart->timeout = sleep_timeout;
+	setup_timer(&uart->timer, omap_uart_idle_timer,
+		    (unsigned long) uart);
+	mod_timer(&uart->timer, jiffies + uart->timeout);
+	omap_uart_smart_idle_enable(uart, 0);
+
+	if (cpu_is_omap34xx()) {
+		u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD;
+		u32 wk_mask = 0;
+		u32 padconf = 0;
+
+		uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1);
+		uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1);
+		switch (uart->num) {
+		case 0:
+			wk_mask = OMAP3430_ST_UART1_MASK;
+			padconf = 0x182;
+			break;
+		case 1:
+			wk_mask = OMAP3430_ST_UART2_MASK;
+			padconf = 0x17a;
+			break;
+		case 2:
+			wk_mask = OMAP3430_ST_UART3_MASK;
+			padconf = 0x19e;
+			break;
+		}
+		uart->wk_mask = wk_mask;
+		uart->padconf = padconf;
+	} else if (cpu_is_omap24xx()) {
+		u32 wk_mask = 0;
+
+		if (cpu_is_omap2430()) {
+			uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKEN1);
+			uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKST1);
+		} else if (cpu_is_omap2420()) {
+			uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKEN1);
+			uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKST1);
+		}
+		switch (uart->num) {
+		case 0:
+			wk_mask = OMAP24XX_ST_UART1_MASK;
+			break;
+		case 1:
+			wk_mask = OMAP24XX_ST_UART2_MASK;
+			break;
+		case 2:
+			wk_mask = OMAP24XX_ST_UART3_MASK;
+			break;
+		}
+		uart->wk_mask = wk_mask;
+	} else {
+		uart->wk_en = 0;
+		uart->wk_st = 0;
+		uart->wk_mask = 0;
+		uart->padconf = 0;
+	}
+
+	/* Set wake-enable bit */
+	if (uart->wk_en && uart->wk_mask) {
+		v = __raw_readl(uart->wk_en);
+		v |= uart->wk_mask;
+		__raw_writel(v, uart->wk_en);
+	}
+
+	/* Ensure IOPAD wake-enables are set */
+	if (cpu_is_omap34xx() && uart->padconf) {
+		u16 v;
+
+		v = omap_ctrl_readw(uart->padconf);
+		v |= OMAP3_PADCONF_WAKEUPENABLE0;
+		omap_ctrl_writew(v, uart->padconf);
+	}
+
+	p->flags |= UPF_SHARE_IRQ;
+	ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED,
+			  "serial idle", (void *)uart);
+	WARN_ON(ret);
+}
+
+static ssize_t sleep_timeout_show(struct kobject *kobj,
+				  struct kobj_attribute *attr,
+				  char *buf)
+{
+	return sprintf(buf, "%u\n", sleep_timeout / HZ);
+}
+
+static ssize_t sleep_timeout_store(struct kobject *kobj,
+				   struct kobj_attribute *attr,
+				   const char *buf, size_t n)
+{
+	struct omap_uart_state *uart;
+	unsigned int value;
+
+	if (sscanf(buf, "%u", &value) != 1) {
+		printk(KERN_ERR "sleep_timeout_store: Invalid value\n");
+		return -EINVAL;
+	}
+	sleep_timeout = value * HZ;
+	list_for_each_entry(uart, &uart_list, node) {
+		uart->timeout = sleep_timeout;
+		if (uart->timeout)
+			mod_timer(&uart->timer, jiffies + uart->timeout);
+		else
+			/* A zero value means disable timeout feature */
+			omap_uart_block_sleep(uart);
+	}
+	return n;
+}
+
+static struct kobj_attribute sleep_timeout_attr =
+	__ATTR(sleep_timeout, 0644, sleep_timeout_show, sleep_timeout_store);
+
+#else
+static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
+#endif /* CONFIG_PM */
+
+static struct platform_device serial_device = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev			= {
+		.platform_data	= serial_platform_data,
+	},
+};
+
 void __init omap_serial_init(void)
 {
-	int i;
+	int i, err;
 	const struct omap_uart_config *info;
 	char name[16];
 
@@ -114,9 +496,14 @@
 
 	if (info == NULL)
 		return;
+	if (cpu_is_omap44xx()) {
+		for (i = 0; i < OMAP_MAX_NR_PORTS; i++)
+			serial_platform_data[i].irq += 32;
+	}
 
 	for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
 		struct plat_serial8250_port *p = serial_platform_data + i;
+		struct omap_uart_state *uart = &omap_uart[i];
 
 		if (!(info->enabled_uarts & (1 << i))) {
 			p->membase = NULL;
@@ -125,35 +512,39 @@
 		}
 
 		sprintf(name, "uart%d_ick", i+1);
-		uart_ick[i] = clk_get(NULL, name);
-		if (IS_ERR(uart_ick[i])) {
+		uart->ick = clk_get(NULL, name);
+		if (IS_ERR(uart->ick)) {
 			printk(KERN_ERR "Could not get uart%d_ick\n", i+1);
-			uart_ick[i] = NULL;
-		} else
-			clk_enable(uart_ick[i]);
+			uart->ick = NULL;
+		}
 
 		sprintf(name, "uart%d_fck", i+1);
-		uart_fck[i] = clk_get(NULL, name);
-		if (IS_ERR(uart_fck[i])) {
+		uart->fck = clk_get(NULL, name);
+		if (IS_ERR(uart->fck)) {
 			printk(KERN_ERR "Could not get uart%d_fck\n", i+1);
-			uart_fck[i] = NULL;
-		} else
-			clk_enable(uart_fck[i]);
+			uart->fck = NULL;
+		}
 
-		omap_serial_reset(p);
+		if (!uart->ick || !uart->fck)
+			continue;
+
+		uart->num = i;
+		p->private_data = uart;
+		uart->p = p;
+		list_add(&uart->node, &uart_list);
+
+		omap_uart_enable_clocks(uart);
+		omap_uart_reset(uart);
+		omap_uart_idle_init(uart);
 	}
+
+	err = platform_device_register(&serial_device);
+
+#ifdef CONFIG_PM
+	if (!err)
+		err = sysfs_create_file(&serial_device.dev.kobj,
+					&sleep_timeout_attr.attr);
+#endif
+
 }
 
-static struct platform_device serial_device = {
-	.name			= "serial8250",
-	.id			= PLAT8250_DEV_PLATFORM,
-	.dev			= {
-		.platform_data	= serial_platform_data,
-	},
-};
-
-static int __init omap_init(void)
-{
-	return platform_device_register(&serial_device);
-}
-arch_initcall(omap_init);
diff --git a/arch/arm/mach-omap2/sleep24xx.S b/arch/arm/mach-omap2/sleep24xx.S
index bf9e961..130aadb 100644
--- a/arch/arm/mach-omap2/sleep24xx.S
+++ b/arch/arm/mach-omap2/sleep24xx.S
@@ -28,7 +28,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <mach/io.h>
-#include <mach/pm.h>
 
 #include <mach/omap24xx.h>
 
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
new file mode 100644
index 0000000..e5e2553
--- /dev/null
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -0,0 +1,436 @@
+/*
+ * linux/arch/arm/mach-omap2/sleep.S
+ *
+ * (C) Copyright 2007
+ * Texas Instruments
+ * Karthik Dasu <karthik-dp@ti.com>
+ *
+ * (C) Copyright 2004
+ * Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@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
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/io.h>
+#include <mach/control.h>
+
+#include "prm.h"
+#include "sdrc.h"
+
+#define PM_PREPWSTST_CORE_V	OMAP34XX_PRM_REGADDR(CORE_MOD, \
+				OMAP3430_PM_PREPWSTST)
+#define PM_PREPWSTST_MPU_V	OMAP34XX_PRM_REGADDR(MPU_MOD, \
+				OMAP3430_PM_PREPWSTST)
+#define PM_PWSTCTRL_MPU_P	OMAP34XX_PRM_REGADDR(MPU_MOD, PM_PWSTCTRL)
+#define SCRATCHPAD_MEM_OFFS	0x310 /* Move this as correct place is
+				       * available */
+#define SCRATCHPAD_BASE_P	OMAP343X_CTRL_REGADDR(\
+				OMAP343X_CONTROL_MEM_WKUP +\
+				SCRATCHPAD_MEM_OFFS)
+#define SDRC_POWER_V		OMAP34XX_SDRC_REGADDR(SDRC_POWER)
+
+	.text
+/* Function call to get the restore pointer for resume from OFF */
+ENTRY(get_restore_pointer)
+        stmfd   sp!, {lr}     @ save registers on stack
+	adr	r0, restore
+        ldmfd   sp!, {pc}     @ restore regs and return
+ENTRY(get_restore_pointer_sz)
+        .word   . - get_restore_pointer_sz
+/*
+ * Forces OMAP into idle state
+ *
+ * omap34xx_suspend() - This bit of code just executes the WFI
+ * for normal idles.
+ *
+ * Note: This code get's copied to internal SRAM at boot. When the OMAP
+ *	 wakes up it continues execution at the point it went to sleep.
+ */
+ENTRY(omap34xx_cpu_suspend)
+	stmfd	sp!, {r0-r12, lr}		@ save registers on stack
+loop:
+	/*b	loop*/	@Enable to debug by stepping through code
+	/* r0 contains restore pointer in sdram */
+	/* r1 contains information about saving context */
+	ldr     r4, sdrc_power          @ read the SDRC_POWER register
+	ldr     r5, [r4]                @ read the contents of SDRC_POWER
+	orr     r5, r5, #0x40           @ enable self refresh on idle req
+	str     r5, [r4]                @ write back to SDRC_POWER register
+
+	cmp	r1, #0x0
+	/* If context save is required, do that and execute wfi */
+	bne	save_context_wfi
+	/* Data memory barrier and Data sync barrier */
+	mov	r1, #0
+	mcr	p15, 0, r1, c7, c10, 4
+	mcr	p15, 0, r1, c7, c10, 5
+
+	wfi				@ wait for interrupt
+
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	bl i_dll_wait
+
+	ldmfd	sp!, {r0-r12, pc}		@ restore regs and return
+restore:
+	/* b restore*/ 	@ Enable to debug restore code
+        /* Check what was the reason for mpu reset and store the reason in r9*/
+        /* 1 - Only L1 and logic lost */
+        /* 2 - Only L2 lost - In this case, we wont be here */
+        /* 3 - Both L1 and L2 lost */
+	ldr     r1, pm_pwstctrl_mpu
+	ldr	r2, [r1]
+	and     r2, r2, #0x3
+	cmp     r2, #0x0	@ Check if target power state was OFF or RET
+        moveq   r9, #0x3        @ MPU OFF => L1 and L2 lost
+	movne	r9, #0x1	@ Only L1 and L2 lost => avoid L2 invalidation
+	bne	logic_l1_restore
+	/* Execute smi to invalidate L2 cache */
+	mov r12, #0x1                         @ set up to invalide L2
+smi:    .word 0xE1600070                @ Call SMI monitor (smieq)
+logic_l1_restore:
+	mov	r1, #0
+	/* Invalidate all instruction caches to PoU
+	 * and flush branch target cache */
+	mcr	p15, 0, r1, c7, c5, 0
+
+	ldr	r4, scratchpad_base
+	ldr	r3, [r4,#0xBC]
+	ldmia	r3!, {r4-r6}
+	mov	sp, r4
+	msr	spsr_cxsf, r5
+	mov	lr, r6
+
+	ldmia	r3!, {r4-r9}
+	/* Coprocessor access Control Register */
+	mcr p15, 0, r4, c1, c0, 2
+
+	/* TTBR0 */
+	MCR p15, 0, r5, c2, c0, 0
+	/* TTBR1 */
+	MCR p15, 0, r6, c2, c0, 1
+	/* Translation table base control register */
+	MCR p15, 0, r7, c2, c0, 2
+	/*domain access Control Register */
+	MCR p15, 0, r8, c3, c0, 0
+	/* data fault status Register */
+	MCR p15, 0, r9, c5, c0, 0
+
+	ldmia  r3!,{r4-r8}
+	/* instruction fault status Register */
+	MCR p15, 0, r4, c5, c0, 1
+	/*Data Auxiliary Fault Status Register */
+	MCR p15, 0, r5, c5, c1, 0
+	/*Instruction Auxiliary Fault Status Register*/
+	MCR p15, 0, r6, c5, c1, 1
+	/*Data Fault Address Register */
+	MCR p15, 0, r7, c6, c0, 0
+	/*Instruction Fault Address Register*/
+	MCR p15, 0, r8, c6, c0, 2
+	ldmia  r3!,{r4-r7}
+
+	/* user r/w thread and process ID */
+	MCR p15, 0, r4, c13, c0, 2
+	/* user ro thread and process ID */
+	MCR p15, 0, r5, c13, c0, 3
+	/*Privileged only thread and process ID */
+	MCR p15, 0, r6, c13, c0, 4
+	/* cache size selection */
+	MCR p15, 2, r7, c0, c0, 0
+	ldmia  r3!,{r4-r8}
+	/* Data TLB lockdown registers */
+	MCR p15, 0, r4, c10, c0, 0
+	/* Instruction TLB lockdown registers */
+	MCR p15, 0, r5, c10, c0, 1
+	/* Secure or Nonsecure Vector Base Address */
+	MCR p15, 0, r6, c12, c0, 0
+	/* FCSE PID */
+	MCR p15, 0, r7, c13, c0, 0
+	/* Context PID */
+	MCR p15, 0, r8, c13, c0, 1
+
+	ldmia  r3!,{r4-r5}
+	/* primary memory remap register */
+	MCR p15, 0, r4, c10, c2, 0
+	/*normal memory remap register */
+	MCR p15, 0, r5, c10, c2, 1
+
+	/* Restore cpsr */
+	ldmia	r3!,{r4}	/*load CPSR from SDRAM*/
+	msr	cpsr, r4	/*store cpsr */
+
+	/* Enabling MMU here */
+	mrc	p15, 0, r7, c2, c0, 2 /* Read TTBRControl */
+	/* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1*/
+	and	r7, #0x7
+	cmp	r7, #0x0
+	beq	usettbr0
+ttbr_error:
+	/* More work needs to be done to support N[0:2] value other than 0
+	* So looping here so that the error can be detected
+	*/
+	b	ttbr_error
+usettbr0:
+	mrc	p15, 0, r2, c2, c0, 0
+	ldr	r5, ttbrbit_mask
+	and	r2, r5
+	mov	r4, pc
+	ldr	r5, table_index_mask
+	and	r4, r5 /* r4 = 31 to 20 bits of pc */
+	/* Extract the value to be written to table entry */
+	ldr	r1, table_entry
+	add	r1, r1, r4 /* r1 has value to be written to table entry*/
+	/* Getting the address of table entry to modify */
+	lsr	r4, #18
+	add	r2, r4 /* r2 has the location which needs to be modified */
+	/* Storing previous entry of location being modified */
+	ldr	r5, scratchpad_base
+	ldr	r4, [r2]
+	str	r4, [r5, #0xC0]
+	/* Modify the table entry */
+	str	r1, [r2]
+	/* Storing address of entry being modified
+	 * - will be restored after enabling MMU */
+	ldr	r5, scratchpad_base
+	str	r2, [r5, #0xC4]
+
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 4	@ Flush prefetch buffer
+	mcr	p15, 0, r0, c7, c5, 6	@ Invalidate branch predictor array
+	mcr	p15, 0, r0, c8, c5, 0	@ Invalidate instruction TLB
+	mcr	p15, 0, r0, c8, c6, 0	@ Invalidate data TLB
+	/* Restore control register  but dont enable caches here*/
+	/* Caches will be enabled after restoring MMU table entry */
+	ldmia	r3!, {r4}
+	/* Store previous value of control register in scratchpad */
+	str	r4, [r5, #0xC8]
+	ldr	r2, cache_pred_disable_mask
+	and	r4, r2
+	mcr	p15, 0, r4, c1, c0, 0
+
+	ldmfd	sp!, {r0-r12, pc}		@ restore regs and return
+save_context_wfi:
+	/*b	save_context_wfi*/	@ enable to debug save code
+	mov	r8, r0 /* Store SDRAM address in r8 */
+        /* Check what that target sleep state is:stored in r1*/
+        /* 1 - Only L1 and logic lost */
+        /* 2 - Only L2 lost */
+        /* 3 - Both L1 and L2 lost */
+	cmp	r1, #0x2 /* Only L2 lost */
+	beq	clean_l2
+	cmp	r1, #0x1 /* L2 retained */
+	/* r9 stores whether to clean L2 or not*/
+	moveq	r9, #0x0 /* Dont Clean L2 */
+	movne	r9, #0x1 /* Clean L2 */
+l1_logic_lost:
+	/* Store sp and spsr to SDRAM */
+	mov	r4, sp
+	mrs	r5, spsr
+	mov	r6, lr
+	stmia	r8!, {r4-r6}
+	/* Save all ARM registers */
+	/* Coprocessor access control register */
+	mrc	p15, 0, r6, c1, c0, 2
+	stmia	r8!, {r6}
+	/* TTBR0, TTBR1 and Translation table base control */
+	mrc	p15, 0, r4, c2, c0, 0
+	mrc	p15, 0, r5, c2, c0, 1
+	mrc	p15, 0, r6, c2, c0, 2
+	stmia	r8!, {r4-r6}
+	/* Domain access control register, data fault status register,
+	and instruction fault status register */
+	mrc	p15, 0, r4, c3, c0, 0
+	mrc	p15, 0, r5, c5, c0, 0
+	mrc	p15, 0, r6, c5, c0, 1
+	stmia	r8!, {r4-r6}
+	/* Data aux fault status register, instruction aux fault status,
+	datat fault address register and instruction fault address register*/
+	mrc	p15, 0, r4, c5, c1, 0
+	mrc	p15, 0, r5, c5, c1, 1
+	mrc	p15, 0, r6, c6, c0, 0
+	mrc	p15, 0, r7, c6, c0, 2
+	stmia	r8!, {r4-r7}
+	/* user r/w thread and process ID, user r/o thread and process ID,
+	priv only thread and process ID, cache size selection */
+	mrc	p15, 0, r4, c13, c0, 2
+	mrc	p15, 0, r5, c13, c0, 3
+	mrc	p15, 0, r6, c13, c0, 4
+	mrc	p15, 2, r7, c0, c0, 0
+	stmia	r8!, {r4-r7}
+	/* Data TLB lockdown, instruction TLB lockdown registers */
+	mrc	p15, 0, r5, c10, c0, 0
+	mrc	p15, 0, r6, c10, c0, 1
+	stmia	r8!, {r5-r6}
+	/* Secure or non secure vector base address, FCSE PID, Context PID*/
+	mrc	p15, 0, r4, c12, c0, 0
+	mrc	p15, 0, r5, c13, c0, 0
+	mrc	p15, 0, r6, c13, c0, 1
+	stmia	r8!, {r4-r6}
+	/* Primary remap, normal remap registers */
+	mrc	p15, 0, r4, c10, c2, 0
+	mrc	p15, 0, r5, c10, c2, 1
+	stmia	r8!,{r4-r5}
+
+	/* Store current cpsr*/
+	mrs	r2, cpsr
+	stmia	r8!, {r2}
+
+	mrc	p15, 0, r4, c1, c0, 0
+	/* save control register */
+	stmia	r8!, {r4}
+clean_caches:
+	/* Clean Data or unified cache to POU*/
+	/* How to invalidate only L1 cache???? - #FIX_ME# */
+	/* mcr	p15, 0, r11, c7, c11, 1 */
+	cmp	r9, #1 /* Check whether L2 inval is required or not*/
+	bne	skip_l2_inval
+clean_l2:
+	/* read clidr */
+	mrc     p15, 1, r0, c0, c0, 1
+	/* extract loc from clidr */
+	ands    r3, r0, #0x7000000
+	/* left align loc bit field */
+	mov     r3, r3, lsr #23
+	/* if loc is 0, then no need to clean */
+	beq     finished
+	/* start clean at cache level 0 */
+	mov     r10, #0
+loop1:
+	/* work out 3x current cache level */
+	add     r2, r10, r10, lsr #1
+	/* extract cache type bits from clidr*/
+	mov     r1, r0, lsr r2
+	/* mask of the bits for current cache only */
+	and     r1, r1, #7
+	/* see what cache we have at this level */
+	cmp     r1, #2
+	/* skip if no cache, or just i-cache */
+	blt     skip
+	/* select current cache level in cssr */
+	mcr     p15, 2, r10, c0, c0, 0
+	/* isb to sych the new cssr&csidr */
+	isb
+	/* read the new csidr */
+	mrc     p15, 1, r1, c0, c0, 0
+	/* extract the length of the cache lines */
+	and     r2, r1, #7
+	/* add 4 (line length offset) */
+	add     r2, r2, #4
+	ldr     r4, assoc_mask
+	/* find maximum number on the way size */
+	ands    r4, r4, r1, lsr #3
+	/* find bit position of way size increment */
+	clz     r5, r4
+	ldr     r7, numset_mask
+	/* extract max number of the index size*/
+	ands    r7, r7, r1, lsr #13
+loop2:
+	mov     r9, r4
+	/* create working copy of max way size*/
+loop3:
+	/* factor way and cache number into r11 */
+	orr     r11, r10, r9, lsl r5
+	/* factor index number into r11 */
+	orr     r11, r11, r7, lsl r2
+	/*clean & invalidate by set/way */
+	mcr     p15, 0, r11, c7, c10, 2
+	/* decrement the way*/
+	subs    r9, r9, #1
+	bge     loop3
+	/*decrement the index */
+	subs    r7, r7, #1
+	bge     loop2
+skip:
+	add     r10, r10, #2
+	/* increment cache number */
+	cmp     r3, r10
+	bgt     loop1
+finished:
+	/*swith back to cache level 0 */
+	mov     r10, #0
+	/* select current cache level in cssr */
+	mcr     p15, 2, r10, c0, c0, 0
+	isb
+skip_l2_inval:
+	/* Data memory barrier and Data sync barrier */
+	mov     r1, #0
+	mcr     p15, 0, r1, c7, c10, 4
+	mcr     p15, 0, r1, c7, c10, 5
+
+	wfi                             @ wait for interrupt
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	bl i_dll_wait
+	/* restore regs and return */
+	ldmfd   sp!, {r0-r12, pc}
+
+i_dll_wait:
+	ldr     r4, clk_stabilize_delay
+
+i_dll_delay:
+	subs    r4, r4, #0x1
+	bne     i_dll_delay
+	ldr     r4, sdrc_power
+	ldr     r5, [r4]
+	bic     r5, r5, #0x40
+	str     r5, [r4]
+	bx	lr
+pm_prepwstst_core:
+	.word	PM_PREPWSTST_CORE_V
+pm_prepwstst_mpu:
+	.word	PM_PREPWSTST_MPU_V
+pm_pwstctrl_mpu:
+	.word	PM_PWSTCTRL_MPU_P
+scratchpad_base:
+	.word	SCRATCHPAD_BASE_P
+sdrc_power:
+	.word SDRC_POWER_V
+context_mem:
+	.word	0x803E3E14
+clk_stabilize_delay:
+	.word 0x000001FF
+assoc_mask:
+	.word	0x3ff
+numset_mask:
+	.word	0x7fff
+ttbrbit_mask:
+	.word	0xFFFFC000
+table_index_mask:
+	.word	0xFFF00000
+table_entry:
+	.word	0x00000C02
+cache_pred_disable_mask:
+	.word	0xFFFFE7FB
+ENTRY(omap34xx_cpu_suspend_sz)
+	.word	. - omap34xx_cpu_suspend
diff --git a/arch/arm/mach-omap2/sram242x.S b/arch/arm/mach-omap2/sram242x.S
index af4bd34..bb29985 100644
--- a/arch/arm/mach-omap2/sram242x.S
+++ b/arch/arm/mach-omap2/sram242x.S
@@ -124,11 +124,11 @@
 omap242x_sdi_sdrc_dlla_ctrl:
 	.word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL)
 omap242x_sdi_prcm_voltctrl:
-	.word OMAP242X_PRCM_VOLTCTRL
+	.word OMAP2420_PRCM_VOLTCTRL
 prcm_mask_val:
 	.word 0xFFFF3FFC
 omap242x_sdi_timer_32ksynct_cr:
-	.word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010)
+	.word IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
 ENTRY(omap242x_sram_ddr_init_sz)
 	.word	. - omap242x_sram_ddr_init
 
@@ -220,11 +220,11 @@
 omap242x_srs_sdrc_rfr_ctrl:
 	.word OMAP242X_SDRC_REGADDR(SDRC_RFR_CTRL_0)
 omap242x_srs_prcm_voltctrl:
-	.word OMAP242X_PRCM_VOLTCTRL
+	.word OMAP2420_PRCM_VOLTCTRL
 ddr_prcm_mask_val:
 	.word 0xFFFF3FFC
 omap242x_srs_timer_32ksynct:
-	.word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010)
+	.word IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
 
 ENTRY(omap242x_sram_reprogram_sdrc_sz)
 	.word	. - omap242x_sram_reprogram_sdrc
@@ -305,7 +305,7 @@
 	ldmfd	sp!, {r0-r12, pc}	@ restore regs and return
 
 omap242x_ssp_set_config:
-	.word OMAP242X_PRCM_CLKCFG_CTRL
+	.word OMAP2420_PRCM_CLKCFG_CTRL
 omap242x_ssp_pll_ctl:
 	.word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKEN)
 omap242x_ssp_pll_stat:
diff --git a/arch/arm/mach-omap2/sram243x.S b/arch/arm/mach-omap2/sram243x.S
index 84363e2..9955abc 100644
--- a/arch/arm/mach-omap2/sram243x.S
+++ b/arch/arm/mach-omap2/sram243x.S
@@ -124,11 +124,11 @@
 omap243x_sdi_sdrc_dlla_ctrl:
 	.word OMAP243X_SDRC_REGADDR(SDRC_DLLA_CTRL)
 omap243x_sdi_prcm_voltctrl:
-	.word OMAP243X_PRCM_VOLTCTRL
+	.word OMAP2430_PRCM_VOLTCTRL
 prcm_mask_val:
 	.word 0xFFFF3FFC
 omap243x_sdi_timer_32ksynct_cr:
-	.word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010)
+	.word IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010)
 ENTRY(omap243x_sram_ddr_init_sz)
 	.word	. - omap243x_sram_ddr_init
 
@@ -220,11 +220,11 @@
 omap243x_srs_sdrc_rfr_ctrl:
 	.word OMAP243X_SDRC_REGADDR(SDRC_RFR_CTRL_0)
 omap243x_srs_prcm_voltctrl:
-	.word OMAP243X_PRCM_VOLTCTRL
+	.word OMAP2430_PRCM_VOLTCTRL
 ddr_prcm_mask_val:
 	.word 0xFFFF3FFC
 omap243x_srs_timer_32ksynct:
-	.word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010)
+	.word IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010)
 
 ENTRY(omap243x_sram_reprogram_sdrc_sz)
 	.word	. - omap243x_sram_reprogram_sdrc
@@ -305,7 +305,7 @@
 	ldmfd	sp!, {r0-r12, pc}	@ restore regs and return
 
 omap243x_ssp_set_config:
-	.word OMAP243X_PRCM_CLKCFG_CTRL
+	.word OMAP2430_PRCM_CLKCFG_CTRL
 omap243x_ssp_pll_ctl:
 	.word OMAP2430_CM_REGADDR(PLL_MOD, CM_CLKEN)
 omap243x_ssp_pll_stat:
diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S
index 2c71461..c080c82 100644
--- a/arch/arm/mach-omap2/sram34xx.S
+++ b/arch/arm/mach-omap2/sram34xx.S
@@ -40,69 +40,74 @@
 /*
  * Change frequency of core dpll
  * r0 = sdrc_rfr_ctrl r1 = sdrc_actim_ctrla r2 = sdrc_actim_ctrlb r3 = M2
+ * r4 = Unlock SDRC DLL? (1 = yes, 0 = no) -- only unlock DLL for
+ *      SDRC rates < 83MHz
  */
 ENTRY(omap3_sram_configure_core_dpll)
 	stmfd	sp!, {r1-r12, lr}	@ store regs to stack
+	ldr	r4, [sp, #52]		@ pull extra args off the stack
+	dsb				@ flush buffered writes to interconnect
 	cmp	r3, #0x2
 	blne	configure_sdrc
-	cmp	r3, #0x2
+	cmp	r4, #0x1
+	bleq	unlock_dll
 	blne	lock_dll
-	cmp	r3, #0x1
-	blne	unlock_dll
 	bl	sdram_in_selfrefresh	@ put the SDRAM in self refresh
 	bl 	configure_core_dpll
 	bl	enable_sdrc
-	cmp	r3, #0x1
-	blne	wait_dll_unlock
-	cmp	r3, #0x2
+	cmp	r4, #0x1
+	bleq	wait_dll_unlock
 	blne	wait_dll_lock
 	cmp	r3, #0x1
 	blne	configure_sdrc
+	isb				@ prevent speculative exec past here
 	mov 	r0, #0 			@ return value
 	ldmfd	sp!, {r1-r12, pc}	@ restore regs and return
 unlock_dll:
-	ldr	r4, omap3_sdrc_dlla_ctrl
-	ldr	r5, [r4]
-	orr	r5, r5, #0x4
-	str	r5, [r4]
+	ldr	r11, omap3_sdrc_dlla_ctrl
+	ldr	r12, [r11]
+	orr	r12, r12, #0x4
+	str	r12, [r11]		@ (no OCP barrier needed)
 	bx	lr
 lock_dll:
-	ldr	r4, omap3_sdrc_dlla_ctrl
-	ldr	r5, [r4]
-	bic	r5, r5, #0x4
-	str	r5, [r4]
+	ldr	r11, omap3_sdrc_dlla_ctrl
+	ldr	r12, [r11]
+	bic	r12, r12, #0x4
+	str	r12, [r11]		@ (no OCP barrier needed)
 	bx	lr
 sdram_in_selfrefresh:
-	mov	r5, #0x0		@ Move 0 to R5
-	mcr	p15, 0, r5, c7, c10, 5	@ memory barrier
-	ldr	r4, omap3_sdrc_power	@ read the SDRC_POWER register
-	ldr	r5, [r4]		@ read the contents of SDRC_POWER
-	orr 	r5, r5, #0x40		@ enable self refresh on idle req
-	str 	r5, [r4]		@ write back to SDRC_POWER register
-	ldr	r4, omap3_cm_iclken1_core	@ read the CM_ICLKEN1_CORE reg
-	ldr	r5, [r4]
-	bic	r5, r5, #0x2		@ disable iclk bit for SRDC
-	str 	r5, [r4]
+	ldr	r11, omap3_sdrc_power	@ read the SDRC_POWER register
+	ldr	r12, [r11]		@ read the contents of SDRC_POWER
+	mov	r9, r12			@ keep a copy of SDRC_POWER bits
+	orr 	r12, r12, #0x40		@ enable self refresh on idle req
+	bic 	r12, r12, #0x4		@ clear PWDENA
+	str 	r12, [r11]		@ write back to SDRC_POWER register
+	ldr	r12, [r11]		@ posted-write barrier for SDRC
+	ldr	r11, omap3_cm_iclken1_core	@ read the CM_ICLKEN1_CORE reg
+	ldr	r12, [r11]
+	bic	r12, r12, #0x2		@ disable iclk bit for SDRC
+	str 	r12, [r11]
 wait_sdrc_idle:
-	ldr 	r4, omap3_cm_idlest1_core
-	ldr 	r5, [r4]
-	and 	r5, r5, #0x2		@ check for SDRC idle
-	cmp 	r5, #2
+	ldr 	r11, omap3_cm_idlest1_core
+	ldr 	r12, [r11]
+	and 	r12, r12, #0x2		@ check for SDRC idle
+	cmp 	r12, #2
 	bne 	wait_sdrc_idle
 	bx 	lr
 configure_core_dpll:
-	ldr 	r4, omap3_cm_clksel1_pll
-	ldr	r5, [r4]
-	ldr	r6, core_m2_mask_val	@ modify m2 for core dpll
-	and	r5, r5, r6
-	orr	r5, r5, r3, lsl #0x1B	@ r3 contains the M2 val
-	str	r5, [r4]
-	mov 	r5, #0x800		@ wait for the clock to stabilise
+	ldr 	r11, omap3_cm_clksel1_pll
+	ldr	r12, [r11]
+	ldr	r10, core_m2_mask_val	@ modify m2 for core dpll
+	and	r12, r12, r10
+	orr	r12, r12, r3, lsl #0x1B	@ r3 contains the M2 val
+	str	r12, [r11]
+	ldr	r12, [r11]		@ posted-write barrier for CM
+	mov 	r12, #0x800		@ wait for the clock to stabilise
 	cmp	r3, #2
 	bne	wait_clk_stable
 	bx	lr
 wait_clk_stable:
-	subs 	r5, r5, #1
+	subs 	r12, r12, #1
 	bne	wait_clk_stable
 	nop
 	nop
@@ -116,42 +121,42 @@
 	nop
 	bx	lr
 enable_sdrc:
-	ldr 	r4, omap3_cm_iclken1_core
-	ldr	r5, [r4]
-	orr 	r5, r5, #0x2		@ enable iclk bit for SDRC
-	str 	r5, [r4]
+	ldr 	r11, omap3_cm_iclken1_core
+	ldr	r12, [r11]
+	orr 	r12, r12, #0x2		@ enable iclk bit for SDRC
+	str 	r12, [r11]
 wait_sdrc_idle1:
-	ldr 	r4, omap3_cm_idlest1_core
-	ldr	r5, [r4]
-	and 	r5, r5, #0x2
-	cmp	r5, #0
+	ldr 	r11, omap3_cm_idlest1_core
+	ldr	r12, [r11]
+	and 	r12, r12, #0x2
+	cmp	r12, #0
 	bne	wait_sdrc_idle1
-	ldr	r4, omap3_sdrc_power
-	ldr	r5, [r4]
-	bic 	r5, r5, #0x40
-	str 	r5, [r4]
+restore_sdrc_power_val:
+	ldr	r11, omap3_sdrc_power
+	str	r9, [r11]		@ restore SDRC_POWER, no barrier needed
 	bx	lr
 wait_dll_lock:
-	ldr	r4, omap3_sdrc_dlla_status
-	ldr	r5, [r4]
-	and 	r5, r5, #0x4
-	cmp	r5, #0x4
+	ldr	r11, omap3_sdrc_dlla_status
+	ldr	r12, [r11]
+	and 	r12, r12, #0x4
+	cmp	r12, #0x4
 	bne	wait_dll_lock
 	bx	lr
 wait_dll_unlock:
-	ldr	r4, omap3_sdrc_dlla_status
-	ldr	r5, [r4]
-	and	r5, r5, #0x4
-	cmp	r5, #0x0
+	ldr	r11, omap3_sdrc_dlla_status
+	ldr	r12, [r11]
+	and	r12, r12, #0x4
+	cmp	r12, #0x0
 	bne	wait_dll_unlock
 	bx	lr
 configure_sdrc:
-	ldr	r4, omap3_sdrc_rfr_ctrl
-	str	r0, [r4]
-	ldr	r4, omap3_sdrc_actim_ctrla
-	str	r1, [r4]
-	ldr	r4, omap3_sdrc_actim_ctrlb
-	str	r2, [r4]
+	ldr	r11, omap3_sdrc_rfr_ctrl
+	str	r0, [r11]
+	ldr	r11, omap3_sdrc_actim_ctrla
+	str	r1, [r11]
+	ldr	r11, omap3_sdrc_actim_ctrlb
+	str	r2, [r11]
+	ldr	r2, [r11]		@ posted-write barrier for SDRC
 	bx	lr
 
 omap3_sdrc_power:
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index f36aba1..97eeeeb 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -17,9 +17,10 @@
  *
  * Some parts based off of TI's 24xx code:
  *
- *   Copyright (C) 2004 Texas Instruments, Inc.
+ * Copyright (C) 2004-2009 Texas Instruments, Inc.
  *
  * Roughly modelled after the OMAP1 MPU timer code.
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License. See the file "COPYING" in the main directory of this archive
@@ -37,6 +38,7 @@
 
 #include <asm/mach/time.h>
 #include <mach/dmtimer.h>
+#include <asm/localtimer.h>
 
 /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
 #define MAX_GPTIMER_ID		12
@@ -82,7 +84,8 @@
 	case CLOCK_EVT_MODE_PERIODIC:
 		period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ;
 		period -= 1;
-
+		if (cpu_is_omap44xx())
+			period = 0xff;	/* FIXME: */
 		omap_dm_timer_set_load_start(gptimer, 1, 0xffffffff - period);
 		break;
 	case CLOCK_EVT_MODE_ONESHOT:
@@ -145,6 +148,9 @@
 		     "timer-gp: omap_dm_timer_set_source() failed\n");
 
 	tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer));
+	if (cpu_is_omap44xx())
+		/* Assuming 32kHz clk is driving GPT1 */
+		tick_rate = 32768;	/* FIXME: */
 
 	pr_info("OMAP clockevent source: GPTIMER%d at %u Hz\n",
 		gptimer_id, tick_rate);
@@ -224,6 +230,9 @@
 
 static void __init omap2_gp_timer_init(void)
 {
+#ifdef CONFIG_LOCAL_TIMERS
+	twd_base = IO_ADDRESS(OMAP44XX_LOCAL_TWD_BASE);
+#endif
 	omap_dm_timer_init();
 
 	omap2_gp_clockevent_init();
diff --git a/arch/arm/mach-omap2/timer-mpu.c b/arch/arm/mach-omap2/timer-mpu.c
new file mode 100644
index 0000000..c1a650a
--- /dev/null
+++ b/arch/arm/mach-omap2/timer-mpu.c
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+void __cpuinit local_timer_setup(struct clock_event_device *evt)
+{
+	evt->irq = INT_44XX_LOCALTIMER_IRQ;
+	twd_timer_setup(evt);
+}
+
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index 34a56a1..d85296d 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -28,10 +28,20 @@
 
 #include <mach/hardware.h>
 #include <mach/irqs.h>
-#include <mach/pm.h>
 #include <mach/mux.h>
 #include <mach/usb.h>
 
+#define OTG_SYSCONFIG	(OMAP34XX_HSUSB_OTG_BASE + 0x404)
+
+static void __init usb_musb_pm_init(void)
+{
+	/* Ensure force-idle mode for OTG controller */
+	if (cpu_is_omap34xx())
+		omap_writel(0, OTG_SYSCONFIG);
+}
+
+#ifdef CONFIG_USB_MUSB_SOC
+
 static struct resource musb_resources[] = {
 	[0] = { /* start and end set dynamically */
 		.flags	= IORESOURCE_MEM,
@@ -184,4 +194,13 @@
 		printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n");
 		return;
 	}
+
+	usb_musb_pm_init();
 }
+
+#else
+void __init usb_musb_init(void)
+{
+	usb_musb_pm_init();
+}
+#endif /* CONFIG_USB_MUSB_SOC */
diff --git a/arch/arm/mach-orion5x/addr-map.c b/arch/arm/mach-orion5x/addr-map.c
index c14d121..6f3f77d 100644
--- a/arch/arm/mach-orion5x/addr-map.c
+++ b/arch/arm/mach-orion5x/addr-map.c
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/mbus.h>
 #include <linux/io.h>
+#include <linux/errno.h>
 #include <mach/hardware.h>
 #include "common.h"
 
@@ -44,6 +45,7 @@
 #define TARGET_DEV_BUS		1
 #define TARGET_PCI		3
 #define TARGET_PCIE		4
+#define TARGET_SRAM		9
 #define ATTR_PCIE_MEM		0x59
 #define ATTR_PCIE_IO		0x51
 #define ATTR_PCIE_WA		0x79
@@ -53,6 +55,7 @@
 #define ATTR_DEV_CS1		0x1d
 #define ATTR_DEV_CS2		0x1b
 #define ATTR_DEV_BOOT		0xf
+#define ATTR_SRAM		0x0
 
 /*
  * Helpers to get DDR bank info
@@ -87,13 +90,13 @@
 	return 0;
 }
 
-static void __init setup_cpu_win(int win, u32 base, u32 size,
+static int __init setup_cpu_win(int win, u32 base, u32 size,
 				 u8 target, u8 attr, int remap)
 {
 	if (win >= 8) {
 		printk(KERN_ERR "setup_cpu_win: trying to allocate "
 				"window %d\n", win);
-		return;
+		return -ENOSPC;
 	}
 
 	writel(base & 0xffff0000, CPU_WIN_BASE(win));
@@ -107,6 +110,7 @@
 		writel(remap & 0xffff0000, CPU_WIN_REMAP_LO(win));
 		writel(0, CPU_WIN_REMAP_HI(win));
 	}
+	return 0;
 }
 
 void __init orion5x_setup_cpu_mbus_bridge(void)
@@ -193,3 +197,9 @@
 	setup_cpu_win(win_alloc_count++, base, size,
 		      TARGET_PCIE, ATTR_PCIE_WA, -1);
 }
+
+int __init orion5x_setup_sram_win(void)
+{
+	return setup_cpu_win(win_alloc_count, ORION5X_SRAM_PHYS_BASE,
+			ORION5X_SRAM_SIZE, TARGET_SRAM, ATTR_SRAM, -1);
+}
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index b1c7778..eafcc49 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -31,7 +31,7 @@
 #include <plat/ehci-orion.h>
 #include <plat/mv_xor.h>
 #include <plat/orion_nand.h>
-#include <plat/orion5x_wdt.h>
+#include <plat/orion_wdt.h>
 #include <plat/time.h>
 #include "common.h"
 
@@ -536,16 +536,52 @@
 	platform_device_register(&orion5x_xor1_channel);
 }
 
+static struct resource orion5x_crypto_res[] = {
+	{
+		.name   = "regs",
+		.start  = ORION5X_CRYPTO_PHYS_BASE,
+		.end    = ORION5X_CRYPTO_PHYS_BASE + 0xffff,
+		.flags  = IORESOURCE_MEM,
+	}, {
+		.name   = "sram",
+		.start  = ORION5X_SRAM_PHYS_BASE,
+		.end    = ORION5X_SRAM_PHYS_BASE + SZ_8K - 1,
+		.flags  = IORESOURCE_MEM,
+	}, {
+		.name   = "crypto interrupt",
+		.start  = IRQ_ORION5X_CESA,
+		.end    = IRQ_ORION5X_CESA,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device orion5x_crypto_device = {
+	.name           = "mv_crypto",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(orion5x_crypto_res),
+	.resource       = orion5x_crypto_res,
+};
+
+int __init orion5x_crypto_init(void)
+{
+	int ret;
+
+	ret = orion5x_setup_sram_win();
+	if (ret)
+		return ret;
+
+	return platform_device_register(&orion5x_crypto_device);
+}
 
 /*****************************************************************************
  * Watchdog
  ****************************************************************************/
-static struct orion5x_wdt_platform_data orion5x_wdt_data = {
+static struct orion_wdt_platform_data orion5x_wdt_data = {
 	.tclk			= 0,
 };
 
 static struct platform_device orion5x_wdt_device = {
-	.name		= "orion5x_wdt",
+	.name		= "orion_wdt",
 	.id		= -1,
 	.dev		= {
 		.platform_data	= &orion5x_wdt_data,
diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h
index 798b9a5..de483e8 100644
--- a/arch/arm/mach-orion5x/common.h
+++ b/arch/arm/mach-orion5x/common.h
@@ -26,6 +26,7 @@
 void orion5x_setup_dev1_win(u32 base, u32 size);
 void orion5x_setup_dev2_win(u32 base, u32 size);
 void orion5x_setup_pcie_wa_win(u32 base, u32 size);
+int orion5x_setup_sram_win(void);
 
 void orion5x_ehci0_init(void);
 void orion5x_ehci1_init(void);
@@ -37,6 +38,7 @@
 void orion5x_uart0_init(void);
 void orion5x_uart1_init(void);
 void orion5x_xor_init(void);
+int orion5x_crypto_init(void);
 
 /*
  * PCIe/PCI functions.
diff --git a/arch/arm/mach-orion5x/include/mach/bridge-regs.h b/arch/arm/mach-orion5x/include/mach/bridge-regs.h
index be896e5..5c9744c 100644
--- a/arch/arm/mach-orion5x/include/mach/bridge-regs.h
+++ b/arch/arm/mach-orion5x/include/mach/bridge-regs.h
@@ -17,8 +17,8 @@
 
 #define CPU_CTRL		(ORION5X_BRIDGE_VIRT_BASE | 0x104)
 
-#define CPU_RESET_MASK		(ORION5X_BRIDGE_VIRT_BASE | 0x108)
-#define WDT_RESET		0x0002
+#define RSTOUTn_MASK		(ORION5X_BRIDGE_VIRT_BASE | 0x108)
+#define WDT_RESET_OUT_EN	0x0002
 
 #define CPU_SOFT_RESET		(ORION5X_BRIDGE_VIRT_BASE | 0x10c)
 
diff --git a/arch/arm/mach-orion5x/include/mach/orion5x.h b/arch/arm/mach-orion5x/include/mach/orion5x.h
index 377a773..2d87665 100644
--- a/arch/arm/mach-orion5x/include/mach/orion5x.h
+++ b/arch/arm/mach-orion5x/include/mach/orion5x.h
@@ -24,6 +24,7 @@
  * f1000000	on-chip peripheral registers
  * f2000000	PCIe I/O space
  * f2100000	PCI I/O space
+ * f2200000	SRAM dedicated for the crypto unit
  * f4000000	device bus mappings (boot)
  * fa000000	device bus mappings (cs0)
  * fa800000	device bus mappings (cs2)
@@ -49,6 +50,9 @@
 #define ORION5X_PCI_IO_BUS_BASE		0x00100000
 #define ORION5X_PCI_IO_SIZE		SZ_1M
 
+#define ORION5X_SRAM_PHYS_BASE		(0xf2200000)
+#define ORION5X_SRAM_SIZE		SZ_8K
+
 /* Relevant only for Orion-1/Orion-NAS */
 #define ORION5X_PCIE_WA_PHYS_BASE	0xf0000000
 #define ORION5X_PCIE_WA_VIRT_BASE	0xfe000000
@@ -94,6 +98,8 @@
 #define ORION5X_SATA_PHYS_BASE		(ORION5X_REGS_PHYS_BASE | 0x80000)
 #define ORION5X_SATA_VIRT_BASE		(ORION5X_REGS_VIRT_BASE | 0x80000)
 
+#define ORION5X_CRYPTO_PHYS_BASE	(ORION5X_REGS_PHYS_BASE | 0x90000)
+
 #define ORION5X_USB1_PHYS_BASE		(ORION5X_REGS_PHYS_BASE | 0xa0000)
 #define ORION5X_USB1_VIRT_BASE		(ORION5X_REGS_VIRT_BASE | 0xa0000)
 
diff --git a/arch/arm/mach-orion5x/include/mach/system.h b/arch/arm/mach-orion5x/include/mach/system.h
index e912490..60e734c 100644
--- a/arch/arm/mach-orion5x/include/mach/system.h
+++ b/arch/arm/mach-orion5x/include/mach/system.h
@@ -23,7 +23,7 @@
 	/*
 	 * Enable and issue soft reset
 	 */
-	orion5x_setbits(CPU_RESET_MASK, (1 << 2));
+	orion5x_setbits(RSTOUTn_MASK, (1 << 2));
 	orion5x_setbits(CPU_SOFT_RESET, 1);
 }
 
diff --git a/arch/arm/mach-orion5x/mpp.c b/arch/arm/mach-orion5x/mpp.c
index e23a3f9..bc4c3b9 100644
--- a/arch/arm/mach-orion5x/mpp.c
+++ b/arch/arm/mach-orion5x/mpp.c
@@ -124,6 +124,9 @@
 	u32 mpp_8_15_ctrl = readl(MPP_8_15_CTRL);
 	u32 mpp_16_19_ctrl = readl(MPP_16_19_CTRL);
 
+	/* Initialize gpiolib. */
+	orion_gpio_init();
+
 	while (mode->mpp >= 0) {
 		u32 *reg;
 		int num_type;
diff --git a/arch/arm/mach-orion5x/mss2-setup.c b/arch/arm/mach-orion5x/mss2-setup.c
index 41e6d50..61c086b 100644
--- a/arch/arm/mach-orion5x/mss2-setup.c
+++ b/arch/arm/mach-orion5x/mss2-setup.c
@@ -181,9 +181,9 @@
 	/*
 	 * Enable and issue soft reset
 	 */
-	reg = readl(CPU_RESET_MASK);
+	reg = readl(RSTOUTn_MASK);
 	reg |= 1 << 2;
-	writel(reg, CPU_RESET_MASK);
+	writel(reg, RSTOUTn_MASK);
 
 	reg = readl(CPU_SOFT_RESET);
 	reg |= 1;
diff --git a/arch/arm/mach-orion5x/ts78xx-fpga.h b/arch/arm/mach-orion5x/ts78xx-fpga.h
index 0f9cdf4..37b3d48 100644
--- a/arch/arm/mach-orion5x/ts78xx-fpga.h
+++ b/arch/arm/mach-orion5x/ts78xx-fpga.h
@@ -25,6 +25,7 @@
 	/* Technologic Systems */
 	struct fpga_device 	ts_rtc;
 	struct fpga_device 	ts_nand;
+	struct fpga_device 	ts_rng;
 };
 
 struct ts78xx_fpga_data {
diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index 9a6b397..5041d1b 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -17,6 +17,7 @@
 #include <linux/m48t86.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/timeriomem-rng.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -270,12 +271,57 @@
 }
 
 /*****************************************************************************
+ * HW RNG
+ ****************************************************************************/
+#define TS_RNG_DATA	(TS78XX_FPGA_REGS_PHYS_BASE | 0x044)
+
+static struct resource ts78xx_ts_rng_resource = {
+	.flags		= IORESOURCE_MEM,
+	.start		= TS_RNG_DATA,
+	.end		= TS_RNG_DATA + 4 - 1,
+};
+
+static struct timeriomem_rng_data ts78xx_ts_rng_data = {
+	.period		= 1000000, /* one second */
+};
+
+static struct platform_device ts78xx_ts_rng_device = {
+	.name		= "timeriomem_rng",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &ts78xx_ts_rng_data,
+	},
+	.resource	= &ts78xx_ts_rng_resource,
+	.num_resources	= 1,
+};
+
+static int ts78xx_ts_rng_load(void)
+{
+	int rc;
+
+	if (ts78xx_fpga.supports.ts_rng.init == 0) {
+		rc = platform_device_register(&ts78xx_ts_rng_device);
+		if (!rc)
+			ts78xx_fpga.supports.ts_rng.init = 1;
+	} else
+		rc = platform_device_add(&ts78xx_ts_rng_device);
+
+	return rc;
+};
+
+static void ts78xx_ts_rng_unload(void)
+{
+	platform_device_del(&ts78xx_ts_rng_device);
+}
+
+/*****************************************************************************
  * FPGA 'hotplug' support code
  ****************************************************************************/
 static void ts78xx_fpga_devices_zero_init(void)
 {
 	ts78xx_fpga.supports.ts_rtc.init = 0;
 	ts78xx_fpga.supports.ts_nand.init = 0;
+	ts78xx_fpga.supports.ts_rng.init = 0;
 }
 
 static void ts78xx_fpga_supports(void)
@@ -289,10 +335,12 @@
 	case TS7800_REV_5:
 		ts78xx_fpga.supports.ts_rtc.present = 1;
 		ts78xx_fpga.supports.ts_nand.present = 1;
+		ts78xx_fpga.supports.ts_rng.present = 1;
 		break;
 	default:
 		ts78xx_fpga.supports.ts_rtc.present = 0;
 		ts78xx_fpga.supports.ts_nand.present = 0;
+		ts78xx_fpga.supports.ts_rng.present = 0;
 	}
 }
 
@@ -316,6 +364,14 @@
 		}
 		ret |= tmp;
 	}
+	if (ts78xx_fpga.supports.ts_rng.present == 1) {
+		tmp = ts78xx_ts_rng_load();
+		if (tmp) {
+			printk(KERN_INFO "TS-78xx: RNG not registered\n");
+			ts78xx_fpga.supports.ts_rng.present = 0;
+		}
+		ret |= tmp;
+	}
 
 	return ret;
 }
@@ -328,6 +384,8 @@
 		ts78xx_ts_rtc_unload();
 	if (ts78xx_fpga.supports.ts_nand.present == 1)
 		ts78xx_ts_nand_unload();
+	if (ts78xx_fpga.supports.ts_rng.present == 1)
+		ts78xx_ts_rng_unload();
 
 	return ret;
 }
diff --git a/arch/arm/mach-orion5x/wnr854t-setup.c b/arch/arm/mach-orion5x/wnr854t-setup.c
index 7ddc22c..6920821 100644
--- a/arch/arm/mach-orion5x/wnr854t-setup.c
+++ b/arch/arm/mach-orion5x/wnr854t-setup.c
@@ -15,6 +15,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/ethtool.h>
+#include <net/dsa.h>
 #include <asm/mach-types.h>
 #include <asm/gpio.h>
 #include <asm/mach/arch.h>
@@ -97,6 +98,20 @@
 	.duplex		= DUPLEX_FULL,
 };
 
+static struct dsa_chip_data wnr854t_switch_chip_data = {
+	.port_names[0] = "lan3",
+	.port_names[1] = "lan4",
+	.port_names[2] = "wan",
+	.port_names[3] = "cpu",
+	.port_names[5] = "lan1",
+	.port_names[7] = "lan2",
+};
+
+static struct dsa_platform_data wnr854t_switch_plat_data = {
+	.nr_chips	= 1,
+	.chip		= &wnr854t_switch_chip_data,
+};
+
 static void __init wnr854t_init(void)
 {
 	/*
@@ -110,6 +125,7 @@
 	 * Configure peripherals.
 	 */
 	orion5x_eth_init(&wnr854t_eth_data);
+	orion5x_eth_switch_init(&wnr854t_switch_plat_data, NO_IRQ);
 	orion5x_uart0_init();
 
 	orion5x_setup_dev_boot_win(WNR854T_NOR_BOOT_BASE,
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 17d3fbd..f4533f8 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -51,6 +51,12 @@
 	select IWMMXT
 	select PXA_HAVE_BOARD_IRQS
 
+config MACH_STARGATE2
+	bool "Intel Stargate 2 Platform"
+	select PXA27x
+	select IWMMXT
+	select PXA_HAVE_BOARD_IRQS
+
 config ARCH_LUBBOCK
 	bool "Intel DBPXA250 Development Platform"
 	select PXA25x
@@ -88,6 +94,10 @@
 	  SL-C3000 (Spitz), SL-C3100 (Borzoi) or SL-C6000x (Tosa)
 	  handheld computer.
 
+config SHARPSL_PM
+	bool
+	select APM_EMULATION
+
 config CORGI_SSP_DEPRECATED
 	bool
 	select PXA_SSP
@@ -280,6 +290,7 @@
 	select PXA3xx
 	select PXA_SSP
 	select HAVE_PWM
+	select PXA_HAVE_BOARD_IRQS
 
 config MACH_LITTLETON
 	bool "PXA3xx Form Factor Platform (aka Littleton)"
@@ -308,6 +319,14 @@
 	select PXA3xx
 	select CPU_PXA300
 
+config MACH_H4700
+	bool "HP iPAQ hx4700"
+	select PXA27x
+	select IWMMXT
+	select PXA_SSP
+	select HAVE_PWM
+	select PXA_HAVE_BOARD_IRQS
+
 config MACH_MAGICIAN
 	bool "Enable HTC Magician Support"
 	select PXA27x
@@ -505,12 +524,6 @@
 	help
 	  Enable support for PXA2xx SSP ports
 
-config PXA_PWM
-	tristate
-	default BACKLIGHT_PWM
-	help
-	  Enable support for PXA2xx/PXA3xx PWM controllers
-
 config TOSA_BT
 	tristate "Control the state of built-in bluetooth chip on Sharp SL-6000"
 	depends on MACH_TOSA
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 682dbf4..d18ffef 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -15,7 +15,6 @@
 
 # Generic drivers that other drivers may depend upon
 obj-$(CONFIG_PXA_SSP)		+= ssp.o
-obj-$(CONFIG_PXA_PWM)		+= pwm.o
 
 # SoC-specific code
 obj-$(CONFIG_PXA25x)		+= mfp-pxa2xx.o pxa2xx.o pxa25x.o
@@ -47,6 +46,7 @@
 obj-$(CONFIG_MACH_PCM990_BASEBOARD)	+= pcm990-baseboard.o
 obj-$(CONFIG_MACH_TOSA)		+= tosa.o
 obj-$(CONFIG_MACH_EM_X270)	+= em-x270.o
+obj-$(CONFIG_MACH_H4700)	+= hx4700.o
 obj-$(CONFIG_MACH_MAGICIAN)	+= magician.o
 obj-$(CONFIG_MACH_HIMALAYA)	+= himalaya.o
 obj-$(CONFIG_MACH_MIOA701)	+= mioa701.o mioa701_bootresume.o
@@ -78,6 +78,7 @@
 obj-$(CONFIG_PXA_EZX)           += ezx.o
 
 obj-$(CONFIG_MACH_INTELMOTE2)   += imote2.o
+obj-$(CONFIG_MACH_STARGATE2)	+= stargate2.o
 obj-$(CONFIG_MACH_CSB726)	+= csb726.o
 obj-$(CONFIG_CSB726_CSB701)	+= csb701.o
 
diff --git a/arch/arm/mach-pxa/clock.c b/arch/arm/mach-pxa/clock.c
index db52d2c..49ae382 100644
--- a/arch/arm/mach-pxa/clock.c
+++ b/arch/arm/mach-pxa/clock.c
@@ -86,20 +86,3 @@
 	for (i = 0; i < num; i++)
 		clkdev_add(&clks[i]);
 }
-
-int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
-	struct device *dev)
-{
-	struct clk *r = clk_get(dev, id);
-	struct clk_lookup *l;
-
-	if (!r)
-		return -ENODEV;
-
-	l = clkdev_alloc(r, alias, alias_dev_name);
-	clk_put(r);
-	if (!l)
-		return -ENODEV;
-	clkdev_add(l);
-	return 0;
-}
diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c
index 34576ba..1d2cec2 100644
--- a/arch/arm/mach-pxa/cm-x270.c
+++ b/arch/arm/mach-pxa/cm-x270.c
@@ -335,6 +335,10 @@
 {
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(cmx270_pin_config));
 
+#ifdef CONFIG_PM
+	pxa27x_set_pwrmode(PWRMODE_DEEPSLEEP);
+#endif
+
 	cmx270_init_rtc();
 	cmx270_init_mmc();
 	cmx270_init_ohci();
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index a9f48b1..465da26 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -21,18 +21,20 @@
 #include <linux/gpio.h>
 #include <linux/dm9000.h>
 #include <linux/leds.h>
+#include <linux/rtc-v3020.h>
 
 #include <linux/i2c.h>
 #include <linux/i2c/pca953x.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/setup.h>
 
 #include <mach/pxa300.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/ohci.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/pxa3xx_nand.h>
 
 #include <asm/mach/map.h>
@@ -46,6 +48,11 @@
 
 #define	CM_X300_MMC2_IRQ	IRQ_GPIO(GPIO82_MMC2_IRQ)
 
+#define GPIO95_RTC_CS		(95)
+#define GPIO96_RTC_WR		(96)
+#define GPIO97_RTC_RD		(97)
+#define GPIO98_RTC_IO		(98)
+
 static mfp_cfg_t cm_x300_mfp_cfg[] __initdata = {
 	/* LCD */
 	GPIO54_LCD_LDD_0,
@@ -135,6 +142,12 @@
 	GPIO85_GPIO,			/* MMC WP */
 	GPIO99_GPIO,			/* Ethernet IRQ */
 
+	/* RTC GPIOs */
+	GPIO95_GPIO,			/* RTC CS */
+	GPIO96_GPIO,			/* RTC WR */
+	GPIO97_GPIO,			/* RTC RD */
+	GPIO98_GPIO,			/* RTC IO */
+
 	/* Standard I2C */
 	GPIO21_I2C_SCL,
 	GPIO22_I2C_SDA,
@@ -265,6 +278,7 @@
 
 static struct pxa3xx_nand_platform_data cm_x300_nand_info = {
 	.enable_arbiter	= 1,
+	.keep_config	= 1,
 	.parts		= cm_x300_nand_partitions,
 	.nr_parts	= ARRAY_SIZE(cm_x300_nand_partitions),
 };
@@ -441,6 +455,31 @@
 static inline void cm_x300_init_i2c(void) {}
 #endif
 
+#if defined(CONFIG_RTC_DRV_V3020) || defined(CONFIG_RTC_DRV_V3020_MODULE)
+struct v3020_platform_data cm_x300_v3020_pdata = {
+	.use_gpio	= 1,
+	.gpio_cs	= GPIO95_RTC_CS,
+	.gpio_wr	= GPIO96_RTC_WR,
+	.gpio_rd	= GPIO97_RTC_RD,
+	.gpio_io	= GPIO98_RTC_IO,
+};
+
+static struct platform_device cm_x300_rtc_device = {
+	.name		= "v3020",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &cm_x300_v3020_pdata,
+	}
+};
+
+static void __init cm_x300_init_rtc(void)
+{
+	platform_device_register(&cm_x300_rtc_device);
+}
+#else
+static inline void cm_x300_init_rtc(void) {}
+#endif
+
 static void __init cm_x300_init(void)
 {
 	/* board-processor specific GPIO initialization */
@@ -453,6 +492,19 @@
 	cm_x300_init_nand();
 	cm_x300_init_leds();
 	cm_x300_init_i2c();
+	cm_x300_init_rtc();
+}
+
+static void __init cm_x300_fixup(struct machine_desc *mdesc, struct tag *tags,
+				 char **cmdline, struct meminfo *mi)
+{
+	mi->nr_banks = 2;
+	mi->bank[0].start = 0xa0000000;
+	mi->bank[0].node = 0;
+	mi->bank[0].size = (64*1024*1024);
+	mi->bank[1].start = 0xc0000000;
+	mi->bank[1].node = 0;
+	mi->bank[1].size = (64*1024*1024);
 }
 
 MACHINE_START(CM_X300, "CM-X300 module")
@@ -463,4 +515,5 @@
 	.init_irq	= pxa3xx_init_irq,
 	.timer		= &pxa_timer,
 	.init_machine	= cm_x300_init,
+	.fixup		= cm_x300_fixup,
 MACHINE_END
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index 930e364..962dda2 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -42,7 +42,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/pxa25x.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/irda.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
@@ -445,13 +445,8 @@
 	.wait_for_sync		= corgi_wait_for_hsync,
 };
 
-static void corgi_ads7846_cs(u32 command)
-{
-	gpio_set_value(CORGI_GPIO_ADS7846_CS, !(command == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip corgi_ads7846_chip = {
-	.cs_control	= corgi_ads7846_cs,
+	.gpio_cs	= CORGI_GPIO_ADS7846_CS,
 };
 
 static void corgi_bl_kick_battery(void)
@@ -475,22 +470,12 @@
 	.kick_battery		= corgi_bl_kick_battery,
 };
 
-static void corgi_lcdcon_cs(u32 command)
-{
-	gpio_set_value(CORGI_GPIO_LCDCON_CS, !(command == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip corgi_lcdcon_chip = {
-	.cs_control	= corgi_lcdcon_cs,
+	.gpio_cs	= CORGI_GPIO_LCDCON_CS,
 };
 
-static void corgi_max1111_cs(u32 command)
-{
-	gpio_set_value(CORGI_GPIO_MAX1111_CS, !(command == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip corgi_max1111_chip = {
-	.cs_control	= corgi_max1111_cs,
+	.gpio_cs	= CORGI_GPIO_MAX1111_CS,
 };
 
 static struct spi_board_info corgi_spi_devices[] = {
@@ -520,32 +505,8 @@
 
 static void __init corgi_init_spi(void)
 {
-	int err;
-
-	err = gpio_request(CORGI_GPIO_ADS7846_CS, "ADS7846_CS");
-	if (err)
-		return;
-
-	err = gpio_request(CORGI_GPIO_LCDCON_CS, "LCDCON_CS");
-	if (err)
-		goto err_free_1;
-
-	err = gpio_request(CORGI_GPIO_MAX1111_CS, "MAX1111_CS");
-	if (err)
-		goto err_free_2;
-
-	gpio_direction_output(CORGI_GPIO_ADS7846_CS, 1);
-	gpio_direction_output(CORGI_GPIO_LCDCON_CS, 1);
-	gpio_direction_output(CORGI_GPIO_MAX1111_CS, 1);
-
 	pxa2xx_set_spi_info(1, &corgi_spi_info);
 	spi_register_board_info(ARRAY_AND_SIZE(corgi_spi_devices));
-	return;
-
-err_free_2:
-	gpio_free(CORGI_GPIO_LCDCON_CS);
-err_free_1:
-	gpio_free(CORGI_GPIO_ADS7846_CS);
 }
 #else
 static inline void corgi_init_spi(void) {}
diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c
index 7f04b3a..a093282 100644
--- a/arch/arm/mach-pxa/corgi_pm.c
+++ b/arch/arm/mach-pxa/corgi_pm.c
@@ -41,7 +41,6 @@
 	pxa_gpio_mode(CORGI_GPIO_CHRG_ON | GPIO_OUT);
 	pxa_gpio_mode(CORGI_GPIO_CHRG_UKN | GPIO_OUT);
 	pxa_gpio_mode(CORGI_GPIO_KEY_INT | GPIO_IN);
-	sharpsl_pm_pxa_init();
 }
 
 static void corgi_measure_temp(int on)
@@ -191,7 +190,7 @@
 
 static struct sharpsl_charger_machinfo corgi_pm_machinfo = {
 	.init            = corgi_charger_init,
-	.exit            = sharpsl_pm_pxa_remove,
+	.exit            = NULL,
 	.gpio_batlock    = CORGI_GPIO_BAT_COVER,
 	.gpio_acin       = CORGI_GPIO_AC_IN,
 	.gpio_batfull    = CORGI_GPIO_CHRG_FULL,
diff --git a/arch/arm/mach-pxa/cpufreq-pxa2xx.c b/arch/arm/mach-pxa/cpufreq-pxa2xx.c
index 083a1d8..3a8ee22 100644
--- a/arch/arm/mach-pxa/cpufreq-pxa2xx.c
+++ b/arch/arm/mach-pxa/cpufreq-pxa2xx.c
@@ -36,6 +36,8 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
 
 #include <mach/pxa2xx-regs.h>
 
@@ -47,6 +49,8 @@
 #define freq_debug  0
 #endif
 
+static struct regulator *vcc_core;
+
 static unsigned int pxa27x_maxfreq;
 module_param(pxa27x_maxfreq, uint, 0);
 MODULE_PARM_DESC(pxa27x_maxfreq, "Set the pxa27x maxfreq in MHz"
@@ -58,6 +62,8 @@
 	unsigned int cccr;
 	unsigned int div2;
 	unsigned int cclkcfg;
+	int vmin;
+	int vmax;
 } pxa_freqs_t;
 
 /* Define the refresh period in mSec for the SDRAM and the number of rows */
@@ -82,24 +88,24 @@
 
 static pxa_freqs_t pxa255_run_freqs[] =
 {
-	/* CPU   MEMBUS  CCCR  DIV2 CCLKCFG	   run  turbo PXbus SDRAM */
-	{ 99500,  99500, 0x121, 1,  CCLKCFG},	/*  99,   99,   50,   50  */
-	{132700, 132700, 0x123, 1,  CCLKCFG},	/* 133,  133,   66,   66  */
-	{199100,  99500, 0x141, 0,  CCLKCFG},	/* 199,  199,   99,   99  */
-	{265400, 132700, 0x143, 1,  CCLKCFG},	/* 265,  265,  133,   66  */
-	{331800, 165900, 0x145, 1,  CCLKCFG},	/* 331,  331,  166,   83  */
-	{398100,  99500, 0x161, 0,  CCLKCFG},	/* 398,  398,  196,   99  */
+	/* CPU   MEMBUS  CCCR  DIV2 CCLKCFG	           run  turbo PXbus SDRAM */
+	{ 99500,  99500, 0x121, 1,  CCLKCFG, -1, -1},	/*  99,   99,   50,   50  */
+	{132700, 132700, 0x123, 1,  CCLKCFG, -1, -1},	/* 133,  133,   66,   66  */
+	{199100,  99500, 0x141, 0,  CCLKCFG, -1, -1},	/* 199,  199,   99,   99  */
+	{265400, 132700, 0x143, 1,  CCLKCFG, -1, -1},	/* 265,  265,  133,   66  */
+	{331800, 165900, 0x145, 1,  CCLKCFG, -1, -1},	/* 331,  331,  166,   83  */
+	{398100,  99500, 0x161, 0,  CCLKCFG, -1, -1},	/* 398,  398,  196,   99  */
 };
 
 /* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */
 static pxa_freqs_t pxa255_turbo_freqs[] =
 {
 	/* CPU   MEMBUS  CCCR  DIV2 CCLKCFG	   run  turbo PXbus SDRAM */
-	{ 99500, 99500,  0x121, 1,  CCLKCFG},	/*  99,   99,   50,   50  */
-	{199100, 99500,  0x221, 0,  CCLKCFG},	/*  99,  199,   50,   99  */
-	{298500, 99500,  0x321, 0,  CCLKCFG},	/*  99,  287,   50,   99  */
-	{298600, 99500,  0x1c1, 0,  CCLKCFG},	/* 199,  287,   99,   99  */
-	{398100, 99500,  0x241, 0,  CCLKCFG},	/* 199,  398,   99,   99  */
+	{ 99500, 99500,  0x121, 1,  CCLKCFG, -1, -1},	/*  99,   99,   50,   50  */
+	{199100, 99500,  0x221, 0,  CCLKCFG, -1, -1},	/*  99,  199,   50,   99  */
+	{298500, 99500,  0x321, 0,  CCLKCFG, -1, -1},	/*  99,  287,   50,   99  */
+	{298600, 99500,  0x1c1, 0,  CCLKCFG, -1, -1},	/* 199,  287,   99,   99  */
+	{398100, 99500,  0x241, 0,  CCLKCFG, -1, -1},	/* 199,  398,   99,   99  */
 };
 
 #define NUM_PXA25x_RUN_FREQS ARRAY_SIZE(pxa255_run_freqs)
@@ -148,13 +154,13 @@
    ((T)  ? CCLKCFG_TURBO : 0))
 
 static pxa_freqs_t pxa27x_freqs[] = {
-	{104000, 104000, PXA27x_CCCR(1,	 8, 2), 0, CCLKCFG2(1, 0, 1)},
-	{156000, 104000, PXA27x_CCCR(1,	 8, 6), 0, CCLKCFG2(1, 1, 1)},
-	{208000, 208000, PXA27x_CCCR(0, 16, 2), 1, CCLKCFG2(0, 0, 1)},
-	{312000, 208000, PXA27x_CCCR(1, 16, 3), 1, CCLKCFG2(1, 0, 1)},
-	{416000, 208000, PXA27x_CCCR(1, 16, 4), 1, CCLKCFG2(1, 0, 1)},
-	{520000, 208000, PXA27x_CCCR(1, 16, 5), 1, CCLKCFG2(1, 0, 1)},
-	{624000, 208000, PXA27x_CCCR(1, 16, 6), 1, CCLKCFG2(1, 0, 1)}
+	{104000, 104000, PXA27x_CCCR(1,	 8, 2), 0, CCLKCFG2(1, 0, 1),  900000, 1705000 },
+	{156000, 104000, PXA27x_CCCR(1,	 8, 6), 0, CCLKCFG2(1, 1, 1), 1000000, 1705000 },
+	{208000, 208000, PXA27x_CCCR(0, 16, 2), 1, CCLKCFG2(0, 0, 1), 1180000, 1705000 },
+	{312000, 208000, PXA27x_CCCR(1, 16, 3), 1, CCLKCFG2(1, 0, 1), 1250000, 1705000 },
+	{416000, 208000, PXA27x_CCCR(1, 16, 4), 1, CCLKCFG2(1, 0, 1), 1350000, 1705000 },
+	{520000, 208000, PXA27x_CCCR(1, 16, 5), 1, CCLKCFG2(1, 0, 1), 1450000, 1705000 },
+	{624000, 208000, PXA27x_CCCR(1, 16, 6), 1, CCLKCFG2(1, 0, 1), 1550000, 1705000 }
 };
 
 #define NUM_PXA27x_FREQS ARRAY_SIZE(pxa27x_freqs)
@@ -163,6 +169,47 @@
 
 extern unsigned get_clk_frequency_khz(int info);
 
+#ifdef CONFIG_REGULATOR
+
+static int pxa_cpufreq_change_voltage(pxa_freqs_t *pxa_freq)
+{
+	int ret = 0;
+	int vmin, vmax;
+
+	if (!cpu_is_pxa27x())
+		return 0;
+
+	vmin = pxa_freq->vmin;
+	vmax = pxa_freq->vmax;
+	if ((vmin == -1) || (vmax == -1))
+		return 0;
+
+	ret = regulator_set_voltage(vcc_core, vmin, vmax);
+	if (ret)
+		pr_err("cpufreq: Failed to set vcc_core in [%dmV..%dmV]\n",
+		       vmin, vmax);
+	return ret;
+}
+
+static __init void pxa_cpufreq_init_voltages(void)
+{
+	vcc_core = regulator_get(NULL, "vcc_core");
+	if (IS_ERR(vcc_core)) {
+		pr_info("cpufreq: Didn't find vcc_core regulator\n");
+		vcc_core = NULL;
+	} else {
+		pr_info("cpufreq: Found vcc_core regulator\n");
+	}
+}
+#else
+static int pxa_cpufreq_change_voltage(pxa_freqs_t *pxa_freq)
+{
+	return 0;
+}
+
+static __init void pxa_cpufreq_init_voltages(void) { }
+#endif
+
 static void find_freq_tables(struct cpufreq_frequency_table **freq_table,
 			     pxa_freqs_t **pxa_freqs)
 {
@@ -251,6 +298,7 @@
 	unsigned long flags;
 	unsigned int new_freq_cpu, new_freq_mem;
 	unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg;
+	int ret = 0;
 
 	/* Get the current policy */
 	find_freq_tables(&pxa_freqs_table, &pxa_freq_settings);
@@ -273,6 +321,10 @@
 			 freqs.new / 1000, (pxa_freq_settings[idx].div2) ?
 			 (new_freq_mem / 2000) : (new_freq_mem / 1000));
 
+	if (vcc_core && freqs.new > freqs.old)
+		ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]);
+	if (ret)
+		return ret;
 	/*
 	 * Tell everyone what we're about to do...
 	 * you should add a notify client with any platform specific
@@ -335,6 +387,18 @@
 	 */
 	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
+	/*
+	 * Even if voltage setting fails, we don't report it, as the frequency
+	 * change succeeded. The voltage reduction is not a critical failure,
+	 * only power savings will suffer from this.
+	 *
+	 * Note: if the voltage change fails, and a return value is returned, a
+	 * bug is triggered (seems a deadlock). Should anybody find out where,
+	 * the "return 0" should become a "return ret".
+	 */
+	if (vcc_core && freqs.new < freqs.old)
+		ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]);
+
 	return 0;
 }
 
@@ -349,6 +413,8 @@
 	if (cpu_is_pxa27x())
 		pxa27x_guess_max_freq();
 
+	pxa_cpufreq_init_voltages();
+
 	init_sdram_rows();
 
 	/* set default policy and cpuinfo */
diff --git a/arch/arm/mach-pxa/csb726.c b/arch/arm/mach-pxa/csb726.c
index 2b289f8..7d3e1b4 100644
--- a/arch/arm/mach-pxa/csb726.c
+++ b/arch/arm/mach-pxa/csb726.c
@@ -16,15 +16,17 @@
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/partitions.h>
 #include <linux/sm501.h>
+#include <linux/smsc911x.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/csb726.h>
 #include <mach/mfp-pxa27x.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/ohci.h>
 #include <mach/pxa2xx-regs.h>
+#include <mach/audio.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -275,15 +277,26 @@
 	{
 		.start	= CSB726_IRQ_LAN,
 		.end	= CSB726_IRQ_LAN,
-		.flags	= IORESOURCE_IRQ,
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
 	},
 };
 
+struct smsc911x_platform_config csb726_lan_config = {
+	.irq_type	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type	= SMSC911X_IRQ_TYPE_PUSH_PULL,
+	.flags		= SMSC911X_USE_32BIT,
+	.phy_interface	= PHY_INTERFACE_MODE_MII,
+};
+
+
 static struct platform_device csb726_lan = {
-	.name		= "smc911x",
+	.name		= "smsc911x",
 	.id		= -1,
 	.num_resources	= ARRAY_SIZE(csb726_lan_resources),
 	.resource	= csb726_lan_resources,
+	.dev		= {
+		.platform_data	= &csb726_lan_config,
+	},
 };
 
 static struct platform_device *devices[] __initdata = {
@@ -303,6 +316,7 @@
 	pxa27x_set_i2c_power_info(NULL);
 	pxa_set_mci_info(&csb726_mci);
 	pxa_set_ohci_info(&csb726_ohci_platform_data);
+	pxa_set_ac97_info(NULL);
 
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 }
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index 29970f7..ecc08f3 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -8,7 +8,7 @@
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/irda.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/ohci.h>
 #include <mach/pxa27x_keypad.h>
 #include <mach/pxa2xx_spi.h>
@@ -290,7 +290,7 @@
 };
 
 struct platform_device pxa3xx_device_i2c_power = {
-	.name		= "pxa2xx-i2c",
+	.name		= "pxa3xx-pwri2c",
 	.id		= 1,
 	.resource	= pxa3xx_resources_i2c_power,
 	.num_resources	= ARRAY_SIZE(pxa3xx_resources_i2c_power),
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index bc0f73f..243e080 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -28,6 +28,8 @@
 #include <linux/spi/libertas_spi.h>
 #include <linux/power_supply.h>
 #include <linux/apm-emulation.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pca953x.h>
 
 #include <media/soc_camera.h>
 
@@ -41,7 +43,7 @@
 #include <mach/ohci.h>
 #include <mach/mmc.h>
 #include <mach/pxa27x_keypad.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/camera.h>
 #include <mach/pxa2xx_spi.h>
 
@@ -52,23 +54,31 @@
 #define GPIO13_MMC_CD		(13)
 #define GPIO95_MMC_WP		(95)
 #define GPIO56_NAND_RB		(56)
+#define GPIO93_CAM_RESET	(93)
+#define GPIO16_USB_HUB_RESET	(16)
 
 /* eXeda specific GPIOs */
 #define GPIO114_MMC_CD		(114)
 #define GPIO20_NAND_RB		(20)
 #define GPIO38_SD_PWEN		(38)
+#define GPIO37_WLAN_RST		(37)
+#define GPIO95_TOUCHPAD_INT	(95)
+#define GPIO130_CAM_RESET	(130)
+#define GPIO10_USB_HUB_RESET	(10)
 
 /* common  GPIOs */
 #define GPIO11_NAND_CS		(11)
-#define GPIO93_CAM_RESET	(93)
 #define GPIO41_ETHIRQ		(41)
 #define EM_X270_ETHIRQ		IRQ_GPIO(GPIO41_ETHIRQ)
 #define GPIO115_WLAN_PWEN	(115)
 #define GPIO19_WLAN_STRAP	(19)
+#define GPIO9_USB_VBUS_EN	(9)
 
 static int mmc_cd;
 static int nand_rb;
 static int dm9000_flags;
+static int cam_reset;
+static int usb_hub_reset;
 
 static unsigned long common_pin_config[] = {
 	/* AC'97 */
@@ -180,7 +190,6 @@
 
 	/* power controls */
 	GPIO20_GPIO	| MFP_LPM_DRIVE_LOW,	/* GPRS_PWEN */
-	GPIO93_GPIO	| MFP_LPM_DRIVE_LOW,	/* Camera reset */
 	GPIO115_GPIO	| MFP_LPM_DRIVE_LOW,	/* WLAN_PWEN */
 
 	/* NAND controls */
@@ -191,14 +200,18 @@
 };
 
 static unsigned long em_x270_pin_config[] = {
-	GPIO13_GPIO,	/* MMC card detect */
-	GPIO56_GPIO,	/* NAND Ready/Busy */
-	GPIO95_GPIO,	/* MMC Write protect */
+	GPIO13_GPIO,				/* MMC card detect */
+	GPIO16_GPIO,				/* USB hub reset */
+	GPIO56_GPIO,				/* NAND Ready/Busy */
+	GPIO93_GPIO	| MFP_LPM_DRIVE_LOW,	/* Camera reset */
+	GPIO95_GPIO,				/* MMC Write protect */
 };
 
 static unsigned long exeda_pin_config[] = {
+	GPIO10_GPIO,				/* USB hub reset */
 	GPIO20_GPIO,				/* NAND Ready/Busy */
 	GPIO38_GPIO	| MFP_LPM_DRIVE_LOW,	/* SD slot power */
+	GPIO95_GPIO,				/* touchpad IRQ */
 	GPIO114_GPIO,				/* MMC card detect */
 };
 
@@ -464,18 +477,79 @@
 
 /* PXA27x OHCI controller setup */
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static struct regulator *em_x270_usb_ldo;
+
+static int em_x270_usb_hub_init(void)
+{
+	int err;
+
+	em_x270_usb_ldo = regulator_get(NULL, "vcc usb");
+	if (IS_ERR(em_x270_usb_ldo))
+		return PTR_ERR(em_x270_usb_ldo);
+
+	err = gpio_request(GPIO9_USB_VBUS_EN, "vbus en");
+	if (err)
+		goto err_free_usb_ldo;
+
+	err = gpio_request(usb_hub_reset, "hub rst");
+	if (err)
+		goto err_free_vbus_gpio;
+
+	/* USB Hub power-on and reset */
+	gpio_direction_output(usb_hub_reset, 0);
+	regulator_enable(em_x270_usb_ldo);
+	gpio_set_value(usb_hub_reset, 1);
+	gpio_set_value(usb_hub_reset, 0);
+	regulator_disable(em_x270_usb_ldo);
+	regulator_enable(em_x270_usb_ldo);
+	gpio_set_value(usb_hub_reset, 1);
+
+	/* enable VBUS */
+	gpio_direction_output(GPIO9_USB_VBUS_EN, 1);
+
+	return 0;
+
+err_free_vbus_gpio:
+	gpio_free(GPIO9_USB_VBUS_EN);
+err_free_usb_ldo:
+	regulator_put(em_x270_usb_ldo);
+
+	return err;
+}
+
 static int em_x270_ohci_init(struct device *dev)
 {
+	int err;
+
+	/* we don't want to entirely disable USB if the HUB init failed */
+	err = em_x270_usb_hub_init();
+	if (err)
+		pr_err("USB Hub initialization failed: %d\n", err);
+
 	/* enable port 2 transiever */
 	UP2OCR = UP2OCR_HXS | UP2OCR_HXOE;
 
 	return 0;
 }
 
+static void em_x270_ohci_exit(struct device *dev)
+{
+	gpio_free(usb_hub_reset);
+	gpio_free(GPIO9_USB_VBUS_EN);
+
+	if (!IS_ERR(em_x270_usb_ldo)) {
+		if (regulator_is_enabled(em_x270_usb_ldo))
+			regulator_disable(em_x270_usb_ldo);
+
+		regulator_put(em_x270_usb_ldo);
+	}
+}
+
 static struct pxaohci_platform_data em_x270_ohci_platform_data = {
 	.port_mode	= PMM_PERPORT_MODE,
 	.flags		= ENABLE_PORT1 | ENABLE_PORT2 | POWER_CONTROL_LOW,
 	.init		= em_x270_ohci_init,
+	.exit		= em_x270_ohci_exit,
 };
 
 static void __init em_x270_init_ohci(void)
@@ -677,26 +751,52 @@
 	if (err)
 		return err;
 
+	err = gpio_request(GPIO19_WLAN_STRAP, "WLAN STRAP");
+	if (err)
+		goto err_free_pwen;
+
+	if (machine_is_exeda()) {
+		err = gpio_request(GPIO37_WLAN_RST, "WLAN RST");
+		if (err)
+			goto err_free_strap;
+
+		gpio_direction_output(GPIO37_WLAN_RST, 1);
+		msleep(100);
+	}
+
 	gpio_direction_output(GPIO19_WLAN_STRAP, 1);
-	mdelay(100);
+	msleep(100);
 
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(em_x270_libertas_pin_config));
 
 	gpio_direction_output(GPIO115_WLAN_PWEN, 0);
-	mdelay(100);
+	msleep(100);
 	gpio_set_value(GPIO115_WLAN_PWEN, 1);
-	mdelay(100);
+	msleep(100);
 
 	spi->bits_per_word = 16;
 	spi_setup(spi);
 
 	return 0;
+
+err_free_strap:
+	gpio_free(GPIO19_WLAN_STRAP);
+err_free_pwen:
+	gpio_free(GPIO115_WLAN_PWEN);
+
+	return err;
 }
 
 static int em_x270_libertas_teardown(struct spi_device *spi)
 {
 	gpio_set_value(GPIO115_WLAN_PWEN, 0);
 	gpio_free(GPIO115_WLAN_PWEN);
+	gpio_free(GPIO19_WLAN_STRAP);
+
+	if (machine_is_exeda()) {
+		gpio_set_value(GPIO37_WLAN_RST, 0);
+		gpio_free(GPIO37_WLAN_RST);
+	}
 
 	return 0;
 }
@@ -863,26 +963,26 @@
 {
 	int ret;
 
-	ret = gpio_request(GPIO93_CAM_RESET, "camera reset");
+	ret = gpio_request(cam_reset, "camera reset");
 	if (ret)
 		return ret;
 
-	gpio_direction_output(GPIO93_CAM_RESET, 0);
+	gpio_direction_output(cam_reset, 0);
 
 	em_x270_camera_ldo = regulator_get(NULL, "vcc cam");
 	if (em_x270_camera_ldo == NULL) {
-		gpio_free(GPIO93_CAM_RESET);
+		gpio_free(cam_reset);
 		return -ENODEV;
 	}
 
 	ret = regulator_enable(em_x270_camera_ldo);
 	if (ret) {
 		regulator_put(em_x270_camera_ldo);
-		gpio_free(GPIO93_CAM_RESET);
+		gpio_free(cam_reset);
 		return ret;
 	}
 
-	gpio_set_value(GPIO93_CAM_RESET, 1);
+	gpio_set_value(cam_reset, 1);
 
 	return 0;
 }
@@ -902,7 +1002,7 @@
 	if (on == is_on)
 		return 0;
 
-	gpio_set_value(GPIO93_CAM_RESET, !on);
+	gpio_set_value(cam_reset, !on);
 
 	if (on)
 		ret = regulator_enable(em_x270_camera_ldo);
@@ -912,7 +1012,7 @@
 	if (ret)
 		return ret;
 
-	gpio_set_value(GPIO93_CAM_RESET, on);
+	gpio_set_value(cam_reset, on);
 
 	return 0;
 }
@@ -929,13 +1029,8 @@
 	},
 };
 
-static struct i2c_pxa_platform_data em_x270_i2c_info = {
-	.fast_mode = 1,
-};
-
 static void  __init em_x270_init_camera(void)
 {
-	pxa_set_i2c_info(&em_x270_i2c_info);
 	i2c_register_board_info(0, ARRAY_AND_SIZE(em_x270_i2c_cam_info));
 	pxa_set_camera_info(&em_x270_camera_platform_data);
 }
@@ -985,7 +1080,7 @@
 };
 
 struct power_supply_info em_x270_psy_info = {
-	.name = "LP555597P6H-FPS",
+	.name = "battery",
 	.technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
 	.voltage_max_design = 4200000,
 	.voltage_min_design = 3000000,
@@ -1069,6 +1164,29 @@
 	i2c_register_board_info(1, &em_x270_i2c_pmic_info, 1);
 }
 
+static struct pca953x_platform_data exeda_gpio_ext_pdata = {
+	.gpio_base = 128,
+};
+
+static struct i2c_board_info exeda_i2c_info[] = {
+	{
+		I2C_BOARD_INFO("pca9555", 0x21),
+		.platform_data = &exeda_gpio_ext_pdata,
+	},
+};
+
+static struct i2c_pxa_platform_data em_x270_i2c_info = {
+	.fast_mode = 1,
+};
+
+static void __init em_x270_init_i2c(void)
+{
+	pxa_set_i2c_info(&em_x270_i2c_info);
+
+	if (machine_is_exeda())
+		i2c_register_board_info(0, ARRAY_AND_SIZE(exeda_i2c_info));
+}
+
 static void __init em_x270_module_init(void)
 {
 	pr_info("%s\n", __func__);
@@ -1077,6 +1195,8 @@
 	mmc_cd = GPIO13_MMC_CD;
 	nand_rb = GPIO56_NAND_RB;
 	dm9000_flags = DM9000_PLATF_32BITONLY;
+	cam_reset = GPIO93_CAM_RESET;
+	usb_hub_reset = GPIO16_USB_HUB_RESET;
 }
 
 static void __init em_x270_exeda_init(void)
@@ -1087,12 +1207,18 @@
 	mmc_cd = GPIO114_MMC_CD;
 	nand_rb = GPIO20_NAND_RB;
 	dm9000_flags = DM9000_PLATF_16BITONLY;
+	cam_reset = GPIO130_CAM_RESET;
+	usb_hub_reset = GPIO10_USB_HUB_RESET;
 }
 
 static void __init em_x270_init(void)
 {
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(common_pin_config));
 
+#ifdef CONFIG_PM
+	pxa27x_set_pwrmode(PWRMODE_DEEPSLEEP);
+#endif
+
 	if (machine_is_em_x270())
 		em_x270_module_init();
 	else if (machine_is_exeda())
@@ -1111,8 +1237,9 @@
 	em_x270_init_keypad();
 	em_x270_init_gpio_keys();
 	em_x270_init_ac97();
-	em_x270_init_camera();
 	em_x270_init_spi();
+	em_x270_init_i2c();
+	em_x270_init_camera();
 }
 
 MACHINE_START(EM_X270, "Compulab EM-X270")
diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c
index 7db966d..588b265 100644
--- a/arch/arm/mach-pxa/ezx.c
+++ b/arch/arm/mach-pxa/ezx.c
@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/pwm_backlight.h>
 #include <linux/input.h>
+#include <linux/gpio_keys.h>
 
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -25,13 +26,19 @@
 #include <mach/pxa27x.h>
 #include <mach/pxafb.h>
 #include <mach/ohci.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/hardware.h>
 #include <mach/pxa27x_keypad.h>
 
 #include "devices.h"
 #include "generic.h"
 
+#define GPIO12_A780_FLIP_LID 		12
+#define GPIO15_A1200_FLIP_LID 		15
+#define GPIO15_A910_FLIP_LID 		15
+#define GPIO12_E680_LOCK_SWITCH 	12
+#define GPIO15_E6_LOCK_SWITCH 		15
+
 static struct platform_pwm_backlight_data ezx_backlight_data = {
 	.pwm_id		= 0,
 	.max_brightness	= 1023,
@@ -88,7 +95,7 @@
 	.lcd_conn	= LCD_COLOR_TFT_18BPP,
 };
 
-static struct platform_device *devices[] __initdata = {
+static struct platform_device *ezx_devices[] __initdata = {
 	&ezx_backlight_device,
 };
 
@@ -651,6 +658,35 @@
 #endif /* CONFIG_MACH_EZX_E2 */
 
 #ifdef CONFIG_MACH_EZX_A780
+/* gpio_keys */
+static struct gpio_keys_button a780_buttons[] = {
+	[0] = {
+		.code       = SW_LID,
+		.gpio       = GPIO12_A780_FLIP_LID,
+		.active_low = 0,
+		.desc       = "A780 flip lid",
+		.type       = EV_SW,
+		.wakeup     = 1,
+	},
+};
+
+static struct gpio_keys_platform_data a780_gpio_keys_platform_data = {
+	.buttons  = a780_buttons,
+	.nbuttons = ARRAY_SIZE(a780_buttons),
+};
+
+static struct platform_device a780_gpio_keys = {
+	.name = "gpio-keys",
+	.id   = -1,
+	.dev  = {
+		.platform_data = &a780_gpio_keys_platform_data,
+	},
+};
+
+static struct platform_device *a780_devices[] __initdata = {
+	&a780_gpio_keys,
+};
+
 static void __init a780_init(void)
 {
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
@@ -663,7 +699,8 @@
 
 	pxa_set_keypad_info(&a780_keypad_platform_data);
 
-	platform_add_devices(devices, ARRAY_SIZE(devices));
+	platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
+	platform_add_devices(ARRAY_AND_SIZE(a780_devices));
 }
 
 MACHINE_START(EZX_A780, "Motorola EZX A780")
@@ -678,10 +715,39 @@
 #endif
 
 #ifdef CONFIG_MACH_EZX_E680
+/* gpio_keys */
+static struct gpio_keys_button e680_buttons[] = {
+	[0] = {
+		.code       = KEY_SCREENLOCK,
+		.gpio       = GPIO12_E680_LOCK_SWITCH,
+		.active_low = 0,
+		.desc       = "E680 lock switch",
+		.type       = EV_KEY,
+		.wakeup     = 1,
+	},
+};
+
+static struct gpio_keys_platform_data e680_gpio_keys_platform_data = {
+	.buttons  = e680_buttons,
+	.nbuttons = ARRAY_SIZE(e680_buttons),
+};
+
+static struct platform_device e680_gpio_keys = {
+	.name = "gpio-keys",
+	.id   = -1,
+	.dev  = {
+		.platform_data = &e680_gpio_keys_platform_data,
+	},
+};
+
 static struct i2c_board_info __initdata e680_i2c_board_info[] = {
 	{ I2C_BOARD_INFO("tea5767", 0x81) },
 };
 
+static struct platform_device *e680_devices[] __initdata = {
+	&e680_gpio_keys,
+};
+
 static void __init e680_init(void)
 {
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
@@ -695,7 +761,8 @@
 
 	pxa_set_keypad_info(&e680_keypad_platform_data);
 
-	platform_add_devices(devices, ARRAY_SIZE(devices));
+	platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
+	platform_add_devices(ARRAY_AND_SIZE(e680_devices));
 }
 
 MACHINE_START(EZX_E680, "Motorola EZX E680")
@@ -710,10 +777,39 @@
 #endif
 
 #ifdef CONFIG_MACH_EZX_A1200
+/* gpio_keys */
+static struct gpio_keys_button a1200_buttons[] = {
+	[0] = {
+		.code       = SW_LID,
+		.gpio       = GPIO15_A1200_FLIP_LID,
+		.active_low = 0,
+		.desc       = "A1200 flip lid",
+		.type       = EV_SW,
+		.wakeup     = 1,
+	},
+};
+
+static struct gpio_keys_platform_data a1200_gpio_keys_platform_data = {
+	.buttons  = a1200_buttons,
+	.nbuttons = ARRAY_SIZE(a1200_buttons),
+};
+
+static struct platform_device a1200_gpio_keys = {
+	.name = "gpio-keys",
+	.id   = -1,
+	.dev  = {
+		.platform_data = &a1200_gpio_keys_platform_data,
+	},
+};
+
 static struct i2c_board_info __initdata a1200_i2c_board_info[] = {
 	{ I2C_BOARD_INFO("tea5767", 0x81) },
 };
 
+static struct platform_device *a1200_devices[] __initdata = {
+	&a1200_gpio_keys,
+};
+
 static void __init a1200_init(void)
 {
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
@@ -727,7 +823,8 @@
 
 	pxa_set_keypad_info(&a1200_keypad_platform_data);
 
-	platform_add_devices(devices, ARRAY_SIZE(devices));
+	platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
+	platform_add_devices(ARRAY_AND_SIZE(a1200_devices));
 }
 
 MACHINE_START(EZX_A1200, "Motorola EZX A1200")
@@ -742,6 +839,35 @@
 #endif
 
 #ifdef CONFIG_MACH_EZX_A910
+/* gpio_keys */
+static struct gpio_keys_button a910_buttons[] = {
+	[0] = {
+		.code       = SW_LID,
+		.gpio       = GPIO15_A910_FLIP_LID,
+		.active_low = 0,
+		.desc       = "A910 flip lid",
+		.type       = EV_SW,
+		.wakeup     = 1,
+	},
+};
+
+static struct gpio_keys_platform_data a910_gpio_keys_platform_data = {
+	.buttons  = a910_buttons,
+	.nbuttons = ARRAY_SIZE(a910_buttons),
+};
+
+static struct platform_device a910_gpio_keys = {
+	.name = "gpio-keys",
+	.id   = -1,
+	.dev  = {
+		.platform_data = &a910_gpio_keys_platform_data,
+	},
+};
+
+static struct platform_device *a910_devices[] __initdata = {
+	&a910_gpio_keys,
+};
+
 static void __init a910_init(void)
 {
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
@@ -754,7 +880,8 @@
 
 	pxa_set_keypad_info(&a910_keypad_platform_data);
 
-	platform_add_devices(devices, ARRAY_SIZE(devices));
+	platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
+	platform_add_devices(ARRAY_AND_SIZE(a910_devices));
 }
 
 MACHINE_START(EZX_A910, "Motorola EZX A910")
@@ -769,10 +896,39 @@
 #endif
 
 #ifdef CONFIG_MACH_EZX_E6
+/* gpio_keys */
+static struct gpio_keys_button e6_buttons[] = {
+	[0] = {
+		.code       = KEY_SCREENLOCK,
+		.gpio       = GPIO15_E6_LOCK_SWITCH,
+		.active_low = 0,
+		.desc       = "E6 lock switch",
+		.type       = EV_KEY,
+		.wakeup     = 1,
+	},
+};
+
+static struct gpio_keys_platform_data e6_gpio_keys_platform_data = {
+	.buttons  = e6_buttons,
+	.nbuttons = ARRAY_SIZE(e6_buttons),
+};
+
+static struct platform_device e6_gpio_keys = {
+	.name = "gpio-keys",
+	.id   = -1,
+	.dev  = {
+		.platform_data = &e6_gpio_keys_platform_data,
+	},
+};
+
 static struct i2c_board_info __initdata e6_i2c_board_info[] = {
 	{ I2C_BOARD_INFO("tea5767", 0x81) },
 };
 
+static struct platform_device *e6_devices[] __initdata = {
+	&e6_gpio_keys,
+};
+
 static void __init e6_init(void)
 {
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
@@ -786,7 +942,8 @@
 
 	pxa_set_keypad_info(&e6_keypad_platform_data);
 
-	platform_add_devices(devices, ARRAY_SIZE(devices));
+	platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
+	platform_add_devices(ARRAY_AND_SIZE(e6_devices));
 }
 
 MACHINE_START(EZX_E6, "Motorola EZX E6")
@@ -805,6 +962,9 @@
 	{ I2C_BOARD_INFO("tea5767", 0x81) },
 };
 
+static struct platform_device *e2_devices[] __initdata = {
+};
+
 static void __init e2_init(void)
 {
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
@@ -818,7 +978,8 @@
 
 	pxa_set_keypad_info(&e2_keypad_platform_data);
 
-	platform_add_devices(devices, ARRAY_SIZE(devices));
+	platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
+	platform_add_devices(ARRAY_AND_SIZE(e2_devices));
 }
 
 MACHINE_START(EZX_E2, "Motorola EZX E2")
diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c
new file mode 100644
index 0000000..7fff467
--- /dev/null
+++ b/arch/arm/mach-pxa/hx4700.c
@@ -0,0 +1,851 @@
+/*
+ * Support for HP iPAQ hx4700 PDAs.
+ *
+ * Copyright (c) 2008-2009 Philipp Zabel
+ *
+ * Based on code:
+ *    Copyright (c) 2004 Hewlett-Packard Company.
+ *    Copyright (c) 2005 SDG Systems, LLC
+ *    Copyright (c) 2006 Anton Vorontsov <cbou@mail.ru>
+ *
+ * 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/delay.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/lcd.h>
+#include <linux/mfd/htc-egpio.h>
+#include <linux/mfd/asic3.h>
+#include <linux/mtd/physmap.h>
+#include <linux/pda_power.h>
+#include <linux/pwm_backlight.h>
+#include <linux/regulator/bq24022.h>
+#include <linux/regulator/machine.h>
+#include <linux/spi/ads7846.h>
+#include <linux/spi/spi.h>
+#include <linux/usb/gpio_vbus.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/pxa27x.h>
+#include <mach/hx4700.h>
+#include <plat/i2c.h>
+#include <mach/irda.h>
+#include <mach/pxa2xx_spi.h>
+
+#include <video/w100fb.h>
+
+#include "devices.h"
+#include "generic.h"
+
+/* Physical address space information */
+
+#define ATI_W3220_PHYS  PXA_CS2_PHYS /* ATI Imageon 3220 Graphics */
+#define ASIC3_PHYS      PXA_CS3_PHYS
+#define ASIC3_SD_PHYS   (PXA_CS3_PHYS + 0x02000000)
+
+static unsigned long hx4700_pin_config[] __initdata = {
+
+	/* SDRAM and Static Memory I/O Signals */
+	GPIO20_nSDCS_2,
+	GPIO21_nSDCS_3,
+	GPIO15_nCS_1,
+	GPIO78_nCS_2,   /* W3220 */
+	GPIO79_nCS_3,   /* ASIC3 */
+	GPIO80_nCS_4,
+	GPIO33_nCS_5,	/* EGPIO, WLAN */
+
+	/* PC CARD */
+	GPIO48_nPOE,
+	GPIO49_nPWE,
+	GPIO50_nPIOR,
+	GPIO51_nPIOW,
+	GPIO54_nPCE_2,
+	GPIO55_nPREG,
+	GPIO56_nPWAIT,
+	GPIO57_nIOIS16,
+	GPIO85_nPCE_1,
+	GPIO104_PSKTSEL,
+
+	/* I2C */
+	GPIO117_I2C_SCL,
+	GPIO118_I2C_SDA,
+
+	/* FFUART (RS-232) */
+	GPIO34_FFUART_RXD,
+	GPIO35_FFUART_CTS,
+	GPIO36_FFUART_DCD,
+	GPIO37_FFUART_DSR,
+	GPIO38_FFUART_RI,
+	GPIO39_FFUART_TXD,
+	GPIO40_FFUART_DTR,
+	GPIO41_FFUART_RTS,
+
+	/* BTUART */
+	GPIO42_BTUART_RXD,
+	GPIO43_BTUART_TXD,
+	GPIO44_BTUART_CTS,
+	GPIO45_BTUART_RTS,
+
+	/* PWM 1 (Backlight) */
+	GPIO17_PWM1_OUT,
+
+	/* I2S */
+	GPIO28_I2S_BITCLK_OUT,
+	GPIO29_I2S_SDATA_IN,
+	GPIO30_I2S_SDATA_OUT,
+	GPIO31_I2S_SYNC,
+	GPIO113_I2S_SYSCLK,
+
+	/* SSP 1 (NavPoint) */
+	GPIO23_SSP1_SCLK,
+	GPIO24_SSP1_SFRM,
+	GPIO25_SSP1_TXD,
+	GPIO26_SSP1_RXD,
+
+	/* SSP 2 (TSC2046) */
+	GPIO19_SSP2_SCLK,
+	GPIO86_SSP2_RXD,
+	GPIO87_SSP2_TXD,
+	GPIO88_GPIO,
+
+	/* HX4700 specific input GPIOs */
+	GPIO12_GPIO,	/* ASIC3_IRQ */
+	GPIO13_GPIO,	/* W3220_IRQ */
+	GPIO14_GPIO,	/* nWLAN_IRQ */
+
+	GPIO10_GPIO,	/* GSM_IRQ */
+	GPIO13_GPIO,	/* CPLD_IRQ */
+	GPIO107_GPIO,	/* DS1WM_IRQ */
+	GPIO108_GPIO,	/* GSM_READY */
+	GPIO58_GPIO,	/* TSC2046_nPENIRQ */
+	GPIO66_GPIO,	/* nSDIO_IRQ */
+};
+
+#define HX4700_GPIO_IN(num, _desc) \
+	{ .gpio = (num), .dir = 0, .desc = (_desc) }
+#define HX4700_GPIO_OUT(num, _init, _desc) \
+	{ .gpio = (num), .dir = 1, .init = (_init), .desc = (_desc) }
+struct gpio_ress {
+	unsigned gpio : 8;
+	unsigned dir : 1;
+	unsigned init : 1;
+	char *desc;
+};
+
+static int hx4700_gpio_request(struct gpio_ress *gpios, int size)
+{
+	int i, rc = 0;
+	int gpio;
+	int dir;
+
+	for (i = 0; (!rc) && (i < size); i++) {
+		gpio = gpios[i].gpio;
+		dir = gpios[i].dir;
+		rc = gpio_request(gpio, gpios[i].desc);
+		if (rc) {
+			pr_err("Error requesting GPIO %d(%s) : %d\n",
+			       gpio, gpios[i].desc, rc);
+			continue;
+		}
+		if (dir)
+			gpio_direction_output(gpio, gpios[i].init);
+		else
+			gpio_direction_input(gpio);
+	}
+	while ((rc) && (--i >= 0))
+		gpio_free(gpios[i].gpio);
+	return rc;
+}
+
+/*
+ * IRDA
+ */
+
+static void irda_transceiver_mode(struct device *dev, int mode)
+{
+	gpio_set_value(GPIO105_HX4700_nIR_ON, mode & IR_OFF);
+}
+
+static struct pxaficp_platform_data ficp_info = {
+	.transceiver_cap  = IR_SIRMODE | IR_OFF,
+	.transceiver_mode = irda_transceiver_mode,
+};
+
+/*
+ * GPIO Keys
+ */
+
+#define INIT_KEY(_code, _gpio, _active_low, _desc)	\
+	{						\
+		.code       = KEY_##_code,		\
+		.gpio       = _gpio,			\
+		.active_low = _active_low,		\
+		.desc       = _desc,			\
+		.type       = EV_KEY,			\
+		.wakeup     = 1,			\
+	}
+
+static struct gpio_keys_button gpio_keys_buttons[] = {
+	INIT_KEY(POWER,       GPIO0_HX4700_nKEY_POWER,   1, "Power button"),
+	INIT_KEY(MAIL,        GPIO94_HX4700_KEY_MAIL,    0, "Mail button"),
+	INIT_KEY(ADDRESSBOOK, GPIO99_HX4700_KEY_CONTACTS,0, "Contacts button"),
+	INIT_KEY(RECORD,      GPIOD6_nKEY_RECORD,        1, "Record button"),
+	INIT_KEY(CALENDAR,    GPIOD1_nKEY_CALENDAR,      1, "Calendar button"),
+	INIT_KEY(HOMEPAGE,    GPIOD3_nKEY_HOME,          1, "Home button"),
+};
+
+static struct gpio_keys_platform_data gpio_keys_data = {
+	.buttons = gpio_keys_buttons,
+	.nbuttons = ARRAY_SIZE(gpio_keys_buttons),
+};
+
+static struct platform_device gpio_keys = {
+	.name = "gpio-keys",
+	.dev  = {
+		.platform_data = &gpio_keys_data,
+	},
+	.id   = -1,
+};
+
+/*
+ * ASIC3
+ */
+
+static u16 asic3_gpio_config[] = {
+	/* ASIC3 GPIO banks A and B along with some of C and D
+	   implement the buffering for the CF slot. */
+	ASIC3_CONFIG_GPIO(0, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(1, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(2, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(3, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(4, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(5, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(6, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(7, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(8, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(9, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(10, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(11, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(12, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(13, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(14, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(15, 1, 1, 0),
+
+	ASIC3_CONFIG_GPIO(16, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(17, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(18, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(19, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(20, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(21, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(22, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(23, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(24, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(25, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(26, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(27, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(28, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(29, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(30, 1, 1, 0),
+	ASIC3_CONFIG_GPIO(31, 1, 1, 0),
+
+	/* GPIOC - CF, LEDs, SD */
+	ASIC3_GPIOC0_LED0,		/* red */
+	ASIC3_GPIOC1_LED1,		/* green */
+	ASIC3_GPIOC2_LED2,		/* blue */
+	ASIC3_GPIOC4_CF_nCD,
+	ASIC3_GPIOC5_nCIOW,
+	ASIC3_GPIOC6_nCIOR,
+	ASIC3_GPIOC7_nPCE_1,
+	ASIC3_GPIOC8_nPCE_2,
+	ASIC3_GPIOC9_nPOE,
+	ASIC3_GPIOC10_nPWE,
+	ASIC3_GPIOC11_PSKTSEL,
+	ASIC3_GPIOC12_nPREG,
+	ASIC3_GPIOC13_nPWAIT,
+	ASIC3_GPIOC14_nPIOIS16,
+	ASIC3_GPIOC15_nPIOR,
+
+	/* GPIOD: input GPIOs, CF */
+	ASIC3_GPIOD11_nCIOIS16,
+	ASIC3_GPIOD12_nCWAIT,
+	ASIC3_GPIOD15_nPIOW,
+};
+
+static struct resource asic3_resources[] = {
+	/* GPIO part */
+	[0] = {
+		.start	= ASIC3_PHYS,
+		.end	= ASIC3_PHYS + ASIC3_MAP_SIZE_16BIT - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= gpio_to_irq(GPIO12_HX4700_ASIC3_IRQ),
+		.end	= gpio_to_irq(GPIO12_HX4700_ASIC3_IRQ),
+		.flags	= IORESOURCE_IRQ,
+	},
+	/* SD part */
+	[2] = {
+		.start	= ASIC3_SD_PHYS,
+		.end	= ASIC3_SD_PHYS + ASIC3_MAP_SIZE_16BIT - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[3] = {
+		.start	= gpio_to_irq(GPIO66_HX4700_ASIC3_nSDIO_IRQ),
+		.end	= gpio_to_irq(GPIO66_HX4700_ASIC3_nSDIO_IRQ),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct asic3_platform_data asic3_platform_data = {
+	.gpio_config     = asic3_gpio_config,
+	.gpio_config_num = ARRAY_SIZE(asic3_gpio_config),
+	.irq_base        = IRQ_BOARD_START,
+	.gpio_base       = HX4700_ASIC3_GPIO_BASE,
+};
+
+static struct platform_device asic3 = {
+	.name          = "asic3",
+	.id            = -1,
+	.resource      = asic3_resources,
+	.num_resources = ARRAY_SIZE(asic3_resources),
+	.dev = {
+		.platform_data = &asic3_platform_data,
+	},
+};
+
+/*
+ * EGPIO
+ */
+
+static struct resource egpio_resources[] = {
+	[0] = {
+		.start = PXA_CS5_PHYS,
+		.end   = PXA_CS5_PHYS + 0x4 - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct htc_egpio_chip egpio_chips[] = {
+	[0] = {
+		.reg_start = 0,
+		.gpio_base = HX4700_EGPIO_BASE,
+		.num_gpios = 8,
+		.direction = HTC_EGPIO_OUTPUT,
+	},
+};
+
+static struct htc_egpio_platform_data egpio_info = {
+	.reg_width = 16,
+	.bus_width = 16,
+	.chip      = egpio_chips,
+	.num_chips = ARRAY_SIZE(egpio_chips),
+};
+
+static struct platform_device egpio = {
+	.name          = "htc-egpio",
+	.id            = -1,
+	.resource      = egpio_resources,
+	.num_resources = ARRAY_SIZE(egpio_resources),
+	.dev = {
+		.platform_data = &egpio_info,
+	},
+};
+
+/*
+ * LCD - Sony display connected to ATI Imageon w3220
+ */
+
+static int lcd_power;
+
+static void sony_lcd_init(void)
+{
+	gpio_set_value(GPIO84_HX4700_LCD_SQN, 1);
+	gpio_set_value(GPIO110_HX4700_LCD_LVDD_3V3_ON, 0);
+	gpio_set_value(GPIO111_HX4700_LCD_AVDD_3V3_ON, 0);
+	gpio_set_value(GPIO70_HX4700_LCD_SLIN1, 0);
+	gpio_set_value(GPIO62_HX4700_LCD_nRESET, 0);
+	mdelay(10);
+	gpio_set_value(GPIO59_HX4700_LCD_PC1, 0);
+	gpio_set_value(GPIO110_HX4700_LCD_LVDD_3V3_ON, 0);
+	mdelay(20);
+
+	gpio_set_value(GPIO110_HX4700_LCD_LVDD_3V3_ON, 1);
+	mdelay(5);
+	gpio_set_value(GPIO111_HX4700_LCD_AVDD_3V3_ON, 1);
+
+	/* FIXME: init w3220 registers here */
+
+	mdelay(5);
+	gpio_set_value(GPIO70_HX4700_LCD_SLIN1, 1);
+	mdelay(10);
+	gpio_set_value(GPIO62_HX4700_LCD_nRESET, 1);
+	mdelay(10);
+	gpio_set_value(GPIO59_HX4700_LCD_PC1, 1);
+	mdelay(10);
+	gpio_set_value(GPIO112_HX4700_LCD_N2V7_7V3_ON, 1);
+}
+
+static void sony_lcd_off(void)
+{
+	gpio_set_value(GPIO59_HX4700_LCD_PC1, 0);
+	gpio_set_value(GPIO62_HX4700_LCD_nRESET, 0);
+	mdelay(10);
+	gpio_set_value(GPIO112_HX4700_LCD_N2V7_7V3_ON, 0);
+	mdelay(10);
+	gpio_set_value(GPIO111_HX4700_LCD_AVDD_3V3_ON, 0);
+	mdelay(10);
+	gpio_set_value(GPIO110_HX4700_LCD_LVDD_3V3_ON, 0);
+}
+
+static int hx4700_lcd_set_power(struct lcd_device *ldev, int level)
+{
+	switch (level) {
+	case FB_BLANK_UNBLANK:
+		sony_lcd_init();
+		break;
+	case FB_BLANK_NORMAL:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_POWERDOWN:
+		sony_lcd_off();
+		break;
+	}
+	lcd_power = level;
+	return 0;
+}
+
+static int hx4700_lcd_get_power(struct lcd_device *lm)
+{
+	return lcd_power;
+}
+
+static struct lcd_ops hx4700_lcd_ops = {
+	.get_power = hx4700_lcd_get_power,
+	.set_power = hx4700_lcd_set_power,
+};
+
+static struct lcd_device *hx4700_lcd_device;
+
+#ifdef CONFIG_PM
+static void w3220_lcd_suspend(struct w100fb_par *wfb)
+{
+	sony_lcd_off();
+}
+
+static void w3220_lcd_resume(struct w100fb_par *wfb)
+{
+	sony_lcd_init();
+}
+#else
+#define w3220_lcd_resume	NULL
+#define w3220_lcd_suspend	NULL
+#endif
+
+static struct w100_tg_info w3220_tg_info = {
+	.suspend	= w3220_lcd_suspend,
+	.resume		= w3220_lcd_resume,
+};
+
+/*  				 W3220_VGA		QVGA */
+static struct w100_gen_regs w3220_regs = {
+	.lcd_format =        0x00000003,
+	.lcdd_cntl1 =        0x00000000,
+	.lcdd_cntl2 =        0x0003ffff,
+	.genlcd_cntl1 =      0x00abf003,	/* 0x00fff003 */
+	.genlcd_cntl2 =      0x00000003,
+	.genlcd_cntl3 =      0x000102aa,
+};
+
+static struct w100_mode w3220_modes[] = {
+{
+	.xres 		= 480,
+	.yres 		= 640,
+	.left_margin 	= 15,
+	.right_margin 	= 16,
+	.upper_margin 	= 8,
+	.lower_margin 	= 7,
+	.crtc_ss	= 0x00000000,
+	.crtc_ls	= 0xa1ff01f9,	/* 0x21ff01f9 */
+	.crtc_gs	= 0xc0000000,	/* 0x40000000 */
+	.crtc_vpos_gs	= 0x0000028f,
+	.crtc_ps1_active = 0x00000000,	/* 0x41060010 */
+	.crtc_rev	= 0,
+	.crtc_dclk	= 0x80000000,
+	.crtc_gclk	= 0x040a0104,
+	.crtc_goe	= 0,
+	.pll_freq 	= 95,
+	.pixclk_divider = 4,
+	.pixclk_divider_rotated = 4,
+	.pixclk_src     = CLK_SRC_PLL,
+	.sysclk_divider = 0,
+	.sysclk_src     = CLK_SRC_PLL,
+},
+{
+	.xres 		= 240,
+	.yres 		= 320,
+	.left_margin 	= 9,
+	.right_margin 	= 8,
+	.upper_margin 	= 5,
+	.lower_margin 	= 4,
+	.crtc_ss	= 0x80150014,
+	.crtc_ls        = 0xa0fb00f7,
+	.crtc_gs	= 0xc0080007,
+	.crtc_vpos_gs	= 0x00080007,
+	.crtc_rev	= 0x0000000a,
+	.crtc_dclk	= 0x81700030,
+	.crtc_gclk	= 0x8015010f,
+	.crtc_goe	= 0x00000000,
+	.pll_freq 	= 95,
+	.pixclk_divider = 4,
+	.pixclk_divider_rotated = 4,
+	.pixclk_src     = CLK_SRC_PLL,
+	.sysclk_divider = 0,
+	.sysclk_src     = CLK_SRC_PLL,
+},
+};
+
+struct w100_mem_info w3220_mem_info = {
+	.ext_cntl        = 0x09640011,
+	.sdram_mode_reg  = 0x00600021,
+	.ext_timing_cntl = 0x1a001545,	/* 0x15001545 */
+	.io_cntl         = 0x7ddd7333,
+	.size            = 0x1fffff,
+};
+
+struct w100_bm_mem_info w3220_bm_mem_info = {
+	.ext_mem_bw = 0x50413e01,
+	.offset = 0,
+	.ext_timing_ctl = 0x00043f7f,
+	.ext_cntl = 0x00000010,
+	.mode_reg = 0x00250000,
+	.io_cntl = 0x0fff0000,
+	.config = 0x08301480,
+};
+
+static struct w100_gpio_regs w3220_gpio_info = {
+	.init_data1 = 0xdfe00100,	/* GPIO_DATA */
+	.gpio_dir1  = 0xffff0000,	/* GPIO_CNTL1 */
+	.gpio_oe1   = 0x00000000,	/* GPIO_CNTL2 */
+	.init_data2 = 0x00000000,	/* GPIO_DATA2 */
+	.gpio_dir2  = 0x00000000,	/* GPIO_CNTL3 */
+	.gpio_oe2   = 0x00000000,	/* GPIO_CNTL4 */
+};
+
+static struct w100fb_mach_info w3220_info = {
+	.tg        = &w3220_tg_info,
+	.mem       = &w3220_mem_info,
+	.bm_mem    = &w3220_bm_mem_info,
+	.gpio      = &w3220_gpio_info,
+	.regs      = &w3220_regs,
+	.modelist  = w3220_modes,
+	.num_modes = 2,
+	.xtal_freq = 16000000,
+};
+
+static struct resource w3220_resources[] = {
+	[0] = {
+		.start	= ATI_W3220_PHYS,
+		.end	= ATI_W3220_PHYS + 0x00ffffff,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device w3220 = {
+	.name	= "w100fb",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &w3220_info,
+	},
+	.num_resources = ARRAY_SIZE(w3220_resources),
+	.resource      = w3220_resources,
+};
+
+/*
+ * Backlight
+ */
+
+static struct platform_pwm_backlight_data backlight_data = {
+	.pwm_id         = 1,
+	.max_brightness = 200,
+	.dft_brightness = 100,
+	.pwm_period_ns  = 30923,
+};
+
+static struct platform_device backlight = {
+	.name = "pwm-backlight",
+	.id   = -1,
+	.dev  = {
+		.parent        = &pxa27x_device_pwm1.dev,
+		.platform_data = &backlight_data,
+	},
+};
+
+/*
+ * USB "Transceiver"
+ */
+
+static struct gpio_vbus_mach_info gpio_vbus_info = {
+	.gpio_pullup        = GPIO76_HX4700_USBC_PUEN,
+	.gpio_vbus          = GPIOD14_nUSBC_DETECT,
+	.gpio_vbus_inverted = 1,
+};
+
+static struct platform_device gpio_vbus = {
+	.name          = "gpio-vbus",
+	.id            = -1,
+	.dev = {
+		.platform_data = &gpio_vbus_info,
+	},
+};
+
+/*
+ * Touchscreen - TSC2046 connected to SSP2
+ */
+
+static const struct ads7846_platform_data tsc2046_info = {
+	.model            = 7846,
+	.vref_delay_usecs = 100,
+	.pressure_max     = 512,
+	.debounce_max     = 10,
+	.debounce_tol     = 3,
+	.debounce_rep     = 1,
+	.gpio_pendown     = GPIO58_HX4700_TSC2046_nPENIRQ,
+};
+
+static struct pxa2xx_spi_chip tsc2046_chip = {
+	.tx_threshold = 1,
+	.rx_threshold = 2,
+	.timeout      = 64,
+	.gpio_cs      = GPIO88_HX4700_TSC2046_CS,
+};
+
+static struct spi_board_info tsc2046_board_info[] __initdata = {
+	{
+		.modalias        = "ads7846",
+		.bus_num         = 2,
+		.max_speed_hz    = 2600000, /* 100 kHz sample rate */
+		.irq             = gpio_to_irq(GPIO58_HX4700_TSC2046_nPENIRQ),
+		.platform_data   = &tsc2046_info,
+		.controller_data = &tsc2046_chip,
+	},
+};
+
+static struct pxa2xx_spi_master pxa_ssp2_master_info = {
+	.num_chipselect = 1,
+	.clock_enable   = CKEN_SSP2,
+	.enable_dma     = 1,
+};
+
+/*
+ * External power
+ */
+
+static int power_supply_init(struct device *dev)
+{
+	return gpio_request(GPIOD9_nAC_IN, "AC charger detect");
+}
+
+static int hx4700_is_ac_online(void)
+{
+	return !gpio_get_value(GPIOD9_nAC_IN);
+}
+
+static void power_supply_exit(struct device *dev)
+{
+	gpio_free(GPIOD9_nAC_IN);
+}
+
+static char *hx4700_supplicants[] = {
+	"ds2760-battery.0", "backup-battery"
+};
+
+static struct pda_power_pdata power_supply_info = {
+	.init            = power_supply_init,
+	.is_ac_online    = hx4700_is_ac_online,
+	.exit            = power_supply_exit,
+	.supplied_to     = hx4700_supplicants,
+	.num_supplicants = ARRAY_SIZE(hx4700_supplicants),
+};
+
+static struct resource power_supply_resources[] = {
+	[0] = {
+		.name  = "ac",
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
+		         IORESOURCE_IRQ_LOWEDGE,
+		.start = gpio_to_irq(GPIOD9_nAC_IN),
+		.end   = gpio_to_irq(GPIOD9_nAC_IN),
+	},
+	[1] = {
+		.name  = "usb",
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
+		         IORESOURCE_IRQ_LOWEDGE,
+		.start = gpio_to_irq(GPIOD14_nUSBC_DETECT),
+		.end   = gpio_to_irq(GPIOD14_nUSBC_DETECT),
+	},
+};
+
+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),
+};
+
+/*
+ * Battery charger
+ */
+
+static struct regulator_consumer_supply bq24022_consumers[] = {
+	{
+		.dev = &gpio_vbus.dev,
+		.supply = "vbus_draw",
+	},
+	{
+		.dev = &power_supply.dev,
+		.supply = "ac_draw",
+	},
+};
+
+static struct regulator_init_data bq24022_init_data = {
+	.constraints = {
+		.max_uA         = 500000,
+		.valid_ops_mask = REGULATOR_CHANGE_CURRENT,
+	},
+	.num_consumer_supplies  = ARRAY_SIZE(bq24022_consumers),
+	.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 platform_device bq24022 = {
+	.name = "bq24022",
+	.id   = -1,
+	.dev  = {
+		.platform_data = &bq24022_info,
+	},
+};
+
+/*
+ * StrataFlash
+ */
+
+static void hx4700_set_vpp(struct map_info *map, int vpp)
+{
+	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 physmap_flash_data strataflash_data = {
+	.width = 4,
+	.set_vpp = hx4700_set_vpp,
+};
+
+static struct platform_device strataflash = {
+	.name          = "physmap-flash",
+	.id            = -1,
+	.resource      = &strataflash_resource,
+	.num_resources = 1,
+	.dev = {
+		.platform_data = &strataflash_data,
+	},
+};
+
+/*
+ * PCMCIA
+ */
+
+static struct platform_device pcmcia = {
+	.name = "hx4700-pcmcia",
+	.dev  = {
+		.parent = &asic3.dev,
+	},
+};
+
+/*
+ * Platform devices
+ */
+
+static struct platform_device *devices[] __initdata = {
+	&asic3,
+	&gpio_keys,
+	&backlight,
+	&w3220,
+	&egpio,
+	&bq24022,
+	&gpio_vbus,
+	&power_supply,
+	&strataflash,
+	&pcmcia,
+};
+
+static struct gpio_ress global_gpios[] = {
+	HX4700_GPIO_IN(GPIO12_HX4700_ASIC3_IRQ, "ASIC3_IRQ"),
+	HX4700_GPIO_IN(GPIO13_HX4700_W3220_IRQ, "W3220_IRQ"),
+	HX4700_GPIO_IN(GPIO14_HX4700_nWLAN_IRQ, "WLAN_IRQ"),
+	HX4700_GPIO_OUT(GPIO59_HX4700_LCD_PC1,          1, "LCD_PC1"),
+	HX4700_GPIO_OUT(GPIO62_HX4700_LCD_nRESET,       1, "LCD_RESET"),
+	HX4700_GPIO_OUT(GPIO70_HX4700_LCD_SLIN1,        1, "LCD_SLIN1"),
+	HX4700_GPIO_OUT(GPIO84_HX4700_LCD_SQN,          1, "LCD_SQN"),
+	HX4700_GPIO_OUT(GPIO110_HX4700_LCD_LVDD_3V3_ON, 1, "LCD_LVDD"),
+	HX4700_GPIO_OUT(GPIO111_HX4700_LCD_AVDD_3V3_ON, 1, "LCD_AVDD"),
+	HX4700_GPIO_OUT(GPIO32_HX4700_RS232_ON,         1, "RS232_ON"),
+	HX4700_GPIO_OUT(GPIO71_HX4700_ASIC3_nRESET,     1, "ASIC3_nRESET"),
+	HX4700_GPIO_OUT(GPIO82_HX4700_EUART_RESET,      1, "EUART_RESET"),
+	HX4700_GPIO_OUT(GPIO105_HX4700_nIR_ON,          1, "nIR_EN"),
+};
+
+static void __init hx4700_init(void)
+{
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(hx4700_pin_config));
+	hx4700_gpio_request(ARRAY_AND_SIZE(global_gpios));
+
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+
+	pxa_set_ficp_info(&ficp_info);
+	pxa27x_set_i2c_power_info(NULL);
+	pxa_set_i2c_info(NULL);
+	pxa2xx_set_spi_info(2, &pxa_ssp2_master_info);
+	spi_register_board_info(ARRAY_AND_SIZE(tsc2046_board_info));
+
+	hx4700_lcd_device = lcd_device_register("w100fb", NULL,
+					(void *)&w3220_info, &hx4700_lcd_ops);
+
+	gpio_set_value(GPIO71_HX4700_ASIC3_nRESET, 0);
+	mdelay(10);
+	gpio_set_value(GPIO71_HX4700_ASIC3_nRESET, 1);
+	mdelay(10);
+}
+
+MACHINE_START(H4700, "HP iPAQ HX4700")
+	.phys_io      = 0x40000000,
+	.io_pg_offst  = (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.boot_params  = 0xa0000100,
+	.map_io       = pxa_map_io,
+	.init_irq     = pxa27x_init_irq,
+	.init_machine = hx4700_init,
+	.timer        = &pxa_timer,
+MACHINE_END
diff --git a/arch/arm/mach-pxa/imote2.c b/arch/arm/mach-pxa/imote2.c
index 2b27336..961807d 100644
--- a/arch/arm/mach-pxa/imote2.c
+++ b/arch/arm/mach-pxa/imote2.c
@@ -22,6 +22,7 @@
 #include <linux/spi/spi.h>
 #include <linux/i2c.h>
 #include <linux/mfd/da903x.h>
+#include <linux/sht15.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -29,7 +30,7 @@
 #include <asm/mach/flash.h>
 
 #include <mach/pxa27x.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/udc.h>
 #include <mach/mmc.h>
 #include <mach/pxa2xx_spi.h>
@@ -102,6 +103,10 @@
 	GPIO96_GPIO,	/* accelerometer interrupt */
 	GPIO99_GPIO,	/* ADC interrupt */
 
+	/* SHT15 */
+	GPIO100_GPIO,
+	GPIO98_GPIO,
+
 	/* Connector pins specified as gpios */
 	GPIO94_GPIO, /* large basic connector pin 14 */
 	GPIO10_GPIO, /* large basic connector pin 23 */
@@ -112,6 +117,26 @@
 	GPIO105_GPIO, /* blue led */
 };
 
+static struct sht15_platform_data platform_data_sht15 = {
+	.gpio_data =  100,
+	.gpio_sck  =  98,
+};
+
+static struct platform_device sht15 = {
+	.name = "sht15",
+	.id = -1,
+	.dev = {
+		.platform_data = &platform_data_sht15,
+	},
+};
+
+static struct regulator_consumer_supply imote2_sensor_3_con[] = {
+	{
+		.dev = &sht15.dev,
+		.supply = "vcc",
+	},
+};
+
 static struct gpio_led imote2_led_pins[] = {
 	{
 		.name       =  "imote2:red",
@@ -257,6 +282,8 @@
 			.min_uV = 2800000,
 			.max_uV = 3000000,
 		},
+		.num_consumer_supplies = ARRAY_SIZE(imote2_sensor_3_con),
+		.consumer_supplies = imote2_sensor_3_con,
 	},
 	[vcc_pxa_pll] = { /* 1.17V - 1.43V, default 1.3V*/
 		.constraints = {
@@ -432,6 +459,9 @@
 		.type = "tmp175",
 		.addr = 0x4A,
 		.irq = IRQ_GPIO(96),
+	}, { /* IMB400 Multimedia board */
+		.type = "wm8940",
+		.addr = 0x1A,
 	},
 };
 
@@ -456,25 +486,12 @@
 	.num_chipselect = 1,
 };
 
-/* Patch posted by Eric Miao <eric.miao@marvell.com> will remove
- * the need for these functions.
- */
-static void spi1control(u32 command)
-{
-	gpio_set_value(24, command & PXA2XX_CS_ASSERT ? 0 : 1);
-};
-
-static void spi3control(u32 command)
-{
-	gpio_set_value(39, command & PXA2XX_CS_ASSERT ? 0 : 1);
-};
-
 static struct pxa2xx_spi_chip staccel_chip_info = {
 	.tx_threshold = 8,
 	.rx_threshold = 8,
 	.dma_burst_size = 8,
 	.timeout = 235,
-	.cs_control = spi1control,
+	.gpio_cs = 24,
 };
 
 static struct pxa2xx_spi_chip cc2420_info = {
@@ -482,7 +499,7 @@
 	.rx_threshold = 8,
 	.dma_burst_size = 8,
 	.timeout = 235,
-	.cs_control = spi3control,
+	.gpio_cs = 39,
 };
 
 static struct spi_board_info spi_board_info[] __initdata = {
@@ -521,6 +538,7 @@
 static struct platform_device *imote2_devices[] = {
 	&imote2_flash_device,
 	&imote2_leds,
+	&sht15,
 };
 
 static struct i2c_pxa_platform_data i2c_pwr_pdata = {
@@ -538,8 +556,6 @@
 	/* SPI chip select directions - all other directions should
 	 * be handled by drivers.*/
 	gpio_direction_output(37, 0);
-	gpio_direction_output(24, 0);
-	gpio_direction_output(39, 0);
 
 	platform_add_devices(imote2_devices, ARRAY_SIZE(imote2_devices));
 
diff --git a/arch/arm/mach-pxa/include/mach/hx4700.h b/arch/arm/mach-pxa/include/mach/hx4700.h
new file mode 100644
index 0000000..9eaeed1
--- /dev/null
+++ b/arch/arm/mach-pxa/include/mach/hx4700.h
@@ -0,0 +1,131 @@
+/*
+ * GPIO and IRQ definitions for HP iPAQ hx4700
+ *
+ * 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.
+ *
+ */
+
+#ifndef _HX4700_H_
+#define _HX4700_H_
+
+#include <linux/gpio.h>
+#include <linux/mfd/asic3.h>
+
+#define HX4700_ASIC3_GPIO_BASE	NR_BUILTIN_GPIO
+#define HX4700_EGPIO_BASE	(HX4700_ASIC3_GPIO_BASE + ASIC3_NUM_GPIOS)
+
+/*
+ * PXA GPIOs
+ */
+
+#define GPIO0_HX4700_nKEY_POWER			0
+#define GPIO12_HX4700_ASIC3_IRQ			12
+#define GPIO13_HX4700_W3220_IRQ			13
+#define GPIO14_HX4700_nWLAN_IRQ			14
+#define GPIO18_HX4700_RDY			18
+#define GPIO22_HX4700_LCD_RL			22
+#define GPIO27_HX4700_CODEC_ON			27
+#define GPIO32_HX4700_RS232_ON			32
+#define GPIO52_HX4700_CPU_nBATT_FAULT		52
+#define GPIO58_HX4700_TSC2046_nPENIRQ		58
+#define GPIO59_HX4700_LCD_PC1			59
+#define GPIO60_HX4700_CF_RNB			60
+#define GPIO61_HX4700_W3220_nRESET		61
+#define GPIO62_HX4700_LCD_nRESET		62
+#define GPIO63_HX4700_CPU_SS_nRESET		63
+#define GPIO65_HX4700_TSC2046_PEN_PU		65
+#define GPIO66_HX4700_ASIC3_nSDIO_IRQ		66
+#define GPIO67_HX4700_EUART_PS			67
+#define GPIO70_HX4700_LCD_SLIN1			70
+#define GPIO71_HX4700_ASIC3_nRESET		71
+#define GPIO72_HX4700_BQ24022_nCHARGE_EN	72
+#define GPIO73_HX4700_LCD_UD_1			73
+#define GPIO75_HX4700_EARPHONE_nDET		75
+#define GPIO76_HX4700_USBC_PUEN			76
+#define GPIO81_HX4700_CPU_GP_nRESET		81
+#define GPIO82_HX4700_EUART_RESET		82
+#define GPIO83_HX4700_WLAN_nRESET		83
+#define GPIO84_HX4700_LCD_SQN			84
+#define GPIO85_HX4700_nPCE1			85
+#define GPIO88_HX4700_TSC2046_CS		88
+#define GPIO91_HX4700_FLASH_VPEN		91
+#define GPIO92_HX4700_HP_DRIVER			92
+#define GPIO93_HX4700_EUART_INT			93
+#define GPIO94_HX4700_KEY_MAIL			94
+#define GPIO95_HX4700_BATT_OFF			95
+#define GPIO96_HX4700_BQ24022_ISET2		96
+#define GPIO97_HX4700_nBL_DETECT		97
+#define GPIO99_HX4700_KEY_CONTACTS		99
+#define GPIO100_HX4700_AUTO_SENSE		100 /* BL auto brightness */
+#define GPIO102_HX4700_SYNAPTICS_POWER_ON	102
+#define GPIO103_HX4700_SYNAPTICS_INT		103
+#define GPIO105_HX4700_nIR_ON			105
+#define GPIO106_HX4700_CPU_BT_nRESET		106
+#define GPIO107_HX4700_SPK_nSD			107
+#define GPIO109_HX4700_CODEC_nPDN		109
+#define GPIO110_HX4700_LCD_LVDD_3V3_ON		110
+#define GPIO111_HX4700_LCD_AVDD_3V3_ON		111
+#define GPIO112_HX4700_LCD_N2V7_7V3_ON		112
+#define GPIO114_HX4700_CF_RESET			114
+#define GPIO116_HX4700_CPU_HW_nRESET		116
+
+/*
+ * ASIC3 GPIOs
+ */
+
+#define GPIOC_BASE		(HX4700_ASIC3_GPIO_BASE + 32)
+#define GPIOD_BASE		(HX4700_ASIC3_GPIO_BASE + 48)
+
+#define GPIOC0_LED_RED		(GPIOC_BASE + 0)
+#define GPIOC1_LED_GREEN	(GPIOC_BASE + 1)
+#define GPIOC2_LED_BLUE		(GPIOC_BASE + 2)
+#define GPIOC3_nSD_CS		(GPIOC_BASE + 3)
+#define GPIOC4_CF_nCD		(GPIOC_BASE + 4)	/* Input */
+#define GPIOC5_nCIOW		(GPIOC_BASE + 5)	/* Output, to CF */
+#define GPIOC6_nCIOR		(GPIOC_BASE + 6)	/* Output, to CF */
+#define GPIOC7_nPCE1		(GPIOC_BASE + 7)	/* Input, from CPU */
+#define GPIOC8_nPCE2		(GPIOC_BASE + 8)	/* Input, from CPU */
+#define GPIOC9_nPOE		(GPIOC_BASE + 9)	/* Input, from CPU */
+#define GPIOC10_CF_nPWE		(GPIOC_BASE + 10)	/* Input */
+#define GPIOC11_PSKTSEL		(GPIOC_BASE + 11)	/* Input, from CPU */
+#define GPIOC12_nPREG		(GPIOC_BASE + 12)	/* Input, from CPU */
+#define GPIOC13_nPWAIT		(GPIOC_BASE + 13)	/* Output, to CPU */
+#define GPIOC14_nPIOIS16	(GPIOC_BASE + 14)	/* Output, to CPU */
+#define GPIOC15_nPIOR		(GPIOC_BASE + 15)	/* Input, from CPU */
+
+#define GPIOD0_CPU_SS_INT	(GPIOD_BASE + 0)	/* Input */
+#define GPIOD1_nKEY_CALENDAR	(GPIOD_BASE + 1)
+#define GPIOD2_BLUETOOTH_WAKEUP	(GPIOD_BASE + 2)
+#define GPIOD3_nKEY_HOME	(GPIOD_BASE + 3)
+#define GPIOD4_CF_nCD		(GPIOD_BASE + 4)	/* Input, from CF */
+#define GPIOD5_nPIO		(GPIOD_BASE + 5)	/* Input */
+#define GPIOD6_nKEY_RECORD	(GPIOD_BASE + 6)
+#define GPIOD7_nSDIO_DETECT	(GPIOD_BASE + 7)
+#define GPIOD8_COM_DCD		(GPIOD_BASE + 8)	/* Input */
+#define GPIOD9_nAC_IN		(GPIOD_BASE + 9)
+#define GPIOD10_nSDIO_IRQ	(GPIOD_BASE + 10)	/* Input */
+#define GPIOD11_nCIOIS16	(GPIOD_BASE + 11)	/* Input, from CF */
+#define GPIOD12_nCWAIT		(GPIOD_BASE + 12)	/* Input, from CF */
+#define GPIOD13_CF_RNB		(GPIOD_BASE + 13)	/* Input */
+#define GPIOD14_nUSBC_DETECT	(GPIOD_BASE + 14)
+#define GPIOD15_nPIOW		(GPIOD_BASE + 15)	/* Input, from CPU */
+
+/*
+ * EGPIOs
+ */
+
+#define EGPIO0_VCC_3V3_EN	(HX4700_EGPIO_BASE + 0)	/* WLAN support chip */
+#define EGPIO1_WL_VREG_EN	(HX4700_EGPIO_BASE + 1)	/* WLAN power */
+#define EGPIO2_VCC_2V1_WL_EN	(HX4700_EGPIO_BASE + 2)	/* unused */
+#define EGPIO3_SS_PWR_ON	(HX4700_EGPIO_BASE + 3)	/* smart slot power */
+#define EGPIO4_CF_3V3_ON	(HX4700_EGPIO_BASE + 4)	/* CF 3.3V enable */
+#define EGPIO5_BT_3V3_ON	(HX4700_EGPIO_BASE + 5)	/* BT 3.3V enable */
+#define EGPIO6_WL1V8_EN		(HX4700_EGPIO_BASE + 6)	/* WLAN 1.8V enable */
+#define EGPIO7_VCC_3V3_WL_EN	(HX4700_EGPIO_BASE + 7)	/* WLAN 3.3V enable */
+#define EGPIO8_USB_3V3_ON	(HX4700_EGPIO_BASE + 8)	/* unused */
+
+#endif /* _HX4700_H_ */
diff --git a/arch/arm/mach-pxa/include/mach/irqs.h b/arch/arm/mach-pxa/include/mach/irqs.h
index 32bb4a2..6a1d959 100644
--- a/arch/arm/mach-pxa/include/mach/irqs.h
+++ b/arch/arm/mach-pxa/include/mach/irqs.h
@@ -91,13 +91,23 @@
 #define IRQ_TO_GPIO(i)	(((i) < IRQ_GPIO(2)) ? ((i) - IRQ_GPIO0) : IRQ_TO_GPIO_2_x(i))
 
 /*
- * The next 16 interrupts are for board specific purposes.  Since
+ * The following interrupts are for board specific purposes. Since
  * the kernel can only run on one machine at a time, we can re-use
- * these.  If you need more, increase IRQ_BOARD_END, but keep it
- * within sensible limits.
+ * these.  There will be 16 IRQs by default.  If it is not enough,
+ * IRQ_BOARD_END is allowed be customized for each board, but keep
+ * the numbers within sensible limits and in descending order, so
+ * when multiple config options are selected, the maximum will be
+ * used.
  */
 #define IRQ_BOARD_START		(PXA_GPIO_IRQ_BASE + PXA_GPIO_IRQ_NUM)
+
+#if defined(CONFIG_MACH_H4700)
+#define IRQ_BOARD_END		(IRQ_BOARD_START + 70)
+#elif defined(CONFIG_MACH_ZYLONITE)
+#define IRQ_BOARD_END		(IRQ_BOARD_START + 32)
+#else
 #define IRQ_BOARD_END		(IRQ_BOARD_START + 16)
+#endif
 
 #define IRQ_SA1111_START	(IRQ_BOARD_END)
 #define IRQ_GPAIN0		(IRQ_BOARD_END + 0)
@@ -188,8 +198,6 @@
 #define NR_IRQS			(IRQ_LOCOMO_SPI_TEND + 1)
 #elif defined(CONFIG_PXA_HAVE_BOARD_IRQS)
 #define NR_IRQS			(IRQ_BOARD_END)
-#elif defined(CONFIG_MACH_ZYLONITE)
-#define NR_IRQS			(IRQ_BOARD_START + 32)
 #else
 #define NR_IRQS			(IRQ_BOARD_START)
 #endif
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa320.h b/arch/arm/mach-pxa/include/mach/mfp-pxa320.h
index 07897e6..3ce4682 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa320.h
+++ b/arch/arm/mach-pxa/include/mach/mfp-pxa320.h
@@ -283,6 +283,9 @@
 #define GPIO41_UART1_TXD	MFP_CFG_LPM(GPIO41, AF4, FLOAT)
 #define GPIO42_UART1_RXD	MFP_CFG_LPM(GPIO42, AF4, FLOAT)
 #define GPIO42_UART1_TXD	MFP_CFG_LPM(GPIO42, AF2, FLOAT)
+#define GPIO75_UART1_RXD	MFP_CFG_LPM(GPIO75, AF1, FLOAT)
+#define GPIO76_UART1_RXD	MFP_CFG_LPM(GPIO76, AF3, FLOAT)
+#define GPIO76_UART1_TXD	MFP_CFG_LPM(GPIO76, AF1, FLOAT)
 #define GPIO97_UART1_RXD	MFP_CFG_LPM(GPIO97, AF1, FLOAT)
 #define GPIO97_UART1_TXD	MFP_CFG_LPM(GPIO97, AF6, FLOAT)
 #define GPIO98_UART1_RXD	MFP_CFG_LPM(GPIO98, AF6, FLOAT)
@@ -291,6 +294,9 @@
 #define GPIO43_UART1_RTS	MFP_CFG_LPM(GPIO43, AF4, FLOAT)
 #define GPIO48_UART1_CTS	MFP_CFG_LPM(GPIO48, AF4, FLOAT)
 #define GPIO48_UART1_RTS	MFP_CFG_LPM(GPIO48, AF2, FLOAT)
+#define GPIO77_UART1_CTS	MFP_CFG_LPM(GPIO77, AF1, FLOAT)
+#define GPIO82_UART1_RTS	MFP_CFG_LPM(GPIO82, AF1, FLOAT)
+#define GPIO82_UART1_CTS	MFP_CFG_LPM(GPIO82, AF3, FLOAT)
 #define GPIO99_UART1_CTS	MFP_CFG_LPM(GPIO99, AF1, FLOAT)
 #define GPIO99_UART1_RTS	MFP_CFG_LPM(GPIO99, AF6, FLOAT)
 #define GPIO104_UART1_CTS	MFP_CFG_LPM(GPIO104, AF6, FLOAT)
@@ -299,13 +305,18 @@
 #define GPIO45_UART1_DSR	MFP_CFG_LPM(GPIO45, AF2, FLOAT)
 #define GPIO47_UART1_DTR	MFP_CFG_LPM(GPIO47, AF2, FLOAT)
 #define GPIO47_UART1_DSR	MFP_CFG_LPM(GPIO47, AF4, FLOAT)
+#define GPIO79_UART1_DSR	MFP_CFG_LPM(GPIO79, AF1, FLOAT)
+#define GPIO81_UART1_DTR	MFP_CFG_LPM(GPIO81, AF1, FLOAT)
+#define GPIO81_UART1_DSR	MFP_CFG_LPM(GPIO81, AF3, FLOAT)
 #define GPIO101_UART1_DTR	MFP_CFG_LPM(GPIO101, AF6, FLOAT)
 #define GPIO101_UART1_DSR	MFP_CFG_LPM(GPIO101, AF1, FLOAT)
 #define GPIO103_UART1_DTR	MFP_CFG_LPM(GPIO103, AF1, FLOAT)
 #define GPIO103_UART1_DSR	MFP_CFG_LPM(GPIO103, AF6, FLOAT)
 #define GPIO44_UART1_DCD	MFP_CFG_LPM(GPIO44, AF2, FLOAT)
+#define GPIO78_UART1_DCD	MFP_CFG_LPM(GPIO78, AF1, FLOAT)
 #define GPIO100_UART1_DCD	MFP_CFG_LPM(GPIO100, AF1, FLOAT)
 #define GPIO46_UART1_RI		MFP_CFG_LPM(GPIO46, AF2, FLOAT)
+#define GPIO80_UART1_RI		MFP_CFG_LPM(GPIO80, AF1, FLOAT)
 #define GPIO102_UART1_RI	MFP_CFG_LPM(GPIO102, AF1, FLOAT)
 
 /* UART2 */
@@ -438,6 +449,9 @@
 
 #define GPIO2_RDY		MFP_CFG(GPIO2, AF1)
 #define GPIO5_NPIOR		MFP_CFG(GPIO5, AF3)
+#define GPIO6_NPIOW		MFP_CFG(GPIO6, AF3)
+#define GPIO7_NPIOS16		MFP_CFG(GPIO7, AF3)
+#define GPIO8_NPWAIT		MFP_CFG(GPIO8, AF3)
 
 #define GPIO11_PWM0_OUT		MFP_CFG(GPIO11, AF1)
 #define GPIO12_PWM1_OUT		MFP_CFG(GPIO12, AF1)
diff --git a/arch/arm/mach-pxa/include/mach/palmld.h b/arch/arm/mach-pxa/include/mach/palmld.h
index fb13c82..8721b80 100644
--- a/arch/arm/mach-pxa/include/mach/palmld.h
+++ b/arch/arm/mach-pxa/include/mach/palmld.h
@@ -56,7 +56,6 @@
 #define GPIO_NR_PALMLD_LED_AMBER	94
 
 /* IDE */
-#define GPIO_NR_PALMLD_IDE_IRQ		95
 #define GPIO_NR_PALMLD_IDE_RESET	98
 #define GPIO_NR_PALMLD_IDE_PWEN		115
 
diff --git a/arch/arm/mach-pxa/include/mach/pm.h b/arch/arm/mach-pxa/include/mach/pm.h
index a6eeef8..fd8360c 100644
--- a/arch/arm/mach-pxa/include/mach/pm.h
+++ b/arch/arm/mach-pxa/include/mach/pm.h
@@ -27,6 +27,8 @@
 extern void pxa_cpu_resume(void);
 
 extern int pxa_pm_enter(suspend_state_t state);
+extern int pxa_pm_prepare(void);
+extern void pxa_pm_finish(void);
 
 /* NOTE: this is for PM debugging on Lubbock,  it's really a big
  * ugly, but let's keep the crap minimum here, instead of direct
diff --git a/arch/arm/mach-pxa/include/mach/pxa27x.h b/arch/arm/mach-pxa/include/mach/pxa27x.h
index 6876e16..0b70269 100644
--- a/arch/arm/mach-pxa/include/mach/pxa27x.h
+++ b/arch/arm/mach-pxa/include/mach/pxa27x.h
@@ -16,4 +16,7 @@
 #define ARB_DMA_PARK		(1<<25)	   /* Be parked with DMA when idle */
 #define ARB_CORE_PARK		(1<<24)	   /* Be parked with core when idle */
 #define ARB_LOCK_FLAG		(1<<23)	   /* Only Locking masters gain access to the bus */
+
+extern int __init pxa27x_set_pwrmode(unsigned int mode);
+
 #endif /* __MACH_PXA27x_H */
diff --git a/arch/arm/mach-pxa/include/mach/sharpsl_pm.h b/arch/arm/mach-pxa/include/mach/sharpsl_pm.h
new file mode 100644
index 0000000..1920dc6
--- /dev/null
+++ b/arch/arm/mach-pxa/include/mach/sharpsl_pm.h
@@ -0,0 +1,104 @@
+/*
+ * SharpSL Battery/PM Driver
+ *
+ * Copyright (c) 2004-2005 Richard Purdie
+ *
+ * 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_SHARPSL_PM
+#define _MACH_SHARPSL_PM
+
+struct sharpsl_charger_machinfo {
+	void (*init)(void);
+	void (*exit)(void);
+	int gpio_acin;
+	int gpio_batfull;
+	int batfull_irq;
+	int gpio_batlock;
+	int gpio_fatal;
+	void (*discharge)(int);
+	void (*discharge1)(int);
+	void (*charge)(int);
+	void (*measure_temp)(int);
+	void (*presuspend)(void);
+	void (*postsuspend)(void);
+	void (*earlyresume)(void);
+	unsigned long (*read_devdata)(int);
+#define SHARPSL_BATT_VOLT       1
+#define SHARPSL_BATT_TEMP       2
+#define SHARPSL_ACIN_VOLT       3
+#define SHARPSL_STATUS_ACIN     4
+#define SHARPSL_STATUS_LOCK     5
+#define SHARPSL_STATUS_CHRGFULL 6
+#define SHARPSL_STATUS_FATAL    7
+	unsigned long (*charger_wakeup)(void);
+	int (*should_wakeup)(unsigned int resume_on_alarm);
+	void (*backlight_limit)(int);
+	int (*backlight_get_status) (void);
+	int charge_on_volt;
+	int charge_on_temp;
+	int charge_acin_high;
+	int charge_acin_low;
+	int fatal_acin_volt;
+	int fatal_noacin_volt;
+	int bat_levels;
+	struct battery_thresh *bat_levels_noac;
+	struct battery_thresh *bat_levels_acin;
+	struct battery_thresh *bat_levels_noac_bl;
+	struct battery_thresh *bat_levels_acin_bl;
+	int status_high_acin;
+	int status_low_acin;
+	int status_high_noac;
+	int status_low_noac;
+};
+
+struct battery_thresh {
+	int voltage;
+	int percentage;
+};
+
+struct battery_stat {
+	int ac_status;         /* APM AC Present/Not Present */
+	int mainbat_status;    /* APM Main Battery Status */
+	int mainbat_percent;   /* Main Battery Percentage Charge */
+	int mainbat_voltage;   /* Main Battery Voltage */
+};
+
+struct sharpsl_pm_status {
+	struct device *dev;
+	struct timer_list ac_timer;
+	struct timer_list chrg_full_timer;
+
+	int charge_mode;
+#define CHRG_ERROR    (-1)
+#define CHRG_OFF      (0)
+#define CHRG_ON       (1)
+#define CHRG_DONE     (2)
+
+	unsigned int flags;
+#define SHARPSL_SUSPENDED       (1 << 0)  /* Device is Suspended */
+#define SHARPSL_ALARM_ACTIVE    (1 << 1)  /* Alarm is for charging event (not user) */
+#define SHARPSL_BL_LIMIT        (1 << 2)  /* Backlight Intensity Limited */
+#define SHARPSL_APM_QUEUED      (1 << 3)  /* APM Event Queued */
+#define SHARPSL_DO_OFFLINE_CHRG (1 << 4)  /* Trigger the offline charger */
+
+	int full_count;
+	unsigned long charge_start_time;
+	struct sharpsl_charger_machinfo *machinfo;
+	struct battery_stat battstat;
+};
+
+extern struct sharpsl_pm_status sharpsl_pm;
+
+
+#define SHARPSL_LED_ERROR  2
+#define SHARPSL_LED_ON     1
+#define SHARPSL_LED_OFF    0
+
+void sharpsl_battery_kick(void);
+void sharpsl_pm_led(int val);
+
+#endif
diff --git a/arch/arm/mach-pxa/include/mach/uncompress.h b/arch/arm/mach-pxa/include/mach/uncompress.h
index 5706cea..b547494 100644
--- a/arch/arm/mach-pxa/include/mach/uncompress.h
+++ b/arch/arm/mach-pxa/include/mach/uncompress.h
@@ -36,7 +36,8 @@
 static inline void arch_decomp_setup(void)
 {
 	if (machine_is_littleton() || machine_is_intelmote2()
-			|| machine_is_csb726())
+	    || machine_is_csb726() || machine_is_stargate2()
+	    || machine_is_cm_x300())
 		UART = STUART;
 }
 
diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
index c872b9f..55b3788 100644
--- a/arch/arm/mach-pxa/littleton.c
+++ b/arch/arm/mach-pxa/littleton.c
@@ -42,14 +42,17 @@
 #include <mach/pxa300.h>
 #include <mach/pxafb.h>
 #include <mach/ssp.h>
+#include <mach/mmc.h>
 #include <mach/pxa2xx_spi.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/pxa27x_keypad.h>
 #include <mach/pxa3xx_nand.h>
 #include <mach/littleton.h>
 
 #include "generic.h"
 
+#define GPIO_MMC1_CARD_DETECT	mfp_to_gpio(MFP_PIN_GPIO15)
+
 /* Littleton MFP configurations */
 static mfp_cfg_t littleton_mfp_cfg[] __initdata = {
 	/* LCD */
@@ -98,6 +101,15 @@
 	GPIO123_KP_MKOUT_2,
 	GPIO124_KP_MKOUT_3,
 	GPIO125_KP_MKOUT_4,
+
+	/* MMC1 */
+	GPIO3_MMC1_DAT0,
+	GPIO4_MMC1_DAT1,
+	GPIO5_MMC1_DAT2,
+	GPIO6_MMC1_DAT3,
+	GPIO7_MMC1_CLK,
+	GPIO8_MMC1_CMD,
+	GPIO15_GPIO, /* card detect */
 };
 
 static struct resource smc91x_resources[] = {
@@ -179,15 +191,10 @@
 	.num_chipselect		= 1,
 };
 
-static void littleton_tdo24m_cs(u32 cmd)
-{
-	gpio_set_value(LITTLETON_GPIO_LCD_CS, !(cmd == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip littleton_tdo24m_chip = {
 	.rx_threshold	= 1,
 	.tx_threshold	= 1,
-	.cs_control	= littleton_tdo24m_cs,
+	.gpio_cs	= LITTLETON_GPIO_LCD_CS,
 };
 
 static struct spi_board_info littleton_spi_devices[] __initdata = {
@@ -202,16 +209,6 @@
 
 static void __init littleton_init_spi(void)
 {
-	int err;
-
-	err = gpio_request(LITTLETON_GPIO_LCD_CS, "LCD_CS");
-	if (err) {
-		pr_warning("failed to request GPIO for LCS CS\n");
-		return;
-	}
-
-	gpio_direction_output(LITTLETON_GPIO_LCD_CS, 1);
-
 	pxa2xx_set_spi_info(2, &littleton_spi_info);
 	spi_register_board_info(ARRAY_AND_SIZE(littleton_spi_devices));
 }
@@ -267,6 +264,56 @@
 static inline void littleton_init_keypad(void) {}
 #endif
 
+#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
+static int littleton_mci_init(struct device *dev,
+			      irq_handler_t littleton_detect_int, void *data)
+{
+	int err, gpio_cd = GPIO_MMC1_CARD_DETECT;
+
+	err = gpio_request(gpio_cd, "mmc card detect");
+	if (err)
+		goto err_request_cd;
+
+	gpio_direction_input(gpio_cd);
+
+	err = request_irq(gpio_to_irq(gpio_cd), littleton_detect_int,
+			  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			  "mmc card detect", data);
+	if (err) {
+		dev_err(dev, "failed to request card detect IRQ\n");
+		goto err_request_irq;
+	}
+	return 0;
+
+err_request_irq:
+	gpio_free(gpio_cd);
+err_request_cd:
+	return err;
+}
+
+static void littleton_mci_exit(struct device *dev, void *data)
+{
+	int gpio_cd = GPIO_MMC1_CARD_DETECT;
+
+	free_irq(gpio_to_irq(gpio_cd), data);
+	gpio_free(gpio_cd);
+}
+
+static struct pxamci_platform_data littleton_mci_platform_data = {
+	.detect_delay	= 20,
+	.ocr_mask	= MMC_VDD_32_33 | MMC_VDD_33_34,
+	.init 		= littleton_mci_init,
+	.exit		= littleton_mci_exit,
+};
+
+static void __init littleton_init_mmc(void)
+{
+	pxa_set_mci_info(&littleton_mci_platform_data);
+}
+#else
+static inline void littleton_init_mmc(void) {}
+#endif
+
 #if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
 static struct mtd_partition littleton_nand_partitions[] = {
 	[0] = {
@@ -407,6 +454,7 @@
 
 	littleton_init_spi();
 	littleton_init_i2c();
+	littleton_init_mmc();
 	littleton_init_lcd();
 	littleton_init_keypad();
 	littleton_init_nand();
diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index c899bbd..ca39669 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -36,7 +36,7 @@
 #include <mach/pxa27x.h>
 #include <mach/magician.h>
 #include <mach/pxafb.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/irda.h>
 #include <mach/ohci.h>
@@ -745,6 +745,14 @@
 };
 
 /*
+ * I2C
+ */
+
+static struct i2c_pxa_platform_data i2c_info = {
+	.fast_mode = 1,
+};
+
+/*
  * Platform devices
  */
 
@@ -771,7 +779,7 @@
 
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(magician_pin_config));
 
-	platform_add_devices(devices, ARRAY_SIZE(devices));
+	platform_add_devices(ARRAY_AND_SIZE(devices));
 
 	err = gpio_request(GPIO83_MAGICIAN_nIR_EN, "nIR_EN");
 	if (!err) {
@@ -779,7 +787,7 @@
 		pxa_set_ficp_info(&magician_ficp_info);
 	}
 	pxa27x_set_i2c_power_info(NULL);
-	pxa_set_i2c_info(NULL);
+	pxa_set_i2c_info(&i2c_info);
 	pxa_set_mci_info(&magician_mci_info);
 	pxa_set_ohci_info(&magician_ohci_info);
 
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index a6c8429..f4dabf0 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -46,7 +46,7 @@
 #include <mach/mainstone.h>
 #include <mach/audio.h>
 #include <mach/pxafb.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/irda.h>
 #include <mach/ohci.h>
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index ff8052c..4dc8c2e 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -48,7 +48,7 @@
 #include <mach/mmc.h>
 #include <mach/udc.h>
 #include <mach/pxa27x-udc.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/camera.h>
 #include <mach/audio.h>
 #include <media/soc_camera.h>
@@ -798,7 +798,7 @@
 	arm_machine_restart('s', cmd);
 }
 
-struct gpio_ress global_gpios[] = {
+static struct gpio_ress global_gpios[] = {
 	MIO_GPIO_OUT(GPIO9_CHARGE_EN, 1, "Charger enable"),
 	MIO_GPIO_OUT(GPIO18_POWEROFF, 0, "Power Off"),
 	MIO_GPIO_OUT(GPIO87_LCD_POWER, 0, "LCD Power")
diff --git a/arch/arm/mach-pxa/palmld.c b/arch/arm/mach-pxa/palmld.c
index 471a853..ed70f28 100644
--- a/arch/arm/mach-pxa/palmld.c
+++ b/arch/arm/mach-pxa/palmld.c
@@ -129,7 +129,7 @@
 	GPIO81_GPIO,	/* wifi reset */
 
 	/* HDD */
-	GPIO95_GPIO,	/* HDD irq */
+	GPIO98_GPIO,	/* HDD reset */
 	GPIO115_GPIO,	/* HDD power */
 
 	/* MISC */
@@ -496,6 +496,14 @@
 };
 
 /******************************************************************************
+ * HDD
+ ******************************************************************************/
+static struct platform_device palmld_hdd = {
+	.name	= "pata_palmld",
+	.id	= -1,
+};
+
+/******************************************************************************
  * Framebuffer
  ******************************************************************************/
 static struct pxafb_mode_info palmld_lcd_modes[] = {
@@ -524,30 +532,18 @@
 /******************************************************************************
  * Power management - standby
  ******************************************************************************/
-#ifdef CONFIG_PM
-static u32 *addr __initdata;
-static u32 resume[3] __initdata = {
-	0xe3a00101,	/* mov	r0,	#0x40000000 */
-	0xe380060f,	/* orr	r0, r0, #0x00f00000 */
-	0xe590f008,	/* ldr	pc, [r0, #0x08] */
-};
-
-static int __init palmld_pm_init(void)
+static void __init palmld_pm_init(void)
 {
-	int i;
+	static u32 resume[] = {
+		0xe3a00101,	/* mov	r0,	#0x40000000 */
+		0xe380060f,	/* orr	r0, r0, #0x00f00000 */
+		0xe590f008,	/* ldr	pc, [r0, #0x08] */
+	};
 
-	/* this is where the bootloader jumps */
-	addr = phys_to_virt(PALMLD_STR_BASE);
-
-	for (i = 0; i < 3; i++)
-		addr[i] = resume[i];
-
-	return 0;
+	/* copy the bootloader */
+	memcpy(phys_to_virt(PALMLD_STR_BASE), resume, sizeof(resume));
 }
 
-device_initcall(palmld_pm_init);
-#endif
-
 /******************************************************************************
  * Machine init
  ******************************************************************************/
@@ -559,6 +555,7 @@
 	&palmld_leds,
 	&power_supply,
 	&palmld_asoc,
+	&palmld_hdd,
 };
 
 static struct map_desc palmld_io_desc[] __initdata = {
@@ -586,6 +583,7 @@
 {
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(palmld_pin_config));
 
+	palmld_pm_init();
 	set_pxa_fb_info(&palmld_lcd_screen);
 	pxa_set_mci_info(&palmld_mci_platform_data);
 	pxa_set_ac97_info(&palmld_ac97_pdata);
diff --git a/arch/arm/mach-pxa/palmt5.c b/arch/arm/mach-pxa/palmt5.c
index 05bf979..aae64a1 100644
--- a/arch/arm/mach-pxa/palmt5.c
+++ b/arch/arm/mach-pxa/palmt5.c
@@ -26,6 +26,7 @@
 #include <linux/gpio.h>
 #include <linux/wm97xx_batt.h>
 #include <linux/power_supply.h>
+#include <linux/usb/gpio_vbus.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -343,11 +344,18 @@
 /******************************************************************************
  * UDC
  ******************************************************************************/
-static struct pxa2xx_udc_mach_info palmt5_udc_info __initdata = {
+static struct gpio_vbus_mach_info palmt5_udc_info = {
 	.gpio_vbus		= GPIO_NR_PALMT5_USB_DETECT_N,
 	.gpio_vbus_inverted	= 1,
 	.gpio_pullup		= GPIO_NR_PALMT5_USB_PULLUP,
-	.gpio_pullup_inverted	= 0,
+};
+
+static struct platform_device palmt5_gpio_vbus = {
+	.name	= "gpio-vbus",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &palmt5_udc_info,
+	},
 };
 
 /******************************************************************************
@@ -466,30 +474,18 @@
 /******************************************************************************
  * Power management - standby
  ******************************************************************************/
-#ifdef CONFIG_PM
-static u32 *addr __initdata;
-static u32 resume[3] __initdata = {
-	0xe3a00101,	/* mov	r0,	#0x40000000 */
-	0xe380060f,	/* orr	r0, r0, #0x00f00000 */
-	0xe590f008,	/* ldr	pc, [r0, #0x08] */
-};
-
-static int __init palmt5_pm_init(void)
+static void __init palmt5_pm_init(void)
 {
-	int i;
+	static u32 resume[] = {
+		0xe3a00101,	/* mov	r0,	#0x40000000 */
+		0xe380060f,	/* orr	r0, r0, #0x00f00000 */
+		0xe590f008,	/* ldr	pc, [r0, #0x08] */
+	};
 
-	/* this is where the bootloader jumps */
-	addr = phys_to_virt(PALMT5_STR_BASE);
-
-	for (i = 0; i < 3; i++)
-		addr[i] = resume[i];
-
-	return 0;
+	/* copy the bootloader */
+	memcpy(phys_to_virt(PALMT5_STR_BASE), resume, sizeof(resume));
 }
 
-device_initcall(palmt5_pm_init);
-#endif
-
 /******************************************************************************
  * Machine init
  ******************************************************************************/
@@ -500,6 +496,7 @@
 	&palmt5_backlight,
 	&power_supply,
 	&palmt5_asoc,
+	&palmt5_gpio_vbus,
 };
 
 /* setup udc GPIOs initial state */
@@ -515,14 +512,15 @@
 {
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(palmt5_pin_config));
 
+	palmt5_pm_init();
 	set_pxa_fb_info(&palmt5_lcd_screen);
 	pxa_set_mci_info(&palmt5_mci_platform_data);
 	palmt5_udc_init();
 	pxa_set_ac97_info(&palmt5_ac97_pdata);
-	pxa_set_udc_info(&palmt5_udc_info);
 	pxa_set_ficp_info(&palmt5_ficp_platform_data);
 	pxa_set_keypad_info(&palmt5_keypad_platform_data);
 	wm97xx_bat_set_pdata(&wm97xx_batt_pdata);
+
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
diff --git a/arch/arm/mach-pxa/palmte2.c b/arch/arm/mach-pxa/palmte2.c
index 43fcf2e..d823b09 100644
--- a/arch/arm/mach-pxa/palmte2.c
+++ b/arch/arm/mach-pxa/palmte2.c
@@ -25,6 +25,7 @@
 #include <linux/gpio.h>
 #include <linux/wm97xx_batt.h>
 #include <linux/power_supply.h>
+#include <linux/usb/gpio_vbus.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -37,6 +38,7 @@
 #include <mach/mfp-pxa25x.h>
 #include <mach/irda.h>
 #include <mach/udc.h>
+#include <mach/palmasoc.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -107,6 +109,7 @@
 	GPIO1_RST,	/* reset */
 	GPIO4_GPIO,	/* Hotsync button */
 	GPIO9_GPIO,	/* power detect */
+	GPIO15_GPIO,	/* earphone detect */
 	GPIO37_GPIO,	/* LCD power */
 	GPIO56_GPIO,	/* Backlight power */
 };
@@ -318,11 +321,18 @@
 /******************************************************************************
  * UDC
  ******************************************************************************/
-static struct pxa2xx_udc_mach_info palmte2_udc_info __initdata = {
+static struct gpio_vbus_mach_info palmte2_udc_info = {
 	.gpio_vbus		= GPIO_NR_PALMTE2_USB_DETECT_N,
 	.gpio_vbus_inverted	= 1,
 	.gpio_pullup		= GPIO_NR_PALMTE2_USB_PULLUP,
-	.gpio_pullup_inverted	= 0,
+};
+
+static struct platform_device palmte2_gpio_vbus = {
+	.name	= "gpio-vbus",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &palmte2_udc_info,
+	},
 };
 
 /******************************************************************************
@@ -395,6 +405,21 @@
 };
 
 /******************************************************************************
+ * aSoC audio
+ ******************************************************************************/
+static struct palm27x_asoc_info palmte2_asoc_pdata = {
+	.jack_gpio	= GPIO_NR_PALMTE2_EARPHONE_DETECT,
+};
+
+static struct platform_device palmte2_asoc = {
+	.name = "palm27x-asoc",
+	.id   = -1,
+	.dev  = {
+		.platform_data = &palmte2_asoc_pdata,
+	},
+};
+
+/******************************************************************************
  * Framebuffer
  ******************************************************************************/
 static struct pxafb_mode_info palmte2_lcd_modes[] = {
@@ -429,6 +454,8 @@
 #endif
 	&palmte2_backlight,
 	&power_supply,
+	&palmte2_asoc,
+	&palmte2_gpio_vbus,
 };
 
 /* setup udc GPIOs initial state */
@@ -447,7 +474,6 @@
 	set_pxa_fb_info(&palmte2_lcd_screen);
 	pxa_set_mci_info(&palmte2_mci_platform_data);
 	palmte2_udc_init();
-	pxa_set_udc_info(&palmte2_udc_info);
 	pxa_set_ac97_info(NULL);
 	pxa_set_ficp_info(&palmte2_ficp_platform_data);
 	wm97xx_bat_set_pdata(&wm97xx_batt_pdata);
diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c
index e99a893..6c15d84 100644
--- a/arch/arm/mach-pxa/palmtx.c
+++ b/arch/arm/mach-pxa/palmtx.c
@@ -27,6 +27,7 @@
 #include <linux/gpio.h>
 #include <linux/wm97xx_batt.h>
 #include <linux/power_supply.h>
+#include <linux/usb/gpio_vbus.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -359,11 +360,18 @@
 /******************************************************************************
  * UDC
  ******************************************************************************/
-static struct pxa2xx_udc_mach_info palmtx_udc_info __initdata = {
+static struct gpio_vbus_mach_info palmtx_udc_info = {
 	.gpio_vbus		= GPIO_NR_PALMTX_USB_DETECT_N,
 	.gpio_vbus_inverted	= 1,
 	.gpio_pullup		= GPIO_NR_PALMTX_USB_PULLUP,
-	.gpio_pullup_inverted	= 0,
+};
+
+static struct platform_device palmtx_gpio_vbus = {
+	.name	= "gpio-vbus",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &palmtx_udc_info,
+	},
 };
 
 /******************************************************************************
@@ -483,30 +491,18 @@
 /******************************************************************************
  * Power management - standby
  ******************************************************************************/
-#ifdef CONFIG_PM
-static u32 *addr __initdata;
-static u32 resume[3] __initdata = {
-	0xe3a00101,	/* mov	r0,	#0x40000000 */
-	0xe380060f,	/* orr	r0, r0, #0x00f00000 */
-	0xe590f008,	/* ldr	pc, [r0, #0x08] */
-};
-
-static int __init palmtx_pm_init(void)
+static void __init palmtx_pm_init(void)
 {
-	int i;
+	static u32 resume[] = {
+		0xe3a00101,	/* mov	r0,	#0x40000000 */
+		0xe380060f,	/* orr	r0, r0, #0x00f00000 */
+		0xe590f008,	/* ldr	pc, [r0, #0x08] */
+	};
 
-	/* this is where the bootloader jumps */
-	addr = phys_to_virt(PALMTX_STR_BASE);
-
-	for (i = 0; i < 3; i++)
-		addr[i] = resume[i];
-
-	return 0;
+	/* copy the bootloader */
+	memcpy(phys_to_virt(PALMTX_STR_BASE), resume, sizeof(resume));
 }
 
-device_initcall(palmtx_pm_init);
-#endif
-
 /******************************************************************************
  * Machine init
  ******************************************************************************/
@@ -517,6 +513,7 @@
 	&palmtx_backlight,
 	&power_supply,
 	&palmtx_asoc,
+	&palmtx_gpio_vbus,
 };
 
 static struct map_desc palmtx_io_desc[] __initdata = {
@@ -548,11 +545,11 @@
 {
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(palmtx_pin_config));
 
+	palmtx_pm_init();
 	set_pxa_fb_info(&palmtx_lcd_screen);
 	pxa_set_mci_info(&palmtx_mci_platform_data);
 	palmtx_udc_init();
 	pxa_set_ac97_info(&palmtx_ac97_pdata);
-	pxa_set_udc_info(&palmtx_udc_info);
 	pxa_set_ficp_info(&palmtx_ficp_platform_data);
 	pxa_set_keypad_info(&palmtx_keypad_platform_data);
 	wm97xx_bat_set_pdata(&wm97xx_batt_pdata);
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index 6c12b5a..095521e 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -28,7 +28,7 @@
 #include <media/soc_camera.h>
 
 #include <asm/gpio.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/camera.h>
 #include <asm/mach/map.h>
 #include <mach/pxa27x.h>
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
index 884b174..7693355 100644
--- a/arch/arm/mach-pxa/pm.c
+++ b/arch/arm/mach-pxa/pm.c
@@ -79,7 +79,7 @@
 	return -EINVAL;
 }
 
-static int pxa_pm_prepare(void)
+int pxa_pm_prepare(void)
 {
 	int ret = 0;
 
@@ -89,7 +89,7 @@
 	return ret;
 }
 
-static void pxa_pm_finish(void)
+void pxa_pm_finish(void)
 {
 	if (pxa_cpu_pm_fns && pxa_cpu_pm_fns->finish)
 		pxa_cpu_pm_fns->finish();
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 036bbde..ac431ed 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -39,7 +39,7 @@
 #include <mach/pxa25x.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/irda.h>
 #include <mach/poodle.h>
 #include <mach/pxafb.h>
@@ -214,13 +214,8 @@
 	.gpio_pendown		= POODLE_GPIO_TP_INT,
 };
 
-static void ads7846_cs(u32 command)
-{
-	gpio_set_value(POODLE_GPIO_TP_CS, !(command == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip poodle_ads7846_chip = {
-	.cs_control		= ads7846_cs,
+	.gpio_cs		= POODLE_GPIO_TP_CS,
 };
 
 static struct spi_board_info poodle_spi_devices[] = {
@@ -236,14 +231,6 @@
 
 static void __init poodle_init_spi(void)
 {
-	int err;
-
-	err = gpio_request(POODLE_GPIO_TP_CS, "ADS7846_CS");
-	if (err)
-		return;
-
-	gpio_direction_output(POODLE_GPIO_TP_CS, 1);
-
 	pxa2xx_set_spi_info(1, &poodle_spi_info);
 	spi_register_board_info(ARRAY_AND_SIZE(poodle_spi_devices));
 }
diff --git a/arch/arm/mach-pxa/pwm.c b/arch/arm/mach-pxa/pwm.c
deleted file mode 100644
index fcdd374..0000000
--- a/arch/arm/mach-pxa/pwm.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/pwm.c
- *
- * simple driver for PWM (Pulse Width Modulator) controller
- *
- * 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.
- *
- * 2008-02-13	initial version
- * 		eric miao <eric.miao@marvell.com>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/pwm.h>
-
-#include <asm/div64.h>
-
-/* PWM registers and bits definitions */
-#define PWMCR		(0x00)
-#define PWMDCR		(0x04)
-#define PWMPCR		(0x08)
-
-#define PWMCR_SD	(1 << 6)
-#define PWMDCR_FD	(1 << 10)
-
-struct pwm_device {
-	struct list_head	node;
-	struct platform_device *pdev;
-
-	const char	*label;
-	struct clk	*clk;
-	int		clk_enabled;
-	void __iomem	*mmio_base;
-
-	unsigned int	use_count;
-	unsigned int	pwm_id;
-};
-
-/*
- * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
- * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
- */
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
-	unsigned long long c;
-	unsigned long period_cycles, prescale, pv, dc;
-
-	if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
-		return -EINVAL;
-
-	c = clk_get_rate(pwm->clk);
-	c = c * period_ns;
-	do_div(c, 1000000000);
-	period_cycles = c;
-
-	if (period_cycles < 1)
-		period_cycles = 1;
-	prescale = (period_cycles - 1) / 1024;
-	pv = period_cycles / (prescale + 1) - 1;
-
-	if (prescale > 63)
-		return -EINVAL;
-
-	if (duty_ns == period_ns)
-		dc = PWMDCR_FD;
-	else
-		dc = (pv + 1) * duty_ns / period_ns;
-
-	/* NOTE: the clock to PWM has to be enabled first
-	 * before writing to the registers
-	 */
-	clk_enable(pwm->clk);
-	__raw_writel(prescale, pwm->mmio_base + PWMCR);
-	__raw_writel(dc, pwm->mmio_base + PWMDCR);
-	__raw_writel(pv, pwm->mmio_base + PWMPCR);
-	clk_disable(pwm->clk);
-
-	return 0;
-}
-EXPORT_SYMBOL(pwm_config);
-
-int pwm_enable(struct pwm_device *pwm)
-{
-	int rc = 0;
-
-	if (!pwm->clk_enabled) {
-		rc = clk_enable(pwm->clk);
-		if (!rc)
-			pwm->clk_enabled = 1;
-	}
-	return rc;
-}
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
-{
-	if (pwm->clk_enabled) {
-		clk_disable(pwm->clk);
-		pwm->clk_enabled = 0;
-	}
-}
-EXPORT_SYMBOL(pwm_disable);
-
-static DEFINE_MUTEX(pwm_lock);
-static LIST_HEAD(pwm_list);
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-	struct pwm_device *pwm;
-	int found = 0;
-
-	mutex_lock(&pwm_lock);
-
-	list_for_each_entry(pwm, &pwm_list, node) {
-		if (pwm->pwm_id == pwm_id) {
-			found = 1;
-			break;
-		}
-	}
-
-	if (found) {
-		if (pwm->use_count == 0) {
-			pwm->use_count++;
-			pwm->label = label;
-		} else
-			pwm = ERR_PTR(-EBUSY);
-	} else
-		pwm = ERR_PTR(-ENOENT);
-
-	mutex_unlock(&pwm_lock);
-	return pwm;
-}
-EXPORT_SYMBOL(pwm_request);
-
-void pwm_free(struct pwm_device *pwm)
-{
-	mutex_lock(&pwm_lock);
-
-	if (pwm->use_count) {
-		pwm->use_count--;
-		pwm->label = NULL;
-	} else
-		pr_warning("PWM device already freed\n");
-
-	mutex_unlock(&pwm_lock);
-}
-EXPORT_SYMBOL(pwm_free);
-
-static inline void __add_pwm(struct pwm_device *pwm)
-{
-	mutex_lock(&pwm_lock);
-	list_add_tail(&pwm->node, &pwm_list);
-	mutex_unlock(&pwm_lock);
-}
-
-static struct pwm_device *pwm_probe(struct platform_device *pdev,
-		unsigned int pwm_id, struct pwm_device *parent_pwm)
-{
-	struct pwm_device *pwm;
-	struct resource *r;
-	int ret = 0;
-
-	pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
-	if (pwm == NULL) {
-		dev_err(&pdev->dev, "failed to allocate memory\n");
-		return ERR_PTR(-ENOMEM);
-	}
-
-	pwm->clk = clk_get(&pdev->dev, NULL);
-	if (IS_ERR(pwm->clk)) {
-		ret = PTR_ERR(pwm->clk);
-		goto err_free;
-	}
-	pwm->clk_enabled = 0;
-
-	pwm->use_count = 0;
-	pwm->pwm_id = pwm_id;
-	pwm->pdev = pdev;
-
-	if (parent_pwm != NULL) {
-		/* registers for the second PWM has offset of 0x10 */
-		pwm->mmio_base = parent_pwm->mmio_base + 0x10;
-		__add_pwm(pwm);
-		return pwm;
-	}
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (r == NULL) {
-		dev_err(&pdev->dev, "no memory resource defined\n");
-		ret = -ENODEV;
-		goto err_free_clk;
-	}
-
-	r = request_mem_region(r->start, r->end - r->start + 1, pdev->name);
-	if (r == NULL) {
-		dev_err(&pdev->dev, "failed to request memory resource\n");
-		ret = -EBUSY;
-		goto err_free_clk;
-	}
-
-	pwm->mmio_base = ioremap(r->start, r->end - r->start + 1);
-	if (pwm->mmio_base == NULL) {
-		dev_err(&pdev->dev, "failed to ioremap() registers\n");
-		ret = -ENODEV;
-		goto err_free_mem;
-	}
-
-	__add_pwm(pwm);
-	platform_set_drvdata(pdev, pwm);
-	return pwm;
-
-err_free_mem:
-	release_mem_region(r->start, r->end - r->start + 1);
-err_free_clk:
-	clk_put(pwm->clk);
-err_free:
-	kfree(pwm);
-	return ERR_PTR(ret);
-}
-
-static int __devinit pxa25x_pwm_probe(struct platform_device *pdev)
-{
-	struct pwm_device *pwm = pwm_probe(pdev, pdev->id, NULL);
-
-	if (IS_ERR(pwm))
-		return PTR_ERR(pwm);
-
-	return 0;
-}
-
-static int __devinit pxa27x_pwm_probe(struct platform_device *pdev)
-{
-	struct pwm_device *pwm;
-
-	pwm = pwm_probe(pdev, pdev->id, NULL);
-	if (IS_ERR(pwm))
-		return PTR_ERR(pwm);
-
-	pwm = pwm_probe(pdev, pdev->id + 2, pwm);
-	if (IS_ERR(pwm))
-		return PTR_ERR(pwm);
-
-	return 0;
-}
-
-static int __devexit pwm_remove(struct platform_device *pdev)
-{
-	struct pwm_device *pwm;
-	struct resource *r;
-
-	pwm = platform_get_drvdata(pdev);
-	if (pwm == NULL)
-		return -ENODEV;
-
-	mutex_lock(&pwm_lock);
-	list_del(&pwm->node);
-	mutex_unlock(&pwm_lock);
-
-	iounmap(pwm->mmio_base);
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(r->start, r->end - r->start + 1);
-
-	clk_put(pwm->clk);
-	kfree(pwm);
-	return 0;
-}
-
-static struct platform_driver pxa25x_pwm_driver = {
-	.driver		= {
-		.name	= "pxa25x-pwm",
-	},
-	.probe		= pxa25x_pwm_probe,
-	.remove		= __devexit_p(pwm_remove),
-};
-
-static struct platform_driver pxa27x_pwm_driver = {
-	.driver		= {
-		.name	= "pxa27x-pwm",
-	},
-	.probe		= pxa27x_pwm_probe,
-	.remove		= __devexit_p(pwm_remove),
-};
-
-static int __init pwm_init(void)
-{
-	int ret = 0;
-
-	ret = platform_driver_register(&pxa25x_pwm_driver);
-	if (ret) {
-		printk(KERN_ERR "failed to register pxa25x_pwm_driver\n");
-		return ret;
-	}
-
-	ret = platform_driver_register(&pxa27x_pwm_driver);
-	if (ret) {
-		printk(KERN_ERR "failed to register pxa27x_pwm_driver\n");
-		return ret;
-	}
-
-	return ret;
-}
-arch_initcall(pwm_init);
-
-static void __exit pwm_exit(void)
-{
-	platform_driver_unregister(&pxa25x_pwm_driver);
-	platform_driver_unregister(&pxa27x_pwm_driver);
-}
-module_exit(pwm_exit);
-
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index a425ec7..ec68cc1 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -27,7 +27,7 @@
 #include <mach/ohci.h>
 #include <mach/pm.h>
 #include <mach/dma.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -204,6 +204,23 @@
 #define RESTORE(x)	x = sleep_save[SLEEP_SAVE_##x]
 
 /*
+ * allow platforms to override default PWRMODE setting used for PM_SUSPEND_MEM
+ */
+static unsigned int pwrmode = PWRMODE_SLEEP;
+
+int __init pxa27x_set_pwrmode(unsigned int mode)
+{
+	switch (mode) {
+	case PWRMODE_SLEEP:
+	case PWRMODE_DEEPSLEEP:
+		pwrmode = mode;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/*
  * List of global PXA peripheral registers to preserve.
  * More ones like CP and general purpose register values are preserved
  * with the stack pointer in sleep.S.
@@ -254,7 +271,7 @@
 		pxa_cpu_standby();
 		break;
 	case PM_SUSPEND_MEM:
-		pxa27x_cpu_suspend(PWRMODE_SLEEP);
+		pxa27x_cpu_suspend(pwrmode);
 		break;
 	}
 }
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index b02d454..6f678d9 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -30,7 +30,7 @@
 #include <mach/pm.h>
 #include <mach/dma.h>
 #include <mach/ssp.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -552,7 +552,7 @@
 }
 
 static struct platform_device *devices[] __initdata = {
-/*	&pxa_device_udc,	The UDC driver is PXA25x only */
+	&pxa27x_device_udc,
 	&pxa_device_ffuart,
 	&pxa_device_btuart,
 	&pxa_device_stuart,
diff --git a/arch/arm/mach-pxa/saar.c b/arch/arm/mach-pxa/saar.c
index ff82399..8241a63 100644
--- a/arch/arm/mach-pxa/saar.c
+++ b/arch/arm/mach-pxa/saar.c
@@ -27,7 +27,7 @@
 #include <asm/mach/arch.h>
 
 #include <mach/pxa930.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/pxafb.h>
 
 #include "devices.h"
diff --git a/arch/arm/mach-pxa/sharpsl.h b/arch/arm/mach-pxa/sharpsl.h
index 047909a..55259f4 100644
--- a/arch/arm/mach-pxa/sharpsl.h
+++ b/arch/arm/mach-pxa/sharpsl.h
@@ -7,7 +7,7 @@
  *
  */
 
-#include <asm/hardware/sharpsl_pm.h>
+#include <mach/sharpsl_pm.h>
 
 /*
  * SharpSL SSP Driver
@@ -44,8 +44,6 @@
 
 extern struct battery_thresh spitz_battery_levels_acin[];
 extern struct battery_thresh spitz_battery_levels_noac[];
-void sharpsl_pm_pxa_init(void);
-void sharpsl_pm_pxa_remove(void);
 int sharpsl_pm_pxa_read_max1111(int channel);
 
 
diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c
index 16b4ec6..2546c06 100644
--- a/arch/arm/mach-pxa/sharpsl_pm.c
+++ b/arch/arm/mach-pxa/sharpsl_pm.c
@@ -15,20 +15,69 @@
 #undef DEBUG
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
-#include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <linux/apm-emulation.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/suspend.h>
+#include <linux/gpio.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <mach/pm.h>
+#include <mach/pxa2xx-regs.h>
 #include <mach/pxa2xx-gpio.h>
+#include <mach/regs-rtc.h>
 #include <mach/sharpsl.h>
+#include <mach/sharpsl_pm.h>
+
 #include "sharpsl.h"
 
+/*
+ * Constants
+ */
+#define SHARPSL_CHARGE_ON_TIME_INTERVAL        (msecs_to_jiffies(1*60*1000))  /* 1 min */
+#define SHARPSL_CHARGE_FINISH_TIME             (msecs_to_jiffies(10*60*1000)) /* 10 min */
+#define SHARPSL_BATCHK_TIME                    (msecs_to_jiffies(15*1000))    /* 15 sec */
+#define SHARPSL_BATCHK_TIME_SUSPEND            (60*10)                        /* 10 min */
+
+#define SHARPSL_WAIT_CO_TIME                   15  /* 15 sec */
+#define SHARPSL_WAIT_DISCHARGE_ON              100 /* 100 msec */
+#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP   10  /* 10 msec */
+#define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT   10  /* 10 msec */
+#define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN   10  /* 10 msec */
+#define SHARPSL_CHARGE_WAIT_TIME               15  /* 15 msec */
+#define SHARPSL_CHARGE_CO_CHECK_TIME           5   /* 5 msec */
+#define SHARPSL_CHARGE_RETRY_CNT               1   /* eqv. 10 min */
+
+/*
+ * Prototypes
+ */
+#ifdef CONFIG_PM
+static int sharpsl_off_charge_battery(void);
+static int sharpsl_check_battery_voltage(void);
+static int sharpsl_fatal_check(void);
+#endif
+static int sharpsl_check_battery_temp(void);
+static int sharpsl_ac_check(void);
+static int sharpsl_average_value(int ad);
+static void sharpsl_average_clear(void);
+static void sharpsl_charge_toggle(struct work_struct *private_);
+static void sharpsl_battery_thread(struct work_struct *private_);
+
+
+/*
+ * Variables
+ */
+struct sharpsl_pm_status sharpsl_pm;
+static DECLARE_DELAYED_WORK(toggle_charger, sharpsl_charge_toggle);
+static DECLARE_DELAYED_WORK(sharpsl_bat, sharpsl_battery_thread);
+DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger);
+
+
+
 struct battery_thresh spitz_battery_levels_acin[] = {
 	{ 213, 100},
 	{ 212,  98},
@@ -144,42 +193,789 @@
 #endif
 }
 
-void sharpsl_pm_pxa_init(void)
+static int get_percentage(int voltage)
 {
-	pxa_gpio_mode(sharpsl_pm.machinfo->gpio_acin | GPIO_IN);
-	pxa_gpio_mode(sharpsl_pm.machinfo->gpio_batfull | GPIO_IN);
-	pxa_gpio_mode(sharpsl_pm.machinfo->gpio_batlock | GPIO_IN);
+	int i = sharpsl_pm.machinfo->bat_levels - 1;
+	int bl_status = sharpsl_pm.machinfo->backlight_get_status ? sharpsl_pm.machinfo->backlight_get_status() : 0;
+	struct battery_thresh *thresh;
+
+	if (sharpsl_pm.charge_mode == CHRG_ON)
+		thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_acin_bl : sharpsl_pm.machinfo->bat_levels_acin;
+	else
+		thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_noac_bl : sharpsl_pm.machinfo->bat_levels_noac;
+
+	while (i > 0 && (voltage > thresh[i].voltage))
+		i--;
+
+	return thresh[i].percentage;
+}
+
+static int get_apm_status(int voltage)
+{
+	int low_thresh, high_thresh;
+
+	if (sharpsl_pm.charge_mode == CHRG_ON) {
+		high_thresh = sharpsl_pm.machinfo->status_high_acin;
+		low_thresh = sharpsl_pm.machinfo->status_low_acin;
+	} else {
+		high_thresh = sharpsl_pm.machinfo->status_high_noac;
+		low_thresh = sharpsl_pm.machinfo->status_low_noac;
+	}
+
+	if (voltage >= high_thresh)
+		return APM_BATTERY_STATUS_HIGH;
+	if (voltage >= low_thresh)
+		return APM_BATTERY_STATUS_LOW;
+	return APM_BATTERY_STATUS_CRITICAL;
+}
+
+void sharpsl_battery_kick(void)
+{
+	schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125));
+}
+EXPORT_SYMBOL(sharpsl_battery_kick);
+
+
+static void sharpsl_battery_thread(struct work_struct *private_)
+{
+	int voltage, percent, apm_status, i = 0;
+
+	if (!sharpsl_pm.machinfo)
+		return;
+
+	sharpsl_pm.battstat.ac_status = (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN) ? APM_AC_ONLINE : APM_AC_OFFLINE);
+
+	/* Corgi cannot confirm when battery fully charged so periodically kick! */
+	if (!sharpsl_pm.machinfo->batfull_irq && (sharpsl_pm.charge_mode == CHRG_ON)
+			&& time_after(jiffies, sharpsl_pm.charge_start_time +  SHARPSL_CHARGE_ON_TIME_INTERVAL))
+		schedule_delayed_work(&toggle_charger, 0);
+
+	while(1) {
+		voltage = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
+
+		if (voltage > 0) break;
+		if (i++ > 5) {
+			voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage;
+			dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n");
+			break;
+		}
+	}
+
+	voltage = sharpsl_average_value(voltage);
+	apm_status = get_apm_status(voltage);
+	percent = get_percentage(voltage);
+
+	/* At low battery voltages, the voltage has a tendency to start
+           creeping back up so we try to avoid this here */
+	if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE) || (apm_status == APM_BATTERY_STATUS_HIGH) ||  percent <= sharpsl_pm.battstat.mainbat_percent) {
+		sharpsl_pm.battstat.mainbat_voltage = voltage;
+		sharpsl_pm.battstat.mainbat_status = apm_status;
+		sharpsl_pm.battstat.mainbat_percent = percent;
+	}
+
+	dev_dbg(sharpsl_pm.dev, "Battery: voltage: %d, status: %d, percentage: %d, time: %ld\n", voltage,
+			sharpsl_pm.battstat.mainbat_status, sharpsl_pm.battstat.mainbat_percent, jiffies);
+
+#ifdef CONFIG_BACKLIGHT_CORGI
+	/* If battery is low. limit backlight intensity to save power. */
+	if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)
+			&& ((sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_LOW) ||
+			(sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL))) {
+		if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) {
+			sharpsl_pm.machinfo->backlight_limit(1);
+			sharpsl_pm.flags |= SHARPSL_BL_LIMIT;
+		}
+	} else if (sharpsl_pm.flags & SHARPSL_BL_LIMIT) {
+		sharpsl_pm.machinfo->backlight_limit(0);
+		sharpsl_pm.flags &= ~SHARPSL_BL_LIMIT;
+	}
+#endif
+
+	/* Suspend if critical battery level */
+	if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)
+			&& (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL)
+			&& !(sharpsl_pm.flags & SHARPSL_APM_QUEUED)) {
+		sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
+		dev_err(sharpsl_pm.dev, "Fatal Off\n");
+		apm_queue_event(APM_CRITICAL_SUSPEND);
+	}
+
+	schedule_delayed_work(&sharpsl_bat, SHARPSL_BATCHK_TIME);
+}
+
+void sharpsl_pm_led(int val)
+{
+	if (val == SHARPSL_LED_ERROR) {
+		dev_err(sharpsl_pm.dev, "Charging Error!\n");
+	} else if (val == SHARPSL_LED_ON) {
+		dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
+		led_trigger_event(sharpsl_charge_led_trigger, LED_FULL);
+	} else {
+		dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
+		led_trigger_event(sharpsl_charge_led_trigger, LED_OFF);
+	}
+}
+
+static void sharpsl_charge_on(void)
+{
+	dev_dbg(sharpsl_pm.dev, "Turning Charger On\n");
+
+	sharpsl_pm.full_count = 0;
+	sharpsl_pm.charge_mode = CHRG_ON;
+	schedule_delayed_work(&toggle_charger, msecs_to_jiffies(250));
+	schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(500));
+}
+
+static void sharpsl_charge_off(void)
+{
+	dev_dbg(sharpsl_pm.dev, "Turning Charger Off\n");
+
+	sharpsl_pm.machinfo->charge(0);
+	sharpsl_pm_led(SHARPSL_LED_OFF);
+	sharpsl_pm.charge_mode = CHRG_OFF;
+
+	schedule_delayed_work(&sharpsl_bat, 0);
+}
+
+static void sharpsl_charge_error(void)
+{
+	sharpsl_pm_led(SHARPSL_LED_ERROR);
+	sharpsl_pm.machinfo->charge(0);
+	sharpsl_pm.charge_mode = CHRG_ERROR;
+}
+
+static void sharpsl_charge_toggle(struct work_struct *private_)
+{
+	dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies);
+
+	if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
+		sharpsl_charge_off();
+		return;
+	} else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) {
+		sharpsl_charge_error();
+		return;
+	}
+
+	sharpsl_pm_led(SHARPSL_LED_ON);
+	sharpsl_pm.machinfo->charge(0);
+	mdelay(SHARPSL_CHARGE_WAIT_TIME);
+	sharpsl_pm.machinfo->charge(1);
+
+	sharpsl_pm.charge_start_time = jiffies;
+}
+
+static void sharpsl_ac_timer(unsigned long data)
+{
+	int acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
+
+	dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin);
+
+	sharpsl_average_clear();
+	if (acin && (sharpsl_pm.charge_mode != CHRG_ON))
+		sharpsl_charge_on();
+	else if (sharpsl_pm.charge_mode == CHRG_ON)
+		sharpsl_charge_off();
+
+	schedule_delayed_work(&sharpsl_bat, 0);
+}
+
+
+static irqreturn_t sharpsl_ac_isr(int irq, void *dev_id)
+{
+	/* Delay the event slightly to debounce */
+	/* Must be a smaller delay than the chrg_full_isr below */
+	mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
+
+	return IRQ_HANDLED;
+}
+
+static void sharpsl_chrg_full_timer(unsigned long data)
+{
+	dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies);
+
+	sharpsl_pm.full_count++;
+
+	if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
+		dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n");
+		if (sharpsl_pm.charge_mode == CHRG_ON)
+			sharpsl_charge_off();
+	} else if (sharpsl_pm.full_count < 2) {
+		dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n");
+		schedule_delayed_work(&toggle_charger, 0);
+	} else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) {
+		dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n");
+		schedule_delayed_work(&toggle_charger, 0);
+	} else {
+		sharpsl_charge_off();
+		sharpsl_pm.charge_mode = CHRG_DONE;
+		dev_dbg(sharpsl_pm.dev, "Charge Full: Charging Finished\n");
+	}
+}
+
+/* Charging Finished Interrupt (Not present on Corgi) */
+/* Can trigger at the same time as an AC status change so
+   delay until after that has been processed */
+static irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id)
+{
+	if (sharpsl_pm.flags & SHARPSL_SUSPENDED)
+		return IRQ_HANDLED;
+
+	/* delay until after any ac interrupt */
+	mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500));
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id)
+{
+	int is_fatal = 0;
+
+	if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) {
+		dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n");
+		is_fatal = 1;
+	}
+
+	if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_FATAL)) {
+		dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n");
+		is_fatal = 1;
+	}
+
+	if (!(sharpsl_pm.flags & SHARPSL_APM_QUEUED) && is_fatal) {
+		sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
+		apm_queue_event(APM_CRITICAL_SUSPEND);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Maintain an average of the last 10 readings
+ */
+#define SHARPSL_CNV_VALUE_NUM    10
+static int sharpsl_ad_index;
+
+static void sharpsl_average_clear(void)
+{
+	sharpsl_ad_index = 0;
+}
+
+static int sharpsl_average_value(int ad)
+{
+	int i, ad_val = 0;
+	static int sharpsl_ad[SHARPSL_CNV_VALUE_NUM+1];
+
+	if (sharpsl_pm.battstat.mainbat_status != APM_BATTERY_STATUS_HIGH) {
+		sharpsl_ad_index = 0;
+		return ad;
+	}
+
+	sharpsl_ad[sharpsl_ad_index] = ad;
+	sharpsl_ad_index++;
+	if (sharpsl_ad_index >= SHARPSL_CNV_VALUE_NUM) {
+		for (i=0; i < (SHARPSL_CNV_VALUE_NUM-1); i++)
+			sharpsl_ad[i] = sharpsl_ad[i+1];
+		sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1;
+	}
+	for (i=0; i < sharpsl_ad_index; i++)
+		ad_val += sharpsl_ad[i];
+
+	return (ad_val / sharpsl_ad_index);
+}
+
+/*
+ * Take an array of 5 integers, remove the maximum and minimum values
+ * and return the average.
+ */
+static int get_select_val(int *val)
+{
+	int i, j, k, temp, sum = 0;
+
+	/* Find MAX val */
+	temp = val[0];
+	j=0;
+	for (i=1; i<5; i++) {
+		if (temp < val[i]) {
+			temp = val[i];
+			j = i;
+		}
+	}
+
+	/* Find MIN val */
+	temp = val[4];
+	k=4;
+	for (i=3; i>=0; i--) {
+		if (temp > val[i]) {
+			temp = val[i];
+			k = i;
+		}
+	}
+
+	for (i=0; i<5; i++)
+		if (i != j && i != k )
+			sum += val[i];
+
+	dev_dbg(sharpsl_pm.dev, "Average: %d from values: %d, %d, %d, %d, %d\n", sum/3, val[0], val[1], val[2], val[3], val[4]);
+
+	return (sum/3);
+}
+
+static int sharpsl_check_battery_temp(void)
+{
+	int val, i, buff[5];
+
+	/* Check battery temperature */
+	for (i=0; i<5; i++) {
+		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
+		sharpsl_pm.machinfo->measure_temp(1);
+		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
+		buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_TEMP);
+		sharpsl_pm.machinfo->measure_temp(0);
+	}
+
+	val = get_select_val(buff);
+
+	dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val);
+	if (val > sharpsl_pm.machinfo->charge_on_temp) {
+		printk(KERN_WARNING "Not charging: temperature out of limits.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int sharpsl_check_battery_voltage(void)
+{
+	int val, i, buff[5];
+
+	/* disable charge, enable discharge */
+	sharpsl_pm.machinfo->charge(0);
+	sharpsl_pm.machinfo->discharge(1);
+	mdelay(SHARPSL_WAIT_DISCHARGE_ON);
+
+	if (sharpsl_pm.machinfo->discharge1)
+		sharpsl_pm.machinfo->discharge1(1);
+
+	/* Check battery voltage */
+	for (i=0; i<5; i++) {
+		buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
+		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
+	}
+
+	if (sharpsl_pm.machinfo->discharge1)
+		sharpsl_pm.machinfo->discharge1(0);
+
+	sharpsl_pm.machinfo->discharge(0);
+
+	val = get_select_val(buff);
+	dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val);
+
+	if (val < sharpsl_pm.machinfo->charge_on_volt)
+		return -1;
+
+	return 0;
+}
+#endif
+
+static int sharpsl_ac_check(void)
+{
+	int temp, i, buff[5];
+
+	for (i=0; i<5; i++) {
+		buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_ACIN_VOLT);
+		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN);
+	}
+
+	temp = get_select_val(buff);
+	dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp);
+
+	if ((temp > sharpsl_pm.machinfo->charge_acin_high) || (temp < sharpsl_pm.machinfo->charge_acin_low)) {
+		dev_err(sharpsl_pm.dev, "Error: AC check failed.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	sharpsl_pm.flags |= SHARPSL_SUSPENDED;
+	flush_scheduled_work();
+
+	if (sharpsl_pm.charge_mode == CHRG_ON)
+		sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
+	else
+		sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
+
+	return 0;
+}
+
+static int sharpsl_pm_resume(struct platform_device *pdev)
+{
+	/* Clear the reset source indicators as they break the bootloader upon reboot */
+	RCSR = 0x0f;
+	sharpsl_average_clear();
+	sharpsl_pm.flags &= ~SHARPSL_APM_QUEUED;
+	sharpsl_pm.flags &= ~SHARPSL_SUSPENDED;
+
+	return 0;
+}
+
+static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state)
+{
+	dev_dbg(sharpsl_pm.dev, "Time is: %08x\n",RCNR);
+
+	dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n",sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG);
+	/* not charging and AC-IN! */
+
+	if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN))) {
+		dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n");
+		sharpsl_pm.charge_mode = CHRG_OFF;
+		sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
+		sharpsl_off_charge_battery();
+	}
+
+	sharpsl_pm.machinfo->presuspend();
+
+	PEDR = 0xffffffff; /* clear it */
+
+	sharpsl_pm.flags &= ~SHARPSL_ALARM_ACTIVE;
+	if ((sharpsl_pm.charge_mode == CHRG_ON) && ((alarm_enable && ((alarm_time - RCNR) > (SHARPSL_BATCHK_TIME_SUSPEND + 30))) || !alarm_enable)) {
+		RTSR &= RTSR_ALE;
+		RTAR = RCNR + SHARPSL_BATCHK_TIME_SUSPEND;
+		dev_dbg(sharpsl_pm.dev, "Charging alarm at: %08x\n",RTAR);
+		sharpsl_pm.flags |= SHARPSL_ALARM_ACTIVE;
+	} else if (alarm_enable) {
+		RTSR &= RTSR_ALE;
+		RTAR = alarm_time;
+		dev_dbg(sharpsl_pm.dev, "User alarm at: %08x\n",RTAR);
+	} else {
+		dev_dbg(sharpsl_pm.dev, "No alarms set.\n");
+	}
+
+	pxa_pm_enter(state);
+
+	sharpsl_pm.machinfo->postsuspend();
+
+	dev_dbg(sharpsl_pm.dev, "Corgi woken up from suspend: %08x\n",PEDR);
+}
+
+static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state)
+{
+	if (!sharpsl_pm.machinfo->should_wakeup(!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE) && alarm_enable) )
+	{
+		if (!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE)) {
+			dev_dbg(sharpsl_pm.dev, "No user triggered wakeup events and not charging. Strange. Suspend.\n");
+			corgi_goto_sleep(alarm_time, alarm_enable, state);
+			return 1;
+		}
+		if(sharpsl_off_charge_battery()) {
+			dev_dbg(sharpsl_pm.dev, "Charging. Suspend...\n");
+			corgi_goto_sleep(alarm_time, alarm_enable, state);
+			return 1;
+		}
+		dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n");
+	}
+
+	if ((!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) || (sharpsl_fatal_check() < 0) )
+	{
+		dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n");
+		corgi_goto_sleep(alarm_time, alarm_enable, state);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int corgi_pxa_pm_enter(suspend_state_t state)
+{
+	unsigned long alarm_time = RTAR;
+	unsigned int alarm_status = ((RTSR & RTSR_ALE) != 0);
+
+	dev_dbg(sharpsl_pm.dev, "SharpSL suspending for first time.\n");
+
+	corgi_goto_sleep(alarm_time, alarm_status, state);
+
+	while (corgi_enter_suspend(alarm_time,alarm_status,state))
+		{}
+
+	if (sharpsl_pm.machinfo->earlyresume)
+		sharpsl_pm.machinfo->earlyresume();
+
+	dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n");
+
+	return 0;
+}
+
+/*
+ * Check for fatal battery errors
+ * Fatal returns -1
+ */
+static int sharpsl_fatal_check(void)
+{
+	int buff[5], temp, i, acin;
+
+	dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n");
+
+	/* Check AC-Adapter */
+	acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
+
+	if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
+		sharpsl_pm.machinfo->charge(0);
+		udelay(100);
+		sharpsl_pm.machinfo->discharge(1);	/* enable discharge */
+		mdelay(SHARPSL_WAIT_DISCHARGE_ON);
+	}
+
+	if (sharpsl_pm.machinfo->discharge1)
+		sharpsl_pm.machinfo->discharge1(1);
+
+	/* Check battery : check inserting battery ? */
+	for (i=0; i<5; i++) {
+		buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
+		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
+	}
+
+	if (sharpsl_pm.machinfo->discharge1)
+		sharpsl_pm.machinfo->discharge1(0);
+
+	if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
+		udelay(100);
+		sharpsl_pm.machinfo->charge(1);
+		sharpsl_pm.machinfo->discharge(0);
+	}
+
+	temp = get_select_val(buff);
+	dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %ld\n", acin, temp, sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT));
+
+	if ((acin && (temp < sharpsl_pm.machinfo->fatal_acin_volt)) ||
+			(!acin && (temp < sharpsl_pm.machinfo->fatal_noacin_volt)))
+		return -1;
+	return 0;
+}
+
+static int sharpsl_off_charge_error(void)
+{
+	dev_err(sharpsl_pm.dev, "Offline Charger: Error occurred.\n");
+	sharpsl_pm.machinfo->charge(0);
+	sharpsl_pm_led(SHARPSL_LED_ERROR);
+	sharpsl_pm.charge_mode = CHRG_ERROR;
+	return 1;
+}
+
+/*
+ * Charging Control while suspended
+ * Return 1 - go straight to sleep
+ * Return 0 - sleep or wakeup depending on other factors
+ */
+static int sharpsl_off_charge_battery(void)
+{
+	int time;
+
+	dev_dbg(sharpsl_pm.dev, "Charge Mode: %d\n", sharpsl_pm.charge_mode);
+
+	if (sharpsl_pm.charge_mode == CHRG_OFF) {
+		dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n");
+
+		/* AC Check */
+		if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery_temp() < 0))
+			return sharpsl_off_charge_error();
+
+		/* Start Charging */
+		sharpsl_pm_led(SHARPSL_LED_ON);
+		sharpsl_pm.machinfo->charge(0);
+		mdelay(SHARPSL_CHARGE_WAIT_TIME);
+		sharpsl_pm.machinfo->charge(1);
+
+		sharpsl_pm.charge_mode = CHRG_ON;
+		sharpsl_pm.full_count = 0;
+
+		return 1;
+	} else if (sharpsl_pm.charge_mode != CHRG_ON) {
+		return 1;
+	}
+
+	if (sharpsl_pm.full_count == 0) {
+		int time;
+
+		dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n");
+
+		if ((sharpsl_check_battery_temp() < 0) || (sharpsl_check_battery_voltage() < 0))
+			return sharpsl_off_charge_error();
+
+		sharpsl_pm.machinfo->charge(0);
+		mdelay(SHARPSL_CHARGE_WAIT_TIME);
+		sharpsl_pm.machinfo->charge(1);
+		sharpsl_pm.charge_mode = CHRG_ON;
+
+		mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
+
+		time = RCNR;
+		while(1) {
+			/* Check if any wakeup event had occurred */
+			if (sharpsl_pm.machinfo->charger_wakeup() != 0)
+				return 0;
+			/* Check for timeout */
+			if ((RCNR - time) > SHARPSL_WAIT_CO_TIME)
+				return 1;
+			if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
+				dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occurred. Retrying to check\n");
+				sharpsl_pm.full_count++;
+				sharpsl_pm.machinfo->charge(0);
+				mdelay(SHARPSL_CHARGE_WAIT_TIME);
+				sharpsl_pm.machinfo->charge(1);
+				return 1;
+			}
+		}
+	}
+
+	dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 3\n");
+
+	mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
+
+	time = RCNR;
+	while(1) {
+		/* Check if any wakeup event had occurred */
+		if (sharpsl_pm.machinfo->charger_wakeup() != 0)
+			return 0;
+		/* Check for timeout */
+		if ((RCNR-time) > SHARPSL_WAIT_CO_TIME) {
+			if (sharpsl_pm.full_count > SHARPSL_CHARGE_RETRY_CNT) {
+				dev_dbg(sharpsl_pm.dev, "Offline Charger: Not charged sufficiently. Retrying.\n");
+				sharpsl_pm.full_count = 0;
+			}
+			sharpsl_pm.full_count++;
+			return 1;
+		}
+		if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
+			dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n");
+			sharpsl_pm_led(SHARPSL_LED_OFF);
+			sharpsl_pm.machinfo->charge(0);
+			sharpsl_pm.charge_mode = CHRG_DONE;
+			return 1;
+		}
+	}
+}
+#else
+#define sharpsl_pm_suspend	NULL
+#define sharpsl_pm_resume	NULL
+#endif
+
+static ssize_t battery_percentage_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_percent);
+}
+
+static ssize_t battery_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_voltage);
+}
+
+static DEVICE_ATTR(battery_percentage, 0444, battery_percentage_show, NULL);
+static DEVICE_ATTR(battery_voltage, 0444, battery_voltage_show, NULL);
+
+extern void (*apm_get_power_status)(struct apm_power_info *);
+
+static void sharpsl_apm_get_power_status(struct apm_power_info *info)
+{
+	info->ac_line_status = sharpsl_pm.battstat.ac_status;
+
+	if (sharpsl_pm.charge_mode == CHRG_ON)
+		info->battery_status = APM_BATTERY_STATUS_CHARGING;
+	else
+		info->battery_status = sharpsl_pm.battstat.mainbat_status;
+
+	info->battery_flag = (1 << info->battery_status);
+	info->battery_life = sharpsl_pm.battstat.mainbat_percent;
+}
+
+#ifdef CONFIG_PM
+static struct platform_suspend_ops sharpsl_pm_ops = {
+	.prepare	= pxa_pm_prepare,
+	.finish		= pxa_pm_finish,
+	.enter		= corgi_pxa_pm_enter,
+	.valid		= suspend_valid_only_mem,
+};
+#endif
+
+static int __init sharpsl_pm_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	if (!pdev->dev.platform_data)
+		return -EINVAL;
+
+	sharpsl_pm.dev = &pdev->dev;
+	sharpsl_pm.machinfo = pdev->dev.platform_data;
+	sharpsl_pm.charge_mode = CHRG_OFF;
+	sharpsl_pm.flags = 0;
+
+	init_timer(&sharpsl_pm.ac_timer);
+	sharpsl_pm.ac_timer.function = sharpsl_ac_timer;
+
+	init_timer(&sharpsl_pm.chrg_full_timer);
+	sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer;
+
+	led_trigger_register_simple("sharpsl-charge", &sharpsl_charge_led_trigger);
+
+	sharpsl_pm.machinfo->init();
+
+	gpio_request(sharpsl_pm.machinfo->gpio_acin, "AC IN");
+	gpio_direction_input(sharpsl_pm.machinfo->gpio_acin);
+	gpio_request(sharpsl_pm.machinfo->gpio_batfull, "Battery Full");
+	gpio_direction_input(sharpsl_pm.machinfo->gpio_batfull);
+	gpio_request(sharpsl_pm.machinfo->gpio_batlock, "Battery Lock");
+	gpio_direction_input(sharpsl_pm.machinfo->gpio_batlock);
 
 	/* Register interrupt handlers */
-	if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr, IRQF_DISABLED, "AC Input Detect", sharpsl_ac_isr)) {
+	if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr, IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "AC Input Detect", sharpsl_ac_isr)) {
 		dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin));
 	}
-	else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin),IRQ_TYPE_EDGE_BOTH);
 
-	if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr, IRQF_DISABLED, "Battery Cover", sharpsl_fatal_isr)) {
+	if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr, IRQF_DISABLED | IRQF_TRIGGER_FALLING, "Battery Cover", sharpsl_fatal_isr)) {
 		dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock));
 	}
-	else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock),IRQ_TYPE_EDGE_FALLING);
 
 	if (sharpsl_pm.machinfo->gpio_fatal) {
-		if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr, IRQF_DISABLED, "Fatal Battery", sharpsl_fatal_isr)) {
+		if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr, IRQF_DISABLED | IRQF_TRIGGER_FALLING, "Fatal Battery", sharpsl_fatal_isr)) {
 			dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal));
 		}
-		else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal),IRQ_TYPE_EDGE_FALLING);
 	}
 
 	if (sharpsl_pm.machinfo->batfull_irq)
 	{
 		/* Register interrupt handler. */
-		if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr, IRQF_DISABLED, "CO", sharpsl_chrg_full_isr)) {
+		if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr, IRQF_DISABLED | IRQF_TRIGGER_RISING, "CO", sharpsl_chrg_full_isr)) {
 			dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull));
 		}
-		else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull),IRQ_TYPE_EDGE_RISING);
 	}
+
+	ret = device_create_file(&pdev->dev, &dev_attr_battery_percentage);
+	ret |= device_create_file(&pdev->dev, &dev_attr_battery_voltage);
+	if (ret != 0)
+		dev_warn(&pdev->dev, "Failed to register attributes (%d)\n", ret);
+
+	apm_get_power_status = sharpsl_apm_get_power_status;
+
+#ifdef CONFIG_PM
+	suspend_set_ops(&sharpsl_pm_ops);
+#endif
+
+	mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
+
+	return 0;
 }
 
-void sharpsl_pm_pxa_remove(void)
+static int sharpsl_pm_remove(struct platform_device *pdev)
 {
+	suspend_set_ops(NULL);
+
+	device_remove_file(&pdev->dev, &dev_attr_battery_percentage);
+	device_remove_file(&pdev->dev, &dev_attr_battery_voltage);
+
+	led_trigger_unregister_simple(sharpsl_charge_led_trigger);
+
 	free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr);
 	free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr);
 
@@ -188,4 +984,39 @@
 
 	if (sharpsl_pm.machinfo->batfull_irq)
 		free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr);
+
+	gpio_free(sharpsl_pm.machinfo->gpio_batlock);
+	gpio_free(sharpsl_pm.machinfo->gpio_batfull);
+	gpio_free(sharpsl_pm.machinfo->gpio_acin);
+
+	if (sharpsl_pm.machinfo->exit)
+		sharpsl_pm.machinfo->exit();
+
+	del_timer_sync(&sharpsl_pm.chrg_full_timer);
+	del_timer_sync(&sharpsl_pm.ac_timer);
+
+	return 0;
 }
+
+static struct platform_driver sharpsl_pm_driver = {
+	.probe		= sharpsl_pm_probe,
+	.remove		= sharpsl_pm_remove,
+	.suspend	= sharpsl_pm_suspend,
+	.resume		= sharpsl_pm_resume,
+	.driver		= {
+		.name		= "sharpsl-pm",
+	},
+};
+
+static int __devinit sharpsl_pm_init(void)
+{
+	return platform_driver_register(&sharpsl_pm_driver);
+}
+
+static void sharpsl_pm_exit(void)
+{
+	platform_driver_unregister(&sharpsl_pm_driver);
+}
+
+late_initcall(sharpsl_pm_init);
+module_exit(sharpsl_pm_exit);
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 5a45fe3..dda310f 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -13,19 +13,11 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/interrupt.h>
 #include <linux/gpio.h>
 #include <linux/leds.h>
-#include <linux/mmc/host.h>
 #include <linux/mtd/physmap.h>
-#include <linux/pm.h>
-#include <linux/backlight.h>
-#include <linux/io.h>
 #include <linux/i2c.h>
 #include <linux/i2c/pca953x.h>
 #include <linux/spi/spi.h>
@@ -34,31 +26,22 @@
 #include <linux/mtd/sharpsl.h>
 
 #include <asm/setup.h>
-#include <asm/memory.h>
 #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>
-#include <asm/mach/irq.h>
+#include <asm/mach/sharpsl_param.h>
+#include <asm/hardware/scoop.h>
+
 
 #include <mach/pxa27x.h>
 #include <mach/pxa27x-udc.h>
 #include <mach/reset.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/irda.h>
 #include <mach/mmc.h>
 #include <mach/ohci.h>
-#include <mach/udc.h>
 #include <mach/pxafb.h>
 #include <mach/pxa2xx_spi.h>
 #include <mach/spitz.h>
-#include <mach/sharpsl.h>
-
-#include <asm/mach/sharpsl_param.h>
-#include <asm/hardware/scoop.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -317,13 +300,8 @@
 	.wait_for_sync		= spitz_wait_for_hsync,
 };
 
-static void spitz_ads7846_cs(u32 command)
-{
-	gpio_set_value(SPITZ_GPIO_ADS7846_CS, !(command == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip spitz_ads7846_chip = {
-	.cs_control		= spitz_ads7846_cs,
+	.gpio_cs		= SPITZ_GPIO_ADS7846_CS,
 };
 
 static void spitz_bl_kick_battery(void)
@@ -347,22 +325,12 @@
 	.kick_battery		= spitz_bl_kick_battery,
 };
 
-static void spitz_lcdcon_cs(u32 command)
-{
-	gpio_set_value(SPITZ_GPIO_LCDCON_CS, !(command == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip spitz_lcdcon_chip = {
-	.cs_control	= spitz_lcdcon_cs,
+	.gpio_cs	= SPITZ_GPIO_LCDCON_CS,
 };
 
-static void spitz_max1111_cs(u32 command)
-{
-	gpio_set_value(SPITZ_GPIO_MAX1111_CS, !(command == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip spitz_max1111_chip = {
-	.cs_control	= spitz_max1111_cs,
+	.gpio_cs	= SPITZ_GPIO_MAX1111_CS,
 };
 
 static struct spi_board_info spitz_spi_devices[] = {
@@ -392,30 +360,6 @@
 
 static void __init spitz_init_spi(void)
 {
-	int err;
-
-	err = gpio_request(SPITZ_GPIO_ADS7846_CS, "ADS7846_CS");
-	if (err)
-		return;
-
-	err = gpio_request(SPITZ_GPIO_LCDCON_CS, "LCDCON_CS");
-	if (err)
-		goto err_free_1;
-
-	err = gpio_request(SPITZ_GPIO_MAX1111_CS, "MAX1111_CS");
-	if (err)
-		goto err_free_2;
-
-	err = gpio_direction_output(SPITZ_GPIO_ADS7846_CS, 1);
-	if (err)
-		goto err_free_3;
-	err = gpio_direction_output(SPITZ_GPIO_LCDCON_CS, 1);
-	if (err)
-		goto err_free_3;
-	err = gpio_direction_output(SPITZ_GPIO_MAX1111_CS, 1);
-	if (err)
-		goto err_free_3;
-
 	if (machine_is_akita()) {
 		spitz_lcdcon_info.gpio_backlight_cont = AKITA_GPIO_BACKLIGHT_CONT;
 		spitz_lcdcon_info.gpio_backlight_on = AKITA_GPIO_BACKLIGHT_ON;
@@ -423,14 +367,6 @@
 
 	pxa2xx_set_spi_info(2, &spitz_spi_info);
 	spi_register_board_info(ARRAY_AND_SIZE(spitz_spi_devices));
-	return;
-
-err_free_3:
-	gpio_free(SPITZ_GPIO_MAX1111_CS);
-err_free_2:
-	gpio_free(SPITZ_GPIO_LCDCON_CS);
-err_free_1:
-	gpio_free(SPITZ_GPIO_ADS7846_CS);
 }
 #else
 static inline void spitz_init_spi(void) {}
diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c
index 2e44905..724ffb0 100644
--- a/arch/arm/mach-pxa/spitz_pm.c
+++ b/arch/arm/mach-pxa/spitz_pm.c
@@ -41,7 +41,6 @@
 {
 	pxa_gpio_mode(SPITZ_GPIO_KEY_INT | GPIO_IN);
 	pxa_gpio_mode(SPITZ_GPIO_SYNC | GPIO_IN);
-	sharpsl_pm_pxa_init();
 }
 
 static void spitz_measure_temp(int on)
@@ -182,7 +181,7 @@
 
 struct sharpsl_charger_machinfo spitz_pm_machinfo = {
 	.init             = spitz_charger_init,
-	.exit             = sharpsl_pm_pxa_remove,
+	.exit             = NULL,
 	.gpio_batlock     = SPITZ_GPIO_BAT_COVER,
 	.gpio_acin        = SPITZ_GPIO_AC_IN,
 	.gpio_batfull     = SPITZ_GPIO_CHRG_FULL,
diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c
new file mode 100644
index 0000000..3b205b6
--- /dev/null
+++ b/arch/arm/mach-pxa/stargate2.c
@@ -0,0 +1,796 @@
+/*
+ *  linux/arch/arm/mach-pxa/stargate2.c
+ *
+ *  Author:	Ed C. Epp
+ *  Created:	Nov 05, 2002
+ *  Copyright:	Intel Corp.
+ *
+ *  Modified 2009:  Jonathan Cameron <jic23@cam.ac.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/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/plat-ram.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/i2c/pcf857x.h>
+#include <linux/i2c/at24.h>
+#include <linux/smc91x.h>
+#include <linux/gpio.h>
+
+#include <asm/types.h>
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/flash.h>
+
+#include <mach/pxa27x.h>
+#include <plat/i2c.h>
+#include <mach/mmc.h>
+#include <mach/udc.h>
+#include <mach/pxa2xx_spi.h>
+#include <mach/pxa27x-udc.h>
+
+#include <linux/spi/spi.h>
+#include <linux/mfd/da903x.h>
+#include <linux/sht15.h>
+
+#include "devices.h"
+#include "generic.h"
+
+/* Bluetooth */
+#define SG2_BT_RESET		81
+
+/* SD */
+#define SG2_GPIO_nSD_DETECT	90
+#define SG2_SD_POWER_ENABLE	89
+
+static unsigned long stargate2_pin_config[] __initdata = {
+
+	GPIO15_nCS_1, /* SRAM */
+	/* SMC91x */
+	GPIO80_nCS_4,
+	GPIO40_GPIO, /*cable detect?*/
+	/* Device Identification for wakeup*/
+	GPIO102_GPIO,
+
+	/* Button */
+	GPIO91_GPIO | WAKEUP_ON_LEVEL_HIGH,
+
+	/* DA9030 */
+	GPIO1_GPIO,
+
+	/* Compact Flash */
+	GPIO79_PSKTSEL,
+	GPIO48_nPOE,
+	GPIO49_nPWE,
+	GPIO50_nPIOR,
+	GPIO51_nPIOW,
+	GPIO85_nPCE_1,
+	GPIO54_nPCE_2,
+	GPIO55_nPREG,
+	GPIO56_nPWAIT,
+	GPIO57_nIOIS16,
+	GPIO120_GPIO, /* Buff ctrl */
+	GPIO108_GPIO, /* Power ctrl */
+	GPIO82_GPIO, /* Reset */
+	GPIO53_GPIO, /* SG2_S0_GPIO_DETECT */
+
+	/* MMC */
+	GPIO32_MMC_CLK,
+	GPIO112_MMC_CMD,
+	GPIO92_MMC_DAT_0,
+	GPIO109_MMC_DAT_1,
+	GPIO110_MMC_DAT_2,
+	GPIO111_MMC_DAT_3,
+	GPIO90_GPIO, /* nSD detect */
+	GPIO89_GPIO, /* SD_POWER_ENABLE */
+
+	/* Bluetooth */
+	GPIO81_GPIO, /* reset */
+
+	/* cc2420 802.15.4 radio */
+	GPIO22_GPIO,		/* CC_RSTN  (out)*/
+	GPIO114_GPIO,		/* CC_FIFO (in) */
+	GPIO116_GPIO, 		/* CC_CCA (in) */
+	GPIO0_GPIO,		/* CC_FIFOP (in) */
+	GPIO16_GPIO,		/* CCSFD (in) */
+	GPIO39_GPIO,		/* CSn (out) */
+
+	/* I2C */
+	GPIO117_I2C_SCL,
+	GPIO118_I2C_SDA,
+
+	/* SSP 3 - 802.15.4 radio */
+	GPIO39_GPIO, /* chip select */
+	GPIO34_SSP3_SCLK,
+	GPIO35_SSP3_TXD,
+	GPIO41_SSP3_RXD,
+
+	/* SSP 2 */
+	GPIO11_SSP2_RXD,
+	GPIO38_SSP2_TXD,
+	GPIO36_SSP2_SCLK,
+	GPIO37_GPIO, /* chip select */
+
+	/* SSP 1 */
+	GPIO26_SSP1_RXD,
+	GPIO25_SSP1_TXD,
+	GPIO23_SSP1_SCLK,
+	GPIO24_GPIO, /* chip select */
+
+	/* BTUART */
+	GPIO42_BTUART_RXD,
+	GPIO43_BTUART_TXD,
+	GPIO44_BTUART_CTS,
+	GPIO45_BTUART_RTS,
+
+	/* STUART */
+	GPIO46_STUART_RXD,
+	GPIO47_STUART_TXD,
+
+	/* Basic sensor board */
+	GPIO96_GPIO,	/* accelerometer interrupt */
+	GPIO99_GPIO,	/* ADC interrupt */
+
+	/* Connector pins specified as gpios */
+	GPIO94_GPIO, /* large basic connector pin 14 */
+	GPIO10_GPIO, /* large basic connector pin 23 */
+
+	/* SHT15 */
+	GPIO100_GPIO,
+	GPIO98_GPIO,
+};
+
+/**
+ * stargate2_reset_bluetooth() reset the bluecore to ensure consistent state
+ **/
+static int stargate2_reset_bluetooth(void)
+{
+	int err;
+	err = gpio_request(SG2_BT_RESET, "SG2_BT_RESET");
+	if (err) {
+		printk(KERN_ERR "Could not get gpio for bluetooth reset \n");
+		return err;
+	}
+	gpio_direction_output(SG2_BT_RESET, 1);
+	mdelay(5);
+	/* now reset it - 5 msec minimum */
+	gpio_set_value(SG2_BT_RESET, 0);
+	mdelay(10);
+	gpio_set_value(SG2_BT_RESET, 1);
+	gpio_free(SG2_BT_RESET);
+	return 0;
+}
+
+static struct led_info stargate2_leds[] = {
+	{
+		.name = "sg2:red",
+		.flags = DA9030_LED_RATE_ON,
+	}, {
+		.name = "sg2:blue",
+		.flags = DA9030_LED_RATE_ON,
+	}, {
+		.name = "sg2:green",
+		.flags = DA9030_LED_RATE_ON,
+	},
+};
+
+static struct sht15_platform_data platform_data_sht15 = {
+	.gpio_data =  100,
+	.gpio_sck  =  98,
+};
+
+static struct platform_device sht15 = {
+	.name = "sht15",
+	.id = -1,
+	.dev = {
+		.platform_data = &platform_data_sht15,
+	},
+};
+
+static struct regulator_consumer_supply stargate2_sensor_3_con[] = {
+	{
+		.dev = &sht15.dev,
+		.supply = "vcc",
+	},
+};
+
+enum stargate2_ldos{
+	vcc_vref,
+	vcc_cc2420,
+	/* a mote connector? */
+	vcc_mica,
+	/* the CSR bluecore chip */
+	vcc_bt,
+	/* The two voltages available to sensor boards */
+	vcc_sensor_1_8,
+	vcc_sensor_3,
+	/* directly connected to the pxa27x */
+	vcc_sram_ext,
+	vcc_pxa_pll,
+	vcc_pxa_usim, /* Reference voltage for certain gpios */
+	vcc_pxa_mem,
+	vcc_pxa_flash,
+	vcc_pxa_core, /*Dc-Dc buck not yet supported */
+	vcc_lcd,
+	vcc_bb,
+	vcc_bbio, /*not sure!*/
+	vcc_io, /* cc2420 802.15.4 radio and pxa vcc_io ?*/
+};
+
+/* The values of the various regulator constraints are obviously dependent
+ * on exactly what is wired to each ldo.  Unfortunately this information is
+ * not generally available.  More information has been requested from Xbow.
+ */
+static struct regulator_init_data stargate2_ldo_init_data[] = {
+	[vcc_bbio] = {
+		.constraints = { /* board default 1.8V */
+			.name = "vcc_bbio",
+			.min_uV = 1800000,
+			.max_uV = 1800000,
+		},
+	},
+	[vcc_bb] = {
+		.constraints = { /* board default 2.8V */
+			.name = "vcc_bb",
+			.min_uV = 2700000,
+			.max_uV = 3000000,
+		},
+	},
+	[vcc_pxa_flash] = {
+		.constraints = {/* default is 1.8V */
+			.name = "vcc_pxa_flash",
+			.min_uV = 1800000,
+			.max_uV = 1800000,
+		},
+	},
+	[vcc_cc2420] = { /* also vcc_io */
+		.constraints = {
+			/* board default is 2.8V */
+			.name = "vcc_cc2420",
+			.min_uV = 2700000,
+			.max_uV = 3300000,
+		},
+	},
+	[vcc_vref] = { /* Reference for what? */
+		.constraints = { /* default 1.8V */
+			.name = "vcc_vref",
+			.min_uV = 1800000,
+			.max_uV = 1800000,
+		},
+	},
+	[vcc_sram_ext] = {
+		.constraints = { /* default 2.8V */
+			.name = "vcc_sram_ext",
+			.min_uV = 2800000,
+			.max_uV = 2800000,
+		},
+	},
+	[vcc_mica] = {
+		.constraints = { /* default 2.8V */
+			.name = "vcc_mica",
+			.min_uV = 2800000,
+			.max_uV = 2800000,
+		},
+	},
+	[vcc_bt] = {
+		.constraints = { /* default 2.8V */
+			.name = "vcc_bt",
+			.min_uV = 2800000,
+			.max_uV = 2800000,
+		},
+	},
+	[vcc_lcd] = {
+		.constraints = { /* default 2.8V */
+			.name = "vcc_lcd",
+			.min_uV = 2700000,
+			.max_uV = 3300000,
+		},
+	},
+	[vcc_io] = { /* Same or higher than everything
+			  * bar vccbat and vccusb */
+		.constraints = { /* default 2.8V */
+			.name = "vcc_io",
+			.min_uV = 2692000,
+			.max_uV = 3300000,
+		},
+	},
+	[vcc_sensor_1_8] = {
+		.constraints = { /* default 1.8V */
+			.name = "vcc_sensor_1_8",
+			.min_uV = 1800000,
+			.max_uV = 1800000,
+		},
+	},
+	[vcc_sensor_3] = { /* curiously default 2.8V */
+		.constraints = {
+			.name = "vcc_sensor_3",
+			.min_uV = 2800000,
+			.max_uV = 3000000,
+		},
+		.num_consumer_supplies = ARRAY_SIZE(stargate2_sensor_3_con),
+		.consumer_supplies = stargate2_sensor_3_con,
+	},
+	[vcc_pxa_pll] = { /* 1.17V - 1.43V, default 1.3V*/
+		.constraints = {
+			.name = "vcc_pxa_pll",
+			.min_uV = 1170000,
+			.max_uV = 1430000,
+		},
+	},
+	[vcc_pxa_usim] = {
+		.constraints = { /* default 1.8V */
+			.name = "vcc_pxa_usim",
+			.min_uV = 1710000,
+			.max_uV = 2160000,
+		},
+	},
+	[vcc_pxa_mem] = {
+		.constraints = { /* default 1.8V */
+			.name = "vcc_pxa_mem",
+			.min_uV = 1800000,
+			.max_uV = 1800000,
+		},
+	},
+};
+
+static struct da903x_subdev_info stargate2_da9030_subdevs[] = {
+	{
+		.name = "da903x-led",
+		.id = DA9030_ID_LED_2,
+		.platform_data = &stargate2_leds[0],
+	}, {
+		.name = "da903x-led",
+		.id = DA9030_ID_LED_3,
+		.platform_data = &stargate2_leds[2],
+	}, {
+		.name = "da903x-led",
+		.id = DA9030_ID_LED_4,
+		.platform_data = &stargate2_leds[1],
+	}, {
+		.name = "da903x-regulator",
+		.id = DA9030_ID_LDO2,
+		.platform_data = &stargate2_ldo_init_data[vcc_bbio],
+	}, {
+		.name = "da903x-regulator",
+		.id = DA9030_ID_LDO3,
+		.platform_data = &stargate2_ldo_init_data[vcc_bb],
+	}, {
+		.name = "da903x-regulator",
+		.id = DA9030_ID_LDO4,
+		.platform_data = &stargate2_ldo_init_data[vcc_pxa_flash],
+	}, {
+		.name = "da903x-regulator",
+		.id = DA9030_ID_LDO5,
+		.platform_data = &stargate2_ldo_init_data[vcc_cc2420],
+	}, {
+		.name = "da903x-regulator",
+		.id = DA9030_ID_LDO6,
+		.platform_data = &stargate2_ldo_init_data[vcc_vref],
+	}, {
+		.name = "da903x-regulator",
+		.id = DA9030_ID_LDO7,
+		.platform_data = &stargate2_ldo_init_data[vcc_sram_ext],
+	}, {
+		.name = "da903x-regulator",
+		.id = DA9030_ID_LDO8,
+		.platform_data = &stargate2_ldo_init_data[vcc_mica],
+	}, {
+		.name = "da903x-regulator",
+		.id = DA9030_ID_LDO9,
+		.platform_data = &stargate2_ldo_init_data[vcc_bt],
+	}, {
+		.name = "da903x-regulator",
+		.id = DA9030_ID_LDO10,
+		.platform_data = &stargate2_ldo_init_data[vcc_sensor_1_8],
+	}, {
+		.name = "da903x-regulator",
+		.id = DA9030_ID_LDO11,
+		.platform_data = &stargate2_ldo_init_data[vcc_sensor_3],
+	}, {
+		.name = "da903x-regulator",
+		.id = DA9030_ID_LDO12,
+		.platform_data = &stargate2_ldo_init_data[vcc_lcd],
+	}, {
+		.name = "da903x-regulator",
+		.id = DA9030_ID_LDO15,
+		.platform_data = &stargate2_ldo_init_data[vcc_pxa_pll],
+	}, {
+		.name = "da903x-regulator",
+		.id = DA9030_ID_LDO17,
+		.platform_data = &stargate2_ldo_init_data[vcc_pxa_usim],
+	}, {
+		.name = "da903x-regulator", /*pxa vcc i/o and cc2420 vcc i/o */
+		.id = DA9030_ID_LDO18,
+		.platform_data = &stargate2_ldo_init_data[vcc_io],
+	}, {
+		.name = "da903x-regulator",
+		.id = DA9030_ID_LDO19,
+		.platform_data = &stargate2_ldo_init_data[vcc_pxa_mem],
+	},
+};
+
+static struct da903x_platform_data stargate2_da9030_pdata = {
+	.num_subdevs = ARRAY_SIZE(stargate2_da9030_subdevs),
+	.subdevs = stargate2_da9030_subdevs,
+};
+
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.name = "smc91x-regs",
+		.start = (PXA_CS4_PHYS + 0x300),
+		.end = (PXA_CS4_PHYS + 0xfffff),
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_GPIO(40),
+		.end = IRQ_GPIO(40),
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+	}
+};
+
+static struct smc91x_platdata stargate2_smc91x_info = {
+	.flags = SMC91X_USE_8BIT | SMC91X_USE_16BIT | SMC91X_USE_32BIT
+	| SMC91X_NOWAIT | SMC91X_USE_DMA,
+};
+
+static struct platform_device smc91x_device = {
+	.name = "smc91x",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(smc91x_resources),
+	.resource = smc91x_resources,
+	.dev = {
+		.platform_data = &stargate2_smc91x_info,
+	},
+};
+
+
+
+static struct pxamci_platform_data stargate2_mci_platform_data;
+
+/*
+ * The card detect interrupt isn't debounced so we delay it by 250ms
+ * to give the card a chance to fully insert / eject.
+ */
+static int stargate2_mci_init(struct device *dev,
+			      irq_handler_t stargate2_detect_int,
+			      void *data)
+{
+	int err;
+
+	err = gpio_request(SG2_SD_POWER_ENABLE, "SG2_sd_power_enable");
+	if (err) {
+		printk(KERN_ERR "Can't get the gpio for SD power control");
+		goto return_err;
+	}
+	gpio_direction_output(SG2_SD_POWER_ENABLE, 0);
+
+	err = gpio_request(SG2_GPIO_nSD_DETECT, "SG2_sd_detect");
+	if (err) {
+		printk(KERN_ERR "Can't get the sd detect gpio");
+		goto free_power_en;
+	}
+	gpio_direction_input(SG2_GPIO_nSD_DETECT);
+	/* Delay to allow for full insertion */
+	stargate2_mci_platform_data.detect_delay = msecs_to_jiffies(250);
+
+	err = request_irq(IRQ_GPIO(SG2_GPIO_nSD_DETECT),
+			  stargate2_detect_int,
+			  IRQ_TYPE_EDGE_BOTH,
+			  "MMC card detect",
+			  data);
+	if (err) {
+		printk(KERN_ERR "can't request MMC card detect IRQ\n");
+		goto free_nsd_detect;
+	}
+	return 0;
+
+ free_nsd_detect:
+	gpio_free(SG2_GPIO_nSD_DETECT);
+ free_power_en:
+	gpio_free(SG2_SD_POWER_ENABLE);
+ return_err:
+	return err;
+}
+
+/**
+ * stargate2_mci_setpower() - set state of mmc power supply
+ *
+ * Very simple control. Either it is on or off and is controlled by
+ * a gpio pin */
+static void stargate2_mci_setpower(struct device *dev, unsigned int vdd)
+{
+	gpio_set_value(SG2_SD_POWER_ENABLE, !!vdd);
+}
+
+static void stargate2_mci_exit(struct device *dev, void *data)
+{
+	free_irq(IRQ_GPIO(SG2_GPIO_nSD_DETECT), data);
+	gpio_free(SG2_SD_POWER_ENABLE);
+	gpio_free(SG2_GPIO_nSD_DETECT);
+}
+
+static struct pxamci_platform_data stargate2_mci_platform_data = {
+	.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+	.init = stargate2_mci_init,
+	.setpower = stargate2_mci_setpower,
+	.exit = stargate2_mci_exit,
+};
+
+static struct mtd_partition stargate2flash_partitions[] = {
+	{
+		.name = "Bootloader",
+		.size = 0x00040000,
+		.offset = 0,
+		.mask_flags = 0,
+	}, {
+		.name = "Kernel",
+		.size = 0x00200000,
+		.offset = 0x00040000,
+		.mask_flags = 0
+	}, {
+		.name = "Filesystem",
+		.size = 0x01DC0000,
+		.offset = 0x00240000,
+		.mask_flags = 0
+	},
+};
+
+static struct resource flash_resources = {
+	.start = PXA_CS0_PHYS,
+	.end = PXA_CS0_PHYS + SZ_32M - 1,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct flash_platform_data stargate2_flash_data = {
+	.map_name = "cfi_probe",
+	.parts = stargate2flash_partitions,
+	.nr_parts = ARRAY_SIZE(stargate2flash_partitions),
+	.name = "PXA27xOnChipROM",
+	.width = 2,
+};
+
+static struct platform_device stargate2_flash_device = {
+	.name = "pxa2xx-flash",
+	.id = 0,
+	.dev = {
+		.platform_data = &stargate2_flash_data,
+	},
+	.resource = &flash_resources,
+	.num_resources = 1,
+};
+
+/*
+ * SRAM - The Stargate 2 has 32MB of SRAM.
+ *
+ * Here it is made available as an MTD. This will then
+ * typically have a cifs filesystem created on it to provide
+ * fast temporary storage.
+ */
+static struct resource sram_resources = {
+	.start = PXA_CS1_PHYS,
+	.end = PXA_CS1_PHYS + SZ_32M-1,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct platdata_mtd_ram stargate2_sram_pdata = {
+	.mapname = "Stargate2 SRAM",
+	.bankwidth = 2,
+};
+
+static struct platform_device stargate2_sram = {
+	.name = "mtd-ram",
+	.id = 0,
+	.resource = &sram_resources,
+	.num_resources = 1,
+	.dev = {
+		.platform_data = &stargate2_sram_pdata,
+	},
+};
+
+static struct pcf857x_platform_data platform_data_pcf857x = {
+	.gpio_base = 128,
+	.n_latch = 0,
+	.setup = NULL,
+	.teardown = NULL,
+	.context = NULL,
+};
+
+static struct at24_platform_data pca9500_eeprom_pdata = {
+	.byte_len = 256,
+	.page_size = 4,
+};
+
+
+static struct i2c_board_info __initdata stargate2_i2c_board_info[] = {
+	/* Techically this a pca9500 - but it's compatible with the 8574
+	 * for gpio expansion and the 24c02 for eeprom access.
+	 */
+	{
+		.type = "pcf8574",
+		.addr =  0x27,
+		.platform_data = &platform_data_pcf857x,
+	}, {
+		.type = "24c02",
+		.addr = 0x57,
+		.platform_data = &pca9500_eeprom_pdata,
+	}, {
+		.type = "max1238",
+		.addr = 0x35,
+	}, { /* ITS400 Sensor board only */
+		.type = "max1363",
+		.addr = 0x34,
+		/* Through a nand gate - Also beware, on V2 sensor board the
+		 * pull up resistors are missing.
+		 */
+		.irq = IRQ_GPIO(99),
+	}, { /* ITS400 Sensor board only */
+		.type = "tsl2561",
+		.addr = 0x49,
+		/* Through a nand gate - Also beware, on V2 sensor board the
+		 * pull up resistors are missing.
+		 */
+		.irq = IRQ_GPIO(99),
+	}, { /* ITS400 Sensor board only */
+		.type = "tmp175",
+		.addr = 0x4A,
+		.irq = IRQ_GPIO(96),
+	},
+};
+
+static struct i2c_board_info __initdata stargate2_pwr_i2c_board_info[] = {
+	{
+		.type = "da9030",
+		.addr = 0x49,
+		.platform_data = &stargate2_da9030_pdata,
+		.irq = gpio_to_irq(1),
+	},
+};
+
+static struct pxa2xx_spi_master pxa_ssp_master_0_info = {
+	.num_chipselect = 1,
+};
+
+static struct pxa2xx_spi_master pxa_ssp_master_1_info = {
+	.num_chipselect = 1,
+};
+
+static struct pxa2xx_spi_master pxa_ssp_master_2_info = {
+	.num_chipselect = 1,
+};
+
+/* An upcoming kernel change will scrap SFRM usage so these
+ * drivers have been moved to use gpio's via cs_control */
+static struct pxa2xx_spi_chip staccel_chip_info = {
+	.tx_threshold = 8,
+	.rx_threshold = 8,
+	.dma_burst_size = 8,
+	.timeout = 235,
+	.gpio_cs = 24,
+};
+
+static struct pxa2xx_spi_chip cc2420_info = {
+	.tx_threshold = 8,
+	.rx_threshold = 8,
+	.dma_burst_size = 8,
+	.timeout = 235,
+	.gpio_cs = 39,
+};
+
+static struct spi_board_info spi_board_info[] __initdata = {
+	{
+		.modalias = "lis3l02dq",
+		.max_speed_hz = 8000000,/* 8MHz max spi frequency at 3V */
+		.bus_num = 1,
+		.chip_select = 0,
+		.controller_data = &staccel_chip_info,
+		.irq = IRQ_GPIO(96),
+	}, {
+		.modalias = "cc2420",
+		.max_speed_hz = 6500000,
+		.bus_num = 3,
+		.chip_select = 0,
+		.controller_data = &cc2420_info,
+	},
+};
+
+static void sg2_udc_command(int cmd)
+{
+	switch (cmd) {
+	case PXA2XX_UDC_CMD_CONNECT:
+		UP2OCR |=  UP2OCR_HXOE  | UP2OCR_DPPUE | UP2OCR_DPPUBE;
+		break;
+	case PXA2XX_UDC_CMD_DISCONNECT:
+		UP2OCR &= ~(UP2OCR_HXOE  | UP2OCR_DPPUE | UP2OCR_DPPUBE);
+		break;
+	}
+}
+
+/* Board doesn't support cable detection - so always lie and say
+ * something is there.
+ */
+static int sg2_udc_detect(void)
+{
+	return 1;
+}
+
+static struct pxa2xx_udc_mach_info stargate2_udc_info __initdata = {
+	.udc_is_connected	= sg2_udc_detect,
+	.udc_command		= sg2_udc_command,
+};
+
+static struct platform_device *stargate2_devices[] = {
+	&stargate2_flash_device,
+	&stargate2_sram,
+	&smc91x_device,
+	&sht15,
+};
+
+static struct i2c_pxa_platform_data i2c_pwr_pdata = {
+	.fast_mode = 1,
+};
+
+static struct i2c_pxa_platform_data i2c_pdata = {
+	.fast_mode = 1,
+};
+
+static void __init stargate2_init(void)
+{
+	/* This is probably a board specific hack as this must be set
+	   prior to connecting the MFP stuff up. */
+	MECR &= ~MECR_NOS;
+
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(stargate2_pin_config));
+
+	/* spi chip selects */
+	gpio_direction_output(37, 0);
+	gpio_direction_output(24, 0);
+	gpio_direction_output(39, 0);
+
+	platform_add_devices(ARRAY_AND_SIZE(stargate2_devices));
+
+	pxa2xx_set_spi_info(1, &pxa_ssp_master_0_info);
+	pxa2xx_set_spi_info(2, &pxa_ssp_master_1_info);
+	pxa2xx_set_spi_info(3, &pxa_ssp_master_2_info);
+	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+	i2c_register_board_info(0, ARRAY_AND_SIZE(stargate2_i2c_board_info));
+	i2c_register_board_info(1,
+				ARRAY_AND_SIZE(stargate2_pwr_i2c_board_info));
+	pxa27x_set_i2c_power_info(&i2c_pwr_pdata);
+	pxa_set_i2c_info(&i2c_pdata);
+
+	pxa_set_mci_info(&stargate2_mci_platform_data);
+
+	pxa_set_udc_info(&stargate2_udc_info);
+
+	stargate2_reset_bluetooth();
+}
+
+MACHINE_START(STARGATE2, "Stargate 2")
+	.phys_io = 0x40000000,
+	.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.map_io = pxa_map_io,
+	.init_irq = pxa27x_init_irq,
+	.timer = &pxa_timer,
+	.init_machine = stargate2_init,
+	.boot_params = 0xA0000100,
+MACHINE_END
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index a0bd46e..168267a 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -40,7 +40,7 @@
 #include <mach/pxa25x.h>
 #include <mach/reset.h>
 #include <mach/irda.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
 #include <mach/tosa_bt.h>
diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c
index f79c9cb..825f540 100644
--- a/arch/arm/mach-pxa/trizeps4.c
+++ b/arch/arm/mach-pxa/trizeps4.c
@@ -47,7 +47,7 @@
 #include <mach/mmc.h>
 #include <mach/irda.h>
 #include <mach/ohci.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 
 #include "generic.h"
 #include "devices.h"
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c
index dd031cc..d33c232 100644
--- a/arch/arm/mach-pxa/viper.c
+++ b/arch/arm/mach-pxa/viper.c
@@ -45,7 +45,7 @@
 #include <mach/pxa25x.h>
 #include <mach/audio.h>
 #include <mach/pxafb.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/regs-uart.h>
 #include <mach/viper.h>
 
diff --git a/arch/arm/mach-pxa/zylonite_pxa300.c b/arch/arm/mach-pxa/zylonite_pxa300.c
index c256c57..cefd1c0 100644
--- a/arch/arm/mach-pxa/zylonite_pxa300.c
+++ b/arch/arm/mach-pxa/zylonite_pxa300.c
@@ -21,7 +21,7 @@
 #include <linux/gpio.h>
 
 #include <mach/pxa300.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/zylonite.h>
 
 #include "generic.h"
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
index b6ec106..d4cfa21 100644
--- a/arch/arm/mach-realview/Kconfig
+++ b/arch/arm/mach-realview/Kconfig
@@ -24,7 +24,6 @@
 config REALVIEW_EB_ARM11MP_REVB
 	bool "Support ARM11MPCore RevB tile"
 	depends on REALVIEW_EB_ARM11MP
-	default n
 	help
 	  Enable support for the ARM11MPCore RevB tile on the Realview
 	  platform. Since there are device address differences, a
@@ -48,6 +47,15 @@
 	help
 	  Include support for the ARM(R) RealView ARM1176 Platform Baseboard.
 
+config REALVIEW_PB1176_SECURE_FLASH
+	bool "Allow access to the secure flash memory block"
+	depends on MACH_REALVIEW_PB1176
+	default n
+	help
+	  Select this option if Linux will only run in secure mode on the
+	  RealView PB1176 platform and access to the secure flash memory
+	  block (64MB @ 0x3c000000) is required.
+
 config MACH_REALVIEW_PBA8
 	bool "Support RealView/PB-A8 platform"
 	select CPU_V7
@@ -58,6 +66,13 @@
 	  PB-A8 is a platform with an on-board Cortex-A8 and has support for
 	  PCI-E and Compact Flash.
 
+config MACH_REALVIEW_PBX
+	bool "Support RealView/PBX platform"
+	select ARM_GIC
+	select HAVE_PATA_PLATFORM
+	help
+	  Include support for the ARM(R) RealView PBX platform.
+
 config REALVIEW_HIGH_PHYS_OFFSET
 	bool "High physical base address for the RealView platform"
 	depends on !MACH_REALVIEW_PB1176
diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile
index 7bea8ff..e704edb 100644
--- a/arch/arm/mach-realview/Makefile
+++ b/arch/arm/mach-realview/Makefile
@@ -7,5 +7,7 @@
 obj-$(CONFIG_MACH_REALVIEW_PB11MP)	+= realview_pb11mp.o
 obj-$(CONFIG_MACH_REALVIEW_PB1176)	+= realview_pb1176.o
 obj-$(CONFIG_MACH_REALVIEW_PBA8)	+= realview_pba8.o
-obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o localtimer.o
+obj-$(CONFIG_MACH_REALVIEW_PBX)		+= realview_pbx.o
+obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)		+= hotplug.o
+obj-$(CONFIG_LOCAL_TIMERS)		+= localtimer.o
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 076acbc..9ea9c05 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -48,6 +48,9 @@
 
 #include <asm/hardware/gic.h>
 
+#include <mach/platform.h>
+#include <mach/irqs.h>
+
 #include "core.h"
 #include "clock.h"
 
@@ -578,21 +581,22 @@
 {
 	unsigned long flags;
 	u32 val;
+	u32 led = 1 << smp_processor_id();
 
 	local_irq_save(flags);
 	val = readl(VA_LEDS_BASE);
 
 	switch (ledevt) {
 	case led_idle_start:
-		val = val & ~REALVIEW_SYS_LED0;
+		val = val & ~led;
 		break;
 
 	case led_idle_end:
-		val = val | REALVIEW_SYS_LED0;
+		val = val | led;
 		break;
 
 	case led_timer:
-		val = val ^ REALVIEW_SYS_LED1;
+		val = val ^ REALVIEW_SYS_LED7;
 		break;
 
 	case led_halted:
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
index 21c0863..59a337b 100644
--- a/arch/arm/mach-realview/core.h
+++ b/arch/arm/mach-realview/core.h
@@ -51,9 +51,6 @@
 extern struct mmc_platform_data realview_mmc1_plat_data;
 extern struct clcd_board clcd_plat_data;
 extern void __iomem *gic_cpu_base_addr;
-#ifdef CONFIG_LOCAL_TIMERS
-extern void __iomem *twd_base;
-#endif
 extern void __iomem *timer0_va_base;
 extern void __iomem *timer1_va_base;
 extern void __iomem *timer2_va_base;
diff --git a/arch/arm/mach-realview/include/mach/board-eb.h b/arch/arm/mach-realview/include/mach/board-eb.h
index 268d770..794a8d9 100644
--- a/arch/arm/mach-realview/include/mach/board-eb.h
+++ b/arch/arm/mach-realview/include/mach/board-eb.h
@@ -62,111 +62,6 @@
 #define REALVIEW_EB11MP_SYS_PLD_CTRL1	0x74		/* Register offset for MPCore sysctl */
 #endif
 
-#define IRQ_EB_GIC_START	32
-
-/*
- * RealView EB interrupt sources
- */
-#define IRQ_EB_WDOG		(IRQ_EB_GIC_START + 0)		/* Watchdog timer */
-#define IRQ_EB_SOFT		(IRQ_EB_GIC_START + 1)		/* Software interrupt */
-#define IRQ_EB_COMMRx		(IRQ_EB_GIC_START + 2)		/* Debug Comm Rx interrupt */
-#define IRQ_EB_COMMTx		(IRQ_EB_GIC_START + 3)		/* Debug Comm Tx interrupt */
-#define IRQ_EB_TIMER0_1		(IRQ_EB_GIC_START + 4)		/* Timer 0 and 1 */
-#define IRQ_EB_TIMER2_3		(IRQ_EB_GIC_START + 5)		/* Timer 2 and 3 */
-#define IRQ_EB_GPIO0		(IRQ_EB_GIC_START + 6)		/* GPIO 0 */
-#define IRQ_EB_GPIO1		(IRQ_EB_GIC_START + 7)		/* GPIO 1 */
-#define IRQ_EB_GPIO2		(IRQ_EB_GIC_START + 8)		/* GPIO 2 */
-								/* 9 reserved */
-#define IRQ_EB_RTC		(IRQ_EB_GIC_START + 10)		/* Real Time Clock */
-#define IRQ_EB_SSP		(IRQ_EB_GIC_START + 11)		/* Synchronous Serial Port */
-#define IRQ_EB_UART0		(IRQ_EB_GIC_START + 12)		/* UART 0 on development chip */
-#define IRQ_EB_UART1		(IRQ_EB_GIC_START + 13)		/* UART 1 on development chip */
-#define IRQ_EB_UART2		(IRQ_EB_GIC_START + 14)		/* UART 2 on development chip */
-#define IRQ_EB_UART3		(IRQ_EB_GIC_START + 15)		/* UART 3 on development chip */
-#define IRQ_EB_SCI		(IRQ_EB_GIC_START + 16)		/* Smart Card Interface */
-#define IRQ_EB_MMCI0A		(IRQ_EB_GIC_START + 17)		/* Multimedia Card 0A */
-#define IRQ_EB_MMCI0B		(IRQ_EB_GIC_START + 18)		/* Multimedia Card 0B */
-#define IRQ_EB_AACI		(IRQ_EB_GIC_START + 19)		/* Audio Codec */
-#define IRQ_EB_KMI0		(IRQ_EB_GIC_START + 20)		/* Keyboard/Mouse port 0 */
-#define IRQ_EB_KMI1		(IRQ_EB_GIC_START + 21)		/* Keyboard/Mouse port 1 */
-#define IRQ_EB_CHARLCD		(IRQ_EB_GIC_START + 22)		/* Character LCD */
-#define IRQ_EB_CLCD		(IRQ_EB_GIC_START + 23)		/* CLCD controller */
-#define IRQ_EB_DMA		(IRQ_EB_GIC_START + 24)		/* DMA controller */
-#define IRQ_EB_PWRFAIL		(IRQ_EB_GIC_START + 25)		/* Power failure */
-#define IRQ_EB_PISMO		(IRQ_EB_GIC_START + 26)		/* PISMO interface */
-#define IRQ_EB_DoC		(IRQ_EB_GIC_START + 27)		/* Disk on Chip memory controller */
-#define IRQ_EB_ETH		(IRQ_EB_GIC_START + 28)		/* Ethernet controller */
-#define IRQ_EB_USB		(IRQ_EB_GIC_START + 29)		/* USB controller */
-#define IRQ_EB_TSPEN		(IRQ_EB_GIC_START + 30)		/* Touchscreen pen */
-#define IRQ_EB_TSKPAD		(IRQ_EB_GIC_START + 31)		/* Touchscreen keypad */
-
-/*
- * RealView EB + ARM11MPCore interrupt sources (primary GIC on the core tile)
- */
-#define IRQ_EB11MP_AACI		(IRQ_EB_GIC_START + 0)
-#define IRQ_EB11MP_TIMER0_1	(IRQ_EB_GIC_START + 1)
-#define IRQ_EB11MP_TIMER2_3	(IRQ_EB_GIC_START + 2)
-#define IRQ_EB11MP_USB		(IRQ_EB_GIC_START + 3)
-#define IRQ_EB11MP_UART0	(IRQ_EB_GIC_START + 4)
-#define IRQ_EB11MP_UART1	(IRQ_EB_GIC_START + 5)
-#define IRQ_EB11MP_RTC		(IRQ_EB_GIC_START + 6)
-#define IRQ_EB11MP_KMI0		(IRQ_EB_GIC_START + 7)
-#define IRQ_EB11MP_KMI1		(IRQ_EB_GIC_START + 8)
-#define IRQ_EB11MP_ETH		(IRQ_EB_GIC_START + 9)
-#define IRQ_EB11MP_EB_IRQ1	(IRQ_EB_GIC_START + 10)		/* main GIC */
-#define IRQ_EB11MP_EB_IRQ2	(IRQ_EB_GIC_START + 11)		/* tile GIC */
-#define IRQ_EB11MP_EB_FIQ1	(IRQ_EB_GIC_START + 12)		/* main GIC */
-#define IRQ_EB11MP_EB_FIQ2	(IRQ_EB_GIC_START + 13)		/* tile GIC */
-#define IRQ_EB11MP_MMCI0A	(IRQ_EB_GIC_START + 14)
-#define IRQ_EB11MP_MMCI0B	(IRQ_EB_GIC_START + 15)
-
-#define IRQ_EB11MP_PMU_CPU0	(IRQ_EB_GIC_START + 17)
-#define IRQ_EB11MP_PMU_CPU1	(IRQ_EB_GIC_START + 18)
-#define IRQ_EB11MP_PMU_CPU2	(IRQ_EB_GIC_START + 19)
-#define IRQ_EB11MP_PMU_CPU3	(IRQ_EB_GIC_START + 20)
-#define IRQ_EB11MP_PMU_SCU0	(IRQ_EB_GIC_START + 21)
-#define IRQ_EB11MP_PMU_SCU1	(IRQ_EB_GIC_START + 22)
-#define IRQ_EB11MP_PMU_SCU2	(IRQ_EB_GIC_START + 23)
-#define IRQ_EB11MP_PMU_SCU3	(IRQ_EB_GIC_START + 24)
-#define IRQ_EB11MP_PMU_SCU4	(IRQ_EB_GIC_START + 25)
-#define IRQ_EB11MP_PMU_SCU5	(IRQ_EB_GIC_START + 26)
-#define IRQ_EB11MP_PMU_SCU6	(IRQ_EB_GIC_START + 27)
-#define IRQ_EB11MP_PMU_SCU7	(IRQ_EB_GIC_START + 28)
-
-#define IRQ_EB11MP_L220_EVENT	(IRQ_EB_GIC_START + 29)
-#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
-
-#define NR_GIC_EB11MP		2
-
-/*
- * Only define NR_IRQS if less than NR_IRQS_EB
- */
-#define NR_IRQS_EB		(IRQ_EB_GIC_START + 96)
-
-#if defined(CONFIG_MACH_REALVIEW_EB) \
-	&& (!defined(NR_IRQS) || (NR_IRQS < NR_IRQS_EB))
-#undef NR_IRQS
-#define NR_IRQS			NR_IRQS_EB
-#endif
-
-#if defined(CONFIG_REALVIEW_EB_ARM11MP) || defined(CONFIG_REALVIEW_EB_A9MP) \
-	&& (!defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_EB11MP))
-#undef MAX_GIC_NR
-#define MAX_GIC_NR		NR_GIC_EB11MP
-#endif
-
 /*
  * Core tile identification (REALVIEW_SYS_PROCID)
  */
diff --git a/arch/arm/mach-realview/include/mach/board-pb1176.h b/arch/arm/mach-realview/include/mach/board-pb1176.h
index 858eea7..98f8e7e 100644
--- a/arch/arm/mach-realview/include/mach/board-pb1176.h
+++ b/arch/arm/mach-realview/include/mach/board-pb1176.h
@@ -32,6 +32,8 @@
 #define REALVIEW_PB1176_SDRAM67_BASE		0x70000000 /* SDRAM banks 6 and 7 */
 #define REALVIEW_PB1176_FLASH_BASE		0x30000000
 #define REALVIEW_PB1176_FLASH_SIZE		SZ_64M
+#define REALVIEW_PB1176_SEC_FLASH_BASE		0x3C000000 /* Secure flash */
+#define REALVIEW_PB1176_SEC_FLASH_SIZE		SZ_64M
 
 #define REALVIEW_PB1176_TIMER0_1_BASE		0x10104000 /* Timer 0 and 1 */
 #define REALVIEW_PB1176_TIMER2_3_BASE		0x10105000 /* Timer 2 and 3 */
@@ -71,82 +73,4 @@
 #define REALVIEW_PB1176_GIC_DIST_BASE		0x10041000 /* GIC distributor, on FPGA */
 #define REALVIEW_PB1176_L220_BASE		0x10110000 /* L220 registers */
 
-/*
- * Irqs
- */
-#define IRQ_DC1176_GIC_START			32
-#define IRQ_PB1176_GIC_START			64
-
-/*
- * ARM1176 DevChip interrupt sources (primary GIC)
- */
-#define IRQ_DC1176_WATCHDOG	(IRQ_DC1176_GIC_START + 0)	/* Watchdog timer */
-#define IRQ_DC1176_SOFTINT	(IRQ_DC1176_GIC_START + 1)	/* Software interrupt */
-#define IRQ_DC1176_COMMRx	(IRQ_DC1176_GIC_START + 2)	/* Debug Comm Rx interrupt */
-#define IRQ_DC1176_COMMTx	(IRQ_DC1176_GIC_START + 3)	/* Debug Comm Tx interrupt */
-#define IRQ_DC1176_TIMER0	(IRQ_DC1176_GIC_START + 8)	/* Timer 0 */
-#define IRQ_DC1176_TIMER1	(IRQ_DC1176_GIC_START + 9)	/* Timer 1 */
-#define IRQ_DC1176_TIMER2	(IRQ_DC1176_GIC_START + 10)	/* Timer 2 */
-#define IRQ_DC1176_APC		(IRQ_DC1176_GIC_START + 11)
-#define IRQ_DC1176_IEC		(IRQ_DC1176_GIC_START + 12)
-#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_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 */
-#define IRQ_DC1176_UART2	(IRQ_DC1176_GIC_START + 20)	/* UART 2 on development chip */
-#define IRQ_DC1176_UART3	(IRQ_DC1176_GIC_START + 21)	/* UART 3 on development chip */
-
-#define IRQ_DC1176_PB_IRQ2	(IRQ_DC1176_GIC_START + 30)	/* tile GIC */
-#define IRQ_DC1176_PB_IRQ1	(IRQ_DC1176_GIC_START + 31)	/* main GIC */
-
-/*
- * RealView PB1176 interrupt sources (secondary GIC)
- */
-#define IRQ_PB1176_MMCI0A	(IRQ_PB1176_GIC_START + 1)	/* Multimedia Card 0A */
-#define IRQ_PB1176_MMCI0B	(IRQ_PB1176_GIC_START + 2)	/* Multimedia Card 0A */
-#define IRQ_PB1176_KMI0		(IRQ_PB1176_GIC_START + 3)	/* Keyboard/Mouse port 0 */
-#define IRQ_PB1176_KMI1		(IRQ_PB1176_GIC_START + 4)	/* Keyboard/Mouse port 1 */
-#define IRQ_PB1176_SCI		(IRQ_PB1176_GIC_START + 5)
-#define IRQ_PB1176_UART4	(IRQ_PB1176_GIC_START + 6)	/* UART 4 on baseboard */
-#define IRQ_PB1176_CHARLCD	(IRQ_PB1176_GIC_START + 7)	/* Character LCD */
-#define IRQ_PB1176_GPIO1	(IRQ_PB1176_GIC_START + 8)
-#define IRQ_PB1176_GPIO2	(IRQ_PB1176_GIC_START + 9)
-#define IRQ_PB1176_ETH		(IRQ_PB1176_GIC_START + 10)	/* Ethernet controller */
-#define IRQ_PB1176_USB		(IRQ_PB1176_GIC_START + 11)	/* USB controller */
-
-#define IRQ_PB1176_PISMO	(IRQ_PB1176_GIC_START + 16)
-
-#define IRQ_PB1176_AACI		(IRQ_PB1176_GIC_START + 19)	/* Audio Codec */
-
-#define IRQ_PB1176_TIMER0_1	(IRQ_PB1176_GIC_START + 22)
-#define IRQ_PB1176_TIMER2_3	(IRQ_PB1176_GIC_START + 23)
-#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_SSP		-1
-#define IRQ_PB1176_SCTL		-1
-
-#define NR_GIC_PB1176		2
-
-/*
- * Only define NR_IRQS if less than NR_IRQS_PB1176
- */
-#define NR_IRQS_PB1176		(IRQ_DC1176_GIC_START + 96)
-
-#if defined(CONFIG_MACH_REALVIEW_PB1176)
-
-#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PB1176)
-#undef NR_IRQS
-#define NR_IRQS			NR_IRQS_PB1176
-#endif
-
-#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PB1176)
-#undef MAX_GIC_NR
-#define MAX_GIC_NR		NR_GIC_PB1176
-#endif
-
-#endif	/* CONFIG_MACH_REALVIEW_PB1176 */
-
 #endif	/* __ASM_ARCH_BOARD_PB1176_H */
diff --git a/arch/arm/mach-realview/include/mach/board-pb11mp.h b/arch/arm/mach-realview/include/mach/board-pb11mp.h
index 53ea0e7..f0d68e0 100644
--- a/arch/arm/mach-realview/include/mach/board-pb11mp.h
+++ b/arch/arm/mach-realview/include/mach/board-pb11mp.h
@@ -81,105 +81,4 @@
 #define REALVIEW_TC11MP_GIC_DIST_BASE		0x1F001000	/* Test chip interrupt controller distributor */
 #define REALVIEW_TC11MP_L220_BASE		0x1F002000	/* L220 registers */
 
-/*
- * Irqs
- */
-#define IRQ_TC11MP_GIC_START			32
-#define IRQ_PB11MP_GIC_START			64
-
-/*
- * ARM11MPCore test chip interrupt sources (primary GIC on the test chip)
- */
-#define IRQ_TC11MP_AACI		(IRQ_TC11MP_GIC_START + 0)
-#define IRQ_TC11MP_TIMER0_1	(IRQ_TC11MP_GIC_START + 1)
-#define IRQ_TC11MP_TIMER2_3	(IRQ_TC11MP_GIC_START + 2)
-#define IRQ_TC11MP_USB		(IRQ_TC11MP_GIC_START + 3)
-#define IRQ_TC11MP_UART0	(IRQ_TC11MP_GIC_START + 4)
-#define IRQ_TC11MP_UART1	(IRQ_TC11MP_GIC_START + 5)
-#define IRQ_TC11MP_RTC		(IRQ_TC11MP_GIC_START + 6)
-#define IRQ_TC11MP_KMI0		(IRQ_TC11MP_GIC_START + 7)
-#define IRQ_TC11MP_KMI1		(IRQ_TC11MP_GIC_START + 8)
-#define IRQ_TC11MP_ETH		(IRQ_TC11MP_GIC_START + 9)
-#define IRQ_TC11MP_PB_IRQ1	(IRQ_TC11MP_GIC_START + 10)		/* main GIC */
-#define IRQ_TC11MP_PB_IRQ2	(IRQ_TC11MP_GIC_START + 11)		/* tile GIC */
-#define IRQ_TC11MP_PB_FIQ1	(IRQ_TC11MP_GIC_START + 12)		/* main GIC */
-#define IRQ_TC11MP_PB_FIQ2	(IRQ_TC11MP_GIC_START + 13)		/* tile GIC */
-#define IRQ_TC11MP_MMCI0A	(IRQ_TC11MP_GIC_START + 14)
-#define IRQ_TC11MP_MMCI0B	(IRQ_TC11MP_GIC_START + 15)
-
-#define IRQ_TC11MP_PMU_CPU0	(IRQ_TC11MP_GIC_START + 17)
-#define IRQ_TC11MP_PMU_CPU1	(IRQ_TC11MP_GIC_START + 18)
-#define IRQ_TC11MP_PMU_CPU2	(IRQ_TC11MP_GIC_START + 19)
-#define IRQ_TC11MP_PMU_CPU3	(IRQ_TC11MP_GIC_START + 20)
-#define IRQ_TC11MP_PMU_SCU0	(IRQ_TC11MP_GIC_START + 21)
-#define IRQ_TC11MP_PMU_SCU1	(IRQ_TC11MP_GIC_START + 22)
-#define IRQ_TC11MP_PMU_SCU2	(IRQ_TC11MP_GIC_START + 23)
-#define IRQ_TC11MP_PMU_SCU3	(IRQ_TC11MP_GIC_START + 24)
-#define IRQ_TC11MP_PMU_SCU4	(IRQ_TC11MP_GIC_START + 25)
-#define IRQ_TC11MP_PMU_SCU5	(IRQ_TC11MP_GIC_START + 26)
-#define IRQ_TC11MP_PMU_SCU6	(IRQ_TC11MP_GIC_START + 27)
-#define IRQ_TC11MP_PMU_SCU7	(IRQ_TC11MP_GIC_START + 28)
-
-#define IRQ_TC11MP_L220_EVENT	(IRQ_TC11MP_GIC_START + 29)
-#define IRQ_TC11MP_L220_SLAVE	(IRQ_TC11MP_GIC_START + 30)
-#define IRQ_TC11MP_L220_DECODE	(IRQ_TC11MP_GIC_START + 31)
-
-/*
- * RealView PB11MPCore GIC interrupt sources (secondary GIC on the board)
- */
-#define IRQ_PB11MP_WATCHDOG	(IRQ_PB11MP_GIC_START + 0)	/* Watchdog timer */
-#define IRQ_PB11MP_SOFT		(IRQ_PB11MP_GIC_START + 1)	/* Software interrupt */
-#define IRQ_PB11MP_COMMRx	(IRQ_PB11MP_GIC_START + 2)	/* Debug Comm Rx interrupt */
-#define IRQ_PB11MP_COMMTx	(IRQ_PB11MP_GIC_START + 3)	/* Debug Comm Tx interrupt */
-#define IRQ_PB11MP_GPIO0	(IRQ_PB11MP_GIC_START + 6)	/* GPIO 0 */
-#define IRQ_PB11MP_GPIO1	(IRQ_PB11MP_GIC_START + 7)	/* GPIO 1 */
-#define IRQ_PB11MP_GPIO2	(IRQ_PB11MP_GIC_START + 8)	/* GPIO 2 */
-								/* 9 reserved */
-#define IRQ_PB11MP_RTC_GIC1	(IRQ_PB11MP_GIC_START + 10)	/* Real Time Clock */
-#define IRQ_PB11MP_SSP		(IRQ_PB11MP_GIC_START + 11)	/* Synchronous Serial Port */
-#define IRQ_PB11MP_UART0_GIC1	(IRQ_PB11MP_GIC_START + 12)	/* UART 0 on development chip */
-#define IRQ_PB11MP_UART1_GIC1	(IRQ_PB11MP_GIC_START + 13)	/* UART 1 on development chip */
-#define IRQ_PB11MP_UART2	(IRQ_PB11MP_GIC_START + 14)	/* UART 2 on development chip */
-#define IRQ_PB11MP_UART3	(IRQ_PB11MP_GIC_START + 15)	/* UART 3 on development chip */
-#define IRQ_PB11MP_SCI		(IRQ_PB11MP_GIC_START + 16)	/* Smart Card Interface */
-#define IRQ_PB11MP_MMCI0A_GIC1	(IRQ_PB11MP_GIC_START + 17)	/* Multimedia Card 0A */
-#define IRQ_PB11MP_MMCI0B_GIC1	(IRQ_PB11MP_GIC_START + 18)	/* Multimedia Card 0B */
-#define IRQ_PB11MP_AACI_GIC1	(IRQ_PB11MP_GIC_START + 19)	/* Audio Codec */
-#define IRQ_PB11MP_KMI0_GIC1	(IRQ_PB11MP_GIC_START + 20)	/* Keyboard/Mouse port 0 */
-#define IRQ_PB11MP_KMI1_GIC1	(IRQ_PB11MP_GIC_START + 21)	/* Keyboard/Mouse port 1 */
-#define IRQ_PB11MP_CHARLCD	(IRQ_PB11MP_GIC_START + 22)	/* Character LCD */
-#define IRQ_PB11MP_CLCD		(IRQ_PB11MP_GIC_START + 23)	/* CLCD controller */
-#define IRQ_PB11MP_DMAC		(IRQ_PB11MP_GIC_START + 24)	/* DMA controller */
-#define IRQ_PB11MP_PWRFAIL	(IRQ_PB11MP_GIC_START + 25)	/* Power failure */
-#define IRQ_PB11MP_PISMO	(IRQ_PB11MP_GIC_START + 26)	/* PISMO interface */
-#define IRQ_PB11MP_DoC		(IRQ_PB11MP_GIC_START + 27)	/* Disk on Chip memory controller */
-#define IRQ_PB11MP_ETH_GIC1	(IRQ_PB11MP_GIC_START + 28)	/* Ethernet controller */
-#define IRQ_PB11MP_USB_GIC1	(IRQ_PB11MP_GIC_START + 29)	/* USB controller */
-#define IRQ_PB11MP_TSPEN	(IRQ_PB11MP_GIC_START + 30)	/* Touchscreen pen */
-#define IRQ_PB11MP_TSKPAD	(IRQ_PB11MP_GIC_START + 31)	/* Touchscreen keypad */
-
-#define IRQ_PB11MP_SMC		-1
-#define IRQ_PB11MP_SCTL		-1
-
-#define NR_GIC_PB11MP		2
-
-/*
- * Only define NR_IRQS if less than NR_IRQS_PB11MP
- */
-#define NR_IRQS_PB11MP		(IRQ_TC11MP_GIC_START + 96)
-
-#if defined(CONFIG_MACH_REALVIEW_PB11MP)
-
-#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PB11MP)
-#undef NR_IRQS
-#define NR_IRQS			NR_IRQS_PB11MP
-#endif
-
-#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PB11MP)
-#undef MAX_GIC_NR
-#define MAX_GIC_NR		NR_GIC_PB11MP
-#endif
-
-#endif	/* CONFIG_MACH_REALVIEW_PB11MP */
-
 #endif	/* __ASM_ARCH_BOARD_PB11MP_H */
diff --git a/arch/arm/mach-realview/include/mach/board-pba8.h b/arch/arm/mach-realview/include/mach/board-pba8.h
index 307f97b..4dfc67a 100644
--- a/arch/arm/mach-realview/include/mach/board-pba8.h
+++ b/arch/arm/mach-realview/include/mach/board-pba8.h
@@ -70,81 +70,4 @@
 #define REALVIEW_PBA8_PCI_IO_SIZE		0x1000		/* 4 Kb */
 #define REALVIEW_PBA8_PCI_MEM_SIZE		0x20000000	/* 512 MB */
 
-/*
- * Irqs
- */
-#define IRQ_PBA8_GIC_START			32
-
-/* L220
-#define IRQ_PBA8_L220_EVENT	(IRQ_PBA8_GIC_START + 29)
-#define IRQ_PBA8_L220_SLAVE	(IRQ_PBA8_GIC_START + 30)
-#define IRQ_PBA8_L220_DECODE	(IRQ_PBA8_GIC_START + 31)
-*/
-
-/*
- * PB-A8 on-board gic irq sources
- */
-#define IRQ_PBA8_WATCHDOG	(IRQ_PBA8_GIC_START + 0)	/* Watchdog timer */
-#define IRQ_PBA8_SOFT		(IRQ_PBA8_GIC_START + 1)	/* Software interrupt */
-#define IRQ_PBA8_COMMRx		(IRQ_PBA8_GIC_START + 2)	/* Debug Comm Rx interrupt */
-#define IRQ_PBA8_COMMTx		(IRQ_PBA8_GIC_START + 3)	/* Debug Comm Tx interrupt */
-#define IRQ_PBA8_TIMER0_1	(IRQ_PBA8_GIC_START + 4)	/* Timer 0/1 (default timer) */
-#define IRQ_PBA8_TIMER2_3	(IRQ_PBA8_GIC_START + 5)	/* Timer 2/3 */
-#define IRQ_PBA8_GPIO0		(IRQ_PBA8_GIC_START + 6)	/* GPIO 0 */
-#define IRQ_PBA8_GPIO1		(IRQ_PBA8_GIC_START + 7)	/* GPIO 1 */
-#define IRQ_PBA8_GPIO2		(IRQ_PBA8_GIC_START + 8)	/* GPIO 2 */
-								/* 9 reserved */
-#define IRQ_PBA8_RTC		(IRQ_PBA8_GIC_START + 10)	/* Real Time Clock */
-#define IRQ_PBA8_SSP		(IRQ_PBA8_GIC_START + 11)	/* Synchronous Serial Port */
-#define IRQ_PBA8_UART0		(IRQ_PBA8_GIC_START + 12)	/* UART 0 on development chip */
-#define IRQ_PBA8_UART1		(IRQ_PBA8_GIC_START + 13)	/* UART 1 on development chip */
-#define IRQ_PBA8_UART2		(IRQ_PBA8_GIC_START + 14)	/* UART 2 on development chip */
-#define IRQ_PBA8_UART3		(IRQ_PBA8_GIC_START + 15)	/* UART 3 on development chip */
-#define IRQ_PBA8_SCI		(IRQ_PBA8_GIC_START + 16)	/* Smart Card Interface */
-#define IRQ_PBA8_MMCI0A		(IRQ_PBA8_GIC_START + 17)	/* Multimedia Card 0A */
-#define IRQ_PBA8_MMCI0B		(IRQ_PBA8_GIC_START + 18)	/* Multimedia Card 0B */
-#define IRQ_PBA8_AACI		(IRQ_PBA8_GIC_START + 19)	/* Audio Codec */
-#define IRQ_PBA8_KMI0		(IRQ_PBA8_GIC_START + 20)	/* Keyboard/Mouse port 0 */
-#define IRQ_PBA8_KMI1		(IRQ_PBA8_GIC_START + 21)	/* Keyboard/Mouse port 1 */
-#define IRQ_PBA8_CHARLCD	(IRQ_PBA8_GIC_START + 22)	/* Character LCD */
-#define IRQ_PBA8_CLCD		(IRQ_PBA8_GIC_START + 23)	/* CLCD controller */
-#define IRQ_PBA8_DMAC		(IRQ_PBA8_GIC_START + 24)	/* DMA controller */
-#define IRQ_PBA8_PWRFAIL	(IRQ_PBA8_GIC_START + 25)	/* Power failure */
-#define IRQ_PBA8_PISMO		(IRQ_PBA8_GIC_START + 26)	/* PISMO interface */
-#define IRQ_PBA8_DoC		(IRQ_PBA8_GIC_START + 27)	/* Disk on Chip memory controller */
-#define IRQ_PBA8_ETH		(IRQ_PBA8_GIC_START + 28)	/* Ethernet controller */
-#define IRQ_PBA8_USB		(IRQ_PBA8_GIC_START + 29)	/* USB controller */
-#define IRQ_PBA8_TSPEN		(IRQ_PBA8_GIC_START + 30)	/* Touchscreen pen */
-#define IRQ_PBA8_TSKPAD		(IRQ_PBA8_GIC_START + 31)	/* Touchscreen keypad */
-
-/* ... */
-#define IRQ_PBA8_PCI0		(IRQ_PBA8_GIC_START + 50)
-#define IRQ_PBA8_PCI1		(IRQ_PBA8_GIC_START + 51)
-#define IRQ_PBA8_PCI2		(IRQ_PBA8_GIC_START + 52)
-#define IRQ_PBA8_PCI3		(IRQ_PBA8_GIC_START + 53)
-
-#define IRQ_PBA8_SMC		-1
-#define IRQ_PBA8_SCTL		-1
-
-#define NR_GIC_PBA8		1
-
-/*
- * Only define NR_IRQS if less than NR_IRQS_PBA8
- */
-#define NR_IRQS_PBA8		(IRQ_PBA8_GIC_START + 64)
-
-#if defined(CONFIG_MACH_REALVIEW_PBA8)
-
-#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PBA8)
-#undef NR_IRQS
-#define NR_IRQS			NR_IRQS_PBA8
-#endif
-
-#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PBA8)
-#undef MAX_GIC_NR
-#define MAX_GIC_NR		NR_GIC_PBA8
-#endif
-
-#endif	/* CONFIG_MACH_REALVIEW_PBA8 */
-
 #endif	/* __ASM_ARCH_BOARD_PBA8_H */
diff --git a/arch/arm/mach-realview/include/mach/board-pbx.h b/arch/arm/mach-realview/include/mach/board-pbx.h
new file mode 100644
index 0000000..848bfff
--- /dev/null
+++ b/arch/arm/mach-realview/include/mach/board-pbx.h
@@ -0,0 +1,108 @@
+/*
+ * arch/arm/mach-realview/include/mach/board-pbx.h
+ *
+ * Copyright (C) 2009 ARM Limited
+ *
+ * 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_BOARD_PBX_H
+#define __ASM_ARCH_BOARD_PBX_H
+
+#include <mach/platform.h>
+
+/*
+ * Peripheral addresses
+ */
+#define REALVIEW_PBX_UART0_BASE			0x10009000	/* UART 0 */
+#define REALVIEW_PBX_UART1_BASE			0x1000A000	/* UART 1 */
+#define REALVIEW_PBX_UART2_BASE			0x1000B000	/* UART 2 */
+#define REALVIEW_PBX_UART3_BASE			0x1000C000	/* UART 3 */
+#define REALVIEW_PBX_SSP_BASE			0x1000D000	/* Synchronous Serial Port */
+#define REALVIEW_PBX_WATCHDOG0_BASE		0x1000F000	/* Watchdog 0 */
+#define REALVIEW_PBX_WATCHDOG_BASE		0x10010000	/* watchdog interface */
+#define REALVIEW_PBX_TIMER0_1_BASE		0x10011000	/* Timer 0 and 1 */
+#define REALVIEW_PBX_TIMER2_3_BASE		0x10012000	/* Timer 2 and 3 */
+#define REALVIEW_PBX_GPIO0_BASE			0x10013000	/* GPIO port 0 */
+#define REALVIEW_PBX_RTC_BASE			0x10017000	/* Real Time Clock */
+#define REALVIEW_PBX_TIMER4_5_BASE		0x10018000	/* Timer 4/5 */
+#define REALVIEW_PBX_TIMER6_7_BASE		0x10019000	/* Timer 6/7 */
+#define REALVIEW_PBX_SCTL_BASE			0x1001A000	/* System Controller */
+#define REALVIEW_PBX_CLCD_BASE			0x10020000	/* CLCD */
+#define REALVIEW_PBX_ONB_SRAM_BASE		0x10060000	/* On-board SRAM */
+#define REALVIEW_PBX_DMC_BASE			0x100E0000	/* DMC configuration */
+#define REALVIEW_PBX_SMC_BASE			0x100E1000	/* SMC configuration */
+#define REALVIEW_PBX_CAN_BASE			0x100E2000	/* CAN bus */
+#define REALVIEW_PBX_GIC_CPU_BASE		0x1E000000	/* Generic interrupt controller CPU interface */
+#define REALVIEW_PBX_FLASH0_BASE		0x40000000
+#define REALVIEW_PBX_FLASH0_SIZE		SZ_64M
+#define REALVIEW_PBX_FLASH1_BASE		0x44000000
+#define REALVIEW_PBX_FLASH1_SIZE		SZ_64M
+#define REALVIEW_PBX_ETH_BASE			0x4E000000	/* Ethernet */
+#define REALVIEW_PBX_USB_BASE			0x4F000000	/* USB */
+#define REALVIEW_PBX_GIC_DIST_BASE		0x1E001000	/* Generic interrupt controller distributor */
+#define REALVIEW_PBX_LT_BASE			0xC0000000	/* Logic Tile expansion */
+#define REALVIEW_PBX_SDRAM6_BASE		0x70000000	/* SDRAM bank 6 256MB */
+#define REALVIEW_PBX_SDRAM7_BASE		0x80000000	/* SDRAM bank 7 256MB */
+
+/*
+ * Tile-specific addresses
+ */
+#define REALVIEW_PBX_TILE_SCU_BASE		0x1F000000      /* SCU registers */
+#define REALVIEW_PBX_TILE_GIC_CPU_BASE		0x1F000100      /* Private Generic interrupt controller CPU interface */
+#define REALVIEW_PBX_TILE_TWD_BASE		0x1F000600
+#define REALVIEW_PBX_TILE_TWD_PERCPU_BASE	0x1F000700
+#define REALVIEW_PBX_TILE_TWD_SIZE		0x00000100
+#define REALVIEW_PBX_TILE_GIC_DIST_BASE		0x1F001000      /* Private Generic interrupt controller distributor */
+#define REALVIEW_PBX_TILE_L220_BASE		0x1F002000      /* L220 registers */
+
+#define REALVIEW_PBX_SYS_PLD_CTRL1		0x74
+
+/*
+ * PBX PCI regions
+ */
+#define REALVIEW_PBX_PCI_BASE			0x90040000	/* PCI-X Unit base */
+#define REALVIEW_PBX_PCI_IO_BASE		0x90050000	/* IO Region on AHB */
+#define REALVIEW_PBX_PCI_MEM_BASE		0xA0000000	/* MEM Region on AHB */
+
+#define REALVIEW_PBX_PCI_BASE_SIZE		0x10000		/* 16 Kb */
+#define REALVIEW_PBX_PCI_IO_SIZE		0x1000		/* 4 Kb */
+#define REALVIEW_PBX_PCI_MEM_SIZE		0x20000000	/* 512 MB */
+
+/*
+ * Core tile identification (REALVIEW_SYS_PROCID)
+ */
+#define REALVIEW_PBX_PROC_MASK          0xFF000000
+#define REALVIEW_PBX_PROC_ARM7TDMI      0x00000000
+#define REALVIEW_PBX_PROC_ARM9          0x02000000
+#define REALVIEW_PBX_PROC_ARM11         0x04000000
+#define REALVIEW_PBX_PROC_ARM11MP       0x06000000
+#define REALVIEW_PBX_PROC_A9MP          0x0C000000
+#define REALVIEW_PBX_PROC_A8            0x0E000000
+
+#define check_pbx_proc(proc_type)                                            \
+	((readl(__io_address(REALVIEW_SYS_PROCID)) & REALVIEW_PBX_PROC_MASK) \
+	== proc_type)
+
+#ifdef CONFIG_MACH_REALVIEW_PBX
+#define core_tile_pbx11mp()     check_pbx_proc(REALVIEW_PBX_PROC_ARM11MP)
+#define core_tile_pbxa9mp()     check_pbx_proc(REALVIEW_PBX_PROC_A9MP)
+#define core_tile_pbxa8()       check_pbx_proc(REALVIEW_PBX_PROC_A8)
+#else
+#define core_tile_pbx11mp()     0
+#define core_tile_pbxa9mp()     0
+#define core_tile_pbxa8()       0
+#endif
+
+#endif	/* __ASM_ARCH_BOARD_PBX_H */
diff --git a/arch/arm/mach-realview/include/mach/debug-macro.S b/arch/arm/mach-realview/include/mach/debug-macro.S
index 92dbcb9..932d8af 100644
--- a/arch/arm/mach-realview/include/mach/debug-macro.S
+++ b/arch/arm/mach-realview/include/mach/debug-macro.S
@@ -12,7 +12,8 @@
 
 #if defined(CONFIG_MACH_REALVIEW_EB) || \
     defined(CONFIG_MACH_REALVIEW_PB11MP) || \
-    defined(CONFIG_MACH_REALVIEW_PBA8)
+    defined(CONFIG_MACH_REALVIEW_PBA8) || \
+    defined(CONFIG_MACH_REALVIEW_PBX)
 #ifndef DEBUG_LL_UART_OFFSET
 #define DEBUG_LL_UART_OFFSET	0x00009000
 #elif DEBUG_LL_UART_OFFSET != 0x00009000
diff --git a/arch/arm/mach-realview/include/mach/irqs-eb.h b/arch/arm/mach-realview/include/mach/irqs-eb.h
new file mode 100644
index 0000000..204d537
--- /dev/null
+++ b/arch/arm/mach-realview/include/mach/irqs-eb.h
@@ -0,0 +1,129 @@
+/*
+ * arch/arm/mach-realview/include/mach/irqs-eb.h
+ *
+ * Copyright (C) 2007 ARM Limited
+ *
+ * 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 Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef __MACH_IRQS_EB_H
+#define __MACH_IRQS_EB_H
+
+#define IRQ_EB_GIC_START	32
+
+/*
+ * RealView EB interrupt sources
+ */
+#define IRQ_EB_WDOG		(IRQ_EB_GIC_START + 0)		/* Watchdog timer */
+#define IRQ_EB_SOFT		(IRQ_EB_GIC_START + 1)		/* Software interrupt */
+#define IRQ_EB_COMMRx		(IRQ_EB_GIC_START + 2)		/* Debug Comm Rx interrupt */
+#define IRQ_EB_COMMTx		(IRQ_EB_GIC_START + 3)		/* Debug Comm Tx interrupt */
+#define IRQ_EB_TIMER0_1		(IRQ_EB_GIC_START + 4)		/* Timer 0 and 1 */
+#define IRQ_EB_TIMER2_3		(IRQ_EB_GIC_START + 5)		/* Timer 2 and 3 */
+#define IRQ_EB_GPIO0		(IRQ_EB_GIC_START + 6)		/* GPIO 0 */
+#define IRQ_EB_GPIO1		(IRQ_EB_GIC_START + 7)		/* GPIO 1 */
+#define IRQ_EB_GPIO2		(IRQ_EB_GIC_START + 8)		/* GPIO 2 */
+								/* 9 reserved */
+#define IRQ_EB_RTC		(IRQ_EB_GIC_START + 10)		/* Real Time Clock */
+#define IRQ_EB_SSP		(IRQ_EB_GIC_START + 11)		/* Synchronous Serial Port */
+#define IRQ_EB_UART0		(IRQ_EB_GIC_START + 12)		/* UART 0 on development chip */
+#define IRQ_EB_UART1		(IRQ_EB_GIC_START + 13)		/* UART 1 on development chip */
+#define IRQ_EB_UART2		(IRQ_EB_GIC_START + 14)		/* UART 2 on development chip */
+#define IRQ_EB_UART3		(IRQ_EB_GIC_START + 15)		/* UART 3 on development chip */
+#define IRQ_EB_SCI		(IRQ_EB_GIC_START + 16)		/* Smart Card Interface */
+#define IRQ_EB_MMCI0A		(IRQ_EB_GIC_START + 17)		/* Multimedia Card 0A */
+#define IRQ_EB_MMCI0B		(IRQ_EB_GIC_START + 18)		/* Multimedia Card 0B */
+#define IRQ_EB_AACI		(IRQ_EB_GIC_START + 19)		/* Audio Codec */
+#define IRQ_EB_KMI0		(IRQ_EB_GIC_START + 20)		/* Keyboard/Mouse port 0 */
+#define IRQ_EB_KMI1		(IRQ_EB_GIC_START + 21)		/* Keyboard/Mouse port 1 */
+#define IRQ_EB_CHARLCD		(IRQ_EB_GIC_START + 22)		/* Character LCD */
+#define IRQ_EB_CLCD		(IRQ_EB_GIC_START + 23)		/* CLCD controller */
+#define IRQ_EB_DMA		(IRQ_EB_GIC_START + 24)		/* DMA controller */
+#define IRQ_EB_PWRFAIL		(IRQ_EB_GIC_START + 25)		/* Power failure */
+#define IRQ_EB_PISMO		(IRQ_EB_GIC_START + 26)		/* PISMO interface */
+#define IRQ_EB_DoC		(IRQ_EB_GIC_START + 27)		/* Disk on Chip memory controller */
+#define IRQ_EB_ETH		(IRQ_EB_GIC_START + 28)		/* Ethernet controller */
+#define IRQ_EB_USB		(IRQ_EB_GIC_START + 29)		/* USB controller */
+#define IRQ_EB_TSPEN		(IRQ_EB_GIC_START + 30)		/* Touchscreen pen */
+#define IRQ_EB_TSKPAD		(IRQ_EB_GIC_START + 31)		/* Touchscreen keypad */
+
+/*
+ * RealView EB + ARM11MPCore interrupt sources (primary GIC on the core tile)
+ */
+#define IRQ_EB11MP_AACI		(IRQ_EB_GIC_START + 0)
+#define IRQ_EB11MP_TIMER0_1	(IRQ_EB_GIC_START + 1)
+#define IRQ_EB11MP_TIMER2_3	(IRQ_EB_GIC_START + 2)
+#define IRQ_EB11MP_USB		(IRQ_EB_GIC_START + 3)
+#define IRQ_EB11MP_UART0	(IRQ_EB_GIC_START + 4)
+#define IRQ_EB11MP_UART1	(IRQ_EB_GIC_START + 5)
+#define IRQ_EB11MP_RTC		(IRQ_EB_GIC_START + 6)
+#define IRQ_EB11MP_KMI0		(IRQ_EB_GIC_START + 7)
+#define IRQ_EB11MP_KMI1		(IRQ_EB_GIC_START + 8)
+#define IRQ_EB11MP_ETH		(IRQ_EB_GIC_START + 9)
+#define IRQ_EB11MP_EB_IRQ1	(IRQ_EB_GIC_START + 10)		/* main GIC */
+#define IRQ_EB11MP_EB_IRQ2	(IRQ_EB_GIC_START + 11)		/* tile GIC */
+#define IRQ_EB11MP_EB_FIQ1	(IRQ_EB_GIC_START + 12)		/* main GIC */
+#define IRQ_EB11MP_EB_FIQ2	(IRQ_EB_GIC_START + 13)		/* tile GIC */
+#define IRQ_EB11MP_MMCI0A	(IRQ_EB_GIC_START + 14)
+#define IRQ_EB11MP_MMCI0B	(IRQ_EB_GIC_START + 15)
+
+#define IRQ_EB11MP_PMU_CPU0	(IRQ_EB_GIC_START + 17)
+#define IRQ_EB11MP_PMU_CPU1	(IRQ_EB_GIC_START + 18)
+#define IRQ_EB11MP_PMU_CPU2	(IRQ_EB_GIC_START + 19)
+#define IRQ_EB11MP_PMU_CPU3	(IRQ_EB_GIC_START + 20)
+#define IRQ_EB11MP_PMU_SCU0	(IRQ_EB_GIC_START + 21)
+#define IRQ_EB11MP_PMU_SCU1	(IRQ_EB_GIC_START + 22)
+#define IRQ_EB11MP_PMU_SCU2	(IRQ_EB_GIC_START + 23)
+#define IRQ_EB11MP_PMU_SCU3	(IRQ_EB_GIC_START + 24)
+#define IRQ_EB11MP_PMU_SCU4	(IRQ_EB_GIC_START + 25)
+#define IRQ_EB11MP_PMU_SCU5	(IRQ_EB_GIC_START + 26)
+#define IRQ_EB11MP_PMU_SCU6	(IRQ_EB_GIC_START + 27)
+#define IRQ_EB11MP_PMU_SCU7	(IRQ_EB_GIC_START + 28)
+
+#define IRQ_EB11MP_L220_EVENT	(IRQ_EB_GIC_START + 29)
+#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
+
+#define NR_GIC_EB11MP		2
+
+/*
+ * Only define NR_IRQS if less than NR_IRQS_EB
+ */
+#define NR_IRQS_EB		(IRQ_EB_GIC_START + 96)
+
+#if defined(CONFIG_MACH_REALVIEW_EB) \
+	&& (!defined(NR_IRQS) || (NR_IRQS < NR_IRQS_EB))
+#undef NR_IRQS
+#define NR_IRQS			NR_IRQS_EB
+#endif
+
+#if defined(CONFIG_REALVIEW_EB_ARM11MP) || defined(CONFIG_REALVIEW_EB_A9MP) \
+	&& (!defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_EB11MP))
+#undef MAX_GIC_NR
+#define MAX_GIC_NR		NR_GIC_EB11MP
+#endif
+
+#endif	/* __MACH_IRQS_EB_H */
diff --git a/arch/arm/mach-realview/include/mach/irqs-pb1176.h b/arch/arm/mach-realview/include/mach/irqs-pb1176.h
new file mode 100644
index 0000000..2410d4f
--- /dev/null
+++ b/arch/arm/mach-realview/include/mach/irqs-pb1176.h
@@ -0,0 +1,99 @@
+/*
+ * arch/arm/mach-realview/include/mach/irqs-pb1176.h
+ *
+ * Copyright (C) 2008 ARM Limited
+ *
+ * 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 Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef __MACH_IRQS_PB1176_H
+#define __MACH_IRQS_PB1176_H
+
+#define IRQ_DC1176_GIC_START			32
+#define IRQ_PB1176_GIC_START			64
+
+/*
+ * ARM1176 DevChip interrupt sources (primary GIC)
+ */
+#define IRQ_DC1176_WATCHDOG	(IRQ_DC1176_GIC_START + 0)	/* Watchdog timer */
+#define IRQ_DC1176_SOFTINT	(IRQ_DC1176_GIC_START + 1)	/* Software interrupt */
+#define IRQ_DC1176_COMMRx	(IRQ_DC1176_GIC_START + 2)	/* Debug Comm Rx interrupt */
+#define IRQ_DC1176_COMMTx	(IRQ_DC1176_GIC_START + 3)	/* Debug Comm Tx interrupt */
+#define IRQ_DC1176_TIMER0	(IRQ_DC1176_GIC_START + 8)	/* Timer 0 */
+#define IRQ_DC1176_TIMER1	(IRQ_DC1176_GIC_START + 9)	/* Timer 1 */
+#define IRQ_DC1176_TIMER2	(IRQ_DC1176_GIC_START + 10)	/* Timer 2 */
+#define IRQ_DC1176_APC		(IRQ_DC1176_GIC_START + 11)
+#define IRQ_DC1176_IEC		(IRQ_DC1176_GIC_START + 12)
+#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_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 */
+#define IRQ_DC1176_UART2	(IRQ_DC1176_GIC_START + 20)	/* UART 2 on development chip */
+#define IRQ_DC1176_UART3	(IRQ_DC1176_GIC_START + 21)	/* UART 3 on development chip */
+
+#define IRQ_DC1176_PB_IRQ2	(IRQ_DC1176_GIC_START + 30)	/* tile GIC */
+#define IRQ_DC1176_PB_IRQ1	(IRQ_DC1176_GIC_START + 31)	/* main GIC */
+
+/*
+ * RealView PB1176 interrupt sources (secondary GIC)
+ */
+#define IRQ_PB1176_MMCI0A	(IRQ_PB1176_GIC_START + 1)	/* Multimedia Card 0A */
+#define IRQ_PB1176_MMCI0B	(IRQ_PB1176_GIC_START + 2)	/* Multimedia Card 0A */
+#define IRQ_PB1176_KMI0		(IRQ_PB1176_GIC_START + 3)	/* Keyboard/Mouse port 0 */
+#define IRQ_PB1176_KMI1		(IRQ_PB1176_GIC_START + 4)	/* Keyboard/Mouse port 1 */
+#define IRQ_PB1176_SCI		(IRQ_PB1176_GIC_START + 5)
+#define IRQ_PB1176_UART4	(IRQ_PB1176_GIC_START + 6)	/* UART 4 on baseboard */
+#define IRQ_PB1176_CHARLCD	(IRQ_PB1176_GIC_START + 7)	/* Character LCD */
+#define IRQ_PB1176_GPIO1	(IRQ_PB1176_GIC_START + 8)
+#define IRQ_PB1176_GPIO2	(IRQ_PB1176_GIC_START + 9)
+#define IRQ_PB1176_ETH		(IRQ_PB1176_GIC_START + 10)	/* Ethernet controller */
+#define IRQ_PB1176_USB		(IRQ_PB1176_GIC_START + 11)	/* USB controller */
+
+#define IRQ_PB1176_PISMO	(IRQ_PB1176_GIC_START + 16)
+
+#define IRQ_PB1176_AACI		(IRQ_PB1176_GIC_START + 19)	/* Audio Codec */
+
+#define IRQ_PB1176_TIMER0_1	(IRQ_PB1176_GIC_START + 22)
+#define IRQ_PB1176_TIMER2_3	(IRQ_PB1176_GIC_START + 23)
+#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_SSP		-1
+#define IRQ_PB1176_SCTL		-1
+
+#define NR_GIC_PB1176		2
+
+/*
+ * Only define NR_IRQS if less than NR_IRQS_PB1176
+ */
+#define NR_IRQS_PB1176		(IRQ_DC1176_GIC_START + 96)
+
+#if defined(CONFIG_MACH_REALVIEW_PB1176)
+
+#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PB1176)
+#undef NR_IRQS
+#define NR_IRQS			NR_IRQS_PB1176
+#endif
+
+#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PB1176)
+#undef MAX_GIC_NR
+#define MAX_GIC_NR		NR_GIC_PB1176
+#endif
+
+#endif	/* CONFIG_MACH_REALVIEW_PB1176 */
+
+#endif	/* __MACH_IRQS_PB1176_H */
diff --git a/arch/arm/mach-realview/include/mach/irqs-pb11mp.h b/arch/arm/mach-realview/include/mach/irqs-pb11mp.h
new file mode 100644
index 0000000..34e255a
--- /dev/null
+++ b/arch/arm/mach-realview/include/mach/irqs-pb11mp.h
@@ -0,0 +1,122 @@
+/*
+ * arch/arm/mach-realview/include/mach/irqs-pb11mp.h
+ *
+ * Copyright (C) 2008 ARM Limited
+ *
+ * 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 Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef __MACH_IRQS_PB11MP_H
+#define __MACH_IRQS_PB11MP_H
+
+#define IRQ_TC11MP_GIC_START			32
+#define IRQ_PB11MP_GIC_START			64
+
+/*
+ * ARM11MPCore test chip interrupt sources (primary GIC on the test chip)
+ */
+#define IRQ_TC11MP_AACI		(IRQ_TC11MP_GIC_START + 0)
+#define IRQ_TC11MP_TIMER0_1	(IRQ_TC11MP_GIC_START + 1)
+#define IRQ_TC11MP_TIMER2_3	(IRQ_TC11MP_GIC_START + 2)
+#define IRQ_TC11MP_USB		(IRQ_TC11MP_GIC_START + 3)
+#define IRQ_TC11MP_UART0	(IRQ_TC11MP_GIC_START + 4)
+#define IRQ_TC11MP_UART1	(IRQ_TC11MP_GIC_START + 5)
+#define IRQ_TC11MP_RTC		(IRQ_TC11MP_GIC_START + 6)
+#define IRQ_TC11MP_KMI0		(IRQ_TC11MP_GIC_START + 7)
+#define IRQ_TC11MP_KMI1		(IRQ_TC11MP_GIC_START + 8)
+#define IRQ_TC11MP_ETH		(IRQ_TC11MP_GIC_START + 9)
+#define IRQ_TC11MP_PB_IRQ1	(IRQ_TC11MP_GIC_START + 10)		/* main GIC */
+#define IRQ_TC11MP_PB_IRQ2	(IRQ_TC11MP_GIC_START + 11)		/* tile GIC */
+#define IRQ_TC11MP_PB_FIQ1	(IRQ_TC11MP_GIC_START + 12)		/* main GIC */
+#define IRQ_TC11MP_PB_FIQ2	(IRQ_TC11MP_GIC_START + 13)		/* tile GIC */
+#define IRQ_TC11MP_MMCI0A	(IRQ_TC11MP_GIC_START + 14)
+#define IRQ_TC11MP_MMCI0B	(IRQ_TC11MP_GIC_START + 15)
+
+#define IRQ_TC11MP_PMU_CPU0	(IRQ_TC11MP_GIC_START + 17)
+#define IRQ_TC11MP_PMU_CPU1	(IRQ_TC11MP_GIC_START + 18)
+#define IRQ_TC11MP_PMU_CPU2	(IRQ_TC11MP_GIC_START + 19)
+#define IRQ_TC11MP_PMU_CPU3	(IRQ_TC11MP_GIC_START + 20)
+#define IRQ_TC11MP_PMU_SCU0	(IRQ_TC11MP_GIC_START + 21)
+#define IRQ_TC11MP_PMU_SCU1	(IRQ_TC11MP_GIC_START + 22)
+#define IRQ_TC11MP_PMU_SCU2	(IRQ_TC11MP_GIC_START + 23)
+#define IRQ_TC11MP_PMU_SCU3	(IRQ_TC11MP_GIC_START + 24)
+#define IRQ_TC11MP_PMU_SCU4	(IRQ_TC11MP_GIC_START + 25)
+#define IRQ_TC11MP_PMU_SCU5	(IRQ_TC11MP_GIC_START + 26)
+#define IRQ_TC11MP_PMU_SCU6	(IRQ_TC11MP_GIC_START + 27)
+#define IRQ_TC11MP_PMU_SCU7	(IRQ_TC11MP_GIC_START + 28)
+
+#define IRQ_TC11MP_L220_EVENT	(IRQ_TC11MP_GIC_START + 29)
+#define IRQ_TC11MP_L220_SLAVE	(IRQ_TC11MP_GIC_START + 30)
+#define IRQ_TC11MP_L220_DECODE	(IRQ_TC11MP_GIC_START + 31)
+
+/*
+ * RealView PB11MPCore GIC interrupt sources (secondary GIC on the board)
+ */
+#define IRQ_PB11MP_WATCHDOG	(IRQ_PB11MP_GIC_START + 0)	/* Watchdog timer */
+#define IRQ_PB11MP_SOFT		(IRQ_PB11MP_GIC_START + 1)	/* Software interrupt */
+#define IRQ_PB11MP_COMMRx	(IRQ_PB11MP_GIC_START + 2)	/* Debug Comm Rx interrupt */
+#define IRQ_PB11MP_COMMTx	(IRQ_PB11MP_GIC_START + 3)	/* Debug Comm Tx interrupt */
+#define IRQ_PB11MP_GPIO0	(IRQ_PB11MP_GIC_START + 6)	/* GPIO 0 */
+#define IRQ_PB11MP_GPIO1	(IRQ_PB11MP_GIC_START + 7)	/* GPIO 1 */
+#define IRQ_PB11MP_GPIO2	(IRQ_PB11MP_GIC_START + 8)	/* GPIO 2 */
+								/* 9 reserved */
+#define IRQ_PB11MP_RTC_GIC1	(IRQ_PB11MP_GIC_START + 10)	/* Real Time Clock */
+#define IRQ_PB11MP_SSP		(IRQ_PB11MP_GIC_START + 11)	/* Synchronous Serial Port */
+#define IRQ_PB11MP_UART0_GIC1	(IRQ_PB11MP_GIC_START + 12)	/* UART 0 on development chip */
+#define IRQ_PB11MP_UART1_GIC1	(IRQ_PB11MP_GIC_START + 13)	/* UART 1 on development chip */
+#define IRQ_PB11MP_UART2	(IRQ_PB11MP_GIC_START + 14)	/* UART 2 on development chip */
+#define IRQ_PB11MP_UART3	(IRQ_PB11MP_GIC_START + 15)	/* UART 3 on development chip */
+#define IRQ_PB11MP_SCI		(IRQ_PB11MP_GIC_START + 16)	/* Smart Card Interface */
+#define IRQ_PB11MP_MMCI0A_GIC1	(IRQ_PB11MP_GIC_START + 17)	/* Multimedia Card 0A */
+#define IRQ_PB11MP_MMCI0B_GIC1	(IRQ_PB11MP_GIC_START + 18)	/* Multimedia Card 0B */
+#define IRQ_PB11MP_AACI_GIC1	(IRQ_PB11MP_GIC_START + 19)	/* Audio Codec */
+#define IRQ_PB11MP_KMI0_GIC1	(IRQ_PB11MP_GIC_START + 20)	/* Keyboard/Mouse port 0 */
+#define IRQ_PB11MP_KMI1_GIC1	(IRQ_PB11MP_GIC_START + 21)	/* Keyboard/Mouse port 1 */
+#define IRQ_PB11MP_CHARLCD	(IRQ_PB11MP_GIC_START + 22)	/* Character LCD */
+#define IRQ_PB11MP_CLCD		(IRQ_PB11MP_GIC_START + 23)	/* CLCD controller */
+#define IRQ_PB11MP_DMAC		(IRQ_PB11MP_GIC_START + 24)	/* DMA controller */
+#define IRQ_PB11MP_PWRFAIL	(IRQ_PB11MP_GIC_START + 25)	/* Power failure */
+#define IRQ_PB11MP_PISMO	(IRQ_PB11MP_GIC_START + 26)	/* PISMO interface */
+#define IRQ_PB11MP_DoC		(IRQ_PB11MP_GIC_START + 27)	/* Disk on Chip memory controller */
+#define IRQ_PB11MP_ETH_GIC1	(IRQ_PB11MP_GIC_START + 28)	/* Ethernet controller */
+#define IRQ_PB11MP_USB_GIC1	(IRQ_PB11MP_GIC_START + 29)	/* USB controller */
+#define IRQ_PB11MP_TSPEN	(IRQ_PB11MP_GIC_START + 30)	/* Touchscreen pen */
+#define IRQ_PB11MP_TSKPAD	(IRQ_PB11MP_GIC_START + 31)	/* Touchscreen keypad */
+
+#define IRQ_PB11MP_SMC		-1
+#define IRQ_PB11MP_SCTL		-1
+
+#define NR_GIC_PB11MP		2
+
+/*
+ * Only define NR_IRQS if less than NR_IRQS_PB11MP
+ */
+#define NR_IRQS_PB11MP		(IRQ_TC11MP_GIC_START + 96)
+
+#if defined(CONFIG_MACH_REALVIEW_PB11MP)
+
+#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PB11MP)
+#undef NR_IRQS
+#define NR_IRQS			NR_IRQS_PB11MP
+#endif
+
+#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PB11MP)
+#undef MAX_GIC_NR
+#define MAX_GIC_NR		NR_GIC_PB11MP
+#endif
+
+#endif	/* CONFIG_MACH_REALVIEW_PB11MP */
+
+#endif	/* __MACH_IRQS_PB11MP_H */
diff --git a/arch/arm/mach-realview/include/mach/irqs-pba8.h b/arch/arm/mach-realview/include/mach/irqs-pba8.h
new file mode 100644
index 0000000..86792a9
--- /dev/null
+++ b/arch/arm/mach-realview/include/mach/irqs-pba8.h
@@ -0,0 +1,98 @@
+/*
+ * arch/arm/mach-realview/include/mach/irqs-pba8.h
+ *
+ * Copyright (C) 2008 ARM Limited
+ *
+ * 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 Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef __MACH_IRQS_PBA8_H
+#define __MACH_IRQS_PBA8_H
+
+#define IRQ_PBA8_GIC_START			32
+
+/* L220
+#define IRQ_PBA8_L220_EVENT	(IRQ_PBA8_GIC_START + 29)
+#define IRQ_PBA8_L220_SLAVE	(IRQ_PBA8_GIC_START + 30)
+#define IRQ_PBA8_L220_DECODE	(IRQ_PBA8_GIC_START + 31)
+*/
+
+/*
+ * PB-A8 on-board gic irq sources
+ */
+#define IRQ_PBA8_WATCHDOG	(IRQ_PBA8_GIC_START + 0)	/* Watchdog timer */
+#define IRQ_PBA8_SOFT		(IRQ_PBA8_GIC_START + 1)	/* Software interrupt */
+#define IRQ_PBA8_COMMRx		(IRQ_PBA8_GIC_START + 2)	/* Debug Comm Rx interrupt */
+#define IRQ_PBA8_COMMTx		(IRQ_PBA8_GIC_START + 3)	/* Debug Comm Tx interrupt */
+#define IRQ_PBA8_TIMER0_1	(IRQ_PBA8_GIC_START + 4)	/* Timer 0/1 (default timer) */
+#define IRQ_PBA8_TIMER2_3	(IRQ_PBA8_GIC_START + 5)	/* Timer 2/3 */
+#define IRQ_PBA8_GPIO0		(IRQ_PBA8_GIC_START + 6)	/* GPIO 0 */
+#define IRQ_PBA8_GPIO1		(IRQ_PBA8_GIC_START + 7)	/* GPIO 1 */
+#define IRQ_PBA8_GPIO2		(IRQ_PBA8_GIC_START + 8)	/* GPIO 2 */
+								/* 9 reserved */
+#define IRQ_PBA8_RTC		(IRQ_PBA8_GIC_START + 10)	/* Real Time Clock */
+#define IRQ_PBA8_SSP		(IRQ_PBA8_GIC_START + 11)	/* Synchronous Serial Port */
+#define IRQ_PBA8_UART0		(IRQ_PBA8_GIC_START + 12)	/* UART 0 on development chip */
+#define IRQ_PBA8_UART1		(IRQ_PBA8_GIC_START + 13)	/* UART 1 on development chip */
+#define IRQ_PBA8_UART2		(IRQ_PBA8_GIC_START + 14)	/* UART 2 on development chip */
+#define IRQ_PBA8_UART3		(IRQ_PBA8_GIC_START + 15)	/* UART 3 on development chip */
+#define IRQ_PBA8_SCI		(IRQ_PBA8_GIC_START + 16)	/* Smart Card Interface */
+#define IRQ_PBA8_MMCI0A		(IRQ_PBA8_GIC_START + 17)	/* Multimedia Card 0A */
+#define IRQ_PBA8_MMCI0B		(IRQ_PBA8_GIC_START + 18)	/* Multimedia Card 0B */
+#define IRQ_PBA8_AACI		(IRQ_PBA8_GIC_START + 19)	/* Audio Codec */
+#define IRQ_PBA8_KMI0		(IRQ_PBA8_GIC_START + 20)	/* Keyboard/Mouse port 0 */
+#define IRQ_PBA8_KMI1		(IRQ_PBA8_GIC_START + 21)	/* Keyboard/Mouse port 1 */
+#define IRQ_PBA8_CHARLCD	(IRQ_PBA8_GIC_START + 22)	/* Character LCD */
+#define IRQ_PBA8_CLCD		(IRQ_PBA8_GIC_START + 23)	/* CLCD controller */
+#define IRQ_PBA8_DMAC		(IRQ_PBA8_GIC_START + 24)	/* DMA controller */
+#define IRQ_PBA8_PWRFAIL	(IRQ_PBA8_GIC_START + 25)	/* Power failure */
+#define IRQ_PBA8_PISMO		(IRQ_PBA8_GIC_START + 26)	/* PISMO interface */
+#define IRQ_PBA8_DoC		(IRQ_PBA8_GIC_START + 27)	/* Disk on Chip memory controller */
+#define IRQ_PBA8_ETH		(IRQ_PBA8_GIC_START + 28)	/* Ethernet controller */
+#define IRQ_PBA8_USB		(IRQ_PBA8_GIC_START + 29)	/* USB controller */
+#define IRQ_PBA8_TSPEN		(IRQ_PBA8_GIC_START + 30)	/* Touchscreen pen */
+#define IRQ_PBA8_TSKPAD		(IRQ_PBA8_GIC_START + 31)	/* Touchscreen keypad */
+
+/* ... */
+#define IRQ_PBA8_PCI0		(IRQ_PBA8_GIC_START + 50)
+#define IRQ_PBA8_PCI1		(IRQ_PBA8_GIC_START + 51)
+#define IRQ_PBA8_PCI2		(IRQ_PBA8_GIC_START + 52)
+#define IRQ_PBA8_PCI3		(IRQ_PBA8_GIC_START + 53)
+
+#define IRQ_PBA8_SMC		-1
+#define IRQ_PBA8_SCTL		-1
+
+#define NR_GIC_PBA8		1
+
+/*
+ * Only define NR_IRQS if less than NR_IRQS_PBA8
+ */
+#define NR_IRQS_PBA8		(IRQ_PBA8_GIC_START + 64)
+
+#if defined(CONFIG_MACH_REALVIEW_PBA8)
+
+#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PBA8)
+#undef NR_IRQS
+#define NR_IRQS			NR_IRQS_PBA8
+#endif
+
+#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PBA8)
+#undef MAX_GIC_NR
+#define MAX_GIC_NR		NR_GIC_PBA8
+#endif
+
+#endif	/* CONFIG_MACH_REALVIEW_PBA8 */
+
+#endif	/* __MACH_IRQS_PBA8_H */
diff --git a/arch/arm/mach-realview/include/mach/irqs-pbx.h b/arch/arm/mach-realview/include/mach/irqs-pbx.h
new file mode 100644
index 0000000..deaad43
--- /dev/null
+++ b/arch/arm/mach-realview/include/mach/irqs-pbx.h
@@ -0,0 +1,115 @@
+/*
+ * arch/arm/mach-realview/include/mach/irqs-pbx.h
+ *
+ * Copyright (C) 2009 ARM Limited
+ *
+ * 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 __MACH_IRQS_PBX_H
+#define __MACH_IRQS_PBX_H
+
+#define IRQ_PBX_GIC_START			32
+
+/* L220
+#define IRQ_PBX_L220_EVENT	(IRQ_PBX_GIC_START + 29)
+#define IRQ_PBX_L220_SLAVE	(IRQ_PBX_GIC_START + 30)
+#define IRQ_PBX_L220_DECODE	(IRQ_PBX_GIC_START + 31)
+*/
+
+/*
+ * PBX on-board gic irq sources
+ */
+#define IRQ_PBX_WATCHDOG	(IRQ_PBX_GIC_START + 0)	/* Watchdog timer */
+#define IRQ_PBX_SOFT		(IRQ_PBX_GIC_START + 1)	/* Software interrupt */
+#define IRQ_PBX_COMMRx		(IRQ_PBX_GIC_START + 2)	/* Debug Comm Rx interrupt */
+#define IRQ_PBX_COMMTx		(IRQ_PBX_GIC_START + 3)	/* Debug Comm Tx interrupt */
+#define IRQ_PBX_TIMER0_1	(IRQ_PBX_GIC_START + 4)	/* Timer 0/1 (default timer) */
+#define IRQ_PBX_TIMER2_3	(IRQ_PBX_GIC_START + 5)	/* Timer 2/3 */
+#define IRQ_PBX_GPIO0		(IRQ_PBX_GIC_START + 6)	/* GPIO 0 */
+#define IRQ_PBX_GPIO1		(IRQ_PBX_GIC_START + 7)	/* GPIO 1 */
+#define IRQ_PBX_GPIO2		(IRQ_PBX_GIC_START + 8)	/* GPIO 2 */
+								/* 9 reserved */
+#define IRQ_PBX_RTC		(IRQ_PBX_GIC_START + 10)	/* Real Time Clock */
+#define IRQ_PBX_SSP		(IRQ_PBX_GIC_START + 11)	/* Synchronous Serial Port */
+#define IRQ_PBX_UART0		(IRQ_PBX_GIC_START + 12)	/* UART 0 on development chip */
+#define IRQ_PBX_UART1		(IRQ_PBX_GIC_START + 13)	/* UART 1 on development chip */
+#define IRQ_PBX_UART2		(IRQ_PBX_GIC_START + 14)	/* UART 2 on development chip */
+#define IRQ_PBX_UART3		(IRQ_PBX_GIC_START + 15)	/* UART 3 on development chip */
+#define IRQ_PBX_SCI		(IRQ_PBX_GIC_START + 16)	/* Smart Card Interface */
+#define IRQ_PBX_MMCI0A		(IRQ_PBX_GIC_START + 17)	/* Multimedia Card 0A */
+#define IRQ_PBX_MMCI0B		(IRQ_PBX_GIC_START + 18)	/* Multimedia Card 0B */
+#define IRQ_PBX_AACI		(IRQ_PBX_GIC_START + 19)	/* Audio Codec */
+#define IRQ_PBX_KMI0		(IRQ_PBX_GIC_START + 20)	/* Keyboard/Mouse port 0 */
+#define IRQ_PBX_KMI1		(IRQ_PBX_GIC_START + 21)	/* Keyboard/Mouse port 1 */
+#define IRQ_PBX_CHARLCD		(IRQ_PBX_GIC_START + 22)	/* Character LCD */
+#define IRQ_PBX_CLCD		(IRQ_PBX_GIC_START + 23)	/* CLCD controller */
+#define IRQ_PBX_DMAC		(IRQ_PBX_GIC_START + 24)	/* DMA controller */
+#define IRQ_PBX_PWRFAIL		(IRQ_PBX_GIC_START + 25)	/* Power failure */
+#define IRQ_PBX_PISMO		(IRQ_PBX_GIC_START + 26)	/* PISMO interface */
+#define IRQ_PBX_DoC		(IRQ_PBX_GIC_START + 27)	/* Disk on Chip memory controller */
+#define IRQ_PBX_ETH		(IRQ_PBX_GIC_START + 28)	/* Ethernet controller */
+#define IRQ_PBX_USB		(IRQ_PBX_GIC_START + 29)	/* USB controller */
+#define IRQ_PBX_TSPEN		(IRQ_PBX_GIC_START + 30)	/* Touchscreen pen */
+#define IRQ_PBX_TSKPAD		(IRQ_PBX_GIC_START + 31)	/* Touchscreen keypad */
+
+#define IRQ_PBX_PMU_SCU0        (IRQ_PBX_GIC_START + 32)        /* SCU PMU Interrupts (11mp) */
+#define IRQ_PBX_PMU_SCU1        (IRQ_PBX_GIC_START + 33)
+#define IRQ_PBX_PMU_SCU2        (IRQ_PBX_GIC_START + 34)
+#define IRQ_PBX_PMU_SCU3        (IRQ_PBX_GIC_START + 35)
+#define IRQ_PBX_PMU_SCU4        (IRQ_PBX_GIC_START + 36)
+#define IRQ_PBX_PMU_SCU5        (IRQ_PBX_GIC_START + 37)
+#define IRQ_PBX_PMU_SCU6        (IRQ_PBX_GIC_START + 38)
+#define IRQ_PBX_PMU_SCU7        (IRQ_PBX_GIC_START + 39)
+
+#define IRQ_PBX_WATCHDOG1       (IRQ_PBX_GIC_START + 40)        /* Watchdog1 timer */
+#define IRQ_PBX_TIMER4_5        (IRQ_PBX_GIC_START + 41)        /* Timer 0/1 (default timer) */
+#define IRQ_PBX_TIMER6_7        (IRQ_PBX_GIC_START + 42)        /* Timer 2/3 */
+/* ... */
+#define IRQ_PBX_PMU_CPU3        (IRQ_PBX_GIC_START + 44)        /* CPU PMU Interrupts */
+#define IRQ_PBX_PMU_CPU2        (IRQ_PBX_GIC_START + 45)
+#define IRQ_PBX_PMU_CPU1        (IRQ_PBX_GIC_START + 46)
+#define IRQ_PBX_PMU_CPU0        (IRQ_PBX_GIC_START + 47)
+
+/* ... */
+#define IRQ_PBX_PCI0		(IRQ_PBX_GIC_START + 50)
+#define IRQ_PBX_PCI1		(IRQ_PBX_GIC_START + 51)
+#define IRQ_PBX_PCI2		(IRQ_PBX_GIC_START + 52)
+#define IRQ_PBX_PCI3		(IRQ_PBX_GIC_START + 53)
+
+#define IRQ_PBX_SMC		-1
+#define IRQ_PBX_SCTL		-1
+
+#define NR_GIC_PBX		1
+
+/*
+ * Only define NR_IRQS if less than NR_IRQS_PBX
+ */
+#define NR_IRQS_PBX		(IRQ_PBX_GIC_START + 96)
+
+#if defined(CONFIG_MACH_REALVIEW_PBX)
+
+#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PBX)
+#undef NR_IRQS
+#define NR_IRQS			NR_IRQS_PBX
+#endif
+
+#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PBX)
+#undef MAX_GIC_NR
+#define MAX_GIC_NR		NR_GIC_PBX
+#endif
+
+#endif	/* CONFIG_MACH_REALVIEW_PBX */
+
+#endif	/* __MACH_IRQS_PBX_H */
diff --git a/arch/arm/mach-realview/include/mach/irqs.h b/arch/arm/mach-realview/include/mach/irqs.h
index fe5cb98..78854f2 100644
--- a/arch/arm/mach-realview/include/mach/irqs.h
+++ b/arch/arm/mach-realview/include/mach/irqs.h
@@ -22,10 +22,11 @@
 #ifndef __ASM_ARCH_IRQS_H
 #define __ASM_ARCH_IRQS_H
 
-#include <mach/board-eb.h>
-#include <mach/board-pb11mp.h>
-#include <mach/board-pb1176.h>
-#include <mach/board-pba8.h>
+#include <mach/irqs-eb.h>
+#include <mach/irqs-pb11mp.h>
+#include <mach/irqs-pb1176.h>
+#include <mach/irqs-pba8.h>
+#include <mach/irqs-pbx.h>
 
 #define IRQ_LOCALTIMER		29
 #define IRQ_LOCALWDOG		30
diff --git a/arch/arm/mach-realview/include/mach/scu.h b/arch/arm/mach-realview/include/mach/scu.h
deleted file mode 100644
index d55802d..0000000
--- a/arch/arm/mach-realview/include/mach/scu.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __ASMARM_ARCH_SCU_H
-#define __ASMARM_ARCH_SCU_H
-
-/*
- * SCU registers
- */
-#define SCU_CTRL		0x00
-#define SCU_CONFIG		0x04
-#define SCU_CPU_STATUS		0x08
-#define SCU_INVALIDATE		0x0c
-#define SCU_FPGA_REVISION	0x10
-
-#endif
diff --git a/arch/arm/mach-realview/include/mach/uncompress.h b/arch/arm/mach-realview/include/mach/uncompress.h
index 415d634..8305037 100644
--- a/arch/arm/mach-realview/include/mach/uncompress.h
+++ b/arch/arm/mach-realview/include/mach/uncompress.h
@@ -24,6 +24,7 @@
 #include <mach/board-pb11mp.h>
 #include <mach/board-pb1176.h>
 #include <mach/board-pba8.h>
+#include <mach/board-pbx.h>
 
 #define AMBA_UART_DR(base)	(*(volatile unsigned char *)((base) + 0x00))
 #define AMBA_UART_LCRH(base)	(*(volatile unsigned char *)((base) + 0x2c))
@@ -43,6 +44,8 @@
 		return REALVIEW_PB1176_UART0_BASE;
 	else if (machine_is_realview_pba8())
 		return REALVIEW_PBA8_UART0_BASE;
+	else if (machine_is_realview_pbx())
+		return REALVIEW_PBX_UART0_BASE;
 	else
 		return 0;
 }
diff --git a/arch/arm/mach-realview/localtimer.c b/arch/arm/mach-realview/localtimer.c
index 1c01d13..60b4e11 100644
--- a/arch/arm/mach-realview/localtimer.c
+++ b/arch/arm/mach-realview/localtimer.c
@@ -9,196 +9,18 @@
  * published by the Free Software Foundation.
  */
 #include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/device.h>
 #include <linux/smp.h>
-#include <linux/jiffies.h>
-#include <linux/percpu.h>
 #include <linux/clockchips.h>
-#include <linux/irq.h>
-#include <linux/io.h>
 
-#include <asm/hardware/arm_twd.h>
-#include <asm/hardware/gic.h>
-#include <mach/hardware.h>
 #include <asm/irq.h>
-
-static DEFINE_PER_CPU(struct clock_event_device, local_clockevent);
-
-/*
- * Used on SMP for either the local timer or IPI_TIMER
- */
-void local_timer_interrupt(void)
-{
-	struct clock_event_device *clk = &__get_cpu_var(local_clockevent);
-
-	clk->event_handler(clk);
-}
-
-#ifdef CONFIG_LOCAL_TIMERS
-
-/* set up by the platform code */
-void __iomem *twd_base;
-
-static unsigned long mpcore_timer_rate;
-
-static void local_timer_set_mode(enum clock_event_mode mode,
-				 struct clock_event_device *clk)
-{
-	unsigned long ctrl;
-
-	switch(mode) {
-	case CLOCK_EVT_MODE_PERIODIC:
-		/* timer load already set up */
-		ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE
-			| TWD_TIMER_CONTROL_PERIODIC;
-		break;
-	case CLOCK_EVT_MODE_ONESHOT:
-		/* period set, and timer enabled in 'next_event' hook */
-		ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT;
-		break;
-	case CLOCK_EVT_MODE_UNUSED:
-	case CLOCK_EVT_MODE_SHUTDOWN:
-	default:
-		ctrl = 0;
-	}
-
-	__raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);
-}
-
-static int local_timer_set_next_event(unsigned long evt,
-				      struct clock_event_device *unused)
-{
-	unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);
-
-	__raw_writel(evt, twd_base + TWD_TIMER_COUNTER);
-	__raw_writel(ctrl | TWD_TIMER_CONTROL_ENABLE, twd_base + TWD_TIMER_CONTROL);
-
-	return 0;
-}
-
-/*
- * local_timer_ack: checks for a local timer interrupt.
- *
- * If a local timer interrupt has occurred, acknowledge and return 1.
- * Otherwise, return 0.
- */
-int local_timer_ack(void)
-{
-	if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {
-		__raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
-		return 1;
-	}
-
-	return 0;
-}
-
-static void __cpuinit twd_calibrate_rate(void)
-{
-	unsigned long load, count;
-	u64 waitjiffies;
-
-	/*
-	 * If this is the first time round, we need to work out how fast
-	 * the timer ticks
-	 */
-	if (mpcore_timer_rate == 0) {
-		printk("Calibrating local timer... ");
-
-		/* Wait for a tick to start */
-		waitjiffies = get_jiffies_64() + 1;
-
-		while (get_jiffies_64() < waitjiffies)
-			udelay(10);
-
-		/* OK, now the tick has started, let's get the timer going */
-		waitjiffies += 5;
-
-				 /* enable, no interrupt or reload */
-		__raw_writel(0x1, twd_base + TWD_TIMER_CONTROL);
-
-				 /* maximum value */
-		__raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);
-
-		while (get_jiffies_64() < waitjiffies)
-			udelay(10);
-
-		count = __raw_readl(twd_base + TWD_TIMER_COUNTER);
-
-		mpcore_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
-
-		printk("%lu.%02luMHz.\n", mpcore_timer_rate / 1000000,
-			(mpcore_timer_rate / 100000) % 100);
-	}
-
-	load = mpcore_timer_rate / HZ;
-
-	__raw_writel(load, twd_base + TWD_TIMER_LOAD);
-}
+#include <asm/smp_twd.h>
+#include <asm/localtimer.h>
 
 /*
  * Setup the local clock events for a CPU.
  */
-void __cpuinit local_timer_setup(void)
+void __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
-	unsigned int cpu = smp_processor_id();
-	struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
-	unsigned long flags;
-
-	twd_calibrate_rate();
-
-	clk->name		= "local_timer";
-	clk->features		= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
-	clk->rating		= 350;
-	clk->set_mode		= local_timer_set_mode;
-	clk->set_next_event	= local_timer_set_next_event;
-	clk->irq		= IRQ_LOCALTIMER;
-	clk->cpumask		= cpumask_of(cpu);
-	clk->shift		= 20;
-	clk->mult		= div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift);
-	clk->max_delta_ns	= clockevent_delta2ns(0xffffffff, clk);
-	clk->min_delta_ns	= clockevent_delta2ns(0xf, clk);
-
-	/* Make sure our local interrupt controller has this enabled */
-	local_irq_save(flags);
-	get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER);
-	local_irq_restore(flags);
-
-	clockevents_register_device(clk);
+	evt->irq = IRQ_LOCALTIMER;
+	twd_timer_setup(evt);
 }
-
-/*
- * take a local timer down
- */
-void __cpuexit local_timer_stop(void)
-{
-	__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
-}
-
-#else	/* CONFIG_LOCAL_TIMERS */
-
-static void dummy_timer_set_mode(enum clock_event_mode mode,
-				 struct clock_event_device *clk)
-{
-}
-
-void __cpuinit local_timer_setup(void)
-{
-	unsigned int cpu = smp_processor_id();
-	struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
-
-	clk->name		= "dummy_timer";
-	clk->features		= CLOCK_EVT_FEAT_ONESHOT |
-				  CLOCK_EVT_FEAT_PERIODIC |
-				  CLOCK_EVT_FEAT_DUMMY;
-	clk->rating		= 400;
-	clk->mult               = 1;
-	clk->set_mode		= dummy_timer_set_mode;
-	clk->broadcast		= smp_timer_broadcast;
-	clk->cpumask		= cpumask_of(cpu);
-
-	clockevents_register_device(clk);
-}
-
-#endif	/* !CONFIG_LOCAL_TIMERS */
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index 30a9c68..ac0e83f 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -19,10 +19,12 @@
 #include <asm/cacheflush.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
+#include <asm/localtimer.h>
 
 #include <mach/board-eb.h>
 #include <mach/board-pb11mp.h>
-#include <mach/scu.h>
+#include <mach/board-pbx.h>
+#include <asm/smp_scu.h>
 
 #include "core.h"
 
@@ -40,35 +42,19 @@
 		return __io_address(REALVIEW_EB11MP_SCU_BASE);
 	else if (machine_is_realview_pb11mp())
 		return __io_address(REALVIEW_TC11MP_SCU_BASE);
+	else if (machine_is_realview_pbx() &&
+		 (core_tile_pbx11mp() || core_tile_pbxa9mp()))
+		return __io_address(REALVIEW_PBX_TILE_SCU_BASE);
 	else
 		return (void __iomem *)0;
 }
 
-static unsigned int __init get_core_count(void)
+static inline unsigned int get_core_count(void)
 {
-	unsigned int ncores;
 	void __iomem *scu_base = scu_base_addr();
-
-	if (scu_base) {
-		ncores = __raw_readl(scu_base + SCU_CONFIG);
-		ncores = (ncores & 0x03) + 1;
-	} else
-		ncores = 1;
-
-	return ncores;
-}
-
-/*
- * Setup the SCU
- */
-static void scu_enable(void)
-{
-	u32 scu_ctrl;
-	void __iomem *scu_base = scu_base_addr();
-
-	scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
-	scu_ctrl |= 1;
-	__raw_writel(scu_ctrl, scu_base + SCU_CTRL);
+	if (scu_base)
+		return scu_get_core_count(scu_base);
+	return 1;
 }
 
 static DEFINE_SPINLOCK(boot_lock);
@@ -184,7 +170,7 @@
 	unsigned int i, ncores = get_core_count();
 
 	for (i = 0; i < ncores; i++)
-		cpu_set(i, cpu_possible_map);
+		set_cpu_possible(i, true);
 }
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
@@ -217,19 +203,12 @@
 	if (max_cpus > ncores)
 		max_cpus = ncores;
 
-#if defined(CONFIG_LOCAL_TIMERS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
-	/*
-	 * Enable the local timer or broadcast device for the boot CPU.
-	 */
-	local_timer_setup();
-#endif
-
 	/*
 	 * Initialise the present map, which describes the set of CPUs
 	 * actually populated at the present time.
 	 */
 	for (i = 0; i < max_cpus; i++)
-		cpu_set(i, cpu_present_map);
+		set_cpu_present(i, true);
 
 	/*
 	 * Initialise the SCU if there are more than one CPU and let
@@ -239,7 +218,13 @@
 	 * WFI
 	 */
 	if (max_cpus > 1) {
-		scu_enable();
+		/*
+		 * Enable the local timer or broadcast device for the
+		 * boot CPU, but only if we have more than one CPU.
+		 */
+		percpu_timer_setup();
+
+		scu_enable(scu_base_addr());
 		poke_milo();
 	}
 }
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index c20fbef..8dfa44e 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -32,6 +32,7 @@
 #include <asm/hardware/gic.h>
 #include <asm/hardware/icst307.h>
 #include <asm/hardware/cache-l2x0.h>
+#include <asm/localtimer.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index a64b84a..25efe71 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -203,11 +203,23 @@
 /*
  * RealView PB1176 platform devices
  */
-static struct resource realview_pb1176_flash_resource = {
-	.start			= REALVIEW_PB1176_FLASH_BASE,
-	.end			= REALVIEW_PB1176_FLASH_BASE + REALVIEW_PB1176_FLASH_SIZE - 1,
-	.flags			= IORESOURCE_MEM,
+static struct resource realview_pb1176_flash_resources[] = {
+	[0] = {
+		.start		= REALVIEW_PB1176_FLASH_BASE,
+		.end		= REALVIEW_PB1176_FLASH_BASE + REALVIEW_PB1176_FLASH_SIZE - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start		= REALVIEW_PB1176_SEC_FLASH_BASE,
+		.end		= REALVIEW_PB1176_SEC_FLASH_BASE + REALVIEW_PB1176_SEC_FLASH_SIZE - 1,
+		.flags		= IORESOURCE_MEM,
+	},
 };
+#ifdef CONFIG_REALVIEW_PB1176_SECURE_FLASH
+#define PB1176_FLASH_BLOCKS	2
+#else
+#define PB1176_FLASH_BLOCKS	1
+#endif
 
 static struct resource realview_pb1176_smsc911x_resources[] = {
 	[0] = {
@@ -271,7 +283,8 @@
 	l2x0_init(__io_address(REALVIEW_PB1176_L220_BASE), 0x00730000, 0xfe000fff);
 #endif
 
-	realview_flash_register(&realview_pb1176_flash_resource, 1);
+	realview_flash_register(realview_pb1176_flash_resources,
+				PB1176_FLASH_BLOCKS);
 	realview_eth_register(NULL, realview_pb1176_smsc911x_resources);
 	platform_device_register(&realview_i2c_device);
 	realview_usb_register(realview_pb1176_isp1761_resources);
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index ea1e60e..dc4b169 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -32,6 +32,7 @@
 #include <asm/hardware/gic.h>
 #include <asm/hardware/icst307.h>
 #include <asm/hardware/cache-l2x0.h>
+#include <asm/localtimer.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
new file mode 100644
index 0000000..1fe294d
--- /dev/null
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -0,0 +1,335 @@
+/*
+ *  arch/arm/mach-realview/realview_pbx.c
+ *
+ *  Copyright (C) 2009 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/amba/bus.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <asm/leds.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/gic.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/mmc.h>
+#include <asm/mach/time.h>
+
+#include <mach/hardware.h>
+#include <mach/board-pbx.h>
+#include <mach/irqs.h>
+
+#include "core.h"
+
+static struct map_desc realview_pbx_io_desc[] __initdata = {
+	{
+		.virtual	= IO_ADDRESS(REALVIEW_SYS_BASE),
+		.pfn		= __phys_to_pfn(REALVIEW_SYS_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= IO_ADDRESS(REALVIEW_PBX_GIC_CPU_BASE),
+		.pfn		= __phys_to_pfn(REALVIEW_PBX_GIC_CPU_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= IO_ADDRESS(REALVIEW_PBX_GIC_DIST_BASE),
+		.pfn		= __phys_to_pfn(REALVIEW_PBX_GIC_DIST_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= IO_ADDRESS(REALVIEW_SCTL_BASE),
+		.pfn		= __phys_to_pfn(REALVIEW_SCTL_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= IO_ADDRESS(REALVIEW_PBX_TIMER0_1_BASE),
+		.pfn		= __phys_to_pfn(REALVIEW_PBX_TIMER0_1_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= IO_ADDRESS(REALVIEW_PBX_TIMER2_3_BASE),
+		.pfn		= __phys_to_pfn(REALVIEW_PBX_TIMER2_3_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	},
+#ifdef CONFIG_PCI
+	{
+		.virtual	= PCIX_UNIT_BASE,
+		.pfn		= __phys_to_pfn(REALVIEW_PBX_PCI_BASE),
+		.length		= REALVIEW_PBX_PCI_BASE_SIZE,
+		.type		= MT_DEVICE,
+	},
+#endif
+#ifdef CONFIG_DEBUG_LL
+	{
+		.virtual	= IO_ADDRESS(REALVIEW_PBX_UART0_BASE),
+		.pfn		= __phys_to_pfn(REALVIEW_PBX_UART0_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	},
+#endif
+};
+
+static struct map_desc realview_local_io_desc[] __initdata = {
+	{
+		.virtual        = IO_ADDRESS(REALVIEW_PBX_TILE_GIC_CPU_BASE),
+		.pfn            = __phys_to_pfn(REALVIEW_PBX_TILE_GIC_CPU_BASE),
+		.length         = SZ_4K,
+		.type           = MT_DEVICE,
+	}, {
+		.virtual        = IO_ADDRESS(REALVIEW_PBX_TILE_GIC_DIST_BASE),
+		.pfn            = __phys_to_pfn(REALVIEW_PBX_TILE_GIC_DIST_BASE),
+		.length         = SZ_4K,
+		.type           = MT_DEVICE,
+	}, {
+		.virtual        = IO_ADDRESS(REALVIEW_PBX_TILE_L220_BASE),
+		.pfn            = __phys_to_pfn(REALVIEW_PBX_TILE_L220_BASE),
+		.length         = SZ_8K,
+		.type           = MT_DEVICE,
+	}
+};
+
+static void __init realview_pbx_map_io(void)
+{
+	iotable_init(realview_pbx_io_desc, ARRAY_SIZE(realview_pbx_io_desc));
+	if (core_tile_pbx11mp() || core_tile_pbxa9mp())
+		iotable_init(realview_local_io_desc, ARRAY_SIZE(realview_local_io_desc));
+}
+
+/*
+ * RealView PBXCore AMBA devices
+ */
+
+#define GPIO2_IRQ		{ IRQ_PBX_GPIO2, NO_IRQ }
+#define GPIO2_DMA		{ 0, 0 }
+#define GPIO3_IRQ		{ IRQ_PBX_GPIO3, NO_IRQ }
+#define GPIO3_DMA		{ 0, 0 }
+#define AACI_IRQ		{ IRQ_PBX_AACI, NO_IRQ }
+#define AACI_DMA		{ 0x80, 0x81 }
+#define MMCI0_IRQ		{ IRQ_PBX_MMCI0A, IRQ_PBX_MMCI0B }
+#define MMCI0_DMA		{ 0x84, 0 }
+#define KMI0_IRQ		{ IRQ_PBX_KMI0, NO_IRQ }
+#define KMI0_DMA		{ 0, 0 }
+#define KMI1_IRQ		{ IRQ_PBX_KMI1, NO_IRQ }
+#define KMI1_DMA		{ 0, 0 }
+#define PBX_SMC_IRQ		{ NO_IRQ, NO_IRQ }
+#define PBX_SMC_DMA		{ 0, 0 }
+#define MPMC_IRQ		{ NO_IRQ, NO_IRQ }
+#define MPMC_DMA		{ 0, 0 }
+#define PBX_CLCD_IRQ		{ IRQ_PBX_CLCD, NO_IRQ }
+#define PBX_CLCD_DMA		{ 0, 0 }
+#define DMAC_IRQ		{ IRQ_PBX_DMAC, NO_IRQ }
+#define DMAC_DMA		{ 0, 0 }
+#define SCTL_IRQ		{ NO_IRQ, NO_IRQ }
+#define SCTL_DMA		{ 0, 0 }
+#define PBX_WATCHDOG_IRQ	{ IRQ_PBX_WATCHDOG, NO_IRQ }
+#define PBX_WATCHDOG_DMA	{ 0, 0 }
+#define PBX_GPIO0_IRQ		{ IRQ_PBX_GPIO0, NO_IRQ }
+#define PBX_GPIO0_DMA		{ 0, 0 }
+#define GPIO1_IRQ		{ IRQ_PBX_GPIO1, NO_IRQ }
+#define GPIO1_DMA		{ 0, 0 }
+#define PBX_RTC_IRQ		{ IRQ_PBX_RTC, NO_IRQ }
+#define PBX_RTC_DMA		{ 0, 0 }
+#define SCI_IRQ			{ IRQ_PBX_SCI, NO_IRQ }
+#define SCI_DMA			{ 7, 6 }
+#define PBX_UART0_IRQ		{ IRQ_PBX_UART0, NO_IRQ }
+#define PBX_UART0_DMA		{ 15, 14 }
+#define PBX_UART1_IRQ		{ IRQ_PBX_UART1, NO_IRQ }
+#define PBX_UART1_DMA		{ 13, 12 }
+#define PBX_UART2_IRQ		{ IRQ_PBX_UART2, NO_IRQ }
+#define PBX_UART2_DMA		{ 11, 10 }
+#define PBX_UART3_IRQ		{ IRQ_PBX_UART3, NO_IRQ }
+#define PBX_UART3_DMA		{ 0x86, 0x87 }
+#define PBX_SSP_IRQ		{ IRQ_PBX_SSP, NO_IRQ }
+#define PBX_SSP_DMA		{ 9, 8 }
+
+/* FPGA Primecells */
+AMBA_DEVICE(aaci,	"fpga:04",	AACI,		NULL);
+AMBA_DEVICE(mmc0,	"fpga:05",	MMCI0,		&realview_mmc0_plat_data);
+AMBA_DEVICE(kmi0,	"fpga:06",	KMI0,		NULL);
+AMBA_DEVICE(kmi1,	"fpga:07",	KMI1,		NULL);
+AMBA_DEVICE(uart3,	"fpga:09",	PBX_UART3,	NULL);
+
+/* DevChip Primecells */
+AMBA_DEVICE(smc,	"dev:00",	PBX_SMC,	NULL);
+AMBA_DEVICE(sctl,	"dev:e0",	SCTL,		NULL);
+AMBA_DEVICE(wdog,	"dev:e1",	PBX_WATCHDOG, 	NULL);
+AMBA_DEVICE(gpio0,	"dev:e4",	PBX_GPIO0,	NULL);
+AMBA_DEVICE(gpio1,	"dev:e5",	GPIO1,		NULL);
+AMBA_DEVICE(gpio2,	"dev:e6",	GPIO2,		NULL);
+AMBA_DEVICE(rtc,	"dev:e8",	PBX_RTC,	NULL);
+AMBA_DEVICE(sci0,	"dev:f0",	SCI,		NULL);
+AMBA_DEVICE(uart0,	"dev:f1",	PBX_UART0,	NULL);
+AMBA_DEVICE(uart1,	"dev:f2",	PBX_UART1,	NULL);
+AMBA_DEVICE(uart2,	"dev:f3",	PBX_UART2,	NULL);
+AMBA_DEVICE(ssp0,	"dev:f4",	PBX_SSP,	NULL);
+
+/* Primecells on the NEC ISSP chip */
+AMBA_DEVICE(clcd,	"issp:20",	PBX_CLCD,	&clcd_plat_data);
+AMBA_DEVICE(dmac,	"issp:30",	DMAC,		NULL);
+
+static struct amba_device *amba_devs[] __initdata = {
+	&dmac_device,
+	&uart0_device,
+	&uart1_device,
+	&uart2_device,
+	&uart3_device,
+	&smc_device,
+	&clcd_device,
+	&sctl_device,
+	&wdog_device,
+	&gpio0_device,
+	&gpio1_device,
+	&gpio2_device,
+	&rtc_device,
+	&sci0_device,
+	&ssp0_device,
+	&aaci_device,
+	&mmc0_device,
+	&kmi0_device,
+	&kmi1_device,
+};
+
+/*
+ * RealView PB-X platform devices
+ */
+static struct resource realview_pbx_flash_resources[] = {
+	[0] = {
+		.start          = REALVIEW_PBX_FLASH0_BASE,
+		.end            = REALVIEW_PBX_FLASH0_BASE + REALVIEW_PBX_FLASH0_SIZE - 1,
+		.flags          = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start          = REALVIEW_PBX_FLASH1_BASE,
+		.end            = REALVIEW_PBX_FLASH1_BASE + REALVIEW_PBX_FLASH1_SIZE - 1,
+		.flags          = IORESOURCE_MEM,
+	},
+};
+
+static struct resource realview_pbx_smsc911x_resources[] = {
+	[0] = {
+		.start		= REALVIEW_PBX_ETH_BASE,
+		.end		= REALVIEW_PBX_ETH_BASE + SZ_64K - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start		= IRQ_PBX_ETH,
+		.end		= IRQ_PBX_ETH,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource realview_pbx_isp1761_resources[] = {
+	[0] = {
+		.start		= REALVIEW_PBX_USB_BASE,
+		.end		= REALVIEW_PBX_USB_BASE + SZ_128K - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start		= IRQ_PBX_USB,
+		.end		= IRQ_PBX_USB,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static void __init gic_init_irq(void)
+{
+	/* ARM PBX on-board GIC */
+	if (core_tile_pbx11mp() || core_tile_pbxa9mp()) {
+		gic_cpu_base_addr = __io_address(REALVIEW_PBX_TILE_GIC_CPU_BASE);
+		gic_dist_init(0, __io_address(REALVIEW_PBX_TILE_GIC_DIST_BASE),
+			      29);
+		gic_cpu_init(0, __io_address(REALVIEW_PBX_TILE_GIC_CPU_BASE));
+	} else {
+		gic_cpu_base_addr = __io_address(REALVIEW_PBX_GIC_CPU_BASE);
+		gic_dist_init(0, __io_address(REALVIEW_PBX_GIC_DIST_BASE),
+			      IRQ_PBX_GIC_START);
+		gic_cpu_init(0, __io_address(REALVIEW_PBX_GIC_CPU_BASE));
+	}
+}
+
+static void __init realview_pbx_timer_init(void)
+{
+	timer0_va_base = __io_address(REALVIEW_PBX_TIMER0_1_BASE);
+	timer1_va_base = __io_address(REALVIEW_PBX_TIMER0_1_BASE) + 0x20;
+	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);
+}
+
+static struct sys_timer realview_pbx_timer = {
+	.init		= realview_pbx_timer_init,
+};
+
+static void __init realview_pbx_init(void)
+{
+	int i;
+
+#ifdef CONFIG_CACHE_L2X0
+	if (core_tile_pbxa9mp()) {
+		void __iomem *l2x0_base =
+			__io_address(REALVIEW_PBX_TILE_L220_BASE);
+
+		/* set RAM latencies to 1 cycle for eASIC */
+		writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL);
+		writel(0, l2x0_base + L2X0_DATA_LATENCY_CTRL);
+
+		/* 16KB way size, 8-way associativity, parity disabled
+		 * Bits:  .. 0 0 0 0 1 00 1 0 1 001 0 000 0 .... .... .... */
+		l2x0_init(l2x0_base, 0x02520000, 0xc0000fff);
+	}
+#endif
+
+	realview_flash_register(realview_pbx_flash_resources,
+				ARRAY_SIZE(realview_pbx_flash_resources));
+	realview_eth_register(NULL, realview_pbx_smsc911x_resources);
+	platform_device_register(&realview_i2c_device);
+	platform_device_register(&realview_cf_device);
+	realview_usb_register(realview_pbx_isp1761_resources);
+
+	for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+		struct amba_device *d = amba_devs[i];
+		amba_device_register(d, &iomem_resource);
+	}
+
+#ifdef CONFIG_LEDS
+	leds_event = realview_leds_event;
+#endif
+}
+
+MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX")
+	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
+	.phys_io	= REALVIEW_PBX_UART0_BASE,
+	.io_pg_offst	= (IO_ADDRESS(REALVIEW_PBX_UART0_BASE) >> 18) & 0xfffc,
+	.boot_params	= PHYS_OFFSET + 0x00000100,
+	.map_io		= realview_pbx_map_io,
+	.init_irq	= gic_init_irq,
+	.timer		= &realview_pbx_timer,
+	.init_machine	= realview_pbx_init,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2400/gpio.c b/arch/arm/mach-s3c2400/gpio.c
index 7a7ed417..6c68e78 100644
--- a/arch/arm/mach-s3c2400/gpio.c
+++ b/arch/arm/mach-s3c2400/gpio.c
@@ -33,10 +33,10 @@
 
 int s3c2400_gpio_getirq(unsigned int pin)
 {
-	if (pin < S3C2410_GPE0 || pin > S3C2400_GPE7_EINT7)
-		return -1;  /* not valid interrupts */
+	if (pin < S3C2410_GPE(0) || pin > S3C2400_GPE(7))
+		return -EINVAL;  /* not valid interrupts */
 
-	return (pin - S3C2410_GPE0) + IRQ_EINT0;
+	return (pin - S3C2410_GPE(0)) + IRQ_EINT0;
 }
 
 EXPORT_SYMBOL(s3c2400_gpio_getirq);
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index 63a30d1..41bb65d 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -59,6 +59,7 @@
 	bool "IPAQ H1940"
 	select CPU_S3C2410
 	select PM_H1940 if PM
+	select S3C_DEV_USB_HOST
 	help
 	  Say Y here if you are using the HP IPAQ H1940
 
@@ -70,6 +71,7 @@
 config MACH_N30
 	bool "Acer N30 family"
 	select CPU_S3C2410
+	select S3C_DEV_USB_HOST
 	help
 	  Say Y here if you want suppt for the Acer N30, Acer N35,
 	  Navman PiN570, Yakumo AlphaX or Airis NC05 PDAs.
@@ -82,6 +84,7 @@
 	select MACH_BAST_IDE
 	select S3C24XX_DCLK
 	select ISA
+	select S3C_DEV_USB_HOST
 	help
 	  Say Y here if you are using the Simtec Electronics EB2410ITX
 	  development board (also known as BAST)
@@ -89,6 +92,7 @@
 config MACH_OTOM
  	bool "NexVision OTOM Board"
  	select CPU_S3C2410
+	select S3C_DEV_USB_HOST
 	help
  	  Say Y here if you are using the Nex Vision OTOM board
 
@@ -96,6 +100,7 @@
 	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>
@@ -111,6 +116,7 @@
 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>
@@ -122,12 +128,14 @@
 	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
 	help
 	   Say Y here if you are using the Armzone QT2410
 
diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c
index 440c014..dbf96e6 100644
--- a/arch/arm/mach-s3c2410/dma.c
+++ b/arch/arm/mach-s3c2410/dma.c
@@ -17,14 +17,16 @@
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 
+#include <mach/map.h>
 #include <mach/dma.h>
 
 #include <plat/cpu.h>
-#include <plat/dma.h>
+#include <plat/dma-plat.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>
diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c
index 36a3132..7974afc 100644
--- a/arch/arm/mach-s3c2410/gpio.c
+++ b/arch/arm/mach-s3c2410/gpio.c
@@ -39,12 +39,12 @@
 	unsigned long flags;
 	unsigned long val;
 
-	if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15)
-		return -1;
+	if (pin < S3C2410_GPG(8) || pin > S3C2410_GPG(15))
+		return -EINVAL;
 
 	config &= 0xff;
 
-	pin -= S3C2410_GPG8;
+	pin -= S3C2410_GPG(8);
 	reg += pin & ~3;
 
 	local_irq_save(flags);
diff --git a/arch/arm/mach-s3c2410/h1940-bluetooth.c b/arch/arm/mach-s3c2410/h1940-bluetooth.c
index 5a6bc56..5aabf11 100644
--- a/arch/arm/mach-s3c2410/h1940-bluetooth.c
+++ b/arch/arm/mach-s3c2410/h1940-bluetooth.c
@@ -16,6 +16,8 @@
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/leds.h>
+#include <linux/gpio.h>
+
 #include <mach/regs-gpio.h>
 #include <mach/hardware.h>
 #include <mach/h1940-latch.h>
@@ -41,9 +43,9 @@
 		h1940_latch_control(0, H1940_LATCH_BLUETOOTH_POWER);
 		/* Reset the chip */
 		mdelay(10);
-		s3c2410_gpio_setpin(S3C2410_GPH1, 1);
+		s3c2410_gpio_setpin(S3C2410_GPH(1), 1);
 		mdelay(10);
-		s3c2410_gpio_setpin(S3C2410_GPH1, 0);
+		s3c2410_gpio_setpin(S3C2410_GPH(1), 0);
 
 		state = 1;
 	}
@@ -52,9 +54,9 @@
 		led_trigger_event(bt_led_trigger, 0);
 #endif
 
-		s3c2410_gpio_setpin(S3C2410_GPH1, 1);
+		s3c2410_gpio_setpin(S3C2410_GPH(1), 1);
 		mdelay(10);
-		s3c2410_gpio_setpin(S3C2410_GPH1, 0);
+		s3c2410_gpio_setpin(S3C2410_GPH(1), 0);
 		mdelay(10);
 		h1940_latch_control(H1940_LATCH_BLUETOOTH_POWER, 0);
 
@@ -87,14 +89,14 @@
 static int __init h1940bt_probe(struct platform_device *pdev)
 {
 	/* Configures BT serial port GPIOs */
-	s3c2410_gpio_cfgpin(S3C2410_GPH0, S3C2410_GPH0_nCTS0);
-	s3c2410_gpio_pullup(S3C2410_GPH0, 1);
-	s3c2410_gpio_cfgpin(S3C2410_GPH1, S3C2410_GPH1_OUTP);
-	s3c2410_gpio_pullup(S3C2410_GPH1, 1);
-	s3c2410_gpio_cfgpin(S3C2410_GPH2, S3C2410_GPH2_TXD0);
-	s3c2410_gpio_pullup(S3C2410_GPH2, 1);
-	s3c2410_gpio_cfgpin(S3C2410_GPH3, S3C2410_GPH3_RXD0);
-	s3c2410_gpio_pullup(S3C2410_GPH3, 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPH(0), S3C2410_GPH0_nCTS0);
+	s3c2410_gpio_pullup(S3C2410_GPH(0), 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_pullup(S3C2410_GPH(1), 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPH(2), S3C2410_GPH2_TXD0);
+	s3c2410_gpio_pullup(S3C2410_GPH(2), 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPH(3), S3C2410_GPH3_RXD0);
+	s3c2410_gpio_pullup(S3C2410_GPH(3), 1);
 
 #ifdef CONFIG_LEDS_H1940
 	led_trigger_register_simple("h1940-bluetooth", &bt_led_trigger);
diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h
index 13358ce..c3a2629 100644
--- a/arch/arm/mach-s3c2410/include/mach/dma.h
+++ b/arch/arm/mach-s3c2410/include/mach/dma.h
@@ -3,7 +3,7 @@
  * Copyright (C) 2003,2004,2006 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
  *
- * Samsung S3C241XX DMA support
+ * Samsung S3C24XX DMA 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,8 +13,8 @@
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H __FILE__
 
+#include <plat/dma.h>
 #include <linux/sysdev.h>
-#include <mach/hardware.h>
 
 #define MAX_DMA_TRANSFER_SIZE   0x100000 /* Data Unit is half word  */
 
@@ -55,9 +55,9 @@
 
 /* we have 4 dma channels */
 #ifndef CONFIG_CPU_S3C2443
-#define S3C2410_DMA_CHANNELS		(4)
+#define S3C_DMA_CHANNELS		(4)
 #else
-#define S3C2410_DMA_CHANNELS		(6)
+#define S3C_DMA_CHANNELS		(6)
 #endif
 
 /* types */
@@ -68,7 +68,6 @@
 	S3C2410_DMA_PAUSED
 };
 
-
 /* enum s3c2410_dma_loadst
  *
  * This represents the state of the DMA engine, wrt to the loaded / running
@@ -104,32 +103,6 @@
 	S3C2410_DMALOAD_1LOADED_1RUNNING,
 };
 
-enum s3c2410_dma_buffresult {
-	S3C2410_RES_OK,
-	S3C2410_RES_ERR,
-	S3C2410_RES_ABORT
-};
-
-enum s3c2410_dmasrc {
-	S3C2410_DMASRC_HW,		/* source is memory */
-	S3C2410_DMASRC_MEM		/* source is hardware */
-};
-
-/* enum s3c2410_chan_op
- *
- * operation codes passed to the DMA code by the user, and also used
- * to inform the current channel owner of any changes to the system state
-*/
-
-enum s3c2410_chan_op {
-	S3C2410_DMAOP_START,
-	S3C2410_DMAOP_STOP,
-	S3C2410_DMAOP_PAUSE,
-	S3C2410_DMAOP_RESUME,
-	S3C2410_DMAOP_FLUSH,
-	S3C2410_DMAOP_TIMEOUT,		/* internal signal to handler */
-	S3C2410_DMAOP_STARTED,		/* indicate channel started */
-};
 
 /* flags */
 
@@ -139,17 +112,14 @@
 
 /* dma buffer */
 
-struct s3c2410_dma_client {
-	char                *name;
-};
+struct s3c2410_dma_buf;
 
-/* s3c2410_dma_buf_s
+/* s3c2410_dma_buf
  *
  * internally used buffer structure to describe a queued or running
  * buffer.
 */
 
-struct s3c2410_dma_buf;
 struct s3c2410_dma_buf {
 	struct s3c2410_dma_buf	*next;
 	int			 magic;		/* magic */
@@ -161,20 +131,6 @@
 
 /* [1] is this updated for both recv/send modes? */
 
-struct s3c2410_dma_chan;
-
-/* s3c2410_dma_cbfn_t
- *
- * buffer callback routine type
-*/
-
-typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *,
-				   void *buf, int size,
-				   enum s3c2410_dma_buffresult result);
-
-typedef int  (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *,
-				   enum s3c2410_chan_op );
-
 struct s3c2410_dma_stats {
 	unsigned long		loads;
 	unsigned long		timeout_longest;
@@ -206,10 +162,10 @@
 
 	/* channel configuration */
 	enum s3c2410_dmasrc	 source;
+	enum dma_ch		 req_ch;
 	unsigned long		 dev_addr;
 	unsigned long		 load_timeout;
 	unsigned int		 flags;		/* channel flags */
-	unsigned int		 hw_cfg;	/* last hw config */
 
 	struct s3c24xx_dma_map	*map;		/* channel hw maps */
 
@@ -236,213 +192,6 @@
 	struct sys_device	dev;
 };
 
-/* the currently allocated channel information */
-extern struct s3c2410_dma_chan s3c2410_chans[];
-
-/* note, we don't really use dma_device_t at the moment */
 typedef unsigned long dma_device_t;
 
-/* functions --------------------------------------------------------------- */
-
-/* s3c2410_dma_request
- *
- * request a dma channel exclusivley
-*/
-
-extern int s3c2410_dma_request(unsigned int channel,
-			       struct s3c2410_dma_client *, void *dev);
-
-
-/* s3c2410_dma_ctrl
- *
- * change the state of the dma channel
-*/
-
-extern int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op);
-
-/* s3c2410_dma_setflags
- *
- * set the channel's flags to a given state
-*/
-
-extern int s3c2410_dma_setflags(unsigned int channel,
-				unsigned int flags);
-
-/* s3c2410_dma_free
- *
- * free the dma channel (will also abort any outstanding operations)
-*/
-
-extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *);
-
-/* s3c2410_dma_enqueue
- *
- * place the given buffer onto the queue of operations for the channel.
- * The buffer must be allocated from dma coherent memory, or the Dcache/WB
- * drained before the buffer is given to the DMA system.
-*/
-
-extern int s3c2410_dma_enqueue(unsigned int channel, void *id,
-			       dma_addr_t data, int size);
-
-/* s3c2410_dma_config
- *
- * configure the dma channel
-*/
-
-extern int s3c2410_dma_config(unsigned int channel, int xferunit, int dcon);
-
-/* s3c2410_dma_devconfig
- *
- * configure the device we're talking to
-*/
-
-extern int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source,
-				 int hwcfg, unsigned long devaddr);
-
-/* s3c2410_dma_getposition
- *
- * get the position that the dma transfer is currently at
-*/
-
-extern int s3c2410_dma_getposition(unsigned int channel,
-				   dma_addr_t *src, dma_addr_t *dest);
-
-extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn);
-extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn);
-
-/* DMA Register definitions */
-
-#define S3C2410_DMA_DISRC       (0x00)
-#define S3C2410_DMA_DISRCC      (0x04)
-#define S3C2410_DMA_DIDST       (0x08)
-#define S3C2410_DMA_DIDSTC      (0x0C)
-#define S3C2410_DMA_DCON        (0x10)
-#define S3C2410_DMA_DSTAT       (0x14)
-#define S3C2410_DMA_DCSRC       (0x18)
-#define S3C2410_DMA_DCDST       (0x1C)
-#define S3C2410_DMA_DMASKTRIG   (0x20)
-#define S3C2412_DMA_DMAREQSEL	(0x24)
-#define S3C2443_DMA_DMAREQSEL	(0x24)
-
-#define S3C2410_DISRCC_INC	(1<<0)
-#define S3C2410_DISRCC_APB	(1<<1)
-
-#define S3C2410_DMASKTRIG_STOP   (1<<2)
-#define S3C2410_DMASKTRIG_ON     (1<<1)
-#define S3C2410_DMASKTRIG_SWTRIG (1<<0)
-
-#define S3C2410_DCON_DEMAND     (0<<31)
-#define S3C2410_DCON_HANDSHAKE  (1<<31)
-#define S3C2410_DCON_SYNC_PCLK  (0<<30)
-#define S3C2410_DCON_SYNC_HCLK  (1<<30)
-
-#define S3C2410_DCON_INTREQ     (1<<29)
-
-#define S3C2410_DCON_CH0_XDREQ0	(0<<24)
-#define S3C2410_DCON_CH0_UART0	(1<<24)
-#define S3C2410_DCON_CH0_SDI	(2<<24)
-#define S3C2410_DCON_CH0_TIMER	(3<<24)
-#define S3C2410_DCON_CH0_USBEP1	(4<<24)
-
-#define S3C2410_DCON_CH1_XDREQ1	(0<<24)
-#define S3C2410_DCON_CH1_UART1	(1<<24)
-#define S3C2410_DCON_CH1_I2SSDI	(2<<24)
-#define S3C2410_DCON_CH1_SPI	(3<<24)
-#define S3C2410_DCON_CH1_USBEP2	(4<<24)
-
-#define S3C2410_DCON_CH2_I2SSDO	(0<<24)
-#define S3C2410_DCON_CH2_I2SSDI	(1<<24)
-#define S3C2410_DCON_CH2_SDI	(2<<24)
-#define S3C2410_DCON_CH2_TIMER	(3<<24)
-#define S3C2410_DCON_CH2_USBEP3	(4<<24)
-
-#define S3C2410_DCON_CH3_UART2	(0<<24)
-#define S3C2410_DCON_CH3_SDI	(1<<24)
-#define S3C2410_DCON_CH3_SPI	(2<<24)
-#define S3C2410_DCON_CH3_TIMER	(3<<24)
-#define S3C2410_DCON_CH3_USBEP4	(4<<24)
-
-#define S3C2410_DCON_SRCSHIFT   (24)
-#define S3C2410_DCON_SRCMASK	(7<<24)
-
-#define S3C2410_DCON_BYTE       (0<<20)
-#define S3C2410_DCON_HALFWORD   (1<<20)
-#define S3C2410_DCON_WORD       (2<<20)
-
-#define S3C2410_DCON_AUTORELOAD (0<<22)
-#define S3C2410_DCON_NORELOAD   (1<<22)
-#define S3C2410_DCON_HWTRIG     (1<<23)
-
-#ifdef CONFIG_CPU_S3C2440
-#define S3C2440_DIDSTC_CHKINT	(1<<2)
-
-#define S3C2440_DCON_CH0_I2SSDO	(5<<24)
-#define S3C2440_DCON_CH0_PCMIN	(6<<24)
-
-#define S3C2440_DCON_CH1_PCMOUT	(5<<24)
-#define S3C2440_DCON_CH1_SDI	(6<<24)
-
-#define S3C2440_DCON_CH2_PCMIN	(5<<24)
-#define S3C2440_DCON_CH2_MICIN	(6<<24)
-
-#define S3C2440_DCON_CH3_MICIN	(5<<24)
-#define S3C2440_DCON_CH3_PCMOUT	(6<<24)
-#endif
-
-#ifdef CONFIG_CPU_S3C2412
-
-#define S3C2412_DMAREQSEL_SRC(x)	((x)<<1)
-
-#define S3C2412_DMAREQSEL_HW		(1)
-
-#define S3C2412_DMAREQSEL_SPI0TX	S3C2412_DMAREQSEL_SRC(0)
-#define S3C2412_DMAREQSEL_SPI0RX	S3C2412_DMAREQSEL_SRC(1)
-#define S3C2412_DMAREQSEL_SPI1TX	S3C2412_DMAREQSEL_SRC(2)
-#define S3C2412_DMAREQSEL_SPI1RX	S3C2412_DMAREQSEL_SRC(3)
-#define S3C2412_DMAREQSEL_I2STX		S3C2412_DMAREQSEL_SRC(4)
-#define S3C2412_DMAREQSEL_I2SRX		S3C2412_DMAREQSEL_SRC(5)
-#define S3C2412_DMAREQSEL_TIMER		S3C2412_DMAREQSEL_SRC(9)
-#define S3C2412_DMAREQSEL_SDI		S3C2412_DMAREQSEL_SRC(10)
-#define S3C2412_DMAREQSEL_USBEP1	S3C2412_DMAREQSEL_SRC(13)
-#define S3C2412_DMAREQSEL_USBEP2	S3C2412_DMAREQSEL_SRC(14)
-#define S3C2412_DMAREQSEL_USBEP3	S3C2412_DMAREQSEL_SRC(15)
-#define S3C2412_DMAREQSEL_USBEP4	S3C2412_DMAREQSEL_SRC(16)
-#define S3C2412_DMAREQSEL_XDREQ0	S3C2412_DMAREQSEL_SRC(17)
-#define S3C2412_DMAREQSEL_XDREQ1	S3C2412_DMAREQSEL_SRC(18)
-#define S3C2412_DMAREQSEL_UART0_0	S3C2412_DMAREQSEL_SRC(19)
-#define S3C2412_DMAREQSEL_UART0_1	S3C2412_DMAREQSEL_SRC(20)
-#define S3C2412_DMAREQSEL_UART1_0	S3C2412_DMAREQSEL_SRC(21)
-#define S3C2412_DMAREQSEL_UART1_1	S3C2412_DMAREQSEL_SRC(22)
-#define S3C2412_DMAREQSEL_UART2_0	S3C2412_DMAREQSEL_SRC(23)
-#define S3C2412_DMAREQSEL_UART2_1	S3C2412_DMAREQSEL_SRC(24)
-
-#endif
-
-#define S3C2443_DMAREQSEL_SRC(x)	((x)<<1)
-
-#define S3C2443_DMAREQSEL_HW		(1)
-
-#define S3C2443_DMAREQSEL_SPI0TX	S3C2443_DMAREQSEL_SRC(0)
-#define S3C2443_DMAREQSEL_SPI0RX	S3C2443_DMAREQSEL_SRC(1)
-#define S3C2443_DMAREQSEL_SPI1TX	S3C2443_DMAREQSEL_SRC(2)
-#define S3C2443_DMAREQSEL_SPI1RX	S3C2443_DMAREQSEL_SRC(3)
-#define S3C2443_DMAREQSEL_I2STX		S3C2443_DMAREQSEL_SRC(4)
-#define S3C2443_DMAREQSEL_I2SRX		S3C2443_DMAREQSEL_SRC(5)
-#define S3C2443_DMAREQSEL_TIMER		S3C2443_DMAREQSEL_SRC(9)
-#define S3C2443_DMAREQSEL_SDI		S3C2443_DMAREQSEL_SRC(10)
-#define S3C2443_DMAREQSEL_XDREQ0	S3C2443_DMAREQSEL_SRC(17)
-#define S3C2443_DMAREQSEL_XDREQ1	S3C2443_DMAREQSEL_SRC(18)
-#define S3C2443_DMAREQSEL_UART0_0	S3C2443_DMAREQSEL_SRC(19)
-#define S3C2443_DMAREQSEL_UART0_1	S3C2443_DMAREQSEL_SRC(20)
-#define S3C2443_DMAREQSEL_UART1_0	S3C2443_DMAREQSEL_SRC(21)
-#define S3C2443_DMAREQSEL_UART1_1	S3C2443_DMAREQSEL_SRC(22)
-#define S3C2443_DMAREQSEL_UART2_0	S3C2443_DMAREQSEL_SRC(23)
-#define S3C2443_DMAREQSEL_UART2_1	S3C2443_DMAREQSEL_SRC(24)
-#define S3C2443_DMAREQSEL_UART3_0	S3C2443_DMAREQSEL_SRC(25)
-#define S3C2443_DMAREQSEL_UART3_1	S3C2443_DMAREQSEL_SRC(26)
-#define S3C2443_DMAREQSEL_PCMOUT	S3C2443_DMAREQSEL_SRC(27)
-#define S3C2443_DMAREQSEL_PCMIN 	S3C2443_DMAREQSEL_SRC(28)
-#define S3C2443_DMAREQSEL_MICIN		S3C2443_DMAREQSEL_SRC(29)
-
 #endif /* __ASM_ARCH_DMA_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-core.h b/arch/arm/mach-s3c2410/include/mach/gpio-core.h
index 6c9fbb9..8fe1920 100644
--- a/arch/arm/mach-s3c2410/include/mach/gpio-core.h
+++ b/arch/arm/mach-s3c2410/include/mach/gpio-core.h
@@ -24,7 +24,7 @@
 {
 	struct s3c_gpio_chip *chip;
 
-	if (pin > S3C2410_GPG10)
+	if (pin > S3C2410_GPG(10))
 		return NULL;
 
 	chip = &s3c24xx_gpios[pin/32];
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-fns.h b/arch/arm/mach-s3c2410/include/mach/gpio-fns.h
new file mode 100644
index 0000000..801dff1
--- /dev/null
+++ b/arch/arm/mach-s3c2410/include/mach/gpio-fns.h
@@ -0,0 +1,103 @@
+/* arch/arm/mach-s3c2410/include/mach/gpio-fns.h
+ *
+ * Copyright (c) 2003,2009 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - hardware
+ *
+ * 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.
+*/
+
+/* These functions are in the to-be-removed category and it is strongly
+ * encouraged not to use these in new code. They will be marked deprecated
+ * very soon.
+ *
+ * Most of the functionality can be either replaced by the gpiocfg calls
+ * for the s3c platform or by the generic GPIOlib API.
+*/
+
+/* external functions for GPIO support
+ *
+ * These allow various different clients to access the same GPIO
+ * registers without conflicting. If your driver only owns the entire
+ * GPIO register, then it is safe to ioremap/__raw_{read|write} to it.
+*/
+
+/* s3c2410_gpio_cfgpin
+ *
+ * set the configuration of the given pin to the value passed.
+ *
+ * eg:
+ *    s3c2410_gpio_cfgpin(S3C2410_GPA(0), S3C2410_GPA0_ADDR0);
+ *    s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1);
+*/
+
+extern void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function);
+
+extern unsigned int s3c2410_gpio_getcfg(unsigned int pin);
+
+/* s3c2410_gpio_getirq
+ *
+ * turn the given pin number into the corresponding IRQ number
+ *
+ * returns:
+ *	< 0 = no interrupt for this pin
+ *	>=0 = interrupt number for the pin
+*/
+
+extern int s3c2410_gpio_getirq(unsigned int pin);
+
+#ifdef CONFIG_CPU_S3C2400
+
+extern int s3c2400_gpio_getirq(unsigned int pin);
+
+#endif /* CONFIG_CPU_S3C2400 */
+
+/* s3c2410_gpio_irqfilter
+ *
+ * set the irq filtering on the given pin
+ *
+ * on = 0 => disable filtering
+ *      1 => enable filtering
+ *
+ * config = S3C2410_EINTFLT_PCLK or S3C2410_EINTFLT_EXTCLK orred with
+ *          width of filter (0 through 63)
+ *
+ *
+*/
+
+extern int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
+				  unsigned int config);
+
+/* s3c2410_gpio_pullup
+ *
+ * configure the pull-up control on the given pin
+ *
+ * to = 1 => disable the pull-up
+ *      0 => enable the pull-up
+ *
+ * eg;
+ *
+ *   s3c2410_gpio_pullup(S3C2410_GPB(0), 0);
+ *   s3c2410_gpio_pullup(S3C2410_GPE(8), 0);
+*/
+
+extern void s3c2410_gpio_pullup(unsigned int pin, unsigned int to);
+
+/* s3c2410_gpio_getpull
+ *
+ * Read the state of the pull-up on a given pin
+ *
+ * return:
+ *	< 0 => error code
+ *	  0 => enabled
+ *	  1 => disabled
+*/
+
+extern int s3c2410_gpio_getpull(unsigned int pin);
+
+extern void s3c2410_gpio_setpin(unsigned int pin, unsigned int to);
+
+extern unsigned int s3c2410_gpio_getpin(unsigned int pin);
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-nrs.h b/arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
index ce1ec69..2edbb9c 100644
--- a/arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
+++ b/arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
@@ -11,6 +11,9 @@
  * published by the Free Software Foundation.
 */
 
+#ifndef __MACH_GPIONRS_H
+#define __MACH_GPIONRS_H
+
 #define S3C2410_GPIONO(bank,offset) ((bank) + (offset))
 
 #define S3C2410_GPIO_BANKA   (32*0)
@@ -21,3 +24,70 @@
 #define S3C2410_GPIO_BANKF   (32*5)
 #define S3C2410_GPIO_BANKG   (32*6)
 #define S3C2410_GPIO_BANKH   (32*7)
+
+/* GPIO bank sizes */
+#define S3C2410_GPIO_A_NR	(32)
+#define S3C2410_GPIO_B_NR	(32)
+#define S3C2410_GPIO_C_NR	(32)
+#define S3C2410_GPIO_D_NR	(32)
+#define S3C2410_GPIO_E_NR	(32)
+#define S3C2410_GPIO_F_NR	(32)
+#define S3C2410_GPIO_G_NR	(32)
+#define S3C2410_GPIO_H_NR	(32)
+
+#if CONFIG_S3C_GPIO_SPACE != 0
+#error CONFIG_S3C_GPIO_SPACE cannot be zero at the moment
+#endif
+
+#define S3C2410_GPIO_NEXT(__gpio) \
+	((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)
+
+#ifndef __ASSEMBLY__
+
+enum s3c_gpio_number {
+	S3C2410_GPIO_A_START = 0,
+	S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A),
+	S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B),
+	S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C),
+	S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D),
+	S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E),
+	S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F),
+	S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G),
+};
+
+#endif /* __ASSEMBLY__ */
+
+/* S3C2410 GPIO number definitions. */
+
+#define S3C2410_GPA(_nr)	(S3C2410_GPIO_A_START + (_nr))
+#define S3C2410_GPB(_nr)	(S3C2410_GPIO_B_START + (_nr))
+#define S3C2410_GPC(_nr)	(S3C2410_GPIO_C_START + (_nr))
+#define S3C2410_GPD(_nr)	(S3C2410_GPIO_D_START + (_nr))
+#define S3C2410_GPE(_nr)	(S3C2410_GPIO_E_START + (_nr))
+#define S3C2410_GPF(_nr)	(S3C2410_GPIO_F_START + (_nr))
+#define S3C2410_GPG(_nr)	(S3C2410_GPIO_G_START + (_nr))
+#define S3C2410_GPH(_nr)	(S3C2410_GPIO_H_START + (_nr))
+
+/* compatibility until drivers can be modified */
+
+#define S3C2410_GPA0	S3C2410_GPA(0)
+#define S3C2410_GPA1	S3C2410_GPA(1)
+#define S3C2410_GPA3	S3C2410_GPA(3)
+#define S3C2410_GPA7	S3C2410_GPA(7)
+
+#define S3C2410_GPE0	S3C2410_GPE(0)
+#define S3C2410_GPE1	S3C2410_GPE(1)
+#define S3C2410_GPE2	S3C2410_GPE(2)
+#define S3C2410_GPE3	S3C2410_GPE(3)
+#define S3C2410_GPE4	S3C2410_GPE(4)
+#define S3C2410_GPE5	S3C2410_GPE(5)
+#define S3C2410_GPE6	S3C2410_GPE(6)
+#define S3C2410_GPE7	S3C2410_GPE(7)
+#define S3C2410_GPE8	S3C2410_GPE(8)
+#define S3C2410_GPE9	S3C2410_GPE(9)
+#define S3C2410_GPE10	S3C2410_GPE(10)
+
+#define S3C2410_GPH10	S3C2410_GPH(10)
+
+#endif /* __MACH_GPIONRS_H */
+
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio.h b/arch/arm/mach-s3c2410/include/mach/gpio.h
index 51a88cf..15f0b3e 100644
--- a/arch/arm/mach-s3c2410/include/mach/gpio.h
+++ b/arch/arm/mach-s3c2410/include/mach/gpio.h
@@ -24,5 +24,6 @@
 
 #include <asm-generic/gpio.h>
 #include <mach/gpio-nrs.h>
+#include <mach/gpio-fns.h>
 
 #define S3C_GPIO_END	(S3C2410_GPIO_BANKH + 32)
diff --git a/arch/arm/mach-s3c2410/include/mach/hardware.h b/arch/arm/mach-s3c2410/include/mach/hardware.h
index 74d5a1a..aef5631 100644
--- a/arch/arm/mach-s3c2410/include/mach/hardware.h
+++ b/arch/arm/mach-s3c2410/include/mach/hardware.h
@@ -15,101 +15,6 @@
 
 #ifndef __ASSEMBLY__
 
-/* external functions for GPIO support
- *
- * These allow various different clients to access the same GPIO
- * registers without conflicting. If your driver only owns the entire
- * GPIO register, then it is safe to ioremap/__raw_{read|write} to it.
-*/
-
-/* s3c2410_gpio_cfgpin
- *
- * set the configuration of the given pin to the value passed.
- *
- * eg:
- *    s3c2410_gpio_cfgpin(S3C2410_GPA0, S3C2410_GPA0_ADDR0);
- *    s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1);
-*/
-
-extern void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function);
-
-extern unsigned int s3c2410_gpio_getcfg(unsigned int pin);
-
-/* s3c2410_gpio_getirq
- *
- * turn the given pin number into the corresponding IRQ number
- *
- * returns:
- *	< 0 = no interrupt for this pin
- *	>=0 = interrupt number for the pin
-*/
-
-extern int s3c2410_gpio_getirq(unsigned int pin);
-
-/* s3c2410_gpio_irq2pin
- *
- * turn the given irq number into the corresponding GPIO number
- *
- * returns:
- *	< 0 = no pin
- *	>=0 = gpio pin number
-*/
-
-extern int s3c2410_gpio_irq2pin(unsigned int irq);
-
-#ifdef CONFIG_CPU_S3C2400
-
-extern int s3c2400_gpio_getirq(unsigned int pin);
-
-#endif /* CONFIG_CPU_S3C2400 */
-
-/* s3c2410_gpio_irqfilter
- *
- * set the irq filtering on the given pin
- *
- * on = 0 => disable filtering
- *      1 => enable filtering
- *
- * config = S3C2410_EINTFLT_PCLK or S3C2410_EINTFLT_EXTCLK orred with
- *          width of filter (0 through 63)
- *
- *
-*/
-
-extern int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
-				  unsigned int config);
-
-/* s3c2410_gpio_pullup
- *
- * configure the pull-up control on the given pin
- *
- * to = 1 => disable the pull-up
- *      0 => enable the pull-up
- *
- * eg;
- *
- *   s3c2410_gpio_pullup(S3C2410_GPB0, 0);
- *   s3c2410_gpio_pullup(S3C2410_GPE8, 0);
-*/
-
-extern void s3c2410_gpio_pullup(unsigned int pin, unsigned int to);
-
-/* s3c2410_gpio_getpull
- *
- * Read the state of the pull-up on a given pin
- *
- * return:
- *	< 0 => error code
- *	  0 => enabled
- *	  1 => disabled
-*/
-
-extern int s3c2410_gpio_getpull(unsigned int pin);
-
-extern void s3c2410_gpio_setpin(unsigned int pin, unsigned int to);
-
-extern unsigned int s3c2410_gpio_getpin(unsigned int pin);
-
 extern unsigned int s3c2410_modify_misccr(unsigned int clr, unsigned int chg);
 
 #ifdef CONFIG_CPU_S3C2440
diff --git a/arch/arm/mach-s3c2410/include/mach/map.h b/arch/arm/mach-s3c2410/include/mach/map.h
index 255fdfe..e99b212 100644
--- a/arch/arm/mach-s3c2410/include/mach/map.h
+++ b/arch/arm/mach-s3c2410/include/mach/map.h
@@ -84,7 +84,6 @@
 
 #define S3C24XX_PA_IRQ      S3C2410_PA_IRQ
 #define S3C24XX_PA_MEMCTRL  S3C2410_PA_MEMCTRL
-#define S3C24XX_PA_USBHOST  S3C2410_PA_USBHOST
 #define S3C24XX_PA_DMA      S3C2410_PA_DMA
 #define S3C24XX_PA_CLKPWR   S3C2410_PA_CLKPWR
 #define S3C24XX_PA_LCD      S3C2410_PA_LCD
@@ -102,6 +101,7 @@
 
 #define S3C_PA_IIC          S3C2410_PA_IIC
 #define S3C_PA_UART	    S3C24XX_PA_UART
+#define S3C_PA_USBHOST	S3C2410_PA_USBHOST
 #define S3C_PA_HSMMC0	    S3C2443_PA_HSMMC
 
 #endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-gpio.h b/arch/arm/mach-s3c2410/include/mach/regs-gpio.h
index 35a03df..b278d0c 100644
--- a/arch/arm/mach-s3c2410/include/mach/regs-gpio.h
+++ b/arch/arm/mach-s3c2410/include/mach/regs-gpio.h
@@ -69,104 +69,58 @@
 #define S3C2400_GPACON	   S3C2410_GPIOREG(0x00)
 #define S3C2400_GPADAT	   S3C2410_GPIOREG(0x04)
 
-#define S3C2410_GPA0         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 0)
-#define S3C2410_GPA0_OUT     (0<<0)
 #define S3C2410_GPA0_ADDR0   (1<<0)
 
-#define S3C2410_GPA1         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 1)
-#define S3C2410_GPA1_OUT     (0<<1)
 #define S3C2410_GPA1_ADDR16  (1<<1)
 
-#define S3C2410_GPA2         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 2)
-#define S3C2410_GPA2_OUT     (0<<2)
 #define S3C2410_GPA2_ADDR17  (1<<2)
 
-#define S3C2410_GPA3         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 3)
-#define S3C2410_GPA3_OUT     (0<<3)
 #define S3C2410_GPA3_ADDR18  (1<<3)
 
-#define S3C2410_GPA4         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 4)
-#define S3C2410_GPA4_OUT     (0<<4)
 #define S3C2410_GPA4_ADDR19  (1<<4)
 
-#define S3C2410_GPA5         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 5)
-#define S3C2410_GPA5_OUT     (0<<5)
 #define S3C2410_GPA5_ADDR20  (1<<5)
 
-#define S3C2410_GPA6         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 6)
-#define S3C2410_GPA6_OUT     (0<<6)
 #define S3C2410_GPA6_ADDR21  (1<<6)
 
-#define S3C2410_GPA7         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 7)
-#define S3C2410_GPA7_OUT     (0<<7)
 #define S3C2410_GPA7_ADDR22  (1<<7)
 
-#define S3C2410_GPA8         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 8)
-#define S3C2410_GPA8_OUT     (0<<8)
 #define S3C2410_GPA8_ADDR23  (1<<8)
 
-#define S3C2410_GPA9         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 9)
-#define S3C2410_GPA9_OUT     (0<<9)
 #define S3C2410_GPA9_ADDR24  (1<<9)
 
-#define S3C2410_GPA10        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 10)
-#define S3C2410_GPA10_OUT    (0<<10)
 #define S3C2410_GPA10_ADDR25 (1<<10)
 #define S3C2400_GPA10_SCKE   (1<<10)
 
-#define S3C2410_GPA11        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 11)
-#define S3C2410_GPA11_OUT    (0<<11)
 #define S3C2410_GPA11_ADDR26 (1<<11)
 #define S3C2400_GPA11_nCAS0  (1<<11)
 
-#define S3C2410_GPA12        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 12)
-#define S3C2410_GPA12_OUT    (0<<12)
 #define S3C2410_GPA12_nGCS1  (1<<12)
 #define S3C2400_GPA12_nCAS1  (1<<12)
 
-#define S3C2410_GPA13        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 13)
-#define S3C2410_GPA13_OUT    (0<<13)
 #define S3C2410_GPA13_nGCS2  (1<<13)
 #define S3C2400_GPA13_nGCS1  (1<<13)
 
-#define S3C2410_GPA14        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 14)
-#define S3C2410_GPA14_OUT    (0<<14)
 #define S3C2410_GPA14_nGCS3  (1<<14)
 #define S3C2400_GPA14_nGCS2  (1<<14)
 
-#define S3C2410_GPA15        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 15)
-#define S3C2410_GPA15_OUT    (0<<15)
 #define S3C2410_GPA15_nGCS4  (1<<15)
 #define S3C2400_GPA15_nGCS3  (1<<15)
 
-#define S3C2410_GPA16        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 16)
-#define S3C2410_GPA16_OUT    (0<<16)
 #define S3C2410_GPA16_nGCS5  (1<<16)
 #define S3C2400_GPA16_nGCS4  (1<<16)
 
-#define S3C2410_GPA17        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 17)
-#define S3C2410_GPA17_OUT    (0<<17)
 #define S3C2410_GPA17_CLE    (1<<17)
 #define S3C2400_GPA17_nGCS5  (1<<17)
 
-#define S3C2410_GPA18        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 18)
-#define S3C2410_GPA18_OUT    (0<<18)
 #define S3C2410_GPA18_ALE    (1<<18)
 
-#define S3C2410_GPA19        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 19)
-#define S3C2410_GPA19_OUT    (0<<19)
 #define S3C2410_GPA19_nFWE   (1<<19)
 
-#define S3C2410_GPA20        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 20)
-#define S3C2410_GPA20_OUT    (0<<20)
 #define S3C2410_GPA20_nFRE   (1<<20)
 
-#define S3C2410_GPA21        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 21)
-#define S3C2410_GPA21_OUT    (0<<21)
 #define S3C2410_GPA21_nRSTOUT (1<<21)
 
-#define S3C2410_GPA22        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 22)
-#define S3C2410_GPA22_OUT    (0<<22)
 #define S3C2410_GPA22_nFCE   (1<<22)
 
 /* 0x08 and 0x0c are reserved on S3C2410 */
@@ -194,107 +148,69 @@
 
 /* no i/o pin in port b can have value 3 (unless it is a s3c2443) ! */
 
-#define S3C2410_GPB0         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 0)
-#define S3C2410_GPB0_INP     (0x00 << 0)
-#define S3C2410_GPB0_OUTP    (0x01 << 0)
 #define S3C2410_GPB0_TOUT0   (0x02 << 0)
 #define S3C2400_GPB0_DATA16  (0x02 << 0)
 
-#define S3C2410_GPB1         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 1)
-#define S3C2410_GPB1_INP     (0x00 << 2)
-#define S3C2410_GPB1_OUTP    (0x01 << 2)
 #define S3C2410_GPB1_TOUT1   (0x02 << 2)
 #define S3C2400_GPB1_DATA17  (0x02 << 2)
 
-#define S3C2410_GPB2         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 2)
-#define S3C2410_GPB2_INP     (0x00 << 4)
-#define S3C2410_GPB2_OUTP    (0x01 << 4)
 #define S3C2410_GPB2_TOUT2   (0x02 << 4)
 #define S3C2400_GPB2_DATA18  (0x02 << 4)
 #define S3C2400_GPB2_TCLK1   (0x03 << 4)
 
-#define S3C2410_GPB3         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 3)
-#define S3C2410_GPB3_INP     (0x00 << 6)
-#define S3C2410_GPB3_OUTP    (0x01 << 6)
 #define S3C2410_GPB3_TOUT3   (0x02 << 6)
 #define S3C2400_GPB3_DATA19  (0x02 << 6)
 #define S3C2400_GPB3_TXD1    (0x03 << 6)
 
-#define S3C2410_GPB4         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 4)
-#define S3C2410_GPB4_INP     (0x00 << 8)
-#define S3C2410_GPB4_OUTP    (0x01 << 8)
 #define S3C2410_GPB4_TCLK0   (0x02 << 8)
 #define S3C2400_GPB4_DATA20  (0x02 << 8)
 #define S3C2410_GPB4_MASK    (0x03 << 8)
 #define S3C2400_GPB4_RXD1    (0x03 << 8)
 #define S3C2400_GPB4_MASK    (0x03 << 8)
 
-#define S3C2410_GPB5         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5)
-#define S3C2410_GPB5_INP     (0x00 << 10)
-#define S3C2410_GPB5_OUTP    (0x01 << 10)
 #define S3C2410_GPB5_nXBACK  (0x02 << 10)
 #define S3C2443_GPB5_XBACK   (0x03 << 10)
 #define S3C2400_GPB5_DATA21  (0x02 << 10)
 #define S3C2400_GPB5_nCTS1   (0x03 << 10)
 
-#define S3C2410_GPB6         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 6)
-#define S3C2410_GPB6_INP     (0x00 << 12)
-#define S3C2410_GPB6_OUTP    (0x01 << 12)
 #define S3C2410_GPB6_nXBREQ  (0x02 << 12)
 #define S3C2443_GPB6_XBREQ   (0x03 << 12)
 #define S3C2400_GPB6_DATA22  (0x02 << 12)
 #define S3C2400_GPB6_nRTS1   (0x03 << 12)
 
-#define S3C2410_GPB7         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 7)
-#define S3C2410_GPB7_INP     (0x00 << 14)
-#define S3C2410_GPB7_OUTP    (0x01 << 14)
 #define S3C2410_GPB7_nXDACK1 (0x02 << 14)
 #define S3C2443_GPB7_XDACK1  (0x03 << 14)
 #define S3C2400_GPB7_DATA23  (0x02 << 14)
 
-#define S3C2410_GPB8         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 8)
-#define S3C2410_GPB8_INP     (0x00 << 16)
-#define S3C2410_GPB8_OUTP    (0x01 << 16)
 #define S3C2410_GPB8_nXDREQ1 (0x02 << 16)
 #define S3C2400_GPB8_DATA24  (0x02 << 16)
 
-#define S3C2410_GPB9         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 9)
-#define S3C2410_GPB9_INP     (0x00 << 18)
-#define S3C2410_GPB9_OUTP    (0x01 << 18)
 #define S3C2410_GPB9_nXDACK0 (0x02 << 18)
 #define S3C2443_GPB9_XDACK0  (0x03 << 18)
 #define S3C2400_GPB9_DATA25  (0x02 << 18)
 #define S3C2400_GPB9_I2SSDI  (0x03 << 18)
 
-#define S3C2410_GPB10        S3C2410_GPIONO(S3C2410_GPIO_BANKB, 10)
-#define S3C2410_GPB10_INP    (0x00 << 20)
-#define S3C2410_GPB10_OUTP   (0x01 << 20)
 #define S3C2410_GPB10_nXDRE0 (0x02 << 20)
 #define S3C2443_GPB10_XDREQ0 (0x03 << 20)
 #define S3C2400_GPB10_DATA26 (0x02 << 20)
 #define S3C2400_GPB10_nSS    (0x03 << 20)
 
-#define S3C2400_GPB11        S3C2410_GPIONO(S3C2410_GPIO_BANKB, 11)
 #define S3C2400_GPB11_INP    (0x00 << 22)
 #define S3C2400_GPB11_OUTP   (0x01 << 22)
 #define S3C2400_GPB11_DATA27 (0x02 << 22)
 
-#define S3C2400_GPB12        S3C2410_GPIONO(S3C2410_GPIO_BANKB, 12)
 #define S3C2400_GPB12_INP    (0x00 << 24)
 #define S3C2400_GPB12_OUTP   (0x01 << 24)
 #define S3C2400_GPB12_DATA28 (0x02 << 24)
 
-#define S3C2400_GPB13        S3C2410_GPIONO(S3C2410_GPIO_BANKB, 13)
 #define S3C2400_GPB13_INP    (0x00 << 26)
 #define S3C2400_GPB13_OUTP   (0x01 << 26)
 #define S3C2400_GPB13_DATA29 (0x02 << 26)
 
-#define S3C2400_GPB14        S3C2410_GPIONO(S3C2410_GPIO_BANKB, 14)
 #define S3C2400_GPB14_INP    (0x00 << 28)
 #define S3C2400_GPB14_OUTP   (0x01 << 28)
 #define S3C2400_GPB14_DATA30 (0x02 << 28)
 
-#define S3C2400_GPB15        S3C2410_GPIONO(S3C2410_GPIO_BANKB, 15)
 #define S3C2400_GPB15_INP    (0x00 << 30)
 #define S3C2400_GPB15_OUTP   (0x01 << 30)
 #define S3C2400_GPB15_DATA31 (0x02 << 30)
@@ -315,99 +231,51 @@
 #define S3C2400_GPCDAT	   S3C2410_GPIOREG(0x18)
 #define S3C2400_GPCUP	   S3C2410_GPIOREG(0x1C)
 
-#define S3C2410_GPC0            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 0)
-#define S3C2410_GPC0_INP	(0x00 << 0)
-#define S3C2410_GPC0_OUTP	(0x01 << 0)
 #define S3C2410_GPC0_LEND	(0x02 << 0)
 #define S3C2400_GPC0_VD0 	(0x02 << 0)
 
-#define S3C2410_GPC1            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 1)
-#define S3C2410_GPC1_INP	(0x00 << 2)
-#define S3C2410_GPC1_OUTP	(0x01 << 2)
 #define S3C2410_GPC1_VCLK	(0x02 << 2)
 #define S3C2400_GPC1_VD1 	(0x02 << 2)
 
-#define S3C2410_GPC2            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 2)
-#define S3C2410_GPC2_INP	(0x00 << 4)
-#define S3C2410_GPC2_OUTP	(0x01 << 4)
 #define S3C2410_GPC2_VLINE	(0x02 << 4)
 #define S3C2400_GPC2_VD2  	(0x02 << 4)
 
-#define S3C2410_GPC3            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 3)
-#define S3C2410_GPC3_INP	(0x00 << 6)
-#define S3C2410_GPC3_OUTP	(0x01 << 6)
 #define S3C2410_GPC3_VFRAME	(0x02 << 6)
 #define S3C2400_GPC3_VD3   	(0x02 << 6)
 
-#define S3C2410_GPC4            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 4)
-#define S3C2410_GPC4_INP	(0x00 << 8)
-#define S3C2410_GPC4_OUTP	(0x01 << 8)
 #define S3C2410_GPC4_VM		(0x02 << 8)
 #define S3C2400_GPC4_VD4	(0x02 << 8)
 
-#define S3C2410_GPC5            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 5)
-#define S3C2410_GPC5_INP	(0x00 << 10)
-#define S3C2410_GPC5_OUTP	(0x01 << 10)
 #define S3C2410_GPC5_LCDVF0	(0x02 << 10)
 #define S3C2400_GPC5_VD5   	(0x02 << 10)
 
-#define S3C2410_GPC6            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 6)
-#define S3C2410_GPC6_INP	(0x00 << 12)
-#define S3C2410_GPC6_OUTP	(0x01 << 12)
 #define S3C2410_GPC6_LCDVF1	(0x02 << 12)
 #define S3C2400_GPC6_VD6   	(0x02 << 12)
 
-#define S3C2410_GPC7            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 7)
-#define S3C2410_GPC7_INP	(0x00 << 14)
-#define S3C2410_GPC7_OUTP	(0x01 << 14)
 #define S3C2410_GPC7_LCDVF2	(0x02 << 14)
 #define S3C2400_GPC7_VD7   	(0x02 << 14)
 
-#define S3C2410_GPC8            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 8)
-#define S3C2410_GPC8_INP	(0x00 << 16)
-#define S3C2410_GPC8_OUTP	(0x01 << 16)
 #define S3C2410_GPC8_VD0	(0x02 << 16)
 #define S3C2400_GPC8_VD8	(0x02 << 16)
 
-#define S3C2410_GPC9            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 9)
-#define S3C2410_GPC9_INP	(0x00 << 18)
-#define S3C2410_GPC9_OUTP	(0x01 << 18)
 #define S3C2410_GPC9_VD1	(0x02 << 18)
 #define S3C2400_GPC9_VD9	(0x02 << 18)
 
-#define S3C2410_GPC10           S3C2410_GPIONO(S3C2410_GPIO_BANKC, 10)
-#define S3C2410_GPC10_INP	(0x00 << 20)
-#define S3C2410_GPC10_OUTP	(0x01 << 20)
 #define S3C2410_GPC10_VD2	(0x02 << 20)
 #define S3C2400_GPC10_VD10	(0x02 << 20)
 
-#define S3C2410_GPC11           S3C2410_GPIONO(S3C2410_GPIO_BANKC, 11)
-#define S3C2410_GPC11_INP	(0x00 << 22)
-#define S3C2410_GPC11_OUTP	(0x01 << 22)
 #define S3C2410_GPC11_VD3	(0x02 << 22)
 #define S3C2400_GPC11_VD11	(0x02 << 22)
 
-#define S3C2410_GPC12           S3C2410_GPIONO(S3C2410_GPIO_BANKC, 12)
-#define S3C2410_GPC12_INP	(0x00 << 24)
-#define S3C2410_GPC12_OUTP	(0x01 << 24)
 #define S3C2410_GPC12_VD4	(0x02 << 24)
 #define S3C2400_GPC12_VD12	(0x02 << 24)
 
-#define S3C2410_GPC13           S3C2410_GPIONO(S3C2410_GPIO_BANKC, 13)
-#define S3C2410_GPC13_INP	(0x00 << 26)
-#define S3C2410_GPC13_OUTP	(0x01 << 26)
 #define S3C2410_GPC13_VD5	(0x02 << 26)
 #define S3C2400_GPC13_VD13	(0x02 << 26)
 
-#define S3C2410_GPC14           S3C2410_GPIONO(S3C2410_GPIO_BANKC, 14)
-#define S3C2410_GPC14_INP	(0x00 << 28)
-#define S3C2410_GPC14_OUTP	(0x01 << 28)
 #define S3C2410_GPC14_VD6	(0x02 << 28)
 #define S3C2400_GPC14_VD14	(0x02 << 28)
 
-#define S3C2410_GPC15           S3C2410_GPIONO(S3C2410_GPIO_BANKC, 15)
-#define S3C2410_GPC15_INP	(0x00 << 30)
-#define S3C2410_GPC15_OUTP	(0x01 << 30)
 #define S3C2410_GPC15_VD7	(0x02 << 30)
 #define S3C2400_GPC15_VD15	(0x02 << 30)
 
@@ -432,99 +300,51 @@
 #define S3C2400_GPDDAT	   S3C2410_GPIOREG(0x24)
 #define S3C2400_GPDUP	   S3C2410_GPIOREG(0x28)
 
-#define S3C2410_GPD0            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 0)
-#define S3C2410_GPD0_INP	(0x00 << 0)
-#define S3C2410_GPD0_OUTP	(0x01 << 0)
 #define S3C2410_GPD0_VD8	(0x02 << 0)
 #define S3C2400_GPD0_VFRAME	(0x02 << 0)
 #define S3C2442_GPD0_nSPICS1	(0x03 << 0)
 
-#define S3C2410_GPD1            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 1)
-#define S3C2410_GPD1_INP	(0x00 << 2)
-#define S3C2410_GPD1_OUTP	(0x01 << 2)
 #define S3C2410_GPD1_VD9	(0x02 << 2)
 #define S3C2400_GPD1_VM		(0x02 << 2)
 #define S3C2442_GPD1_SPICLK1	(0x03 << 2)
 
-#define S3C2410_GPD2            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 2)
-#define S3C2410_GPD2_INP	(0x00 << 4)
-#define S3C2410_GPD2_OUTP	(0x01 << 4)
 #define S3C2410_GPD2_VD10	(0x02 << 4)
 #define S3C2400_GPD2_VLINE	(0x02 << 4)
 
-#define S3C2410_GPD3            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 3)
-#define S3C2410_GPD3_INP	(0x00 << 6)
-#define S3C2410_GPD3_OUTP	(0x01 << 6)
 #define S3C2410_GPD3_VD11	(0x02 << 6)
 #define S3C2400_GPD3_VCLK	(0x02 << 6)
 
-#define S3C2410_GPD4            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 4)
-#define S3C2410_GPD4_INP	(0x00 << 8)
-#define S3C2410_GPD4_OUTP	(0x01 << 8)
 #define S3C2410_GPD4_VD12	(0x02 << 8)
 #define S3C2400_GPD4_LEND	(0x02 << 8)
 
-#define S3C2410_GPD5            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 5)
-#define S3C2410_GPD5_INP	(0x00 << 10)
-#define S3C2410_GPD5_OUTP	(0x01 << 10)
 #define S3C2410_GPD5_VD13	(0x02 << 10)
 #define S3C2400_GPD5_TOUT0	(0x02 << 10)
 
-#define S3C2410_GPD6            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 6)
-#define S3C2410_GPD6_INP	(0x00 << 12)
-#define S3C2410_GPD6_OUTP	(0x01 << 12)
 #define S3C2410_GPD6_VD14	(0x02 << 12)
 #define S3C2400_GPD6_TOUT1	(0x02 << 12)
 
-#define S3C2410_GPD7            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 7)
-#define S3C2410_GPD7_INP	(0x00 << 14)
-#define S3C2410_GPD7_OUTP	(0x01 << 14)
 #define S3C2410_GPD7_VD15	(0x02 << 14)
 #define S3C2400_GPD7_TOUT2	(0x02 << 14)
 
-#define S3C2410_GPD8            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 8)
-#define S3C2410_GPD8_INP	(0x00 << 16)
-#define S3C2410_GPD8_OUTP	(0x01 << 16)
 #define S3C2410_GPD8_VD16	(0x02 << 16)
 #define S3C2400_GPD8_TOUT3	(0x02 << 16)
 
-#define S3C2410_GPD9            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 9)
-#define S3C2410_GPD9_INP	(0x00 << 18)
-#define S3C2410_GPD9_OUTP	(0x01 << 18)
 #define S3C2410_GPD9_VD17	(0x02 << 18)
 #define S3C2400_GPD9_TCLK0	(0x02 << 18)
 #define S3C2410_GPD9_MASK       (0x03 << 18)
 
-#define S3C2410_GPD10           S3C2410_GPIONO(S3C2410_GPIO_BANKD, 10)
-#define S3C2410_GPD10_INP	(0x00 << 20)
-#define S3C2410_GPD10_OUTP	(0x01 << 20)
 #define S3C2410_GPD10_VD18	(0x02 << 20)
 #define S3C2400_GPD10_nWAIT	(0x02 << 20)
 
-#define S3C2410_GPD11           S3C2410_GPIONO(S3C2410_GPIO_BANKD, 11)
-#define S3C2410_GPD11_INP	(0x00 << 22)
-#define S3C2410_GPD11_OUTP	(0x01 << 22)
 #define S3C2410_GPD11_VD19	(0x02 << 22)
 
-#define S3C2410_GPD12           S3C2410_GPIONO(S3C2410_GPIO_BANKD, 12)
-#define S3C2410_GPD12_INP	(0x00 << 24)
-#define S3C2410_GPD12_OUTP	(0x01 << 24)
 #define S3C2410_GPD12_VD20	(0x02 << 24)
 
-#define S3C2410_GPD13           S3C2410_GPIONO(S3C2410_GPIO_BANKD, 13)
-#define S3C2410_GPD13_INP	(0x00 << 26)
-#define S3C2410_GPD13_OUTP	(0x01 << 26)
 #define S3C2410_GPD13_VD21	(0x02 << 26)
 
-#define S3C2410_GPD14           S3C2410_GPIONO(S3C2410_GPIO_BANKD, 14)
-#define S3C2410_GPD14_INP	(0x00 << 28)
-#define S3C2410_GPD14_OUTP	(0x01 << 28)
 #define S3C2410_GPD14_VD22	(0x02 << 28)
 #define S3C2410_GPD14_nSS1	(0x03 << 28)
 
-#define S3C2410_GPD15           S3C2410_GPIONO(S3C2410_GPIO_BANKD, 15)
-#define S3C2410_GPD15_INP	(0x00 << 30)
-#define S3C2410_GPD15_OUTP	(0x01 << 30)
 #define S3C2410_GPD15_VD23	(0x02 << 30)
 #define S3C2410_GPD15_nSS0	(0x03 << 30)
 
@@ -550,34 +370,22 @@
 #define S3C2400_GPEDAT	   S3C2410_GPIOREG(0x30)
 #define S3C2400_GPEUP	   S3C2410_GPIOREG(0x34)
 
-#define S3C2410_GPE0           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 0)
-#define S3C2410_GPE0_INP       (0x00 << 0)
-#define S3C2410_GPE0_OUTP      (0x01 << 0)
 #define S3C2410_GPE0_I2SLRCK   (0x02 << 0)
 #define S3C2443_GPE0_AC_nRESET (0x03 << 0)
 #define S3C2400_GPE0_EINT0     (0x02 << 0)
 #define S3C2410_GPE0_MASK      (0x03 << 0)
 
-#define S3C2410_GPE1           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 1)
-#define S3C2410_GPE1_INP       (0x00 << 2)
-#define S3C2410_GPE1_OUTP      (0x01 << 2)
 #define S3C2410_GPE1_I2SSCLK   (0x02 << 2)
 #define S3C2443_GPE1_AC_SYNC   (0x03 << 2)
 #define S3C2400_GPE1_EINT1     (0x02 << 2)
 #define S3C2400_GPE1_nSS       (0x03 << 2)
 #define S3C2410_GPE1_MASK      (0x03 << 2)
 
-#define S3C2410_GPE2           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 2)
-#define S3C2410_GPE2_INP       (0x00 << 4)
-#define S3C2410_GPE2_OUTP      (0x01 << 4)
 #define S3C2410_GPE2_CDCLK     (0x02 << 4)
 #define S3C2443_GPE2_AC_BITCLK (0x03 << 4)
 #define S3C2400_GPE2_EINT2     (0x02 << 4)
 #define S3C2400_GPE2_I2SSDI    (0x03 << 4)
 
-#define S3C2410_GPE3           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 3)
-#define S3C2410_GPE3_INP       (0x00 << 6)
-#define S3C2410_GPE3_OUTP      (0x01 << 6)
 #define S3C2410_GPE3_I2SSDI    (0x02 << 6)
 #define S3C2443_GPE3_AC_SDI    (0x03 << 6)
 #define S3C2400_GPE3_EINT3     (0x02 << 6)
@@ -585,9 +393,6 @@
 #define S3C2410_GPE3_nSS0      (0x03 << 6)
 #define S3C2410_GPE3_MASK      (0x03 << 6)
 
-#define S3C2410_GPE4           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 4)
-#define S3C2410_GPE4_INP       (0x00 << 8)
-#define S3C2410_GPE4_OUTP      (0x01 << 8)
 #define S3C2410_GPE4_I2SSDO    (0x02 << 8)
 #define S3C2443_GPE4_AC_SDO    (0x03 << 8)
 #define S3C2400_GPE4_EINT4     (0x02 << 8)
@@ -595,81 +400,48 @@
 #define S3C2410_GPE4_I2SSDI    (0x03 << 8)
 #define S3C2410_GPE4_MASK      (0x03 << 8)
 
-#define S3C2410_GPE5           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 5)
-#define S3C2410_GPE5_INP       (0x00 << 10)
-#define S3C2410_GPE5_OUTP      (0x01 << 10)
 #define S3C2410_GPE5_SDCLK     (0x02 << 10)
 #define S3C2443_GPE5_SD1_CLK   (0x02 << 10)
 #define S3C2400_GPE5_EINT5     (0x02 << 10)
 #define S3C2400_GPE5_TCLK1     (0x03 << 10)
 
-#define S3C2410_GPE6           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 6)
-#define S3C2410_GPE6_INP       (0x00 << 12)
-#define S3C2410_GPE6_OUTP      (0x01 << 12)
 #define S3C2410_GPE6_SDCMD     (0x02 << 12)
 #define S3C2443_GPE6_SD1_CMD   (0x02 << 12)
 #define S3C2443_GPE6_AC_BITCLK (0x03 << 12)
 #define S3C2400_GPE6_EINT6     (0x02 << 12)
 
-#define S3C2410_GPE7           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 7)
-#define S3C2410_GPE7_INP       (0x00 << 14)
-#define S3C2410_GPE7_OUTP      (0x01 << 14)
 #define S3C2410_GPE7_SDDAT0    (0x02 << 14)
 #define S3C2443_GPE5_SD1_DAT0  (0x02 << 14)
 #define S3C2443_GPE7_AC_SDI    (0x03 << 14)
 #define S3C2400_GPE7_EINT7     (0x02 << 14)
 
-#define S3C2410_GPE8           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 8)
-#define S3C2410_GPE8_INP       (0x00 << 16)
-#define S3C2410_GPE8_OUTP      (0x01 << 16)
 #define S3C2410_GPE8_SDDAT1    (0x02 << 16)
 #define S3C2443_GPE8_SD1_DAT1  (0x02 << 16)
 #define S3C2443_GPE8_AC_SDO    (0x03 << 16)
 #define S3C2400_GPE8_nXDACK0   (0x02 << 16)
 
-#define S3C2410_GPE9           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 9)
-#define S3C2410_GPE9_INP       (0x00 << 18)
-#define S3C2410_GPE9_OUTP      (0x01 << 18)
 #define S3C2410_GPE9_SDDAT2    (0x02 << 18)
 #define S3C2443_GPE9_SD1_DAT2  (0x02 << 18)
 #define S3C2443_GPE9_AC_SYNC   (0x03 << 18)
 #define S3C2400_GPE9_nXDACK1   (0x02 << 18)
 #define S3C2400_GPE9_nXBACK    (0x03 << 18)
 
-#define S3C2410_GPE10          S3C2410_GPIONO(S3C2410_GPIO_BANKE, 10)
-#define S3C2410_GPE10_INP      (0x00 << 20)
-#define S3C2410_GPE10_OUTP     (0x01 << 20)
 #define S3C2410_GPE10_SDDAT3   (0x02 << 20)
 #define S3C2443_GPE10_SD1_DAT3 (0x02 << 20)
 #define S3C2443_GPE10_AC_nRESET (0x03 << 20)
 #define S3C2400_GPE10_nXDREQ0  (0x02 << 20)
 
-#define S3C2410_GPE11          S3C2410_GPIONO(S3C2410_GPIO_BANKE, 11)
-#define S3C2410_GPE11_INP      (0x00 << 22)
-#define S3C2410_GPE11_OUTP     (0x01 << 22)
 #define S3C2410_GPE11_SPIMISO0 (0x02 << 22)
 #define S3C2400_GPE11_nXDREQ1  (0x02 << 22)
 #define S3C2400_GPE11_nXBREQ   (0x03 << 22)
 
-#define S3C2410_GPE12          S3C2410_GPIONO(S3C2410_GPIO_BANKE, 12)
-#define S3C2410_GPE12_INP      (0x00 << 24)
-#define S3C2410_GPE12_OUTP     (0x01 << 24)
 #define S3C2410_GPE12_SPIMOSI0 (0x02 << 24)
 
-#define S3C2410_GPE13          S3C2410_GPIONO(S3C2410_GPIO_BANKE, 13)
-#define S3C2410_GPE13_INP      (0x00 << 26)
-#define S3C2410_GPE13_OUTP     (0x01 << 26)
 #define S3C2410_GPE13_SPICLK0  (0x02 << 26)
 
-#define S3C2410_GPE14          S3C2410_GPIONO(S3C2410_GPIO_BANKE, 14)
-#define S3C2410_GPE14_INP      (0x00 << 28)
-#define S3C2410_GPE14_OUTP     (0x01 << 28)
 #define S3C2410_GPE14_IICSCL   (0x02 << 28)
 #define S3C2410_GPE14_MASK     (0x03 << 28)
 
-#define S3C2410_GPE15          S3C2410_GPIONO(S3C2410_GPIO_BANKE, 15)
-#define S3C2410_GPE15_INP      (0x00 << 30)
-#define S3C2410_GPE15_OUTP     (0x01 << 30)
 #define S3C2410_GPE15_IICSDA   (0x02 << 30)
 #define S3C2410_GPE15_MASK     (0x03 << 30)
 
@@ -705,55 +477,31 @@
 #define S3C2400_GPFDAT	   S3C2410_GPIOREG(0x3C)
 #define S3C2400_GPFUP	   S3C2410_GPIOREG(0x40)
 
-#define S3C2410_GPF0        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 0)
-#define S3C2410_GPF0_INP    (0x00 << 0)
-#define S3C2410_GPF0_OUTP   (0x01 << 0)
 #define S3C2410_GPF0_EINT0  (0x02 << 0)
 #define S3C2400_GPF0_RXD0   (0x02 << 0)
 
-#define S3C2410_GPF1        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 1)
-#define S3C2410_GPF1_INP    (0x00 << 2)
-#define S3C2410_GPF1_OUTP   (0x01 << 2)
 #define S3C2410_GPF1_EINT1  (0x02 << 2)
 #define S3C2400_GPF1_RXD1   (0x02 << 2)
 #define S3C2400_GPF1_IICSDA (0x03 << 2)
 
-#define S3C2410_GPF2        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 2)
-#define S3C2410_GPF2_INP    (0x00 << 4)
-#define S3C2410_GPF2_OUTP   (0x01 << 4)
 #define S3C2410_GPF2_EINT2  (0x02 << 4)
 #define S3C2400_GPF2_TXD0   (0x02 << 4)
 
-#define S3C2410_GPF3        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 3)
-#define S3C2410_GPF3_INP    (0x00 << 6)
-#define S3C2410_GPF3_OUTP   (0x01 << 6)
 #define S3C2410_GPF3_EINT3  (0x02 << 6)
 #define S3C2400_GPF3_TXD1   (0x02 << 6)
 #define S3C2400_GPF3_IICSCL (0x03 << 6)
 
-#define S3C2410_GPF4        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 4)
-#define S3C2410_GPF4_INP    (0x00 << 8)
-#define S3C2410_GPF4_OUTP   (0x01 << 8)
 #define S3C2410_GPF4_EINT4  (0x02 << 8)
 #define S3C2400_GPF4_nRTS0  (0x02 << 8)
 #define S3C2400_GPF4_nXBACK (0x03 << 8)
 
-#define S3C2410_GPF5        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 5)
-#define S3C2410_GPF5_INP    (0x00 << 10)
-#define S3C2410_GPF5_OUTP   (0x01 << 10)
 #define S3C2410_GPF5_EINT5  (0x02 << 10)
 #define S3C2400_GPF5_nCTS0  (0x02 << 10)
 #define S3C2400_GPF5_nXBREQ (0x03 << 10)
 
-#define S3C2410_GPF6        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 6)
-#define S3C2410_GPF6_INP    (0x00 << 12)
-#define S3C2410_GPF6_OUTP   (0x01 << 12)
 #define S3C2410_GPF6_EINT6  (0x02 << 12)
 #define S3C2400_GPF6_CLKOUT (0x02 << 12)
 
-#define S3C2410_GPF7        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 7)
-#define S3C2410_GPF7_INP    (0x00 << 14)
-#define S3C2410_GPF7_OUTP   (0x01 << 14)
 #define S3C2410_GPF7_EINT7  (0x02 << 14)
 
 #define S3C2410_GPF_PUPDIS(x)  (1<<(x))
@@ -778,117 +526,69 @@
 #define S3C2400_GPGDAT	   S3C2410_GPIOREG(0x48)
 #define S3C2400_GPGUP	   S3C2410_GPIOREG(0x4C)
 
-#define S3C2410_GPG0          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 0)
-#define S3C2410_GPG0_INP      (0x00 << 0)
-#define S3C2410_GPG0_OUTP     (0x01 << 0)
 #define S3C2410_GPG0_EINT8    (0x02 << 0)
 #define S3C2400_GPG0_I2SLRCK  (0x02 << 0)
 
-#define S3C2410_GPG1          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 1)
-#define S3C2410_GPG1_INP      (0x00 << 2)
-#define S3C2410_GPG1_OUTP     (0x01 << 2)
 #define S3C2410_GPG1_EINT9    (0x02 << 2)
 #define S3C2400_GPG1_I2SSCLK  (0x02 << 2)
 
-#define S3C2410_GPG2          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 2)
-#define S3C2410_GPG2_INP      (0x00 << 4)
-#define S3C2410_GPG2_OUTP     (0x01 << 4)
 #define S3C2410_GPG2_EINT10   (0x02 << 4)
 #define S3C2410_GPG2_nSS0     (0x03 << 4)
 #define S3C2400_GPG2_CDCLK    (0x02 << 4)
 
-#define S3C2410_GPG3          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 3)
-#define S3C2410_GPG3_INP      (0x00 << 6)
-#define S3C2410_GPG3_OUTP     (0x01 << 6)
 #define S3C2410_GPG3_EINT11   (0x02 << 6)
 #define S3C2410_GPG3_nSS1     (0x03 << 6)
 #define S3C2400_GPG3_I2SSDO   (0x02 << 6)
 #define S3C2400_GPG3_I2SSDI   (0x03 << 6)
 
-#define S3C2410_GPG4          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 4)
-#define S3C2410_GPG4_INP      (0x00 << 8)
-#define S3C2410_GPG4_OUTP     (0x01 << 8)
 #define S3C2410_GPG4_EINT12   (0x02 << 8)
 #define S3C2400_GPG4_MMCCLK   (0x02 << 8)
 #define S3C2400_GPG4_I2SSDI   (0x03 << 8)
 #define S3C2410_GPG4_LCDPWREN (0x03 << 8)
 #define S3C2443_GPG4_LCDPWRDN (0x03 << 8)
 
-#define S3C2410_GPG5          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 5)
-#define S3C2410_GPG5_INP      (0x00 << 10)
-#define S3C2410_GPG5_OUTP     (0x01 << 10)
 #define S3C2410_GPG5_EINT13   (0x02 << 10)
 #define S3C2400_GPG5_MMCCMD   (0x02 << 10)
 #define S3C2400_GPG5_IICSDA   (0x03 << 10)
 #define S3C2410_GPG5_SPIMISO1 (0x03 << 10)	/* not s3c2443 */
 
-#define S3C2410_GPG6          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 6)
-#define S3C2410_GPG6_INP      (0x00 << 12)
-#define S3C2410_GPG6_OUTP     (0x01 << 12)
 #define S3C2410_GPG6_EINT14   (0x02 << 12)
 #define S3C2400_GPG6_MMCDAT   (0x02 << 12)
 #define S3C2400_GPG6_IICSCL   (0x03 << 12)
 #define S3C2410_GPG6_SPIMOSI1 (0x03 << 12)
 
-#define S3C2410_GPG7          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 7)
-#define S3C2410_GPG7_INP      (0x00 << 14)
-#define S3C2410_GPG7_OUTP     (0x01 << 14)
 #define S3C2410_GPG7_EINT15   (0x02 << 14)
 #define S3C2410_GPG7_SPICLK1  (0x03 << 14)
 #define S3C2400_GPG7_SPIMISO  (0x02 << 14)
 #define S3C2400_GPG7_IICSDA   (0x03 << 14)
 
-#define S3C2410_GPG8          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 8)
-#define S3C2410_GPG8_INP      (0x00 << 16)
-#define S3C2410_GPG8_OUTP     (0x01 << 16)
 #define S3C2410_GPG8_EINT16   (0x02 << 16)
 #define S3C2400_GPG8_SPIMOSI  (0x02 << 16)
 #define S3C2400_GPG8_IICSCL   (0x03 << 16)
 
-#define S3C2410_GPG9          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 9)
-#define S3C2410_GPG9_INP      (0x00 << 18)
-#define S3C2410_GPG9_OUTP     (0x01 << 18)
 #define S3C2410_GPG9_EINT17   (0x02 << 18)
 #define S3C2400_GPG9_SPICLK   (0x02 << 18)
 #define S3C2400_GPG9_MMCCLK   (0x03 << 18)
 
-#define S3C2410_GPG10         S3C2410_GPIONO(S3C2410_GPIO_BANKG, 10)
-#define S3C2410_GPG10_INP     (0x00 << 20)
-#define S3C2410_GPG10_OUTP    (0x01 << 20)
 #define S3C2410_GPG10_EINT18  (0x02 << 20)
 
-#define S3C2410_GPG11         S3C2410_GPIONO(S3C2410_GPIO_BANKG, 11)
-#define S3C2410_GPG11_INP     (0x00 << 22)
-#define S3C2410_GPG11_OUTP    (0x01 << 22)
 #define S3C2410_GPG11_EINT19  (0x02 << 22)
 #define S3C2410_GPG11_TCLK1   (0x03 << 22)
 #define S3C2443_GPG11_CF_nIREQ (0x03 << 22)
 
-#define S3C2410_GPG12         S3C2410_GPIONO(S3C2410_GPIO_BANKG, 12)
-#define S3C2410_GPG12_INP     (0x00 << 24)
-#define S3C2410_GPG12_OUTP    (0x01 << 24)
 #define S3C2410_GPG12_EINT20  (0x02 << 24)
 #define S3C2410_GPG12_XMON    (0x03 << 24)
 #define S3C2442_GPG12_nSPICS0 (0x03 << 24)
 #define S3C2443_GPG12_nINPACK (0x03 << 24)
 
-#define S3C2410_GPG13         S3C2410_GPIONO(S3C2410_GPIO_BANKG, 13)
-#define S3C2410_GPG13_INP     (0x00 << 26)
-#define S3C2410_GPG13_OUTP    (0x01 << 26)
 #define S3C2410_GPG13_EINT21  (0x02 << 26)
 #define S3C2410_GPG13_nXPON   (0x03 << 26)
 #define S3C2443_GPG13_CF_nREG (0x03 << 26)
 
-#define S3C2410_GPG14         S3C2410_GPIONO(S3C2410_GPIO_BANKG, 14)
-#define S3C2410_GPG14_INP     (0x00 << 28)
-#define S3C2410_GPG14_OUTP    (0x01 << 28)
 #define S3C2410_GPG14_EINT22  (0x02 << 28)
 #define S3C2410_GPG14_YMON    (0x03 << 28)
 #define S3C2443_GPG14_CF_RESET (0x03 << 28)
 
-#define S3C2410_GPG15         S3C2410_GPIONO(S3C2410_GPIO_BANKG, 15)
-#define S3C2410_GPG15_INP     (0x00 << 30)
-#define S3C2410_GPG15_OUTP    (0x01 << 30)
 #define S3C2410_GPG15_EINT23  (0x02 << 30)
 #define S3C2410_GPG15_nYPON   (0x03 << 30)
 #define S3C2443_GPG15_CF_PWR  (0x03 << 30)
@@ -907,62 +607,29 @@
 #define S3C2410_GPHDAT	   S3C2410_GPIOREG(0x74)
 #define S3C2410_GPHUP	   S3C2410_GPIOREG(0x78)
 
-#define S3C2410_GPH0        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 0)
-#define S3C2410_GPH0_INP    (0x00 << 0)
-#define S3C2410_GPH0_OUTP   (0x01 << 0)
 #define S3C2410_GPH0_nCTS0  (0x02 << 0)
 
-#define S3C2410_GPH1        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 1)
-#define S3C2410_GPH1_INP    (0x00 << 2)
-#define S3C2410_GPH1_OUTP   (0x01 << 2)
 #define S3C2410_GPH1_nRTS0  (0x02 << 2)
 
-#define S3C2410_GPH2        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 2)
-#define S3C2410_GPH2_INP    (0x00 << 4)
-#define S3C2410_GPH2_OUTP   (0x01 << 4)
 #define S3C2410_GPH2_TXD0   (0x02 << 4)
 
-#define S3C2410_GPH3        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 3)
-#define S3C2410_GPH3_INP    (0x00 << 6)
-#define S3C2410_GPH3_OUTP   (0x01 << 6)
 #define S3C2410_GPH3_RXD0   (0x02 << 6)
 
-#define S3C2410_GPH4        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 4)
-#define S3C2410_GPH4_INP    (0x00 << 8)
-#define S3C2410_GPH4_OUTP   (0x01 << 8)
 #define S3C2410_GPH4_TXD1   (0x02 << 8)
 
-#define S3C2410_GPH5        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 5)
-#define S3C2410_GPH5_INP    (0x00 << 10)
-#define S3C2410_GPH5_OUTP   (0x01 << 10)
 #define S3C2410_GPH5_RXD1   (0x02 << 10)
 
-#define S3C2410_GPH6        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 6)
-#define S3C2410_GPH6_INP    (0x00 << 12)
-#define S3C2410_GPH6_OUTP   (0x01 << 12)
 #define S3C2410_GPH6_TXD2   (0x02 << 12)
 #define S3C2410_GPH6_nRTS1  (0x03 << 12)
 
-#define S3C2410_GPH7        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 7)
-#define S3C2410_GPH7_INP    (0x00 << 14)
-#define S3C2410_GPH7_OUTP   (0x01 << 14)
 #define S3C2410_GPH7_RXD2   (0x02 << 14)
 #define S3C2410_GPH7_nCTS1  (0x03 << 14)
 
-#define S3C2410_GPH8        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 8)
-#define S3C2410_GPH8_INP    (0x00 << 16)
-#define S3C2410_GPH8_OUTP   (0x01 << 16)
 #define S3C2410_GPH8_UCLK   (0x02 << 16)
 
-#define S3C2410_GPH9          S3C2410_GPIONO(S3C2410_GPIO_BANKH, 9)
-#define S3C2410_GPH9_INP      (0x00 << 18)
-#define S3C2410_GPH9_OUTP     (0x01 << 18)
 #define S3C2410_GPH9_CLKOUT0  (0x02 << 18)
 #define S3C2442_GPH9_nSPICS0  (0x03 << 18)
 
-#define S3C2410_GPH10         S3C2410_GPIONO(S3C2410_GPIO_BANKH, 10)
-#define S3C2410_GPH10_INP     (0x00 << 20)
-#define S3C2410_GPH10_OUTP    (0x01 << 20)
 #define S3C2410_GPH10_CLKOUT1 (0x02 << 20)
 
 /* The S3C2412 and S3C2413 move the GPJ register set to after
diff --git a/arch/arm/mach-s3c2410/include/mach/system-reset.h b/arch/arm/mach-s3c2410/include/mach/system-reset.h
index b8687f7..6faadce 100644
--- a/arch/arm/mach-s3c2410/include/mach/system-reset.h
+++ b/arch/arm/mach-s3c2410/include/mach/system-reset.h
@@ -11,21 +11,13 @@
 */
 
 #include <mach/hardware.h>
-#include <linux/io.h>
-
-#include <plat/regs-watchdog.h>
-#include <mach/regs-clock.h>
-
-#include <linux/clk.h>
-#include <linux/err.h>
+#include <plat/watchdog-reset.h>
 
 extern void (*s3c24xx_reset_hook)(void);
 
 static void
 arch_reset(char mode, const char *cmd)
 {
-	struct clk *wdtclk;
-
 	if (mode == 's') {
 		cpu_reset(0);
 	}
@@ -33,31 +25,7 @@
 	if (s3c24xx_reset_hook)
 		s3c24xx_reset_hook();
 
-	printk("arch_reset: attempting watchdog reset\n");
-
-	__raw_writel(0, S3C2410_WTCON);	  /* disable watchdog, to be safe  */
-
-	wdtclk = clk_get(NULL, "watchdog");
-	if (!IS_ERR(wdtclk)) {
-		clk_enable(wdtclk);
-	} else
-		printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__);
-
-	/* put initial values into count and data */
-	__raw_writel(0x80, S3C2410_WTCNT);
-	__raw_writel(0x80, S3C2410_WTDAT);
-
-	/* set the watchdog to go and reset... */
-	__raw_writel(S3C2410_WTCON_ENABLE|S3C2410_WTCON_DIV16|S3C2410_WTCON_RSTEN |
-		     S3C2410_WTCON_PRESCALE(0x20), S3C2410_WTCON);
-
-	/* wait for reset to assert... */
-	mdelay(500);
-
-	printk(KERN_ERR "Watchdog reset failed to assert reset\n");
-
-	/* delay to allow the serial port to show the message */
-	mdelay(50);
+	arch_wdt_reset();
 
 	/* we'll take a jump through zero as a poor second */
 	cpu_reset(0);
diff --git a/arch/arm/mach-s3c2410/mach-amlm5900.c b/arch/arm/mach-s3c2410/mach-amlm5900.c
index 6d6995a..06a84ad 100644
--- a/arch/arm/mach-s3c2410/mach-amlm5900.c
+++ b/arch/arm/mach-s3c2410/mach-amlm5900.c
@@ -32,6 +32,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/proc_fs.h>
@@ -224,8 +225,8 @@
 	} else {
 		enable_irq_wake(IRQ_EINT9);
 		/* configure the suspend/resume status pin */
-		s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_OUTP);
-		s3c2410_gpio_pullup(S3C2410_GPF2, 0);
+		s3c2410_gpio_cfgpin(S3C2410_GPF(2), S3C2410_GPIO_OUTPUT);
+		s3c2410_gpio_pullup(S3C2410_GPF(2), 0);
 	}
 }
 static void __init amlm5900_init(void)
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index 8637dea..ce3baba 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -16,6 +16,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
@@ -212,15 +213,15 @@
 static int bast_pm_suspend(struct sys_device *sd, pm_message_t state)
 {
 	/* ensure that an nRESET is not generated on resume. */
-	s3c2410_gpio_setpin(S3C2410_GPA21, 1);
-	s3c2410_gpio_cfgpin(S3C2410_GPA21, S3C2410_GPA21_OUT);
+	s3c2410_gpio_setpin(S3C2410_GPA(21), 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPIO_OUTPUT);
 
 	return 0;
 }
 
 static int bast_pm_resume(struct sys_device *sd)
 {
-	s3c2410_gpio_cfgpin(S3C2410_GPA21, S3C2410_GPA21_nRSTOUT);
+	s3c2410_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
 	return 0;
 }
 
@@ -591,8 +592,6 @@
 	s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc));
 	s3c24xx_init_clocks(0);
 	s3c24xx_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs));
-
-	usb_simtec_init();
 }
 
 static void __init bast_init(void)
@@ -607,6 +606,7 @@
 	i2c_register_board_info(0, bast_i2c_devs,
 				ARRAY_SIZE(bast_i2c_devs));
 
+	usb_simtec_init();
 	nor_simtec_init();
 }
 
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
index 7a7c4da..d9cd5dd 100644
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -127,7 +127,7 @@
 
 static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = {
 	.udc_command		= h1940_udc_pullup,
-	.vbus_pin		= S3C2410_GPG5,
+	.vbus_pin		= S3C2410_GPG(5),
 	.vbus_pin_inverted	= 1,
 };
 
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
index 2b83f87..0f6ed61 100644
--- a/arch/arm/mach-s3c2410/mach-n30.c
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -19,6 +19,7 @@
 
 #include <linux/gpio_keys.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
@@ -85,10 +86,10 @@
 {
 	switch (cmd) {
 	case S3C2410_UDC_P_ENABLE :
-		s3c2410_gpio_setpin(S3C2410_GPB3, 1);
+		s3c2410_gpio_setpin(S3C2410_GPB(3), 1);
 		break;
 	case S3C2410_UDC_P_DISABLE :
-		s3c2410_gpio_setpin(S3C2410_GPB3, 0);
+		s3c2410_gpio_setpin(S3C2410_GPB(3), 0);
 		break;
 	case S3C2410_UDC_P_RESET :
 		break;
@@ -99,55 +100,55 @@
 
 static struct s3c2410_udc_mach_info n30_udc_cfg __initdata = {
 	.udc_command		= n30_udc_pullup,
-	.vbus_pin		= S3C2410_GPG1,
+	.vbus_pin		= S3C2410_GPG(1),
 	.vbus_pin_inverted	= 0,
 };
 
 static struct gpio_keys_button n30_buttons[] = {
 	{
-		.gpio		= S3C2410_GPF0,
+		.gpio		= S3C2410_GPF(0),
 		.code		= KEY_POWER,
 		.desc		= "Power",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPG9,
+		.gpio		= S3C2410_GPG(9),
 		.code		= KEY_UP,
 		.desc		= "Thumbwheel Up",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPG8,
+		.gpio		= S3C2410_GPG(8),
 		.code		= KEY_DOWN,
 		.desc		= "Thumbwheel Down",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPG7,
+		.gpio		= S3C2410_GPG(7),
 		.code		= KEY_ENTER,
 		.desc		= "Thumbwheel Press",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPF7,
+		.gpio		= S3C2410_GPF(7),
 		.code		= KEY_HOMEPAGE,
 		.desc		= "Home",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPF6,
+		.gpio		= S3C2410_GPF(6),
 		.code		= KEY_CALENDAR,
 		.desc		= "Calendar",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPF5,
+		.gpio		= S3C2410_GPF(5),
 		.code		= KEY_ADDRESSBOOK,
 		.desc		= "Contacts",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPF4,
+		.gpio		= S3C2410_GPF(4),
 		.code		= KEY_MAIL,
 		.desc		= "Mail",
 		.active_low	= 0,
@@ -169,73 +170,73 @@
 
 static struct gpio_keys_button n35_buttons[] = {
 	{
-		.gpio		= S3C2410_GPF0,
+		.gpio		= S3C2410_GPF(0),
 		.code		= KEY_POWER,
 		.desc		= "Power",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPG9,
+		.gpio		= S3C2410_GPG(9),
 		.code		= KEY_UP,
 		.desc		= "Joystick Up",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPG8,
+		.gpio		= S3C2410_GPG(8),
 		.code		= KEY_DOWN,
 		.desc		= "Joystick Down",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPG6,
+		.gpio		= S3C2410_GPG(6),
 		.code		= KEY_DOWN,
 		.desc		= "Joystick Left",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPG5,
+		.gpio		= S3C2410_GPG(5),
 		.code		= KEY_DOWN,
 		.desc		= "Joystick Right",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPG7,
+		.gpio		= S3C2410_GPG(7),
 		.code		= KEY_ENTER,
 		.desc		= "Joystick Press",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPF7,
+		.gpio		= S3C2410_GPF(7),
 		.code		= KEY_HOMEPAGE,
 		.desc		= "Home",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPF6,
+		.gpio		= S3C2410_GPF(6),
 		.code		= KEY_CALENDAR,
 		.desc		= "Calendar",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPF5,
+		.gpio		= S3C2410_GPF(5),
 		.code		= KEY_ADDRESSBOOK,
 		.desc		= "Contacts",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPF4,
+		.gpio		= S3C2410_GPF(4),
 		.code		= KEY_MAIL,
 		.desc		= "Mail",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPF3,
+		.gpio		= S3C2410_GPF(3),
 		.code		= SW_RADIO,
 		.desc		= "GPS Antenna",
 		.active_low	= 0,
 	},
 	{
-		.gpio		= S3C2410_GPG2,
+		.gpio		= S3C2410_GPG(2),
 		.code		= SW_HEADPHONE_INSERT,
 		.desc		= "Headphone",
 		.active_low	= 0,
@@ -259,7 +260,7 @@
 /* This is the bluetooth LED on the device. */
 static struct s3c24xx_led_platdata n30_blue_led_pdata = {
 	.name		= "blue_led",
-	.gpio		= S3C2410_GPG6,
+	.gpio		= S3C2410_GPG(6),
 	.def_trigger	= "",
 };
 
@@ -270,7 +271,7 @@
 static struct s3c24xx_led_platdata n30_warning_led_pdata = {
 	.name		= "warning_led",
 	.flags          = S3C24XX_LEDF_ACTLOW,
-	.gpio		= S3C2410_GPD9,
+	.gpio		= S3C2410_GPD(9),
 	.def_trigger	= "",
 };
 
diff --git a/arch/arm/mach-s3c2410/mach-qt2410.c b/arch/arm/mach-s3c2410/mach-qt2410.c
index 9f1ba9b..2cc9849 100644
--- a/arch/arm/mach-s3c2410/mach-qt2410.c
+++ b/arch/arm/mach-s3c2410/mach-qt2410.c
@@ -27,6 +27,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/sysdev.h>
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
@@ -198,7 +199,7 @@
 /* LED */
 
 static struct s3c24xx_led_platdata qt2410_pdata_led = {
-	.gpio		= S3C2410_GPB0,
+	.gpio		= S3C2410_GPB(0),
 	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
 	.name		= "led",
 	.def_trigger	= "timer",
@@ -218,18 +219,18 @@
 {
 	switch (cs) {
 	case BITBANG_CS_ACTIVE:
-		s3c2410_gpio_setpin(S3C2410_GPB5, 0);
+		s3c2410_gpio_setpin(S3C2410_GPB(5), 0);
 		break;
 	case BITBANG_CS_INACTIVE:
-		s3c2410_gpio_setpin(S3C2410_GPB5, 1);
+		s3c2410_gpio_setpin(S3C2410_GPB(5), 1);
 		break;
 	}
 }
 
 static struct s3c2410_spigpio_info spi_gpio_cfg = {
-	.pin_clk	= S3C2410_GPG7,
-	.pin_mosi	= S3C2410_GPG6,
-	.pin_miso	= S3C2410_GPG5,
+	.pin_clk	= S3C2410_GPG(7),
+	.pin_mosi	= S3C2410_GPG(6),
+	.pin_miso	= S3C2410_GPG(5),
 	.chip_select	= &spi_gpio_cs,
 };
 
@@ -346,13 +347,13 @@
 	}
 	s3c24xx_fb_set_platdata(&qt2410_fb_info);
 
-	s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPIO_OUTPUT);
-	s3c2410_gpio_setpin(S3C2410_GPB0, 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_setpin(S3C2410_GPB(0), 1);
 
 	s3c24xx_udc_set_platdata(&qt2410_udc_cfg);
 	s3c_i2c0_set_platdata(NULL);
 
-	s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_cfgpin(S3C2410_GPB(5), S3C2410_GPIO_OUTPUT);
 
 	platform_add_devices(qt2410_devices, ARRAY_SIZE(qt2410_devices));
 	s3c_pm_init();
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
index 61a1ea9..1628cc7 100644
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -18,6 +18,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/dm9000.h>
 #include <linux/i2c.h>
 
@@ -277,19 +278,19 @@
 
 static struct s3c24xx_led_platdata vr1000_led1_pdata = {
 	.name		= "led1",
-	.gpio		= S3C2410_GPB0,
+	.gpio		= S3C2410_GPB(0),
 	.def_trigger	= "",
 };
 
 static struct s3c24xx_led_platdata vr1000_led2_pdata = {
 	.name		= "led2",
-	.gpio		= S3C2410_GPB1,
+	.gpio		= S3C2410_GPB(1),
 	.def_trigger	= "",
 };
 
 static struct s3c24xx_led_platdata vr1000_led3_pdata = {
 	.name		= "led3",
-	.gpio		= S3C2410_GPB2,
+	.gpio		= S3C2410_GPB(2),
 	.def_trigger	= "",
 };
 
@@ -355,8 +356,8 @@
 
 static void vr1000_power_off(void)
 {
-	s3c2410_gpio_cfgpin(S3C2410_GPB9, S3C2410_GPB9_OUTP);
-	s3c2410_gpio_setpin(S3C2410_GPB9, 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPB(9), S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_setpin(S3C2410_GPB(9), 1);
 }
 
 static void __init vr1000_map_io(void)
diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c
index 87fc481..143e08a 100644
--- a/arch/arm/mach-s3c2410/pm.c
+++ b/arch/arm/mach-s3c2410/pm.c
@@ -25,6 +25,7 @@
 #include <linux/errno.h>
 #include <linux/time.h>
 #include <linux/sysdev.h>
+#include <linux/gpio.h>
 #include <linux/io.h>
 
 #include <mach/hardware.h>
@@ -76,7 +77,7 @@
 	}
 
 	if ( machine_is_aml_m5900() )
-		s3c2410_gpio_setpin(S3C2410_GPF2, 1);
+		s3c2410_gpio_setpin(S3C2410_GPF(2), 1);
 
 }
 
@@ -91,7 +92,7 @@
 	__raw_writel(tmp, S3C2410_GSTATUS2);
 
 	if ( machine_is_aml_m5900() )
-		s3c2410_gpio_setpin(S3C2410_GPF2, 0);
+		s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
 
 	return 0;
 }
diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c
index 8331e8d..6cd9377 100644
--- a/arch/arm/mach-s3c2410/usb-simtec.c
+++ b/arch/arm/mach-s3c2410/usb-simtec.c
@@ -18,9 +18,11 @@
 #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/gpio.h>
 #include <linux/io.h>
 
 #include <asm/mach/arch.h>
@@ -29,7 +31,6 @@
 
 #include <mach/bast-map.h>
 #include <mach/bast-irq.h>
-#include <mach/regs-gpio.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
@@ -53,9 +54,9 @@
 	power_state[port] = to;
 
 	if (power_state[0] && power_state[1])
-		s3c2410_gpio_setpin(S3C2410_GPB4, 0);
+		gpio_set_value(S3C2410_GPB(4), 0);
 	else
-		s3c2410_gpio_setpin(S3C2410_GPB4, 1);
+		gpio_set_value(S3C2410_GPB(4), 1);
 }
 
 static irqreturn_t
@@ -63,7 +64,7 @@
 {
 	struct s3c2410_hcd_info *info = pw;
 
-	if (s3c2410_gpio_getpin(S3C2410_GPG10) == 0) {
+	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 {
@@ -106,10 +107,27 @@
 
 int usb_simtec_init(void)
 {
-	printk("USB Power Control, (c) 2004 Simtec Electronics\n");
-	s3c_device_usb.dev.platform_data = &usb_simtec_info;
+	int ret;
 
-	s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
-	s3c2410_gpio_setpin(S3C2410_GPB4, 1);
+	printk("USB Power Control, (c) 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_device_usb.dev.platform_data = &usb_simtec_info;
 	return 0;
 }
diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig
index ca99564..63586ff 100644
--- a/arch/arm/mach-s3c2412/Kconfig
+++ b/arch/arm/mach-s3c2412/Kconfig
@@ -38,6 +38,7 @@
 config MACH_JIVE
 	bool "Logitech Jive"
 	select CPU_S3C2412
+	select S3C_DEV_USB_HOST
 	help
 	  Say Y here if you are using the Logitech Jive.
 
@@ -50,6 +51,7 @@
 	select CPU_S3C2412
 	select MACH_S3C2413
 	select MACH_SMDK
+	select S3C_DEV_USB_HOST
 	help
 	  Say Y here if you are using an SMDK2413
 
@@ -72,6 +74,7 @@
 config MACH_VSTMS
 	bool "VMSTMS"
 	select CPU_S3C2412
+	select S3C_DEV_USB_HOST
 	help
 	  Say Y here if you are using an VSTMS board
 
diff --git a/arch/arm/mach-s3c2412/dma.c b/arch/arm/mach-s3c2412/dma.c
index 9e34785..f8d16fc 100644
--- a/arch/arm/mach-s3c2412/dma.c
+++ b/arch/arm/mach-s3c2412/dma.c
@@ -20,12 +20,13 @@
 
 #include <mach/dma.h>
 
-#include <plat/dma.h>
+#include <plat/dma-plat.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>
diff --git a/arch/arm/mach-s3c2412/mach-jive.c b/arch/arm/mach-s3c2412/mach-jive.c
index 8f0d37d..8df506e 100644
--- a/arch/arm/mach-s3c2412/mach-jive.c
+++ b/arch/arm/mach-s3c2412/mach-jive.c
@@ -16,6 +16,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
@@ -356,8 +357,8 @@
 {
 	printk(KERN_DEBUG "%s(%d)\n", __func__, set);
 
-	s3c2410_gpio_setpin(S3C2410_GPG13, set);
-	s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_setpin(S3C2410_GPG(13), set);
+	s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPIO_OUTPUT);
 }
 
 #undef LCD_UPPER_MARGIN
@@ -390,13 +391,13 @@
 
 static void jive_lcd_spi_chipselect(struct s3c2410_spigpio_info *spi, int cs)
 {
-	s3c2410_gpio_setpin(S3C2410_GPB7, cs ? 0 : 1);
+	s3c2410_gpio_setpin(S3C2410_GPB(7), cs ? 0 : 1);
 }
 
 static struct s3c2410_spigpio_info jive_lcd_spi = {
 	.bus_num	= 1,
-	.pin_clk	= S3C2410_GPG8,
-	.pin_mosi	= S3C2410_GPB8,
+	.pin_clk	= S3C2410_GPG(8),
+	.pin_mosi	= S3C2410_GPB(8),
 	.num_chipselect	= 1,
 	.chip_select	= jive_lcd_spi_chipselect,
 };
@@ -412,13 +413,13 @@
 
 static void jive_wm8750_chipselect(struct s3c2410_spigpio_info *spi, int cs)
 {
-	s3c2410_gpio_setpin(S3C2410_GPH10, cs ? 0 : 1);
+	s3c2410_gpio_setpin(S3C2410_GPH(10), cs ? 0 : 1);
 }
 
 static struct s3c2410_spigpio_info jive_wm8750_spi = {
 	.bus_num	= 2,
-	.pin_clk	= S3C2410_GPB4,
-	.pin_mosi	= S3C2410_GPB9,
+	.pin_clk	= S3C2410_GPB(4),
+	.pin_mosi	= S3C2410_GPB(9),
 	.num_chipselect	= 1,
 	.chip_select	= jive_wm8750_chipselect,
 };
@@ -479,7 +480,7 @@
 };
 
 static struct s3c2410_udc_mach_info jive_udc_cfg __initdata = {
-	.vbus_pin	= S3C2410_GPG1,		/* detect is on GPG1 */
+	.vbus_pin	= S3C2410_GPG(1),		/* detect is on GPG1 */
 };
 
 /* Jive power management device */
@@ -529,8 +530,8 @@
 {
 	printk(KERN_INFO "powering system down...\n");
 
-	s3c2410_gpio_setpin(S3C2410_GPC5, 1);
-	s3c2410_gpio_cfgpin(S3C2410_GPC5, S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_setpin(S3C2410_GPC(5), 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPC(5), S3C2410_GPIO_OUTPUT);
 }
 
 static void __init jive_machine_init(void)
@@ -634,22 +635,22 @@
 
 	/* initialise the spi */
 
-	s3c2410_gpio_setpin(S3C2410_GPG13, 0);
-	s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_setpin(S3C2410_GPG(13), 0);
+	s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPIO_OUTPUT);
 
-	s3c2410_gpio_setpin(S3C2410_GPB7, 1);
-	s3c2410_gpio_cfgpin(S3C2410_GPB7, S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_setpin(S3C2410_GPB(7), 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPB(7), S3C2410_GPIO_OUTPUT);
 
-	s3c2410_gpio_setpin(S3C2410_GPB6, 0);
-	s3c2410_gpio_cfgpin(S3C2410_GPB6, S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_setpin(S3C2410_GPB(6), 0);
+	s3c2410_gpio_cfgpin(S3C2410_GPB(6), S3C2410_GPIO_OUTPUT);
 
-	s3c2410_gpio_setpin(S3C2410_GPG8, 1);
-	s3c2410_gpio_cfgpin(S3C2410_GPG8, S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_setpin(S3C2410_GPG(8), 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPG(8), S3C2410_GPIO_OUTPUT);
 
 	/* initialise the WM8750 spi */
 
-	s3c2410_gpio_setpin(S3C2410_GPH10, 1);
-	s3c2410_gpio_cfgpin(S3C2410_GPH10, S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_setpin(S3C2410_GPH(10), 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPH(10), S3C2410_GPIO_OUTPUT);
 
 	/* Turn off suspend on both USB ports, and switch the
 	 * selectable USB port to USB device mode. */
diff --git a/arch/arm/mach-s3c2412/mach-smdk2413.c b/arch/arm/mach-s3c2412/mach-smdk2413.c
index eba66aa..9a5e434 100644
--- a/arch/arm/mach-s3c2412/mach-smdk2413.c
+++ b/arch/arm/mach-s3c2412/mach-smdk2413.c
@@ -17,6 +17,7 @@
 #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/io.h>
@@ -84,10 +85,10 @@
 	switch (cmd)
 	{
 		case S3C2410_UDC_P_ENABLE :
-			s3c2410_gpio_setpin(S3C2410_GPF2, 1);
+			s3c2410_gpio_setpin(S3C2410_GPF(2), 1);
 			break;
 		case S3C2410_UDC_P_DISABLE :
-			s3c2410_gpio_setpin(S3C2410_GPF2, 0);
+			s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
 			break;
 		case S3C2410_UDC_P_RESET :
 			break;
@@ -134,8 +135,8 @@
 {	/* Turn off suspend on both USB ports, and switch the
 	 * selectable USB port to USB device mode. */
 
-	s3c2410_gpio_setpin(S3C2410_GPF2, 0);
-	s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
+	s3c2410_gpio_cfgpin(S3C2410_GPF(2), S3C2410_GPIO_OUTPUT);
 
 	s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
 			      S3C2410_MISCCR_USBSUSPND0 |
diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig
index cde5ae9..5df73cb 100644
--- a/arch/arm/mach-s3c2440/Kconfig
+++ b/arch/arm/mach-s3c2440/Kconfig
@@ -33,6 +33,7 @@
 	select PM_SIMTEC if PM
 	select HAVE_PATA_PLATFORM
 	select S3C24XX_GPIO_EXTRA64
+	select S3C_DEV_USB_HOST
 	help
 	  Say Y here if you are using the Simtec Electronics ANUBIS
 	  development system
@@ -43,6 +44,7 @@
 	select S3C24XX_DCLK
 	select PM_SIMTEC if PM
 	select S3C24XX_GPIO_EXTRA128
+	select S3C_DEV_USB_HOST
 	help
 	  Say Y here if you are using the Simtec IM2440D20 module, also
 	  known as the Osiris.
@@ -58,12 +60,14 @@
 	bool "SMDK2440"
 	select CPU_S3C2440
 	select MACH_SMDK
+	select S3C_DEV_USB_HOST
 	help
 	  Say Y here if you are using the SMDK2440.
 
 config MACH_NEXCODER_2440
  	bool "NexVision NEXCODER 2440 Light Board"
  	select CPU_S3C2440
+	select S3C_DEV_USB_HOST
 	help
  	  Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
 
@@ -76,6 +80,7 @@
 config MACH_AT2440EVB
 	bool "Avantech AT2440EVB development board"
 	select CPU_S3C2440
+	select S3C_DEV_USB_HOST
 	help
 	  Say Y here if you are using the AT2440EVB development board
 
diff --git a/arch/arm/mach-s3c2440/dma.c b/arch/arm/mach-s3c2440/dma.c
index 69b6cf3..e08e081 100644
--- a/arch/arm/mach-s3c2440/dma.c
+++ b/arch/arm/mach-s3c2440/dma.c
@@ -17,14 +17,16 @@
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 
+#include <mach/map.h>
 #include <mach/dma.h>
 
-#include <plat/dma.h>
+#include <plat/dma-plat.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>
diff --git a/arch/arm/mach-s3c2440/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c
index 9c6abf9..68f3870 100644
--- a/arch/arm/mach-s3c2440/mach-anubis.c
+++ b/arch/arm/mach-s3c2440/mach-anubis.c
@@ -15,6 +15,7 @@
 #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>
@@ -468,7 +469,7 @@
 		anubis_nand_sets[0].nr_partitions = ARRAY_SIZE(anubis_default_nand_part_large);
 	} else {
 		/* ensure that the GPIO is setup */
-		s3c2410_gpio_setpin(S3C2410_GPA0, 1);
+		s3c2410_gpio_setpin(S3C2410_GPA(0), 1);
 	}
 }
 
diff --git a/arch/arm/mach-s3c2440/mach-at2440evb.c b/arch/arm/mach-s3c2440/mach-at2440evb.c
index 315c42e..dfc7010 100644
--- a/arch/arm/mach-s3c2440/mach-at2440evb.c
+++ b/arch/arm/mach-s3c2440/mach-at2440evb.c
@@ -166,7 +166,7 @@
 };
 
 static struct s3c24xx_mci_pdata at2440evb_mci_pdata = {
-	.gpio_detect	= S3C2410_GPG10,
+	.gpio_detect	= S3C2410_GPG(10),
 };
 
 /* 7" LCD panel */
diff --git a/arch/arm/mach-s3c2440/mach-nexcoder.c b/arch/arm/mach-s3c2440/mach-nexcoder.c
index 7aeaa97..d43eded 100644
--- a/arch/arm/mach-s3c2440/mach-nexcoder.c
+++ b/arch/arm/mach-s3c2440/mach-nexcoder.c
@@ -18,6 +18,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/string.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
@@ -120,16 +121,16 @@
 static void __init nexcoder_sensorboard_init(void)
 {
 	// Initialize SCCB bus
-	s3c2410_gpio_setpin(S3C2410_GPE14, 1); // IICSCL
-	s3c2410_gpio_cfgpin(S3C2410_GPE14, S3C2410_GPE14_OUTP);
-	s3c2410_gpio_setpin(S3C2410_GPE15, 1); // IICSDA
-	s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_OUTP);
+	s3c2410_gpio_setpin(S3C2410_GPE(14), 1); // IICSCL
+	s3c2410_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_setpin(S3C2410_GPE(15), 1); // IICSDA
+	s3c2410_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPIO_OUTPUT);
 
 	// Power up the sensor board
-	s3c2410_gpio_setpin(S3C2410_GPF1, 1);
-	s3c2410_gpio_cfgpin(S3C2410_GPF1, S3C2410_GPF1_OUTP); // CAM_GPIO7 => nLDO_PWRDN
-	s3c2410_gpio_setpin(S3C2410_GPF2, 0);
-	s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_OUTP); // CAM_GPIO6 => CAM_PWRDN
+	s3c2410_gpio_setpin(S3C2410_GPF(1), 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPF(1), S3C2410_GPIO_OUTPUT); // CAM_GPIO7 => nLDO_PWRDN
+	s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
+	s3c2410_gpio_cfgpin(S3C2410_GPF(2), S3C2410_GPIO_OUTPUT); // CAM_GPIO6 => CAM_PWRDN
 }
 
 static void __init nexcoder_map_io(void)
diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c
index c8a4668..cba064b 100644
--- a/arch/arm/mach-s3c2440/mach-osiris.c
+++ b/arch/arm/mach-s3c2440/mach-osiris.c
@@ -15,6 +15,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/device.h>
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
@@ -291,8 +292,8 @@
 	__raw_writeb(tmp, OSIRIS_VA_CTRL0);
 
 	/* ensure that an nRESET is not generated on resume. */
-	s3c2410_gpio_setpin(S3C2410_GPA21, 1);
-	s3c2410_gpio_cfgpin(S3C2410_GPA21, S3C2410_GPA21_OUT);
+	s3c2410_gpio_setpin(S3C2410_GPA(21), 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPIO_OUTPUT);
 
 	return 0;
 }
@@ -304,7 +305,7 @@
 
 	__raw_writeb(pm_osiris_ctrl0, OSIRIS_VA_CTRL0);
 
-	s3c2410_gpio_cfgpin(S3C2410_GPA21, S3C2410_GPA21_nRSTOUT);
+	s3c2410_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
 
 	return 0;
 }
@@ -384,7 +385,7 @@
 		osiris_nand_sets[0].nr_partitions = ARRAY_SIZE(osiris_default_nand_part_large);
 	} else {
 		/* write-protect line to the NAND */
-		s3c2410_gpio_setpin(S3C2410_GPA0, 1);
+		s3c2410_gpio_setpin(S3C2410_GPA(0), 1);
 	}
 
 	/* fix bus configuration (nBE settings wrong on ABLE pre v2.20) */
diff --git a/arch/arm/mach-s3c2443/dma.c b/arch/arm/mach-s3c2443/dma.c
index 8430e58..397f3b5 100644
--- a/arch/arm/mach-s3c2443/dma.c
+++ b/arch/arm/mach-s3c2443/dma.c
@@ -20,12 +20,13 @@
 
 #include <mach/dma.h>
 
-#include <plat/dma.h>
+#include <plat/dma-plat.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>
diff --git a/arch/arm/mach-s3c6400/Kconfig b/arch/arm/mach-s3c6400/Kconfig
index 6da82b5..f5af212 100644
--- a/arch/arm/mach-s3c6400/Kconfig
+++ b/arch/arm/mach-s3c6400/Kconfig
@@ -5,4 +5,27 @@
 #
 # Licensed under GPLv2
 
-# Currently nothing here, this will be added later
+# Configuration options for the S3C6410 CPU
+
+config CPU_S3C6400
+	bool
+	select CPU_S3C6400_INIT
+	select CPU_S3C6400_CLOCK
+	help
+	  Enable S3C6400 CPU support
+
+config S3C6400_SETUP_SDHCI
+	bool
+	help
+	  Internal configuration for default SDHCI
+	  setup for S3C6400.
+
+# S36400 Macchine support
+
+config MACH_SMDK6400
+       bool "SMDK6400"
+	select CPU_S3C6400
+	select S3C_DEV_HSMMC
+	select S3C6400_SETUP_SDHCI
+	help
+	  Machine support for the Samsung SMDK6400
diff --git a/arch/arm/mach-s3c6400/Makefile b/arch/arm/mach-s3c6400/Makefile
index 8f397db..df1ce4a 100644
--- a/arch/arm/mach-s3c6400/Makefile
+++ b/arch/arm/mach-s3c6400/Makefile
@@ -12,4 +12,12 @@
 
 # Core support for S3C6400 system
 
-obj-n				+= blank.o
+obj-$(CONFIG_CPU_S3C6400)	+= s3c6400.o
+
+# setup support
+
+obj-$(CONFIG_S3C6400_SETUP_SDHCI) += setup-sdhci.o
+
+# Machine support
+
+obj-$(CONFIG_MACH_SMDK6400)	+= mach-smdk6400.o
diff --git a/arch/arm/mach-s3c6400/include/mach/dma.h b/arch/arm/mach-s3c6400/include/mach/dma.h
index 9771ac2..1067619 100644
--- a/arch/arm/mach-s3c6400/include/mach/dma.h
+++ b/arch/arm/mach-s3c6400/include/mach/dma.h
@@ -11,6 +11,63 @@
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H __FILE__
 
-/* currently nothing here, placeholder */
+#define S3C_DMA_CHANNELS	(16)
+
+/* see mach-s3c2410/dma.h for notes on dma channel numbers */
+
+/* Note, for the S3C64XX architecture we keep the DMACH_
+ * defines in the order they are allocated to [S]DMA0/[S]DMA1
+ * so that is easy to do DHACH_ -> DMA controller conversion
+ */
+enum dma_ch {
+	/* DMA0/SDMA0 */
+	DMACH_UART0 = 0,
+	DMACH_UART0_SRC2,
+	DMACH_UART1,
+	DMACH_UART1_SRC2,
+	DMACH_UART2,
+	DMACH_UART2_SRC2,
+	DMACH_UART3,
+	DMACH_UART3_SRC2,
+	DMACH_PCM0_TX,
+	DMACH_PCM0_RX,
+	DMACH_I2S0_OUT,
+	DMACH_I2S0_IN,
+	DMACH_SPI0_TX,
+	DMACH_SPI0_RX,
+	DMACH_HSI_I2SV40_TX,
+	DMACH_HSI_I2SV40_RX,
+
+	/* DMA1/SDMA1 */
+	DMACH_PCM1_TX = 16,
+	DMACH_PCM1_RX,
+	DMACH_I2S1_OUT,
+	DMACH_I2S1_IN,
+	DMACH_SPI1_TX,
+	DMACH_SPI1_RX,
+	DMACH_AC97_PCMOUT,
+	DMACH_AC97_PCMIN,
+	DMACH_AC97_MICIN,
+	DMACH_PWM,
+	DMACH_IRDA,
+	DMACH_EXTERNAL,
+	DMACH_RES1,
+	DMACH_RES2,
+	DMACH_SECURITY_RX,	/* SDMA1 only */
+	DMACH_SECURITY_TX,	/* SDMA1 only */
+	DMACH_MAX		/* the end */
+};
+
+static __inline__ int s3c_dma_has_circular(void)
+{
+	/* we will be supporting ciruclar buffers as soon as we have DMA
+	 * engine support.
+	 */
+	return 1;
+}
+
+#define S3C2410_DMAF_CIRCULAR		(1 << 0)
+
+#include <plat/dma.h>
 
 #endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-s3c6400/include/mach/map.h b/arch/arm/mach-s3c6400/include/mach/map.h
index 8199972..5057d99 100644
--- a/arch/arm/mach-s3c6400/include/mach/map.h
+++ b/arch/arm/mach-s3c6400/include/mach/map.h
@@ -39,6 +39,8 @@
 #define S3C_VA_UART3		S3C_VA_UARTx(3)
 
 #define S3C64XX_PA_FB		(0x77100000)
+#define S3C64XX_PA_USB_HSOTG	(0x7C000000)
+#define S3C64XX_PA_WATCHDOG	(0x7E004000)
 #define S3C64XX_PA_SYSCON	(0x7E00F000)
 #define S3C64XX_PA_IIS0		(0x7F002000)
 #define S3C64XX_PA_IIS1		(0x7F003000)
@@ -57,6 +59,8 @@
 #define S3C64XX_PA_MODEM	(0x74108000)
 #define S3C64XX_VA_MODEM	S3C_ADDR(0x00600000)
 
+#define S3C64XX_PA_USBHOST	(0x74300000)
+
 /* place VICs close together */
 #define S3C_VA_VIC0		(S3C_VA_IRQ + 0x00)
 #define S3C_VA_VIC1		(S3C_VA_IRQ + 0x10000)
@@ -69,5 +73,7 @@
 #define S3C_PA_IIC		S3C64XX_PA_IIC0
 #define S3C_PA_IIC1		S3C64XX_PA_IIC1
 #define S3C_PA_FB		S3C64XX_PA_FB
+#define S3C_PA_USBHOST		S3C64XX_PA_USBHOST
+#define S3C_PA_USB_HSOTG	S3C64XX_PA_USB_HSOTG
 
 #endif /* __ASM_ARCH_6400_MAP_H */
diff --git a/arch/arm/mach-s3c6400/include/mach/regs-clock.h b/arch/arm/mach-s3c6400/include/mach/regs-clock.h
new file mode 100644
index 0000000..a6c7f4e
--- /dev/null
+++ b/arch/arm/mach-s3c6400/include/mach/regs-clock.h
@@ -0,0 +1,16 @@
+/* linux/arch/arm/mach-s3c6400/include/mach/regs-clock.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C64XX - clock register compatibility with s3c24xx
+ *
+ * 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 <plat/regs-clock.h>
+
diff --git a/arch/arm/mach-s3c6400/include/mach/system.h b/arch/arm/mach-s3c6400/include/mach/system.h
index 090cfd9..2e58cb7 100644
--- a/arch/arm/mach-s3c6400/include/mach/system.h
+++ b/arch/arm/mach-s3c6400/include/mach/system.h
@@ -11,6 +11,8 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H __FILE__
 
+#include <plat/watchdog-reset.h>
+
 static void arch_idle(void)
 {
 	/* nothing here yet */
@@ -18,7 +20,11 @@
 
 static void arch_reset(char mode, const char *cmd)
 {
-	/* nothing here yet */
+	if (mode != 's')
+		arch_wdt_reset();
+
+	/* if all else fails, or mode was for soft, jump to 0 */
+	cpu_reset(0);
 }
 
 #endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-s3c6400/mach-smdk6400.c b/arch/arm/mach-s3c6400/mach-smdk6400.c
new file mode 100644
index 0000000..ab19285
--- /dev/null
+++ b/arch/arm/mach-s3c6400/mach-smdk6400.c
@@ -0,0 +1,96 @@
+/* linux/arch/arm/mach-s3c6400/mach-smdk6400.c
+ *
+ * Copyright 2008 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/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+
+#include <plat/regs-serial.h>
+
+#include <plat/s3c6400.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/iic.h>
+
+#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 smdk6400_uartcfgs[] __initdata = {
+	[0] = {
+		.hwport	     = 0,
+		.flags	     = 0,
+		.ucon	     = 0x3c5,
+		.ulcon	     = 0x03,
+		.ufcon	     = 0x51,
+	},
+	[1] = {
+		.hwport	     = 1,
+		.flags	     = 0,
+		.ucon	     = 0x3c5,
+		.ulcon	     = 0x03,
+		.ufcon	     = 0x51,
+	},
+};
+
+static struct map_desc smdk6400_iodesc[] = {};
+
+static void __init smdk6400_map_io(void)
+{
+	s3c64xx_init_io(smdk6400_iodesc, ARRAY_SIZE(smdk6400_iodesc));
+	s3c24xx_init_clocks(12000000);
+	s3c24xx_init_uarts(smdk6400_uartcfgs, ARRAY_SIZE(smdk6400_uartcfgs));
+}
+
+static struct platform_device *smdk6400_devices[] __initdata = {
+	&s3c_device_hsmmc1,
+	&s3c_device_i2c0,
+};
+
+static struct i2c_board_info i2c_devs[] __initdata = {
+	{ I2C_BOARD_INFO("wm8753", 0x1A), },
+	{ I2C_BOARD_INFO("24c08", 0x50), },
+};
+
+static void __init smdk6400_machine_init(void)
+{
+	i2c_register_board_info(0, i2c_devs, ARRAY_SIZE(i2c_devs));
+	platform_add_devices(smdk6400_devices, ARRAY_SIZE(smdk6400_devices));
+}
+
+MACHINE_START(SMDK6400, "SMDK6400")
+	/* Maintainer: Ben Dooks <ben@fluff.org> */
+	.phys_io	= S3C_PA_UART & 0xfff00000,
+	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
+	.boot_params	= S3C64XX_PA_SDRAM + 0x100,
+
+	.init_irq	= s3c6400_init_irq,
+	.map_io		= smdk6400_map_io,
+	.init_machine	= smdk6400_machine_init,
+	.timer		= &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c6400/s3c6400.c b/arch/arm/mach-s3c6400/s3c6400.c
new file mode 100644
index 0000000..1ece887
--- /dev/null
+++ b/arch/arm/mach-s3c6400/s3c6400.c
@@ -0,0 +1,89 @@
+/* linux/arch/arm/mach-s3c6410/cpu.c
+ *
+ * Copyright 2009 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/io.h>
+#include <linux/sysdev.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.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 <plat/regs-serial.h>
+#include <plat/regs-clock.h>
+
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+#include <plat/sdhci.h>
+#include <plat/iic-core.h>
+#include <plat/s3c6400.h>
+
+void __init s3c6400_map_io(void)
+{
+	/* setup SDHCI */
+
+	s3c6400_default_sdhci0();
+	s3c6400_default_sdhci1();
+
+	/* the i2c devices are directly compatible with s3c2440 */
+	s3c_i2c0_setname("s3c2440-i2c");
+}
+
+void __init s3c6400_init_clocks(int xtal)
+{
+	printk(KERN_DEBUG "%s: initialising clocks\n", __func__);
+	s3c24xx_register_baseclocks(xtal);
+	s3c64xx_register_clocks();
+	s3c6400_register_clocks(S3C6400_CLKDIV0_ARM_MASK);
+	s3c6400_setup_clocks();
+}
+
+void __init s3c6400_init_irq(void)
+{
+	/* VIC0 does not have IRQS 5..7,
+	 * VIC1 is fully populated. */
+	s3c64xx_init_irq(~0 & ~(0xf << 5), ~0);
+}
+
+struct sysdev_class s3c6400_sysclass = {
+	.name	= "s3c6400-core",
+};
+
+static struct sys_device s3c6400_sysdev = {
+	.cls	= &s3c6400_sysclass,
+};
+
+static int __init s3c6400_core_init(void)
+{
+	return sysdev_class_register(&s3c6400_sysclass);
+}
+
+core_initcall(s3c6400_core_init);
+
+int __init s3c6400_init(void)
+{
+	printk("S3C6400: Initialising architecture\n");
+
+	return sysdev_register(&s3c6400_sysdev);
+}
diff --git a/arch/arm/mach-s3c6400/setup-sdhci.c b/arch/arm/mach-s3c6400/setup-sdhci.c
new file mode 100644
index 0000000..b93dafb
--- /dev/null
+++ b/arch/arm/mach-s3c6400/setup-sdhci.c
@@ -0,0 +1,63 @@
+/* linux/arch/arm/mach-s3c6410/setup-sdhci.c
+ *
+ * Copyright 2008 Simtec Electronics
+ * Copyright 2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * S3C6410 - Helper functions for settign up SDHCI device(s) (HSMMC)
+ *
+ * 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/platform_device.h>
+#include <linux/io.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include <plat/regs-sdhci.h>
+#include <plat/sdhci.h>
+
+/* clock sources for the mmc bus clock, order as for the ctrl2[5..4] */
+
+char *s3c6400_hsmmc_clksrcs[4] = {
+	[0] = "hsmmc",
+	[1] = "hsmmc",
+	[2] = "mmc_bus",
+	/* [3] = "48m", - note not succesfully used yet */
+};
+
+void s3c6400_setup_sdhci_cfg_card(struct platform_device *dev,
+				  void __iomem *r,
+				  struct mmc_ios *ios,
+				  struct mmc_card *card)
+{
+	u32 ctrl2, ctrl3;
+
+	ctrl2 = readl(r + S3C_SDHCI_CONTROL2);
+	ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK;
+	ctrl2 |= (S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR |
+		  S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK |
+		  S3C_SDHCI_CTRL2_ENFBCLKRX |
+		  S3C_SDHCI_CTRL2_DFCNT_NONE |
+		  S3C_SDHCI_CTRL2_ENCLKOUTHOLD);
+
+	if (ios->clock < 25 * 1000000)
+		ctrl3 = (S3C_SDHCI_CTRL3_FCSEL3 |
+			 S3C_SDHCI_CTRL3_FCSEL2 |
+			 S3C_SDHCI_CTRL3_FCSEL1 |
+			 S3C_SDHCI_CTRL3_FCSEL0);
+	else
+		ctrl3 = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0);
+
+	printk(KERN_INFO "%s: CTRL 2=%08x, 3=%08x\n", __func__, ctrl2, ctrl3);
+	writel(ctrl2, r + S3C_SDHCI_CONTROL2);
+	writel(ctrl3, r + S3C_SDHCI_CONTROL3);
+}
+
diff --git a/arch/arm/mach-s3c6410/Kconfig b/arch/arm/mach-s3c6410/Kconfig
index 1d50100..e63aac7 100644
--- a/arch/arm/mach-s3c6410/Kconfig
+++ b/arch/arm/mach-s3c6410/Kconfig
@@ -16,9 +16,18 @@
 
 config S3C6410_SETUP_SDHCI
 	bool
+	select S3C64XX_SETUP_SDHCI_GPIO
 	help
 	  Internal helper functions for S3C6410 based SDHCI systems
 
+config MACH_ANW6410
+	bool "A&W6410"
+	select CPU_S3C6410
+	select S3C_DEV_FB
+	select S3C64XX_SETUP_FB_24BPP
+	help
+	  Machine support for the A&W6410
+
 config MACH_SMDK6410
 	bool "SMDK6410"
 	select CPU_S3C6410
@@ -26,6 +35,8 @@
 	select S3C_DEV_HSMMC1
 	select S3C_DEV_I2C1
 	select S3C_DEV_FB
+	select S3C_DEV_USB_HOST
+	select S3C_DEV_USB_HSOTG
 	select S3C6410_SETUP_SDHCI
 	select S3C64XX_SETUP_I2C1
 	select S3C64XX_SETUP_FB_24BPP
@@ -60,3 +71,29 @@
 	  channels 0 and 1 are the same.
 
 endchoice
+
+config SMDK6410_WM1190_EV1
+	bool "Support Wolfson Microelectronics 1190-EV1 PMIC card"
+	depends on MACH_SMDK6410
+	select REGULATOR
+	select REGULATOR_WM8350
+	select MFD_WM8350_I2C
+	select MFD_WM8350_CONFIG_MODE_0
+	select MFD_WM8350_CONFIG_MODE_3
+	select MFD_WM8352_CONFIG_MODE_0
+	help
+	  The Wolfson Microelectronics 1190-EV1 is a WM835x based PMIC
+	  and audio daughtercard for the Samsung SMDK6410 reference
+	  platform.  Enabling this option will build support for this
+	  module into the kernel.  The presence of the module will be
+	  detected at runtime so the the resulting kernel can be used
+	  with or without the 1190-EV1 fitted.
+
+config MACH_NCP
+	bool "NCP"
+	select CPU_S3C6410
+	select S3C_DEV_I2C1
+	select S3C_DEV_HSMMC1
+	select S3C64XX_SETUP_I2C1
+	help
+          Machine support for the Samsung NCP
diff --git a/arch/arm/mach-s3c6410/Makefile b/arch/arm/mach-s3c6410/Makefile
index 2cd4f18..6f9deac 100644
--- a/arch/arm/mach-s3c6410/Makefile
+++ b/arch/arm/mach-s3c6410/Makefile
@@ -20,4 +20,8 @@
 
 # machine support
 
+obj-$(CONFIG_MACH_ANW6410)	+= mach-anw6410.o
 obj-$(CONFIG_MACH_SMDK6410)	+= mach-smdk6410.o
+obj-$(CONFIG_MACH_NCP)		+= mach-ncp.o
+
+
diff --git a/arch/arm/mach-s3c6410/cpu.c b/arch/arm/mach-s3c6410/cpu.c
index 6a73ca6..ade904d 100644
--- a/arch/arm/mach-s3c6410/cpu.c
+++ b/arch/arm/mach-s3c6410/cpu.c
@@ -31,6 +31,7 @@
 
 #include <plat/cpu-freq.h>
 #include <plat/regs-serial.h>
+#include <plat/regs-clock.h>
 
 #include <plat/cpu.h>
 #include <plat/devs.h>
@@ -68,7 +69,7 @@
 	printk(KERN_DEBUG "%s: initialising clocks\n", __func__);
 	s3c24xx_register_baseclocks(xtal);
 	s3c64xx_register_clocks();
-	s3c6400_register_clocks();
+	s3c6400_register_clocks(S3C6410_CLKDIV0_ARM_MASK);
 	s3c6400_setup_clocks();
 }
 
diff --git a/arch/arm/mach-s3c6410/mach-anw6410.c b/arch/arm/mach-s3c6410/mach-anw6410.c
new file mode 100644
index 0000000..661cca6
--- /dev/null
+++ b/arch/arm/mach-s3c6410/mach-anw6410.c
@@ -0,0 +1,245 @@
+/* linux/arch/arm/mach-s3c6410/mach-anw6410.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ * Copyright 2009 Kwangwoo Lee
+ * 	Kwangwoo Lee <kwangwoo.lee@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+#include <linux/kernel.h>
+#include <linux/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/i2c.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/dm9000.h>
+
+#include <video/platform_lcd.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-fb.h>
+#include <mach/map.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <plat/iic.h>
+#include <plat/fb.h>
+
+#include <plat/s3c6410.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/regs-gpio.h>
+#include <plat/regs-modem.h>
+
+/* DM9000 */
+#define ANW6410_PA_DM9000	(0x18000000)
+
+/* A hardware buffer to control external devices is mapped at 0x30000000.
+ * It can not be read. So current status must be kept in anw6410_extdev_status.
+ */
+#define ANW6410_VA_EXTDEV	S3C_ADDR(0x02000000)
+#define ANW6410_PA_EXTDEV	(0x30000000)
+
+#define ANW6410_EN_DM9000	(1<<11)
+#define ANW6410_EN_LCD		(1<<14)
+
+static __u32 anw6410_extdev_status;
+
+static struct s3c2410_uartcfg anw6410_uartcfgs[] __initdata = {
+	[0] = {
+		.hwport	     = 0,
+		.flags	     = 0,
+		.ucon	     = 0x3c5,
+		.ulcon	     = 0x03,
+		.ufcon	     = 0x51,
+	},
+	[1] = {
+		.hwport	     = 1,
+		.flags	     = 0,
+		.ucon	     = 0x3c5,
+		.ulcon	     = 0x03,
+		.ufcon	     = 0x51,
+	},
+};
+
+/* framebuffer and LCD setup. */
+static void __init anw6410_lcd_mode_set(void)
+{
+	u32 tmp;
+
+	/* set the LCD type */
+	tmp = __raw_readl(S3C64XX_SPCON);
+	tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK;
+	tmp |= S3C64XX_SPCON_LCD_SEL_RGB;
+	__raw_writel(tmp, S3C64XX_SPCON);
+
+	/* remove the LCD bypass */
+	tmp = __raw_readl(S3C64XX_MODEM_MIFPCON);
+	tmp &= ~MIFPCON_LCD_BYPASS;
+	__raw_writel(tmp, S3C64XX_MODEM_MIFPCON);
+}
+
+/* GPF1 = LCD panel power
+ * GPF4 = LCD backlight control
+ */
+static void anw6410_lcd_power_set(struct plat_lcd_data *pd,
+				   unsigned int power)
+{
+	if (power) {
+		anw6410_extdev_status |= (ANW6410_EN_LCD << 16);
+		__raw_writel(anw6410_extdev_status, ANW6410_VA_EXTDEV);
+
+		gpio_direction_output(S3C64XX_GPF(1), 1);
+		gpio_direction_output(S3C64XX_GPF(4), 1);
+	} else {
+		anw6410_extdev_status &= ~(ANW6410_EN_LCD << 16);
+		__raw_writel(anw6410_extdev_status, ANW6410_VA_EXTDEV);
+
+		gpio_direction_output(S3C64XX_GPF(1), 0);
+		gpio_direction_output(S3C64XX_GPF(4), 0);
+	}
+}
+
+static struct plat_lcd_data anw6410_lcd_power_data = {
+	.set_power	= anw6410_lcd_power_set,
+};
+
+static struct platform_device anw6410_lcd_powerdev = {
+	.name			= "platform-lcd",
+	.dev.parent		= &s3c_device_fb.dev,
+	.dev.platform_data	= &anw6410_lcd_power_data,
+};
+
+static struct s3c_fb_pd_win anw6410_fb_win0 = {
+	/* this is to ensure we use win0 */
+	.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,
+	},
+	.max_bpp	= 32,
+	.default_bpp	= 16,
+};
+
+/* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
+static struct s3c_fb_platdata anw6410_lcd_pdata __initdata = {
+	.setup_gpio	= s3c64xx_fb_gpio_setup_24bpp,
+	.win[0]		= &anw6410_fb_win0,
+	.vidcon0	= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+	.vidcon1	= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+};
+
+/* DM9000AEP 10/100 ethernet controller */
+static void __init anw6410_dm9000_enable(void)
+{
+	anw6410_extdev_status |= (ANW6410_EN_DM9000 << 16);
+	__raw_writel(anw6410_extdev_status, ANW6410_VA_EXTDEV);
+}
+
+static struct resource anw6410_dm9000_resource[] = {
+	[0] = {
+		.start = ANW6410_PA_DM9000,
+		.end   = ANW6410_PA_DM9000 + 3,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = ANW6410_PA_DM9000 + 4,
+		.end   = ANW6410_PA_DM9000 + 4 + 500,
+		.flags = IORESOURCE_MEM,
+	},
+	[2] = {
+		.start = IRQ_EINT(15),
+		.end   = IRQ_EINT(15),
+		.flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
+	},
+};
+
+static struct dm9000_plat_data anw6410_dm9000_pdata = {
+	.flags	  = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
+	/* dev_addr can be set to provide hwaddr. */
+};
+
+static struct platform_device anw6410_device_eth = {
+	.name	= "dm9000",
+	.id	= -1,
+	.num_resources	= ARRAY_SIZE(anw6410_dm9000_resource),
+	.resource	= anw6410_dm9000_resource,
+	.dev	= {
+		.platform_data  = &anw6410_dm9000_pdata,
+	},
+};
+
+static struct map_desc anw6410_iodesc[] __initdata = {
+	{
+		.virtual	= (unsigned long)ANW6410_VA_EXTDEV,
+		.pfn		= __phys_to_pfn(ANW6410_PA_EXTDEV),
+		.length		= SZ_64K,
+		.type		= MT_DEVICE,
+	},
+};
+
+static struct platform_device *anw6410_devices[] __initdata = {
+	&s3c_device_fb,
+	&anw6410_lcd_powerdev,
+	&anw6410_device_eth,
+};
+
+static void __init anw6410_map_io(void)
+{
+	s3c64xx_init_io(anw6410_iodesc, ARRAY_SIZE(anw6410_iodesc));
+	s3c24xx_init_clocks(12000000);
+	s3c24xx_init_uarts(anw6410_uartcfgs, ARRAY_SIZE(anw6410_uartcfgs));
+
+	anw6410_lcd_mode_set();
+}
+
+static void __init anw6410_machine_init(void)
+{
+	s3c_fb_set_platdata(&anw6410_lcd_pdata);
+
+	gpio_request(S3C64XX_GPF(1), "panel power");
+	gpio_request(S3C64XX_GPF(4), "LCD backlight");
+
+	anw6410_dm9000_enable();
+
+	platform_add_devices(anw6410_devices, ARRAY_SIZE(anw6410_devices));
+}
+
+MACHINE_START(ANW6410, "A&W6410")
+	/* Maintainer: Kwangwoo Lee <kwangwoo.lee@gmail.com> */
+	.phys_io	= S3C_PA_UART & 0xfff00000,
+	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
+	.boot_params	= S3C64XX_PA_SDRAM + 0x100,
+
+	.init_irq	= s3c6410_init_irq,
+	.map_io		= anw6410_map_io,
+	.init_machine	= anw6410_machine_init,
+	.timer		= &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c6410/mach-ncp.c b/arch/arm/mach-s3c6410/mach-ncp.c
new file mode 100644
index 0000000..6030636
--- /dev/null
+++ b/arch/arm/mach-s3c6410/mach-ncp.c
@@ -0,0 +1,107 @@
+/*
+ * linux/arch/arm/mach-s3c6410/mach-ncp.c
+ *
+ * Copyright (C) 2008-2009 Samsung Electronics
+ *
+ * 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/i2c.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include <video/platform_lcd.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-fb.h>
+#include <mach/map.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <plat/iic.h>
+#include <plat/fb.h>
+
+#include <plat/s3c6410.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg ncp_uartcfgs[] __initdata = {
+	/* REVISIT: NCP uses only serial 1, 2 */
+	[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,
+	},
+};
+
+static struct platform_device *ncp_devices[] __initdata = {
+	&s3c_device_hsmmc1,
+	&s3c_device_i2c0,
+};
+
+struct map_desc ncp_iodesc[] = {};
+
+static void __init ncp_map_io(void)
+{
+	s3c64xx_init_io(ncp_iodesc, ARRAY_SIZE(ncp_iodesc));
+	s3c24xx_init_clocks(12000000);
+	s3c24xx_init_uarts(ncp_uartcfgs, ARRAY_SIZE(ncp_uartcfgs));
+}
+
+static void __init ncp_machine_init(void)
+{
+	s3c_i2c0_set_platdata(NULL);
+
+	platform_add_devices(ncp_devices, ARRAY_SIZE(ncp_devices));
+}
+
+MACHINE_START(NCP, "NCP")
+	/* Maintainer: Samsung Electronics */
+	.phys_io	= S3C_PA_UART & 0xfff00000,
+	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
+	.boot_params	= S3C64XX_PA_SDRAM + 0x100,
+	.init_irq	= s3c6410_init_irq,
+	.map_io		= ncp_map_io,
+	.init_machine	= ncp_machine_init,
+	.timer		= &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c6410/mach-smdk6410.c b/arch/arm/mach-s3c6410/mach-smdk6410.c
index 7f473e4..bc9a7de 100644
--- a/arch/arm/mach-s3c6410/mach-smdk6410.c
+++ b/arch/arm/mach-s3c6410/mach-smdk6410.c
@@ -24,6 +24,12 @@
 #include <linux/fb.h>
 #include <linux/gpio.h>
 #include <linux/delay.h>
+#include <linux/smsc911x.h>
+
+#ifdef CONFIG_SMDK6410_WM1190_EV1
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/pmic.h>
+#endif
 
 #include <video/platform_lcd.h>
 
@@ -39,8 +45,12 @@
 #include <asm/mach-types.h>
 
 #include <plat/regs-serial.h>
+#include <plat/regs-modem.h>
+#include <plat/regs-gpio.h>
+#include <plat/regs-sys.h>
 #include <plat/iic.h>
 #include <plat/fb.h>
+#include <plat/gpio-cfg.h>
 
 #include <plat/s3c6410.h>
 #include <plat/clock.h>
@@ -129,6 +139,37 @@
 	.vidcon1	= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
 };
 
+static struct resource smdk6410_smsc911x_resources[] = {
+	[0] = {
+		.start = 0x18000000,
+		.end   = 0x18000000 + SZ_64K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = S3C_EINT(10),
+		.end   = S3C_EINT(10),
+		.flags = IORESOURCE_IRQ | IRQ_TYPE_LEVEL_LOW,
+	},
+};
+
+static struct smsc911x_platform_config smdk6410_smsc911x_pdata = {
+	.irq_polarity  = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type      = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+	.flags         = SMSC911X_USE_32BIT | SMSC911X_FORCE_INTERNAL_PHY,
+	.phy_interface = PHY_INTERFACE_MODE_MII,
+};
+
+
+static struct platform_device smdk6410_smsc911x = {
+	.name          = "smsc911x",
+	.id            = -1,
+	.num_resources = ARRAY_SIZE(smdk6410_smsc911x_resources),
+	.resource      = &smdk6410_smsc911x_resources[0],
+	.dev = {
+		.platform_data = &smdk6410_smsc911x_pdata,
+	},
+};
+
 static struct map_desc smdk6410_iodesc[] = {};
 
 static struct platform_device *smdk6410_devices[] __initdata = {
@@ -141,12 +182,155 @@
 	&s3c_device_i2c0,
 	&s3c_device_i2c1,
 	&s3c_device_fb,
+	&s3c_device_usb,
+	&s3c_device_usb_hsotg,
 	&smdk6410_lcd_powerdev,
+
+	&smdk6410_smsc911x,
 };
 
+#ifdef CONFIG_SMDK6410_WM1190_EV1
+/* S3C64xx internal logic & PLL */
+static struct regulator_init_data wm8350_dcdc1_data = {
+	.constraints = {
+		.name = "PVDD_INT/PVDD_PLL",
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.always_on = 1,
+		.apply_uV = 1,
+	},
+};
+
+/* Memory */
+static struct regulator_init_data wm8350_dcdc3_data = {
+	.constraints = {
+		.name = "PVDD_MEM",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.always_on = 1,
+		.state_mem = {
+			 .uV = 1800000,
+			 .mode = REGULATOR_MODE_NORMAL,
+			 .enabled = 1,
+		 },
+		.initial_state = PM_SUSPEND_MEM,
+	},
+};
+
+/* USB, EXT, PCM, ADC/DAC, USB, MMC */
+static struct regulator_init_data wm8350_dcdc4_data = {
+	.constraints = {
+		.name = "PVDD_HI/PVDD_EXT/PVDD_SYS/PVCCM2MTV",
+		.min_uV = 3000000,
+		.max_uV = 3000000,
+		.always_on = 1,
+	},
+};
+
+/* ARM core */
+static struct regulator_consumer_supply dcdc6_consumers[] = {
+	{
+		.supply = "vddarm",
+	}
+};
+
+static struct regulator_init_data wm8350_dcdc6_data = {
+	.constraints = {
+		.name = "PVDD_ARM",
+		.min_uV = 1000000,
+		.max_uV = 1300000,
+		.always_on = 1,
+		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+	},
+	.num_consumer_supplies = ARRAY_SIZE(dcdc6_consumers),
+	.consumer_supplies = dcdc6_consumers,
+};
+
+/* Alive */
+static struct regulator_init_data wm8350_ldo1_data = {
+	.constraints = {
+		.name = "PVDD_ALIVE",
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.always_on = 1,
+		.apply_uV = 1,
+	},
+};
+
+/* OTG */
+static struct regulator_init_data wm8350_ldo2_data = {
+	.constraints = {
+		.name = "PVDD_OTG",
+		.min_uV = 3300000,
+		.max_uV = 3300000,
+		.always_on = 1,
+	},
+};
+
+/* LCD */
+static struct regulator_init_data wm8350_ldo3_data = {
+	.constraints = {
+		.name = "PVDD_LCD",
+		.min_uV = 3000000,
+		.max_uV = 3000000,
+		.always_on = 1,
+	},
+};
+
+/* OTGi/1190-EV1 HPVDD & AVDD */
+static struct regulator_init_data wm8350_ldo4_data = {
+	.constraints = {
+		.name = "PVDD_OTGI/HPVDD/AVDD",
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.apply_uV = 1,
+		.always_on = 1,
+	},
+};
+
+static struct {
+	int regulator;
+	struct regulator_init_data *initdata;
+} wm1190_regulators[] = {
+	{ WM8350_DCDC_1, &wm8350_dcdc1_data },
+	{ WM8350_DCDC_3, &wm8350_dcdc3_data },
+	{ WM8350_DCDC_4, &wm8350_dcdc4_data },
+	{ WM8350_DCDC_6, &wm8350_dcdc6_data },
+	{ WM8350_LDO_1, &wm8350_ldo1_data },
+	{ WM8350_LDO_2, &wm8350_ldo2_data },
+	{ WM8350_LDO_3, &wm8350_ldo3_data },
+	{ WM8350_LDO_4, &wm8350_ldo4_data },
+};
+
+static int __init smdk6410_wm8350_init(struct wm8350 *wm8350)
+{
+	int i;
+
+	/* Instantiate the regulators */
+	for (i = 0; i < ARRAY_SIZE(wm1190_regulators); i++)
+		wm8350_register_regulator(wm8350,
+					  wm1190_regulators[i].regulator,
+					  wm1190_regulators[i].initdata);
+
+	return 0;
+}
+
+static struct wm8350_platform_data __initdata smdk6410_wm8350_pdata = {
+	.init = smdk6410_wm8350_init,
+	.irq_high = 1,
+};
+#endif
+
 static struct i2c_board_info i2c_devs0[] __initdata = {
 	{ I2C_BOARD_INFO("24c08", 0x50), },
 	{ I2C_BOARD_INFO("wm8580", 0x1b), },
+
+#ifdef CONFIG_SMDK6410_WM1190_EV1
+	{ I2C_BOARD_INFO("wm8350", 0x1a),
+	  .platform_data = &smdk6410_wm8350_pdata,
+	  .irq = S3C_EINT(12),
+	},
+#endif
 };
 
 static struct i2c_board_info i2c_devs1[] __initdata = {
@@ -155,9 +339,23 @@
 
 static void __init smdk6410_map_io(void)
 {
+	u32 tmp;
+
 	s3c64xx_init_io(smdk6410_iodesc, ARRAY_SIZE(smdk6410_iodesc));
 	s3c24xx_init_clocks(12000000);
 	s3c24xx_init_uarts(smdk6410_uartcfgs, ARRAY_SIZE(smdk6410_uartcfgs));
+
+	/* set the LCD type */
+
+	tmp = __raw_readl(S3C64XX_SPCON);
+	tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK;
+	tmp |= S3C64XX_SPCON_LCD_SEL_RGB;
+	__raw_writel(tmp, S3C64XX_SPCON);
+
+	/* remove the lcd bypass */
+	tmp = __raw_readl(S3C64XX_MODEM_MIFPCON);
+	tmp &= ~MIFPCON_LCD_BYPASS;
+	__raw_writel(tmp, S3C64XX_MODEM_MIFPCON);
 }
 
 static void __init smdk6410_machine_init(void)
diff --git a/arch/arm/mach-s3c6410/setup-sdhci.c b/arch/arm/mach-s3c6410/setup-sdhci.c
index 0b5788b..20666f3 100644
--- a/arch/arm/mach-s3c6410/setup-sdhci.c
+++ b/arch/arm/mach-s3c6410/setup-sdhci.c
@@ -21,8 +21,6 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 
-#include <mach/gpio.h>
-#include <plat/gpio-cfg.h>
 #include <plat/regs-sdhci.h>
 #include <plat/sdhci.h>
 
@@ -35,22 +33,6 @@
 	/* [3] = "48m", - note not succesfully used yet */
 };
 
-void s3c6410_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
-{
-	unsigned int gpio;
-	unsigned int end;
-
-	end = S3C64XX_GPG(2 + width);
-
-	/* Set all the necessary GPG pins to special-function 0 */
-	for (gpio = S3C64XX_GPG(0); gpio < end; gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
-
-	s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
-	s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(2));
-}
 
 void s3c6410_setup_sdhci0_cfg_card(struct platform_device *dev,
 				    void __iomem *r,
@@ -84,19 +66,3 @@
 	writel(ctrl3, r + S3C_SDHCI_CONTROL3);
 }
 
-void s3c6410_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
-{
-	unsigned int gpio;
-	unsigned int end;
-
-	end = S3C64XX_GPH(2 + width);
-
-	/* Set all the necessary GPG pins to special-function 0 */
-	for (gpio = S3C64XX_GPH(0); gpio < end; gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
-
-	s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
-	s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(3));
-}
diff --git a/arch/arm/mach-sa1100/collie_pm.c b/arch/arm/mach-sa1100/collie_pm.c
deleted file mode 100644
index 444f266..0000000
--- a/arch/arm/mach-sa1100/collie_pm.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Based on spitz_pm.c and sharp code.
- *
- * Copyright (C) 2001  SHARP
- * Copyright 2005 Pavel Machek <pavel@suse.cz>
- *
- * Distribute under GPLv2.
- *
- * Li-ion batteries are angry beasts, and they like to explode. This driver is not finished,
- * and sometimes charges them when it should not. If it makes angry lithium to come your way...
- * ...well, you have been warned.
- *
- * Actually, this should be quite safe, it seems sharp leaves charger enabled by default,
- * and my collie did not explode (yet).
- */
-
-#include <linux/module.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <asm/hardware/scoop.h>
-#include <mach/dma.h>
-#include <mach/collie.h>
-#include <asm/mach/sharpsl_param.h>
-#include <asm/hardware/sharpsl_pm.h>
-
-#include "../drivers/mfd/ucb1x00.h"
-
-static struct ucb1x00 *ucb;
-static int ad_revise;
-
-#define ADCtoPower(x)	       ((330 * x * 2) / 1024)
-
-static void collie_charger_init(void)
-{
-	int err;
-
-	if (sharpsl_param.adadj != -1)
-		ad_revise = sharpsl_param.adadj;
-
-	/* Register interrupt handler. */
-	if ((err = request_irq(COLLIE_IRQ_GPIO_AC_IN, sharpsl_ac_isr, IRQF_DISABLED,
-			       "ACIN", sharpsl_ac_isr))) {
-		printk("Could not get irq %d.\n", COLLIE_IRQ_GPIO_AC_IN);
-		return;
-	}
-	if ((err = request_irq(COLLIE_IRQ_GPIO_CO, sharpsl_chrg_full_isr, IRQF_DISABLED,
-			       "CO", sharpsl_chrg_full_isr))) {
-		free_irq(COLLIE_IRQ_GPIO_AC_IN, sharpsl_ac_isr);
-		printk("Could not get irq %d.\n", COLLIE_IRQ_GPIO_CO);
-		return;
-	}
-
-	gpio_request(COLLIE_GPIO_CHARGE_ON, "charge on");
-	gpio_direction_output(COLLIE_GPIO_CHARGE_ON, 1);
-
-	ucb1x00_io_set_dir(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON | COLLIE_TC35143_GPIO_TMP_ON |
-			           COLLIE_TC35143_GPIO_BBAT_ON);
-	return;
-}
-
-static void collie_measure_temp(int on)
-{
-	if (on)
-		ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0);
-	else
-		ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON);
-}
-
-static void collie_charge(int on)
-{
-	/* Zaurus seems to contain LTC1731; it should know when to
-	 * stop charging itself, so setting charge on should be
-	 * relatively harmless (as long as it is not done too often).
-	 */
-	gpio_set_value(COLLIE_GPIO_CHARGE_ON, on);
-}
-
-static void collie_discharge(int on)
-{
-}
-
-static void collie_discharge1(int on)
-{
-}
-
-static void collie_presuspend(void)
-{
-}
-
-static void collie_postsuspend(void)
-{
-}
-
-static int collie_should_wakeup(unsigned int resume_on_alarm)
-{
-	return 0;
-}
-
-static unsigned long collie_charger_wakeup(void)
-{
-	return 0;
-}
-
-int collie_read_backup_battery(void)
-{
-	int voltage;
-
-	ucb1x00_adc_enable(ucb);
-
-	ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_BBAT_ON, 0);
-	voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC);
-
-	ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON);
-	ucb1x00_adc_disable(ucb);
-
-	printk("Backup battery = %d(%d)\n", ADCtoPower(voltage), voltage);
-
-	return ADCtoPower(voltage);
-}
-
-int collie_read_main_battery(void)
-{
-	int voltage, voltage_rev, voltage_volts;
-
-	ucb1x00_adc_enable(ucb);
-	ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON);
-	ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_MBAT_ON, 0);
-
-	mdelay(1);
-	voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC);
-
-	ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON);
-	ucb1x00_adc_disable(ucb);
-
-	voltage_rev = voltage + ((ad_revise * voltage) / 652);
-	voltage_volts = ADCtoPower(voltage_rev);
-
-	printk("Main battery = %d(%d)\n", voltage_volts, voltage);
-
-	if (voltage != -1)
-		return voltage_volts;
-	else
-		return voltage;
-}
-
-int collie_read_temp(void)
-{
-	int voltage;
-
-	/* According to Sharp, temp must be > 973, main battery must be < 465,
-	   FIXME: sharpsl_pm.c has both conditions negated? FIXME: values
-	   are way out of range? */
-
-	ucb1x00_adc_enable(ucb);
-	ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0);
-	/* >1010 = battery removed, 460 = 22C ?, higher = lower temp ? */
-	voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD0, UCB_SYNC);
-	ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON);
-	ucb1x00_adc_disable(ucb);
-
-	printk("Battery temp = %d\n", voltage);
-	return voltage;
-}
-
-static unsigned long read_devdata(int which)
-{
-	switch (which) {
-	case SHARPSL_BATT_VOLT:
-		return collie_read_main_battery();
-	case SHARPSL_BATT_TEMP:
-		return collie_read_temp();
-	case SHARPSL_ACIN_VOLT:
-		return 500;
-	case SHARPSL_STATUS_ACIN: {
-		int ret = GPLR & COLLIE_GPIO_AC_IN;
-		printk("AC status = %d\n", ret);
-		return ret;
-	}
-	case SHARPSL_STATUS_FATAL: {
-		int ret = GPLR & COLLIE_GPIO_MAIN_BAT_LOW;
-		printk("Fatal bat = %d\n", ret);
-		return ret;
-	}
-	default:
-		return ~0;
-	}
-}
-
-struct battery_thresh collie_battery_levels_acin[] = {
-	{ 420, 100},
-	{ 417,  95},
-	{ 415,  90},
-	{ 413,  80},
-	{ 411,  75},
-	{ 408,  70},
-	{ 406,  60},
-	{ 403,  50},
-	{ 398,  40},
-	{ 391,  25},
-	{  10,   5},
-	{   0,   0},
-};
-
-struct battery_thresh collie_battery_levels[] = {
-	{ 394, 100},
-	{ 390,  95},
-	{ 380,  90},
-	{ 370,  80},
-	{ 368,  75},	/* From sharp code: battery high with frontlight */
-	{ 366,  70},	/* 60..90 -- fake values invented by me for testing */
-	{ 364,  60},
-	{ 362,  50},
-	{ 360,  40},
-	{ 358,  25},	/* From sharp code: battery low with frontlight */
-	{ 356,   5},	/* From sharp code: battery verylow with frontlight */
-	{   0,   0},
-};
-
-struct sharpsl_charger_machinfo collie_pm_machinfo = {
-	.init             = collie_charger_init,
-	.read_devdata	  = read_devdata,
-	.discharge        = collie_discharge,
-	.discharge1       = collie_discharge1,
-	.charge           = collie_charge,
-	.measure_temp     = collie_measure_temp,
-	.presuspend       = collie_presuspend,
-	.postsuspend      = collie_postsuspend,
-	.charger_wakeup   = collie_charger_wakeup,
-	.should_wakeup    = collie_should_wakeup,
-	.bat_levels       = 12,
-	.bat_levels_noac  = collie_battery_levels,
-	.bat_levels_acin  = collie_battery_levels_acin,
-	.status_high_acin = 368,
-	.status_low_acin  = 358,
-	.status_high_noac = 368,
-	.status_low_noac  = 358,
-	.charge_on_volt	  = 350,	/* spitz uses 2.90V, but lets play it safe. */
-	.charge_on_temp   = 550,
-	.charge_acin_high = 550,	/* collie does not seem to have sensor for this, anyway */
-	.charge_acin_low  = 450,	/* ignored, too */
-	.fatal_acin_volt  = 356,
-	.fatal_noacin_volt = 356,
-
-	.batfull_irq = 1,		/* We do not want periodical charge restarts */
-};
-
-static int __init collie_pm_ucb_add(struct ucb1x00_dev *pdev)
-{
-	sharpsl_pm.machinfo = &collie_pm_machinfo;
-	ucb = pdev->ucb;
-	return 0;
-}
-
-static struct ucb1x00_driver collie_pm_ucb_driver = {
-	.add	= collie_pm_ucb_add,
-};
-
-static struct platform_device *collie_pm_device;
-
-static int __init collie_pm_init(void)
-{
-	int ret;
-
-	collie_pm_device = platform_device_alloc("sharpsl-pm", -1);
-	if (!collie_pm_device)
-		return -ENOMEM;
-
-	collie_pm_device->dev.platform_data = &collie_pm_machinfo;
-	ret = platform_device_add(collie_pm_device);
-
-	if (ret)
-		platform_device_put(collie_pm_device);
-
-	if (!ret)
-		ret = ucb1x00_register_driver(&collie_pm_ucb_driver);
-
-	return ret;
-}
-
-static void __exit collie_pm_exit(void)
-{
-	ucb1x00_unregister_driver(&collie_pm_ucb_driver);
-	platform_device_unregister(collie_pm_device);
-}
-
-module_init(collie_pm_init);
-module_exit(collie_pm_exit);
diff --git a/arch/arm/mach-stmp378x/Makefile b/arch/arm/mach-stmp378x/Makefile
new file mode 100644
index 0000000..d156f76
--- /dev/null
+++ b/arch/arm/mach-stmp378x/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ARCH_STMP378X) += stmp378x.o
+obj-$(CONFIG_MACH_STMP378X) += stmp378x_devb.o
diff --git a/arch/arm/mach-stmp378x/Makefile.boot b/arch/arm/mach-stmp378x/Makefile.boot
new file mode 100644
index 0000000..1568ad4
--- /dev/null
+++ b/arch/arm/mach-stmp378x/Makefile.boot
@@ -0,0 +1,3 @@
+   zreladdr-y	:= 0x40008000
+params_phys-y	:= 0x40000100
+initrd_phys-y	:= 0x40800000
diff --git a/arch/arm/mach-stmp378x/include/mach/entry-macro.S b/arch/arm/mach-stmp378x/include/mach/entry-macro.S
new file mode 100644
index 0000000..731a922
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/entry-macro.S
@@ -0,0 +1,35 @@
+/*
+ * Low-level IRQ helper macros for Freescale STMP378X
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+
+		.macro	disable_fiq
+		.endm
+
+		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+	        mov	\base, #0xf0000000	@ vm address of IRQ controller
+		ldr	\irqnr, [\base, #0x70]	@ HW_ICOLL_STAT
+		cmp	\irqnr, #0x7f
+		moveqs	\irqnr, #0		@ Zero flag set for no IRQ
+
+		.endm
+
+                .macro  get_irqnr_preamble, base, tmp
+                .endm
+
+                .macro  arch_ret_to_user, tmp1, tmp2
+                .endm
diff --git a/arch/arm/mach-stmp378x/include/mach/irqs.h b/arch/arm/mach-stmp378x/include/mach/irqs.h
new file mode 100644
index 0000000..cc59673
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/irqs.h
@@ -0,0 +1,95 @@
+/*
+ * Freescale STMP378X interrupts
+ *
+ * Copyright (C) 2005 Sigmatel Inc
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+
+#define IRQ_DEBUG_UART			0
+#define IRQ_COMMS_RX			1
+#define IRQ_COMMS_TX			1
+#define IRQ_SSP2_ERROR			2
+#define IRQ_VDD5V			3
+#define IRQ_HEADPHONE_SHORT		4
+#define IRQ_DAC_DMA			5
+#define IRQ_DAC_ERROR			6
+#define IRQ_ADC_DMA			7
+#define IRQ_ADC_ERROR			8
+#define IRQ_SPDIF_DMA			9
+#define IRQ_SAIF2_DMA			9
+#define IRQ_SPDIF_ERROR			10
+#define IRQ_SAIF1_IRQ			10
+#define IRQ_SAIF2_IRQ			10
+#define IRQ_USB_CTRL			11
+#define IRQ_USB_WAKEUP			12
+#define IRQ_GPMI_DMA			13
+#define IRQ_SSP1_DMA			14
+#define IRQ_SSP_ERROR			15
+#define IRQ_GPIO0			16
+#define IRQ_GPIO1			17
+#define IRQ_GPIO2			18
+#define IRQ_SAIF1_DMA			19
+#define IRQ_SSP2_DMA			20
+#define IRQ_ECC8_IRQ			21
+#define IRQ_RTC_ALARM			22
+#define IRQ_UARTAPP_TX_DMA		23
+#define IRQ_UARTAPP_INTERNAL		24
+#define IRQ_UARTAPP_RX_DMA		25
+#define IRQ_I2C_DMA			26
+#define IRQ_I2C_ERROR			27
+#define IRQ_TIMER0			28
+#define IRQ_TIMER1			29
+#define IRQ_TIMER2			30
+#define IRQ_TIMER3			31
+#define IRQ_BATT_BRNOUT			32
+#define IRQ_VDDD_BRNOUT			33
+#define IRQ_VDDIO_BRNOUT		34
+#define IRQ_VDD18_BRNOUT		35
+#define IRQ_TOUCH_DETECT		36
+#define IRQ_LRADC_CH0			37
+#define IRQ_LRADC_CH1			38
+#define IRQ_LRADC_CH2			39
+#define IRQ_LRADC_CH3			40
+#define IRQ_LRADC_CH4			41
+#define IRQ_LRADC_CH5			42
+#define IRQ_LRADC_CH6			43
+#define IRQ_LRADC_CH7			44
+#define IRQ_LCDIF_DMA			45
+#define IRQ_LCDIF_ERROR			46
+#define IRQ_DIGCTL_DEBUG_TRAP		47
+#define IRQ_RTC_1MSEC			48
+#define IRQ_DRI_DMA			49
+#define IRQ_DRI_ATTENTION		50
+#define IRQ_GPMI_ATTENTION		51
+#define IRQ_IR				52
+#define IRQ_DCP_VMI			53
+#define IRQ_DCP				54
+#define IRQ_BCH				56
+#define IRQ_PXP				57
+#define IRQ_UARTAPP2_TX_DMA		58
+#define IRQ_UARTAPP2_INTERNAL		59
+#define IRQ_UARTAPP2_RX_DMA		60
+#define IRQ_VDAC_DETECT			61
+#define IRQ_VDD5V_DROOP			64
+#define IRQ_DCDC4P2_BO			65
+
+
+#define NR_REAL_IRQS	128
+#define NR_IRQS		(NR_REAL_IRQS + 32 * 3)
+
+/* All interrupts are FIQ capable */
+#define FIQ_START		IRQ_DEBUG_UART
+
+/* Hard disk IRQ is a GPMI attention IRQ */
+#define IRQ_HARDDISK		IRQ_GPMI_ATTENTION
diff --git a/arch/arm/mach-stmp378x/include/mach/pins.h b/arch/arm/mach-stmp378x/include/mach/pins.h
new file mode 100644
index 0000000..93f952d
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/pins.h
@@ -0,0 +1,151 @@
+/*
+ * Freescale STMP378X SoC pin multiplexing
+ *
+ * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __ASM_ARCH_PINS_H
+#define __ASM_ARCH_PINS_H
+
+/*
+ * Define all STMP378x pins, a pin name corresponds to a STMP378x hardware
+ * interface  this pin belongs to.
+ */
+
+/* Bank 0 */
+#define PINID_GPMI_D00		STMP3XXX_PINID(0, 0)
+#define PINID_GPMI_D01		STMP3XXX_PINID(0, 1)
+#define PINID_GPMI_D02		STMP3XXX_PINID(0, 2)
+#define PINID_GPMI_D03		STMP3XXX_PINID(0, 3)
+#define PINID_GPMI_D04		STMP3XXX_PINID(0, 4)
+#define PINID_GPMI_D05		STMP3XXX_PINID(0, 5)
+#define PINID_GPMI_D06		STMP3XXX_PINID(0, 6)
+#define PINID_GPMI_D07		STMP3XXX_PINID(0, 7)
+#define PINID_GPMI_D08		STMP3XXX_PINID(0, 8)
+#define PINID_GPMI_D09		STMP3XXX_PINID(0, 9)
+#define PINID_GPMI_D10		STMP3XXX_PINID(0, 10)
+#define PINID_GPMI_D11		STMP3XXX_PINID(0, 11)
+#define PINID_GPMI_D12		STMP3XXX_PINID(0, 12)
+#define PINID_GPMI_D13		STMP3XXX_PINID(0, 13)
+#define PINID_GPMI_D14		STMP3XXX_PINID(0, 14)
+#define PINID_GPMI_D15		STMP3XXX_PINID(0, 15)
+#define PINID_GPMI_CLE		STMP3XXX_PINID(0, 16)
+#define PINID_GPMI_ALE		STMP3XXX_PINID(0, 17)
+#define PINID_GMPI_CE2N		STMP3XXX_PINID(0, 18)
+#define PINID_GPMI_RDY0		STMP3XXX_PINID(0, 19)
+#define PINID_GPMI_RDY1		STMP3XXX_PINID(0, 20)
+#define PINID_GPMI_RDY2		STMP3XXX_PINID(0, 21)
+#define PINID_GPMI_RDY3		STMP3XXX_PINID(0, 22)
+#define PINID_GPMI_WPN		STMP3XXX_PINID(0, 23)
+#define PINID_GPMI_WRN		STMP3XXX_PINID(0, 24)
+#define PINID_GPMI_RDN		STMP3XXX_PINID(0, 25)
+#define PINID_AUART1_CTS	STMP3XXX_PINID(0, 26)
+#define PINID_AUART1_RTS	STMP3XXX_PINID(0, 27)
+#define PINID_AUART1_RX		STMP3XXX_PINID(0, 28)
+#define PINID_AUART1_TX		STMP3XXX_PINID(0, 29)
+#define PINID_I2C_SCL		STMP3XXX_PINID(0, 30)
+#define PINID_I2C_SDA		STMP3XXX_PINID(0, 31)
+
+/* Bank 1 */
+#define PINID_LCD_D00		STMP3XXX_PINID(1, 0)
+#define PINID_LCD_D01		STMP3XXX_PINID(1, 1)
+#define PINID_LCD_D02		STMP3XXX_PINID(1, 2)
+#define PINID_LCD_D03		STMP3XXX_PINID(1, 3)
+#define PINID_LCD_D04		STMP3XXX_PINID(1, 4)
+#define PINID_LCD_D05		STMP3XXX_PINID(1, 5)
+#define PINID_LCD_D06		STMP3XXX_PINID(1, 6)
+#define PINID_LCD_D07		STMP3XXX_PINID(1, 7)
+#define PINID_LCD_D08		STMP3XXX_PINID(1, 8)
+#define PINID_LCD_D09		STMP3XXX_PINID(1, 9)
+#define PINID_LCD_D10		STMP3XXX_PINID(1, 10)
+#define PINID_LCD_D11		STMP3XXX_PINID(1, 11)
+#define PINID_LCD_D12		STMP3XXX_PINID(1, 12)
+#define PINID_LCD_D13		STMP3XXX_PINID(1, 13)
+#define PINID_LCD_D14		STMP3XXX_PINID(1, 14)
+#define PINID_LCD_D15		STMP3XXX_PINID(1, 15)
+#define PINID_LCD_D16		STMP3XXX_PINID(1, 16)
+#define PINID_LCD_D17		STMP3XXX_PINID(1, 17)
+#define PINID_LCD_RESET		STMP3XXX_PINID(1, 18)
+#define PINID_LCD_RS		STMP3XXX_PINID(1, 19)
+#define PINID_LCD_WR		STMP3XXX_PINID(1, 20)
+#define PINID_LCD_CS		STMP3XXX_PINID(1, 21)
+#define PINID_LCD_DOTCK		STMP3XXX_PINID(1, 22)
+#define PINID_LCD_ENABLE	STMP3XXX_PINID(1, 23)
+#define PINID_LCD_HSYNC		STMP3XXX_PINID(1, 24)
+#define PINID_LCD_VSYNC		STMP3XXX_PINID(1, 25)
+#define PINID_PWM0		STMP3XXX_PINID(1, 26)
+#define PINID_PWM1		STMP3XXX_PINID(1, 27)
+#define PINID_PWM2		STMP3XXX_PINID(1, 28)
+#define PINID_PWM3		STMP3XXX_PINID(1, 29)
+#define PINID_PWM4		STMP3XXX_PINID(1, 30)
+
+/* Bank 2 */
+#define PINID_SSP1_CMD		STMP3XXX_PINID(2, 0)
+#define PINID_SSP1_DETECT	STMP3XXX_PINID(2, 1)
+#define PINID_SSP1_DATA0	STMP3XXX_PINID(2, 2)
+#define PINID_SSP1_DATA1	STMP3XXX_PINID(2, 3)
+#define PINID_SSP1_DATA2	STMP3XXX_PINID(2, 4)
+#define PINID_SSP1_DATA3	STMP3XXX_PINID(2, 5)
+#define PINID_SSP1_SCK		STMP3XXX_PINID(2, 6)
+#define PINID_ROTARYA		STMP3XXX_PINID(2, 7)
+#define PINID_ROTARYB		STMP3XXX_PINID(2, 8)
+#define PINID_EMI_A00		STMP3XXX_PINID(2, 9)
+#define PINID_EMI_A01		STMP3XXX_PINID(2, 10)
+#define PINID_EMI_A02		STMP3XXX_PINID(2, 11)
+#define PINID_EMI_A03		STMP3XXX_PINID(2, 12)
+#define PINID_EMI_A04		STMP3XXX_PINID(2, 13)
+#define PINID_EMI_A05		STMP3XXX_PINID(2, 14)
+#define PINID_EMI_A06		STMP3XXX_PINID(2, 15)
+#define PINID_EMI_A07		STMP3XXX_PINID(2, 16)
+#define PINID_EMI_A08		STMP3XXX_PINID(2, 17)
+#define PINID_EMI_A09		STMP3XXX_PINID(2, 18)
+#define PINID_EMI_A10		STMP3XXX_PINID(2, 19)
+#define PINID_EMI_A11		STMP3XXX_PINID(2, 20)
+#define PINID_EMI_A12		STMP3XXX_PINID(2, 21)
+#define PINID_EMI_BA0		STMP3XXX_PINID(2, 22)
+#define PINID_EMI_BA1		STMP3XXX_PINID(2, 23)
+#define PINID_EMI_CASN		STMP3XXX_PINID(2, 24)
+#define PINID_EMI_CE0N		STMP3XXX_PINID(2, 25)
+#define PINID_EMI_CE1N		STMP3XXX_PINID(2, 26)
+#define PINID_GPMI_CE1N		STMP3XXX_PINID(2, 27)
+#define PINID_GPMI_CE0N		STMP3XXX_PINID(2, 28)
+#define PINID_EMI_CKE		STMP3XXX_PINID(2, 29)
+#define PINID_EMI_RASN		STMP3XXX_PINID(2, 30)
+#define PINID_EMI_WEN		STMP3XXX_PINID(2, 31)
+
+/* Bank 3 */
+#define PINID_EMI_D00		STMP3XXX_PINID(3, 0)
+#define PINID_EMI_D01		STMP3XXX_PINID(3, 1)
+#define PINID_EMI_D02		STMP3XXX_PINID(3, 2)
+#define PINID_EMI_D03		STMP3XXX_PINID(3, 3)
+#define PINID_EMI_D04		STMP3XXX_PINID(3, 4)
+#define PINID_EMI_D05		STMP3XXX_PINID(3, 5)
+#define PINID_EMI_D06		STMP3XXX_PINID(3, 6)
+#define PINID_EMI_D07		STMP3XXX_PINID(3, 7)
+#define PINID_EMI_D08		STMP3XXX_PINID(3, 8)
+#define PINID_EMI_D09		STMP3XXX_PINID(3, 9)
+#define PINID_EMI_D10		STMP3XXX_PINID(3, 10)
+#define PINID_EMI_D11		STMP3XXX_PINID(3, 11)
+#define PINID_EMI_D12		STMP3XXX_PINID(3, 12)
+#define PINID_EMI_D13		STMP3XXX_PINID(3, 13)
+#define PINID_EMI_D14		STMP3XXX_PINID(3, 14)
+#define PINID_EMI_D15		STMP3XXX_PINID(3, 15)
+#define PINID_EMI_DQM0		STMP3XXX_PINID(3, 16)
+#define PINID_EMI_DQM1		STMP3XXX_PINID(3, 17)
+#define PINID_EMI_DQS0		STMP3XXX_PINID(3, 18)
+#define PINID_EMI_DQS1		STMP3XXX_PINID(3, 19)
+#define PINID_EMI_CLK		STMP3XXX_PINID(3, 20)
+#define PINID_EMI_CLKN		STMP3XXX_PINID(3, 21)
+
+#endif /* __ASM_ARCH_PINS_H */
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-apbh.h b/arch/arm/mach-stmp378x/include/mach/regs-apbh.h
new file mode 100644
index 0000000..dbcf85b
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-apbh.h
@@ -0,0 +1,101 @@
+/*
+ * stmp378x: APBH register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef _MACH_REGS_APBH
+#define _MACH_REGS_APBH
+
+#define REGS_APBH_BASE	(STMP3XXX_REGS_BASE + 0x4000)
+#define REGS_APBH_PHYS	0x80004000
+#define REGS_APBH_SIZE	0x2000
+
+#define HW_APBH_CTRL0		0x0
+#define BM_APBH_CTRL0_RESET_CHANNEL	0x00FF0000
+#define BP_APBH_CTRL0_RESET_CHANNEL	16
+#define BM_APBH_CTRL0_CLKGATE	0x40000000
+#define BM_APBH_CTRL0_SFTRST	0x80000000
+
+#define HW_APBH_CTRL1		0x10
+#define BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ	0x00000001
+#define BP_APBH_CTRL1_CH0_CMDCMPLT_IRQ	0
+
+#define HW_APBH_CTRL2		0x20
+
+#define HW_APBH_DEVSEL		0x30
+
+#define HW_APBH_CH0_NXTCMDAR	(0x50 + 0 * 0x70)
+#define HW_APBH_CH1_NXTCMDAR	(0x50 + 1 * 0x70)
+#define HW_APBH_CH2_NXTCMDAR	(0x50 + 2 * 0x70)
+#define HW_APBH_CH3_NXTCMDAR	(0x50 + 3 * 0x70)
+#define HW_APBH_CH4_NXTCMDAR	(0x50 + 4 * 0x70)
+#define HW_APBH_CH5_NXTCMDAR	(0x50 + 5 * 0x70)
+#define HW_APBH_CH6_NXTCMDAR	(0x50 + 6 * 0x70)
+#define HW_APBH_CH7_NXTCMDAR	(0x50 + 7 * 0x70)
+#define HW_APBH_CH8_NXTCMDAR	(0x50 + 8 * 0x70)
+#define HW_APBH_CH9_NXTCMDAR	(0x50 + 9 * 0x70)
+#define HW_APBH_CH10_NXTCMDAR	(0x50 + 10 * 0x70)
+#define HW_APBH_CH11_NXTCMDAR	(0x50 + 11 * 0x70)
+#define HW_APBH_CH12_NXTCMDAR	(0x50 + 12 * 0x70)
+#define HW_APBH_CH13_NXTCMDAR	(0x50 + 13 * 0x70)
+#define HW_APBH_CH14_NXTCMDAR	(0x50 + 14 * 0x70)
+#define HW_APBH_CH15_NXTCMDAR	(0x50 + 15 * 0x70)
+
+#define HW_APBH_CHn_NXTCMDAR	0x50
+
+#define BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER	 0
+#define BV_APBH_CHn_CMD_COMMAND__DMA_WRITE	 1
+#define BV_APBH_CHn_CMD_COMMAND__DMA_READ	 2
+#define BV_APBH_CHn_CMD_COMMAND__DMA_SENSE	 3
+#define BM_APBH_CHn_CMD_COMMAND	0x00000003
+#define BP_APBH_CHn_CMD_COMMAND	0
+#define BM_APBH_CHn_CMD_CHAIN	0x00000004
+#define BM_APBH_CHn_CMD_IRQONCMPLT	0x00000008
+#define BM_APBH_CHn_CMD_NANDLOCK	0x00000010
+#define BM_APBH_CHn_CMD_NANDWAIT4READY	0x00000020
+#define BM_APBH_CHn_CMD_SEMAPHORE	0x00000040
+#define BM_APBH_CHn_CMD_WAIT4ENDCMD	0x00000080
+#define BM_APBH_CHn_CMD_CMDWORDS	0x0000F000
+#define BP_APBH_CHn_CMD_CMDWORDS	12
+#define BM_APBH_CHn_CMD_XFER_COUNT	0xFFFF0000
+#define BP_APBH_CHn_CMD_XFER_COUNT	16
+
+#define HW_APBH_CH0_SEMA	(0x80 + 0 * 0x70)
+#define HW_APBH_CH1_SEMA	(0x80 + 1 * 0x70)
+#define HW_APBH_CH2_SEMA	(0x80 + 2 * 0x70)
+#define HW_APBH_CH3_SEMA	(0x80 + 3 * 0x70)
+#define HW_APBH_CH4_SEMA	(0x80 + 4 * 0x70)
+#define HW_APBH_CH5_SEMA	(0x80 + 5 * 0x70)
+#define HW_APBH_CH6_SEMA	(0x80 + 6 * 0x70)
+#define HW_APBH_CH7_SEMA	(0x80 + 7 * 0x70)
+#define HW_APBH_CH8_SEMA	(0x80 + 8 * 0x70)
+#define HW_APBH_CH9_SEMA	(0x80 + 9 * 0x70)
+#define HW_APBH_CH10_SEMA	(0x80 + 10 * 0x70)
+#define HW_APBH_CH11_SEMA	(0x80 + 11 * 0x70)
+#define HW_APBH_CH12_SEMA	(0x80 + 12 * 0x70)
+#define HW_APBH_CH13_SEMA	(0x80 + 13 * 0x70)
+#define HW_APBH_CH14_SEMA	(0x80 + 14 * 0x70)
+#define HW_APBH_CH15_SEMA	(0x80 + 15 * 0x70)
+
+#define HW_APBH_CHn_SEMA	0x80
+#define BM_APBH_CHn_SEMA_INCREMENT_SEMA	0x000000FF
+#define BP_APBH_CHn_SEMA_INCREMENT_SEMA	0
+#define BM_APBH_CHn_SEMA_PHORE	0x00FF0000
+#define BP_APBH_CHn_SEMA_PHORE	16
+
+#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-apbx.h b/arch/arm/mach-stmp378x/include/mach/regs-apbx.h
new file mode 100644
index 0000000..3b934a4
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-apbx.h
@@ -0,0 +1,119 @@
+/*
+ * stmp378x: APBX register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef _MACH_REGS_APBX
+#define _MACH_REGS_APBX
+
+#define REGS_APBX_BASE	(STMP3XXX_REGS_BASE + 0x24000)
+#define REGS_APBX_PHYS	0x80024000
+#define REGS_APBX_SIZE	0x2000
+
+#define HW_APBX_CTRL0		0x0
+#define BM_APBX_CTRL0_CLKGATE	0x40000000
+#define BM_APBX_CTRL0_SFTRST	0x80000000
+
+#define HW_APBX_CTRL1		0x10
+
+#define HW_APBX_CTRL2		0x20
+
+#define HW_APBX_CHANNEL_CTRL	0x30
+#define BM_APBX_CHANNEL_CTRL_RESET_CHANNEL	0xFFFF0000
+#define BP_APBX_CHANNEL_CTRL_RESET_CHANNEL	16
+
+#define HW_APBX_DEVSEL		0x40
+
+#define HW_APBX_CH0_NXTCMDAR	(0x110 + 0 * 0x70)
+#define HW_APBX_CH1_NXTCMDAR	(0x110 + 1 * 0x70)
+#define HW_APBX_CH2_NXTCMDAR	(0x110 + 2 * 0x70)
+#define HW_APBX_CH3_NXTCMDAR	(0x110 + 3 * 0x70)
+#define HW_APBX_CH4_NXTCMDAR	(0x110 + 4 * 0x70)
+#define HW_APBX_CH5_NXTCMDAR	(0x110 + 5 * 0x70)
+#define HW_APBX_CH6_NXTCMDAR	(0x110 + 6 * 0x70)
+#define HW_APBX_CH7_NXTCMDAR	(0x110 + 7 * 0x70)
+#define HW_APBX_CH8_NXTCMDAR	(0x110 + 8 * 0x70)
+#define HW_APBX_CH9_NXTCMDAR	(0x110 + 9 * 0x70)
+#define HW_APBX_CH10_NXTCMDAR	(0x110 + 10 * 0x70)
+#define HW_APBX_CH11_NXTCMDAR	(0x110 + 11 * 0x70)
+#define HW_APBX_CH12_NXTCMDAR	(0x110 + 12 * 0x70)
+#define HW_APBX_CH13_NXTCMDAR	(0x110 + 13 * 0x70)
+#define HW_APBX_CH14_NXTCMDAR	(0x110 + 14 * 0x70)
+#define HW_APBX_CH15_NXTCMDAR	(0x110 + 15 * 0x70)
+
+#define HW_APBX_CHn_NXTCMDAR	0x110
+#define BM_APBX_CHn_CMD_COMMAND	0x00000003
+#define BP_APBX_CHn_CMD_COMMAND	0
+#define BV_APBX_CHn_CMD_COMMAND__NO_DMA_XFER	 0
+#define BV_APBX_CHn_CMD_COMMAND__DMA_WRITE	 1
+#define BV_APBX_CHn_CMD_COMMAND__DMA_READ	 2
+#define BV_APBX_CHn_CMD_COMMAND__DMA_SENSE	 3
+#define BM_APBX_CHn_CMD_CHAIN	0x00000004
+#define BM_APBX_CHn_CMD_IRQONCMPLT	0x00000008
+#define BM_APBX_CHn_CMD_SEMAPHORE	0x00000040
+#define BM_APBX_CHn_CMD_WAIT4ENDCMD	0x00000080
+#define BM_APBX_CHn_CMD_HALTONTERMINATE	0x00000100
+#define BM_APBX_CHn_CMD_CMDWORDS	0x0000F000
+#define BP_APBX_CHn_CMD_CMDWORDS	12
+#define BM_APBX_CHn_CMD_XFER_COUNT	0xFFFF0000
+#define BP_APBX_CHn_CMD_XFER_COUNT	16
+
+#define HW_APBX_CH0_BAR		(0x130 + 0 * 0x70)
+#define HW_APBX_CH1_BAR		(0x130 + 1 * 0x70)
+#define HW_APBX_CH2_BAR		(0x130 + 2 * 0x70)
+#define HW_APBX_CH3_BAR		(0x130 + 3 * 0x70)
+#define HW_APBX_CH4_BAR		(0x130 + 4 * 0x70)
+#define HW_APBX_CH5_BAR		(0x130 + 5 * 0x70)
+#define HW_APBX_CH6_BAR		(0x130 + 6 * 0x70)
+#define HW_APBX_CH7_BAR		(0x130 + 7 * 0x70)
+#define HW_APBX_CH8_BAR		(0x130 + 8 * 0x70)
+#define HW_APBX_CH9_BAR		(0x130 + 9 * 0x70)
+#define HW_APBX_CH10_BAR		(0x130 + 10 * 0x70)
+#define HW_APBX_CH11_BAR		(0x130 + 11 * 0x70)
+#define HW_APBX_CH12_BAR		(0x130 + 12 * 0x70)
+#define HW_APBX_CH13_BAR		(0x130 + 13 * 0x70)
+#define HW_APBX_CH14_BAR		(0x130 + 14 * 0x70)
+#define HW_APBX_CH15_BAR		(0x130 + 15 * 0x70)
+
+#define HW_APBX_CHn_BAR		0x130
+
+#define HW_APBX_CH0_SEMA	(0x140 + 0 * 0x70)
+#define HW_APBX_CH1_SEMA	(0x140 + 1 * 0x70)
+#define HW_APBX_CH2_SEMA	(0x140 + 2 * 0x70)
+#define HW_APBX_CH3_SEMA	(0x140 + 3 * 0x70)
+#define HW_APBX_CH4_SEMA	(0x140 + 4 * 0x70)
+#define HW_APBX_CH5_SEMA	(0x140 + 5 * 0x70)
+#define HW_APBX_CH6_SEMA	(0x140 + 6 * 0x70)
+#define HW_APBX_CH7_SEMA	(0x140 + 7 * 0x70)
+#define HW_APBX_CH8_SEMA	(0x140 + 8 * 0x70)
+#define HW_APBX_CH9_SEMA	(0x140 + 9 * 0x70)
+#define HW_APBX_CH10_SEMA	(0x140 + 10 * 0x70)
+#define HW_APBX_CH11_SEMA	(0x140 + 11 * 0x70)
+#define HW_APBX_CH12_SEMA	(0x140 + 12 * 0x70)
+#define HW_APBX_CH13_SEMA	(0x140 + 13 * 0x70)
+#define HW_APBX_CH14_SEMA	(0x140 + 14 * 0x70)
+#define HW_APBX_CH15_SEMA	(0x140 + 15 * 0x70)
+
+#define HW_APBX_CHn_SEMA	0x140
+#define BM_APBX_CHn_SEMA_INCREMENT_SEMA	0x000000FF
+#define BP_APBX_CHn_SEMA_INCREMENT_SEMA	0
+#define BM_APBX_CHn_SEMA_PHORE	0x00FF0000
+#define BP_APBX_CHn_SEMA_PHORE	16
+
+#endif
+
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-audioin.h b/arch/arm/mach-stmp378x/include/mach/regs-audioin.h
new file mode 100644
index 0000000..641ac61
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-audioin.h
@@ -0,0 +1,63 @@
+/*
+ * stmp378x: AUDIOIN register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_AUDIOIN_BASE	(STMP3XXX_REGS_BASE + 0x4C000)
+#define REGS_AUDIOIN_PHYS	0x8004C000
+#define REGS_AUDIOIN_SIZE	0x2000
+
+#define HW_AUDIOIN_CTRL		0x0
+#define BM_AUDIOIN_CTRL_RUN	0x00000001
+#define BP_AUDIOIN_CTRL_RUN	0
+#define BM_AUDIOIN_CTRL_FIFO_ERROR_IRQ_EN	0x00000002
+#define BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ	0x00000004
+#define BM_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ	0x00000008
+#define BM_AUDIOIN_CTRL_WORD_LENGTH	0x00000020
+#define BM_AUDIOIN_CTRL_CLKGATE	0x40000000
+#define BM_AUDIOIN_CTRL_SFTRST	0x80000000
+
+#define HW_AUDIOIN_STAT		0x10
+
+#define HW_AUDIOIN_ADCSRR	0x20
+
+#define HW_AUDIOIN_ADCVOLUME	0x30
+#define BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT	0x000000FF
+#define BP_AUDIOIN_ADCVOLUME_VOLUME_RIGHT	0
+#define BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT	0x00FF0000
+#define BP_AUDIOIN_ADCVOLUME_VOLUME_LEFT	16
+
+#define HW_AUDIOIN_ADCDEBUG	0x40
+
+#define HW_AUDIOIN_ADCVOL	0x50
+#define BM_AUDIOIN_ADCVOL_GAIN_RIGHT	0x0000000F
+#define BP_AUDIOIN_ADCVOL_GAIN_RIGHT	0
+#define BM_AUDIOIN_ADCVOL_SELECT_RIGHT	0x00000030
+#define BP_AUDIOIN_ADCVOL_SELECT_RIGHT	4
+#define BM_AUDIOIN_ADCVOL_GAIN_LEFT	0x00000F00
+#define BP_AUDIOIN_ADCVOL_GAIN_LEFT	8
+#define BM_AUDIOIN_ADCVOL_SELECT_LEFT	0x00003000
+#define BP_AUDIOIN_ADCVOL_SELECT_LEFT	12
+#define BM_AUDIOIN_ADCVOL_MUTE	0x01000000
+
+#define HW_AUDIOIN_MICLINE	0x60
+
+#define HW_AUDIOIN_ANACLKCTRL	0x70
+#define BM_AUDIOIN_ANACLKCTRL_CLKGATE	0x80000000
+
+#define HW_AUDIOIN_DATA		0x80
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-audioout.h b/arch/arm/mach-stmp378x/include/mach/regs-audioout.h
new file mode 100644
index 0000000..f533e23
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-audioout.h
@@ -0,0 +1,104 @@
+/*
+ * stmp378x: AUDIOOUT register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_AUDIOOUT_BASE	(STMP3XXX_REGS_BASE + 0x48000)
+#define REGS_AUDIOOUT_PHYS	0x80048000
+#define REGS_AUDIOOUT_SIZE	0x2000
+
+#define HW_AUDIOOUT_CTRL	0x0
+#define BM_AUDIOOUT_CTRL_RUN	0x00000001
+#define BP_AUDIOOUT_CTRL_RUN	0
+#define BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN	0x00000002
+#define BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ	0x00000004
+#define BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ	0x00000008
+#define BM_AUDIOOUT_CTRL_WORD_LENGTH	0x00000040
+#define BM_AUDIOOUT_CTRL_CLKGATE	0x40000000
+#define BM_AUDIOOUT_CTRL_SFTRST	0x80000000
+
+#define HW_AUDIOOUT_STAT	0x10
+
+#define HW_AUDIOOUT_DACSRR	0x20
+#define BM_AUDIOOUT_DACSRR_SRC_FRAC	0x00001FFF
+#define BP_AUDIOOUT_DACSRR_SRC_FRAC	0
+#define BM_AUDIOOUT_DACSRR_SRC_INT	0x001F0000
+#define BP_AUDIOOUT_DACSRR_SRC_INT	16
+#define BM_AUDIOOUT_DACSRR_SRC_HOLD	0x07000000
+#define BP_AUDIOOUT_DACSRR_SRC_HOLD	24
+#define BM_AUDIOOUT_DACSRR_BASEMULT	0x70000000
+#define BP_AUDIOOUT_DACSRR_BASEMULT	28
+
+#define HW_AUDIOOUT_DACVOLUME	0x30
+#define BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT	0x00000100
+#define BM_AUDIOOUT_DACVOLUME_MUTE_LEFT	0x01000000
+#define BM_AUDIOOUT_DACVOLUME_EN_ZCD	0x02000000
+
+#define HW_AUDIOOUT_DACDEBUG	0x40
+
+#define HW_AUDIOOUT_HPVOL	0x50
+#define BM_AUDIOOUT_HPVOL_MUTE	0x01000000
+#define BM_AUDIOOUT_HPVOL_EN_MSTR_ZCD	0x02000000
+
+#define HW_AUDIOOUT_PWRDN	0x70
+#define BM_AUDIOOUT_PWRDN_HEADPHONE	0x00000001
+#define BP_AUDIOOUT_PWRDN_HEADPHONE	0
+#define BM_AUDIOOUT_PWRDN_CAPLESS	0x00000010
+#define BM_AUDIOOUT_PWRDN_ADC	0x00000100
+#define BM_AUDIOOUT_PWRDN_DAC	0x00001000
+#define BM_AUDIOOUT_PWRDN_RIGHT_ADC	0x00010000
+#define BM_AUDIOOUT_PWRDN_SPEAKER	0x01000000
+
+#define HW_AUDIOOUT_REFCTRL	0x80
+#define BM_AUDIOOUT_REFCTRL_VAG_VAL	0x000000F0
+#define BP_AUDIOOUT_REFCTRL_VAG_VAL	4
+#define BM_AUDIOOUT_REFCTRL_ADC_REFVAL	0x00000F00
+#define BP_AUDIOOUT_REFCTRL_ADC_REFVAL	8
+#define BM_AUDIOOUT_REFCTRL_ADJ_VAG	0x00001000
+#define BM_AUDIOOUT_REFCTRL_ADJ_ADC	0x00002000
+#define BM_AUDIOOUT_REFCTRL_BIAS_CTRL	0x00030000
+#define BP_AUDIOOUT_REFCTRL_BIAS_CTRL	16
+#define BM_AUDIOOUT_REFCTRL_LOW_PWR	0x00080000
+#define BM_AUDIOOUT_REFCTRL_VBG_ADJ	0x00700000
+#define BP_AUDIOOUT_REFCTRL_VBG_ADJ	20
+#define BM_AUDIOOUT_REFCTRL_XTAL_BGR_BIAS	0x01000000
+#define BM_AUDIOOUT_REFCTRL_RAISE_REF	0x02000000
+
+#define HW_AUDIOOUT_ANACTRL	0x90
+#define BM_AUDIOOUT_ANACTRL_HP_CLASSAB	0x00000010
+#define BM_AUDIOOUT_ANACTRL_HP_HOLD_GND	0x00000020
+
+#define HW_AUDIOOUT_TEST	0xA0
+#define BM_AUDIOOUT_TEST_HP_I1_ADJ	0x00C00000
+#define BP_AUDIOOUT_TEST_HP_I1_ADJ	22
+
+#define HW_AUDIOOUT_BISTCTRL	0xB0
+
+#define HW_AUDIOOUT_BISTSTAT0	0xC0
+
+#define HW_AUDIOOUT_BISTSTAT1	0xD0
+
+#define HW_AUDIOOUT_ANACLKCTRL	0xE0
+#define BM_AUDIOOUT_ANACLKCTRL_CLKGATE	0x80000000
+
+#define HW_AUDIOOUT_DATA	0xF0
+
+#define HW_AUDIOOUT_SPEAKERCTRL	0x100
+#define BM_AUDIOOUT_SPEAKERCTRL_MUTE	0x01000000
+
+#define HW_AUDIOOUT_VERSION	0x200
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-bch.h b/arch/arm/mach-stmp378x/include/mach/regs-bch.h
new file mode 100644
index 0000000..532d246
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-bch.h
@@ -0,0 +1,56 @@
+/*
+ * stmp378x: BCH register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_BCH_BASE	(STMP3XXX_REGS_BASE + 0xA000)
+#define REGS_BCH_PHYS	0x8000A000
+#define REGS_BCH_SIZE	0x2000
+
+#define HW_BCH_CTRL		0x0
+#define BM_BCH_CTRL_COMPLETE_IRQ	0x00000001
+#define BP_BCH_CTRL_COMPLETE_IRQ	0
+#define BM_BCH_CTRL_COMPLETE_IRQ_EN	0x00000100
+
+#define HW_BCH_STATUS0		0x10
+#define BM_BCH_STATUS0_UNCORRECTABLE	0x00000004
+#define BM_BCH_STATUS0_CORRECTED	0x00000008
+#define BM_BCH_STATUS0_STATUS_BLK0	0x0000FF00
+#define BP_BCH_STATUS0_STATUS_BLK0	8
+#define BM_BCH_STATUS0_COMPLETED_CE	0x000F0000
+#define BP_BCH_STATUS0_COMPLETED_CE	16
+
+#define HW_BCH_LAYOUTSELECT	0x70
+
+#define HW_BCH_FLASH0LAYOUT0	0x80
+#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE	0x00000FFF
+#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE	0
+#define BM_BCH_FLASH0LAYOUT0_ECC0	0x0000F000
+#define BP_BCH_FLASH0LAYOUT0_ECC0	12
+#define BM_BCH_FLASH0LAYOUT0_META_SIZE	0x00FF0000
+#define BP_BCH_FLASH0LAYOUT0_META_SIZE	16
+#define BM_BCH_FLASH0LAYOUT0_NBLOCKS	0xFF000000
+#define BP_BCH_FLASH0LAYOUT0_NBLOCKS	24
+#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE	0x00000FFF
+#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE	0
+#define BM_BCH_FLASH0LAYOUT1_ECCN	0x0000F000
+#define BP_BCH_FLASH0LAYOUT1_ECCN	12
+#define BM_BCH_FLASH0LAYOUT1_PAGE_SIZE	0xFFFF0000
+#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE	16
+
+#define HW_BCH_BLOCKNAME	0x150
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-clkctrl.h b/arch/arm/mach-stmp378x/include/mach/regs-clkctrl.h
new file mode 100644
index 0000000..7c546af
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-clkctrl.h
@@ -0,0 +1,88 @@
+/*
+ * stmp378x: CLKCTRL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef _MACH_REGS_CLKCTRL
+#define _MACH_REGS_CLKCTRL
+
+#define REGS_CLKCTRL_BASE	(STMP3XXX_REGS_BASE + 0x40000)
+#define REGS_CLKCTRL_PHYS	0x80040000
+#define REGS_CLKCTRL_SIZE	0x2000
+
+#define HW_CLKCTRL_PLLCTRL0	0x0
+#define BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS	0x00040000
+
+#define HW_CLKCTRL_CPU		0x20
+#define BM_CLKCTRL_CPU_DIV_CPU	0x0000003F
+#define BP_CLKCTRL_CPU_DIV_CPU	0
+
+#define HW_CLKCTRL_HBUS		0x30
+#define BM_CLKCTRL_HBUS_DIV	0x0000001F
+#define BP_CLKCTRL_HBUS_DIV	0
+#define BM_CLKCTRL_HBUS_DIV_FRAC_EN	0x00000020
+
+#define HW_CLKCTRL_XBUS		0x40
+
+#define HW_CLKCTRL_XTAL		0x50
+#define BM_CLKCTRL_XTAL_DRI_CLK24M_GATE	0x10000000
+
+#define HW_CLKCTRL_PIX		0x60
+#define BM_CLKCTRL_PIX_DIV	0x00000FFF
+#define BP_CLKCTRL_PIX_DIV	0
+#define BM_CLKCTRL_PIX_CLKGATE	0x80000000
+
+#define HW_CLKCTRL_SSP		0x70
+
+#define HW_CLKCTRL_GPMI		0x80
+
+#define HW_CLKCTRL_SPDIF	0x90
+
+#define HW_CLKCTRL_EMI		0xA0
+#define BM_CLKCTRL_EMI_DIV_EMI	0x0000003F
+#define BP_CLKCTRL_EMI_DIV_EMI	0
+#define BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE	0x00010000
+#define BM_CLKCTRL_EMI_BUSY_DCC_RESYNC	0x00020000
+#define BM_CLKCTRL_EMI_BUSY_REF_EMI	0x10000000
+#define BM_CLKCTRL_EMI_BUSY_REF_XTAL	0x20000000
+
+#define HW_CLKCTRL_IR		0xB0
+
+#define HW_CLKCTRL_SAIF		0xC0
+
+#define HW_CLKCTRL_TV		0xD0
+
+#define HW_CLKCTRL_ETM		0xE0
+
+#define HW_CLKCTRL_FRAC		0xF0
+#define BM_CLKCTRL_FRAC_EMIFRAC	0x00003F00
+#define BP_CLKCTRL_FRAC_EMIFRAC	8
+#define BM_CLKCTRL_FRAC_PIXFRAC	0x003F0000
+#define BP_CLKCTRL_FRAC_PIXFRAC	16
+#define BM_CLKCTRL_FRAC_CLKGATEPIX	0x00800000
+
+#define HW_CLKCTRL_FRAC1	0x100
+
+#define HW_CLKCTRL_CLKSEQ	0x110
+#define BM_CLKCTRL_CLKSEQ_BYPASS_PIX	0x00000002
+
+#define HW_CLKCTRL_RESET	0x120
+#define BM_CLKCTRL_RESET_DIG	0x00000001
+#define BP_CLKCTRL_RESET_DIG	0
+
+#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-dcp.h b/arch/arm/mach-stmp378x/include/mach/regs-dcp.h
new file mode 100644
index 0000000..fdedd00
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-dcp.h
@@ -0,0 +1,87 @@
+/*
+ * stmp378x: DCP register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_DCP_BASE	(STMP3XXX_REGS_BASE + 0x28000)
+#define REGS_DCP_PHYS	0x80028000
+#define REGS_DCP_SIZE	0x2000
+
+#define HW_DCP_CTRL		0x0
+#define BM_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE	0x000000FF
+#define BP_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE	0
+#define BM_DCP_CTRL_ENABLE_CONTEXT_CACHING	0x00400000
+#define BM_DCP_CTRL_GATHER_RESIDUAL_WRITES	0x00800000
+#define BM_DCP_CTRL_CLKGATE	0x40000000
+#define BM_DCP_CTRL_SFTRST	0x80000000
+
+#define HW_DCP_STAT		0x10
+#define BM_DCP_STAT_IRQ		0x0000000F
+#define BP_DCP_STAT_IRQ		0
+
+#define HW_DCP_CHANNELCTRL	0x20
+#define BM_DCP_CHANNELCTRL_ENABLE_CHANNEL	0x000000FF
+#define BP_DCP_CHANNELCTRL_ENABLE_CHANNEL	0
+
+#define HW_DCP_CONTEXT		0x50
+#define BM_DCP_PACKET1_INTERRUPT	0x00000001
+#define BP_DCP_PACKET1_INTERRUPT	0
+#define BM_DCP_PACKET1_DECR_SEMAPHORE	0x00000002
+#define BM_DCP_PACKET1_CHAIN	0x00000004
+#define BM_DCP_PACKET1_CHAIN_CONTIGUOUS	0x00000008
+#define BM_DCP_PACKET1_ENABLE_CIPHER	0x00000020
+#define BM_DCP_PACKET1_ENABLE_HASH	0x00000040
+#define BM_DCP_PACKET1_CIPHER_ENCRYPT	0x00000100
+#define BM_DCP_PACKET1_CIPHER_INIT	0x00000200
+#define BM_DCP_PACKET1_OTP_KEY	0x00000400
+#define BM_DCP_PACKET1_PAYLOAD_KEY	0x00000800
+#define BM_DCP_PACKET1_HASH_INIT	0x00001000
+#define BM_DCP_PACKET1_HASH_TERM	0x00002000
+#define BM_DCP_PACKET2_CIPHER_SELECT	0x0000000F
+#define BP_DCP_PACKET2_CIPHER_SELECT	0
+#define BM_DCP_PACKET2_CIPHER_MODE	0x000000F0
+#define BP_DCP_PACKET2_CIPHER_MODE	4
+#define BM_DCP_PACKET2_KEY_SELECT	0x0000FF00
+#define BP_DCP_PACKET2_KEY_SELECT	8
+#define BM_DCP_PACKET2_HASH_SELECT	0x000F0000
+#define BP_DCP_PACKET2_HASH_SELECT	16
+#define BM_DCP_PACKET2_CIPHER_CFG	0xFF000000
+#define BP_DCP_PACKET2_CIPHER_CFG	24
+
+#define HW_DCP_CH0CMDPTR	(0x100 + 0 * 0x40)
+#define HW_DCP_CH1CMDPTR	(0x100 + 1 * 0x40)
+#define HW_DCP_CH2CMDPTR	(0x100 + 2 * 0x40)
+#define HW_DCP_CH3CMDPTR	(0x100 + 3 * 0x40)
+
+#define HW_DCP_CHnCMDPTR	0x100
+
+#define HW_DCP_CH0SEMA		(0x110 + 0 * 0x40)
+#define HW_DCP_CH1SEMA		(0x110 + 1 * 0x40)
+#define HW_DCP_CH2SEMA		(0x110 + 2 * 0x40)
+#define HW_DCP_CH3SEMA		(0x110 + 3 * 0x40)
+
+#define HW_DCP_CHnSEMA		0x110
+#define BM_DCP_CHnSEMA_INCREMENT	0x000000FF
+#define BP_DCP_CHnSEMA_INCREMENT	0
+
+#define HW_DCP_CH0STAT		(0x120 + 0 * 0x40)
+#define HW_DCP_CH1STAT		(0x120 + 1 * 0x40)
+#define HW_DCP_CH2STAT		(0x120 + 2 * 0x40)
+#define HW_DCP_CH3STAT		(0x120 + 3 * 0x40)
+
+#define HW_DCP_CHnSTAT		0x120
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-digctl.h b/arch/arm/mach-stmp378x/include/mach/regs-digctl.h
new file mode 100644
index 0000000..5293005
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-digctl.h
@@ -0,0 +1,38 @@
+/*
+ * stmp378x: DIGCTL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_DIGCTL_BASE	(STMP3XXX_REGS_BASE + 0x1C000)
+#define REGS_DIGCTL_PHYS	0x8001C000
+#define REGS_DIGCTL_SIZE	0x2000
+
+#define HW_DIGCTL_CTRL		0x0
+#define BM_DIGCTL_CTRL_USB_CLKGATE	0x00000004
+
+#define HW_DIGCTL_ARMCACHE	0x2B0
+#define BM_DIGCTL_ARMCACHE_ITAG_SS	0x00000003
+#define BP_DIGCTL_ARMCACHE_ITAG_SS	0
+#define BM_DIGCTL_ARMCACHE_DTAG_SS	0x00000030
+#define BP_DIGCTL_ARMCACHE_DTAG_SS	4
+#define BM_DIGCTL_ARMCACHE_CACHE_SS	0x00000300
+#define BP_DIGCTL_ARMCACHE_CACHE_SS	8
+#define BM_DIGCTL_ARMCACHE_DRTY_SS	0x00003000
+#define BP_DIGCTL_ARMCACHE_DRTY_SS	12
+#define BM_DIGCTL_ARMCACHE_VALID_SS	0x00030000
+#define BP_DIGCTL_ARMCACHE_VALID_SS	16
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-dram.h b/arch/arm/mach-stmp378x/include/mach/regs-dram.h
new file mode 100644
index 0000000..0285143
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-dram.h
@@ -0,0 +1,27 @@
+/*
+ * stmp378x: DRAM register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_DRAM_BASE	(STMP3XXX_REGS_BASE + 0xE0000)
+#define REGS_DRAM_PHYS	0x800E0000
+#define REGS_DRAM_SIZE	0x2000
+
+#define HW_DRAM_CTL06		0x18
+
+#define HW_DRAM_CTL08		0x20
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-dri.h b/arch/arm/mach-stmp378x/include/mach/regs-dri.h
new file mode 100644
index 0000000..da25f7e
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-dri.h
@@ -0,0 +1,45 @@
+/*
+ * stmp378x: DRI register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_DRI_BASE	(STMP3XXX_REGS_BASE + 0x74000)
+#define REGS_DRI_PHYS	0x80074000
+#define REGS_DRI_SIZE	0x2000
+
+#define HW_DRI_CTRL		0x0
+#define BM_DRI_CTRL_RUN		0x00000001
+#define BP_DRI_CTRL_RUN		0
+#define BM_DRI_CTRL_ATTENTION_IRQ	0x00000002
+#define BM_DRI_CTRL_PILOT_SYNC_LOSS_IRQ	0x00000004
+#define BM_DRI_CTRL_OVERFLOW_IRQ	0x00000008
+#define BM_DRI_CTRL_ATTENTION_IRQ_EN	0x00000200
+#define BM_DRI_CTRL_PILOT_SYNC_LOSS_IRQ_EN	0x00000400
+#define BM_DRI_CTRL_OVERFLOW_IRQ_EN	0x00000800
+#define BM_DRI_CTRL_REACQUIRE_PHASE	0x00008000
+#define BM_DRI_CTRL_STOP_ON_PILOT_ERROR	0x02000000
+#define BM_DRI_CTRL_STOP_ON_OFLOW_ERROR	0x04000000
+#define BM_DRI_CTRL_ENABLE_INPUTS	0x20000000
+#define BM_DRI_CTRL_CLKGATE	0x40000000
+#define BM_DRI_CTRL_SFTRST	0x80000000
+
+#define HW_DRI_TIMING		0x10
+#define BM_DRI_TIMING_GAP_DETECTION_INTERVAL	0x000000FF
+#define BP_DRI_TIMING_GAP_DETECTION_INTERVAL	0
+#define BM_DRI_TIMING_PILOT_REP_RATE	0x000F0000
+#define BP_DRI_TIMING_PILOT_REP_RATE	16
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-ecc8.h b/arch/arm/mach-stmp378x/include/mach/regs-ecc8.h
new file mode 100644
index 0000000..cc353be
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-ecc8.h
@@ -0,0 +1,39 @@
+/*
+ * stmp378x: ECC8 register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_ECC8_BASE	(STMP3XXX_REGS_BASE + 0x8000)
+#define REGS_ECC8_PHYS	0x80008000
+#define REGS_ECC8_SIZE	0x2000
+
+#define HW_ECC8_CTRL		0x0
+#define BM_ECC8_CTRL_COMPLETE_IRQ	0x00000001
+#define BP_ECC8_CTRL_COMPLETE_IRQ	0
+#define BM_ECC8_CTRL_COMPLETE_IRQ_EN	0x00000100
+#define BM_ECC8_CTRL_AHBM_SFTRST	0x20000000
+
+#define HW_ECC8_STATUS0		0x10
+#define BM_ECC8_STATUS0_UNCORRECTABLE	0x00000004
+#define BM_ECC8_STATUS0_CORRECTED	0x00000008
+#define BM_ECC8_STATUS0_STATUS_AUX	0x00000F00
+#define BP_ECC8_STATUS0_STATUS_AUX	8
+#define BM_ECC8_STATUS0_COMPLETED_CE	0x000F0000
+#define BP_ECC8_STATUS0_COMPLETED_CE	16
+
+#define HW_ECC8_STATUS1		0x20
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-emi.h b/arch/arm/mach-stmp378x/include/mach/regs-emi.h
new file mode 100644
index 0000000..98773fc
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-emi.h
@@ -0,0 +1,25 @@
+/*
+ * stmp378x: EMI register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_EMI_BASE	(STMP3XXX_REGS_BASE + 0x20000)
+#define REGS_EMI_PHYS	0x80020000
+#define REGS_EMI_SIZE	0x2000
+
+#define HW_EMI_STAT		0x10
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-gpmi.h b/arch/arm/mach-stmp378x/include/mach/regs-gpmi.h
new file mode 100644
index 0000000..2cc8bbe
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-gpmi.h
@@ -0,0 +1,78 @@
+/*
+ * stmp378x: GPMI register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_GPMI_BASE	(STMP3XXX_REGS_BASE + 0xC000)
+#define REGS_GPMI_PHYS	0x8000C000
+#define REGS_GPMI_SIZE	0x2000
+
+#define HW_GPMI_CTRL0		0x0
+#define BM_GPMI_CTRL0_XFER_COUNT	0x0000FFFF
+#define BP_GPMI_CTRL0_XFER_COUNT	0
+#define BM_GPMI_CTRL0_CS	0x00300000
+#define BP_GPMI_CTRL0_CS	20
+#define BM_GPMI_CTRL0_LOCK_CS	0x00400000
+#define BM_GPMI_CTRL0_WORD_LENGTH	0x00800000
+#define BM_GPMI_CTRL0_ADDRESS      0x000E0000
+#define BP_GPMI_CTRL0_ADDRESS      17
+#define BV_GPMI_CTRL0_ADDRESS__NAND_DATA  0x0
+#define BV_GPMI_CTRL0_ADDRESS__NAND_CLE   0x1
+#define BV_GPMI_CTRL0_ADDRESS__NAND_ALE   0x2
+#define BM_GPMI_CTRL0_ADDRESS_INCREMENT      0x00010000
+#define BM_GPMI_CTRL0_COMMAND_MODE	0x03000000
+#define BP_GPMI_CTRL0_COMMAND_MODE	24
+#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE	    0x0
+#define BV_GPMI_CTRL0_COMMAND_MODE__READ	     0x1
+#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE 0x2
+#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY   0x3
+#define BM_GPMI_CTRL0_RUN	0x20000000
+#define BM_GPMI_CTRL0_CLKGATE	0x40000000
+#define BM_GPMI_CTRL0_SFTRST	0x80000000
+#define BM_GPMI_ECCCTRL_BUFFER_MASK	0x000001FF
+#define BP_GPMI_ECCCTRL_BUFFER_MASK	0
+#define BM_GPMI_ECCCTRL_ENABLE_ECC	0x00001000
+#define BM_GPMI_ECCCTRL_ECC_CMD	0x00006000
+#define BP_GPMI_ECCCTRL_ECC_CMD	13
+#define BV_GPMI_ECCCTRL_ECC_CMD__DECODE_4_BIT			0
+#define BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_4_BIT			1
+#define BV_GPMI_ECCCTRL_ECC_CMD__DECODE_8_BIT			2
+#define BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_8_BIT			3
+
+#define HW_GPMI_CTRL1		0x60
+#define BM_GPMI_CTRL1_GPMI_MODE	0x00000001
+#define BP_GPMI_CTRL1_GPMI_MODE	0
+#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY	0x00000004
+#define BM_GPMI_CTRL1_DEV_RESET	0x00000008
+#define BM_GPMI_CTRL1_TIMEOUT_IRQ	0x00000200
+#define BM_GPMI_CTRL1_DEV_IRQ	0x00000400
+#define BM_GPMI_CTRL1_RDN_DELAY	0x0000F000
+#define BP_GPMI_CTRL1_RDN_DELAY	12
+#define BM_GPMI_CTRL1_BCH_MODE	0x00040000
+
+#define HW_GPMI_TIMING0		0x70
+#define BM_GPMI_TIMING0_DATA_SETUP	0x000000FF
+#define BP_GPMI_TIMING0_DATA_SETUP	0
+#define BM_GPMI_TIMING0_DATA_HOLD	0x0000FF00
+#define BP_GPMI_TIMING0_DATA_HOLD	8
+#define BM_GPMI_TIMING0_ADDRESS_SETUP	0x00FF0000
+#define BP_GPMI_TIMING0_ADDRESS_SETUP	16
+
+#define HW_GPMI_TIMING1		0x80
+#define BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT	0xFFFF0000
+#define BP_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT	16
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-i2c.h b/arch/arm/mach-stmp378x/include/mach/regs-i2c.h
new file mode 100644
index 0000000..13a234c
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-i2c.h
@@ -0,0 +1,55 @@
+/*
+ * stmp378x: I2C register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_I2C_BASE	(STMP3XXX_REGS_BASE + 0x58000)
+#define REGS_I2C_PHYS	0x80058000
+#define REGS_I2C_SIZE	0x2000
+
+#define HW_I2C_CTRL0		0x0
+#define BM_I2C_CTRL0_XFER_COUNT	0x0000FFFF
+#define BP_I2C_CTRL0_XFER_COUNT	0
+#define BM_I2C_CTRL0_DIRECTION	0x00010000
+#define BM_I2C_CTRL0_MASTER_MODE	0x00020000
+#define BM_I2C_CTRL0_PRE_SEND_START	0x00080000
+#define BM_I2C_CTRL0_POST_SEND_STOP	0x00100000
+#define BM_I2C_CTRL0_RETAIN_CLOCK	0x00200000
+#define BM_I2C_CTRL0_SEND_NAK_ON_LAST	0x02000000
+#define BM_I2C_CTRL0_CLKGATE	0x40000000
+#define BM_I2C_CTRL0_SFTRST	0x80000000
+
+#define HW_I2C_TIMING0		0x10
+
+#define HW_I2C_TIMING1		0x20
+
+#define HW_I2C_TIMING2		0x30
+
+#define HW_I2C_CTRL1		0x40
+#define BM_I2C_CTRL1_SLAVE_IRQ	0x00000001
+#define BP_I2C_CTRL1_SLAVE_IRQ	0
+#define BM_I2C_CTRL1_SLAVE_STOP_IRQ	0x00000002
+#define BM_I2C_CTRL1_MASTER_LOSS_IRQ	0x00000004
+#define BM_I2C_CTRL1_EARLY_TERM_IRQ	0x00000008
+#define BM_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ	0x00000010
+#define BM_I2C_CTRL1_NO_SLAVE_ACK_IRQ	0x00000020
+#define BM_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ	0x00000040
+#define BM_I2C_CTRL1_BUS_FREE_IRQ	0x00000080
+#define BM_I2C_CTRL1_CLR_GOT_A_NAK	0x10000000
+
+#define HW_I2C_VERSION		0x90
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-icoll.h b/arch/arm/mach-stmp378x/include/mach/regs-icoll.h
new file mode 100644
index 0000000..f996e80
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-icoll.h
@@ -0,0 +1,45 @@
+/*
+ * stmp378x: ICOLL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef _MACH_REGS_ICOLL
+#define _MACH_REGS_ICOLL
+
+#define REGS_ICOLL_BASE	(STMP3XXX_REGS_BASE + 0x0)
+#define REGS_ICOLL_PHYS	0x80000000
+#define REGS_ICOLL_SIZE	0x2000
+
+#define HW_ICOLL_VECTOR		0x0
+
+#define HW_ICOLL_LEVELACK	0x10
+#define BM_ICOLL_LEVELACK_IRQLEVELACK	0x0000000F
+#define BP_ICOLL_LEVELACK_IRQLEVELACK	0
+
+#define HW_ICOLL_CTRL		0x20
+#define BM_ICOLL_CTRL_CLKGATE	0x40000000
+#define BM_ICOLL_CTRL_SFTRST	0x80000000
+
+#define HW_ICOLL_STAT		0x70
+
+#define HW_ICOLL_INTERRUPTn	0x120
+
+#define HW_ICOLL_INTERRUPTn	0x120
+#define BM_ICOLL_INTERRUPTn_ENABLE	0x00000004
+
+#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-ir.h b/arch/arm/mach-stmp378x/include/mach/regs-ir.h
new file mode 100644
index 0000000..a5b4ef1
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-ir.h
@@ -0,0 +1,23 @@
+/*
+ * stmp378x: IR register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_IR_BASE	(STMP3XXX_REGS_BASE + 0x78000)
+#define REGS_IR_PHYS	0x80078000
+#define REGS_IR_SIZE	0x2000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-lcdif.h b/arch/arm/mach-stmp378x/include/mach/regs-lcdif.h
new file mode 100644
index 0000000..9cdbef4
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-lcdif.h
@@ -0,0 +1,195 @@
+/*
+ * stmp378x: LCDIF register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_LCDIF_BASE	(STMP3XXX_REGS_BASE + 0x30000)
+#define REGS_LCDIF_PHYS	0x80030000
+#define REGS_LCDIF_SIZE	0x2000
+
+#define HW_LCDIF_CTRL		0x0
+#define BM_LCDIF_CTRL_RUN	0x00000001
+#define BP_LCDIF_CTRL_RUN	0
+#define BM_LCDIF_CTRL_LCDIF_MASTER	0x00000020
+#define BM_LCDIF_CTRL_RGB_TO_YCBCR422_CSC	0x00000080
+#define BM_LCDIF_CTRL_WORD_LENGTH	0x00000300
+#define BP_LCDIF_CTRL_WORD_LENGTH	8
+#define BM_LCDIF_CTRL_LCD_DATABUS_WIDTH	0x00000C00
+#define BP_LCDIF_CTRL_LCD_DATABUS_WIDTH	10
+#define BM_LCDIF_CTRL_INPUT_DATA_SWIZZLE	0x0000C000
+#define BP_LCDIF_CTRL_INPUT_DATA_SWIZZLE	14
+#define BM_LCDIF_CTRL_DATA_SELECT	0x00010000
+#define BM_LCDIF_CTRL_DOTCLK_MODE	0x00020000
+#define BM_LCDIF_CTRL_VSYNC_MODE	0x00040000
+#define BM_LCDIF_CTRL_BYPASS_COUNT	0x00080000
+#define BM_LCDIF_CTRL_DVI_MODE	0x00100000
+#define BM_LCDIF_CTRL_SHIFT_NUM_BITS	0x03E00000
+#define BP_LCDIF_CTRL_SHIFT_NUM_BITS	21
+#define BM_LCDIF_CTRL_DATA_SHIFT_DIR	0x04000000
+#define BM_LCDIF_CTRL_WAIT_FOR_VSYNC_EDGE	0x08000000
+#define BM_LCDIF_CTRL_CLKGATE	0x40000000
+#define BM_LCDIF_CTRL_SFTRST	0x80000000
+
+#define HW_LCDIF_CTRL1		0x10
+#define BM_LCDIF_CTRL1_RESET	0x00000001
+#define BP_LCDIF_CTRL1_RESET	0
+#define BM_LCDIF_CTRL1_MODE86	0x00000002
+#define BM_LCDIF_CTRL1_BUSY_ENABLE	0x00000004
+#define BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ	0x00000100
+#define BM_LCDIF_CTRL1_CUR_FRAME_DONE_IRQ	0x00000200
+#define BM_LCDIF_CTRL1_UNDERFLOW_IRQ	0x00000400
+#define BM_LCDIF_CTRL1_OVERFLOW_IRQ	0x00000800
+#define BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ_EN	0x00001000
+#define BM_LCDIF_CTRL1_BYTE_PACKING_FORMAT	0x000F0000
+#define BP_LCDIF_CTRL1_BYTE_PACKING_FORMAT	16
+#define BM_LCDIF_CTRL1_INTERLACE_FIELDS	0x00800000
+#define BM_LCDIF_CTRL1_RECOVER_ON_UNDERFLOW	0x01000000
+
+#define HW_LCDIF_TRANSFER_COUNT	0x20
+#define BM_LCDIF_TRANSFER_COUNT_H_COUNT	0x0000FFFF
+#define BP_LCDIF_TRANSFER_COUNT_H_COUNT	0
+#define BM_LCDIF_TRANSFER_COUNT_V_COUNT	0xFFFF0000
+#define BP_LCDIF_TRANSFER_COUNT_V_COUNT	16
+
+#define HW_LCDIF_CUR_BUF	0x30
+
+#define HW_LCDIF_NEXT_BUF	0x40
+
+#define HW_LCDIF_TIMING		0x60
+
+#define HW_LCDIF_VDCTRL0	0x70
+#define BM_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH	0x0003FFFF
+#define BP_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH	0
+#define BM_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT	0x00100000
+#define BM_LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT	0x00200000
+#define BM_LCDIF_VDCTRL0_ENABLE_POL	0x01000000
+#define BM_LCDIF_VDCTRL0_DOTCLK_POL	0x02000000
+#define BM_LCDIF_VDCTRL0_HSYNC_POL	0x04000000
+#define BM_LCDIF_VDCTRL0_VSYNC_POL	0x08000000
+#define BM_LCDIF_VDCTRL0_ENABLE_PRESENT	0x10000000
+#define BM_LCDIF_VDCTRL0_VSYNC_OEB	0x20000000
+
+#define HW_LCDIF_VDCTRL1	0x80
+#define BM_LCDIF_VDCTRL1_VSYNC_PERIOD	0xFFFFFFFF
+#define BP_LCDIF_VDCTRL1_VSYNC_PERIOD	0
+
+#define HW_LCDIF_VDCTRL2	0x90
+#define BM_LCDIF_VDCTRL2_HSYNC_PERIOD	0x0003FFFF
+#define BP_LCDIF_VDCTRL2_HSYNC_PERIOD	0
+#define BM_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH	0xFF000000
+#define BP_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH	24
+
+#define HW_LCDIF_VDCTRL3	0xA0
+#define BM_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT	0x0000FFFF
+#define BP_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT	0
+#define BM_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT	0x0FFF0000
+#define BP_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT	16
+
+#define HW_LCDIF_VDCTRL4	0xB0
+#define BM_LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT	0x0003FFFF
+#define BP_LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT	0
+#define BM_LCDIF_VDCTRL4_SYNC_SIGNALS_ON	0x00040000
+
+#define HW_LCDIF_DVICTRL0	0xC0
+#define BM_LCDIF_DVICTRL0_V_LINES_CNT	0x000003FF
+#define BP_LCDIF_DVICTRL0_V_LINES_CNT	0
+#define BM_LCDIF_DVICTRL0_H_BLANKING_CNT	0x000FFC00
+#define BP_LCDIF_DVICTRL0_H_BLANKING_CNT	10
+#define BM_LCDIF_DVICTRL0_H_ACTIVE_CNT	0x7FF00000
+#define BP_LCDIF_DVICTRL0_H_ACTIVE_CNT	20
+
+#define HW_LCDIF_DVICTRL1	0xD0
+#define BM_LCDIF_DVICTRL1_F2_START_LINE	0x000003FF
+#define BP_LCDIF_DVICTRL1_F2_START_LINE	0
+#define BM_LCDIF_DVICTRL1_F1_END_LINE	0x000FFC00
+#define BP_LCDIF_DVICTRL1_F1_END_LINE	10
+#define BM_LCDIF_DVICTRL1_F1_START_LINE	0x3FF00000
+#define BP_LCDIF_DVICTRL1_F1_START_LINE	20
+
+#define HW_LCDIF_DVICTRL2	0xE0
+#define BM_LCDIF_DVICTRL2_V1_BLANK_END_LINE	0x000003FF
+#define BP_LCDIF_DVICTRL2_V1_BLANK_END_LINE	0
+#define BM_LCDIF_DVICTRL2_V1_BLANK_START_LINE	0x000FFC00
+#define BP_LCDIF_DVICTRL2_V1_BLANK_START_LINE	10
+#define BM_LCDIF_DVICTRL2_F2_END_LINE	0x3FF00000
+#define BP_LCDIF_DVICTRL2_F2_END_LINE	20
+
+#define HW_LCDIF_DVICTRL3	0xF0
+#define BM_LCDIF_DVICTRL3_V2_BLANK_END_LINE	0x000003FF
+#define BP_LCDIF_DVICTRL3_V2_BLANK_END_LINE	0
+#define BM_LCDIF_DVICTRL3_V2_BLANK_START_LINE	0x03FF0000
+#define BP_LCDIF_DVICTRL3_V2_BLANK_START_LINE	16
+
+#define HW_LCDIF_DVICTRL4	0x100
+#define BM_LCDIF_DVICTRL4_H_FILL_CNT	0x000000FF
+#define BP_LCDIF_DVICTRL4_H_FILL_CNT	0
+#define BM_LCDIF_DVICTRL4_CR_FILL_VALUE	0x0000FF00
+#define BP_LCDIF_DVICTRL4_CR_FILL_VALUE	8
+#define BM_LCDIF_DVICTRL4_CB_FILL_VALUE	0x00FF0000
+#define BP_LCDIF_DVICTRL4_CB_FILL_VALUE	16
+#define BM_LCDIF_DVICTRL4_Y_FILL_VALUE	0xFF000000
+#define BP_LCDIF_DVICTRL4_Y_FILL_VALUE	24
+
+#define HW_LCDIF_CSC_COEFF0	0x110
+#define BM_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER	0x00000003
+#define BP_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER	0
+#define BM_LCDIF_CSC_COEFF0_C0	0x03FF0000
+#define BP_LCDIF_CSC_COEFF0_C0	16
+
+#define HW_LCDIF_CSC_COEFF1	0x120
+#define BM_LCDIF_CSC_COEFF1_C1	0x000003FF
+#define BP_LCDIF_CSC_COEFF1_C1	0
+#define BM_LCDIF_CSC_COEFF1_C2	0x03FF0000
+#define BP_LCDIF_CSC_COEFF1_C2	16
+
+#define HW_LCDIF_CSC_COEFF2	0x130
+#define BM_LCDIF_CSC_COEFF2_C3	0x000003FF
+#define BP_LCDIF_CSC_COEFF2_C3	0
+#define BM_LCDIF_CSC_COEFF2_C4	0x03FF0000
+#define BP_LCDIF_CSC_COEFF2_C4	16
+
+#define HW_LCDIF_CSC_COEFF3	0x140
+#define BM_LCDIF_CSC_COEFF3_C5	0x000003FF
+#define BP_LCDIF_CSC_COEFF3_C5	0
+#define BM_LCDIF_CSC_COEFF3_C6	0x03FF0000
+#define BP_LCDIF_CSC_COEFF3_C6	16
+
+#define HW_LCDIF_CSC_COEFF4	0x150
+#define BM_LCDIF_CSC_COEFF4_C7	0x000003FF
+#define BP_LCDIF_CSC_COEFF4_C7	0
+#define BM_LCDIF_CSC_COEFF4_C8	0x03FF0000
+#define BP_LCDIF_CSC_COEFF4_C8	16
+
+#define HW_LCDIF_CSC_OFFSET	0x160
+#define BM_LCDIF_CSC_OFFSET_Y_OFFSET	0x000001FF
+#define BP_LCDIF_CSC_OFFSET_Y_OFFSET	0
+#define BM_LCDIF_CSC_OFFSET_CBCR_OFFSET	0x01FF0000
+#define BP_LCDIF_CSC_OFFSET_CBCR_OFFSET	16
+
+#define HW_LCDIF_CSC_LIMIT	0x170
+#define BM_LCDIF_CSC_LIMIT_Y_MAX	0x000000FF
+#define BP_LCDIF_CSC_LIMIT_Y_MAX	0
+#define BM_LCDIF_CSC_LIMIT_Y_MIN	0x0000FF00
+#define BP_LCDIF_CSC_LIMIT_Y_MIN	8
+#define BM_LCDIF_CSC_LIMIT_CBCR_MAX	0x00FF0000
+#define BP_LCDIF_CSC_LIMIT_CBCR_MAX	16
+#define BM_LCDIF_CSC_LIMIT_CBCR_MIN	0xFF000000
+#define BP_LCDIF_CSC_LIMIT_CBCR_MIN	24
+
+#define HW_LCDIF_STAT		0x1D0
+#define BM_LCDIF_STAT_TXFIFO_EMPTY	0x04000000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-lradc.h b/arch/arm/mach-stmp378x/include/mach/regs-lradc.h
new file mode 100644
index 0000000..cb8cb06
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-lradc.h
@@ -0,0 +1,99 @@
+/*
+ * stmp378x: LRADC register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_LRADC_BASE	(STMP3XXX_REGS_BASE + 0x50000)
+#define REGS_LRADC_PHYS	0x80050000
+#define REGS_LRADC_SIZE	0x2000
+
+#define HW_LRADC_CTRL0		0x0
+#define BM_LRADC_CTRL0_SCHEDULE	0x000000FF
+#define BP_LRADC_CTRL0_SCHEDULE	0
+#define BM_LRADC_CTRL0_XPLUS_ENABLE	0x00010000
+#define BM_LRADC_CTRL0_YPLUS_ENABLE	0x00020000
+#define BM_LRADC_CTRL0_XMINUS_ENABLE	0x00040000
+#define BM_LRADC_CTRL0_YMINUS_ENABLE	0x00080000
+#define BM_LRADC_CTRL0_TOUCH_DETECT_ENABLE	0x00100000
+#define BM_LRADC_CTRL0_ONCHIP_GROUNDREF	0x00200000
+#define BM_LRADC_CTRL0_CLKGATE	0x40000000
+#define BM_LRADC_CTRL0_SFTRST	0x80000000
+
+#define HW_LRADC_CTRL1		0x10
+#define BM_LRADC_CTRL1_LRADC0_IRQ	0x00000001
+#define BP_LRADC_CTRL1_LRADC0_IRQ	0
+#define BM_LRADC_CTRL1_LRADC5_IRQ	0x00000020
+#define BM_LRADC_CTRL1_LRADC6_IRQ	0x00000040
+#define BM_LRADC_CTRL1_TOUCH_DETECT_IRQ	0x00000100
+#define BM_LRADC_CTRL1_LRADC0_IRQ_EN	0x00010000
+#define BM_LRADC_CTRL1_LRADC5_IRQ_EN	0x00200000
+#define BM_LRADC_CTRL1_TOUCH_DETECT_IRQ_EN	0x01000000
+
+#define HW_LRADC_CTRL2		0x20
+#define BM_LRADC_CTRL2_BL_BRIGHTNESS	0x001F0000
+#define BP_LRADC_CTRL2_BL_BRIGHTNESS	16
+#define BM_LRADC_CTRL2_BL_MUX_SELECT	0x00200000
+#define BM_LRADC_CTRL2_BL_ENABLE	0x00400000
+#define BM_LRADC_CTRL2_DIVIDE_BY_TWO	0xFF000000
+#define BP_LRADC_CTRL2_DIVIDE_BY_TWO	24
+
+#define HW_LRADC_CTRL3		0x30
+#define BM_LRADC_CTRL3_CYCLE_TIME	0x00000300
+#define BP_LRADC_CTRL3_CYCLE_TIME	8
+
+#define HW_LRADC_STATUS		0x40
+#define BM_LRADC_STATUS_TOUCH_DETECT_RAW	0x00000001
+#define BP_LRADC_STATUS_TOUCH_DETECT_RAW	0
+
+#define HW_LRADC_CH0		(0x50 + 0 * 0x10)
+#define HW_LRADC_CH1		(0x50 + 1 * 0x10)
+#define HW_LRADC_CH2		(0x50 + 2 * 0x10)
+#define HW_LRADC_CH3		(0x50 + 3 * 0x10)
+#define HW_LRADC_CH4		(0x50 + 4 * 0x10)
+#define HW_LRADC_CH5		(0x50 + 5 * 0x10)
+#define HW_LRADC_CH6		(0x50 + 6 * 0x10)
+#define HW_LRADC_CH7		(0x50 + 7 * 0x10)
+
+#define HW_LRADC_CHn		0x50
+#define BM_LRADC_CHn_VALUE	0x0003FFFF
+#define BP_LRADC_CHn_VALUE	0
+#define BM_LRADC_CHn_NUM_SAMPLES	0x1F000000
+#define BP_LRADC_CHn_NUM_SAMPLES	24
+#define BM_LRADC_CHn_ACCUMULATE	0x20000000
+
+#define HW_LRADC_DELAY0		(0xD0 + 0 * 0x10)
+#define HW_LRADC_DELAY1		(0xD0 + 1 * 0x10)
+#define HW_LRADC_DELAY2		(0xD0 + 2 * 0x10)
+#define HW_LRADC_DELAY3		(0xD0 + 3 * 0x10)
+
+#define HW_LRADC_DELAYn		0xD0
+#define BM_LRADC_DELAYn_DELAY	0x000007FF
+#define BP_LRADC_DELAYn_DELAY	0
+#define BM_LRADC_DELAYn_LOOP_COUNT	0x0000F800
+#define BP_LRADC_DELAYn_LOOP_COUNT	11
+#define BM_LRADC_DELAYn_TRIGGER_DELAYS	0x000F0000
+#define BP_LRADC_DELAYn_TRIGGER_DELAYS	16
+#define BM_LRADC_DELAYn_KICK	0x00100000
+#define BM_LRADC_DELAYn_TRIGGER_LRADCS	0xFF000000
+#define BP_LRADC_DELAYn_TRIGGER_LRADCS	24
+
+#define HW_LRADC_CTRL4		0x140
+#define BM_LRADC_CTRL4_LRADC6SELECT	0x0F000000
+#define BP_LRADC_CTRL4_LRADC6SELECT	24
+#define BM_LRADC_CTRL4_LRADC7SELECT	0xF0000000
+#define BP_LRADC_CTRL4_LRADC7SELECT	28
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-ocotp.h b/arch/arm/mach-stmp378x/include/mach/regs-ocotp.h
new file mode 100644
index 0000000..f0af64d
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-ocotp.h
@@ -0,0 +1,40 @@
+/*
+ * stmp378x: OCOTP register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_OCOTP_BASE	(STMP3XXX_REGS_BASE + 0x2C000)
+#define REGS_OCOTP_PHYS	0x8002C000
+#define REGS_OCOTP_SIZE	0x2000
+
+#define HW_OCOTP_CTRL		0x0
+#define BM_OCOTP_CTRL_BUSY	0x00000100
+#define BM_OCOTP_CTRL_ERROR	0x00000200
+#define BM_OCOTP_CTRL_RD_BANK_OPEN	0x00001000
+#define BM_OCOTP_CTRL_RELOAD_SHADOWS	0x00002000
+#define BM_OCOTP_CTRL_WR_UNLOCK	0xFFFF0000
+#define BP_OCOTP_CTRL_WR_UNLOCK	16
+
+#define HW_OCOTP_DATA		0x10
+
+#define HW_OCOTP_CUST0		(0x20 + 0 * 0x10)
+#define HW_OCOTP_CUST1		(0x20 + 1 * 0x10)
+#define HW_OCOTP_CUST2		(0x20 + 2 * 0x10)
+#define HW_OCOTP_CUST3		(0x20 + 3 * 0x10)
+
+#define HW_OCOTP_CUSTn		0x20
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-pinctrl.h b/arch/arm/mach-stmp378x/include/mach/regs-pinctrl.h
new file mode 100644
index 0000000..50d90ea
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-pinctrl.h
@@ -0,0 +1,90 @@
+/*
+ * stmp378x: PINCTRL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef _MACH_REGS_PINCTRL
+#define _MACH_REGS_PINCTRL
+
+#define REGS_PINCTRL_BASE	(STMP3XXX_REGS_BASE + 0x18000)
+#define REGS_PINCTRL_PHYS	0x80018000
+#define REGS_PINCTRL_SIZE	0x2000
+
+#define HW_PINCTRL_MUXSEL0	0x100
+#define HW_PINCTRL_MUXSEL1	0x110
+#define HW_PINCTRL_MUXSEL2	0x120
+#define HW_PINCTRL_MUXSEL3	0x130
+#define HW_PINCTRL_MUXSEL4	0x140
+#define HW_PINCTRL_MUXSEL5	0x150
+#define HW_PINCTRL_MUXSEL6	0x160
+#define HW_PINCTRL_MUXSEL7	0x170
+
+#define HW_PINCTRL_DRIVE0	0x200
+#define HW_PINCTRL_DRIVE1	0x210
+#define HW_PINCTRL_DRIVE2	0x220
+#define HW_PINCTRL_DRIVE3	0x230
+#define HW_PINCTRL_DRIVE4	0x240
+#define HW_PINCTRL_DRIVE5	0x250
+#define HW_PINCTRL_DRIVE6	0x260
+#define HW_PINCTRL_DRIVE7	0x270
+#define HW_PINCTRL_DRIVE8	0x280
+#define HW_PINCTRL_DRIVE9	0x290
+#define HW_PINCTRL_DRIVE10	0x2A0
+#define HW_PINCTRL_DRIVE11	0x2B0
+#define HW_PINCTRL_DRIVE12	0x2C0
+#define HW_PINCTRL_DRIVE13	0x2D0
+#define HW_PINCTRL_DRIVE14	0x2E0
+
+#define HW_PINCTRL_PULL0	0x400
+#define HW_PINCTRL_PULL1	0x410
+#define HW_PINCTRL_PULL2	0x420
+#define HW_PINCTRL_PULL3	0x430
+
+#define HW_PINCTRL_DOUT0	0x500
+#define HW_PINCTRL_DOUT1	0x510
+#define HW_PINCTRL_DOUT2	0x520
+
+#define HW_PINCTRL_DIN0		0x600
+#define HW_PINCTRL_DIN1		0x610
+#define HW_PINCTRL_DIN2		0x620
+
+#define HW_PINCTRL_DOE0		0x700
+#define HW_PINCTRL_DOE1		0x710
+#define HW_PINCTRL_DOE2		0x720
+
+#define HW_PINCTRL_PIN2IRQ0	0x800
+#define HW_PINCTRL_PIN2IRQ1	0x810
+#define HW_PINCTRL_PIN2IRQ2	0x820
+
+#define HW_PINCTRL_IRQEN0	0x900
+#define HW_PINCTRL_IRQEN1	0x910
+#define HW_PINCTRL_IRQEN2	0x920
+
+#define HW_PINCTRL_IRQLEVEL0	0xA00
+#define HW_PINCTRL_IRQLEVEL1	0xA10
+#define HW_PINCTRL_IRQLEVEL2	0xA20
+
+#define HW_PINCTRL_IRQPOL0	0xB00
+#define HW_PINCTRL_IRQPOL1	0xB10
+#define HW_PINCTRL_IRQPOL2	0xB20
+
+#define HW_PINCTRL_IRQSTAT0	0xC00
+#define HW_PINCTRL_IRQSTAT1	0xC10
+#define HW_PINCTRL_IRQSTAT2	0xC20
+
+#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-power.h b/arch/arm/mach-stmp378x/include/mach/regs-power.h
new file mode 100644
index 0000000..e454c83
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-power.h
@@ -0,0 +1,63 @@
+/*
+ * stmp378x: POWER register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef _MACH_REGS_POWER
+#define _MACH_REGS_POWER
+
+#define REGS_POWER_BASE	(STMP3XXX_REGS_BASE + 0x44000)
+#define REGS_POWER_PHYS	0x80044000
+#define REGS_POWER_SIZE	0x2000
+
+#define HW_POWER_CTRL		0x0
+#define BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO	0x00000001
+#define BP_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO	0
+#define BM_POWER_CTRL_ENIRQ_PSWITCH	0x00020000
+#define BM_POWER_CTRL_PSWITCH_IRQ	0x00100000
+#define BM_POWER_CTRL_CLKGATE	0x40000000
+
+#define HW_POWER_5VCTRL		0x10
+#define BM_POWER_5VCTRL_ENABLE_LINREG_ILIMIT	0x00000040
+
+#define HW_POWER_MINPWR		0x20
+
+#define HW_POWER_CHARGE		0x30
+
+#define HW_POWER_VDDDCTRL	0x40
+
+#define HW_POWER_VDDACTRL	0x50
+
+#define HW_POWER_VDDIOCTRL	0x60
+#define BM_POWER_VDDIOCTRL_TRG	0x0000001F
+#define BP_POWER_VDDIOCTRL_TRG	0
+
+#define HW_POWER_STS		0xC0
+#define BM_POWER_STS_VBUSVALID	0x00000002
+#define BM_POWER_STS_BVALID	0x00000004
+#define BM_POWER_STS_AVALID	0x00000008
+#define BM_POWER_STS_DC_OK	0x00000200
+
+#define HW_POWER_RESET		0x100
+
+#define HW_POWER_DEBUG		0x110
+#define BM_POWER_DEBUG_BVALIDPIOLOCK	0x00000002
+#define BM_POWER_DEBUG_AVALIDPIOLOCK	0x00000004
+#define BM_POWER_DEBUG_VBUSVALIDPIOLOCK	0x00000008
+
+#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-pwm.h b/arch/arm/mach-stmp378x/include/mach/regs-pwm.h
new file mode 100644
index 0000000..0d0f9e5
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-pwm.h
@@ -0,0 +1,53 @@
+/*
+ * stmp378x: PWM register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_PWM_BASE	(STMP3XXX_REGS_BASE + 0x64000)
+#define REGS_PWM_PHYS	0x80064000
+#define REGS_PWM_SIZE	0x2000
+
+#define HW_PWM_CTRL		0x0
+#define BM_PWM_CTRL_PWM2_ENABLE	0x00000004
+#define BM_PWM_CTRL_PWM2_ANA_CTRL_ENABLE	0x00000020
+
+#define HW_PWM_ACTIVE0		(0x10 + 0 * 0x20)
+#define HW_PWM_ACTIVE1		(0x10 + 1 * 0x20)
+#define HW_PWM_ACTIVE2		(0x10 + 2 * 0x20)
+#define HW_PWM_ACTIVE3		(0x10 + 3 * 0x20)
+
+#define HW_PWM_ACTIVEn		0x10
+#define BM_PWM_ACTIVEn_ACTIVE	0x0000FFFF
+#define BP_PWM_ACTIVEn_ACTIVE	0
+#define BM_PWM_ACTIVEn_INACTIVE	0xFFFF0000
+#define BP_PWM_ACTIVEn_INACTIVE	16
+
+#define HW_PWM_PERIOD0		(0x20 + 0 * 0x20)
+#define HW_PWM_PERIOD1		(0x20 + 1 * 0x20)
+#define HW_PWM_PERIOD2		(0x20 + 2 * 0x20)
+#define HW_PWM_PERIOD3		(0x20 + 3 * 0x20)
+
+#define HW_PWM_PERIODn		0x20
+#define BM_PWM_PERIODn_PERIOD	0x0000FFFF
+#define BP_PWM_PERIODn_PERIOD	0
+#define BM_PWM_PERIODn_ACTIVE_STATE	0x00030000
+#define BP_PWM_PERIODn_ACTIVE_STATE	16
+#define BM_PWM_PERIODn_INACTIVE_STATE	0x000C0000
+#define BP_PWM_PERIODn_INACTIVE_STATE	18
+#define BM_PWM_PERIODn_CDIV	0x00700000
+#define BP_PWM_PERIODn_CDIV	20
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-pxp.h b/arch/arm/mach-stmp378x/include/mach/regs-pxp.h
new file mode 100644
index 0000000..54d2978
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-pxp.h
@@ -0,0 +1,140 @@
+/*
+ * stmp378x: PXP register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_PXP_BASE	(STMP3XXX_REGS_BASE + 0x2A000)
+#define REGS_PXP_PHYS	0x8002A000
+#define REGS_PXP_SIZE	0x2000
+
+#define HW_PXP_CTRL		0x0
+#define BM_PXP_CTRL_ENABLE	0x00000001
+#define BP_PXP_CTRL_ENABLE	0
+#define BM_PXP_CTRL_IRQ_ENABLE	0x00000002
+#define BM_PXP_CTRL_OUTPUT_RGB_FORMAT	0x000000F0
+#define BP_PXP_CTRL_OUTPUT_RGB_FORMAT	4
+#define BM_PXP_CTRL_ROTATE	0x00000300
+#define BP_PXP_CTRL_ROTATE	8
+#define BM_PXP_CTRL_HFLIP	0x00000400
+#define BM_PXP_CTRL_VFLIP	0x00000800
+#define BM_PXP_CTRL_S0_FORMAT	0x0000F000
+#define BP_PXP_CTRL_S0_FORMAT	12
+#define BM_PXP_CTRL_SCALE	0x00040000
+#define BM_PXP_CTRL_CROP	0x00080000
+
+#define HW_PXP_STAT		0x10
+#define BM_PXP_STAT_IRQ		0x00000001
+#define BP_PXP_STAT_IRQ		0
+
+#define HW_PXP_RGBBUF		0x20
+
+#define HW_PXP_RGBSIZE		0x40
+#define BM_PXP_RGBSIZE_HEIGHT	0x00000FFF
+#define BP_PXP_RGBSIZE_HEIGHT	0
+#define BM_PXP_RGBSIZE_WIDTH	0x00FFF000
+#define BP_PXP_RGBSIZE_WIDTH	12
+
+#define HW_PXP_S0BUF		0x50
+
+#define HW_PXP_S0UBUF		0x60
+
+#define HW_PXP_S0VBUF		0x70
+
+#define HW_PXP_S0PARAM		0x80
+#define BM_PXP_S0PARAM_HEIGHT	0x000000FF
+#define BP_PXP_S0PARAM_HEIGHT	0
+#define BM_PXP_S0PARAM_WIDTH	0x0000FF00
+#define BP_PXP_S0PARAM_WIDTH	8
+#define BM_PXP_S0PARAM_YBASE	0x00FF0000
+#define BP_PXP_S0PARAM_YBASE	16
+#define BM_PXP_S0PARAM_XBASE	0xFF000000
+#define BP_PXP_S0PARAM_XBASE	24
+
+#define HW_PXP_S0BACKGROUND	0x90
+
+#define HW_PXP_S0CROP		0xA0
+#define BM_PXP_S0CROP_HEIGHT	0x000000FF
+#define BP_PXP_S0CROP_HEIGHT	0
+#define BM_PXP_S0CROP_WIDTH	0x0000FF00
+#define BP_PXP_S0CROP_WIDTH	8
+#define BM_PXP_S0CROP_YBASE	0x00FF0000
+#define BP_PXP_S0CROP_YBASE	16
+#define BM_PXP_S0CROP_XBASE	0xFF000000
+#define BP_PXP_S0CROP_XBASE	24
+
+#define HW_PXP_S0SCALE		0xB0
+#define BM_PXP_S0SCALE_XSCALE	0x00003FFF
+#define BP_PXP_S0SCALE_XSCALE	0
+#define BM_PXP_S0SCALE_YSCALE	0x3FFF0000
+#define BP_PXP_S0SCALE_YSCALE	16
+
+#define HW_PXP_CSCCOEFF0	0xD0
+
+#define HW_PXP_CSCCOEFF1	0xE0
+
+#define HW_PXP_CSCCOEFF2	0xF0
+
+#define HW_PXP_S0COLORKEYLOW	0x180
+
+#define HW_PXP_S0COLORKEYHIGH	0x190
+
+#define HW_PXP_OL0		(0x200 + 0 * 0x40)
+#define HW_PXP_OL1		(0x200 + 1 * 0x40)
+#define HW_PXP_OL2		(0x200 + 2 * 0x40)
+#define HW_PXP_OL3		(0x200 + 3 * 0x40)
+#define HW_PXP_OL4		(0x200 + 4 * 0x40)
+#define HW_PXP_OL5		(0x200 + 5 * 0x40)
+#define HW_PXP_OL6		(0x200 + 6 * 0x40)
+#define HW_PXP_OL7		(0x200 + 7 * 0x40)
+
+#define HW_PXP_OLn		0x200
+
+#define HW_PXP_OL0SIZE		(0x210 + 0 * 0x40)
+#define HW_PXP_OL1SIZE		(0x210 + 1 * 0x40)
+#define HW_PXP_OL2SIZE		(0x210 + 2 * 0x40)
+#define HW_PXP_OL3SIZE		(0x210 + 3 * 0x40)
+#define HW_PXP_OL4SIZE		(0x210 + 4 * 0x40)
+#define HW_PXP_OL5SIZE		(0x210 + 5 * 0x40)
+#define HW_PXP_OL6SIZE		(0x210 + 6 * 0x40)
+#define HW_PXP_OL7SIZE		(0x210 + 7 * 0x40)
+
+#define HW_PXP_OLnSIZE		0x210
+#define BM_PXP_OLnSIZE_HEIGHT	0x000000FF
+#define BP_PXP_OLnSIZE_HEIGHT	0
+#define BM_PXP_OLnSIZE_WIDTH	0x0000FF00
+#define BP_PXP_OLnSIZE_WIDTH	8
+
+#define HW_PXP_OL0PARAM		(0x220 + 0 * 0x40)
+#define HW_PXP_OL1PARAM		(0x220 + 1 * 0x40)
+#define HW_PXP_OL2PARAM		(0x220 + 2 * 0x40)
+#define HW_PXP_OL3PARAM		(0x220 + 3 * 0x40)
+#define HW_PXP_OL4PARAM		(0x220 + 4 * 0x40)
+#define HW_PXP_OL5PARAM		(0x220 + 5 * 0x40)
+#define HW_PXP_OL6PARAM		(0x220 + 6 * 0x40)
+#define HW_PXP_OL7PARAM		(0x220 + 7 * 0x40)
+
+#define HW_PXP_OLnPARAM		0x220
+#define BM_PXP_OLnPARAM_ENABLE	0x00000001
+#define BP_PXP_OLnPARAM_ENABLE	0
+#define BM_PXP_OLnPARAM_ALPHA_CNTL	0x00000006
+#define BP_PXP_OLnPARAM_ALPHA_CNTL	1
+#define BM_PXP_OLnPARAM_ENABLE_COLORKEY	0x00000008
+#define BM_PXP_OLnPARAM_FORMAT	0x000000F0
+#define BP_PXP_OLnPARAM_FORMAT	4
+#define BM_PXP_OLnPARAM_ALPHA	0x0000FF00
+#define BP_PXP_OLnPARAM_ALPHA	8
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-rtc.h b/arch/arm/mach-stmp378x/include/mach/regs-rtc.h
new file mode 100644
index 0000000..b8dbd67
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-rtc.h
@@ -0,0 +1,59 @@
+/*
+ * stmp378x: RTC register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_RTC_BASE	(STMP3XXX_REGS_BASE + 0x5C000)
+#define REGS_RTC_PHYS	0x8005C000
+#define REGS_RTC_SIZE	0x2000
+
+#define HW_RTC_CTRL		0x0
+#define BM_RTC_CTRL_ALARM_IRQ_EN	0x00000001
+#define BP_RTC_CTRL_ALARM_IRQ_EN	0
+#define BM_RTC_CTRL_ONEMSEC_IRQ_EN	0x00000002
+#define BM_RTC_CTRL_ALARM_IRQ	0x00000004
+#define BM_RTC_CTRL_ONEMSEC_IRQ	0x00000008
+#define BM_RTC_CTRL_WATCHDOGEN	0x00000010
+
+#define HW_RTC_STAT		0x10
+#define BM_RTC_STAT_NEW_REGS	0x0000FF00
+#define BP_RTC_STAT_NEW_REGS	8
+#define BM_RTC_STAT_STALE_REGS	0x00FF0000
+#define BP_RTC_STAT_STALE_REGS	16
+#define BM_RTC_STAT_RTC_PRESENT	0x80000000
+
+#define HW_RTC_SECONDS		0x30
+
+#define HW_RTC_ALARM		0x40
+
+#define HW_RTC_WATCHDOG		0x50
+
+#define HW_RTC_PERSISTENT0	0x60
+#define BM_RTC_PERSISTENT0_ALARM_WAKE_EN	0x00000002
+#define BM_RTC_PERSISTENT0_ALARM_EN	0x00000004
+#define BM_RTC_PERSISTENT0_XTAL24MHZ_PWRUP	0x00000010
+#define BM_RTC_PERSISTENT0_XTAL32KHZ_PWRUP	0x00000020
+#define BM_RTC_PERSISTENT0_ALARM_WAKE	0x00000080
+#define BM_RTC_PERSISTENT0_SPARE_ANALOG	0xFFFC0000
+#define BP_RTC_PERSISTENT0_SPARE_ANALOG	18
+
+#define HW_RTC_PERSISTENT1	0x70
+#define BM_RTC_PERSISTENT1_GENERAL	0xFFFFFFFF
+#define BP_RTC_PERSISTENT1_GENERAL	0
+
+#define HW_RTC_VERSION		0xD0
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-saif.h b/arch/arm/mach-stmp378x/include/mach/regs-saif.h
new file mode 100644
index 0000000..6df4176
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-saif.h
@@ -0,0 +1,21 @@
+/*
+ * stmp378x: SAIF register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_SAIF_SIZE	0x2000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-spdif.h b/arch/arm/mach-stmp378x/include/mach/regs-spdif.h
new file mode 100644
index 0000000..8015398
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-spdif.h
@@ -0,0 +1,49 @@
+/*
+ * stmp378x: SPDIF register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_SPDIF_BASE	(STMP3XXX_REGS_BASE + 0x54000)
+#define REGS_SPDIF_PHYS	0x80054000
+#define REGS_SPDIF_SIZE	0x2000
+
+#define HW_SPDIF_CTRL		0x0
+#define BM_SPDIF_CTRL_RUN	0x00000001
+#define BP_SPDIF_CTRL_RUN	0
+#define BM_SPDIF_CTRL_FIFO_ERROR_IRQ_EN	0x00000002
+#define BM_SPDIF_CTRL_FIFO_OVERFLOW_IRQ	0x00000004
+#define BM_SPDIF_CTRL_FIFO_UNDERFLOW_IRQ	0x00000008
+#define BM_SPDIF_CTRL_WORD_LENGTH	0x00000010
+#define BM_SPDIF_CTRL_CLKGATE	0x40000000
+#define BM_SPDIF_CTRL_SFTRST	0x80000000
+
+#define HW_SPDIF_STAT		0x10
+
+#define HW_SPDIF_FRAMECTRL	0x20
+
+#define HW_SPDIF_SRR		0x30
+#define BM_SPDIF_SRR_RATE	0x000FFFFF
+#define BP_SPDIF_SRR_RATE	0
+#define BM_SPDIF_SRR_BASEMULT	0x70000000
+#define BP_SPDIF_SRR_BASEMULT	28
+
+#define HW_SPDIF_DEBUG		0x40
+
+#define HW_SPDIF_DATA		0x50
+
+#define HW_SPDIF_VERSION	0x60
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-ssp.h b/arch/arm/mach-stmp378x/include/mach/regs-ssp.h
new file mode 100644
index 0000000..28aacf0
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-ssp.h
@@ -0,0 +1,102 @@
+/*
+ * stmp378x: SSP register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_SSP1_BASE	(STMP3XXX_REGS_BASE + 0x10000)
+#define REGS_SSP1_PHYS	0x80010000
+#define REGS_SSP2_BASE	(STMP3XXX_REGS_BASE + 0x34000)
+#define REGS_SSP2_PHYS	0x80034000
+#define REGS_SSP_SIZE	0x2000
+
+#define HW_SSP_CTRL0		0x0
+#define BM_SSP_CTRL0_XFER_COUNT	0x0000FFFF
+#define BP_SSP_CTRL0_XFER_COUNT	0
+#define BM_SSP_CTRL0_ENABLE	0x00010000
+#define BM_SSP_CTRL0_GET_RESP	0x00020000
+#define BM_SSP_CTRL0_LONG_RESP	0x00080000
+#define BM_SSP_CTRL0_WAIT_FOR_CMD	0x00100000
+#define BM_SSP_CTRL0_WAIT_FOR_IRQ	0x00200000
+#define BM_SSP_CTRL0_BUS_WIDTH	0x00C00000
+#define BP_SSP_CTRL0_BUS_WIDTH	22
+#define BM_SSP_CTRL0_DATA_XFER	0x01000000
+#define BM_SSP_CTRL0_READ	0x02000000
+#define BM_SSP_CTRL0_IGNORE_CRC	0x04000000
+#define BM_SSP_CTRL0_LOCK_CS	0x08000000
+#define BM_SSP_CTRL0_RUN	0x20000000
+#define BM_SSP_CTRL0_CLKGATE	0x40000000
+#define BM_SSP_CTRL0_SFTRST	0x80000000
+
+#define HW_SSP_CMD0		0x10
+#define BM_SSP_CMD0_CMD		0x000000FF
+#define BP_SSP_CMD0_CMD		0
+#define BM_SSP_CMD0_BLOCK_COUNT	0x0000FF00
+#define BP_SSP_CMD0_BLOCK_COUNT	8
+#define BM_SSP_CMD0_BLOCK_SIZE	0x000F0000
+#define BP_SSP_CMD0_BLOCK_SIZE	16
+#define BM_SSP_CMD0_APPEND_8CYC	0x00100000
+#define BM_SSP_CMD1_CMD_ARG	0xFFFFFFFF
+#define BP_SSP_CMD1_CMD_ARG	0
+
+#define HW_SSP_TIMING		0x50
+#define BM_SSP_TIMING_CLOCK_RATE	0x000000FF
+#define BP_SSP_TIMING_CLOCK_RATE	0
+#define BM_SSP_TIMING_CLOCK_DIVIDE	0x0000FF00
+#define BP_SSP_TIMING_CLOCK_DIVIDE	8
+#define BM_SSP_TIMING_TIMEOUT	0xFFFF0000
+#define BP_SSP_TIMING_TIMEOUT	16
+
+#define HW_SSP_CTRL1		0x60
+#define BM_SSP_CTRL1_SSP_MODE	0x0000000F
+#define BP_SSP_CTRL1_SSP_MODE	0
+#define BM_SSP_CTRL1_WORD_LENGTH	0x000000F0
+#define BP_SSP_CTRL1_WORD_LENGTH	4
+#define BM_SSP_CTRL1_POLARITY	0x00000200
+#define BM_SSP_CTRL1_PHASE	0x00000400
+#define BM_SSP_CTRL1_DMA_ENABLE	0x00002000
+#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ	0x00008000
+#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN	0x00010000
+#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ	0x00020000
+#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ	0x00200000
+#define BM_SSP_CTRL1_DATA_CRC_IRQ_EN	0x00400000
+#define BM_SSP_CTRL1_DATA_CRC_IRQ	0x00800000
+#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN	0x01000000
+#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ	0x02000000
+#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN	0x04000000
+#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ	0x08000000
+#define BM_SSP_CTRL1_RESP_ERR_IRQ_EN	0x10000000
+#define BM_SSP_CTRL1_RESP_ERR_IRQ	0x20000000
+#define BM_SSP_CTRL1_SDIO_IRQ	0x80000000
+
+#define HW_SSP_DATA		0x70
+
+#define HW_SSP_SDRESP0		0x80
+
+#define HW_SSP_SDRESP1		0x90
+
+#define HW_SSP_SDRESP2		0xA0
+
+#define HW_SSP_SDRESP3		0xB0
+
+#define HW_SSP_STATUS		0xC0
+#define BM_SSP_STATUS_FIFO_EMPTY	0x00000020
+#define BM_SSP_STATUS_TIMEOUT	0x00001000
+#define BM_SSP_STATUS_RESP_TIMEOUT	0x00004000
+#define BM_SSP_STATUS_RESP_ERR	0x00008000
+#define BM_SSP_STATUS_RESP_CRC_ERR	0x00010000
+#define BM_SSP_STATUS_CARD_DETECT	0x10000000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-sydma.h b/arch/arm/mach-stmp378x/include/mach/regs-sydma.h
new file mode 100644
index 0000000..08343a8
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-sydma.h
@@ -0,0 +1,23 @@
+/*
+ * stmp378x: SYDMA register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_SYDMA_BASE	(STMP3XXX_REGS_BASE + 0x26000)
+#define REGS_SYDMA_PHYS	0x80026000
+#define REGS_SYDMA_SIZE	0x2000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-timrot.h b/arch/arm/mach-stmp378x/include/mach/regs-timrot.h
new file mode 100644
index 0000000..b552795
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-timrot.h
@@ -0,0 +1,68 @@
+/*
+ * stmp378x: TIMROT register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef _MACH_REGS_TIMROT
+#define _MACH_REGS_TIMROT
+
+#define REGS_TIMROT_BASE	(STMP3XXX_REGS_BASE + 0x68000)
+#define REGS_TIMROT_PHYS	0x80068000
+#define REGS_TIMROT_SIZE	0x2000
+
+#define HW_TIMROT_ROTCTRL	0x0
+#define BM_TIMROT_ROTCTRL_SELECT_A	0x00000007
+#define BP_TIMROT_ROTCTRL_SELECT_A	0
+#define BM_TIMROT_ROTCTRL_SELECT_B	0x00000070
+#define BP_TIMROT_ROTCTRL_SELECT_B	4
+#define BM_TIMROT_ROTCTRL_POLARITY_A	0x00000100
+#define BM_TIMROT_ROTCTRL_POLARITY_B	0x00000200
+#define BM_TIMROT_ROTCTRL_OVERSAMPLE	0x00000C00
+#define BP_TIMROT_ROTCTRL_OVERSAMPLE	10
+#define BM_TIMROT_ROTCTRL_RELATIVE	0x00001000
+#define BM_TIMROT_ROTCTRL_DIVIDER	0x003F0000
+#define BP_TIMROT_ROTCTRL_DIVIDER	16
+#define BM_TIMROT_ROTCTRL_ROTARY_PRESENT	0x20000000
+#define BM_TIMROT_ROTCTRL_CLKGATE	0x40000000
+#define BM_TIMROT_ROTCTRL_SFTRST	0x80000000
+
+#define HW_TIMROT_ROTCOUNT	0x10
+#define BM_TIMROT_ROTCOUNT_UPDOWN	0x0000FFFF
+#define BP_TIMROT_ROTCOUNT_UPDOWN	0
+
+#define HW_TIMROT_TIMCTRL0	(0x20 + 0 * 0x20)
+#define HW_TIMROT_TIMCTRL1	(0x20 + 1 * 0x20)
+#define HW_TIMROT_TIMCTRL2	(0x20 + 2 * 0x20)
+
+#define HW_TIMROT_TIMCTRLn	0x20
+#define BM_TIMROT_TIMCTRLn_SELECT	0x0000000F
+#define BP_TIMROT_TIMCTRLn_SELECT	0
+#define BM_TIMROT_TIMCTRLn_PRESCALE	0x00000030
+#define BP_TIMROT_TIMCTRLn_PRESCALE	4
+#define BM_TIMROT_TIMCTRLn_RELOAD	0x00000040
+#define BM_TIMROT_TIMCTRLn_UPDATE	0x00000080
+#define BM_TIMROT_TIMCTRLn_IRQ_EN	0x00004000
+#define BM_TIMROT_TIMCTRLn_IRQ	0x00008000
+
+#define HW_TIMROT_TIMCOUNT0	(0x30 + 0 * 0x20)
+#define HW_TIMROT_TIMCOUNT1	(0x30 + 1 * 0x20)
+#define HW_TIMROT_TIMCOUNT2	(0x30 + 2 * 0x20)
+
+#define HW_TIMROT_TIMCOUNTn	0x30
+
+#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-tvenc.h b/arch/arm/mach-stmp378x/include/mach/regs-tvenc.h
new file mode 100644
index 0000000..7f895cb
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-tvenc.h
@@ -0,0 +1,67 @@
+/*
+ * stmp378x: TVENC register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_TVENC_BASE	(STMP3XXX_REGS_BASE + 0x38000)
+#define REGS_TVENC_PHYS	0x80038000
+#define REGS_TVENC_SIZE	0x2000
+
+#define HW_TVENC_CTRL		0x0
+#define BM_TVENC_CTRL_CLKGATE	0x40000000
+#define BM_TVENC_CTRL_SFTRST	0x80000000
+
+#define HW_TVENC_CONFIG		0x10
+#define BM_TVENC_CONFIG_ENCD_MODE	0x00000007
+#define BP_TVENC_CONFIG_ENCD_MODE	0
+#define BM_TVENC_CONFIG_SYNC_MODE	0x00000070
+#define BP_TVENC_CONFIG_SYNC_MODE	4
+#define BM_TVENC_CONFIG_FSYNC_PHS	0x00000200
+#define BM_TVENC_CONFIG_CGAIN	0x0000C000
+#define BP_TVENC_CONFIG_CGAIN	14
+#define BM_TVENC_CONFIG_YGAIN_SEL	0x00030000
+#define BP_TVENC_CONFIG_YGAIN_SEL	16
+#define BM_TVENC_CONFIG_PAL_SHAPE	0x00100000
+
+#define HW_TVENC_SYNCOFFSET	0x30
+
+#define HW_TVENC_COLORSUB0	0xC0
+
+#define HW_TVENC_COLORBURST	0x140
+#define BM_TVENC_COLORBURST_PBA	0x00FF0000
+#define BP_TVENC_COLORBURST_PBA	16
+#define BM_TVENC_COLORBURST_NBA	0xFF000000
+#define BP_TVENC_COLORBURST_NBA	24
+
+#define HW_TVENC_MACROVISION0	0x150
+
+#define HW_TVENC_MACROVISION1	0x160
+
+#define HW_TVENC_MACROVISION2	0x170
+
+#define HW_TVENC_MACROVISION3	0x180
+
+#define HW_TVENC_MACROVISION4	0x190
+
+#define HW_TVENC_DACCTRL	0x1A0
+#define BM_TVENC_DACCTRL_RVAL	0x00000070
+#define BP_TVENC_DACCTRL_RVAL	4
+#define BM_TVENC_DACCTRL_DUMP_TOVDD1	0x00000100
+#define BM_TVENC_DACCTRL_PWRUP1	0x00001000
+#define BM_TVENC_DACCTRL_GAINUP	0x00040000
+#define BM_TVENC_DACCTRL_GAINDN	0x00080000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-uartapp.h b/arch/arm/mach-stmp378x/include/mach/regs-uartapp.h
new file mode 100644
index 0000000..a251e68
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-uartapp.h
@@ -0,0 +1,87 @@
+/*
+ * stmp378x: UARTAPP register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_UARTAPP1_BASE	(STMP3XXX_REGS_BASE + 0x6C000)
+#define REGS_UARTAPP1_PHYS	0x8006C000
+#define REGS_UARTAPP2_BASE	(STMP3XXX_REGS_BASE + 0x6E000)
+#define REGS_UARTAPP2_PHYS	0x8006E000
+#define REGS_UARTAPP_SIZE	0x2000
+
+#define HW_UARTAPP_CTRL0	0x0
+#define BM_UARTAPP_CTRL0_XFER_COUNT	0x0000FFFF
+#define BP_UARTAPP_CTRL0_XFER_COUNT	0
+#define BM_UARTAPP_CTRL0_RXTIMEOUT	0x07FF0000
+#define BP_UARTAPP_CTRL0_RXTIMEOUT	16
+#define BM_UARTAPP_CTRL0_RXTO_ENABLE	0x08000000
+#define BM_UARTAPP_CTRL0_RUN	0x20000000
+#define BM_UARTAPP_CTRL0_SFTRST	0x80000000
+#define BM_UARTAPP_CTRL1_XFER_COUNT	0x0000FFFF
+#define BP_UARTAPP_CTRL1_XFER_COUNT	0
+#define BM_UARTAPP_CTRL1_RUN	0x10000000
+
+#define HW_UARTAPP_CTRL2	0x20
+#define BM_UARTAPP_CTRL2_UARTEN	0x00000001
+#define BP_UARTAPP_CTRL2_UARTEN	0
+#define BM_UARTAPP_CTRL2_TXE	0x00000100
+#define BM_UARTAPP_CTRL2_RXE	0x00000200
+#define BM_UARTAPP_CTRL2_RTS	0x00000800
+#define BM_UARTAPP_CTRL2_RTSEN	0x00004000
+#define BM_UARTAPP_CTRL2_CTSEN	0x00008000
+#define BM_UARTAPP_CTRL2_RXDMAE	0x01000000
+#define BM_UARTAPP_CTRL2_TXDMAE	0x02000000
+#define BM_UARTAPP_CTRL2_DMAONERR	0x04000000
+
+#define HW_UARTAPP_LINECTRL	0x30
+#define BM_UARTAPP_LINECTRL_BRK	0x00000001
+#define BP_UARTAPP_LINECTRL_BRK	0
+#define BM_UARTAPP_LINECTRL_PEN	0x00000002
+#define BM_UARTAPP_LINECTRL_EPS	0x00000004
+#define BM_UARTAPP_LINECTRL_STP2	0x00000008
+#define BM_UARTAPP_LINECTRL_FEN	0x00000010
+#define BM_UARTAPP_LINECTRL_WLEN	0x00000060
+#define BP_UARTAPP_LINECTRL_WLEN	5
+#define BM_UARTAPP_LINECTRL_SPS	0x00000080
+#define BM_UARTAPP_LINECTRL_BAUD_DIVFRAC	0x00003F00
+#define BP_UARTAPP_LINECTRL_BAUD_DIVFRAC	8
+#define BM_UARTAPP_LINECTRL_BAUD_DIVINT	0xFFFF0000
+#define BP_UARTAPP_LINECTRL_BAUD_DIVINT	16
+
+#define HW_UARTAPP_INTR		0x50
+#define BM_UARTAPP_INTR_CTSMIS	0x00000002
+#define BM_UARTAPP_INTR_RTIS	0x00000040
+#define BM_UARTAPP_INTR_CTSMIEN	0x00020000
+#define BM_UARTAPP_INTR_RXIEN	0x00100000
+#define BM_UARTAPP_INTR_RTIEN	0x00400000
+
+#define HW_UARTAPP_DATA		0x60
+
+#define HW_UARTAPP_STAT		0x70
+#define BM_UARTAPP_STAT_RXCOUNT	0x0000FFFF
+#define BP_UARTAPP_STAT_RXCOUNT	0
+#define BM_UARTAPP_STAT_FERR	0x00010000
+#define BM_UARTAPP_STAT_PERR	0x00020000
+#define BM_UARTAPP_STAT_BERR	0x00040000
+#define BM_UARTAPP_STAT_OERR	0x00080000
+#define BM_UARTAPP_STAT_RXFE	0x01000000
+#define BM_UARTAPP_STAT_TXFF	0x02000000
+#define BM_UARTAPP_STAT_TXFE	0x08000000
+#define BM_UARTAPP_STAT_CTS	0x10000000
+
+#define HW_UARTAPP_VERSION	0x90
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-uartdbg.h b/arch/arm/mach-stmp378x/include/mach/regs-uartdbg.h
new file mode 100644
index 0000000..b810deb
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-uartdbg.h
@@ -0,0 +1,268 @@
+/*
+ * stmp378x: UARTDBG register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_UARTDBG_BASE	(STMP3XXX_REGS_BASE + 0x70000)
+#define REGS_UARTDBG_PHYS	0x80070000
+#define REGS_UARTDBG_SIZE	0x2000
+
+#define HW_UARTDBGDR 0x00000000
+#define BP_UARTDBGDR_UNAVAILABLE      16
+#define BM_UARTDBGDR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGDR_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGDR_UNAVAILABLE)
+#define BP_UARTDBGDR_RESERVED      12
+#define BM_UARTDBGDR_RESERVED 0x0000F000
+#define BF_UARTDBGDR_RESERVED(v)  \
+	(((v) << 12) & BM_UARTDBGDR_RESERVED)
+#define BM_UARTDBGDR_OE 0x00000800
+#define BM_UARTDBGDR_BE 0x00000400
+#define BM_UARTDBGDR_PE 0x00000200
+#define BM_UARTDBGDR_FE 0x00000100
+#define BP_UARTDBGDR_DATA      0
+#define BM_UARTDBGDR_DATA 0x000000FF
+#define BF_UARTDBGDR_DATA(v)  \
+	(((v) << 0) & BM_UARTDBGDR_DATA)
+#define HW_UARTDBGRSR_ECR 0x00000004
+#define BP_UARTDBGRSR_ECR_UNAVAILABLE      8
+#define BM_UARTDBGRSR_ECR_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGRSR_ECR_UNAVAILABLE(v) \
+	(((v) << 8) & BM_UARTDBGRSR_ECR_UNAVAILABLE)
+#define BP_UARTDBGRSR_ECR_EC      4
+#define BM_UARTDBGRSR_ECR_EC 0x000000F0
+#define BF_UARTDBGRSR_ECR_EC(v)  \
+	(((v) << 4) & BM_UARTDBGRSR_ECR_EC)
+#define BM_UARTDBGRSR_ECR_OE 0x00000008
+#define BM_UARTDBGRSR_ECR_BE 0x00000004
+#define BM_UARTDBGRSR_ECR_PE 0x00000002
+#define BM_UARTDBGRSR_ECR_FE 0x00000001
+#define HW_UARTDBGFR 0x00000018
+#define BP_UARTDBGFR_UNAVAILABLE      16
+#define BM_UARTDBGFR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGFR_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGFR_UNAVAILABLE)
+#define BP_UARTDBGFR_RESERVED      9
+#define BM_UARTDBGFR_RESERVED 0x0000FE00
+#define BF_UARTDBGFR_RESERVED(v)  \
+	(((v) << 9) & BM_UARTDBGFR_RESERVED)
+#define BM_UARTDBGFR_RI 0x00000100
+#define BM_UARTDBGFR_TXFE 0x00000080
+#define BM_UARTDBGFR_RXFF 0x00000040
+#define BM_UARTDBGFR_TXFF 0x00000020
+#define BM_UARTDBGFR_RXFE 0x00000010
+#define BM_UARTDBGFR_BUSY 0x00000008
+#define BM_UARTDBGFR_DCD 0x00000004
+#define BM_UARTDBGFR_DSR 0x00000002
+#define BM_UARTDBGFR_CTS 0x00000001
+#define HW_UARTDBGILPR 0x00000020
+#define BP_UARTDBGILPR_UNAVAILABLE      8
+#define BM_UARTDBGILPR_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGILPR_UNAVAILABLE(v) \
+	(((v) << 8) & BM_UARTDBGILPR_UNAVAILABLE)
+#define BP_UARTDBGILPR_ILPDVSR      0
+#define BM_UARTDBGILPR_ILPDVSR 0x000000FF
+#define BF_UARTDBGILPR_ILPDVSR(v)  \
+	(((v) << 0) & BM_UARTDBGILPR_ILPDVSR)
+#define HW_UARTDBGIBRD 0x00000024
+#define BP_UARTDBGIBRD_UNAVAILABLE      16
+#define BM_UARTDBGIBRD_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIBRD_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGIBRD_UNAVAILABLE)
+#define BP_UARTDBGIBRD_BAUD_DIVINT      0
+#define BM_UARTDBGIBRD_BAUD_DIVINT 0x0000FFFF
+#define BF_UARTDBGIBRD_BAUD_DIVINT(v)  \
+	(((v) << 0) & BM_UARTDBGIBRD_BAUD_DIVINT)
+#define HW_UARTDBGFBRD 0x00000028
+#define BP_UARTDBGFBRD_UNAVAILABLE      8
+#define BM_UARTDBGFBRD_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGFBRD_UNAVAILABLE(v) \
+	(((v) << 8) & BM_UARTDBGFBRD_UNAVAILABLE)
+#define BP_UARTDBGFBRD_RESERVED      6
+#define BM_UARTDBGFBRD_RESERVED 0x000000C0
+#define BF_UARTDBGFBRD_RESERVED(v)  \
+	(((v) << 6) & BM_UARTDBGFBRD_RESERVED)
+#define BP_UARTDBGFBRD_BAUD_DIVFRAC      0
+#define BM_UARTDBGFBRD_BAUD_DIVFRAC 0x0000003F
+#define BF_UARTDBGFBRD_BAUD_DIVFRAC(v)  \
+	(((v) << 0) & BM_UARTDBGFBRD_BAUD_DIVFRAC)
+#define HW_UARTDBGLCR_H 0x0000002c
+#define BP_UARTDBGLCR_H_UNAVAILABLE      16
+#define BM_UARTDBGLCR_H_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGLCR_H_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGLCR_H_UNAVAILABLE)
+#define BP_UARTDBGLCR_H_RESERVED      8
+#define BM_UARTDBGLCR_H_RESERVED 0x0000FF00
+#define BF_UARTDBGLCR_H_RESERVED(v)  \
+	(((v) << 8) & BM_UARTDBGLCR_H_RESERVED)
+#define BM_UARTDBGLCR_H_SPS 0x00000080
+#define BP_UARTDBGLCR_H_WLEN      5
+#define BM_UARTDBGLCR_H_WLEN 0x00000060
+#define BF_UARTDBGLCR_H_WLEN(v)  \
+	(((v) << 5) & BM_UARTDBGLCR_H_WLEN)
+#define BM_UARTDBGLCR_H_FEN 0x00000010
+#define BM_UARTDBGLCR_H_STP2 0x00000008
+#define BM_UARTDBGLCR_H_EPS 0x00000004
+#define BM_UARTDBGLCR_H_PEN 0x00000002
+#define BM_UARTDBGLCR_H_BRK 0x00000001
+#define HW_UARTDBGCR 0x00000030
+#define BP_UARTDBGCR_UNAVAILABLE      16
+#define BM_UARTDBGCR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGCR_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGCR_UNAVAILABLE)
+#define BM_UARTDBGCR_CTSEN 0x00008000
+#define BM_UARTDBGCR_RTSEN 0x00004000
+#define BM_UARTDBGCR_OUT2 0x00002000
+#define BM_UARTDBGCR_OUT1 0x00001000
+#define BM_UARTDBGCR_RTS 0x00000800
+#define BM_UARTDBGCR_DTR 0x00000400
+#define BM_UARTDBGCR_RXE 0x00000200
+#define BM_UARTDBGCR_TXE 0x00000100
+#define BM_UARTDBGCR_LBE 0x00000080
+#define BP_UARTDBGCR_RESERVED      3
+#define BM_UARTDBGCR_RESERVED 0x00000078
+#define BF_UARTDBGCR_RESERVED(v)  \
+	(((v) << 3) & BM_UARTDBGCR_RESERVED)
+#define BM_UARTDBGCR_SIRLP 0x00000004
+#define BM_UARTDBGCR_SIREN 0x00000002
+#define BM_UARTDBGCR_UARTEN 0x00000001
+#define HW_UARTDBGIFLS 0x00000034
+#define BP_UARTDBGIFLS_UNAVAILABLE      16
+#define BM_UARTDBGIFLS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIFLS_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGIFLS_UNAVAILABLE)
+#define BP_UARTDBGIFLS_RESERVED      6
+#define BM_UARTDBGIFLS_RESERVED 0x0000FFC0
+#define BF_UARTDBGIFLS_RESERVED(v)  \
+	(((v) << 6) & BM_UARTDBGIFLS_RESERVED)
+#define BP_UARTDBGIFLS_RXIFLSEL      3
+#define BM_UARTDBGIFLS_RXIFLSEL 0x00000038
+#define BF_UARTDBGIFLS_RXIFLSEL(v)  \
+	(((v) << 3) & BM_UARTDBGIFLS_RXIFLSEL)
+#define BV_UARTDBGIFLS_RXIFLSEL__NOT_EMPTY      0x0
+#define BV_UARTDBGIFLS_RXIFLSEL__ONE_QUARTER    0x1
+#define BV_UARTDBGIFLS_RXIFLSEL__ONE_HALF       0x2
+#define BV_UARTDBGIFLS_RXIFLSEL__THREE_QUARTERS 0x3
+#define BV_UARTDBGIFLS_RXIFLSEL__SEVEN_EIGHTHS  0x4
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID5       0x5
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID6       0x6
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID7       0x7
+#define BP_UARTDBGIFLS_TXIFLSEL      0
+#define BM_UARTDBGIFLS_TXIFLSEL 0x00000007
+#define BF_UARTDBGIFLS_TXIFLSEL(v)  \
+	(((v) << 0) & BM_UARTDBGIFLS_TXIFLSEL)
+#define BV_UARTDBGIFLS_TXIFLSEL__EMPTY	  0x0
+#define BV_UARTDBGIFLS_TXIFLSEL__ONE_QUARTER    0x1
+#define BV_UARTDBGIFLS_TXIFLSEL__ONE_HALF       0x2
+#define BV_UARTDBGIFLS_TXIFLSEL__THREE_QUARTERS 0x3
+#define BV_UARTDBGIFLS_TXIFLSEL__SEVEN_EIGHTHS  0x4
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID5       0x5
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID6       0x6
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID7       0x7
+#define HW_UARTDBGIMSC 0x00000038
+#define BP_UARTDBGIMSC_UNAVAILABLE      16
+#define BM_UARTDBGIMSC_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIMSC_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGIMSC_UNAVAILABLE)
+#define BP_UARTDBGIMSC_RESERVED      11
+#define BM_UARTDBGIMSC_RESERVED 0x0000F800
+#define BF_UARTDBGIMSC_RESERVED(v)  \
+	(((v) << 11) & BM_UARTDBGIMSC_RESERVED)
+#define BM_UARTDBGIMSC_OEIM 0x00000400
+#define BM_UARTDBGIMSC_BEIM 0x00000200
+#define BM_UARTDBGIMSC_PEIM 0x00000100
+#define BM_UARTDBGIMSC_FEIM 0x00000080
+#define BM_UARTDBGIMSC_RTIM 0x00000040
+#define BM_UARTDBGIMSC_TXIM 0x00000020
+#define BM_UARTDBGIMSC_RXIM 0x00000010
+#define BM_UARTDBGIMSC_DSRMIM 0x00000008
+#define BM_UARTDBGIMSC_DCDMIM 0x00000004
+#define BM_UARTDBGIMSC_CTSMIM 0x00000002
+#define BM_UARTDBGIMSC_RIMIM 0x00000001
+#define HW_UARTDBGRIS 0x0000003c
+#define BP_UARTDBGRIS_UNAVAILABLE      16
+#define BM_UARTDBGRIS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGRIS_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGRIS_UNAVAILABLE)
+#define BP_UARTDBGRIS_RESERVED      11
+#define BM_UARTDBGRIS_RESERVED 0x0000F800
+#define BF_UARTDBGRIS_RESERVED(v)  \
+	(((v) << 11) & BM_UARTDBGRIS_RESERVED)
+#define BM_UARTDBGRIS_OERIS 0x00000400
+#define BM_UARTDBGRIS_BERIS 0x00000200
+#define BM_UARTDBGRIS_PERIS 0x00000100
+#define BM_UARTDBGRIS_FERIS 0x00000080
+#define BM_UARTDBGRIS_RTRIS 0x00000040
+#define BM_UARTDBGRIS_TXRIS 0x00000020
+#define BM_UARTDBGRIS_RXRIS 0x00000010
+#define BM_UARTDBGRIS_DSRRMIS 0x00000008
+#define BM_UARTDBGRIS_DCDRMIS 0x00000004
+#define BM_UARTDBGRIS_CTSRMIS 0x00000002
+#define BM_UARTDBGRIS_RIRMIS 0x00000001
+#define HW_UARTDBGMIS 0x00000040
+#define BP_UARTDBGMIS_UNAVAILABLE      16
+#define BM_UARTDBGMIS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGMIS_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGMIS_UNAVAILABLE)
+#define BP_UARTDBGMIS_RESERVED      11
+#define BM_UARTDBGMIS_RESERVED 0x0000F800
+#define BF_UARTDBGMIS_RESERVED(v)  \
+	(((v) << 11) & BM_UARTDBGMIS_RESERVED)
+#define BM_UARTDBGMIS_OEMIS 0x00000400
+#define BM_UARTDBGMIS_BEMIS 0x00000200
+#define BM_UARTDBGMIS_PEMIS 0x00000100
+#define BM_UARTDBGMIS_FEMIS 0x00000080
+#define BM_UARTDBGMIS_RTMIS 0x00000040
+#define BM_UARTDBGMIS_TXMIS 0x00000020
+#define BM_UARTDBGMIS_RXMIS 0x00000010
+#define BM_UARTDBGMIS_DSRMMIS 0x00000008
+#define BM_UARTDBGMIS_DCDMMIS 0x00000004
+#define BM_UARTDBGMIS_CTSMMIS 0x00000002
+#define BM_UARTDBGMIS_RIMMIS 0x00000001
+#define HW_UARTDBGICR 0x00000044
+#define BP_UARTDBGICR_UNAVAILABLE      16
+#define BM_UARTDBGICR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGICR_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGICR_UNAVAILABLE)
+#define BP_UARTDBGICR_RESERVED      11
+#define BM_UARTDBGICR_RESERVED 0x0000F800
+#define BF_UARTDBGICR_RESERVED(v)  \
+	(((v) << 11) & BM_UARTDBGICR_RESERVED)
+#define BM_UARTDBGICR_OEIC 0x00000400
+#define BM_UARTDBGICR_BEIC 0x00000200
+#define BM_UARTDBGICR_PEIC 0x00000100
+#define BM_UARTDBGICR_FEIC 0x00000080
+#define BM_UARTDBGICR_RTIC 0x00000040
+#define BM_UARTDBGICR_TXIC 0x00000020
+#define BM_UARTDBGICR_RXIC 0x00000010
+#define BM_UARTDBGICR_DSRMIC 0x00000008
+#define BM_UARTDBGICR_DCDMIC 0x00000004
+#define BM_UARTDBGICR_CTSMIC 0x00000002
+#define BM_UARTDBGICR_RIMIC 0x00000001
+#define HW_UARTDBGDMACR 0x00000048
+#define BP_UARTDBGDMACR_UNAVAILABLE      16
+#define BM_UARTDBGDMACR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGDMACR_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGDMACR_UNAVAILABLE)
+#define BP_UARTDBGDMACR_RESERVED      3
+#define BM_UARTDBGDMACR_RESERVED 0x0000FFF8
+#define BF_UARTDBGDMACR_RESERVED(v)  \
+	(((v) << 3) & BM_UARTDBGDMACR_RESERVED)
+#define BM_UARTDBGDMACR_DMAONERR 0x00000004
+#define BM_UARTDBGDMACR_TXDMAE 0x00000002
+#define BM_UARTDBGDMACR_RXDMAE 0x00000001
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-usbctrl.h b/arch/arm/mach-stmp378x/include/mach/regs-usbctrl.h
new file mode 100644
index 0000000..25112c1
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-usbctrl.h
@@ -0,0 +1,40 @@
+/*
+ * stmp378x: USBCTRL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_USBCTRL_BASE	(STMP3XXX_REGS_BASE + 0x80000)
+#define REGS_USBCTRL_PHYS	0x80080000
+#define REGS_USBCTRL_SIZE	0x2000
+
+#define HW_USBCTRL_USBCMD	0x140
+#define BM_USBCTRL_USBCMD_RS	0x00000001
+#define BP_USBCTRL_USBCMD_RS	0
+#define BM_USBCTRL_USBCMD_RST	0x00000002
+
+#define HW_USBCTRL_USBINTR	0x148
+#define BM_USBCTRL_USBINTR_UE	0x00000001
+#define BP_USBCTRL_USBINTR_UE	0
+
+#define HW_USBCTRL_PORTSC1	0x184
+#define BM_USBCTRL_PORTSC1_PHCD	0x00800000
+
+#define HW_USBCTRL_OTGSC	0x1A4
+#define BM_USBCTRL_OTGSC_ID	0x00000100
+#define BM_USBCTRL_OTGSC_IDIS	0x00010000
+#define BM_USBCTRL_OTGSC_IDIE	0x01000000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-usbphy.h b/arch/arm/mach-stmp378x/include/mach/regs-usbphy.h
new file mode 100644
index 0000000..11f3b73
--- /dev/null
+++ b/arch/arm/mach-stmp378x/include/mach/regs-usbphy.h
@@ -0,0 +1,37 @@
+/*
+ * stmp378x: USBPHY register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_USBPHY_BASE	(STMP3XXX_REGS_BASE + 0x7C000)
+#define REGS_USBPHY_PHYS	0x8007C000
+#define REGS_USBPHY_SIZE	0x2000
+
+#define HW_USBPHY_PWD		0x0
+
+#define HW_USBPHY_CTRL		0x30
+#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT	0x00000002
+#define BM_USBPHY_CTRL_ENDEVPLUGINDETECT	0x00000010
+#define BM_USBPHY_CTRL_ENOTGIDDETECT	0x00000080
+#define BM_USBPHY_CTRL_ENIRQDEVPLUGIN	0x00000800
+#define BM_USBPHY_CTRL_CLKGATE	0x40000000
+#define BM_USBPHY_CTRL_SFTRST	0x80000000
+
+#define HW_USBPHY_STATUS	0x40
+#define BM_USBPHY_STATUS_DEVPLUGIN_STATUS	0x00000040
+#define BM_USBPHY_STATUS_OTGID_STATUS	0x00000100
diff --git a/arch/arm/mach-stmp378x/stmp378x.c b/arch/arm/mach-stmp378x/stmp378x.c
new file mode 100644
index 0000000..ddd49a7
--- /dev/null
+++ b/arch/arm/mach-stmp378x/stmp378x.c
@@ -0,0 +1,299 @@
+/*
+ * Freescale STMP378X platform support
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/dma.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+#include <mach/pins.h>
+#include <mach/pinmux.h>
+#include <mach/dma.h>
+#include <mach/hardware.h>
+#include <mach/system.h>
+#include <mach/platform.h>
+#include <mach/stmp3xxx.h>
+#include <mach/regs-icoll.h>
+#include <mach/regs-apbh.h>
+#include <mach/regs-apbx.h>
+#include <mach/regs-pxp.h>
+#include <mach/regs-i2c.h>
+
+#include "stmp378x.h"
+/*
+ * IRQ handling
+ */
+static void stmp378x_ack_irq(unsigned int irq)
+{
+	/* Tell ICOLL to release IRQ line */
+	__raw_writel(0, REGS_ICOLL_BASE + HW_ICOLL_VECTOR);
+
+	/* ACK current interrupt */
+	__raw_writel(0x01 /* BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 */,
+			REGS_ICOLL_BASE + HW_ICOLL_LEVELACK);
+
+	/* Barrier */
+	(void)__raw_readl(REGS_ICOLL_BASE + HW_ICOLL_STAT);
+}
+
+static void stmp378x_mask_irq(unsigned int irq)
+{
+	/* IRQ disable */
+	stmp3xxx_clearl(BM_ICOLL_INTERRUPTn_ENABLE,
+			REGS_ICOLL_BASE + HW_ICOLL_INTERRUPTn + irq * 0x10);
+}
+
+static void stmp378x_unmask_irq(unsigned int irq)
+{
+	/* IRQ enable */
+	stmp3xxx_setl(BM_ICOLL_INTERRUPTn_ENABLE,
+		      REGS_ICOLL_BASE + HW_ICOLL_INTERRUPTn + irq * 0x10);
+}
+
+static struct irq_chip stmp378x_chip = {
+	.ack	= stmp378x_ack_irq,
+	.mask	= stmp378x_mask_irq,
+	.unmask = stmp378x_unmask_irq,
+};
+
+void __init stmp378x_init_irq(void)
+{
+	stmp3xxx_init_irq(&stmp378x_chip);
+}
+
+/*
+ * DMA interrupt handling
+ */
+void stmp3xxx_arch_dma_enable_interrupt(int channel)
+{
+	void __iomem *c1, *c2;
+
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		c1 = REGS_APBH_BASE + HW_APBH_CTRL1;
+		c2 = REGS_APBH_BASE + HW_APBH_CTRL2;
+		break;
+
+	case STMP3XXX_BUS_APBX:
+		c1 = REGS_APBX_BASE + HW_APBX_CTRL1;
+		c2 = REGS_APBX_BASE + HW_APBX_CTRL2;
+		break;
+
+	default:
+		return;
+	}
+	stmp3xxx_setl(1 << (16 + STMP3XXX_DMA_CHANNEL(channel)), c1);
+	stmp3xxx_setl(1 << (16 + STMP3XXX_DMA_CHANNEL(channel)), c2);
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_enable_interrupt);
+
+void stmp3xxx_arch_dma_clear_interrupt(int channel)
+{
+	void __iomem *c1, *c2;
+
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		c1 = REGS_APBH_BASE + HW_APBH_CTRL1;
+		c2 = REGS_APBH_BASE + HW_APBH_CTRL2;
+		break;
+
+	case STMP3XXX_BUS_APBX:
+		c1 = REGS_APBX_BASE + HW_APBX_CTRL1;
+		c2 = REGS_APBX_BASE + HW_APBX_CTRL2;
+		break;
+
+	default:
+		return;
+	}
+	stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel), c1);
+	stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel), c2);
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_clear_interrupt);
+
+int stmp3xxx_arch_dma_is_interrupt(int channel)
+{
+	int r = 0;
+
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		r = __raw_readl(REGS_APBH_BASE + HW_APBH_CTRL1) &
+			(1 << STMP3XXX_DMA_CHANNEL(channel));
+		break;
+
+	case STMP3XXX_BUS_APBX:
+		r = __raw_readl(REGS_APBX_BASE + HW_APBX_CTRL1) &
+			(1 << STMP3XXX_DMA_CHANNEL(channel));
+		break;
+	}
+	return r;
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_is_interrupt);
+
+void stmp3xxx_arch_dma_reset_channel(int channel)
+{
+	unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
+	void __iomem *c0;
+	u32 mask;
+
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		c0 = REGS_APBH_BASE + HW_APBH_CTRL0;
+		mask = chbit << BP_APBH_CTRL0_RESET_CHANNEL;
+		break;
+	case STMP3XXX_BUS_APBX:
+		c0 = REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL;
+		mask = chbit << BP_APBX_CHANNEL_CTRL_RESET_CHANNEL;
+		break;
+	default:
+		return;
+	}
+
+	/* Reset channel and wait for it to complete */
+	stmp3xxx_setl(mask, c0);
+	while (__raw_readl(c0) & mask)
+		cpu_relax();
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_reset_channel);
+
+void stmp3xxx_arch_dma_freeze(int channel)
+{
+	unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
+	u32 mask = 1 << chbit;
+
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		stmp3xxx_setl(mask, REGS_APBH_BASE + HW_APBH_CTRL0);
+		break;
+	case STMP3XXX_BUS_APBX:
+		stmp3xxx_setl(mask, REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL);
+		break;
+	}
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_freeze);
+
+void stmp3xxx_arch_dma_unfreeze(int channel)
+{
+	unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
+	u32 mask = 1 << chbit;
+
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		stmp3xxx_clearl(mask, REGS_APBH_BASE + HW_APBH_CTRL0);
+		break;
+	case STMP3XXX_BUS_APBX:
+		stmp3xxx_clearl(mask, REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL);
+		break;
+	}
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_unfreeze);
+
+/*
+ * The registers are all very closely mapped, so we might as well map them all
+ * with a single mapping
+ *
+ * Logical      Physical
+ * f0000000	80000000	On-chip registers
+ * f1000000	00000000	32k on-chip SRAM
+ */
+
+static struct map_desc stmp378x_io_desc[] __initdata = {
+	{
+		.virtual	= (u32)STMP3XXX_REGS_BASE,
+		.pfn		= __phys_to_pfn(STMP3XXX_REGS_PHBASE),
+		.length		= STMP3XXX_REGS_SIZE,
+		.type		= MT_DEVICE,
+	},
+	{
+		.virtual	= (u32)STMP3XXX_OCRAM_BASE,
+		.pfn		= __phys_to_pfn(STMP3XXX_OCRAM_PHBASE),
+		.length		= STMP3XXX_OCRAM_SIZE,
+		.type		= MT_DEVICE,
+	},
+};
+
+
+static u64 common_dmamask = DMA_BIT_MASK(32);
+
+/*
+ * devices that are present only on stmp378x, not on all 3xxx boards:
+ * 	PxP
+ * 	I2C
+ */
+static struct resource pxp_resource[] = {
+	{
+		.flags	= IORESOURCE_MEM,
+		.start	= REGS_PXP_PHYS,
+		.end	= REGS_PXP_PHYS + REGS_PXP_SIZE,
+	}, {
+		.flags	= IORESOURCE_IRQ,
+		.start	= IRQ_PXP,
+		.end	= IRQ_PXP,
+	},
+};
+
+struct platform_device stmp378x_pxp = {
+	.name		= "stmp3xxx-pxp",
+	.id		= -1,
+	.dev		= {
+		.dma_mask		= &common_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.num_resources	= ARRAY_SIZE(pxp_resource),
+	.resource	= pxp_resource,
+};
+
+static struct resource i2c_resources[] = {
+	{
+		.flags = IORESOURCE_IRQ,
+		.start = IRQ_I2C_ERROR,
+		.end = IRQ_I2C_ERROR,
+	}, {
+		.flags = IORESOURCE_MEM,
+		.start = REGS_I2C_PHYS,
+		.end = REGS_I2C_PHYS + REGS_I2C_SIZE,
+	}, {
+		.flags = IORESOURCE_DMA,
+		.start = STMP3XXX_DMA(3, STMP3XXX_BUS_APBX),
+		.end = STMP3XXX_DMA(3, STMP3XXX_BUS_APBX),
+	},
+};
+
+struct platform_device stmp378x_i2c = {
+	.name = "i2c_stmp3xxx",
+	.id = 0,
+	.dev	= {
+		.dma_mask	= &common_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.resource = i2c_resources,
+	.num_resources = ARRAY_SIZE(i2c_resources),
+};
+
+void __init stmp378x_map_io(void)
+{
+	iotable_init(stmp378x_io_desc, ARRAY_SIZE(stmp378x_io_desc));
+}
diff --git a/arch/arm/mach-stmp378x/stmp378x.h b/arch/arm/mach-stmp378x/stmp378x.h
new file mode 100644
index 0000000..0dc15b3
--- /dev/null
+++ b/arch/arm/mach-stmp378x/stmp378x.h
@@ -0,0 +1,25 @@
+/*
+ * Freescale STMP37XX/STMP378X internal functions and data declarations
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __MACH_STMP378X_H
+#define __MACH_STMP378X_H
+
+void stmp378x_map_io(void);
+void stmp378x_init_irq(void);
+
+extern struct platform_device stmp378x_pxp, stmp378x_i2c;
+#endif /* __MACH_STMP378X_COMMON_H */
diff --git a/arch/arm/mach-stmp378x/stmp378x_devb.c b/arch/arm/mach-stmp378x/stmp378x_devb.c
new file mode 100644
index 0000000..90d8fe6
--- /dev/null
+++ b/arch/arm/mach-stmp378x/stmp378x_devb.c
@@ -0,0 +1,334 @@
+/*
+ * Freescale STMP378X development board support
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/spi/spi.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/pins.h>
+#include <mach/pinmux.h>
+#include <mach/platform.h>
+#include <mach/stmp3xxx.h>
+#include <mach/mmc.h>
+#include <mach/gpmi.h>
+
+#include "stmp378x.h"
+
+static struct platform_device *devices[] = {
+	&stmp3xxx_dbguart,
+	&stmp3xxx_appuart,
+	&stmp3xxx_watchdog,
+	&stmp3xxx_touchscreen,
+	&stmp3xxx_rtc,
+	&stmp3xxx_keyboard,
+	&stmp3xxx_framebuffer,
+	&stmp3xxx_backlight,
+	&stmp3xxx_rotdec,
+	&stmp3xxx_persistent,
+	&stmp3xxx_dcp_bootstream,
+	&stmp3xxx_dcp,
+	&stmp3xxx_battery,
+	&stmp378x_pxp,
+	&stmp378x_i2c,
+};
+
+static struct pin_desc i2c_pins_desc[] = {
+	{ PINID_I2C_SCL, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_I2C_SDA, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+};
+
+static struct pin_group i2c_pins = {
+	.pins		= i2c_pins_desc,
+	.nr_pins	= ARRAY_SIZE(i2c_pins_desc),
+};
+
+static struct pin_desc dbguart_pins_0[] = {
+	{ PINID_PWM0, PIN_FUN3, },
+	{ PINID_PWM1, PIN_FUN3, },
+};
+
+static struct pin_group dbguart_pins[] = {
+	[0] = {
+		.pins		= dbguart_pins_0,
+		.nr_pins	= ARRAY_SIZE(dbguart_pins_0),
+	},
+};
+
+static int dbguart_pins_control(int id, int request)
+{
+	int r = 0;
+
+	if (request)
+		r = stmp3xxx_request_pin_group(&dbguart_pins[id], "debug uart");
+	else
+		stmp3xxx_release_pin_group(&dbguart_pins[id], "debug uart");
+	return r;
+}
+
+static struct pin_desc appuart_pins_0[] = {
+	{ PINID_AUART1_CTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+	{ PINID_AUART1_RTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+	{ PINID_AUART1_RX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+	{ PINID_AUART1_TX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+};
+
+static struct pin_desc appuart_pins_1[] = {
+#if 0 /* enable these when second appuart will be connected */
+	{ PINID_AUART2_CTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+	{ PINID_AUART2_RTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+	{ PINID_AUART2_RX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+	{ PINID_AUART2_TX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+#endif
+};
+
+static struct pin_desc mmc_pins_desc[] = {
+	{ PINID_SSP1_DATA0, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+	{ PINID_SSP1_DATA1, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+	{ PINID_SSP1_DATA2, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+	{ PINID_SSP1_DATA3, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+	{ PINID_SSP1_CMD, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+	{ PINID_SSP1_SCK, PIN_FUN1, PIN_8MA, PIN_3_3V, 0 },
+	{ PINID_SSP1_DETECT, PIN_FUN1, PIN_8MA, PIN_3_3V, 0 },
+};
+
+static struct pin_group mmc_pins = {
+	.pins		= mmc_pins_desc,
+	.nr_pins	= ARRAY_SIZE(mmc_pins_desc),
+};
+
+static int stmp3xxxmmc_get_wp(void)
+{
+	return gpio_get_value(PINID_PWM4);
+}
+
+static int stmp3xxxmmc_hw_init_ssp1(void)
+{
+	int ret;
+
+	ret = stmp3xxx_request_pin_group(&mmc_pins, "mmc");
+	if (ret)
+		goto out;
+
+	/* Configure write protect GPIO pin */
+	ret = gpio_request(PINID_PWM4, "mmc wp");
+	if (ret)
+		goto out_wp;
+
+	gpio_direction_input(PINID_PWM4);
+
+	/* Configure POWER pin as gpio to drive power to MMC slot */
+	ret = gpio_request(PINID_PWM3, "mmc power");
+	if (ret)
+		goto out_power;
+
+	gpio_direction_output(PINID_PWM3, 0);
+	mdelay(100);
+
+	return 0;
+
+out_power:
+	gpio_free(PINID_PWM4);
+out_wp:
+	stmp3xxx_release_pin_group(&mmc_pins, "mmc");
+out:
+	return ret;
+}
+
+static void stmp3xxxmmc_hw_release_ssp1(void)
+{
+	gpio_free(PINID_PWM3);
+	gpio_free(PINID_PWM4);
+	stmp3xxx_release_pin_group(&mmc_pins, "mmc");
+}
+
+static void stmp3xxxmmc_cmd_pullup_ssp1(int enable)
+{
+	stmp3xxx_pin_pullup(PINID_SSP1_CMD, enable, "mmc");
+}
+
+static unsigned long
+stmp3xxxmmc_setclock_ssp1(void __iomem *base, unsigned long hz)
+{
+	struct clk *ssp, *parent;
+	char *p;
+	long r;
+
+	ssp = clk_get(NULL, "ssp");
+
+	/* using SSP1, no timeout, clock rate 1 */
+	writel(BF(2, SSP_TIMING_CLOCK_DIVIDE) |
+	       BF(0xFFFF, SSP_TIMING_TIMEOUT),
+	       base + HW_SSP_TIMING);
+
+	p = (hz > 1000000) ? "io" : "osc_24M";
+	parent = clk_get(NULL, p);
+	clk_set_parent(ssp, parent);
+	r = clk_set_rate(ssp, 2 * hz / 1000);
+	clk_put(parent);
+	clk_put(ssp);
+
+	return hz;
+}
+
+static struct stmp3xxxmmc_platform_data mmc_data = {
+	.hw_init	= stmp3xxxmmc_hw_init_ssp1,
+	.hw_release	= stmp3xxxmmc_hw_release_ssp1,
+	.get_wp		= stmp3xxxmmc_get_wp,
+	.cmd_pullup	= stmp3xxxmmc_cmd_pullup_ssp1,
+	.setclock	= stmp3xxxmmc_setclock_ssp1,
+};
+
+
+static struct pin_group appuart_pins[] = {
+	[0] = {
+		.pins		= appuart_pins_0,
+		.nr_pins	= ARRAY_SIZE(appuart_pins_0),
+	},
+	[1] = {
+		.pins		= appuart_pins_1,
+		.nr_pins	= ARRAY_SIZE(appuart_pins_1),
+	},
+};
+
+static struct pin_desc ssp1_pins_desc[] = {
+	{ PINID_SSP1_SCK,	PIN_FUN1, PIN_8MA, PIN_3_3V, 0, },
+	{ PINID_SSP1_CMD,	PIN_FUN1, PIN_4MA, PIN_3_3V, 0, },
+	{ PINID_SSP1_DATA0,	PIN_FUN1, PIN_4MA, PIN_3_3V, 0, },
+	{ PINID_SSP1_DATA3,	PIN_FUN1, PIN_4MA, PIN_3_3V, 0, },
+};
+
+static struct pin_desc ssp2_pins_desc[] = {
+	{ PINID_GPMI_WRN,	PIN_FUN3, PIN_8MA, PIN_3_3V, 0, },
+	{ PINID_GPMI_RDY1,	PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
+	{ PINID_GPMI_D00,	PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
+	{ PINID_GPMI_D03,	PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
+};
+
+static struct pin_group ssp1_pins = {
+	.pins = ssp1_pins_desc,
+	.nr_pins = ARRAY_SIZE(ssp1_pins_desc),
+};
+
+static struct pin_group ssp2_pins = {
+	.pins = ssp1_pins_desc,
+	.nr_pins = ARRAY_SIZE(ssp2_pins_desc),
+};
+
+static struct pin_desc gpmi_pins_desc[] = {
+	{ PINID_GPMI_CE0N, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_CE1N, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GMPI_CE2N, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_CLE, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_ALE, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_WPN, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_RDY1, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_D00, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_D01, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_D02, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_D03, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_D04, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_D05, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_D06, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_D07, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_RDY0, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_RDY2, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_RDY3, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_WRN, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 },
+	{ PINID_GPMI_RDN, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 },
+};
+
+static struct pin_group gpmi_pins = {
+	.pins		= gpmi_pins_desc,
+	.nr_pins	= ARRAY_SIZE(gpmi_pins_desc),
+};
+
+static struct mtd_partition gpmi_partitions[] = {
+	[0] = {
+		.name	= "boot",
+		.size	= 10 * SZ_1M,
+		.offset	= 0,
+	},
+	[1] = {
+		.name	= "data",
+		.size	= MTDPART_SIZ_FULL,
+		.offset	= MTDPART_OFS_APPEND,
+	},
+};
+
+static struct gpmi_platform_data gpmi_data = {
+	.pins = &gpmi_pins,
+	.nr_parts = ARRAY_SIZE(gpmi_partitions),
+	.parts = gpmi_partitions,
+	.part_types = { "cmdline", NULL },
+};
+
+static struct spi_board_info spi_board_info[] __initdata = {
+#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE)
+	{
+		.modalias       = "enc28j60",
+		.max_speed_hz   = 6 * 1000 * 1000,
+		.bus_num	= 1,
+		.chip_select    = 0,
+		.platform_data  = NULL,
+	},
+#endif
+};
+
+static void __init stmp378x_devb_init(void)
+{
+	stmp3xxx_pinmux_init(NR_REAL_IRQS);
+
+	/* init stmp3xxx platform */
+	stmp3xxx_init();
+
+	stmp3xxx_dbguart.dev.platform_data = dbguart_pins_control;
+	stmp3xxx_appuart.dev.platform_data = appuart_pins;
+	stmp3xxx_mmc.dev.platform_data = &mmc_data;
+	stmp3xxx_gpmi.dev.platform_data = &gpmi_data;
+	stmp3xxx_spi1.dev.platform_data = &ssp1_pins;
+	stmp3xxx_spi2.dev.platform_data = &ssp2_pins;
+	stmp378x_i2c.dev.platform_data = &i2c_pins;
+
+	/* register spi devices */
+	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+	/* add board's devices */
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+
+	/* add devices selected by command line ssp1= and ssp2= options */
+	stmp3xxx_ssp1_device_register();
+	stmp3xxx_ssp2_device_register();
+}
+
+MACHINE_START(STMP378X, "STMP378X")
+	.phys_io	= 0x80000000,
+	.io_pg_offst	= ((0xf0000000) >> 18) & 0xfffc,
+	.boot_params	= 0x40000100,
+	.map_io		= stmp378x_map_io,
+	.init_irq	= stmp378x_init_irq,
+	.timer		= &stmp3xxx_timer,
+	.init_machine	= stmp378x_devb_init,
+MACHINE_END
diff --git a/arch/arm/mach-stmp37xx/Makefile b/arch/arm/mach-stmp37xx/Makefile
new file mode 100644
index 0000000..57deffd
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ARCH_STMP37XX) += stmp37xx.o
+obj-$(CONFIG_MACH_STMP37XX) += stmp37xx_devb.o
diff --git a/arch/arm/mach-stmp37xx/Makefile.boot b/arch/arm/mach-stmp37xx/Makefile.boot
new file mode 100644
index 0000000..1568ad4
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/Makefile.boot
@@ -0,0 +1,3 @@
+   zreladdr-y	:= 0x40008000
+params_phys-y	:= 0x40000100
+initrd_phys-y	:= 0x40800000
diff --git a/arch/arm/mach-stmp37xx/include/mach/entry-macro.S b/arch/arm/mach-stmp37xx/include/mach/entry-macro.S
new file mode 100644
index 0000000..fed2787
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/entry-macro.S
@@ -0,0 +1,37 @@
+/*
+ * Low-level IRQ helper macros for Freescale STMP37XX
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+
+		.macro	disable_fiq
+		.endm
+
+		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+	        mov	\base, #0xf0000000	@ vm address of IRQ controller
+		ldr	\irqnr, [\base, #0x30]	@ HW_ICOLL_STAT
+		cmp	\irqnr, #0x3f
+		movne	\irqstat, #0		@ Ack this IRQ
+		strne	\irqstat, [\base, #0x00]@ HW_ICOLL_VECTOR
+		moveqs	\irqnr, #0		@ Zero flag set for no IRQ
+
+		.endm
+
+                .macro  get_irqnr_preamble, base, tmp
+                .endm
+
+                .macro  arch_ret_to_user, tmp1, tmp2
+                .endm
diff --git a/arch/arm/mach-stmp37xx/include/mach/irqs.h b/arch/arm/mach-stmp37xx/include/mach/irqs.h
new file mode 100644
index 0000000..98f1293
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/irqs.h
@@ -0,0 +1,99 @@
+/*
+ * Freescale STMP37XX interrupts
+ *
+ * Copyright (C) 2005 Sigmatel Inc
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _ASM_ARCH_IRQS_H
+#define _ASM_ARCH_IRQS_H
+
+#define IRQ_DEBUG_UART	         0
+#define IRQ_COMMS_RX	           1
+#define IRQ_COMMS_TX	           1
+#define IRQ_SSP2_ERROR	         2
+#define IRQ_VDD5V	              3
+#define IRQ_HEADPHONE_SHORT	    4
+#define IRQ_DAC_DMA	            5
+#define IRQ_DAC_ERROR	          6
+#define IRQ_ADC_DMA	            7
+#define IRQ_ADC_ERROR	          8
+#define IRQ_SPDIF_DMA	          9
+#define IRQ_SAIF2_DMA	          9
+#define IRQ_SPDIF_ERROR	        10
+#define IRQ_SAIF1_IRQ	          10
+#define IRQ_SAIF2_IRQ	          10
+#define IRQ_USB_CTRL	           11
+#define IRQ_USB_WAKEUP	         12
+#define IRQ_GPMI_DMA	           13
+#define IRQ_SSP1_DMA	           14
+#define IRQ_SSP_ERROR	          15
+#define IRQ_GPIO0	              16
+#define IRQ_GPIO1	              17
+#define IRQ_GPIO2	              18
+#define IRQ_SAIF1_DMA	          19
+#define IRQ_SSP2_DMA	           20
+#define IRQ_ECC8_IRQ	           21
+#define IRQ_RTC_ALARM	          22
+#define IRQ_UARTAPP_TX_DMA	     23
+#define IRQ_UARTAPP_INTERNAL	   24
+#define IRQ_UARTAPP_RX_DMA	     25
+#define IRQ_I2C_DMA	            26
+#define IRQ_I2C_ERROR	          27
+#define IRQ_TIMER0	             28
+#define IRQ_TIMER1	             29
+#define IRQ_TIMER2	             30
+#define IRQ_TIMER3	             31
+#define IRQ_BATT_BRNOUT	        32
+#define IRQ_VDDD_BRNOUT	        33
+#define IRQ_VDDIO_BRNOUT	       34
+#define IRQ_VDD18_BRNOUT	       35
+#define IRQ_TOUCH_DETECT	       36
+#define IRQ_LRADC_CH0	          37
+#define IRQ_LRADC_CH1	          38
+#define IRQ_LRADC_CH2	          39
+#define IRQ_LRADC_CH3	          40
+#define IRQ_LRADC_CH4	          41
+#define IRQ_LRADC_CH5	          42
+#define IRQ_LRADC_CH6	          43
+#define IRQ_LRADC_CH7	          44
+#define IRQ_LCDIF_DMA	          45
+#define IRQ_LCDIF_ERROR	        46
+#define IRQ_DIGCTL_DEBUG_TRAP	  47
+#define IRQ_RTC_1MSEC	          48
+#define IRQ_DRI_DMA	            49
+#define IRQ_DRI_ATTENTION	      50
+#define IRQ_GPMI_ATTENTION	     51
+#define IRQ_IR	                 52
+#define IRQ_DCP_VMI	            53
+#define IRQ_DCP	                54
+#define IRQ_RESERVED_55	        55
+#define IRQ_RESERVED_56	        56
+#define IRQ_RESERVED_57	        57
+#define IRQ_RESERVED_58	        58
+#define IRQ_RESERVED_59	        59
+#define SW_IRQ_60	              60
+#define SW_IRQ_61	              61
+#define SW_IRQ_62	              62
+#define SW_IRQ_63	              63
+
+#define NR_REAL_IRQS		64
+#define NR_IRQS			(NR_REAL_IRQS + 32 * 3)
+
+/* TIMER and BRNOUT are FIQ capable */
+#define FIQ_START			IRQ_TIMER0
+
+/* Hard disk IRQ is a GPMI attention IRQ */
+#define IRQ_HARDDISK		IRQ_GPMI_ATTENTION
+
+#endif /* _ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-stmp37xx/include/mach/pins.h b/arch/arm/mach-stmp37xx/include/mach/pins.h
new file mode 100644
index 0000000..d56de0c
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/pins.h
@@ -0,0 +1,147 @@
+/*
+ * Freescale STMP37XX SoC pin multiplexing
+ *
+ * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __ASM_ARCH_PINS_H
+#define __ASM_ARCH_PINS_H
+
+/*
+ * Define all STMP37XX pins, a pin name corresponds to a STMP37xx hardware
+ * interface  this pin belongs to.
+ */
+
+/* Bank 0 */
+#define PINID_GPMI_D00		STMP3XXX_PINID(0, 0)
+#define PINID_GPMI_D01		STMP3XXX_PINID(0, 1)
+#define PINID_GPMI_D02		STMP3XXX_PINID(0, 2)
+#define PINID_GPMI_D03		STMP3XXX_PINID(0, 3)
+#define PINID_GPMI_D04		STMP3XXX_PINID(0, 4)
+#define PINID_GPMI_D05		STMP3XXX_PINID(0, 5)
+#define PINID_GPMI_D06		STMP3XXX_PINID(0, 6)
+#define PINID_GPMI_D07		STMP3XXX_PINID(0, 7)
+#define PINID_GPMI_D08		STMP3XXX_PINID(0, 8)
+#define PINID_GPMI_D09		STMP3XXX_PINID(0, 9)
+#define PINID_GPMI_D10		STMP3XXX_PINID(0, 10)
+#define PINID_GPMI_D11		STMP3XXX_PINID(0, 11)
+#define PINID_GPMI_D12		STMP3XXX_PINID(0, 12)
+#define PINID_GPMI_D13		STMP3XXX_PINID(0, 13)
+#define PINID_GPMI_D14		STMP3XXX_PINID(0, 14)
+#define PINID_GPMI_D15		STMP3XXX_PINID(0, 15)
+#define PINID_GPMI_A0		STMP3XXX_PINID(0, 16)
+#define PINID_GPMI_A1		STMP3XXX_PINID(0, 17)
+#define PINID_GPMI_A2		STMP3XXX_PINID(0, 18)
+#define PINID_GPMI_RDY0		STMP3XXX_PINID(0, 19)
+#define PINID_GPMI_RDY2		STMP3XXX_PINID(0, 20)
+#define PINID_GPMI_RDY3		STMP3XXX_PINID(0, 21)
+#define PINID_GPMI_RESETN	STMP3XXX_PINID(0, 22)
+#define PINID_GPMI_IRQ		STMP3XXX_PINID(0, 23)
+#define PINID_GPMI_WRN		STMP3XXX_PINID(0, 24)
+#define PINID_GPMI_RDN		STMP3XXX_PINID(0, 25)
+#define PINID_UART2_CTS		STMP3XXX_PINID(0, 26)
+#define PINID_UART2_RTS		STMP3XXX_PINID(0, 27)
+#define PINID_UART2_RX		STMP3XXX_PINID(0, 28)
+#define PINID_UART2_TX		STMP3XXX_PINID(0, 29)
+
+/* Bank 1 */
+#define PINID_LCD_D00		STMP3XXX_PINID(1, 0)
+#define PINID_LCD_D01		STMP3XXX_PINID(1, 1)
+#define PINID_LCD_D02		STMP3XXX_PINID(1, 2)
+#define PINID_LCD_D03		STMP3XXX_PINID(1, 3)
+#define PINID_LCD_D04		STMP3XXX_PINID(1, 4)
+#define PINID_LCD_D05		STMP3XXX_PINID(1, 5)
+#define PINID_LCD_D06		STMP3XXX_PINID(1, 6)
+#define PINID_LCD_D07		STMP3XXX_PINID(1, 7)
+#define PINID_LCD_D08		STMP3XXX_PINID(1, 8)
+#define PINID_LCD_D09		STMP3XXX_PINID(1, 9)
+#define PINID_LCD_D10		STMP3XXX_PINID(1, 10)
+#define PINID_LCD_D11		STMP3XXX_PINID(1, 11)
+#define PINID_LCD_D12		STMP3XXX_PINID(1, 12)
+#define PINID_LCD_D13		STMP3XXX_PINID(1, 13)
+#define PINID_LCD_D14		STMP3XXX_PINID(1, 14)
+#define PINID_LCD_D15		STMP3XXX_PINID(1, 15)
+#define PINID_LCD_RESET 	STMP3XXX_PINID(1, 16)
+#define PINID_LCD_RS		STMP3XXX_PINID(1, 17)
+#define PINID_LCD_WR_RWN	STMP3XXX_PINID(1, 18)
+#define PINID_LCD_RD_E		STMP3XXX_PINID(1, 19)
+#define PINID_LCD_CS		STMP3XXX_PINID(1, 20)
+#define PINID_LCD_BUSY		STMP3XXX_PINID(1, 21)
+#define PINID_SSP1_CMD		STMP3XXX_PINID(1, 22)
+#define PINID_SSP1_SCK		STMP3XXX_PINID(1, 23)
+#define PINID_SSP1_DATA0	STMP3XXX_PINID(1, 24)
+#define PINID_SSP1_DATA1	STMP3XXX_PINID(1, 25)
+#define PINID_SSP1_DATA2	STMP3XXX_PINID(1, 26)
+#define PINID_SSP1_DATA3	STMP3XXX_PINID(1, 27)
+#define PINID_SSP1_DETECT	STMP3XXX_PINID(1, 28)
+
+/* Bank 2 */
+#define PINID_PWM0		STMP3XXX_PINID(2, 0)
+#define PINID_PWM1		STMP3XXX_PINID(2, 1)
+#define PINID_PWM2		STMP3XXX_PINID(2, 2)
+#define PINID_PWM3		STMP3XXX_PINID(2, 3)
+#define PINID_PWM4		STMP3XXX_PINID(2, 4)
+#define PINID_I2C_SCL		STMP3XXX_PINID(2, 5)
+#define PINID_I2C_SDA		STMP3XXX_PINID(2, 6)
+#define PINID_ROTTARYA		STMP3XXX_PINID(2, 7)
+#define PINID_ROTTARYB		STMP3XXX_PINID(2, 8)
+#define PINID_EMI_CKE		STMP3XXX_PINID(2, 9)
+#define PINID_EMI_RASN		STMP3XXX_PINID(2, 10)
+#define PINID_EMI_CASN		STMP3XXX_PINID(2, 11)
+#define PINID_EMI_CE0N		STMP3XXX_PINID(2, 12)
+#define PINID_EMI_CE1N		STMP3XXX_PINID(2, 13)
+#define PINID_EMI_CE2N		STMP3XXX_PINID(2, 14)
+#define PINID_EMI_CE3N		STMP3XXX_PINID(2, 15)
+#define PINID_EMI_A00		STMP3XXX_PINID(2, 16)
+#define PINID_EMI_A01		STMP3XXX_PINID(2, 17)
+#define PINID_EMI_A02		STMP3XXX_PINID(2, 18)
+#define PINID_EMI_A03		STMP3XXX_PINID(2, 19)
+#define PINID_EMI_A04		STMP3XXX_PINID(2, 20)
+#define PINID_EMI_A05		STMP3XXX_PINID(2, 21)
+#define PINID_EMI_A06		STMP3XXX_PINID(2, 22)
+#define PINID_EMI_A07		STMP3XXX_PINID(2, 23)
+#define PINID_EMI_A08		STMP3XXX_PINID(2, 24)
+#define PINID_EMI_A09		STMP3XXX_PINID(2, 25)
+#define PINID_EMI_A10		STMP3XXX_PINID(2, 26)
+#define PINID_EMI_A11		STMP3XXX_PINID(2, 27)
+#define PINID_EMI_A12		STMP3XXX_PINID(2, 28)
+#define PINID_EMI_A13		STMP3XXX_PINID(2, 29)
+#define PINID_EMI_A14		STMP3XXX_PINID(2, 30)
+#define PINID_EMI_WEN		STMP3XXX_PINID(2, 31)
+
+/* Bank 3 */
+#define PINID_EMI_D00		STMP3XXX_PINID(3, 0)
+#define PINID_EMI_D01		STMP3XXX_PINID(3, 1)
+#define PINID_EMI_D02		STMP3XXX_PINID(3, 2)
+#define PINID_EMI_D03		STMP3XXX_PINID(3, 3)
+#define PINID_EMI_D04		STMP3XXX_PINID(3, 4)
+#define PINID_EMI_D05		STMP3XXX_PINID(3, 5)
+#define PINID_EMI_D06		STMP3XXX_PINID(3, 6)
+#define PINID_EMI_D07		STMP3XXX_PINID(3, 7)
+#define PINID_EMI_D08		STMP3XXX_PINID(3, 8)
+#define PINID_EMI_D09		STMP3XXX_PINID(3, 9)
+#define PINID_EMI_D10		STMP3XXX_PINID(3, 10)
+#define PINID_EMI_D11		STMP3XXX_PINID(3, 11)
+#define PINID_EMI_D12		STMP3XXX_PINID(3, 12)
+#define PINID_EMI_D13		STMP3XXX_PINID(3, 13)
+#define PINID_EMI_D14		STMP3XXX_PINID(3, 14)
+#define PINID_EMI_D15		STMP3XXX_PINID(3, 15)
+#define PINID_EMI_DQS0		STMP3XXX_PINID(3, 16)
+#define PINID_EMI_DQS1		STMP3XXX_PINID(3, 17)
+#define PINID_EMI_DQM0		STMP3XXX_PINID(3, 18)
+#define PINID_EMI_DQM1		STMP3XXX_PINID(3, 19)
+#define PINID_EMI_CLK		STMP3XXX_PINID(3, 20)
+#define PINID_EMI_CLKN		STMP3XXX_PINID(3, 21)
+
+#endif /* __ASM_ARCH_PINS_H */
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-apbh.h b/arch/arm/mach-stmp37xx/include/mach/regs-apbh.h
new file mode 100644
index 0000000..a323aa9
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-apbh.h
@@ -0,0 +1,97 @@
+/*
+ * stmp37xx: APBH register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef _MACH_REGS_APBH
+#define _MACH_REGS_APBH
+
+#define REGS_APBH_BASE	(STMP3XXX_REGS_BASE + 0x4000)
+
+#define HW_APBH_CTRL0		0x0
+#define BM_APBH_CTRL0_RESET_CHANNEL	0x00FF0000
+#define BP_APBH_CTRL0_RESET_CHANNEL	16
+#define BM_APBH_CTRL0_CLKGATE	0x40000000
+#define BM_APBH_CTRL0_SFTRST	0x80000000
+
+#define HW_APBH_CTRL1		0x10
+#define BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ	0x00000001
+#define BP_APBH_CTRL1_CH0_CMDCMPLT_IRQ	0
+
+#define HW_APBH_DEVSEL		0x20
+
+#define HW_APBH_CH0_NXTCMDAR	(0x50 + 0 * 0x70)
+#define HW_APBH_CH1_NXTCMDAR	(0x50 + 1 * 0x70)
+#define HW_APBH_CH2_NXTCMDAR	(0x50 + 2 * 0x70)
+#define HW_APBH_CH3_NXTCMDAR	(0x50 + 3 * 0x70)
+#define HW_APBH_CH4_NXTCMDAR	(0x50 + 4 * 0x70)
+#define HW_APBH_CH5_NXTCMDAR	(0x50 + 5 * 0x70)
+#define HW_APBH_CH6_NXTCMDAR	(0x50 + 6 * 0x70)
+#define HW_APBH_CH7_NXTCMDAR	(0x50 + 7 * 0x70)
+#define HW_APBH_CH8_NXTCMDAR	(0x50 + 8 * 0x70)
+#define HW_APBH_CH9_NXTCMDAR	(0x50 + 9 * 0x70)
+#define HW_APBH_CH10_NXTCMDAR	(0x50 + 10 * 0x70)
+#define HW_APBH_CH11_NXTCMDAR	(0x50 + 11 * 0x70)
+#define HW_APBH_CH12_NXTCMDAR	(0x50 + 12 * 0x70)
+#define HW_APBH_CH13_NXTCMDAR	(0x50 + 13 * 0x70)
+#define HW_APBH_CH14_NXTCMDAR	(0x50 + 14 * 0x70)
+#define HW_APBH_CH15_NXTCMDAR	(0x50 + 15 * 0x70)
+
+#define HW_APBH_CHn_NXTCMDAR	0x50
+
+#define BM_APBH_CHn_CMD_MODE		0x00000003
+#define BP_APBH_CHn_CMD_MODE		0x00000001
+#define BV_APBH_CHn_CMD_MODE_NOOP		 0
+#define BV_APBH_CHn_CMD_MODE_WRITE		 1
+#define BV_APBH_CHn_CMD_MODE_READ		 2
+#define BV_APBH_CHn_CMD_MODE_SENSE		 3
+#define BM_APBH_CHn_CMD_CHAIN		0x00000004
+#define BM_APBH_CHn_CMD_IRQONCMPLT	0x00000008
+#define BM_APBH_CHn_CMD_NANDLOCK	0x00000010
+#define BM_APBH_CHn_CMD_NANDWAIT4READY	0x00000020
+#define BM_APBH_CHn_CMD_SEMAPHORE	0x00000040
+#define BM_APBH_CHn_CMD_WAIT4ENDCMD	0x00000080
+#define BM_APBH_CHn_CMD_CMDWORDS	0x0000F000
+#define BP_APBH_CHn_CMD_CMDWORDS	12
+#define BM_APBH_CHn_CMD_XFER_COUNT	0xFFFF0000
+#define BP_APBH_CHn_CMD_XFER_COUNT	16
+
+#define HW_APBH_CH0_SEMA	(0x80 + 0 * 0x70)
+#define HW_APBH_CH1_SEMA	(0x80 + 1 * 0x70)
+#define HW_APBH_CH2_SEMA	(0x80 + 2 * 0x70)
+#define HW_APBH_CH3_SEMA	(0x80 + 3 * 0x70)
+#define HW_APBH_CH4_SEMA	(0x80 + 4 * 0x70)
+#define HW_APBH_CH5_SEMA	(0x80 + 5 * 0x70)
+#define HW_APBH_CH6_SEMA	(0x80 + 6 * 0x70)
+#define HW_APBH_CH7_SEMA	(0x80 + 7 * 0x70)
+#define HW_APBH_CH8_SEMA	(0x80 + 8 * 0x70)
+#define HW_APBH_CH9_SEMA	(0x80 + 9 * 0x70)
+#define HW_APBH_CH10_SEMA	(0x80 + 10 * 0x70)
+#define HW_APBH_CH11_SEMA	(0x80 + 11 * 0x70)
+#define HW_APBH_CH12_SEMA	(0x80 + 12 * 0x70)
+#define HW_APBH_CH13_SEMA	(0x80 + 13 * 0x70)
+#define HW_APBH_CH14_SEMA	(0x80 + 14 * 0x70)
+#define HW_APBH_CH15_SEMA	(0x80 + 15 * 0x70)
+
+#define HW_APBH_CHn_SEMA	0x80
+#define BM_APBH_CHn_SEMA_INCREMENT_SEMA	0x000000FF
+#define BP_APBH_CHn_SEMA_INCREMENT_SEMA	0
+#define BM_APBH_CHn_SEMA_PHORE	0x00FF0000
+#define BP_APBH_CHn_SEMA_PHORE	16
+
+#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-apbx.h b/arch/arm/mach-stmp37xx/include/mach/regs-apbx.h
new file mode 100644
index 0000000..6d080cd
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-apbx.h
@@ -0,0 +1,113 @@
+/*
+ * stmp37xx: APBX register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef _MACH_REGS_APBX
+#define _MACH_REGS_APBX
+
+#define REGS_APBX_BASE	(STMP3XXX_REGS_BASE + 0x24000)
+
+#define HW_APBX_CTRL0		0x0
+#define BM_APBX_CTRL0_RESET_CHANNEL	0x00FF0000
+#define BP_APBX_CTRL0_RESET_CHANNEL	16
+#define BM_APBX_CTRL0_CLKGATE	0x40000000
+#define BM_APBX_CTRL0_SFTRST	0x80000000
+
+#define HW_APBX_CTRL1		0x10
+
+#define HW_APBX_DEVSEL		0x20
+
+#define HW_APBX_CH0_NXTCMDAR	(0x50 + 0 * 0x70)
+#define HW_APBX_CH1_NXTCMDAR	(0x50 + 1 * 0x70)
+#define HW_APBX_CH2_NXTCMDAR	(0x50 + 2 * 0x70)
+#define HW_APBX_CH3_NXTCMDAR	(0x50 + 3 * 0x70)
+#define HW_APBX_CH4_NXTCMDAR	(0x50 + 4 * 0x70)
+#define HW_APBX_CH5_NXTCMDAR	(0x50 + 5 * 0x70)
+#define HW_APBX_CH6_NXTCMDAR	(0x50 + 6 * 0x70)
+#define HW_APBX_CH7_NXTCMDAR	(0x50 + 7 * 0x70)
+#define HW_APBX_CH8_NXTCMDAR	(0x50 + 8 * 0x70)
+#define HW_APBX_CH9_NXTCMDAR	(0x50 + 9 * 0x70)
+#define HW_APBX_CH10_NXTCMDAR	(0x50 + 10 * 0x70)
+#define HW_APBX_CH11_NXTCMDAR	(0x50 + 11 * 0x70)
+#define HW_APBX_CH12_NXTCMDAR	(0x50 + 12 * 0x70)
+#define HW_APBX_CH13_NXTCMDAR	(0x50 + 13 * 0x70)
+#define HW_APBX_CH14_NXTCMDAR	(0x50 + 14 * 0x70)
+#define HW_APBX_CH15_NXTCMDAR	(0x50 + 15 * 0x70)
+
+#define HW_APBX_CHn_NXTCMDAR	0x50
+#define BM_APBX_CHn_CMD_MODE		0x00000003
+#define BP_APBX_CHn_CMD_MODE		0x00000001
+#define BV_APBX_CHn_CMD_MODE_NOOP		 0
+#define BV_APBX_CHn_CMD_MODE_WRITE		 1
+#define BV_APBX_CHn_CMD_MODE_READ		 2
+#define BV_APBX_CHn_CMD_MODE_SENSE		 3
+#define BM_APBX_CHn_CMD_COMMAND	0x00000003
+#define BP_APBX_CHn_CMD_COMMAND	0
+#define BM_APBX_CHn_CMD_CHAIN	0x00000004
+#define BM_APBX_CHn_CMD_IRQONCMPLT	0x00000008
+#define BM_APBX_CHn_CMD_SEMAPHORE	0x00000040
+#define BM_APBX_CHn_CMD_WAIT4ENDCMD	0x00000080
+#define BM_APBX_CHn_CMD_CMDWORDS	0x0000F000
+#define BP_APBX_CHn_CMD_CMDWORDS	12
+#define BM_APBX_CHn_CMD_XFER_COUNT	0xFFFF0000
+#define BP_APBX_CHn_CMD_XFER_COUNT	16
+
+#define HW_APBX_CH0_BAR		(0x70 + 0 * 0x70)
+#define HW_APBX_CH1_BAR		(0x70 + 1 * 0x70)
+#define HW_APBX_CH2_BAR		(0x70 + 2 * 0x70)
+#define HW_APBX_CH3_BAR		(0x70 + 3 * 0x70)
+#define HW_APBX_CH4_BAR		(0x70 + 4 * 0x70)
+#define HW_APBX_CH5_BAR		(0x70 + 5 * 0x70)
+#define HW_APBX_CH6_BAR		(0x70 + 6 * 0x70)
+#define HW_APBX_CH7_BAR		(0x70 + 7 * 0x70)
+#define HW_APBX_CH8_BAR		(0x70 + 8 * 0x70)
+#define HW_APBX_CH9_BAR		(0x70 + 9 * 0x70)
+#define HW_APBX_CH10_BAR		(0x70 + 10 * 0x70)
+#define HW_APBX_CH11_BAR		(0x70 + 11 * 0x70)
+#define HW_APBX_CH12_BAR		(0x70 + 12 * 0x70)
+#define HW_APBX_CH13_BAR		(0x70 + 13 * 0x70)
+#define HW_APBX_CH14_BAR		(0x70 + 14 * 0x70)
+#define HW_APBX_CH15_BAR		(0x70 + 15 * 0x70)
+
+#define HW_APBX_CHn_BAR		0x70
+
+#define HW_APBX_CH0_SEMA	(0x80 + 0 * 0x70)
+#define HW_APBX_CH1_SEMA	(0x80 + 1 * 0x70)
+#define HW_APBX_CH2_SEMA	(0x80 + 2 * 0x70)
+#define HW_APBX_CH3_SEMA	(0x80 + 3 * 0x70)
+#define HW_APBX_CH4_SEMA	(0x80 + 4 * 0x70)
+#define HW_APBX_CH5_SEMA	(0x80 + 5 * 0x70)
+#define HW_APBX_CH6_SEMA	(0x80 + 6 * 0x70)
+#define HW_APBX_CH7_SEMA	(0x80 + 7 * 0x70)
+#define HW_APBX_CH8_SEMA	(0x80 + 8 * 0x70)
+#define HW_APBX_CH9_SEMA	(0x80 + 9 * 0x70)
+#define HW_APBX_CH10_SEMA	(0x80 + 10 * 0x70)
+#define HW_APBX_CH11_SEMA	(0x80 + 11 * 0x70)
+#define HW_APBX_CH12_SEMA	(0x80 + 12 * 0x70)
+#define HW_APBX_CH13_SEMA	(0x80 + 13 * 0x70)
+#define HW_APBX_CH14_SEMA	(0x80 + 14 * 0x70)
+#define HW_APBX_CH15_SEMA	(0x80 + 15 * 0x70)
+
+#define HW_APBX_CHn_SEMA	0x80
+#define BM_APBX_CHn_SEMA_INCREMENT_SEMA	0x000000FF
+#define BP_APBX_CHn_SEMA_INCREMENT_SEMA	0
+#define BM_APBX_CHn_SEMA_PHORE	0x00FF0000
+#define BP_APBX_CHn_SEMA_PHORE	16
+
+#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-audioin.h b/arch/arm/mach-stmp37xx/include/mach/regs-audioin.h
new file mode 100644
index 0000000..3b511f9
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-audioin.h
@@ -0,0 +1,61 @@
+/*
+ * stmp37xx: AUDIOIN register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_AUDIOIN_BASE	(STMP3XXX_REGS_BASE + 0x4C000)
+
+#define HW_AUDIOIN_CTRL		0x0
+#define BM_AUDIOIN_CTRL_RUN	0x00000001
+#define BP_AUDIOIN_CTRL_RUN	0
+#define BM_AUDIOIN_CTRL_FIFO_ERROR_IRQ_EN	0x00000002
+#define BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ	0x00000004
+#define BM_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ	0x00000008
+#define BM_AUDIOIN_CTRL_WORD_LENGTH	0x00000020
+#define BM_AUDIOIN_CTRL_CLKGATE	0x40000000
+#define BM_AUDIOIN_CTRL_SFTRST	0x80000000
+
+#define HW_AUDIOIN_STAT		0x10
+
+#define HW_AUDIOIN_ADCSRR	0x20
+
+#define HW_AUDIOIN_ADCVOLUME	0x30
+#define BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT	0x000000FF
+#define BP_AUDIOIN_ADCVOLUME_VOLUME_RIGHT	0
+#define BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT	0x00FF0000
+#define BP_AUDIOIN_ADCVOLUME_VOLUME_LEFT	16
+
+#define HW_AUDIOIN_ADCDEBUG	0x40
+
+#define HW_AUDIOIN_ADCVOL	0x50
+#define BM_AUDIOIN_ADCVOL_GAIN_RIGHT	0x0000000F
+#define BP_AUDIOIN_ADCVOL_GAIN_RIGHT	0
+#define BM_AUDIOIN_ADCVOL_SELECT_RIGHT	0x00000030
+#define BP_AUDIOIN_ADCVOL_SELECT_RIGHT	4
+#define BM_AUDIOIN_ADCVOL_GAIN_LEFT	0x00000F00
+#define BP_AUDIOIN_ADCVOL_GAIN_LEFT	8
+#define BM_AUDIOIN_ADCVOL_SELECT_LEFT	0x00003000
+#define BP_AUDIOIN_ADCVOL_SELECT_LEFT	12
+#define BM_AUDIOIN_ADCVOL_MUTE	0x01000000
+
+#define HW_AUDIOIN_MICLINE	0x60
+
+#define HW_AUDIOIN_ANACLKCTRL	0x70
+#define BM_AUDIOIN_ANACLKCTRL_CLKGATE	0x80000000
+
+#define HW_AUDIOIN_DATA		0x80
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-audioout.h b/arch/arm/mach-stmp37xx/include/mach/regs-audioout.h
new file mode 100644
index 0000000..ca1942b
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-audioout.h
@@ -0,0 +1,111 @@
+/*
+ * stmp37xx: AUDIOOUT register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_AUDIOOUT_BASE	(STMP3XXX_REGS_BASE + 0x48000)
+
+#define HW_AUDIOOUT_CTRL	0x0
+#define BM_AUDIOOUT_CTRL_RUN	0x00000001
+#define BP_AUDIOOUT_CTRL_RUN	0
+#define BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN	0x00000002
+#define BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ	0x00000004
+#define BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ	0x00000008
+#define BM_AUDIOOUT_CTRL_WORD_LENGTH	0x00000040
+#define BM_AUDIOOUT_CTRL_CLKGATE	0x40000000
+#define BM_AUDIOOUT_CTRL_SFTRST	0x80000000
+
+#define HW_AUDIOOUT_STAT	0x10
+
+#define HW_AUDIOOUT_DACSRR	0x20
+#define BM_AUDIOOUT_DACSRR_SRC_FRAC	0x00001FFF
+#define BP_AUDIOOUT_DACSRR_SRC_FRAC	0
+#define BM_AUDIOOUT_DACSRR_SRC_INT	0x001F0000
+#define BP_AUDIOOUT_DACSRR_SRC_INT	16
+#define BM_AUDIOOUT_DACSRR_SRC_HOLD	0x07000000
+#define BP_AUDIOOUT_DACSRR_SRC_HOLD	24
+#define BM_AUDIOOUT_DACSRR_BASEMULT	0x70000000
+#define BP_AUDIOOUT_DACSRR_BASEMULT	28
+
+#define HW_AUDIOOUT_DACVOLUME	0x30
+#define BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT	0x00000100
+#define BM_AUDIOOUT_DACVOLUME_MUTE_LEFT	0x01000000
+#define BM_AUDIOOUT_DACVOLUME_EN_ZCD	0x02000000
+
+#define HW_AUDIOOUT_DACDEBUG	0x40
+
+#define HW_AUDIOOUT_HPVOL	0x50
+#define BM_AUDIOOUT_HPVOL_MUTE	0x01000000
+#define BM_AUDIOOUT_HPVOL_EN_MSTR_ZCD	0x02000000
+
+#define HW_AUDIOOUT_PWRDN	0x70
+#define BM_AUDIOOUT_PWRDN_HEADPHONE	0x00000001
+#define BP_AUDIOOUT_PWRDN_HEADPHONE	0
+#define BM_AUDIOOUT_PWRDN_CAPLESS	0x00000010
+#define BM_AUDIOOUT_PWRDN_ADC	0x00000100
+#define BM_AUDIOOUT_PWRDN_DAC	0x00001000
+#define BM_AUDIOOUT_PWRDN_RIGHT_ADC	0x00010000
+#define BM_AUDIOOUT_PWRDN_LINEOUT	0x01000000
+
+#define HW_AUDIOOUT_REFCTRL	0x80
+#define BM_AUDIOOUT_REFCTRL_VAG_VAL	0x000000F0
+#define BP_AUDIOOUT_REFCTRL_VAG_VAL	4
+#define BM_AUDIOOUT_REFCTRL_ADC_REFVAL	0x00000F00
+#define BP_AUDIOOUT_REFCTRL_ADC_REFVAL	8
+#define BM_AUDIOOUT_REFCTRL_ADJ_VAG	0x00001000
+#define BM_AUDIOOUT_REFCTRL_ADJ_ADC	0x00002000
+#define BM_AUDIOOUT_REFCTRL_BIAS_CTRL	0x00030000
+#define BP_AUDIOOUT_REFCTRL_BIAS_CTRL	16
+#define BM_AUDIOOUT_REFCTRL_LOW_PWR	0x00080000
+#define BM_AUDIOOUT_REFCTRL_VBG_ADJ	0x00700000
+#define BP_AUDIOOUT_REFCTRL_VBG_ADJ	20
+#define BM_AUDIOOUT_REFCTRL_XTAL_BGR_BIAS	0x01000000
+#define BM_AUDIOOUT_REFCTRL_RAISE_REF	0x02000000
+
+#define HW_AUDIOOUT_ANACTRL	0x90
+#define BM_AUDIOOUT_ANACTRL_HP_CLASSAB	0x00000010
+#define BM_AUDIOOUT_ANACTRL_HP_HOLD_GND	0x00000020
+
+#define HW_AUDIOOUT_TEST	0xA0
+#define BM_AUDIOOUT_TEST_HP_I1_ADJ	0x00C00000
+#define BP_AUDIOOUT_TEST_HP_I1_ADJ	22
+
+#define HW_AUDIOOUT_BISTCTRL	0xB0
+
+#define HW_AUDIOOUT_BISTSTAT0	0xC0
+
+#define HW_AUDIOOUT_BISTSTAT1	0xD0
+
+#define HW_AUDIOOUT_ANACLKCTRL	0xE0
+#define BM_AUDIOOUT_ANACLKCTRL_CLKGATE	0x80000000
+
+#define HW_AUDIOOUT_DATA	0xF0
+
+#define HW_AUDIOOUT_LINEOUTCTRL	0x100
+#define BM_AUDIOOUT_LINEOUTCTRL_VOL_RIGHT	0x0000001F
+#define BP_AUDIOOUT_LINEOUTCTRL_VOL_RIGHT	0
+#define BM_AUDIOOUT_LINEOUTCTRL_VOL_LEFT	0x00001F00
+#define BP_AUDIOOUT_LINEOUTCTRL_VOL_LEFT	8
+#define BM_AUDIOOUT_LINEOUTCTRL_CHARGE_CAP	0x00007000
+#define BP_AUDIOOUT_LINEOUTCTRL_CHARGE_CAP	12
+#define BM_AUDIOOUT_LINEOUTCTRL_VAG_CTRL	0x00F00000
+#define BP_AUDIOOUT_LINEOUTCTRL_VAG_CTRL	20
+#define BM_AUDIOOUT_LINEOUTCTRL_MUTE	0x01000000
+#define BM_AUDIOOUT_LINEOUTCTRL_EN_ZCD	0x02000000
+
+#define HW_AUDIOOUT_VERSION	0x200
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-clkctrl.h b/arch/arm/mach-stmp37xx/include/mach/regs-clkctrl.h
new file mode 100644
index 0000000..47f5c92
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-clkctrl.h
@@ -0,0 +1,72 @@
+/*
+ * stmp37xx: CLKCTRL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef _MACH_REGS_CLKCTRL
+#define _MACH_REGS_CLKCTRL
+
+#define REGS_CLKCTRL_BASE	(STMP3XXX_REGS_BASE + 0x40000)
+
+#define HW_CLKCTRL_PLLCTRL0	0x0
+#define BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS	0x00040000
+
+#define HW_CLKCTRL_CPU		0x20
+#define BM_CLKCTRL_CPU_DIV_CPU	0x0000003F
+#define BP_CLKCTRL_CPU_DIV_CPU	0
+
+#define HW_CLKCTRL_HBUS		0x30
+#define BM_CLKCTRL_HBUS_DIV	0x0000001F
+#define BP_CLKCTRL_HBUS_DIV	0
+
+#define HW_CLKCTRL_XBUS		0x40
+
+#define HW_CLKCTRL_XTAL		0x50
+
+#define HW_CLKCTRL_PIX		0x60
+#define BM_CLKCTRL_PIX_DIV	0x00007FFF
+#define BP_CLKCTRL_PIX_DIV	0
+#define BM_CLKCTRL_PIX_CLKGATE	0x80000000
+
+#define HW_CLKCTRL_SSP		0x70
+
+#define HW_CLKCTRL_GPMI		0x80
+
+#define HW_CLKCTRL_SPDIF	0x90
+
+#define HW_CLKCTRL_EMI		0xA0
+
+#define HW_CLKCTRL_IR		0xB0
+
+#define HW_CLKCTRL_SAIF		0xC0
+
+#define HW_CLKCTRL_FRAC		0xD0
+#define BM_CLKCTRL_FRAC_EMIFRAC	0x00003F00
+#define BP_CLKCTRL_FRAC_EMIFRAC	8
+#define BM_CLKCTRL_FRAC_PIXFRAC	0x003F0000
+#define BP_CLKCTRL_FRAC_PIXFRAC	16
+#define BM_CLKCTRL_FRAC_CLKGATEPIX	0x00800000
+
+#define HW_CLKCTRL_CLKSEQ	0xE0
+#define BM_CLKCTRL_CLKSEQ_BYPASS_PIX	0x00000002
+
+#define HW_CLKCTRL_RESET	0xF0
+#define BM_CLKCTRL_RESET_DIG	0x00000001
+#define BP_CLKCTRL_RESET_DIG	0
+
+#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-digctl.h b/arch/arm/mach-stmp37xx/include/mach/regs-digctl.h
new file mode 100644
index 0000000..ba1bbe2
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-digctl.h
@@ -0,0 +1,24 @@
+/*
+ * stmp37xx: DIGCTL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_DIGCTL_BASE	(STMP3XXX_REGS_BASE + 0x1C000)
+
+#define HW_DIGCTL_CTRL		0x0
+#define BM_DIGCTL_CTRL_USB_CLKGATE	0x00000004
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-ecc8.h b/arch/arm/mach-stmp37xx/include/mach/regs-ecc8.h
new file mode 100644
index 0000000..3b6d990
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-ecc8.h
@@ -0,0 +1,37 @@
+/*
+ * stmp37xx: ECC8 register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_ECC8_BASE	(STMP3XXX_REGS_BASE + 0x8000)
+
+#define HW_ECC8_CTRL		0x0
+#define BM_ECC8_CTRL_COMPLETE_IRQ	0x00000001
+#define BP_ECC8_CTRL_COMPLETE_IRQ	0
+#define BM_ECC8_CTRL_COMPLETE_IRQ_EN	0x00000100
+#define BM_ECC8_CTRL_AHBM_SFTRST	0x20000000
+
+#define HW_ECC8_STATUS0		0x10
+#define BM_ECC8_STATUS0_UNCORRECTABLE	0x00000004
+#define BM_ECC8_STATUS0_CORRECTED	0x00000008
+#define BM_ECC8_STATUS0_STATUS_AUX	0x00000F00
+#define BP_ECC8_STATUS0_STATUS_AUX	8
+#define BM_ECC8_STATUS0_COMPLETED_CE	0x000F0000
+#define BP_ECC8_STATUS0_COMPLETED_CE	16
+
+#define HW_ECC8_STATUS1		0x20
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-gpmi.h b/arch/arm/mach-stmp37xx/include/mach/regs-gpmi.h
new file mode 100644
index 0000000..f2b304f
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-gpmi.h
@@ -0,0 +1,63 @@
+/*
+ * stmp37xx: GPMI register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_GPMI_BASE	(STMP3XXX_REGS_BASE + 0xC000)
+#define REGS_GPMI_PHYS	0x8000C000
+#define REGS_GPMI_SIZE	0x2000
+
+#define HW_GPMI_CTRL0		0x0
+#define BM_GPMI_CTRL0_XFER_COUNT	0x0000FFFF
+#define BP_GPMI_CTRL0_XFER_COUNT	0
+#define BM_GPMI_CTRL0_CS	0x00300000
+#define BP_GPMI_CTRL0_CS	20
+#define BM_GPMI_CTRL0_LOCK_CS	0x00400000
+#define BM_GPMI_CTRL0_WORD_LENGTH	0x00800000
+#define BM_GPMI_CTRL0_COMMAND_MODE	0x03000000
+#define BP_GPMI_CTRL0_COMMAND_MODE	24
+#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE	    0x0
+#define BV_GPMI_CTRL0_COMMAND_MODE__READ	     0x1
+#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE 0x2
+#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY   0x3
+#define BM_GPMI_CTRL0_RUN	0x20000000
+#define BM_GPMI_CTRL0_CLKGATE	0x40000000
+#define BM_GPMI_CTRL0_SFTRST	0x80000000
+#define BM_GPMI_ECCCTRL_ENABLE_ECC	0x00001000
+#define BM_GPMI_ECCCTRL_ECC_CMD	0x00006000
+#define BP_GPMI_ECCCTRL_ECC_CMD	13
+
+#define HW_GPMI_CTRL1		0x60
+#define BM_GPMI_CTRL1_GPMI_MODE	0x00000003
+#define BP_GPMI_CTRL1_GPMI_MODE	0
+#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY	0x00000004
+#define BM_GPMI_CTRL1_DEV_RESET	0x00000008
+#define BM_GPMI_CTRL1_TIMEOUT_IRQ	0x00000200
+#define BM_GPMI_CTRL1_DEV_IRQ	0x00000400
+#define BM_GPMI_CTRL1_DSAMPLE_TIME	0x00007000
+#define BP_GPMI_CTRL1_DSAMPLE_TIME	12
+
+#define HW_GPMI_TIMING0		0x70
+#define BM_GPMI_TIMING0_DATA_SETUP	0x000000FF
+#define BP_GPMI_TIMING0_DATA_SETUP	0
+#define BM_GPMI_TIMING0_DATA_HOLD	0x0000FF00
+#define BP_GPMI_TIMING0_DATA_HOLD	8
+
+#define HW_GPMI_TIMING1		0x80
+#define BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT	0xFFFF0000
+#define BP_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT	16
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-i2c.h b/arch/arm/mach-stmp37xx/include/mach/regs-i2c.h
new file mode 100644
index 0000000..35882a9
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-i2c.h
@@ -0,0 +1,55 @@
+/*
+ * stmp37xx: I2C register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_I2C_BASE	(STMP3XXX_REGS_BASE + 0x58000)
+#define REGS_I2C_PHYS	0x80058000
+#define REGS_I2C_SIZE	0x2000
+
+#define HW_I2C_CTRL0		0x0
+#define BM_I2C_CTRL0_XFER_COUNT	0x0000FFFF
+#define BP_I2C_CTRL0_XFER_COUNT	0
+#define BM_I2C_CTRL0_DIRECTION	0x00010000
+#define BM_I2C_CTRL0_MASTER_MODE	0x00020000
+#define BM_I2C_CTRL0_PRE_SEND_START	0x00080000
+#define BM_I2C_CTRL0_POST_SEND_STOP	0x00100000
+#define BM_I2C_CTRL0_RETAIN_CLOCK	0x00200000
+#define BM_I2C_CTRL0_SEND_NAK_ON_LAST	0x02000000
+#define BM_I2C_CTRL0_CLKGATE	0x40000000
+#define BM_I2C_CTRL0_SFTRST	0x80000000
+
+#define HW_I2C_TIMING0		0x10
+
+#define HW_I2C_TIMING1		0x20
+
+#define HW_I2C_TIMING2		0x30
+
+#define HW_I2C_CTRL1		0x40
+#define BM_I2C_CTRL1_SLAVE_IRQ	0x00000001
+#define BP_I2C_CTRL1_SLAVE_IRQ	0
+#define BM_I2C_CTRL1_SLAVE_STOP_IRQ	0x00000002
+#define BM_I2C_CTRL1_MASTER_LOSS_IRQ	0x00000004
+#define BM_I2C_CTRL1_EARLY_TERM_IRQ	0x00000008
+#define BM_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ	0x00000010
+#define BM_I2C_CTRL1_NO_SLAVE_ACK_IRQ	0x00000020
+#define BM_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ	0x00000040
+#define BM_I2C_CTRL1_BUS_FREE_IRQ	0x00000080
+#define BM_I2C_CTRL1_CLR_GOT_A_NAK	0x10000000
+
+#define HW_I2C_VERSION		0x90
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-icoll.h b/arch/arm/mach-stmp37xx/include/mach/regs-icoll.h
new file mode 100644
index 0000000..3b7c922
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-icoll.h
@@ -0,0 +1,43 @@
+/*
+ * stmp37xx: ICOLL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef _MACH_REGS_ICOLL
+#define _MACH_REGS_ICOLL
+
+#define REGS_ICOLL_BASE	(STMP3XXX_REGS_BASE + 0x0)
+
+#define HW_ICOLL_VECTOR		0x0
+
+#define HW_ICOLL_LEVELACK	0x10
+
+#define HW_ICOLL_CTRL		0x20
+#define BM_ICOLL_CTRL_CLKGATE	0x40000000
+#define BM_ICOLL_CTRL_SFTRST	0x80000000
+
+#define HW_ICOLL_STAT		0x30
+
+#define HW_ICOLL_PRIORITY0	(0x60 + 0 * 0x10)
+#define HW_ICOLL_PRIORITY1	(0x60 + 1 * 0x10)
+#define HW_ICOLL_PRIORITY2	(0x60 + 2 * 0x10)
+#define HW_ICOLL_PRIORITY3	(0x60 + 3 * 0x10)
+
+#define HW_ICOLL_PRIORITYn	0x60
+
+#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-lcdif.h b/arch/arm/mach-stmp37xx/include/mach/regs-lcdif.h
new file mode 100644
index 0000000..72514e8
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-lcdif.h
@@ -0,0 +1,89 @@
+/*
+ * stmp37xx: LCDIF register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_LCDIF_BASE	(STMP3XXX_REGS_BASE + 0x30000)
+#define REGS_LCDIF_PHYS	0x80030000
+#define REGS_LCDIF_SIZE	0x2000
+
+#define HW_LCDIF_CTRL		0x0
+#define BM_LCDIF_CTRL_COUNT	0x0000FFFF
+#define BP_LCDIF_CTRL_COUNT	0
+#define BM_LCDIF_CTRL_RUN	0x00010000
+#define BM_LCDIF_CTRL_WORD_LENGTH	0x00020000
+#define BM_LCDIF_CTRL_DATA_SELECT	0x00040000
+#define BM_LCDIF_CTRL_DOTCLK_MODE	0x00080000
+#define BM_LCDIF_CTRL_VSYNC_MODE	0x00100000
+#define BM_LCDIF_CTRL_DATA_SWIZZLE	0x00600000
+#define BP_LCDIF_CTRL_DATA_SWIZZLE	21
+#define BM_LCDIF_CTRL_BYPASS_COUNT	0x00800000
+#define BM_LCDIF_CTRL_SHIFT_NUM_BITS	0x06000000
+#define BP_LCDIF_CTRL_SHIFT_NUM_BITS	25
+#define BM_LCDIF_CTRL_DATA_SHIFT_DIR	0x08000000
+#define BM_LCDIF_CTRL_WAIT_FOR_VSYNC_EDGE	0x10000000
+#define BM_LCDIF_CTRL_CLKGATE	0x40000000
+#define BM_LCDIF_CTRL_SFTRST	0x80000000
+
+#define HW_LCDIF_CTRL1		0x10
+#define BM_LCDIF_CTRL1_RESET	0x00000001
+#define BP_LCDIF_CTRL1_RESET	0
+#define BM_LCDIF_CTRL1_MODE86	0x00000002
+#define BM_LCDIF_CTRL1_BUSY_ENABLE	0x00000004
+#define BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ	0x00000100
+#define BM_LCDIF_CTRL1_CUR_FRAME_DONE_IRQ	0x00000200
+#define BM_LCDIF_CTRL1_UNDERFLOW_IRQ	0x00000400
+#define BM_LCDIF_CTRL1_OVERFLOW_IRQ	0x00000800
+#define BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ_EN	0x00001000
+#define BM_LCDIF_CTRL1_BYTE_PACKING_FORMAT	0x000F0000
+#define BP_LCDIF_CTRL1_BYTE_PACKING_FORMAT	16
+
+#define HW_LCDIF_TIMING		0x20
+
+#define HW_LCDIF_VDCTRL0	0x30
+#define BM_LCDIF_VDCTRL0_VALID_DATA_CNT	0x000003FF
+#define BP_LCDIF_VDCTRL0_VALID_DATA_CNT	0
+#define BM_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT	0x00100000
+#define BM_LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT	0x00200000
+#define BM_LCDIF_VDCTRL0_ENABLE_POL	0x01000000
+#define BM_LCDIF_VDCTRL0_DOTCLK_POL	0x02000000
+#define BM_LCDIF_VDCTRL0_HSYNC_POL	0x04000000
+#define BM_LCDIF_VDCTRL0_VSYNC_POL	0x08000000
+#define BM_LCDIF_VDCTRL0_ENABLE_PRESENT	0x10000000
+#define BM_LCDIF_VDCTRL0_VSYNC_OEB	0x20000000
+
+#define HW_LCDIF_VDCTRL1	0x40
+#define BM_LCDIF_VDCTRL1_VSYNC_PERIOD	0x000FFFFF
+#define BP_LCDIF_VDCTRL1_VSYNC_PERIOD	0
+#define BM_LCDIF_VDCTRL1_VSYNC_PULSE_WIDTH	0xFFF00000
+#define BP_LCDIF_VDCTRL1_VSYNC_PULSE_WIDTH	20
+
+#define HW_LCDIF_VDCTRL2	0x50
+#define BM_LCDIF_VDCTRL2_VALID_DATA_CNT	0x000007FF
+#define BP_LCDIF_VDCTRL2_VALID_DATA_CNT	0
+#define BM_LCDIF_VDCTRL2_HSYNC_PERIOD	0x007FF800
+#define BP_LCDIF_VDCTRL2_HSYNC_PERIOD	11
+#define BM_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH	0xFF800000
+#define BP_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH	23
+
+#define HW_LCDIF_VDCTRL3	0x60
+#define BM_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT	0x000001FF
+#define BP_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT	0
+#define BM_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT	0x00FFF000
+#define BP_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT	12
+#define BM_LCDIF_VDCTRL3_SYNC_SIGNALS_ON	0x01000000
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-lradc.h b/arch/arm/mach-stmp37xx/include/mach/regs-lradc.h
new file mode 100644
index 0000000..cc7b470
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-lradc.h
@@ -0,0 +1,97 @@
+/*
+ * stmp37xx: LRADC register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_LRADC_BASE	(STMP3XXX_REGS_BASE + 0x50000)
+
+#define HW_LRADC_CTRL0		0x0
+#define BM_LRADC_CTRL0_SCHEDULE	0x000000FF
+#define BP_LRADC_CTRL0_SCHEDULE	0
+#define BM_LRADC_CTRL0_XPLUS_ENABLE	0x00010000
+#define BM_LRADC_CTRL0_YPLUS_ENABLE	0x00020000
+#define BM_LRADC_CTRL0_XMINUS_ENABLE	0x00040000
+#define BM_LRADC_CTRL0_YMINUS_ENABLE	0x00080000
+#define BM_LRADC_CTRL0_TOUCH_DETECT_ENABLE	0x00100000
+#define BM_LRADC_CTRL0_ONCHIP_GROUNDREF	0x00200000
+#define BM_LRADC_CTRL0_CLKGATE	0x40000000
+#define BM_LRADC_CTRL0_SFTRST	0x80000000
+
+#define HW_LRADC_CTRL1		0x10
+#define BM_LRADC_CTRL1_LRADC0_IRQ	0x00000001
+#define BP_LRADC_CTRL1_LRADC0_IRQ	0
+#define BM_LRADC_CTRL1_LRADC5_IRQ	0x00000020
+#define BM_LRADC_CTRL1_LRADC6_IRQ	0x00000040
+#define BM_LRADC_CTRL1_TOUCH_DETECT_IRQ	0x00000100
+#define BM_LRADC_CTRL1_LRADC0_IRQ_EN	0x00010000
+#define BM_LRADC_CTRL1_LRADC5_IRQ_EN	0x00200000
+#define BM_LRADC_CTRL1_TOUCH_DETECT_IRQ_EN	0x01000000
+
+#define HW_LRADC_CTRL2		0x20
+#define BM_LRADC_CTRL2_BL_BRIGHTNESS	0x001F0000
+#define BP_LRADC_CTRL2_BL_BRIGHTNESS	16
+#define BM_LRADC_CTRL2_BL_MUX_SELECT	0x00200000
+#define BM_LRADC_CTRL2_BL_ENABLE	0x00400000
+#define BM_LRADC_CTRL2_DIVIDE_BY_TWO	0xFF000000
+#define BP_LRADC_CTRL2_DIVIDE_BY_TWO	24
+
+#define HW_LRADC_CTRL3		0x30
+#define BM_LRADC_CTRL3_CYCLE_TIME	0x00000300
+#define BP_LRADC_CTRL3_CYCLE_TIME	8
+
+#define HW_LRADC_STATUS		0x40
+#define BM_LRADC_STATUS_TOUCH_DETECT_RAW	0x00000001
+#define BP_LRADC_STATUS_TOUCH_DETECT_RAW	0
+
+#define HW_LRADC_CH0		(0x50 + 0 * 0x10)
+#define HW_LRADC_CH1		(0x50 + 1 * 0x10)
+#define HW_LRADC_CH2		(0x50 + 2 * 0x10)
+#define HW_LRADC_CH3		(0x50 + 3 * 0x10)
+#define HW_LRADC_CH4		(0x50 + 4 * 0x10)
+#define HW_LRADC_CH5		(0x50 + 5 * 0x10)
+#define HW_LRADC_CH6		(0x50 + 6 * 0x10)
+#define HW_LRADC_CH7		(0x50 + 7 * 0x10)
+
+#define HW_LRADC_CHn		0x50
+#define BM_LRADC_CHn_VALUE	0x0003FFFF
+#define BP_LRADC_CHn_VALUE	0
+#define BM_LRADC_CHn_NUM_SAMPLES	0x1F000000
+#define BP_LRADC_CHn_NUM_SAMPLES	24
+#define BM_LRADC_CHn_ACCUMULATE	0x20000000
+
+#define HW_LRADC_DELAY0		(0xD0 + 0 * 0x10)
+#define HW_LRADC_DELAY1		(0xD0 + 1 * 0x10)
+#define HW_LRADC_DELAY2		(0xD0 + 2 * 0x10)
+#define HW_LRADC_DELAY3		(0xD0 + 3 * 0x10)
+
+#define HW_LRADC_DELAYn		0xD0
+#define BM_LRADC_DELAYn_DELAY	0x000007FF
+#define BP_LRADC_DELAYn_DELAY	0
+#define BM_LRADC_DELAYn_LOOP_COUNT	0x0000F800
+#define BP_LRADC_DELAYn_LOOP_COUNT	11
+#define BM_LRADC_DELAYn_TRIGGER_DELAYS	0x000F0000
+#define BP_LRADC_DELAYn_TRIGGER_DELAYS	16
+#define BM_LRADC_DELAYn_KICK	0x00100000
+#define BM_LRADC_DELAYn_TRIGGER_LRADCS	0xFF000000
+#define BP_LRADC_DELAYn_TRIGGER_LRADCS	24
+
+#define HW_LRADC_CTRL4		0x140
+#define BM_LRADC_CTRL4_LRADC6SELECT	0x0F000000
+#define BP_LRADC_CTRL4_LRADC6SELECT	24
+#define BM_LRADC_CTRL4_LRADC7SELECT	0xF0000000
+#define BP_LRADC_CTRL4_LRADC7SELECT	28
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-pinctrl.h b/arch/arm/mach-stmp37xx/include/mach/regs-pinctrl.h
new file mode 100644
index 0000000..d5efce2
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-pinctrl.h
@@ -0,0 +1,88 @@
+/*
+ * stmp37xx: PINCTRL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef _MACH_REGS_PINCTRL
+#define _MACH_REGS_PINCTRL
+
+#define REGS_PINCTRL_BASE	(STMP3XXX_REGS_BASE + 0x18000)
+
+#define HW_PINCTRL_MUXSEL0	0x100
+#define HW_PINCTRL_MUXSEL1	0x110
+#define HW_PINCTRL_MUXSEL2	0x120
+#define HW_PINCTRL_MUXSEL3	0x130
+#define HW_PINCTRL_MUXSEL4	0x140
+#define HW_PINCTRL_MUXSEL5	0x150
+#define HW_PINCTRL_MUXSEL6	0x160
+#define HW_PINCTRL_MUXSEL7	0x170
+
+#define HW_PINCTRL_DRIVE0	0x200
+#define HW_PINCTRL_DRIVE1	0x210
+#define HW_PINCTRL_DRIVE2	0x220
+#define HW_PINCTRL_DRIVE3	0x230
+#define HW_PINCTRL_DRIVE4	0x240
+#define HW_PINCTRL_DRIVE5	0x250
+#define HW_PINCTRL_DRIVE6	0x260
+#define HW_PINCTRL_DRIVE7	0x270
+#define HW_PINCTRL_DRIVE8	0x280
+#define HW_PINCTRL_DRIVE9	0x290
+#define HW_PINCTRL_DRIVE10	0x2A0
+#define HW_PINCTRL_DRIVE11	0x2B0
+#define HW_PINCTRL_DRIVE12	0x2C0
+#define HW_PINCTRL_DRIVE13	0x2D0
+#define HW_PINCTRL_DRIVE14	0x2E0
+
+#define HW_PINCTRL_PULL0	0x300
+#define HW_PINCTRL_PULL1	0x310
+#define HW_PINCTRL_PULL2	0x320
+#define HW_PINCTRL_PULL3	0x330
+
+#define HW_PINCTRL_DOUT0	0x400
+#define HW_PINCTRL_DOUT1	0x410
+#define HW_PINCTRL_DOUT2	0x420
+
+#define HW_PINCTRL_DIN0		0x500
+#define HW_PINCTRL_DIN1		0x510
+#define HW_PINCTRL_DIN2		0x520
+
+#define HW_PINCTRL_DOE0		0x600
+#define HW_PINCTRL_DOE1		0x610
+#define HW_PINCTRL_DOE2		0x620
+
+#define HW_PINCTRL_PIN2IRQ0	0x700
+#define HW_PINCTRL_PIN2IRQ1	0x710
+#define HW_PINCTRL_PIN2IRQ2	0x720
+
+#define HW_PINCTRL_IRQEN0	0x800
+#define HW_PINCTRL_IRQEN1	0x810
+#define HW_PINCTRL_IRQEN2	0x820
+
+#define HW_PINCTRL_IRQLEVEL0	0x900
+#define HW_PINCTRL_IRQLEVEL1	0x910
+#define HW_PINCTRL_IRQLEVEL2	0x920
+
+#define HW_PINCTRL_IRQPOL0	0xA00
+#define HW_PINCTRL_IRQPOL1	0xA10
+#define HW_PINCTRL_IRQPOL2	0xA20
+
+#define HW_PINCTRL_IRQSTAT0	0xB00
+#define HW_PINCTRL_IRQSTAT1	0xB10
+#define HW_PINCTRL_IRQSTAT2	0xB20
+
+#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-power.h b/arch/arm/mach-stmp37xx/include/mach/regs-power.h
new file mode 100644
index 0000000..0e733d7
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-power.h
@@ -0,0 +1,56 @@
+/*
+ * stmp37xx: POWER register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef _MACH_REGS_POWER
+#define _MACH_REGS_POWER
+
+#define REGS_POWER_BASE	(STMP3XXX_REGS_BASE + 0x44000)
+
+#define HW_POWER_CTRL		0x0
+#define BM_POWER_CTRL_CLKGATE	0x40000000
+
+#define HW_POWER_5VCTRL		0x10
+
+#define HW_POWER_MINPWR		0x20
+
+#define HW_POWER_CHARGE		0x30
+
+#define HW_POWER_VDDDCTRL	0x40
+
+#define HW_POWER_VDDACTRL	0x50
+
+#define HW_POWER_VDDIOCTRL	0x60
+#define BM_POWER_VDDIOCTRL_TRG	0x0000001F
+#define BP_POWER_VDDIOCTRL_TRG	0
+
+#define HW_POWER_STS		0xB0
+#define BM_POWER_STS_VBUSVALID	0x00000002
+#define BM_POWER_STS_BVALID	0x00000004
+#define BM_POWER_STS_AVALID	0x00000008
+#define BM_POWER_STS_DC_OK	0x00000100
+
+#define HW_POWER_RESET		0xE0
+
+#define HW_POWER_DEBUG		0xF0
+#define BM_POWER_DEBUG_BVALIDPIOLOCK	0x00000002
+#define BM_POWER_DEBUG_AVALIDPIOLOCK	0x00000004
+#define BM_POWER_DEBUG_VBUSVALIDPIOLOCK	0x00000008
+
+#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-pwm.h b/arch/arm/mach-stmp37xx/include/mach/regs-pwm.h
new file mode 100644
index 0000000..15966a1
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-pwm.h
@@ -0,0 +1,51 @@
+/*
+ * stmp37xx: PWM register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_PWM_BASE	(STMP3XXX_REGS_BASE + 0x64000)
+
+#define HW_PWM_CTRL		0x0
+#define BM_PWM_CTRL_PWM2_ENABLE	0x00000004
+#define BM_PWM_CTRL_PWM2_ANA_CTRL_ENABLE	0x00000020
+
+#define HW_PWM_ACTIVE0		(0x10 + 0 * 0x20)
+#define HW_PWM_ACTIVE1		(0x10 + 1 * 0x20)
+#define HW_PWM_ACTIVE2		(0x10 + 2 * 0x20)
+#define HW_PWM_ACTIVE3		(0x10 + 3 * 0x20)
+
+#define HW_PWM_ACTIVEn		0x10
+#define BM_PWM_ACTIVEn_ACTIVE	0x0000FFFF
+#define BP_PWM_ACTIVEn_ACTIVE	0
+#define BM_PWM_ACTIVEn_INACTIVE	0xFFFF0000
+#define BP_PWM_ACTIVEn_INACTIVE	16
+
+#define HW_PWM_PERIOD0		(0x20 + 0 * 0x20)
+#define HW_PWM_PERIOD1		(0x20 + 1 * 0x20)
+#define HW_PWM_PERIOD2		(0x20 + 2 * 0x20)
+#define HW_PWM_PERIOD3		(0x20 + 3 * 0x20)
+
+#define HW_PWM_PERIODn		0x20
+#define BM_PWM_PERIODn_PERIOD	0x0000FFFF
+#define BP_PWM_PERIODn_PERIOD	0
+#define BM_PWM_PERIODn_ACTIVE_STATE	0x00030000
+#define BP_PWM_PERIODn_ACTIVE_STATE	16
+#define BM_PWM_PERIODn_INACTIVE_STATE	0x000C0000
+#define BP_PWM_PERIODn_INACTIVE_STATE	18
+#define BM_PWM_PERIODn_CDIV	0x00700000
+#define BP_PWM_PERIODn_CDIV	20
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-rtc.h b/arch/arm/mach-stmp37xx/include/mach/regs-rtc.h
new file mode 100644
index 0000000..fac40ed
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-rtc.h
@@ -0,0 +1,57 @@
+/*
+ * stmp37xx: RTC register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_RTC_BASE	(STMP3XXX_REGS_BASE + 0x5C000)
+#define REGS_RTC_PHYS   0x8005C000
+#define REGS_RTC_SIZE   0x2000
+
+#define HW_RTC_CTRL		0x0
+#define BM_RTC_CTRL_ALARM_IRQ_EN	0x00000001
+#define BP_RTC_CTRL_ALARM_IRQ_EN	0
+#define BM_RTC_CTRL_ONEMSEC_IRQ_EN	0x00000002
+#define BM_RTC_CTRL_ALARM_IRQ	0x00000004
+#define BM_RTC_CTRL_ONEMSEC_IRQ	0x00000008
+#define BM_RTC_CTRL_WATCHDOGEN	0x00000010
+
+#define HW_RTC_STAT		0x10
+#define BM_RTC_STAT_NEW_REGS	0x0000FF00
+#define BP_RTC_STAT_NEW_REGS	8
+#define BM_RTC_STAT_STALE_REGS	0x00FF0000
+#define BP_RTC_STAT_STALE_REGS	16
+#define BM_RTC_STAT_RTC_PRESENT	0x80000000
+
+#define HW_RTC_SECONDS		0x30
+
+#define HW_RTC_ALARM		0x40
+
+#define HW_RTC_WATCHDOG		0x50
+
+#define HW_RTC_PERSISTENT0	0x60
+#define BM_RTC_PERSISTENT0_ALARM_WAKE_EN	0x00000002
+#define BM_RTC_PERSISTENT0_ALARM_EN	0x00000004
+#define BM_RTC_PERSISTENT0_XTAL24MHZ_PWRUP	0x00000010
+#define BM_RTC_PERSISTENT0_XTAL32KHZ_PWRUP	0x00000020
+#define BM_RTC_PERSISTENT0_ALARM_WAKE	0x00000080
+#define BM_RTC_PERSISTENT0_SPARE_ANALOG	0xFFFC0000
+#define BP_RTC_PERSISTENT0_SPARE_ANALOG	18
+
+#define HW_RTC_PERSISTENT1	0x70
+
+#define HW_RTC_VERSION		0xD0
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-ssp.h b/arch/arm/mach-stmp37xx/include/mach/regs-ssp.h
new file mode 100644
index 0000000..cbde891
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-ssp.h
@@ -0,0 +1,101 @@
+/*
+ * stmp37xx: SSP register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_SSP_BASE	(STMP3XXX_REGS_BASE + 0x10000)
+#define REGS_SSP1_PHYS	0x80010000
+#define REGS_SSP2_PHYS	0x80034000
+#define REGS_SSP_SIZE	0x2000
+
+#define HW_SSP_CTRL0		0x0
+#define BM_SSP_CTRL0_XFER_COUNT	0x0000FFFF
+#define BP_SSP_CTRL0_XFER_COUNT	0
+#define BM_SSP_CTRL0_ENABLE	0x00010000
+#define BM_SSP_CTRL0_GET_RESP	0x00020000
+#define BM_SSP_CTRL0_LONG_RESP	0x00080000
+#define BM_SSP_CTRL0_WAIT_FOR_CMD	0x00100000
+#define BM_SSP_CTRL0_WAIT_FOR_IRQ	0x00200000
+#define BM_SSP_CTRL0_BUS_WIDTH	0x00C00000
+#define BP_SSP_CTRL0_BUS_WIDTH	22
+#define BM_SSP_CTRL0_DATA_XFER	0x01000000
+#define BM_SSP_CTRL0_READ	0x02000000
+#define BM_SSP_CTRL0_IGNORE_CRC	0x04000000
+#define BM_SSP_CTRL0_LOCK_CS	0x08000000
+#define BM_SSP_CTRL0_RUN	0x20000000
+#define BM_SSP_CTRL0_CLKGATE	0x40000000
+#define BM_SSP_CTRL0_SFTRST	0x80000000
+
+#define HW_SSP_CMD0		0x10
+#define BM_SSP_CMD0_CMD		0x000000FF
+#define BP_SSP_CMD0_CMD		0
+#define BM_SSP_CMD0_BLOCK_COUNT	0x0000FF00
+#define BP_SSP_CMD0_BLOCK_COUNT	8
+#define BM_SSP_CMD0_BLOCK_SIZE	0x000F0000
+#define BP_SSP_CMD0_BLOCK_SIZE	16
+#define BM_SSP_CMD0_APPEND_8CYC	0x00100000
+#define BM_SSP_CMD1_CMD_ARG	0xFFFFFFFF
+#define BP_SSP_CMD1_CMD_ARG	0
+
+#define HW_SSP_TIMING		0x50
+#define BM_SSP_TIMING_CLOCK_RATE	0x000000FF
+#define BP_SSP_TIMING_CLOCK_RATE	0
+#define BM_SSP_TIMING_CLOCK_DIVIDE	0x0000FF00
+#define BP_SSP_TIMING_CLOCK_DIVIDE	8
+#define BM_SSP_TIMING_TIMEOUT	0xFFFF0000
+#define BP_SSP_TIMING_TIMEOUT	16
+
+#define HW_SSP_CTRL1		0x60
+#define BM_SSP_CTRL1_SSP_MODE	0x0000000F
+#define BP_SSP_CTRL1_SSP_MODE	0
+#define BM_SSP_CTRL1_WORD_LENGTH	0x000000F0
+#define BP_SSP_CTRL1_WORD_LENGTH	4
+#define BM_SSP_CTRL1_POLARITY	0x00000200
+#define BM_SSP_CTRL1_PHASE	0x00000400
+#define BM_SSP_CTRL1_DMA_ENABLE	0x00002000
+#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ	0x00008000
+#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN	0x00010000
+#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ	0x00020000
+#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ	0x00200000
+#define BM_SSP_CTRL1_DATA_CRC_IRQ_EN	0x00400000
+#define BM_SSP_CTRL1_DATA_CRC_IRQ	0x00800000
+#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN	0x01000000
+#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ	0x02000000
+#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN	0x04000000
+#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ	0x08000000
+#define BM_SSP_CTRL1_RESP_ERR_IRQ_EN	0x10000000
+#define BM_SSP_CTRL1_RESP_ERR_IRQ	0x20000000
+#define BM_SSP_CTRL1_SDIO_IRQ	0x80000000
+
+#define HW_SSP_DATA		0x70
+
+#define HW_SSP_SDRESP0		0x80
+
+#define HW_SSP_SDRESP1		0x90
+
+#define HW_SSP_SDRESP2		0xA0
+
+#define HW_SSP_SDRESP3		0xB0
+
+#define HW_SSP_STATUS		0xC0
+#define BM_SSP_STATUS_FIFO_EMPTY	0x00000020
+#define BM_SSP_STATUS_TIMEOUT	0x00001000
+#define BM_SSP_STATUS_RESP_TIMEOUT	0x00004000
+#define BM_SSP_STATUS_RESP_ERR	0x00008000
+#define BM_SSP_STATUS_RESP_CRC_ERR	0x00010000
+#define BM_SSP_STATUS_CARD_DETECT	0x10000000
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-timrot.h b/arch/arm/mach-stmp37xx/include/mach/regs-timrot.h
new file mode 100644
index 0000000..4af0f6e
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-timrot.h
@@ -0,0 +1,49 @@
+/*
+ * stmp37xx: TIMROT register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef _MACH_REGS_TIMROT
+#define _MACH_REGS_TIMROT
+
+#define REGS_TIMROT_BASE	(STMP3XXX_REGS_BASE + 0x68000)
+
+#define HW_TIMROT_ROTCTRL	0x0
+#define BM_TIMROT_ROTCTRL_CLKGATE	0x40000000
+#define BM_TIMROT_ROTCTRL_SFTRST	0x80000000
+
+#define HW_TIMROT_TIMCTRL0	(0x20 + 0 * 0x20)
+#define HW_TIMROT_TIMCTRL1	(0x20 + 1 * 0x20)
+#define HW_TIMROT_TIMCTRL2	(0x20 + 2 * 0x20)
+
+#define HW_TIMROT_TIMCTRLn	0x20
+#define BM_TIMROT_TIMCTRLn_SELECT	0x0000000F
+#define BP_TIMROT_TIMCTRLn_SELECT	0
+#define BM_TIMROT_TIMCTRLn_PRESCALE	0x00000030
+#define BP_TIMROT_TIMCTRLn_PRESCALE	4
+#define BM_TIMROT_TIMCTRLn_RELOAD	0x00000040
+#define BM_TIMROT_TIMCTRLn_UPDATE	0x00000080
+#define BM_TIMROT_TIMCTRLn_IRQ_EN	0x00004000
+#define BM_TIMROT_TIMCTRLn_IRQ	0x00008000
+
+#define HW_TIMROT_TIMCOUNT0	(0x30 + 0 * 0x20)
+#define HW_TIMROT_TIMCOUNT1	(0x30 + 1 * 0x20)
+#define HW_TIMROT_TIMCOUNT2	(0x30 + 2 * 0x20)
+
+#define HW_TIMROT_TIMCOUNTn	0x30
+#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-uartapp.h b/arch/arm/mach-stmp37xx/include/mach/regs-uartapp.h
new file mode 100644
index 0000000..0594275
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-uartapp.h
@@ -0,0 +1,85 @@
+/*
+ * stmp37xx: UARTAPP register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_UARTAPP_BASE	(STMP3XXX_REGS_BASE + 0x6C000)
+#define REGS_UARTAPP1_PHYS	0x8006C000
+#define REGS_UARTAPP_SIZE	0x2000
+
+#define HW_UARTAPP_CTRL0	0x0
+#define BM_UARTAPP_CTRL0_XFER_COUNT	0x0000FFFF
+#define BP_UARTAPP_CTRL0_XFER_COUNT	0
+#define BM_UARTAPP_CTRL0_RXTIMEOUT	0x07FF0000
+#define BP_UARTAPP_CTRL0_RXTIMEOUT	16
+#define BM_UARTAPP_CTRL0_RXTO_ENABLE	0x08000000
+#define BM_UARTAPP_CTRL0_RUN	0x20000000
+#define BM_UARTAPP_CTRL0_SFTRST	0x80000000
+#define BM_UARTAPP_CTRL1_XFER_COUNT	0x0000FFFF
+#define BP_UARTAPP_CTRL1_XFER_COUNT	0
+#define BM_UARTAPP_CTRL1_RUN	0x10000000
+
+#define HW_UARTAPP_CTRL2	0x20
+#define BM_UARTAPP_CTRL2_UARTEN	0x00000001
+#define BP_UARTAPP_CTRL2_UARTEN	0
+#define BM_UARTAPP_CTRL2_TXE	0x00000100
+#define BM_UARTAPP_CTRL2_RXE	0x00000200
+#define BM_UARTAPP_CTRL2_RTS	0x00000800
+#define BM_UARTAPP_CTRL2_RTSEN	0x00004000
+#define BM_UARTAPP_CTRL2_CTSEN	0x00008000
+#define BM_UARTAPP_CTRL2_RXDMAE	0x01000000
+#define BM_UARTAPP_CTRL2_TXDMAE	0x02000000
+#define BM_UARTAPP_CTRL2_DMAONERR	0x04000000
+
+#define HW_UARTAPP_LINECTRL	0x30
+#define BM_UARTAPP_LINECTRL_BRK	0x00000001
+#define BP_UARTAPP_LINECTRL_BRK	0
+#define BM_UARTAPP_LINECTRL_PEN	0x00000002
+#define BM_UARTAPP_LINECTRL_EPS	0x00000004
+#define BM_UARTAPP_LINECTRL_STP2	0x00000008
+#define BM_UARTAPP_LINECTRL_FEN	0x00000010
+#define BM_UARTAPP_LINECTRL_WLEN	0x00000060
+#define BP_UARTAPP_LINECTRL_WLEN	5
+#define BM_UARTAPP_LINECTRL_SPS	0x00000080
+#define BM_UARTAPP_LINECTRL_BAUD_DIVFRAC	0x00003F00
+#define BP_UARTAPP_LINECTRL_BAUD_DIVFRAC	8
+#define BM_UARTAPP_LINECTRL_BAUD_DIVINT	0xFFFF0000
+#define BP_UARTAPP_LINECTRL_BAUD_DIVINT	16
+
+#define HW_UARTAPP_INTR		0x50
+#define BM_UARTAPP_INTR_CTSMIS	0x00000002
+#define BM_UARTAPP_INTR_RTIS	0x00000040
+#define BM_UARTAPP_INTR_CTSMIEN	0x00020000
+#define BM_UARTAPP_INTR_RXIEN	0x00100000
+#define BM_UARTAPP_INTR_RTIEN	0x00400000
+
+#define HW_UARTAPP_DATA		0x60
+
+#define HW_UARTAPP_STAT		0x70
+#define BM_UARTAPP_STAT_RXCOUNT	0x0000FFFF
+#define BP_UARTAPP_STAT_RXCOUNT	0
+#define BM_UARTAPP_STAT_FERR	0x00010000
+#define BM_UARTAPP_STAT_PERR	0x00020000
+#define BM_UARTAPP_STAT_BERR	0x00040000
+#define BM_UARTAPP_STAT_OERR	0x00080000
+#define BM_UARTAPP_STAT_RXFE	0x01000000
+#define BM_UARTAPP_STAT_TXFF	0x02000000
+#define BM_UARTAPP_STAT_TXFE	0x08000000
+#define BM_UARTAPP_STAT_CTS	0x10000000
+
+#define HW_UARTAPP_VERSION	0x90
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-uartdbg.h b/arch/arm/mach-stmp37xx/include/mach/regs-uartdbg.h
new file mode 100644
index 0000000..b810deb
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-uartdbg.h
@@ -0,0 +1,268 @@
+/*
+ * stmp378x: UARTDBG register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_UARTDBG_BASE	(STMP3XXX_REGS_BASE + 0x70000)
+#define REGS_UARTDBG_PHYS	0x80070000
+#define REGS_UARTDBG_SIZE	0x2000
+
+#define HW_UARTDBGDR 0x00000000
+#define BP_UARTDBGDR_UNAVAILABLE      16
+#define BM_UARTDBGDR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGDR_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGDR_UNAVAILABLE)
+#define BP_UARTDBGDR_RESERVED      12
+#define BM_UARTDBGDR_RESERVED 0x0000F000
+#define BF_UARTDBGDR_RESERVED(v)  \
+	(((v) << 12) & BM_UARTDBGDR_RESERVED)
+#define BM_UARTDBGDR_OE 0x00000800
+#define BM_UARTDBGDR_BE 0x00000400
+#define BM_UARTDBGDR_PE 0x00000200
+#define BM_UARTDBGDR_FE 0x00000100
+#define BP_UARTDBGDR_DATA      0
+#define BM_UARTDBGDR_DATA 0x000000FF
+#define BF_UARTDBGDR_DATA(v)  \
+	(((v) << 0) & BM_UARTDBGDR_DATA)
+#define HW_UARTDBGRSR_ECR 0x00000004
+#define BP_UARTDBGRSR_ECR_UNAVAILABLE      8
+#define BM_UARTDBGRSR_ECR_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGRSR_ECR_UNAVAILABLE(v) \
+	(((v) << 8) & BM_UARTDBGRSR_ECR_UNAVAILABLE)
+#define BP_UARTDBGRSR_ECR_EC      4
+#define BM_UARTDBGRSR_ECR_EC 0x000000F0
+#define BF_UARTDBGRSR_ECR_EC(v)  \
+	(((v) << 4) & BM_UARTDBGRSR_ECR_EC)
+#define BM_UARTDBGRSR_ECR_OE 0x00000008
+#define BM_UARTDBGRSR_ECR_BE 0x00000004
+#define BM_UARTDBGRSR_ECR_PE 0x00000002
+#define BM_UARTDBGRSR_ECR_FE 0x00000001
+#define HW_UARTDBGFR 0x00000018
+#define BP_UARTDBGFR_UNAVAILABLE      16
+#define BM_UARTDBGFR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGFR_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGFR_UNAVAILABLE)
+#define BP_UARTDBGFR_RESERVED      9
+#define BM_UARTDBGFR_RESERVED 0x0000FE00
+#define BF_UARTDBGFR_RESERVED(v)  \
+	(((v) << 9) & BM_UARTDBGFR_RESERVED)
+#define BM_UARTDBGFR_RI 0x00000100
+#define BM_UARTDBGFR_TXFE 0x00000080
+#define BM_UARTDBGFR_RXFF 0x00000040
+#define BM_UARTDBGFR_TXFF 0x00000020
+#define BM_UARTDBGFR_RXFE 0x00000010
+#define BM_UARTDBGFR_BUSY 0x00000008
+#define BM_UARTDBGFR_DCD 0x00000004
+#define BM_UARTDBGFR_DSR 0x00000002
+#define BM_UARTDBGFR_CTS 0x00000001
+#define HW_UARTDBGILPR 0x00000020
+#define BP_UARTDBGILPR_UNAVAILABLE      8
+#define BM_UARTDBGILPR_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGILPR_UNAVAILABLE(v) \
+	(((v) << 8) & BM_UARTDBGILPR_UNAVAILABLE)
+#define BP_UARTDBGILPR_ILPDVSR      0
+#define BM_UARTDBGILPR_ILPDVSR 0x000000FF
+#define BF_UARTDBGILPR_ILPDVSR(v)  \
+	(((v) << 0) & BM_UARTDBGILPR_ILPDVSR)
+#define HW_UARTDBGIBRD 0x00000024
+#define BP_UARTDBGIBRD_UNAVAILABLE      16
+#define BM_UARTDBGIBRD_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIBRD_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGIBRD_UNAVAILABLE)
+#define BP_UARTDBGIBRD_BAUD_DIVINT      0
+#define BM_UARTDBGIBRD_BAUD_DIVINT 0x0000FFFF
+#define BF_UARTDBGIBRD_BAUD_DIVINT(v)  \
+	(((v) << 0) & BM_UARTDBGIBRD_BAUD_DIVINT)
+#define HW_UARTDBGFBRD 0x00000028
+#define BP_UARTDBGFBRD_UNAVAILABLE      8
+#define BM_UARTDBGFBRD_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGFBRD_UNAVAILABLE(v) \
+	(((v) << 8) & BM_UARTDBGFBRD_UNAVAILABLE)
+#define BP_UARTDBGFBRD_RESERVED      6
+#define BM_UARTDBGFBRD_RESERVED 0x000000C0
+#define BF_UARTDBGFBRD_RESERVED(v)  \
+	(((v) << 6) & BM_UARTDBGFBRD_RESERVED)
+#define BP_UARTDBGFBRD_BAUD_DIVFRAC      0
+#define BM_UARTDBGFBRD_BAUD_DIVFRAC 0x0000003F
+#define BF_UARTDBGFBRD_BAUD_DIVFRAC(v)  \
+	(((v) << 0) & BM_UARTDBGFBRD_BAUD_DIVFRAC)
+#define HW_UARTDBGLCR_H 0x0000002c
+#define BP_UARTDBGLCR_H_UNAVAILABLE      16
+#define BM_UARTDBGLCR_H_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGLCR_H_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGLCR_H_UNAVAILABLE)
+#define BP_UARTDBGLCR_H_RESERVED      8
+#define BM_UARTDBGLCR_H_RESERVED 0x0000FF00
+#define BF_UARTDBGLCR_H_RESERVED(v)  \
+	(((v) << 8) & BM_UARTDBGLCR_H_RESERVED)
+#define BM_UARTDBGLCR_H_SPS 0x00000080
+#define BP_UARTDBGLCR_H_WLEN      5
+#define BM_UARTDBGLCR_H_WLEN 0x00000060
+#define BF_UARTDBGLCR_H_WLEN(v)  \
+	(((v) << 5) & BM_UARTDBGLCR_H_WLEN)
+#define BM_UARTDBGLCR_H_FEN 0x00000010
+#define BM_UARTDBGLCR_H_STP2 0x00000008
+#define BM_UARTDBGLCR_H_EPS 0x00000004
+#define BM_UARTDBGLCR_H_PEN 0x00000002
+#define BM_UARTDBGLCR_H_BRK 0x00000001
+#define HW_UARTDBGCR 0x00000030
+#define BP_UARTDBGCR_UNAVAILABLE      16
+#define BM_UARTDBGCR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGCR_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGCR_UNAVAILABLE)
+#define BM_UARTDBGCR_CTSEN 0x00008000
+#define BM_UARTDBGCR_RTSEN 0x00004000
+#define BM_UARTDBGCR_OUT2 0x00002000
+#define BM_UARTDBGCR_OUT1 0x00001000
+#define BM_UARTDBGCR_RTS 0x00000800
+#define BM_UARTDBGCR_DTR 0x00000400
+#define BM_UARTDBGCR_RXE 0x00000200
+#define BM_UARTDBGCR_TXE 0x00000100
+#define BM_UARTDBGCR_LBE 0x00000080
+#define BP_UARTDBGCR_RESERVED      3
+#define BM_UARTDBGCR_RESERVED 0x00000078
+#define BF_UARTDBGCR_RESERVED(v)  \
+	(((v) << 3) & BM_UARTDBGCR_RESERVED)
+#define BM_UARTDBGCR_SIRLP 0x00000004
+#define BM_UARTDBGCR_SIREN 0x00000002
+#define BM_UARTDBGCR_UARTEN 0x00000001
+#define HW_UARTDBGIFLS 0x00000034
+#define BP_UARTDBGIFLS_UNAVAILABLE      16
+#define BM_UARTDBGIFLS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIFLS_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGIFLS_UNAVAILABLE)
+#define BP_UARTDBGIFLS_RESERVED      6
+#define BM_UARTDBGIFLS_RESERVED 0x0000FFC0
+#define BF_UARTDBGIFLS_RESERVED(v)  \
+	(((v) << 6) & BM_UARTDBGIFLS_RESERVED)
+#define BP_UARTDBGIFLS_RXIFLSEL      3
+#define BM_UARTDBGIFLS_RXIFLSEL 0x00000038
+#define BF_UARTDBGIFLS_RXIFLSEL(v)  \
+	(((v) << 3) & BM_UARTDBGIFLS_RXIFLSEL)
+#define BV_UARTDBGIFLS_RXIFLSEL__NOT_EMPTY      0x0
+#define BV_UARTDBGIFLS_RXIFLSEL__ONE_QUARTER    0x1
+#define BV_UARTDBGIFLS_RXIFLSEL__ONE_HALF       0x2
+#define BV_UARTDBGIFLS_RXIFLSEL__THREE_QUARTERS 0x3
+#define BV_UARTDBGIFLS_RXIFLSEL__SEVEN_EIGHTHS  0x4
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID5       0x5
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID6       0x6
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID7       0x7
+#define BP_UARTDBGIFLS_TXIFLSEL      0
+#define BM_UARTDBGIFLS_TXIFLSEL 0x00000007
+#define BF_UARTDBGIFLS_TXIFLSEL(v)  \
+	(((v) << 0) & BM_UARTDBGIFLS_TXIFLSEL)
+#define BV_UARTDBGIFLS_TXIFLSEL__EMPTY	  0x0
+#define BV_UARTDBGIFLS_TXIFLSEL__ONE_QUARTER    0x1
+#define BV_UARTDBGIFLS_TXIFLSEL__ONE_HALF       0x2
+#define BV_UARTDBGIFLS_TXIFLSEL__THREE_QUARTERS 0x3
+#define BV_UARTDBGIFLS_TXIFLSEL__SEVEN_EIGHTHS  0x4
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID5       0x5
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID6       0x6
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID7       0x7
+#define HW_UARTDBGIMSC 0x00000038
+#define BP_UARTDBGIMSC_UNAVAILABLE      16
+#define BM_UARTDBGIMSC_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIMSC_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGIMSC_UNAVAILABLE)
+#define BP_UARTDBGIMSC_RESERVED      11
+#define BM_UARTDBGIMSC_RESERVED 0x0000F800
+#define BF_UARTDBGIMSC_RESERVED(v)  \
+	(((v) << 11) & BM_UARTDBGIMSC_RESERVED)
+#define BM_UARTDBGIMSC_OEIM 0x00000400
+#define BM_UARTDBGIMSC_BEIM 0x00000200
+#define BM_UARTDBGIMSC_PEIM 0x00000100
+#define BM_UARTDBGIMSC_FEIM 0x00000080
+#define BM_UARTDBGIMSC_RTIM 0x00000040
+#define BM_UARTDBGIMSC_TXIM 0x00000020
+#define BM_UARTDBGIMSC_RXIM 0x00000010
+#define BM_UARTDBGIMSC_DSRMIM 0x00000008
+#define BM_UARTDBGIMSC_DCDMIM 0x00000004
+#define BM_UARTDBGIMSC_CTSMIM 0x00000002
+#define BM_UARTDBGIMSC_RIMIM 0x00000001
+#define HW_UARTDBGRIS 0x0000003c
+#define BP_UARTDBGRIS_UNAVAILABLE      16
+#define BM_UARTDBGRIS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGRIS_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGRIS_UNAVAILABLE)
+#define BP_UARTDBGRIS_RESERVED      11
+#define BM_UARTDBGRIS_RESERVED 0x0000F800
+#define BF_UARTDBGRIS_RESERVED(v)  \
+	(((v) << 11) & BM_UARTDBGRIS_RESERVED)
+#define BM_UARTDBGRIS_OERIS 0x00000400
+#define BM_UARTDBGRIS_BERIS 0x00000200
+#define BM_UARTDBGRIS_PERIS 0x00000100
+#define BM_UARTDBGRIS_FERIS 0x00000080
+#define BM_UARTDBGRIS_RTRIS 0x00000040
+#define BM_UARTDBGRIS_TXRIS 0x00000020
+#define BM_UARTDBGRIS_RXRIS 0x00000010
+#define BM_UARTDBGRIS_DSRRMIS 0x00000008
+#define BM_UARTDBGRIS_DCDRMIS 0x00000004
+#define BM_UARTDBGRIS_CTSRMIS 0x00000002
+#define BM_UARTDBGRIS_RIRMIS 0x00000001
+#define HW_UARTDBGMIS 0x00000040
+#define BP_UARTDBGMIS_UNAVAILABLE      16
+#define BM_UARTDBGMIS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGMIS_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGMIS_UNAVAILABLE)
+#define BP_UARTDBGMIS_RESERVED      11
+#define BM_UARTDBGMIS_RESERVED 0x0000F800
+#define BF_UARTDBGMIS_RESERVED(v)  \
+	(((v) << 11) & BM_UARTDBGMIS_RESERVED)
+#define BM_UARTDBGMIS_OEMIS 0x00000400
+#define BM_UARTDBGMIS_BEMIS 0x00000200
+#define BM_UARTDBGMIS_PEMIS 0x00000100
+#define BM_UARTDBGMIS_FEMIS 0x00000080
+#define BM_UARTDBGMIS_RTMIS 0x00000040
+#define BM_UARTDBGMIS_TXMIS 0x00000020
+#define BM_UARTDBGMIS_RXMIS 0x00000010
+#define BM_UARTDBGMIS_DSRMMIS 0x00000008
+#define BM_UARTDBGMIS_DCDMMIS 0x00000004
+#define BM_UARTDBGMIS_CTSMMIS 0x00000002
+#define BM_UARTDBGMIS_RIMMIS 0x00000001
+#define HW_UARTDBGICR 0x00000044
+#define BP_UARTDBGICR_UNAVAILABLE      16
+#define BM_UARTDBGICR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGICR_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGICR_UNAVAILABLE)
+#define BP_UARTDBGICR_RESERVED      11
+#define BM_UARTDBGICR_RESERVED 0x0000F800
+#define BF_UARTDBGICR_RESERVED(v)  \
+	(((v) << 11) & BM_UARTDBGICR_RESERVED)
+#define BM_UARTDBGICR_OEIC 0x00000400
+#define BM_UARTDBGICR_BEIC 0x00000200
+#define BM_UARTDBGICR_PEIC 0x00000100
+#define BM_UARTDBGICR_FEIC 0x00000080
+#define BM_UARTDBGICR_RTIC 0x00000040
+#define BM_UARTDBGICR_TXIC 0x00000020
+#define BM_UARTDBGICR_RXIC 0x00000010
+#define BM_UARTDBGICR_DSRMIC 0x00000008
+#define BM_UARTDBGICR_DCDMIC 0x00000004
+#define BM_UARTDBGICR_CTSMIC 0x00000002
+#define BM_UARTDBGICR_RIMIC 0x00000001
+#define HW_UARTDBGDMACR 0x00000048
+#define BP_UARTDBGDMACR_UNAVAILABLE      16
+#define BM_UARTDBGDMACR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGDMACR_UNAVAILABLE(v) \
+	(((v) << 16) & BM_UARTDBGDMACR_UNAVAILABLE)
+#define BP_UARTDBGDMACR_RESERVED      3
+#define BM_UARTDBGDMACR_RESERVED 0x0000FFF8
+#define BF_UARTDBGDMACR_RESERVED(v)  \
+	(((v) << 3) & BM_UARTDBGDMACR_RESERVED)
+#define BM_UARTDBGDMACR_DMAONERR 0x00000004
+#define BM_UARTDBGDMACR_TXDMAE 0x00000002
+#define BM_UARTDBGDMACR_RXDMAE 0x00000001
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-usbctl.h b/arch/arm/mach-stmp37xx/include/mach/regs-usbctl.h
new file mode 100644
index 0000000..9145e22
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-usbctl.h
@@ -0,0 +1,22 @@
+/*
+ * stmp37xx: USBCTL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_USBCTL_BASE	(STMP3XXX_REGS_BASE + 0x80000)
+#define REGS_USBCTL_PHYS	0x80000
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-usbctrl.h b/arch/arm/mach-stmp37xx/include/mach/regs-usbctrl.h
new file mode 100644
index 0000000..1a2ae9c
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-usbctrl.h
@@ -0,0 +1,22 @@
+/*
+ * stmp37xx: USBCTRL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_USBCTRL_BASE	(STMP3XXX_REGS_BASE + 0x80000)
+#define REGS_USBCTRL_PHYS	0x80080000
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-usbphy.h b/arch/arm/mach-stmp37xx/include/mach/regs-usbphy.h
new file mode 100644
index 0000000..b7fce0f
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/include/mach/regs-usbphy.h
@@ -0,0 +1,37 @@
+/*
+ * stmp37xx: USBPHY register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#define REGS_USBPHY_BASE	(STMP3XXX_REGS_BASE + 0x7C000)
+
+#define HW_USBPHY_PWD		0x0
+
+#define HW_USBPHY_CTRL		0x30
+#define BM_USBPHY_CTRL_ENHSPRECHARGEXMIT	0x00000001
+#define BP_USBPHY_CTRL_ENHSPRECHARGEXMIT	0
+#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT	0x00000002
+#define BM_USBPHY_CTRL_ENDEVPLUGINDETECT	0x00000010
+#define BM_USBPHY_CTRL_ENOTGIDDETECT	0x00000080
+#define BM_USBPHY_CTRL_ENIRQDEVPLUGIN	0x00000800
+#define BM_USBPHY_CTRL_CLKGATE	0x40000000
+#define BM_USBPHY_CTRL_SFTRST	0x80000000
+
+#define HW_USBPHY_STATUS	0x40
+#define BM_USBPHY_STATUS_DEVPLUGIN_STATUS	0x00000040
+#define BM_USBPHY_STATUS_OTGID_STATUS	0x00000100
diff --git a/arch/arm/mach-stmp37xx/stmp37xx.c b/arch/arm/mach-stmp37xx/stmp37xx.c
new file mode 100644
index 0000000..8c7d6fb
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/stmp37xx.c
@@ -0,0 +1,219 @@
+/*
+ * Freescale STMP37XX platform support
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+#include <mach/stmp3xxx.h>
+#include <mach/dma.h>
+
+#include <mach/platform.h>
+#include <mach/regs-icoll.h>
+#include <mach/regs-apbh.h>
+#include <mach/regs-apbx.h>
+#include "stmp37xx.h"
+
+/*
+ * IRQ handling
+ */
+static void stmp37xx_ack_irq(unsigned int irq)
+{
+	/* Disable IRQ */
+	stmp3xxx_clearl(0x04 << ((irq % 4) * 8),
+		REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + irq / 4 * 0x10);
+
+	/* ACK current interrupt */
+	__raw_writel(1, REGS_ICOLL_BASE + HW_ICOLL_LEVELACK);
+
+	/* Barrier */
+	(void)__raw_readl(REGS_ICOLL_BASE + HW_ICOLL_STAT);
+}
+
+static void stmp37xx_mask_irq(unsigned int irq)
+{
+	/* IRQ disable */
+	stmp3xxx_clearl(0x04 << ((irq % 4) * 8),
+		REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + irq / 4 * 0x10);
+}
+
+static void stmp37xx_unmask_irq(unsigned int irq)
+{
+	/* IRQ enable */
+	stmp3xxx_setl(0x04 << ((irq % 4) * 8),
+		REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + irq / 4 * 0x10);
+}
+
+static struct irq_chip stmp37xx_chip = {
+	.ack	= stmp37xx_ack_irq,
+	.mask	= stmp37xx_mask_irq,
+	.unmask = stmp37xx_unmask_irq,
+};
+
+void __init stmp37xx_init_irq(void)
+{
+	stmp3xxx_init_irq(&stmp37xx_chip);
+}
+
+/*
+ * DMA interrupt handling
+ */
+void stmp3xxx_arch_dma_enable_interrupt(int channel)
+{
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		stmp3xxx_setl(1 << (8 + STMP3XXX_DMA_CHANNEL(channel)),
+			REGS_APBH_BASE + HW_APBH_CTRL1);
+		break;
+
+	case STMP3XXX_BUS_APBX:
+		stmp3xxx_setl(1 << (8 + STMP3XXX_DMA_CHANNEL(channel)),
+			REGS_APBX_BASE + HW_APBX_CTRL1);
+		break;
+	}
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_enable_interrupt);
+
+void stmp3xxx_arch_dma_clear_interrupt(int channel)
+{
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel),
+				REGS_APBH_BASE + HW_APBH_CTRL1);
+		break;
+
+	case STMP3XXX_BUS_APBX:
+		stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel),
+				REGS_APBX_BASE + HW_APBX_CTRL1);
+		break;
+	}
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_clear_interrupt);
+
+int stmp3xxx_arch_dma_is_interrupt(int channel)
+{
+	int r = 0;
+
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		r = __raw_readl(REGS_APBH_BASE + HW_APBH_CTRL1) &
+			(1 << STMP3XXX_DMA_CHANNEL(channel));
+		break;
+
+	case STMP3XXX_BUS_APBX:
+		r = __raw_readl(REGS_APBH_BASE + HW_APBH_CTRL1) &
+			(1 << STMP3XXX_DMA_CHANNEL(channel));
+		break;
+	}
+	return r;
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_is_interrupt);
+
+void stmp3xxx_arch_dma_reset_channel(int channel)
+{
+	unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
+
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		/* Reset channel and wait for it to complete */
+		stmp3xxx_setl(chbit << BP_APBH_CTRL0_RESET_CHANNEL,
+			REGS_APBH_BASE + HW_APBH_CTRL0);
+		while (__raw_readl(REGS_APBH_BASE + HW_APBH_CTRL0) &
+		       (chbit << BP_APBH_CTRL0_RESET_CHANNEL))
+				cpu_relax();
+		break;
+
+	case STMP3XXX_BUS_APBX:
+		stmp3xxx_setl(chbit << BP_APBX_CTRL0_RESET_CHANNEL,
+			REGS_APBX_BASE + HW_APBX_CTRL0);
+		while (__raw_readl(REGS_APBX_BASE + HW_APBX_CTRL0) &
+		       (chbit << BP_APBX_CTRL0_RESET_CHANNEL))
+				cpu_relax();
+		break;
+	}
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_reset_channel);
+
+void stmp3xxx_arch_dma_freeze(int channel)
+{
+	unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
+
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		stmp3xxx_setl(1 << chbit, REGS_APBH_BASE + HW_APBH_CTRL0);
+		break;
+	case STMP3XXX_BUS_APBX:
+		stmp3xxx_setl(1 << chbit, REGS_APBH_BASE + HW_APBH_CTRL0);
+		break;
+	}
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_freeze);
+
+void stmp3xxx_arch_dma_unfreeze(int channel)
+{
+	unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
+
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		stmp3xxx_clearl(1 << chbit, REGS_APBH_BASE + HW_APBH_CTRL0);
+		break;
+	case STMP3XXX_BUS_APBX:
+		stmp3xxx_clearl(1 << chbit, REGS_APBH_BASE + HW_APBH_CTRL0);
+		break;
+	}
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_unfreeze);
+
+/*
+ * The registers are all very closely mapped, so we might as well map them all
+ * with a single mapping
+ *
+ * Logical      Physical
+ * f0000000	80000000	On-chip registers
+ * f1000000	00000000	32k on-chip SRAM
+ */
+static struct map_desc stmp37xx_io_desc[] __initdata = {
+	{
+		.virtual	= (u32)STMP3XXX_REGS_BASE,
+		.pfn		= __phys_to_pfn(STMP3XXX_REGS_PHBASE),
+		.length		= SZ_1M,
+		.type		= MT_DEVICE
+	},
+	{
+		.virtual	= (u32)STMP3XXX_OCRAM_BASE,
+		.pfn		= __phys_to_pfn(STMP3XXX_OCRAM_PHBASE),
+		.length		= STMP3XXX_OCRAM_SIZE,
+		.type		= MT_DEVICE,
+	},
+};
+
+void __init stmp37xx_map_io(void)
+{
+	iotable_init(stmp37xx_io_desc, ARRAY_SIZE(stmp37xx_io_desc));
+}
diff --git a/arch/arm/mach-stmp37xx/stmp37xx.h b/arch/arm/mach-stmp37xx/stmp37xx.h
new file mode 100644
index 0000000..0b75fb7
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/stmp37xx.h
@@ -0,0 +1,24 @@
+/*
+ * Freescale STMP37XX/STMP378X internal functions and data declarations
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __MACH_STMP37XX_H
+#define __MACH_STMP37XX_H
+
+void stmp37xx_map_io(void);
+void stmp37xx_init_irq(void);
+
+#endif /* __MACH_STMP37XX_H */
diff --git a/arch/arm/mach-stmp37xx/stmp37xx_devb.c b/arch/arm/mach-stmp37xx/stmp37xx_devb.c
new file mode 100644
index 0000000..394f21a
--- /dev/null
+++ b/arch/arm/mach-stmp37xx/stmp37xx_devb.c
@@ -0,0 +1,101 @@
+/*
+ * Freescale STMP37XX development board support
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/stmp3xxx.h>
+#include <mach/pins.h>
+#include <mach/pinmux.h>
+#include "stmp37xx.h"
+
+/*
+ * List of STMP37xx development board specific devices
+ */
+static struct platform_device *stmp37xx_devb_devices[] = {
+	&stmp3xxx_dbguart,
+	&stmp3xxx_appuart,
+};
+
+static struct pin_desc dbguart_pins_0[] = {
+	{ PINID_PWM0, PIN_FUN3, },
+	{ PINID_PWM1, PIN_FUN3, },
+};
+
+struct pin_desc appuart_pins_0[] = {
+	{ PINID_UART2_CTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+	{ PINID_UART2_RTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+	{ PINID_UART2_RX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+	{ PINID_UART2_TX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+};
+
+static struct pin_group appuart_pins[] = {
+	[0] = {
+		.pins		= appuart_pins_0,
+		.nr_pins	= ARRAY_SIZE(appuart_pins_0),
+	},
+	/* 37xx has the only app uart */
+};
+
+static struct pin_group dbguart_pins[] = {
+	[0] = {
+		.pins		= dbguart_pins_0,
+		.nr_pins	= ARRAY_SIZE(dbguart_pins_0),
+	},
+};
+
+static int dbguart_pins_control(int id, int request)
+{
+	int r = 0;
+
+	if (request)
+		r = stmp3xxx_request_pin_group(&dbguart_pins[id], "debug uart");
+	else
+		stmp3xxx_release_pin_group(&dbguart_pins[id], "debug uart");
+	return r;
+}
+
+
+static void __init stmp37xx_devb_init(void)
+{
+	stmp3xxx_pinmux_init(NR_REAL_IRQS);
+
+	/* Init STMP3xxx platform */
+	stmp3xxx_init();
+
+	stmp3xxx_dbguart.dev.platform_data = dbguart_pins_control;
+	stmp3xxx_appuart.dev.platform_data = appuart_pins;
+
+	/* Add STMP37xx development board devices */
+	platform_add_devices(stmp37xx_devb_devices,
+			ARRAY_SIZE(stmp37xx_devb_devices));
+}
+
+MACHINE_START(STMP37XX, "STMP37XX")
+	.phys_io	= 0x80000000,
+	.io_pg_offst	= ((0xf0000000) >> 18) & 0xfffc,
+	.boot_params	= 0x40000100,
+	.map_io		= stmp37xx_map_io,
+	.init_irq	= stmp37xx_init_irq,
+	.timer		= &stmp3xxx_timer,
+	.init_machine	= stmp37xx_devb_init,
+MACHINE_END
diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig
new file mode 100644
index 0000000..337b9aa
--- /dev/null
+++ b/arch/arm/mach-u300/Kconfig
@@ -0,0 +1,105 @@
+if ARCH_U300
+
+menu "ST-Ericsson AB U300/U330/U335/U365 Platform"
+
+comment "ST-Ericsson Mobile Platform Products"
+
+config MACH_U300
+	bool "U300"
+
+comment "ST-Ericsson U300/U330/U335/U365 Feature Selections"
+
+choice
+	prompt "U300/U330/U335/U365 system type"
+	default MACH_U300_BS2X
+	---help---
+	You need to select the target system, i.e. the
+	U300/U330/U335/U365 board that you want to compile your kernel
+	for.
+
+config MACH_U300_BS2X
+	bool "S26/S26/B25/B26 Test Products"
+	depends on MACH_U300
+	help
+		Select this if you're developing on the
+		S26/S25 test products. (Also works on
+		B26/B25 big boards.)
+
+config MACH_U300_BS330
+	bool "S330/B330 Test Products"
+	depends on MACH_U300
+	help
+		Select this if you're developing on the
+		S330/B330 test products.
+
+config MACH_U300_BS335
+	bool "S335/B335 Test Products"
+	depends on MACH_U300
+	help
+		Select this if you're developing on the
+		S335/B335 test products.
+
+config MACH_U300_BS365
+	bool "S365/B365 Test Products"
+	depends on MACH_U300
+	help
+		Select this if you're developing on the
+		S365/B365 test products.
+
+endchoice
+
+choice
+	prompt "Memory configuration"
+	default MACH_U300_SINGLE_RAM
+	---help---
+	You have to config the kernel according to the physical memory
+	configuration.
+
+config MACH_U300_SINGLE_RAM
+	bool "Single RAM"
+	help
+		Select this if you want support for Single RAM phones.
+
+config MACH_U300_DUAL_RAM
+	bool "Dual RAM"
+	help
+		Select this if you want support for Dual RAM phones.
+		This is two RAM memorys on different EMIFs.
+endchoice
+
+config U300_DEBUG
+	bool "Debug support for U300"
+	depends on PM
+	help
+		Debug support for U300 in sysfs, procfs etc.
+
+config MACH_U300_SEMI_IS_SHARED
+	bool "The SEMI is used by both the access and application side"
+	depends on MACH_U300
+	help
+		This makes it possible to use the SEMI (Shared External
+		Memory Interface) from both from access and application
+		side.
+
+comment "All the settings below must match the bootloader's settings"
+
+config MACH_U300_ACCESS_MEM_SIZE
+       int "Access CPU memory allocation"
+       range 7 25
+       depends on MACH_U300_SINGLE_RAM
+       default 13
+       help
+		How much memory in MiB that the Access side CPU has allocated
+
+config MACH_U300_2MB_ALIGNMENT_FIX
+       bool "2MiB alignment fix"
+       depends on MACH_U300_SINGLE_RAM
+       default y
+       help
+		If yes and the Access side CPU has allocated an odd size in
+		MiB, this fix gives you one MiB extra that would otherwise be
+		lost due to Linux 2 MiB alignment policy.
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile
new file mode 100644
index 0000000..24950e0
--- /dev/null
+++ b/arch/arm/mach-u300/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the linux kernel, U300 machine.
+#
+
+obj-y		:= core.o clock.o timer.o gpio.o padmux.o
+obj-m		:=
+obj-n		:=
+obj-		:=
+
+obj-$(CONFIG_ARCH_U300)	          += u300.o
+obj-$(CONFIG_MMC)                 += mmc.o
diff --git a/arch/arm/mach-u300/Makefile.boot b/arch/arm/mach-u300/Makefile.boot
new file mode 100644
index 0000000..6fbfc6e
--- /dev/null
+++ b/arch/arm/mach-u300/Makefile.boot
@@ -0,0 +1,15 @@
+# Note: the following conditions must always be true:
+#   ZRELADDR == virt_to_phys(TEXTADDR)
+#   PARAMS_PHYS must be within 4MB of ZRELADDR
+#   INITRD_PHYS must be in RAM
+
+ifdef CONFIG_MACH_U300_SINGLE_RAM
+     zreladdr-y	:= 0x28E08000
+  params_phys-y	:= 0x28E00100
+else
+     zreladdr-y	:= 0x48008000
+  params_phys-y	:= 0x48000100
+endif
+
+# This isn't used.
+#initrd_phys-y	:= 0x29800000
diff --git a/arch/arm/mach-u300/clock.c b/arch/arm/mach-u300/clock.c
new file mode 100644
index 0000000..5cd04d6
--- /dev/null
+++ b/arch/arm/mach-u300/clock.c
@@ -0,0 +1,1487 @@
+/*
+ *
+ * arch/arm/mach-u300/clock.c
+ *
+ *
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Define clocks in the app platform.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+
+#include <asm/clkdev.h>
+#include <mach/hardware.h>
+#include <mach/syscon.h>
+
+#include "clock.h"
+
+/*
+ * TODO:
+ * - move all handling of the CCR register into this file and create
+ *   a spinlock for the CCR register
+ * - switch to the clkdevice lookup mechanism that maps clocks to
+ *   device ID:s instead when it becomes available in kernel 2.6.29.
+ * - implement rate get/set for all clocks that need it.
+ */
+
+/*
+ * Syscon clock I/O registers lock so clock requests don't collide
+ * NOTE: this is a local lock only used to lock access to clock and
+ * reset registers in syscon.
+ */
+static DEFINE_SPINLOCK(syscon_clkreg_lock);
+static DEFINE_SPINLOCK(syscon_resetreg_lock);
+
+/*
+ * The clocking hierarchy currently looks like this.
+ * NOTE: the idea is NOT to show how the clocks are routed on the chip!
+ * The ideas is to show dependencies, so a clock higher up in the
+ * hierarchy has to be on in order for another clock to be on. Now,
+ * both CPU and DMA can actually be on top of the hierarchy, and that
+ * is not modeled currently. Instead we have the backbone AMBA bus on
+ * top. This bus cannot be programmed in any way but conceptually it
+ * needs to be active for the bridges and devices to transport data.
+ *
+ * Please be aware that a few clocks are hw controlled, which mean that
+ * the hw itself can turn on/off or change the rate of the clock when
+ * needed!
+ *
+ *  AMBA bus
+ *  |
+ *  +- CPU
+ *  +- NANDIF NAND Flash interface
+ *  +- SEMI Shared Memory interface
+ *  +- ISP Image Signal Processor (U335 only)
+ *  +- CDS (U335 only)
+ *  +- DMA Direct Memory Access Controller
+ *  +- AAIF APP/ACC Inteface (Mobile Scalable Link, MSL)
+ *  +- APEX
+ *  +- VIDEO_ENC AVE2/3 Video Encoder
+ *  +- XGAM Graphics Accelerator Controller
+ *  +- AHB
+ *  |
+ *  +- ahb:0 AHB Bridge
+ *  |  |
+ *  |  +- ahb:1 INTCON Interrupt controller
+ *  |  +- ahb:3 MSPRO  Memory Stick Pro controller
+ *  |  +- ahb:4 EMIF   External Memory interface
+ *  |
+ *  +- fast:0 FAST bridge
+ *  |  |
+ *  |  +- fast:1 MMCSD MMC/SD card reader controller
+ *  |  +- fast:2 I2S0  PCM I2S channel 0 controller
+ *  |  +- fast:3 I2S1  PCM I2S channel 1 controller
+ *  |  +- fast:4 I2C0  I2C channel 0 controller
+ *  |  +- fast:5 I2C1  I2C channel 1 controller
+ *  |  +- fast:6 SPI   SPI controller
+ *  |  +- fast:7 UART1 Secondary UART (U335 only)
+ *  |
+ *  +- slow:0 SLOW bridge
+ *     |
+ *     +- slow:1 SYSCON (not possible to control)
+ *     +- slow:2 WDOG Watchdog
+ *     +- slow:3 UART0 primary UART
+ *     +- slow:4 TIMER_APP Application timer - used in Linux
+ *     +- slow:5 KEYPAD controller
+ *     +- slow:6 GPIO controller
+ *     +- slow:7 RTC controller
+ *     +- slow:8 BT Bus Tracer (not used currently)
+ *     +- slow:9 EH Event Handler (not used currently)
+ *     +- slow:a TIMER_ACC Access style timer (not used currently)
+ *     +- slow:b PPM (U335 only, what is that?)
+ */
+
+/*
+ * Reset control functions. We remember if a block has been
+ * taken out of reset and don't remove the reset assertion again
+ * and vice versa. Currently we only remove resets so the
+ * enablement function is defined out.
+ */
+static void syscon_block_reset_enable(struct clk *clk)
+{
+	u16 val;
+	unsigned long iflags;
+
+	/* Not all blocks support resetting */
+	if (!clk->res_reg || !clk->res_mask)
+		return;
+	spin_lock_irqsave(&syscon_resetreg_lock, iflags);
+	val = readw(clk->res_reg);
+	val |= clk->res_mask;
+	writew(val, clk->res_reg);
+	spin_unlock_irqrestore(&syscon_resetreg_lock, iflags);
+	clk->reset = true;
+}
+
+static void syscon_block_reset_disable(struct clk *clk)
+{
+	u16 val;
+	unsigned long iflags;
+
+	/* Not all blocks support resetting */
+	if (!clk->res_reg || !clk->res_mask)
+		return;
+	spin_lock_irqsave(&syscon_resetreg_lock, iflags);
+	val = readw(clk->res_reg);
+	val &= ~clk->res_mask;
+	writew(val, clk->res_reg);
+	spin_unlock_irqrestore(&syscon_resetreg_lock, iflags);
+	clk->reset = false;
+}
+
+int __clk_get(struct clk *clk)
+{
+	u16 val;
+
+	/* The MMC and MSPRO clocks need some special set-up */
+	if (!strcmp(clk->name, "MCLK")) {
+		/* Set default MMC clock divisor to 18.9 MHz */
+		writew(0x0054U, U300_SYSCON_VBASE + U300_SYSCON_MMF0R);
+		val = readw(U300_SYSCON_VBASE + U300_SYSCON_MMCR);
+		/* Disable the MMC feedback clock */
+		val &= ~U300_SYSCON_MMCR_MMC_FB_CLK_SEL_ENABLE;
+		/* Disable MSPRO frequency */
+		val &= ~U300_SYSCON_MMCR_MSPRO_FREQSEL_ENABLE;
+		writew(val, U300_SYSCON_VBASE + U300_SYSCON_MMCR);
+	}
+	if (!strcmp(clk->name, "MSPRO")) {
+		val = readw(U300_SYSCON_VBASE + U300_SYSCON_MMCR);
+		/* Disable the MMC feedback clock */
+		val &= ~U300_SYSCON_MMCR_MMC_FB_CLK_SEL_ENABLE;
+		/* Enable MSPRO frequency */
+		val |= U300_SYSCON_MMCR_MSPRO_FREQSEL_ENABLE;
+		writew(val, U300_SYSCON_VBASE + U300_SYSCON_MMCR);
+	}
+	return 1;
+}
+EXPORT_SYMBOL(__clk_get);
+
+void __clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(__clk_put);
+
+static void syscon_clk_disable(struct clk *clk)
+{
+	unsigned long iflags;
+
+	/* Don't touch the hardware controlled clocks */
+	if (clk->hw_ctrld)
+		return;
+
+	spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+	writew(clk->clk_val, U300_SYSCON_VBASE + U300_SYSCON_SBCDR);
+	spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+
+static void syscon_clk_enable(struct clk *clk)
+{
+	unsigned long iflags;
+
+	/* Don't touch the hardware controlled clocks */
+	if (clk->hw_ctrld)
+		return;
+
+	spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+	writew(clk->clk_val, U300_SYSCON_VBASE + U300_SYSCON_SBCER);
+	spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+
+static u16 syscon_clk_get_rate(void)
+{
+	u16 val;
+	unsigned long iflags;
+
+	spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	val &= U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK;
+	spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+	return val;
+}
+
+#ifdef CONFIG_MACH_U300_USE_I2S_AS_MASTER
+static void enable_i2s0_vcxo(void)
+{
+	u16 val;
+	unsigned long iflags;
+
+	spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+	/* Set I2S0 to use the VCXO 26 MHz clock */
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	val |= U300_SYSCON_CCR_TURN_VCXO_ON;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	val |= U300_SYSCON_CCR_I2S0_USE_VCXO;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+	val |= U300_SYSCON_CEFR_I2S0_CLK_EN;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+	spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+
+static void enable_i2s1_vcxo(void)
+{
+	u16 val;
+	unsigned long iflags;
+
+	spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+	/* Set I2S1 to use the VCXO 26 MHz clock */
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	val |= U300_SYSCON_CCR_TURN_VCXO_ON;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	val |= U300_SYSCON_CCR_I2S1_USE_VCXO;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+	val |= U300_SYSCON_CEFR_I2S1_CLK_EN;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+	spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+
+static void disable_i2s0_vcxo(void)
+{
+	u16 val;
+	unsigned long iflags;
+
+	spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+	/* Disable I2S0 use of the VCXO 26 MHz clock */
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	val &= ~U300_SYSCON_CCR_I2S0_USE_VCXO;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	/* Deactivate VCXO if noone else is using VCXO */
+	if (!(val & U300_SYSCON_CCR_I2S1_USE_VCXO))
+		val &= ~U300_SYSCON_CCR_TURN_VCXO_ON;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+	val &= ~U300_SYSCON_CEFR_I2S0_CLK_EN;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+	spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+
+static void disable_i2s1_vcxo(void)
+{
+	u16 val;
+	unsigned long iflags;
+
+	spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+	/* Disable I2S1 use of the VCXO 26 MHz clock */
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	val &= ~U300_SYSCON_CCR_I2S1_USE_VCXO;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	/* Deactivate VCXO if noone else is using VCXO */
+	if (!(val & U300_SYSCON_CCR_I2S0_USE_VCXO))
+		val &= ~U300_SYSCON_CCR_TURN_VCXO_ON;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+	val &= ~U300_SYSCON_CEFR_I2S0_CLK_EN;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+	spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+#endif /* CONFIG_MACH_U300_USE_I2S_AS_MASTER */
+
+
+static void syscon_clk_rate_set_mclk(unsigned long rate)
+{
+	u16 val;
+	u32 reg;
+	unsigned long iflags;
+
+	switch (rate) {
+	case 18900000:
+		val = 0x0054;
+		break;
+	case 20800000:
+		val = 0x0044;
+		break;
+	case 23100000:
+		val = 0x0043;
+		break;
+	case 26000000:
+		val = 0x0033;
+		break;
+	case 29700000:
+		val = 0x0032;
+		break;
+	case 34700000:
+		val = 0x0022;
+		break;
+	case 41600000:
+		val = 0x0021;
+		break;
+	case 52000000:
+		val = 0x0011;
+		break;
+	case 104000000:
+		val = 0x0000;
+		break;
+	default:
+		printk(KERN_ERR "Trying to set MCLK to unknown speed! %ld\n",
+		       rate);
+		return;
+	}
+
+	spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+	reg = readw(U300_SYSCON_VBASE + U300_SYSCON_MMF0R) &
+		~U300_SYSCON_MMF0R_MASK;
+	writew(reg | val, U300_SYSCON_VBASE + U300_SYSCON_MMF0R);
+	spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+
+void syscon_clk_rate_set_cpuclk(unsigned long rate)
+{
+	u16 val;
+	unsigned long iflags;
+
+	switch (rate) {
+	case 13000000:
+		val = U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER;
+		break;
+	case 52000000:
+		val = U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE;
+		break;
+	case 104000000:
+		val = U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH;
+		break;
+	case 208000000:
+		val = U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST;
+		break;
+	default:
+		return;
+	}
+	spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+	val |= readw(U300_SYSCON_VBASE + U300_SYSCON_CCR) &
+		~U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK ;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+EXPORT_SYMBOL(syscon_clk_rate_set_cpuclk);
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long iflags;
+
+	spin_lock_irqsave(&clk->lock, iflags);
+	if (clk->usecount > 0 && !(--clk->usecount)) {
+		/* some blocks lack clocking registers and cannot be disabled */
+		if (clk->disable)
+			clk->disable(clk);
+		if (likely((u32)clk->parent))
+			clk_disable(clk->parent);
+	}
+#ifdef CONFIG_MACH_U300_USE_I2S_AS_MASTER
+	if (unlikely(!strcmp(clk->name, "I2S0")))
+		disable_i2s0_vcxo();
+	if (unlikely(!strcmp(clk->name, "I2S1")))
+		disable_i2s1_vcxo();
+#endif
+	spin_unlock_irqrestore(&clk->lock, iflags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+int clk_enable(struct clk *clk)
+{
+	int ret = 0;
+	unsigned long iflags;
+
+	spin_lock_irqsave(&clk->lock, iflags);
+	if (clk->usecount++ == 0) {
+		if (likely((u32)clk->parent))
+			ret = clk_enable(clk->parent);
+
+		if (unlikely(ret != 0))
+			clk->usecount--;
+		else {
+			/* remove reset line (we never enable reset again) */
+			syscon_block_reset_disable(clk);
+			/* clocks without enable function are always on */
+			if (clk->enable)
+				clk->enable(clk);
+#ifdef CONFIG_MACH_U300_USE_I2S_AS_MASTER
+			if (unlikely(!strcmp(clk->name, "I2S0")))
+				enable_i2s0_vcxo();
+			if (unlikely(!strcmp(clk->name, "I2S1")))
+				enable_i2s1_vcxo();
+#endif
+		}
+	}
+	spin_unlock_irqrestore(&clk->lock, iflags);
+	return ret;
+
+}
+EXPORT_SYMBOL(clk_enable);
+
+/* Returns the clock rate in Hz */
+static unsigned long clk_get_rate_cpuclk(struct clk *clk)
+{
+	u16 val;
+
+	val = syscon_clk_get_rate();
+
+	switch (val) {
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
+		return 13000000;
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
+		return 52000000;
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
+		return 104000000;
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
+		return 208000000;
+	default:
+		break;
+	}
+	return clk->rate;
+}
+
+static unsigned long clk_get_rate_ahb_clk(struct clk *clk)
+{
+	u16 val;
+
+	val = syscon_clk_get_rate();
+
+	switch (val) {
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
+		return 6500000;
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
+		return 26000000;
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
+		return 52000000;
+	default:
+		break;
+	}
+	return clk->rate;
+
+}
+
+static unsigned long clk_get_rate_emif_clk(struct clk *clk)
+{
+	u16 val;
+
+	val = syscon_clk_get_rate();
+
+	switch (val) {
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
+		return 13000000;
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
+		return 52000000;
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
+		return 104000000;
+	default:
+		break;
+	}
+	return clk->rate;
+
+}
+
+static unsigned long clk_get_rate_xgamclk(struct clk *clk)
+{
+	u16 val;
+
+	val = syscon_clk_get_rate();
+
+	switch (val) {
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
+		return 6500000;
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
+		return 26000000;
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
+		return 52000000;
+	default:
+		break;
+	}
+
+	return clk->rate;
+}
+
+static unsigned long clk_get_rate_mclk(struct clk *clk)
+{
+	u16 val;
+
+	val = syscon_clk_get_rate();
+
+	switch (val) {
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
+		/*
+		 * Here, the 208 MHz PLL gets shut down and the always
+		 * on 13 MHz PLL used for RTC etc kicks into use
+		 * instead.
+		 */
+		return 13000000;
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
+	{
+		/*
+		 * This clock is under program control. The register is
+		 * divided in two nybbles, bit 7-4 gives cycles-1 to count
+		 * high, bit 3-0 gives cycles-1 to count low. Distribute
+		 * these with no more than 1 cycle difference between
+		 * low and high and add low and high to get the actual
+		 * divisor. The base PLL is 208 MHz. Writing 0x00 will
+		 * divide by 1 and 1 so the highest frequency possible
+		 * is 104 MHz.
+		 *
+		 * e.g. 0x54 =>
+		 * f = 208 / ((5+1) + (4+1)) = 208 / 11 = 18.9 MHz
+		 */
+		u16 val = readw(U300_SYSCON_VBASE + U300_SYSCON_MMF0R) &
+			U300_SYSCON_MMF0R_MASK;
+		switch (val) {
+		case 0x0054:
+			return 18900000;
+		case 0x0044:
+			return 20800000;
+		case 0x0043:
+			return 23100000;
+		case 0x0033:
+			return 26000000;
+		case 0x0032:
+			return 29700000;
+		case 0x0022:
+			return 34700000;
+		case 0x0021:
+			return 41600000;
+		case 0x0011:
+			return 52000000;
+		case 0x0000:
+			return 104000000;
+		default:
+			break;
+		}
+	}
+	default:
+		break;
+	}
+
+	return clk->rate;
+}
+
+static unsigned long clk_get_rate_i2s_i2c_spi(struct clk *clk)
+{
+	u16 val;
+
+	val = syscon_clk_get_rate();
+
+	switch (val) {
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
+		return 13000000;
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
+	case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
+		return 26000000;
+	default:
+		break;
+	}
+
+	return clk->rate;
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->get_rate)
+		return clk->get_rate(clk);
+	else
+		return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+static unsigned long clk_round_rate_mclk(struct clk *clk, unsigned long rate)
+{
+	if (rate >= 18900000)
+		return 18900000;
+	if (rate >= 20800000)
+		return 20800000;
+	if (rate >= 23100000)
+		return 23100000;
+	if (rate >= 26000000)
+		return 26000000;
+	if (rate >= 29700000)
+		return 29700000;
+	if (rate >= 34700000)
+		return 34700000;
+	if (rate >= 41600000)
+		return 41600000;
+	if (rate >= 52000000)
+		return 52000000;
+	return -EINVAL;
+}
+
+static unsigned long clk_round_rate_cpuclk(struct clk *clk, unsigned long rate)
+{
+	if (rate >= 13000000)
+		return 13000000;
+	if (rate >= 52000000)
+		return 52000000;
+	if (rate >= 104000000)
+		return 104000000;
+	if (rate >= 208000000)
+		return 208000000;
+	return -EINVAL;
+}
+
+/*
+ * This adjusts a requested rate to the closest exact rate
+ * a certain clock can provide. For a fixed clock it's
+ * mostly clk->rate.
+ */
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	/* TODO: get apropriate switches for EMIFCLK, AHBCLK and MCLK */
+	/* Else default to fixed value */
+
+	if (clk->round_rate) {
+		return (long) clk->round_rate(clk, rate);
+	} else {
+		printk(KERN_ERR "clock: Failed to round rate of %s\n",
+		       clk->name);
+	}
+	return (long) clk->rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+static int clk_set_rate_mclk(struct clk *clk, unsigned long rate)
+{
+	syscon_clk_rate_set_mclk(clk_round_rate(clk, rate));
+	return 0;
+}
+
+static int clk_set_rate_cpuclk(struct clk *clk, unsigned long rate)
+{
+	syscon_clk_rate_set_cpuclk(clk_round_rate(clk, rate));
+	return 0;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	/* TODO: set for EMIFCLK and AHBCLK */
+	/* Else assume the clock is fixed and fail */
+	if (clk->set_rate) {
+		return clk->set_rate(clk, rate);
+	} else {
+		printk(KERN_ERR "clock: Failed to set %s to %ld hz\n",
+		       clk->name, rate);
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+/*
+ * Clock definitions. The clock parents are set to respective
+ * bridge and the clock framework makes sure that the clocks have
+ * parents activated and are brought out of reset when in use.
+ *
+ * Clocks that have hw_ctrld = true are hw controlled, and the hw
+ * can by itself turn these clocks on and off.
+ * So in other words, we don't really have to care about them.
+ */
+
+static struct clk amba_clk = {
+	.name	    = "AMBA",
+	.rate	    = 52000000, /* this varies! */
+	.hw_ctrld   = true,
+	.reset	    = false,
+};
+
+/*
+ * These blocks are connected directly to the AMBA bus
+ * with no bridge.
+ */
+
+static struct clk cpu_clk = {
+	.name	    = "CPU",
+	.parent	    = &amba_clk,
+	.rate	    = 208000000, /* this varies! */
+	.hw_ctrld   = true,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+	.res_mask   = U300_SYSCON_RRR_CPU_RESET_EN,
+	.set_rate   = clk_set_rate_cpuclk,
+	.get_rate   = clk_get_rate_cpuclk,
+	.round_rate = clk_round_rate_cpuclk,
+};
+
+static struct clk nandif_clk = {
+	.name       = "NANDIF",
+	.parent	    = &amba_clk,
+	.hw_ctrld   = false,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+	.res_mask   = U300_SYSCON_RRR_NANDIF_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_NANDIF_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+static struct clk semi_clk = {
+	.name       = "SEMI",
+	.parent	    = &amba_clk,
+	.rate       = 0, /* FIXME */
+	/* It is not possible to reset SEMI */
+	.hw_ctrld   = false,
+	.reset	    = false,
+	.clk_val    = U300_SYSCON_SBCER_SEMI_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+#ifdef CONFIG_MACH_U300_BS335
+static struct clk isp_clk = {
+	.name	    = "ISP",
+	.parent	    = &amba_clk,
+	.rate	    = 0, /* FIXME */
+	.hw_ctrld   = false,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+	.res_mask   = U300_SYSCON_RRR_ISP_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_ISP_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+static struct clk cds_clk = {
+	.name	    = "CDS",
+	.parent	    = &amba_clk,
+	.rate	    = 0, /* FIXME */
+	.hw_ctrld   = false,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+	.res_mask   = U300_SYSCON_RRR_CDS_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_CDS_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+#endif
+
+static struct clk dma_clk = {
+	.name       = "DMA",
+	.parent	    = &amba_clk,
+	.rate       = 52000000, /* this varies! */
+	.hw_ctrld   = true,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+	.res_mask   = U300_SYSCON_RRR_DMAC_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_DMAC_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+static struct clk aaif_clk = {
+	.name       = "AAIF",
+	.parent	    = &amba_clk,
+	.rate       = 52000000, /* this varies! */
+	.hw_ctrld   = true,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+	.res_mask   = U300_SYSCON_RRR_AAIF_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_AAIF_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+static struct clk apex_clk = {
+	.name       = "APEX",
+	.parent	    = &amba_clk,
+	.rate       = 0, /* FIXME */
+	.hw_ctrld   = true,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+	.res_mask   = U300_SYSCON_RRR_APEX_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_APEX_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+static struct clk video_enc_clk = {
+	.name       = "VIDEO_ENC",
+	.parent	    = &amba_clk,
+	.rate       = 208000000, /* this varies! */
+	.hw_ctrld   = false,
+	.reset	    = false,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+	/* This has XGAM in the name but refers to the video encoder */
+	.res_mask   = U300_SYSCON_RRR_XGAM_VC_SYNC_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_VIDEO_ENC_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+static struct clk xgam_clk = {
+	.name       = "XGAMCLK",
+	.parent	    = &amba_clk,
+	.rate       = 52000000, /* this varies! */
+	.hw_ctrld   = false,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+	.res_mask   = U300_SYSCON_RRR_XGAM_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_XGAM_CLK_EN,
+	.get_rate   = clk_get_rate_xgamclk,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+/* This clock is used to activate the video encoder */
+static struct clk ahb_clk = {
+	.name	    = "AHB",
+	.parent	    = &amba_clk,
+	.rate	    = 52000000, /* this varies! */
+	.hw_ctrld   = false, /* This one is set to false due to HW bug */
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+	.res_mask   = U300_SYSCON_RRR_AHB_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_AHB_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+	.get_rate   = clk_get_rate_ahb_clk,
+};
+
+
+/*
+ * Clocks on the AHB bridge
+ */
+
+static struct clk ahb_subsys_clk = {
+	.name	    = "AHB_SUBSYS",
+	.parent	    = &amba_clk,
+	.rate	    = 52000000, /* this varies! */
+	.hw_ctrld   = true,
+	.reset	    = false,
+	.clk_val    = U300_SYSCON_SBCER_AHB_SUBSYS_BRIDGE_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+	.get_rate   = clk_get_rate_ahb_clk,
+};
+
+static struct clk intcon_clk = {
+	.name	    = "INTCON",
+	.parent	    = &ahb_subsys_clk,
+	.rate	    = 52000000, /* this varies! */
+	.hw_ctrld   = false,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+	.res_mask   = U300_SYSCON_RRR_INTCON_RESET_EN,
+	/* INTCON can be reset but not clock-gated */
+};
+
+static struct clk mspro_clk = {
+	.name       = "MSPRO",
+	.parent	    = &ahb_subsys_clk,
+	.rate       = 0, /* FIXME */
+	.hw_ctrld   = false,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+	.res_mask   = U300_SYSCON_RRR_MSPRO_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_MSPRO_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+static struct clk emif_clk = {
+	.name	    = "EMIF",
+	.parent	    = &ahb_subsys_clk,
+	.rate	    = 104000000, /* this varies! */
+	.hw_ctrld   = false,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+	.res_mask   = U300_SYSCON_RRR_EMIF_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_EMIF_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+	.get_rate   = clk_get_rate_emif_clk,
+};
+
+
+/*
+ * Clocks on the FAST bridge
+ */
+static struct clk fast_clk = {
+	.name	    = "FAST_BRIDGE",
+	.parent	    = &amba_clk,
+	.rate	    = 13000000, /* this varies! */
+	.hw_ctrld   = true,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+	.res_mask   = U300_SYSCON_RFR_FAST_BRIDGE_RESET_ENABLE,
+	.clk_val    = U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+static struct clk mmcsd_clk = {
+	.name       = "MCLK",
+	.parent	    = &fast_clk,
+	.rate       = 18900000, /* this varies! */
+	.hw_ctrld   = false,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+	.res_mask   = U300_SYSCON_RFR_MMC_RESET_ENABLE,
+	.clk_val    = U300_SYSCON_SBCER_MMC_CLK_EN,
+	.get_rate   = clk_get_rate_mclk,
+	.set_rate   = clk_set_rate_mclk,
+	.round_rate = clk_round_rate_mclk,
+	.disable    = syscon_clk_disable,
+	.enable     = syscon_clk_enable,
+};
+
+static struct clk i2s0_clk = {
+	.name       = "i2s0",
+	.parent	    = &fast_clk,
+	.rate       = 26000000, /* this varies! */
+	.hw_ctrld   = true,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+	.res_mask   = U300_SYSCON_RFR_PCM_I2S0_RESET_ENABLE,
+	.clk_val    = U300_SYSCON_SBCER_I2S0_CORE_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+	.get_rate   = clk_get_rate_i2s_i2c_spi,
+};
+
+static struct clk i2s1_clk = {
+	.name       = "i2s1",
+	.parent	    = &fast_clk,
+	.rate       = 26000000, /* this varies! */
+	.hw_ctrld   = true,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+	.res_mask   = U300_SYSCON_RFR_PCM_I2S1_RESET_ENABLE,
+	.clk_val    = U300_SYSCON_SBCER_I2S1_CORE_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+	.get_rate   = clk_get_rate_i2s_i2c_spi,
+};
+
+static struct clk i2c0_clk = {
+	.name       = "I2C0",
+	.parent	    = &fast_clk,
+	.rate       = 26000000, /* this varies! */
+	.hw_ctrld   = false,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+	.res_mask   = U300_SYSCON_RFR_I2C0_RESET_ENABLE,
+	.clk_val    = U300_SYSCON_SBCER_I2C0_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+	.get_rate   = clk_get_rate_i2s_i2c_spi,
+};
+
+static struct clk i2c1_clk = {
+	.name       = "I2C1",
+	.parent	    = &fast_clk,
+	.rate       = 26000000, /* this varies! */
+	.hw_ctrld   = false,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+	.res_mask   = U300_SYSCON_RFR_I2C1_RESET_ENABLE,
+	.clk_val    = U300_SYSCON_SBCER_I2C1_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+	.get_rate   = clk_get_rate_i2s_i2c_spi,
+};
+
+static struct clk spi_clk = {
+	.name       = "SPI",
+	.parent	    = &fast_clk,
+	.rate       = 26000000, /* this varies! */
+	.hw_ctrld   = false,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+	.res_mask   = U300_SYSCON_RFR_SPI_RESET_ENABLE,
+	.clk_val    = U300_SYSCON_SBCER_SPI_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+	.get_rate   = clk_get_rate_i2s_i2c_spi,
+};
+
+#ifdef CONFIG_MACH_U300_BS335
+static struct clk uart1_clk = {
+	.name	    = "UART1",
+	.parent	    = &fast_clk,
+	.rate	    = 13000000,
+	.hw_ctrld   = false,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+	.res_mask   = U300_SYSCON_RFR_UART1_RESET_ENABLE,
+	.clk_val    = U300_SYSCON_SBCER_UART1_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+#endif
+
+
+/*
+ * Clocks on the SLOW bridge
+ */
+static struct clk slow_clk = {
+	.name	    = "SLOW_BRIDGE",
+	.parent	    = &amba_clk,
+	.rate	    = 13000000,
+	.hw_ctrld   = true,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+	.res_mask   = U300_SYSCON_RSR_SLOW_BRIDGE_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_SLOW_BRIDGE_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+/* TODO: implement SYSCON clock? */
+
+static struct clk wdog_clk = {
+	.name	    = "WDOG",
+	.parent	    = &slow_clk,
+	.hw_ctrld   = false,
+	.rate	    = 32768,
+	.reset	    = false,
+	/* This is always on, cannot be enabled/disabled or reset */
+};
+
+/* This one is hardwired to PLL13 */
+static struct clk uart_clk = {
+	.name	    = "UARTCLK",
+	.parent	    = &slow_clk,
+	.rate	    = 13000000,
+	.hw_ctrld   = false,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+	.res_mask   = U300_SYSCON_RSR_UART_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_UART_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+static struct clk keypad_clk = {
+	.name       = "KEYPAD",
+	.parent	    = &slow_clk,
+	.rate       = 32768,
+	.hw_ctrld   = false,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+	.res_mask   = U300_SYSCON_RSR_KEYPAD_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_KEYPAD_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+static struct clk gpio_clk = {
+	.name       = "GPIO",
+	.parent	    = &slow_clk,
+	.rate       = 13000000,
+	.hw_ctrld   = true,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+	.res_mask   = U300_SYSCON_RSR_GPIO_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_GPIO_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+static struct clk rtc_clk = {
+	.name	    = "RTC",
+	.parent	    = &slow_clk,
+	.rate	    = 32768,
+	.hw_ctrld   = true,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+	.res_mask   = U300_SYSCON_RSR_RTC_RESET_EN,
+	/* This clock is always on, cannot be enabled/disabled */
+};
+
+static struct clk bustr_clk = {
+	.name       = "BUSTR",
+	.parent	    = &slow_clk,
+	.rate       = 13000000,
+	.hw_ctrld   = true,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+	.res_mask   = U300_SYSCON_RSR_BTR_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_BTR_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+static struct clk evhist_clk = {
+	.name       = "EVHIST",
+	.parent	    = &slow_clk,
+	.rate       = 13000000,
+	.hw_ctrld   = true,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+	.res_mask   = U300_SYSCON_RSR_EH_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_EH_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+static struct clk timer_clk = {
+	.name       = "TIMER",
+	.parent	    = &slow_clk,
+	.rate       = 13000000,
+	.hw_ctrld   = true,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+	.res_mask   = U300_SYSCON_RSR_ACC_TMR_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_ACC_TMR_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+static struct clk app_timer_clk = {
+	.name       = "TIMER_APP",
+	.parent	    = &slow_clk,
+	.rate       = 13000000,
+	.hw_ctrld   = true,
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+	.res_mask   = U300_SYSCON_RSR_APP_TMR_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_APP_TMR_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+
+#ifdef CONFIG_MACH_U300_BS335
+static struct clk ppm_clk = {
+	.name	    = "PPM",
+	.parent	    = &slow_clk,
+	.rate	    = 0, /* FIXME */
+	.hw_ctrld   = true, /* TODO: Look up if it is hw ctrld or not */
+	.reset	    = true,
+	.res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+	.res_mask   = U300_SYSCON_RSR_PPM_RESET_EN,
+	.clk_val    = U300_SYSCON_SBCER_PPM_CLK_EN,
+	.enable     = syscon_clk_enable,
+	.disable    = syscon_clk_disable,
+};
+#endif
+
+#define DEF_LOOKUP(devid, clkref)		\
+	{					\
+	.dev_id = devid,			\
+	.clk = clkref,				\
+	}
+
+/*
+ * Here we only define clocks that are meaningful to
+ * look up through clockdevice.
+ */
+static struct clk_lookup lookups[] = {
+	/* Connected directly to the AMBA bus */
+	DEF_LOOKUP("amba", &amba_clk),
+	DEF_LOOKUP("cpu", &cpu_clk),
+	DEF_LOOKUP("nandif", &nandif_clk),
+	DEF_LOOKUP("semi", &semi_clk),
+#ifdef CONFIG_MACH_U300_BS335
+	DEF_LOOKUP("isp", &isp_clk),
+	DEF_LOOKUP("cds", &cds_clk),
+#endif
+	DEF_LOOKUP("dma", &dma_clk),
+	DEF_LOOKUP("aaif", &aaif_clk),
+	DEF_LOOKUP("apex", &apex_clk),
+	DEF_LOOKUP("video_enc", &video_enc_clk),
+	DEF_LOOKUP("xgam", &xgam_clk),
+	DEF_LOOKUP("ahb", &ahb_clk),
+	/* AHB bridge clocks */
+	DEF_LOOKUP("ahb", &ahb_subsys_clk),
+	DEF_LOOKUP("intcon", &intcon_clk),
+	DEF_LOOKUP("mspro", &mspro_clk),
+	DEF_LOOKUP("pl172", &emif_clk),
+	/* FAST bridge clocks */
+	DEF_LOOKUP("fast", &fast_clk),
+	DEF_LOOKUP("mmci", &mmcsd_clk),
+	/*
+	 * The .0 and .1 identifiers on these comes from the platform device
+	 * .id field and are assigned when the platform devices are registered.
+	 */
+	DEF_LOOKUP("i2s.0", &i2s0_clk),
+	DEF_LOOKUP("i2s.1", &i2s1_clk),
+	DEF_LOOKUP("stddci2c.0", &i2c0_clk),
+	DEF_LOOKUP("stddci2c.1", &i2c1_clk),
+	DEF_LOOKUP("pl022", &spi_clk),
+#ifdef CONFIG_MACH_U300_BS335
+	DEF_LOOKUP("uart1", &uart1_clk),
+#endif
+	/* SLOW bridge clocks */
+	DEF_LOOKUP("slow", &slow_clk),
+	DEF_LOOKUP("wdog", &wdog_clk),
+	DEF_LOOKUP("uart0", &uart_clk),
+	DEF_LOOKUP("apptimer", &app_timer_clk),
+	DEF_LOOKUP("keypad", &keypad_clk),
+	DEF_LOOKUP("u300-gpio", &gpio_clk),
+	DEF_LOOKUP("rtc0", &rtc_clk),
+	DEF_LOOKUP("bustr", &bustr_clk),
+	DEF_LOOKUP("evhist", &evhist_clk),
+	DEF_LOOKUP("timer", &timer_clk),
+#ifdef CONFIG_MACH_U300_BS335
+	DEF_LOOKUP("ppm", &ppm_clk),
+#endif
+};
+
+static void __init clk_register(void)
+{
+	int i;
+
+	/* Register the lookups */
+	for (i = 0; i < ARRAY_SIZE(lookups); i++)
+		clkdev_add(&lookups[i]);
+}
+
+/*
+ * These are the clocks for cells registered as primecell drivers
+ * on the AMBA bus. These must be on during AMBA device registration
+ * since the bus probe will attempt to read magic configuration
+ * registers for these devices. If they are deactivated these probes
+ * will fail.
+ *
+ *
+ * Please note that on emif, both RAM and NAND is connected in dual
+ * RAM phones. On single RAM phones, ram is on semi and NAND on emif.
+ *
+ */
+void u300_clock_primecells(void)
+{
+	clk_enable(&intcon_clk);
+	clk_enable(&uart_clk);
+#ifdef CONFIG_MACH_U300_BS335
+	clk_enable(&uart1_clk);
+#endif
+	clk_enable(&spi_clk);
+
+	clk_enable(&mmcsd_clk);
+
+}
+EXPORT_SYMBOL(u300_clock_primecells);
+
+void u300_unclock_primecells(void)
+{
+
+	clk_disable(&intcon_clk);
+	clk_disable(&uart_clk);
+#ifdef CONFIG_MACH_U300_BS335
+	clk_disable(&uart1_clk);
+#endif
+	clk_disable(&spi_clk);
+	clk_disable(&mmcsd_clk);
+
+}
+EXPORT_SYMBOL(u300_unclock_primecells);
+
+/*
+ * The interrupt controller is enabled before the clock API is registered.
+ */
+void u300_enable_intcon_clock(void)
+{
+	clk_enable(&intcon_clk);
+}
+EXPORT_SYMBOL(u300_enable_intcon_clock);
+
+/*
+ * The timer is enabled before the clock API is registered.
+ */
+void u300_enable_timer_clock(void)
+{
+	clk_enable(&app_timer_clk);
+}
+EXPORT_SYMBOL(u300_enable_timer_clock);
+
+#if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_U300_DEBUG))
+/*
+ * The following makes it possible to view the status (especially
+ * reference count and reset status) for the clocks in the platform
+ * by looking into the special file <debugfs>/u300_clocks
+ */
+
+/* A list of all clocks in the platform */
+static struct clk *clks[] = {
+	/* Top node clock for the AMBA bus */
+	&amba_clk,
+	/* Connected directly to the AMBA bus */
+	&cpu_clk,
+	&nandif_clk,
+	&semi_clk,
+#ifdef CONFIG_MACH_U300_BS335
+	&isp_clk,
+	&cds_clk,
+#endif
+	&dma_clk,
+	&aaif_clk,
+	&apex_clk,
+	&video_enc_clk,
+	&xgam_clk,
+	&ahb_clk,
+
+	/* AHB bridge clocks */
+	&ahb_subsys_clk,
+	&intcon_clk,
+	&mspro_clk,
+	&emif_clk,
+	/* FAST bridge clocks */
+	&fast_clk,
+	&mmcsd_clk,
+	&i2s0_clk,
+	&i2s1_clk,
+	&i2c0_clk,
+	&i2c1_clk,
+	&spi_clk,
+#ifdef CONFIG_MACH_U300_BS335
+	&uart1_clk,
+#endif
+	/* SLOW bridge clocks */
+	&slow_clk,
+	&wdog_clk,
+	&uart_clk,
+	&app_timer_clk,
+	&keypad_clk,
+	&gpio_clk,
+	&rtc_clk,
+	&bustr_clk,
+	&evhist_clk,
+	&timer_clk,
+#ifdef CONFIG_MACH_U300_BS335
+	&ppm_clk,
+#endif
+};
+
+static int u300_clocks_show(struct seq_file *s, void *data)
+{
+	struct clk *clk;
+	int i;
+
+	seq_printf(s, "CLOCK           DEVICE          RESET STATE\t" \
+		   "ACTIVE\tUSERS\tHW CTRL FREQ\n");
+	seq_printf(s, "---------------------------------------------" \
+		   "-----------------------------------------\n");
+	for (i = 0; i < ARRAY_SIZE(clks); i++) {
+		clk = clks[i];
+		if (clk != ERR_PTR(-ENOENT)) {
+			/* Format clock and device name nicely */
+			char cdp[33];
+			int chars;
+
+			chars = snprintf(&cdp[0], 17, "%s", clk->name);
+			while (chars < 16) {
+				cdp[chars] = ' ';
+				chars++;
+			}
+			chars = snprintf(&cdp[16], 17, "%s", clk->dev ?
+					 dev_name(clk->dev) : "N/A");
+			while (chars < 16) {
+				cdp[chars+16] = ' ';
+				chars++;
+			}
+			cdp[32] = '\0';
+			if (clk->get_rate)
+				seq_printf(s,
+					   "%s%s\t%s\t%d\t%s\t%lu Hz\n",
+					   &cdp[0],
+					   clk->reset ?
+					   "ASSERTED" : "RELEASED",
+					   clk->usecount ? "ON" : "OFF",
+					   clk->usecount,
+					   clk->hw_ctrld  ? "YES" : "NO ",
+					   clk->get_rate(clk));
+			else
+				seq_printf(s,
+					   "%s%s\t%s\t%d\t%s\t" \
+					   "(unknown rate)\n",
+					   &cdp[0],
+					   clk->reset ?
+					   "ASSERTED" : "RELEASED",
+					   clk->usecount ? "ON" : "OFF",
+					   clk->usecount,
+					   clk->hw_ctrld  ? "YES" : "NO ");
+		}
+	}
+	return 0;
+}
+
+static int u300_clocks_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, u300_clocks_show, NULL);
+}
+
+static const struct file_operations u300_clocks_operations = {
+	.open		= u300_clocks_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void init_clk_read_procfs(void)
+{
+	/* Expose a simple debugfs interface to view all clocks */
+	(void) debugfs_create_file("u300_clocks", S_IFREG | S_IRUGO,
+				   NULL, NULL, &u300_clocks_operations);
+}
+#else
+static inline void init_clk_read_procfs(void)
+{
+}
+#endif
+
+static int __init u300_clock_init(void)
+{
+	u16 val;
+
+	/*
+	 * FIXME: shall all this powermanagement stuff really live here???
+	 */
+
+	/* Set system to run at PLL208, max performance, a known state. */
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	val &= ~U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	/* Wait for the PLL208 to lock if not locked in yet */
+	while (!(readw(U300_SYSCON_VBASE + U300_SYSCON_CSR) &
+		 U300_SYSCON_CSR_PLL208_LOCK_IND));
+
+	/* Power management enable */
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_PMCR);
+	val |= U300_SYSCON_PMCR_PWR_MGNT_ENABLE;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_PMCR);
+
+	clk_register();
+
+	init_clk_read_procfs();
+
+	/*
+	 * Some of these may be on when we boot the system so make sure they
+	 * are turned OFF.
+	 */
+	syscon_block_reset_enable(&timer_clk);
+	timer_clk.disable(&timer_clk);
+
+	/*
+	 * These shall be turned on by default when we boot the system
+	 * so make sure they are ON. (Adding CPU here is a bit too much.)
+	 * These clocks will be claimed by drivers later.
+	 */
+	syscon_block_reset_disable(&semi_clk);
+	syscon_block_reset_disable(&emif_clk);
+	semi_clk.enable(&semi_clk);
+	emif_clk.enable(&emif_clk);
+
+	return 0;
+}
+/* initialize clocking early to be available later in the boot */
+core_initcall(u300_clock_init);
diff --git a/arch/arm/mach-u300/clock.h b/arch/arm/mach-u300/clock.h
new file mode 100644
index 0000000..fc6d9cc
--- /dev/null
+++ b/arch/arm/mach-u300/clock.h
@@ -0,0 +1,53 @@
+/*
+ * arch/arm/mach-u300/include/mach/clock.h
+ *
+ * Copyright (C) 2004 - 2005 Nokia corporation
+ * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * Adopted to ST-Ericsson U300 platforms by
+ * Jonas Aaberg <jonas.aberg@stericsson.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 __MACH_CLOCK_H
+#define __MACH_CLOCK_H
+
+#include <linux/clk.h>
+
+struct clk {
+	struct list_head node;
+	struct module *owner;
+	struct device *dev;
+	const char *name;
+	struct clk *parent;
+
+	spinlock_t lock;
+	unsigned long rate;
+	bool reset;
+	__u16 clk_val;
+	__s8 usecount;
+	__u32 res_reg;
+	__u16 res_mask;
+
+	bool hw_ctrld;
+
+	void (*recalc) (struct clk *);
+	int (*set_rate) (struct clk *, unsigned long);
+	unsigned long (*get_rate) (struct clk *);
+	unsigned long (*round_rate) (struct clk *, unsigned long);
+	void (*init) (struct clk *);
+	void (*enable) (struct clk *);
+	void (*disable) (struct clk *);
+};
+
+void u300_clock_primecells(void);
+void u300_unclock_primecells(void);
+void u300_enable_intcon_clock(void);
+void u300_enable_timer_clock(void);
+
+#endif
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
new file mode 100644
index 0000000..89b3ccf
--- /dev/null
+++ b/arch/arm/mach-u300/core.c
@@ -0,0 +1,649 @@
+/*
+ *
+ * arch/arm/mach-u300/core.c
+ *
+ *
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Core platform support, IRQ handling and device definitions.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/termios.h>
+#include <linux/amba/bus.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <asm/types.h>
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/hardware/vic.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/syscon.h>
+
+#include "clock.h"
+#include "mmc.h"
+
+/*
+ * Static I/O mappings that are needed for booting the U300 platforms. The
+ * only things we need are the areas where we find the timer, syscon and
+ * intcon, since the remaining device drivers will map their own memory
+ * physical to virtual as the need arise.
+ */
+static struct map_desc u300_io_desc[] __initdata = {
+	{
+		.virtual	= U300_SLOW_PER_VIRT_BASE,
+		.pfn		= __phys_to_pfn(U300_SLOW_PER_PHYS_BASE),
+		.length		= SZ_64K,
+		.type		= MT_DEVICE,
+	},
+	{
+		.virtual	= U300_AHB_PER_VIRT_BASE,
+		.pfn		= __phys_to_pfn(U300_AHB_PER_PHYS_BASE),
+		.length		= SZ_32K,
+		.type		= MT_DEVICE,
+	},
+	{
+		.virtual	= U300_FAST_PER_VIRT_BASE,
+		.pfn		= __phys_to_pfn(U300_FAST_PER_PHYS_BASE),
+		.length		= SZ_32K,
+		.type		= MT_DEVICE,
+	},
+	{
+		.virtual	= 0xffff2000, /* TCM memory */
+		.pfn		= __phys_to_pfn(0xffff2000),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+	},
+
+	/*
+	 * This overlaps with the IRQ vectors etc at 0xffff0000, so these
+	 * may have to be moved to 0x00000000 in order to use the ROM.
+	 */
+	/*
+	{
+		.virtual	= U300_BOOTROM_VIRT_BASE,
+		.pfn		= __phys_to_pfn(U300_BOOTROM_PHYS_BASE),
+		.length		= SZ_64K,
+		.type		= MT_ROM,
+	},
+	*/
+};
+
+void __init u300_map_io(void)
+{
+	iotable_init(u300_io_desc, ARRAY_SIZE(u300_io_desc));
+}
+
+/*
+ * Declaration of devices found on the U300 board and
+ * their respective memory locations.
+ */
+static struct amba_device uart0_device = {
+	.dev = {
+		.init_name = "uart0", /* Slow device at 0x3000 offset */
+		.platform_data = NULL,
+	},
+	.res = {
+		.start = U300_UART0_BASE,
+		.end   = U300_UART0_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	.irq = { IRQ_U300_UART0, NO_IRQ },
+};
+
+/* The U335 have an additional UART1 on the APP CPU */
+#ifdef CONFIG_MACH_U300_BS335
+static struct amba_device uart1_device = {
+	.dev = {
+		.init_name = "uart1", /* Fast device at 0x7000 offset */
+		.platform_data = NULL,
+	},
+	.res = {
+		.start = U300_UART1_BASE,
+		.end   = U300_UART1_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	.irq = { IRQ_U300_UART1, NO_IRQ },
+};
+#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,
+	},
+};
+
+
+/*
+ * 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 },
+	/*
+	 * This device has a DMA channel but the Linux driver does not use
+	 * it currently.
+	 */
+};
+
+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.
+	 */
+};
+
+/*
+ * The order of device declaration may be important, since some devices
+ * have dependencies on other devices being initialized first.
+ */
+static struct amba_device *amba_devs[] __initdata = {
+	&uart0_device,
+#ifdef CONFIG_MACH_U300_BS335
+	&uart1_device,
+#endif
+	&pl022_device,
+	&pl172_device,
+	&mmcsd_device,
+};
+
+/* Here follows a list of all hw resources that the platform devices
+ * allocate. Note, clock dependencies are not included
+ */
+
+static struct resource gpio_resources[] = {
+	{
+		.start = U300_GPIO_BASE,
+		.end   = (U300_GPIO_BASE + SZ_4K - 1),
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "gpio0",
+		.start = IRQ_U300_GPIO_PORT0,
+		.end   = IRQ_U300_GPIO_PORT0,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name  = "gpio1",
+		.start = IRQ_U300_GPIO_PORT1,
+		.end   = IRQ_U300_GPIO_PORT1,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name  = "gpio2",
+		.start = IRQ_U300_GPIO_PORT2,
+		.end   = IRQ_U300_GPIO_PORT2,
+		.flags = IORESOURCE_IRQ,
+	},
+#ifdef U300_COH901571_3
+	{
+		.name  = "gpio3",
+		.start = IRQ_U300_GPIO_PORT3,
+		.end   = IRQ_U300_GPIO_PORT3,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name  = "gpio4",
+		.start = IRQ_U300_GPIO_PORT4,
+		.end   = IRQ_U300_GPIO_PORT4,
+		.flags = IORESOURCE_IRQ,
+	},
+#ifdef CONFIG_MACH_U300_BS335
+	{
+		.name  = "gpio5",
+		.start = IRQ_U300_GPIO_PORT5,
+		.end   = IRQ_U300_GPIO_PORT5,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name  = "gpio6",
+		.start = IRQ_U300_GPIO_PORT6,
+		.end   = IRQ_U300_GPIO_PORT6,
+		.flags = IORESOURCE_IRQ,
+	},
+#endif /* CONFIG_MACH_U300_BS335 */
+#endif /* U300_COH901571_3 */
+};
+
+static struct resource keypad_resources[] = {
+	{
+		.start = U300_KEYPAD_BASE,
+		.end   = U300_KEYPAD_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "coh901461-press",
+		.start = IRQ_U300_KEYPAD_KEYBF,
+		.end   = IRQ_U300_KEYPAD_KEYBF,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name  = "coh901461-release",
+		.start = IRQ_U300_KEYPAD_KEYBR,
+		.end   = IRQ_U300_KEYPAD_KEYBR,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource rtc_resources[] = {
+	{
+		.start = U300_RTC_BASE,
+		.end   = U300_RTC_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_U300_RTC,
+		.end   = IRQ_U300_RTC,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+/*
+ * Fsmc does have IRQs: #43 and #44 (NFIF and NFIF2)
+ * but these are not yet used by the driver.
+ */
+static struct resource fsmc_resources[] = {
+	{
+		.start = U300_NAND_IF_PHYS_BASE,
+		.end   = U300_NAND_IF_PHYS_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct resource i2c0_resources[] = {
+	{
+		.start = U300_I2C0_BASE,
+		.end   = U300_I2C0_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_U300_I2C0,
+		.end   = IRQ_U300_I2C0,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource i2c1_resources[] = {
+	{
+		.start = U300_I2C1_BASE,
+		.end   = U300_I2C1_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_U300_I2C1,
+		.end   = IRQ_U300_I2C1,
+		.flags = IORESOURCE_IRQ,
+	},
+
+};
+
+static struct resource wdog_resources[] = {
+	{
+		.start = U300_WDOG_BASE,
+		.end   = U300_WDOG_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_U300_WDOG,
+		.end   = IRQ_U300_WDOG,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+/* TODO: These should be protected by suitable #ifdef's */
+static struct resource ave_resources[] = {
+	{
+		.name  = "AVE3e I/O Area",
+		.start = U300_VIDEOENC_BASE,
+		.end   = U300_VIDEOENC_BASE + SZ_512K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "AVE3e IRQ0",
+		.start = IRQ_U300_VIDEO_ENC_0,
+		.end   = IRQ_U300_VIDEO_ENC_0,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name  = "AVE3e IRQ1",
+		.start = IRQ_U300_VIDEO_ENC_1,
+		.end   = IRQ_U300_VIDEO_ENC_1,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name  = "AVE3e Physmem Area",
+		.start = 0, /* 0 will be remapped to reserved memory */
+		.end   = SZ_1M - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	/*
+	 * The AVE3e requires two regions of 256MB that it considers
+	 * "invisible". The hardware will not be able to access these
+	 * adresses, so they should never point to system RAM.
+	 */
+	{
+		.name  = "AVE3e Reserved 0",
+		.start = 0xd0000000,
+		.end   = 0xd0000000 + SZ_256M - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "AVE3e Reserved 1",
+		.start = 0xe0000000,
+		.end   = 0xe0000000 + SZ_256M - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device wdog_device = {
+	.name = "wdog",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(wdog_resources),
+	.resource = wdog_resources,
+};
+
+static struct platform_device i2c0_device = {
+	.name = "stddci2c",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(i2c0_resources),
+	.resource = i2c0_resources,
+};
+
+static struct platform_device i2c1_device = {
+	.name = "stddci2c",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(i2c1_resources),
+	.resource = i2c1_resources,
+};
+
+static struct platform_device gpio_device = {
+	.name = "u300-gpio",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(gpio_resources),
+	.resource = gpio_resources,
+};
+
+static struct platform_device keypad_device = {
+	.name = "keypad",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(keypad_resources),
+	.resource = keypad_resources,
+};
+
+static struct platform_device rtc_device = {
+	.name = "rtc0",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(rtc_resources),
+	.resource = rtc_resources,
+};
+
+static struct platform_device fsmc_device = {
+	.name = "nandif",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(fsmc_resources),
+	.resource = fsmc_resources,
+};
+
+static struct platform_device ave_device = {
+	.name = "video_enc",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(ave_resources),
+	.resource = ave_resources,
+};
+
+/*
+ * Notice that AMBA devices are initialized before platform devices.
+ *
+ */
+static struct platform_device *platform_devs[] __initdata = {
+	&i2c0_device,
+	&i2c1_device,
+	&keypad_device,
+	&rtc_device,
+	&gpio_device,
+	&fsmc_device,
+	&wdog_device,
+	&ave_device
+};
+
+
+/*
+ * Interrupts: the U300 platforms have two pl190 ARM PrimeCells connected
+ * together so some interrupts are connected to the first one and some
+ * to the second one.
+ */
+void __init u300_init_irq(void)
+{
+	u32 mask[2] = {0, 0};
+	int i;
+
+	for (i = 0; i < NR_IRQS; i++)
+		set_bit(i, (unsigned long *) &mask[0]);
+	u300_enable_intcon_clock();
+	vic_init((void __iomem *) U300_INTCON0_VBASE, 0, mask[0], 0);
+	vic_init((void __iomem *) U300_INTCON1_VBASE, 32, mask[1], 0);
+}
+
+
+/*
+ * U300 platforms peripheral handling
+ */
+struct db_chip {
+	u16 chipid;
+	const char *name;
+};
+
+/*
+ * This is a list of the Digital Baseband chips used in the U300 platform.
+ */
+static struct db_chip db_chips[] __initdata = {
+	{
+		.chipid = 0xb800,
+		.name = "DB3000",
+	},
+	{
+		.chipid = 0xc000,
+		.name = "DB3100",
+	},
+	{
+		.chipid = 0xc800,
+		.name = "DB3150",
+	},
+	{
+		.chipid = 0xd800,
+		.name = "DB3200",
+	},
+	{
+		.chipid = 0xe000,
+		.name = "DB3250",
+	},
+	{
+		.chipid = 0xe800,
+		.name = "DB3210",
+	},
+	{
+		.chipid = 0xf000,
+		.name = "DB3350 P1x",
+	},
+	{
+		.chipid = 0xf100,
+		.name = "DB3350 P2x",
+	},
+	{
+		.chipid = 0x0000, /* List terminator */
+		.name = NULL,
+	}
+};
+
+static void u300_init_check_chip(void)
+{
+
+	u16 val;
+	struct db_chip *chip;
+	const char *chipname;
+	const char unknown[] = "UNKNOWN";
+
+	/* Read out and print chip ID */
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_CIDR);
+	/* This is in funky bigendian order... */
+	val = (val & 0xFFU) << 8 | (val >> 8);
+	chip = db_chips;
+	chipname = unknown;
+
+	for ( ; chip->chipid; chip++) {
+		if (chip->chipid == (val & 0xFF00U)) {
+			chipname = chip->name;
+			break;
+		}
+	}
+	printk(KERN_INFO "Initializing U300 system on %s baseband chip " \
+	       "(chip ID 0x%04x)\n", chipname, val);
+
+#ifdef CONFIG_MACH_U300_BS26
+	if ((val & 0xFF00U) != 0xc800) {
+		printk(KERN_ERR "Platform configured for BS25/BS26 " \
+		       "with DB3150 but %s detected, expect problems!",
+		       chipname);
+	}
+#endif
+#ifdef CONFIG_MACH_U300_BS330
+	if ((val & 0xFF00U) != 0xd800) {
+		printk(KERN_ERR "Platform configured for BS330 " \
+		       "with DB3200 but %s detected, expect problems!",
+		       chipname);
+	}
+#endif
+#ifdef CONFIG_MACH_U300_BS335
+	if ((val & 0xFF00U) != 0xf000 && (val & 0xFF00U) != 0xf100) {
+		printk(KERN_ERR "Platform configured for BS365 " \
+		       " with DB3350 but %s detected, expect problems!",
+		       chipname);
+	}
+#endif
+#ifdef CONFIG_MACH_U300_BS365
+	if ((val & 0xFF00U) != 0xe800) {
+		printk(KERN_ERR "Platform configured for BS365 " \
+		       "with DB3210 but %s detected, expect problems!",
+		       chipname);
+	}
+#endif
+
+
+}
+
+/*
+ * Some devices and their resources require reserved physical memory from
+ * the end of the available RAM. This function traverses the list of devices
+ * and assigns actual adresses to these.
+ */
+static void __init u300_assign_physmem(void)
+{
+	unsigned long curr_start = __pa(high_memory);
+	int i, j;
+
+	for (i = 0; i < ARRAY_SIZE(platform_devs); i++) {
+		for (j = 0; j < platform_devs[i]->num_resources; j++) {
+			struct resource *const res =
+			  &platform_devs[i]->resource[j];
+
+			if (IORESOURCE_MEM == res->flags &&
+				     0 == res->start) {
+				res->start  = curr_start;
+				res->end   += curr_start;
+				curr_start += (res->end - res->start + 1);
+
+				printk(KERN_INFO "core.c: Mapping RAM " \
+				       "%#x-%#x to device %s:%s\n",
+					res->start, res->end,
+				       platform_devs[i]->name, res->name);
+			}
+		}
+	}
+}
+
+void __init u300_init_devices(void)
+{
+	int i;
+	u16 val;
+
+	/* Check what platform we run and print some status information */
+	u300_init_check_chip();
+
+	/* Set system to run at PLL208, max performance, a known state. */
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	val &= ~U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+	/* Wait for the PLL208 to lock if not locked in yet */
+	while (!(readw(U300_SYSCON_VBASE + U300_SYSCON_CSR) &
+		 U300_SYSCON_CSR_PLL208_LOCK_IND));
+
+	/* Register the AMBA devices in the AMBA bus abstraction layer */
+	u300_clock_primecells();
+	for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+		struct amba_device *d = amba_devs[i];
+		amba_device_register(d, &iomem_resource);
+	}
+	u300_unclock_primecells();
+
+	u300_assign_physmem();
+
+	/* Register the platform devices */
+	platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
+
+#ifndef CONFIG_MACH_U300_SEMI_IS_SHARED
+	/*
+	 * Enable SEMI self refresh. Self-refresh of the SDRAM is entered when
+	 * both subsystems are requesting this mode.
+	 * If we not share the Acc SDRAM, this is never the case. Therefore
+	 * enable it here from the App side.
+	 */
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_SMCR) |
+		U300_SYSCON_SMCR_SEMI_SREFREQ_ENABLE;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_SMCR);
+#endif /* CONFIG_MACH_U300_SEMI_IS_SHARED */
+}
+
+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);
diff --git a/arch/arm/mach-u300/gpio.c b/arch/arm/mach-u300/gpio.c
new file mode 100644
index 0000000..308cdb1
--- /dev/null
+++ b/arch/arm/mach-u300/gpio.c
@@ -0,0 +1,703 @@
+/*
+ *
+ * arch/arm/mach-u300/gpio.c
+ *
+ *
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * U300 GPIO module.
+ * This can driver either of the two basic GPIO cores
+ * available in the U300 platforms:
+ * COH 901 335   - Used in DB3150 (U300 1.0) and DB3200 (U330 1.0)
+ * COH 901 571/3 - Used in DB3210 (U365 2.0) and DB3350 (U335 1.0)
+ * Notice that you also have inline macros in <asm-arch/gpio.h>
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ *
+ */
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+/* Need access to SYSCON registers for PADmuxing */
+#include <mach/syscon.h>
+
+#include "padmux.h"
+
+/* Reference to GPIO block clock */
+static struct clk *clk;
+
+/* Memory resource */
+static struct resource *memres;
+static void __iomem *virtbase;
+static struct device *gpiodev;
+
+struct u300_gpio_port {
+	const char *name;
+	int irq;
+	int number;
+};
+
+
+static struct u300_gpio_port gpio_ports[] = {
+	{
+		.name = "gpio0",
+		.number = 0,
+	},
+	{
+		.name = "gpio1",
+		.number = 1,
+	},
+	{
+		.name = "gpio2",
+		.number = 2,
+	},
+#ifdef U300_COH901571_3
+	{
+		.name = "gpio3",
+		.number = 3,
+	},
+	{
+		.name = "gpio4",
+		.number = 4,
+	},
+#ifdef CONFIG_MACH_U300_BS335
+	{
+		.name = "gpio5",
+		.number = 5,
+	},
+	{
+		.name = "gpio6",
+		.number = 6,
+	},
+#endif
+#endif
+
+};
+
+
+#ifdef U300_COH901571_3
+
+/* Default input value */
+#define DEFAULT_OUTPUT_LOW   0
+#define DEFAULT_OUTPUT_HIGH  1
+
+/* GPIO Pull-Up status */
+#define DISABLE_PULL_UP  0
+#define ENABLE_PULL_UP  1
+
+#define GPIO_NOT_USED 0
+#define GPIO_IN       1
+#define GPIO_OUT      2
+
+struct u300_gpio_configuration_data {
+	unsigned char pin_usage;
+	unsigned char default_output_value;
+	unsigned char pull_up;
+};
+
+/* Initial configuration */
+const struct u300_gpio_configuration_data
+u300_gpio_config[U300_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
+#ifdef CONFIG_MACH_U300_BS335
+	/* Port 0, pins 0-7 */
+	{
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_HIGH,  DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+	},
+	/* Port 1, pins 0-7 */
+	{
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_HIGH,  DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+	},
+	/* Port 2, pins 0-7 */
+	{
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP}
+	},
+	/* Port 3, pins 0-7 */
+	{
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+	},
+	/* Port 4, pins 0-7 */
+	{
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+	},
+	/* Port 5, pins 0-7 */
+	{
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+	},
+	/* Port 6, pind 0-7 */
+	{
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+	}
+#endif
+
+#ifdef CONFIG_MACH_U300_BS365
+	/* Port 0, pins 0-7 */
+	{
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+	},
+	/* Port 1, pins 0-7 */
+	{
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_HIGH,  DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+	},
+	/* Port 2, pins 0-7 */
+	{
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP}
+	},
+	/* Port 3, pins 0-7 */
+	{
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP}
+	},
+	/* Port 4, pins 0-7 */
+	{
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		/* These 4 pins doesn't exist on DB3210 */
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+		{GPIO_OUT, DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP}
+	}
+#endif
+};
+#endif
+
+
+/* No users == we can power down GPIO */
+static int gpio_users;
+
+struct gpio_struct {
+	int (*callback)(void *);
+	void *data;
+	int users;
+};
+
+static struct gpio_struct gpio_pin[U300_GPIO_MAX];
+
+/*
+ * Let drivers register callback in order to get notified when there is
+ * an interrupt on the gpio pin
+ */
+int gpio_register_callback(unsigned gpio, int (*func)(void *arg), void *data)
+{
+	if (gpio_pin[gpio].callback)
+		dev_warn(gpiodev, "%s: WARNING: callback already "
+			 "registered for gpio pin#%d\n", __func__, gpio);
+	gpio_pin[gpio].callback = func;
+	gpio_pin[gpio].data = data;
+
+	return 0;
+}
+EXPORT_SYMBOL(gpio_register_callback);
+
+int gpio_unregister_callback(unsigned gpio)
+{
+	if (!gpio_pin[gpio].callback)
+		dev_warn(gpiodev, "%s: WARNING: callback already "
+			 "unregistered for gpio pin#%d\n", __func__, gpio);
+	gpio_pin[gpio].callback = NULL;
+	gpio_pin[gpio].data = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL(gpio_unregister_callback);
+
+int gpio_request(unsigned gpio, const char *label)
+{
+	if (gpio_pin[gpio].users)
+		return -EINVAL;
+	else
+		gpio_pin[gpio].users++;
+
+	gpio_users++;
+
+	return 0;
+}
+EXPORT_SYMBOL(gpio_request);
+
+void gpio_free(unsigned gpio)
+{
+	gpio_users--;
+	gpio_pin[gpio].users--;
+	if (unlikely(gpio_pin[gpio].users < 0)) {
+		dev_warn(gpiodev, "warning: gpio#%d release mismatch\n",
+			 gpio);
+		gpio_pin[gpio].users = 0;
+	}
+
+	return;
+}
+EXPORT_SYMBOL(gpio_free);
+
+/* This returns zero or nonzero */
+int gpio_get_value(unsigned gpio)
+{
+	return readl(virtbase + U300_GPIO_PXPDIR +
+	  PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) & (1 << (gpio & 0x07));
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+/*
+ * We hope that the compiler will optimize away the unused branch
+ * in case "value" is a constant
+ */
+void gpio_set_value(unsigned gpio, int value)
+{
+	u32 val;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (value) {
+		/* set */
+		val = readl(virtbase + U300_GPIO_PXPDOR +
+		  PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING)
+		  & (1 << (gpio & 0x07));
+		writel(val | (1 << (gpio & 0x07)), virtbase +
+		  U300_GPIO_PXPDOR +
+		  PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING);
+	} else {
+		/* clear */
+		val = readl(virtbase + U300_GPIO_PXPDOR +
+		  PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING)
+		  & (1 << (gpio & 0x07));
+		writel(val & ~(1 << (gpio & 0x07)), virtbase +
+		  U300_GPIO_PXPDOR +
+		  PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING);
+	}
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_set_value);
+
+int gpio_direction_input(unsigned gpio)
+{
+	unsigned long flags;
+	u32 val;
+
+	if (gpio > U300_GPIO_MAX)
+		return -EINVAL;
+
+	local_irq_save(flags);
+	val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) *
+				U300_GPIO_PORTX_SPACING);
+	/* Mask out this pin*/
+	val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1));
+	/* This is not needed since it sets the bits to zero.*/
+	/* val |= (U300_GPIO_PXPCR_PIN_MODE_INPUT << (gpio*2)); */
+	writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) *
+				U300_GPIO_PORTX_SPACING);
+	local_irq_restore(flags);
+	return 0;
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+	unsigned long flags;
+	u32 val;
+
+	if (gpio > U300_GPIO_MAX)
+		return -EINVAL;
+
+	local_irq_save(flags);
+	val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) *
+				U300_GPIO_PORTX_SPACING);
+	/* Mask out this pin */
+	val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1));
+	/*
+	 * FIXME: configure for push/pull, open drain or open source per pin
+	 * in setup. The current driver will only support push/pull.
+	 */
+	val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL
+			<< ((gpio & 0x07) << 1));
+	writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) *
+				U300_GPIO_PORTX_SPACING);
+	gpio_set_value(gpio, value);
+	local_irq_restore(flags);
+	return 0;
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+/*
+ * Enable an IRQ, edge is rising edge (!= 0) or falling edge (==0).
+ */
+void enable_irq_on_gpio_pin(unsigned gpio, int edge)
+{
+	u32 val;
+	unsigned long flags;
+	local_irq_save(flags);
+
+	val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) *
+				U300_GPIO_PORTX_SPACING);
+	val |= (1 << (gpio & 0x07));
+	writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) *
+				U300_GPIO_PORTX_SPACING);
+	val = readl(virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) *
+				U300_GPIO_PORTX_SPACING);
+	if (edge)
+		val |= (1 << (gpio & 0x07));
+	else
+		val &= ~(1 << (gpio & 0x07));
+	writel(val, virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) *
+				U300_GPIO_PORTX_SPACING);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(enable_irq_on_gpio_pin);
+
+void disable_irq_on_gpio_pin(unsigned gpio)
+{
+	u32 val;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) *
+				U300_GPIO_PORTX_SPACING);
+	val &= ~(1 << (gpio & 0x07));
+	writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) *
+				U300_GPIO_PORTX_SPACING);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(disable_irq_on_gpio_pin);
+
+/* Enable (value == 0) or disable (value == 1) internal pullup */
+void gpio_pullup(unsigned gpio, int value)
+{
+	u32 val;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (value) {
+		val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) *
+					U300_GPIO_PORTX_SPACING);
+		writel(val | (1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER +
+				PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING);
+	} else {
+		val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) *
+					U300_GPIO_PORTX_SPACING);
+		writel(val & ~(1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER +
+				PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING);
+	}
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_pullup);
+
+static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
+{
+	struct u300_gpio_port *port = dev_id;
+	u32 val;
+	int pin;
+
+	/* Read event register */
+	val = readl(virtbase + U300_GPIO_PXIEV + port->number *
+				U300_GPIO_PORTX_SPACING);
+	/* Mask with enable register */
+	val &= readl(virtbase + U300_GPIO_PXIEV + port->number *
+				U300_GPIO_PORTX_SPACING);
+	/* Mask relevant bits */
+	val &= U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK;
+	/* ACK IRQ (clear event) */
+	writel(val, virtbase + U300_GPIO_PXIEV + port->number *
+				U300_GPIO_PORTX_SPACING);
+	/* Print message */
+	while (val != 0) {
+		unsigned gpio;
+
+		pin = __ffs(val);
+		/* mask off this pin */
+		val &= ~(1 << pin);
+		gpio = (port->number << 3) + pin;
+
+		if (gpio_pin[gpio].callback)
+			(void)gpio_pin[gpio].callback(gpio_pin[gpio].data);
+		else
+			dev_dbg(gpiodev, "stray GPIO IRQ on line %d\n",
+			       gpio);
+	}
+	return IRQ_HANDLED;
+}
+
+static void gpio_set_initial_values(void)
+{
+#ifdef U300_COH901571_3
+	int i, j;
+	unsigned long flags;
+	u32 val;
+
+	/* Write default values to all pins */
+	for (i = 0; i < U300_GPIO_NUM_PORTS; i++) {
+		val = 0;
+		for (j = 0; j < 8; j++)
+			val |= (u32) (u300_gpio_config[i][j].default_output_value != DEFAULT_OUTPUT_LOW) << j;
+		local_irq_save(flags);
+		writel(val, virtbase + U300_GPIO_PXPDOR + i * U300_GPIO_PORTX_SPACING);
+		local_irq_restore(flags);
+	}
+
+	/*
+	 * Put all pins that are set to either 'GPIO_OUT' or 'GPIO_NOT_USED'
+	 * to output and 'GPIO_IN' to input for each port. And initalize
+	 * default value on outputs.
+	 */
+	for (i = 0; i < U300_GPIO_NUM_PORTS; i++) {
+		for (j = 0; j < U300_GPIO_PINS_PER_PORT; j++) {
+			local_irq_save(flags);
+			val = readl(virtbase + U300_GPIO_PXPCR +
+					 i * U300_GPIO_PORTX_SPACING);
+			/* Mask out this pin */
+			val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << (j << 1));
+
+			if (u300_gpio_config[i][j].pin_usage != GPIO_IN)
+				val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL << (j << 1));
+			writel(val, virtbase + U300_GPIO_PXPCR +
+					 i * U300_GPIO_PORTX_SPACING);
+			local_irq_restore(flags);
+		}
+	}
+
+	/* Enable or disable the internal pull-ups in the GPIO ASIC block */
+	for (i = 0; i < U300_GPIO_MAX; i++) {
+		val = 0;
+		for (j = 0; j < 8; j++)
+			val |= (u32)((u300_gpio_config[i][j].pull_up == DISABLE_PULL_UP)) << j;
+		local_irq_save(flags);
+		writel(val, virtbase + U300_GPIO_PXPER + i * U300_GPIO_PORTX_SPACING);
+		local_irq_restore(flags);
+	}
+#endif
+}
+
+static int __init gpio_probe(struct platform_device *pdev)
+{
+	u32 val;
+	int err = 0;
+	int i;
+	int num_irqs;
+
+	gpiodev = &pdev->dev;
+	memset(gpio_pin, 0, sizeof(gpio_pin));
+
+	/* Get GPIO clock */
+	clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk)) {
+		err = PTR_ERR(clk);
+		dev_err(gpiodev, "could not get GPIO clock\n");
+		goto err_no_clk;
+	}
+	err = clk_enable(clk);
+	if (err) {
+		dev_err(gpiodev, "could not enable GPIO clock\n");
+		goto err_no_clk_enable;
+	}
+
+	memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!memres)
+		goto err_no_resource;
+
+	if (request_mem_region(memres->start, memres->end - memres->start, "GPIO Controller")
+	    == NULL) {
+		err = -ENODEV;
+		goto err_no_ioregion;
+	}
+
+	virtbase = ioremap(memres->start, resource_size(memres));
+	if (!virtbase) {
+		err = -ENOMEM;
+		goto err_no_ioremap;
+	}
+	dev_info(gpiodev, "remapped 0x%08x to %p\n",
+		 memres->start, virtbase);
+
+#ifdef U300_COH901335
+	dev_info(gpiodev, "initializing GPIO Controller COH 901 335\n");
+	/* Turn on the GPIO block */
+	writel(U300_GPIO_CR_BLOCK_CLOCK_ENABLE, virtbase + U300_GPIO_CR);
+#endif
+
+#ifdef U300_COH901571_3
+	dev_info(gpiodev, "initializing GPIO Controller COH 901 571/3\n");
+	val = readl(virtbase + U300_GPIO_CR);
+	dev_info(gpiodev, "COH901571/3 block version: %d, " \
+	       "number of cores: %d\n",
+	       ((val & 0x0000FE00) >> 9),
+	       ((val & 0x000001FC) >> 2));
+	writel(U300_GPIO_CR_BLOCK_CLKRQ_ENABLE, virtbase + U300_GPIO_CR);
+#endif
+
+	/* Set up some padmuxing here */
+#ifdef CONFIG_MMC
+	pmx_set_mission_mode_mmc();
+#endif
+#ifdef CONFIG_SPI_PL022
+	pmx_set_mission_mode_spi();
+#endif
+
+	gpio_set_initial_values();
+
+	for (num_irqs = 0 ; num_irqs < U300_GPIO_NUM_PORTS; num_irqs++) {
+
+		gpio_ports[num_irqs].irq =
+			platform_get_irq_byname(pdev,
+						gpio_ports[num_irqs].name);
+
+		err = request_irq(gpio_ports[num_irqs].irq,
+				  gpio_irq_handler, IRQF_DISABLED,
+				  gpio_ports[num_irqs].name,
+				  &gpio_ports[num_irqs]);
+		if (err) {
+			dev_err(gpiodev, "cannot allocate IRQ for %s!\n",
+				gpio_ports[num_irqs].name);
+			goto err_no_irq;
+		}
+		/* Turns off PortX_irq_force */
+		writel(0x0, virtbase + U300_GPIO_PXIFR +
+				 num_irqs * U300_GPIO_PORTX_SPACING);
+	}
+
+	return 0;
+
+ err_no_irq:
+	for (i = 0; i < num_irqs; i++)
+		free_irq(gpio_ports[i].irq, &gpio_ports[i]);
+	iounmap(virtbase);
+ err_no_ioremap:
+	release_mem_region(memres->start, memres->end - memres->start);
+ err_no_ioregion:
+ err_no_resource:
+	clk_disable(clk);
+ err_no_clk_enable:
+	clk_put(clk);
+ err_no_clk:
+	dev_info(gpiodev, "module ERROR:%d\n", err);
+	return err;
+}
+
+static int __exit gpio_remove(struct platform_device *pdev)
+{
+	int i;
+
+	/* Turn off the GPIO block */
+	writel(0x00000000U, virtbase + U300_GPIO_CR);
+	for (i = 0 ; i < U300_GPIO_NUM_PORTS; i++)
+		free_irq(gpio_ports[i].irq, &gpio_ports[i]);
+	iounmap(virtbase);
+	release_mem_region(memres->start, memres->end - memres->start);
+	clk_disable(clk);
+	clk_put(clk);
+	return 0;
+}
+
+static struct platform_driver gpio_driver = {
+	.driver		= {
+		.name	= "u300-gpio",
+	},
+	.remove		= __exit_p(gpio_remove),
+};
+
+
+static int __init u300_gpio_init(void)
+{
+	return platform_driver_probe(&gpio_driver, gpio_probe);
+}
+
+static void __exit u300_gpio_exit(void)
+{
+	platform_driver_unregister(&gpio_driver);
+}
+
+arch_initcall(u300_gpio_init);
+module_exit(u300_gpio_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
+
+#ifdef U300_COH901571_3
+MODULE_DESCRIPTION("ST-Ericsson AB COH 901 571/3 GPIO driver");
+#endif
+
+#ifdef U300_COH901335
+MODULE_DESCRIPTION("ST-Ericsson AB COH 901 335 GPIO driver");
+#endif
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-u300/include/mach/clkdev.h b/arch/arm/mach-u300/include/mach/clkdev.h
new file mode 100644
index 0000000..92e3cc8
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/clkdev.h
@@ -0,0 +1,7 @@
+#ifndef __MACH_CLKDEV_H
+#define __MACH_CLKDEV_H
+
+int __clk_get(struct clk *clk);
+void __clk_put(struct clk *clk);
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/debug-macro.S b/arch/arm/mach-u300/include/mach/debug-macro.S
new file mode 100644
index 0000000..f3a1cbb
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/debug-macro.S
@@ -0,0 +1,22 @@
+/*
+ *
+ * arch-arm/mach-u300/include/mach/debug-macro.S
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Debugging macro include header.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#include <mach/hardware.h>
+
+	.macro	addruart,rx
+	/* If we move the adress using MMU, use this. */
+	mrc	p15, 0, \rx, c1, c0
+	tst	\rx, #1			@ MMU enabled?
+	ldreq	\rx,	  = U300_SLOW_PER_PHYS_BASE @ MMU off, physical address
+	ldrne	\rx,	  = U300_SLOW_PER_VIRT_BASE @ MMU on, virtual address
+	orr	\rx, \rx, #0x00003000
+	.endm
+
+#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/mach-u300/include/mach/entry-macro.S b/arch/arm/mach-u300/include/mach/entry-macro.S
new file mode 100644
index 0000000..20731ae
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/entry-macro.S
@@ -0,0 +1,40 @@
+/*
+ *
+ * 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>
+ */
+#include <mach/hardware.h>
+#include <asm/hardware/vic.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	\base, = U300_AHB_PER_VIRT_BASE-U300_AHB_PER_PHYS_BASE+U300_INTCON0_BASE
+	ldr	\irqstat, [\base, #VIC_IRQ_STATUS] @ get masked status
+	mov	\irqnr, #0
+	teq	\irqstat, #0
+	bne	1002f
+1001:	ldr	\base, = U300_AHB_PER_VIRT_BASE-U300_AHB_PER_PHYS_BASE+U300_INTCON1_BASE
+	ldr	\irqstat, [\base, #VIC_IRQ_STATUS] @ get masked status
+	mov	\irqnr, #32
+	teq	\irqstat, #0
+	beq	1003f
+1002:	tst	\irqstat, #1
+	bne	1003f
+	add	\irqnr, \irqnr, #1
+	movs	\irqstat, \irqstat, lsr #1
+	bne	1002b
+1003:		/* EQ will be set if no irqs pending */
+	.endm
diff --git a/arch/arm/mach-u300/include/mach/gpio.h b/arch/arm/mach-u300/include/mach/gpio.h
new file mode 100644
index 0000000..c817412
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/gpio.h
@@ -0,0 +1,290 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/gpio.h
+ *
+ *
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * GPIO block resgister definitions and inline macros for
+ * U300 GPIO COH 901 335 or COH 901 571/3
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+
+#ifndef __MACH_U300_GPIO_H
+#define __MACH_U300_GPIO_H
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+/* Switch type depending on platform/chip variant */
+#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
+#define U300_COH901335
+#endif
+#if defined(CONFIG_MACH_U300_BS365) || defined(CONFIG_MACH_U300_BS335)
+#define U300_COH901571_3
+#endif
+
+/* Get base address for regs here */
+#include "u300-regs.h"
+/* IRQ numbers */
+#include "irqs.h"
+
+/*
+ * This is the GPIO block definitions. GPIO (General Purpose I/O) can be
+ * used for anything, and often is. The event/enable etc figures are for
+ * the lowermost pin (pin 0 on each port), shift this left to match your
+ * pin if you're gonna use these values.
+ */
+#ifdef U300_COH901335
+#define U300_GPIO_PORTX_SPACING				(0x1C)
+/* Port X Pin Data Register 32bit, this is both input and output (R/W) */
+#define U300_GPIO_PXPDIR				(0x00)
+#define U300_GPIO_PXPDOR				(0x00)
+/* Port X Pin Config Register 32bit (R/W) */
+#define U300_GPIO_PXPCR					(0x04)
+#define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK		(0x0000FFFFUL)
+#define U300_GPIO_PXPCR_PIN_MODE_MASK			(0x00000003UL)
+#define U300_GPIO_PXPCR_PIN_MODE_SHIFT			(0x00000002UL)
+#define U300_GPIO_PXPCR_PIN_MODE_INPUT			(0x00000000UL)
+#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL	(0x00000001UL)
+#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN	(0x00000002UL)
+#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE	(0x00000003UL)
+/* Port X Interrupt Event Register 32bit (R/W) */
+#define U300_GPIO_PXIEV					(0x08)
+#define U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK		(0x000000FFUL)
+#define U300_GPIO_PXIEV_IRQ_EVENT			(0x00000001UL)
+/* Port X Interrupt Enable Register 32bit (R/W) */
+#define U300_GPIO_PXIEN					(0x0C)
+#define U300_GPIO_PXIEN_ALL_IRQ_ENABLE_MASK		(0x000000FFUL)
+#define U300_GPIO_PXIEN_IRQ_ENABLE			(0x00000001UL)
+/* Port X Interrupt Force Register 32bit (R/W) */
+#define U300_GPIO_PXIFR					(0x10)
+#define U300_GPIO_PXIFR_ALL_IRQ_FORCE_MASK		(0x000000FFUL)
+#define U300_GPIO_PXIFR_IRQ_FORCE			(0x00000001UL)
+/* Port X Interrupt Config Register 32bit (R/W) */
+#define U300_GPIO_PXICR					(0x14)
+#define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK		(0x000000FFUL)
+#define U300_GPIO_PXICR_IRQ_CONFIG_MASK			(0x00000001UL)
+#define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE		(0x00000000UL)
+#define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE		(0x00000001UL)
+/* Port X Pull-up Enable Register 32bit (R/W) */
+#define U300_GPIO_PXPER					(0x18)
+#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK	(0x000000FFUL)
+#define U300_GPIO_PXPER_PULL_UP_DISABLE			(0x00000001UL)
+/* Control Register 32bit (R/W) */
+#define U300_GPIO_CR					(0x54)
+#define U300_GPIO_CR_BLOCK_CLOCK_ENABLE			(0x00000001UL)
+/* three ports of 8 bits each = GPIO pins 0..23 */
+#define U300_GPIO_NUM_PORTS 3
+#define U300_GPIO_PINS_PER_PORT 8
+#define U300_GPIO_MAX	(U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS - 1)
+#endif
+
+#ifdef U300_COH901571_3
+/*
+ * Control Register 32bit (R/W)
+ * bit 15-9 (mask 0x0000FE00) contains the number of cores. 8*cores
+ * gives the number of GPIO pins.
+ * bit 8-2  (mask 0x000001FC) contains the core version ID.
+ */
+#define U300_GPIO_CR					(0x00)
+#define U300_GPIO_CR_SYNC_SEL_ENABLE			(0x00000002UL)
+#define U300_GPIO_CR_BLOCK_CLKRQ_ENABLE			(0x00000001UL)
+#define U300_GPIO_PORTX_SPACING				(0x30)
+/* Port X Pin Data INPUT Register 32bit (R/W) */
+#define U300_GPIO_PXPDIR				(0x04)
+/* Port X Pin Data OUTPUT Register 32bit (R/W) */
+#define U300_GPIO_PXPDOR				(0x08)
+/* Port X Pin Config Register 32bit (R/W) */
+#define U300_GPIO_PXPCR					(0x0C)
+#define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK		(0x0000FFFFUL)
+#define U300_GPIO_PXPCR_PIN_MODE_MASK			(0x00000003UL)
+#define U300_GPIO_PXPCR_PIN_MODE_SHIFT			(0x00000002UL)
+#define U300_GPIO_PXPCR_PIN_MODE_INPUT			(0x00000000UL)
+#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL	(0x00000001UL)
+#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN	(0x00000002UL)
+#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE	(0x00000003UL)
+/* Port X Pull-up Enable Register 32bit (R/W) */
+#define U300_GPIO_PXPER					(0x10)
+#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK	(0x000000FFUL)
+#define U300_GPIO_PXPER_PULL_UP_DISABLE			(0x00000001UL)
+/* Port X Interrupt Event Register 32bit (R/W) */
+#define U300_GPIO_PXIEV					(0x14)
+#define U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK		(0x000000FFUL)
+#define U300_GPIO_PXIEV_IRQ_EVENT			(0x00000001UL)
+/* Port X Interrupt Enable Register 32bit (R/W) */
+#define U300_GPIO_PXIEN					(0x18)
+#define U300_GPIO_PXIEN_ALL_IRQ_ENABLE_MASK		(0x000000FFUL)
+#define U300_GPIO_PXIEN_IRQ_ENABLE			(0x00000001UL)
+/* Port X Interrupt Force Register 32bit (R/W) */
+#define U300_GPIO_PXIFR					(0x1C)
+#define U300_GPIO_PXIFR_ALL_IRQ_FORCE_MASK		(0x000000FFUL)
+#define U300_GPIO_PXIFR_IRQ_FORCE			(0x00000001UL)
+/* Port X Interrupt Config Register 32bit (R/W) */
+#define U300_GPIO_PXICR					(0x20)
+#define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK		(0x000000FFUL)
+#define U300_GPIO_PXICR_IRQ_CONFIG_MASK			(0x00000001UL)
+#define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE		(0x00000000UL)
+#define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE		(0x00000001UL)
+#ifdef CONFIG_MACH_U300_BS335
+/* seven ports of 8 bits each = GPIO pins 0..55 */
+#define U300_GPIO_NUM_PORTS 7
+#else
+/* five ports of 8 bits each = GPIO pins 0..39 */
+#define U300_GPIO_NUM_PORTS 5
+#endif
+#define U300_GPIO_PINS_PER_PORT 8
+#define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS - 1)
+#endif
+
+/*
+ * Individual pin assignments for the B26/S26. Notice that the
+ * actual usage of these pins depends on the PAD MUX settings, that
+ * is why the same number can potentially appear several times.
+ * In the reference design each pin is only used for one purpose.
+ * These were determined by inspecting the B26/S26 schematic:
+ * 2/1911-ROA 128 1603
+ */
+#ifdef CONFIG_MACH_U300_BS2X
+#define U300_GPIO_PIN_UART_RX		0
+#define U300_GPIO_PIN_UART_TX		1
+#define U300_GPIO_PIN_GPIO02		2  /* Unrouted */
+#define U300_GPIO_PIN_GPIO03		3  /* Unrouted */
+#define U300_GPIO_PIN_CAM_SLEEP		4
+#define U300_GPIO_PIN_CAM_REG_EN	5
+#define U300_GPIO_PIN_GPIO06		6  /* Unrouted */
+#define U300_GPIO_PIN_GPIO07		7  /* Unrouted */
+
+#define U300_GPIO_PIN_GPIO08		8  /* Service point SP2321 */
+#define U300_GPIO_PIN_GPIO09		9  /* Service point SP2322 */
+#define U300_GPIO_PIN_PHFSENSE		10 /* Headphone jack sensing */
+#define U300_GPIO_PIN_MMC_CLKRET	11 /* Clock return from MMC/SD card */
+#define U300_GPIO_PIN_MMC_CD		12 /* MMC Card insertion detection */
+#define U300_GPIO_PIN_FLIPSENSE		13 /* Mechanical flip sensing */
+#define U300_GPIO_PIN_GPIO14		14 /* DSP JTAG Port RTCK */
+#define U300_GPIO_PIN_GPIO15		15 /* Unrouted */
+
+#define U300_GPIO_PIN_GPIO16		16 /* Unrouted */
+#define U300_GPIO_PIN_GPIO17		17 /* Unrouted */
+#define U300_GPIO_PIN_GPIO18		18 /* Unrouted */
+#define U300_GPIO_PIN_GPIO19		19 /* Unrouted */
+#define U300_GPIO_PIN_GPIO20		20 /* Unrouted */
+#define U300_GPIO_PIN_GPIO21		21 /* Unrouted */
+#define U300_GPIO_PIN_GPIO22		22 /* Unrouted */
+#define U300_GPIO_PIN_GPIO23		23 /* Unrouted */
+#endif
+
+/*
+ * Individual pin assignments for the B330/S330 and B365/S365.
+ * Notice that the actual usage of these pins depends on the
+ * PAD MUX settings, that is why the same number can potentially
+ * appear several times. In the reference design each pin is only
+ * used for one purpose. These were determined by inspecting the
+ * S365 schematic.
+ */
+#if defined(CONFIG_MACH_U300_BS330) || defined(CONFIG_MACH_U300_BS365) || \
+    defined(CONFIG_MACH_U300_BS335)
+#define U300_GPIO_PIN_UART_RX		0
+#define U300_GPIO_PIN_UART_TX		1
+#define U300_GPIO_PIN_UART_CTS		2
+#define U300_GPIO_PIN_UART_RTS		3
+#define U300_GPIO_PIN_CAM_MAIN_STANDBY	4 /* Camera MAIN standby */
+#define U300_GPIO_PIN_GPIO05		5 /* Unrouted */
+#define U300_GPIO_PIN_MS_CD		6 /* Memory Stick Card insertion */
+#define U300_GPIO_PIN_GPIO07		7 /* Test point TP2430 */
+
+#define U300_GPIO_PIN_GPIO08		8 /* Test point TP2437 */
+#define U300_GPIO_PIN_GPIO09		9 /* Test point TP2431 */
+#define U300_GPIO_PIN_GPIO10		10 /* Test point TP2432 */
+#define U300_GPIO_PIN_MMC_CLKRET	11 /* Clock return from MMC/SD card */
+#define U300_GPIO_PIN_MMC_CD		12 /* MMC Card insertion detection */
+#define U300_GPIO_PIN_CAM_SUB_STANDBY	13 /* Camera SUB standby */
+#define U300_GPIO_PIN_GPIO14		14 /* Test point TP2436 */
+#define U300_GPIO_PIN_GPIO15		15 /* Unrouted */
+
+#define U300_GPIO_PIN_GPIO16		16 /* Test point TP2438 */
+#define U300_GPIO_PIN_PHFSENSE		17 /* Headphone jack sensing */
+#define U300_GPIO_PIN_GPIO18		18 /* Test point TP2439 */
+#define U300_GPIO_PIN_GPIO19		19 /* Routed somewhere */
+#define U300_GPIO_PIN_GPIO20		20 /* Unrouted */
+#define U300_GPIO_PIN_GPIO21		21 /* Unrouted */
+#define U300_GPIO_PIN_GPIO22		22 /* Unrouted */
+#define U300_GPIO_PIN_GPIO23		23 /* Unrouted */
+
+#define U300_GPIO_PIN_GPIO24		24 /* Unrouted */
+#define U300_GPIO_PIN_GPIO25		25 /* Unrouted */
+#define U300_GPIO_PIN_GPIO26		26 /* Unrouted */
+#define U300_GPIO_PIN_GPIO27		27 /* Unrouted */
+#define U300_GPIO_PIN_GPIO28		28 /* Unrouted */
+#define U300_GPIO_PIN_GPIO29		29 /* Unrouted */
+#define U300_GPIO_PIN_GPIO30		30 /* Unrouted */
+#define U300_GPIO_PIN_GPIO31		31 /* Unrouted */
+
+#define U300_GPIO_PIN_GPIO32		32 /* Unrouted */
+#define U300_GPIO_PIN_GPIO33		33 /* Unrouted */
+#define U300_GPIO_PIN_GPIO34		34 /* Unrouted */
+#define U300_GPIO_PIN_GPIO35		35 /* Unrouted */
+#define U300_GPIO_PIN_GPIO36		36 /* Unrouted */
+#define U300_GPIO_PIN_GPIO37		37 /* Unrouted */
+#define U300_GPIO_PIN_GPIO38		38 /* Unrouted */
+#define U300_GPIO_PIN_GPIO39		39 /* Unrouted */
+
+#ifdef CONFIG_MACH_U300_BS335
+
+#define U300_GPIO_PIN_GPIO40		40 /* Unrouted */
+#define U300_GPIO_PIN_GPIO41		41 /* Unrouted */
+#define U300_GPIO_PIN_GPIO42		42 /* Unrouted */
+#define U300_GPIO_PIN_GPIO43		43 /* Unrouted */
+#define U300_GPIO_PIN_GPIO44		44 /* Unrouted */
+#define U300_GPIO_PIN_GPIO45		45 /* Unrouted */
+#define U300_GPIO_PIN_GPIO46		46 /* Unrouted */
+#define U300_GPIO_PIN_GPIO47		47 /* Unrouted */
+
+#define U300_GPIO_PIN_GPIO48		48 /* Unrouted */
+#define U300_GPIO_PIN_GPIO49		49 /* Unrouted */
+#define U300_GPIO_PIN_GPIO50		50 /* Unrouted */
+#define U300_GPIO_PIN_GPIO51		51 /* Unrouted */
+#define U300_GPIO_PIN_GPIO52		52 /* Unrouted */
+#define U300_GPIO_PIN_GPIO53		53 /* Unrouted */
+#define U300_GPIO_PIN_GPIO54		54 /* Unrouted */
+#define U300_GPIO_PIN_GPIO55		55 /* Unrouted */
+#endif
+
+#endif
+
+/* translates a pin number to a port number */
+#define PIN_TO_PORT(val) (val >> 3)
+
+/* These can be found in arch/arm/mach-u300/gpio.c */
+extern int gpio_request(unsigned gpio, const char *label);
+extern void gpio_free(unsigned gpio);
+extern int gpio_direction_input(unsigned gpio);
+extern int gpio_direction_output(unsigned gpio, int value);
+extern int gpio_register_callback(unsigned gpio,
+				  int (*func)(void *arg),
+				  void *);
+extern int gpio_unregister_callback(unsigned gpio);
+extern void enable_irq_on_gpio_pin(unsigned gpio, int edge);
+extern void disable_irq_on_gpio_pin(unsigned gpio);
+extern void gpio_pullup(unsigned gpio, int value);
+extern int gpio_get_value(unsigned gpio);
+extern void gpio_set_value(unsigned gpio, int value);
+
+/* wrappers to sleep-enable the previous two functions */
+static inline unsigned gpio_to_irq(unsigned gpio)
+{
+	return PIN_TO_PORT(gpio) + IRQ_U300_GPIO_PORT0;
+}
+
+static inline unsigned irq_to_gpio(unsigned irq)
+{
+	/*
+	 * FIXME: This is no 1-1 mapping at all, it points to the
+	 * whole block of 8 pins.
+	 */
+	return (irq - IRQ_U300_GPIO_PORT0) << 3;
+}
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/hardware.h b/arch/arm/mach-u300/include/mach/hardware.h
new file mode 100644
index 0000000..b99d4ce
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/hardware.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-u300/include/mach/hardware.h
+ */
+#include <asm/sizes.h>
+#include <mach/u300-regs.h>
diff --git a/arch/arm/mach-u300/include/mach/io.h b/arch/arm/mach-u300/include/mach/io.h
new file mode 100644
index 0000000..5d6b4c1
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/io.h
@@ -0,0 +1,20 @@
+/*
+ *
+ * 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/irqs.h b/arch/arm/mach-u300/include/mach/irqs.h
new file mode 100644
index 0000000..a6867b1
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/irqs.h
@@ -0,0 +1,114 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/irqs.h
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * IRQ channel definitions for the U300 platforms.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+
+#ifndef __MACH_IRQS_H
+#define __MACH_IRQS_H
+
+#define IRQ_U300_INTCON0_START		0
+#define IRQ_U300_INTCON1_START		32
+/* These are on INTCON0 - 30 lines */
+#define IRQ_U300_IRQ0_EXT		0
+#define IRQ_U300_IRQ1_EXT		1
+#define IRQ_U300_DMA			2
+#define IRQ_U300_VIDEO_ENC_0		3
+#define IRQ_U300_VIDEO_ENC_1		4
+#define IRQ_U300_AAIF_RX		5
+#define IRQ_U300_AAIF_TX		6
+#define IRQ_U300_AAIF_VGPIO		7
+#define IRQ_U300_AAIF_WAKEUP		8
+#define IRQ_U300_PCM_I2S0_FRAME		9
+#define IRQ_U300_PCM_I2S0_FIFO		10
+#define IRQ_U300_PCM_I2S1_FRAME		11
+#define IRQ_U300_PCM_I2S1_FIFO		12
+#define IRQ_U300_XGAM_GAMCON		13
+#define IRQ_U300_XGAM_CDI		14
+#define IRQ_U300_XGAM_CDICON		15
+#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
+/* MMIACC not used on the DB3210 or DB3350 chips */
+#define IRQ_U300_XGAM_MMIACC		16
+#endif
+#define IRQ_U300_XGAM_PDI		17
+#define IRQ_U300_XGAM_PDICON		18
+#define IRQ_U300_XGAM_GAMEACC		19
+#define IRQ_U300_XGAM_MCIDCT		20
+#define IRQ_U300_APEX			21
+#define IRQ_U300_UART0			22
+#define IRQ_U300_SPI			23
+#define IRQ_U300_TIMER_APP_OS		24
+#define IRQ_U300_TIMER_APP_DD		25
+#define IRQ_U300_TIMER_APP_GP1		26
+#define IRQ_U300_TIMER_APP_GP2		27
+#define IRQ_U300_TIMER_OS		28
+#define IRQ_U300_TIMER_MS		29
+#define IRQ_U300_KEYPAD_KEYBF		30
+#define IRQ_U300_KEYPAD_KEYBR		31
+/* These are on INTCON1 - 32 lines */
+#define IRQ_U300_GPIO_PORT0		32
+#define IRQ_U300_GPIO_PORT1		33
+#define IRQ_U300_GPIO_PORT2		34
+
+#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330) || \
+    defined(CONFIG_MACH_U300_BS335)
+/* These are for DB3150, DB3200 and DB3350 */
+#define IRQ_U300_WDOG			35
+#define IRQ_U300_EVHIST			36
+#define IRQ_U300_MSPRO			37
+#define IRQ_U300_MMCSD_MCIINTR0		38
+#define IRQ_U300_MMCSD_MCIINTR1		39
+#define IRQ_U300_I2C0			40
+#define IRQ_U300_I2C1			41
+#define IRQ_U300_RTC			42
+#define IRQ_U300_NFIF			43
+#define IRQ_U300_NFIF2			44
+#endif
+
+/* DB3150 and DB3200 have only 45 IRQs */
+#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
+#define U300_NR_IRQS			45
+#endif
+
+/* The DB3350-specific interrupt lines */
+#ifdef CONFIG_MACH_U300_BS335
+#define IRQ_U300_ISP_F0			45
+#define IRQ_U300_ISP_F1			46
+#define IRQ_U300_ISP_F2			47
+#define IRQ_U300_ISP_F3			48
+#define IRQ_U300_ISP_F4			49
+#define IRQ_U300_GPIO_PORT3		50
+#define IRQ_U300_SYSCON_PLL_LOCK	51
+#define IRQ_U300_UART1			52
+#define IRQ_U300_GPIO_PORT4		53
+#define IRQ_U300_GPIO_PORT5		54
+#define IRQ_U300_GPIO_PORT6		55
+#define U300_NR_IRQS			56
+#endif
+
+/* The DB3210-specific interrupt lines */
+#ifdef CONFIG_MACH_U300_BS365
+#define IRQ_U300_GPIO_PORT3		35
+#define IRQ_U300_GPIO_PORT4		36
+#define IRQ_U300_WDOG			37
+#define IRQ_U300_EVHIST			38
+#define IRQ_U300_MSPRO			39
+#define IRQ_U300_MMCSD_MCIINTR0		40
+#define IRQ_U300_MMCSD_MCIINTR1		41
+#define IRQ_U300_I2C0			42
+#define IRQ_U300_I2C1			43
+#define IRQ_U300_RTC			44
+#define IRQ_U300_NFIF			45
+#define IRQ_U300_NFIF2			46
+#define IRQ_U300_SYSCON_PLL_LOCK	47
+#define U300_NR_IRQS			48
+#endif
+
+#define NR_IRQS U300_NR_IRQS
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/memory.h b/arch/arm/mach-u300/include/mach/memory.h
new file mode 100644
index 0000000..bf134bc
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/memory.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/memory.h
+ *
+ *
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Memory virtual/physical mapping constants.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ */
+
+#ifndef __MACH_MEMORY_H
+#define __MACH_MEMORY_H
+
+#ifdef CONFIG_MACH_U300_DUAL_RAM
+
+#define PHYS_OFFSET		UL(0x48000000)
+#define BOOT_PARAMS_OFFSET	(PHYS_OFFSET + 0x100)
+
+#else
+
+#ifdef CONFIG_MACH_U300_2MB_ALIGNMENT_FIX
+#define PHYS_OFFSET (0x28000000 + \
+	     (CONFIG_MACH_U300_ACCESS_MEM_SIZE - \
+	     (CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1))*1024*1024)
+#else
+#define PHYS_OFFSET (0x28000000 + \
+	     (CONFIG_MACH_U300_ACCESS_MEM_SIZE +	\
+	     (CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1))*1024*1024)
+#endif
+#define BOOT_PARAMS_OFFSET (0x28000000 + \
+	    (CONFIG_MACH_U300_ACCESS_MEM_SIZE +		\
+	    (CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1))*1024*1024 + 0x100)
+#endif
+
+/*
+ * We enable a real big DMA buffer if need be.
+ */
+#define CONSISTENT_DMA_SIZE SZ_4M
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/platform.h b/arch/arm/mach-u300/include/mach/platform.h
new file mode 100644
index 0000000..77d9210
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/platform.h
@@ -0,0 +1,19 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/platform.h
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Basic platform init and mapping functions.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+
+#ifndef __ASSEMBLY__
+
+void u300_map_io(void);
+void u300_init_irq(void);
+void u300_init_devices(void);
+extern struct sys_timer u300_timer;
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/syscon.h b/arch/arm/mach-u300/include/mach/syscon.h
new file mode 100644
index 0000000..1c90d1b
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/syscon.h
@@ -0,0 +1,644 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/syscon.h
+ *
+ *
+ * Copyright (C) 2008 ST-Ericsson AB
+ *
+ * Author: Rickard Andersson <rickard.andersson@stericsson.com>
+ */
+
+#ifndef __MACH_SYSCON_H
+#define __MACH_SYSCON_H
+
+/*
+ * All register defines for SYSCON registers that concerns individual
+ * block clocks and reset lines are registered here. This is because
+ * we don't want any other file to try to fool around with this stuff.
+ */
+
+/* APP side SYSCON registers */
+/* TODO: this is incomplete. Add all from asic_syscon_map.h eventually. */
+/* CLK Control Register 16bit (R/W) */
+#define U300_SYSCON_CCR						(0x0000)
+#define U300_SYSCON_CCR_I2S1_USE_VCXO				(0x0040)
+#define U300_SYSCON_CCR_I2S0_USE_VCXO				(0x0020)
+#define U300_SYSCON_CCR_TURN_VCXO_ON				(0x0008)
+#define U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK			(0x0007)
+#define U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER		(0x04)
+#define U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW			(0x03)
+#define U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE		(0x02)
+#define U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH			(0x01)
+#define U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST			(0x00)
+/* CLK Status Register 16bit (R/W) */
+#define U300_SYSCON_CSR						(0x0004)
+#define U300_SYSCON_CSR_PLL208_LOCK_IND				(0x0002)
+#define U300_SYSCON_CSR_PLL13_LOCK_IND				(0x0001)
+/* Reset lines for SLOW devices 16bit (R/W) */
+#define U300_SYSCON_RSR						(0x0014)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_RSR_PPM_RESET_EN				(0x0200)
+#endif
+#define U300_SYSCON_RSR_ACC_TMR_RESET_EN			(0x0100)
+#define U300_SYSCON_RSR_APP_TMR_RESET_EN			(0x0080)
+#define U300_SYSCON_RSR_RTC_RESET_EN				(0x0040)
+#define U300_SYSCON_RSR_KEYPAD_RESET_EN				(0x0020)
+#define U300_SYSCON_RSR_GPIO_RESET_EN				(0x0010)
+#define U300_SYSCON_RSR_EH_RESET_EN				(0x0008)
+#define U300_SYSCON_RSR_BTR_RESET_EN				(0x0004)
+#define U300_SYSCON_RSR_UART_RESET_EN				(0x0002)
+#define U300_SYSCON_RSR_SLOW_BRIDGE_RESET_EN			(0x0001)
+/* Reset lines for FAST devices 16bit (R/W) */
+#define U300_SYSCON_RFR						(0x0018)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_RFR_UART1_RESET_ENABLE			(0x0080)
+#endif
+#define U300_SYSCON_RFR_SPI_RESET_ENABLE			(0x0040)
+#define U300_SYSCON_RFR_MMC_RESET_ENABLE			(0x0020)
+#define U300_SYSCON_RFR_PCM_I2S1_RESET_ENABLE			(0x0010)
+#define U300_SYSCON_RFR_PCM_I2S0_RESET_ENABLE			(0x0008)
+#define U300_SYSCON_RFR_I2C1_RESET_ENABLE			(0x0004)
+#define U300_SYSCON_RFR_I2C0_RESET_ENABLE			(0x0002)
+#define U300_SYSCON_RFR_FAST_BRIDGE_RESET_ENABLE		(0x0001)
+/* Reset lines for the rest of the peripherals 16bit (R/W) */
+#define U300_SYSCON_RRR						(0x001c)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_RRR_CDS_RESET_EN				(0x4000)
+#define U300_SYSCON_RRR_ISP_RESET_EN				(0x2000)
+#endif
+#define U300_SYSCON_RRR_INTCON_RESET_EN				(0x1000)
+#define U300_SYSCON_RRR_MSPRO_RESET_EN				(0x0800)
+#define U300_SYSCON_RRR_XGAM_RESET_EN				(0x0100)
+#define U300_SYSCON_RRR_XGAM_VC_SYNC_RESET_EN			(0x0080)
+#define U300_SYSCON_RRR_NANDIF_RESET_EN				(0x0040)
+#define U300_SYSCON_RRR_EMIF_RESET_EN				(0x0020)
+#define U300_SYSCON_RRR_DMAC_RESET_EN				(0x0010)
+#define U300_SYSCON_RRR_CPU_RESET_EN				(0x0008)
+#define U300_SYSCON_RRR_APEX_RESET_EN				(0x0004)
+#define U300_SYSCON_RRR_AHB_RESET_EN				(0x0002)
+#define U300_SYSCON_RRR_AAIF_RESET_EN				(0x0001)
+/* Clock enable for SLOW peripherals 16bit (R/W) */
+#define U300_SYSCON_CESR					(0x0020)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_CESR_PPM_CLK_EN				(0x0200)
+#endif
+#define U300_SYSCON_CESR_ACC_TMR_CLK_EN				(0x0100)
+#define U300_SYSCON_CESR_APP_TMR_CLK_EN				(0x0080)
+#define U300_SYSCON_CESR_KEYPAD_CLK_EN				(0x0040)
+#define U300_SYSCON_CESR_GPIO_CLK_EN				(0x0010)
+#define U300_SYSCON_CESR_EH_CLK_EN				(0x0008)
+#define U300_SYSCON_CESR_BTR_CLK_EN				(0x0004)
+#define U300_SYSCON_CESR_UART_CLK_EN				(0x0002)
+#define U300_SYSCON_CESR_SLOW_BRIDGE_CLK_EN			(0x0001)
+/* Clock enable for FAST peripherals 16bit (R/W) */
+#define U300_SYSCON_CEFR					(0x0024)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_CEFR_UART1_CLK_EN				(0x0200)
+#endif
+#define U300_SYSCON_CEFR_I2S1_CORE_CLK_EN			(0x0100)
+#define U300_SYSCON_CEFR_I2S0_CORE_CLK_EN			(0x0080)
+#define U300_SYSCON_CEFR_SPI_CLK_EN				(0x0040)
+#define U300_SYSCON_CEFR_MMC_CLK_EN				(0x0020)
+#define U300_SYSCON_CEFR_I2S1_CLK_EN    			(0x0010)
+#define U300_SYSCON_CEFR_I2S0_CLK_EN     			(0x0008)
+#define U300_SYSCON_CEFR_I2C1_CLK_EN     			(0x0004)
+#define U300_SYSCON_CEFR_I2C0_CLK_EN     			(0x0002)
+#define U300_SYSCON_CEFR_FAST_BRIDGE_CLK_EN			(0x0001)
+/* Clock enable for the rest of the peripherals 16bit (R/W) */
+#define U300_SYSCON_CERR					(0x0028)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_CERR_CDS_CLK_EN				(0x2000)
+#define U300_SYSCON_CERR_ISP_CLK_EN				(0x1000)
+#endif
+#define U300_SYSCON_CERR_MSPRO_CLK_EN				(0x0800)
+#define U300_SYSCON_CERR_AHB_SUBSYS_BRIDGE_CLK_EN		(0x0400)
+#define U300_SYSCON_CERR_SEMI_CLK_EN				(0x0200)
+#define U300_SYSCON_CERR_XGAM_CLK_EN				(0x0100)
+#define U300_SYSCON_CERR_VIDEO_ENC_CLK_EN			(0x0080)
+#define U300_SYSCON_CERR_NANDIF_CLK_EN				(0x0040)
+#define U300_SYSCON_CERR_EMIF_CLK_EN				(0x0020)
+#define U300_SYSCON_CERR_DMAC_CLK_EN				(0x0010)
+#define U300_SYSCON_CERR_CPU_CLK_EN				(0x0008)
+#define U300_SYSCON_CERR_APEX_CLK_EN				(0x0004)
+#define U300_SYSCON_CERR_AHB_CLK_EN				(0x0002)
+#define U300_SYSCON_CERR_AAIF_CLK_EN				(0x0001)
+/* Single block clock enable 16bit (-/W) */
+#define U300_SYSCON_SBCER					(0x002c)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_SBCER_PPM_CLK_EN				(0x0009)
+#endif
+#define U300_SYSCON_SBCER_ACC_TMR_CLK_EN			(0x0008)
+#define U300_SYSCON_SBCER_APP_TMR_CLK_EN			(0x0007)
+#define U300_SYSCON_SBCER_KEYPAD_CLK_EN				(0x0006)
+#define U300_SYSCON_SBCER_GPIO_CLK_EN				(0x0004)
+#define U300_SYSCON_SBCER_EH_CLK_EN				(0x0003)
+#define U300_SYSCON_SBCER_BTR_CLK_EN				(0x0002)
+#define U300_SYSCON_SBCER_UART_CLK_EN				(0x0001)
+#define U300_SYSCON_SBCER_SLOW_BRIDGE_CLK_EN			(0x0000)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_SBCER_UART1_CLK_EN				(0x0019)
+#endif
+#define U300_SYSCON_SBCER_I2S1_CORE_CLK_EN			(0x0018)
+#define U300_SYSCON_SBCER_I2S0_CORE_CLK_EN			(0x0017)
+#define U300_SYSCON_SBCER_SPI_CLK_EN				(0x0016)
+#define U300_SYSCON_SBCER_MMC_CLK_EN				(0x0015)
+#define U300_SYSCON_SBCER_I2S1_CLK_EN				(0x0014)
+#define U300_SYSCON_SBCER_I2S0_CLK_EN				(0x0013)
+#define U300_SYSCON_SBCER_I2C1_CLK_EN				(0x0012)
+#define U300_SYSCON_SBCER_I2C0_CLK_EN				(0x0011)
+#define U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN			(0x0010)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_SBCER_CDS_CLK_EN				(0x002D)
+#define U300_SYSCON_SBCER_ISP_CLK_EN				(0x002C)
+#endif
+#define U300_SYSCON_SBCER_MSPRO_CLK_EN				(0x002B)
+#define U300_SYSCON_SBCER_AHB_SUBSYS_BRIDGE_CLK_EN		(0x002A)
+#define U300_SYSCON_SBCER_SEMI_CLK_EN				(0x0029)
+#define U300_SYSCON_SBCER_XGAM_CLK_EN				(0x0028)
+#define U300_SYSCON_SBCER_VIDEO_ENC_CLK_EN			(0x0027)
+#define U300_SYSCON_SBCER_NANDIF_CLK_EN				(0x0026)
+#define U300_SYSCON_SBCER_EMIF_CLK_EN				(0x0025)
+#define U300_SYSCON_SBCER_DMAC_CLK_EN				(0x0024)
+#define U300_SYSCON_SBCER_CPU_CLK_EN				(0x0023)
+#define U300_SYSCON_SBCER_APEX_CLK_EN				(0x0022)
+#define U300_SYSCON_SBCER_AHB_CLK_EN				(0x0021)
+#define U300_SYSCON_SBCER_AAIF_CLK_EN				(0x0020)
+/* Single block clock disable 16bit (-/W) */
+#define U300_SYSCON_SBCDR					(0x0030)
+/* Same values as above for SBCER */
+/* Clock force SLOW peripherals 16bit (R/W) */
+#define U300_SYSCON_CFSR					(0x003c)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_CFSR_PPM_CLK_FORCE_EN			(0x0200)
+#endif
+#define U300_SYSCON_CFSR_ACC_TMR_CLK_FORCE_EN			(0x0100)
+#define U300_SYSCON_CFSR_APP_TMR_CLK_FORCE_EN			(0x0080)
+#define U300_SYSCON_CFSR_KEYPAD_CLK_FORCE_EN			(0x0020)
+#define U300_SYSCON_CFSR_GPIO_CLK_FORCE_EN			(0x0010)
+#define U300_SYSCON_CFSR_EH_CLK_FORCE_EN			(0x0008)
+#define U300_SYSCON_CFSR_BTR_CLK_FORCE_EN			(0x0004)
+#define U300_SYSCON_CFSR_UART_CLK_FORCE_EN			(0x0002)
+#define U300_SYSCON_CFSR_SLOW_BRIDGE_CLK_FORCE_EN		(0x0001)
+/* Clock force FAST peripherals 16bit (R/W) */
+#define U300_SYSCON_CFFR					(0x40)
+/* Values not defined. Define if you want to use them. */
+/* Clock force the rest of the peripherals 16bit (R/W) */
+#define U300_SYSCON_CFRR					(0x44)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_CFRR_CDS_CLK_FORCE_EN			(0x2000)
+#define U300_SYSCON_CFRR_ISP_CLK_FORCE_EN			(0x1000)
+#endif
+#define U300_SYSCON_CFRR_MSPRO_CLK_FORCE_EN			(0x0800)
+#define U300_SYSCON_CFRR_AHB_SUBSYS_BRIDGE_CLK_FORCE_EN		(0x0400)
+#define U300_SYSCON_CFRR_SEMI_CLK_FORCE_EN			(0x0200)
+#define U300_SYSCON_CFRR_XGAM_CLK_FORCE_EN			(0x0100)
+#define U300_SYSCON_CFRR_VIDEO_ENC_CLK_FORCE_EN			(0x0080)
+#define U300_SYSCON_CFRR_NANDIF_CLK_FORCE_EN			(0x0040)
+#define U300_SYSCON_CFRR_EMIF_CLK_FORCE_EN			(0x0020)
+#define U300_SYSCON_CFRR_DMAC_CLK_FORCE_EN			(0x0010)
+#define U300_SYSCON_CFRR_CPU_CLK_FORCE_EN			(0x0008)
+#define U300_SYSCON_CFRR_APEX_CLK_FORCE_EN			(0x0004)
+#define U300_SYSCON_CFRR_AHB_CLK_FORCE_EN			(0x0002)
+#define U300_SYSCON_CFRR_AAIF_CLK_FORCE_EN			(0x0001)
+/* PLL208 Frequency Control 16bit (R/W) */
+#define U300_SYSCON_PFCR					(0x48)
+#define U300_SYSCON_PFCR_DPLL_MULT_NUM				(0x000F)
+/* Power Management Control 16bit (R/W) */
+#define U300_SYSCON_PMCR					(0x50)
+#define U300_SYSCON_PMCR_DCON_ENABLE				(0x0002)
+#define U300_SYSCON_PMCR_PWR_MGNT_ENABLE			(0x0001)
+/*
+ * All other clocking registers moved to clock.c!
+ */
+/* Reset Out 16bit (R/W) */
+#define U300_SYSCON_RCR						(0x6c)
+#define U300_SYSCON_RCR_RESOUT0_RST_N_DISABLE			(0x0001)
+/* EMIF Slew Rate Control 16bit (R/W) */
+#define U300_SYSCON_SRCLR					(0x70)
+#define U300_SYSCON_SRCLR_MASK					(0x03FF)
+#define U300_SYSCON_SRCLR_VALUE					(0x03FF)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_5_B			(0x0200)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_5_A			(0x0100)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_4_B			(0x0080)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_4_A			(0x0040)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_3_B			(0x0020)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_3_A			(0x0010)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_2_B			(0x0008)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_2_A			(0x0004)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_1_B			(0x0002)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_1_A			(0x0001)
+/* EMIF Clock Control Register 16bit (R/W) */
+#define U300_SYSCON_ECCR					(0x0078)
+#define U300_SYSCON_ECCR_MASK					(0x000F)
+#define U300_SYSCON_ECCR_EMIF_1_STATIC_CLK_EN_N_DISABLE		(0x0008)
+#define U300_SYSCON_ECCR_EMIF_1_RET_OUT_CLK_EN_N_DISABLE	(0x0004)
+#define U300_SYSCON_ECCR_EMIF_MEMCLK_RET_EN_N_DISABLE		(0x0002)
+#define U300_SYSCON_ECCR_EMIF_SDRCLK_RET_EN_N_DISABLE		(0x0001)
+/* PAD MUX Control register 1 (LOW) 16bit (R/W) */
+#define U300_SYSCON_PMC1LR					(0x007C)
+#define U300_SYSCON_PMC1LR_MASK					(0xFFFF)
+#define U300_SYSCON_PMC1LR_CDI_MASK				(0xC000)
+#define U300_SYSCON_PMC1LR_CDI_CDI				(0x0000)
+#define U300_SYSCON_PMC1LR_CDI_EMIF				(0x4000)
+#define U300_SYSCON_PMC1LR_CDI_GPIO				(0x8000)
+#define U300_SYSCON_PMC1LR_CDI_WCDMA				(0xC000)
+#define U300_SYSCON_PMC1LR_PDI_MASK				(0x3000)
+#define U300_SYSCON_PMC1LR_PDI_PDI				(0x0000)
+#define U300_SYSCON_PMC1LR_PDI_EGG				(0x1000)
+#define U300_SYSCON_PMC1LR_PDI_WCDMA				(0x3000)
+#define U300_SYSCON_PMC1LR_MMCSD_MASK				(0x0C00)
+#define U300_SYSCON_PMC1LR_MMCSD_MMCSD				(0x0000)
+#define U300_SYSCON_PMC1LR_MMCSD_MSPRO				(0x0400)
+#define U300_SYSCON_PMC1LR_MMCSD_DSP				(0x0800)
+#define U300_SYSCON_PMC1LR_MMCSD_WCDMA				(0x0C00)
+#define U300_SYSCON_PMC1LR_ETM_MASK				(0x0300)
+#define U300_SYSCON_PMC1LR_ETM_ACC				(0x0000)
+#define U300_SYSCON_PMC1LR_ETM_APP				(0x0100)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_MASK			(0x00C0)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_STATIC			(0x0000)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_NFIF			(0x0040)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_SDRAM			(0x0080)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_STATIC_2GB		(0x00C0)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_MASK			(0x0030)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_STATIC			(0x0000)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_NFIF			(0x0010)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_SDRAM			(0x0020)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_SEMI			(0x0030)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_MASK			(0x000C)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_STATIC			(0x0000)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_NFIF			(0x0004)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_SDRAM			(0x0008)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_SEMI			(0x000C)
+#define U300_SYSCON_PMC1LR_EMIF_1_MASK				(0x0003)
+#define U300_SYSCON_PMC1LR_EMIF_1_STATIC			(0x0000)
+#define U300_SYSCON_PMC1LR_EMIF_1_SDRAM0			(0x0001)
+#define U300_SYSCON_PMC1LR_EMIF_1_SDRAM1			(0x0002)
+#define U300_SYSCON_PMC1LR_EMIF_1				(0x0003)
+/* PAD MUX Control register 2 (HIGH) 16bit (R/W) */
+#define U300_SYSCON_PMC1HR					(0x007E)
+#define U300_SYSCON_PMC1HR_MASK					(0xFFFF)
+#define U300_SYSCON_PMC1HR_MISC_2_MASK				(0xC000)
+#define U300_SYSCON_PMC1HR_MISC_2_APP_GPIO			(0x0000)
+#define U300_SYSCON_PMC1HR_MISC_2_MSPRO				(0x4000)
+#define U300_SYSCON_PMC1HR_MISC_2_DSP				(0x8000)
+#define U300_SYSCON_PMC1HR_MISC_2_AAIF				(0xC000)
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_MASK			(0x3000)
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_APP_GPIO			(0x0000)
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_NFIF			(0x1000)
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_DSP			(0x2000)
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_AAIF			(0x3000)
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_MASK			(0x0C00)
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_APP_GPIO			(0x0000)
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_MMC			(0x0400)
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_DSP			(0x0800)
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_AAIF			(0x0C00)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK			(0x0300)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_APP_GPIO		(0x0000)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI			(0x0100)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_AAIF			(0x0300)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK			(0x00C0)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_APP_GPIO		(0x0000)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI			(0x0040)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_AAIF			(0x00C0)
+#define U300_SYSCON_PMC1HR_APP_SPI_2_MASK			(0x0030)
+#define U300_SYSCON_PMC1HR_APP_SPI_2_APP_GPIO			(0x0000)
+#define U300_SYSCON_PMC1HR_APP_SPI_2_SPI			(0x0010)
+#define U300_SYSCON_PMC1HR_APP_SPI_2_DSP			(0x0020)
+#define U300_SYSCON_PMC1HR_APP_SPI_2_AAIF			(0x0030)
+#define U300_SYSCON_PMC1HR_APP_UART0_2_MASK			(0x000C)
+#define U300_SYSCON_PMC1HR_APP_UART0_2_APP_GPIO			(0x0000)
+#define U300_SYSCON_PMC1HR_APP_UART0_2_UART0			(0x0004)
+#define U300_SYSCON_PMC1HR_APP_UART0_2_NFIF_CS			(0x0008)
+#define U300_SYSCON_PMC1HR_APP_UART0_2_AAIF			(0x000C)
+#define U300_SYSCON_PMC1HR_APP_UART0_1_MASK			(0x0003)
+#define U300_SYSCON_PMC1HR_APP_UART0_1_APP_GPIO			(0x0000)
+#define U300_SYSCON_PMC1HR_APP_UART0_1_UART0			(0x0001)
+#define U300_SYSCON_PMC1HR_APP_UART0_1_AAIF			(0x0003)
+/* Step one for killing the applications system 16bit (-/W) */
+#define U300_SYSCON_KA1R					(0x0080)
+#define U300_SYSCON_KA1R_MASK					(0xFFFF)
+#define U300_SYSCON_KA1R_VALUE					(0xFFFF)
+/* Step two for killing the application system 16bit (-/W) */
+#define U300_SYSCON_KA2R					(0x0084)
+#define U300_SYSCON_KA2R_MASK					(0xFFFF)
+#define U300_SYSCON_KA2R_VALUE					(0xFFFF)
+/* MMC/MSPRO frequency divider register 0 16bit (R/W) */
+#define U300_SYSCON_MMF0R					(0x90)
+#define U300_SYSCON_MMF0R_MASK					(0x00FF)
+#define U300_SYSCON_MMF0R_FREQ_0_HIGH_MASK			(0x00F0)
+#define U300_SYSCON_MMF0R_FREQ_0_LOW_MASK			(0x000F)
+/* MMC/MSPRO frequency divider register 1 16bit (R/W) */
+#define U300_SYSCON_MMF1R					(0x94)
+#define U300_SYSCON_MMF1R_MASK					(0x00FF)
+#define U300_SYSCON_MMF1R_FREQ_1_HIGH_MASK			(0x00F0)
+#define U300_SYSCON_MMF1R_FREQ_1_LOW_MASK			(0x000F)
+/* AAIF control register 16 bit (R/W) */
+#define U300_SYSCON_AAIFCR					(0x98)
+#define U300_SYSCON_AAIFCR_MASK					(0x0003)
+#define U300_SYSCON_AAIFCR_AASW_CTRL_MASK			(0x0003)
+#define U300_SYSCON_AAIFCR_AASW_CTRL_FUNCTIONAL			(0x0000)
+#define U300_SYSCON_AAIFCR_AASW_CTRL_MONITORING			(0x0001)
+#define U300_SYSCON_AAIFCR_AASW_CTRL_ACC_TO_EXT			(0x0002)
+#define U300_SYSCON_AAIFCR_AASW_CTRL_APP_TO_EXT			(0x0003)
+/* Clock control for the MMC and MSPRO blocks 16bit (R/W) */
+#define U300_SYSCON_MMCR					(0x9C)
+#define U300_SYSCON_MMCR_MASK					(0x0003)
+#define U300_SYSCON_MMCR_MMC_FB_CLK_SEL_ENABLE			(0x0002)
+#define U300_SYSCON_MMCR_MSPRO_FREQSEL_ENABLE			(0x0001)
+
+/* TODO: More SYSCON registers missing */
+#define U300_SYSCON_PMC3R					(0x10c)
+#define U300_SYSCON_PMC3R_APP_MISC_11_MASK			(0xc000)
+#define U300_SYSCON_PMC3R_APP_MISC_11_SPI			(0x4000)
+#define U300_SYSCON_PMC3R_APP_MISC_10_MASK			(0x3000)
+#define U300_SYSCON_PMC3R_APP_MISC_10_SPI			(0x1000)
+/* TODO: Missing other configs, I just added the SPI stuff */
+
+/* SYS_0_CLK_CONTROL first clock control 16bit (R/W) */
+#define U300_SYSCON_S0CCR					(0x120)
+#define U300_SYSCON_S0CCR_FIELD_MASK				(0x43FF)
+#define U300_SYSCON_S0CCR_CLOCK_REQ				(0x4000)
+#define U300_SYSCON_S0CCR_CLOCK_INV				(0x0200)
+#define U300_SYSCON_S0CCR_CLOCK_FREQ_MASK			(0x01E0)
+#define U300_SYSCON_S0CCR_CLOCK_SELECT_MASK			(0x001E)
+#define U300_SYSCON_S0CCR_CLOCK_ENABLE				(0x0001)
+#define U300_SYSCON_S0CCR_SEL_MCLK				(0x8<<1)
+#define U300_SYSCON_S0CCR_SEL_ACC_FSM_CLK			(0xA<<1)
+#define U300_SYSCON_S0CCR_SEL_PLL60_48_CLK			(0xC<<1)
+#define U300_SYSCON_S0CCR_SEL_PLL60_60_CLK			(0xD<<1)
+#define U300_SYSCON_S0CCR_SEL_ACC_PLL208_CLK			(0xE<<1)
+#define U300_SYSCON_S0CCR_SEL_APP_PLL13_CLK			(0x0<<1)
+#define U300_SYSCON_S0CCR_SEL_APP_FSM_CLK			(0x2<<1)
+#define U300_SYSCON_S0CCR_SEL_RTC_CLK				(0x4<<1)
+#define U300_SYSCON_S0CCR_SEL_APP_PLL208_CLK			(0x6<<1)
+/* SYS_1_CLK_CONTROL second clock control 16 bit (R/W) */
+#define U300_SYSCON_S1CCR					(0x124)
+#define U300_SYSCON_S1CCR_FIELD_MASK				(0x43FF)
+#define U300_SYSCON_S1CCR_CLOCK_REQ				(0x4000)
+#define U300_SYSCON_S1CCR_CLOCK_INV				(0x0200)
+#define U300_SYSCON_S1CCR_CLOCK_FREQ_MASK			(0x01E0)
+#define U300_SYSCON_S1CCR_CLOCK_SELECT_MASK			(0x001E)
+#define U300_SYSCON_S1CCR_CLOCK_ENABLE				(0x0001)
+#define U300_SYSCON_S1CCR_SEL_MCLK				(0x8<<1)
+#define U300_SYSCON_S1CCR_SEL_ACC_FSM_CLK			(0xA<<1)
+#define U300_SYSCON_S1CCR_SEL_PLL60_48_CLK			(0xC<<1)
+#define U300_SYSCON_S1CCR_SEL_PLL60_60_CLK			(0xD<<1)
+#define U300_SYSCON_S1CCR_SEL_ACC_PLL208_CLK			(0xE<<1)
+#define U300_SYSCON_S1CCR_SEL_ACC_PLL13_CLK			(0x0<<1)
+#define U300_SYSCON_S1CCR_SEL_APP_FSM_CLK			(0x2<<1)
+#define U300_SYSCON_S1CCR_SEL_RTC_CLK				(0x4<<1)
+#define U300_SYSCON_S1CCR_SEL_APP_PLL208_CLK			(0x6<<1)
+/* SYS_2_CLK_CONTROL third clock contol 16 bit (R/W) */
+#define U300_SYSCON_S2CCR					(0x128)
+#define U300_SYSCON_S2CCR_FIELD_MASK				(0xC3FF)
+#define U300_SYSCON_S2CCR_CLK_STEAL				(0x8000)
+#define U300_SYSCON_S2CCR_CLOCK_REQ				(0x4000)
+#define U300_SYSCON_S2CCR_CLOCK_INV				(0x0200)
+#define U300_SYSCON_S2CCR_CLOCK_FREQ_MASK			(0x01E0)
+#define U300_SYSCON_S2CCR_CLOCK_SELECT_MASK			(0x001E)
+#define U300_SYSCON_S2CCR_CLOCK_ENABLE				(0x0001)
+#define U300_SYSCON_S2CCR_SEL_MCLK				(0x8<<1)
+#define U300_SYSCON_S2CCR_SEL_ACC_FSM_CLK			(0xA<<1)
+#define U300_SYSCON_S2CCR_SEL_PLL60_48_CLK			(0xC<<1)
+#define U300_SYSCON_S2CCR_SEL_PLL60_60_CLK			(0xD<<1)
+#define U300_SYSCON_S2CCR_SEL_ACC_PLL208_CLK			(0xE<<1)
+#define U300_SYSCON_S2CCR_SEL_ACC_PLL13_CLK			(0x0<<1)
+#define U300_SYSCON_S2CCR_SEL_APP_FSM_CLK			(0x2<<1)
+#define U300_SYSCON_S2CCR_SEL_RTC_CLK				(0x4<<1)
+#define U300_SYSCON_S2CCR_SEL_APP_PLL208_CLK			(0x6<<1)
+/* SYS_MISC_CONTROL, miscellaneous 16bit (R/W) */
+#define U300_SYSCON_MCR						(0x12c)
+#define U300_SYSCON_MCR_FIELD_MASK				(0x00FF)
+#define U300_SYSCON_MCR_PMGEN_CR_4_MASK				(0x00C0)
+#define U300_SYSCON_MCR_PMGEN_CR_4_GPIO				(0x0000)
+#define U300_SYSCON_MCR_PMGEN_CR_4_SPI				(0x0040)
+#define U300_SYSCON_MCR_PMGEN_CR_4_AAIF				(0x00C0)
+#define U300_SYSCON_MCR_PMGEN_CR_2_MASK				(0x0030)
+#define U300_SYSCON_MCR_PMGEN_CR_2_GPIO				(0x0000)
+#define U300_SYSCON_MCR_PMGEN_CR_2_EMIF_1_STATIC		(0x0010)
+#define U300_SYSCON_MCR_PMGEN_CR_2_DSP				(0x0020)
+#define U300_SYSCON_MCR_PMGEN_CR_2_AAIF				(0x0030)
+#define U300_SYSCON_MCR_PMGEN_CR_0_MASK				(0x000C)
+#define U300_SYSCON_MCR_PMGEN_CR_0_EMIF_1_SDRAM_M1		(0x0000)
+#define U300_SYSCON_MCR_PMGEN_CR_0_EMIF_1_SDRAM_M2		(0x0004)
+#define U300_SYSCON_MCR_PMGEN_CR_0_EMIF_1_SDRAM_M3		(0x0008)
+#define U300_SYSCON_MCR_PMGEN_CR_0_EMIF_0_SDRAM			(0x000C)
+#define U300_SYSCON_MCR_PM1G_MODE_ENABLE			(0x0002)
+#define U300_SYSCON_MCR_PMTG5_MODE_ENABLE			(0x0001)
+/* Clock activity observability register 0 */
+#define U300_SYSCON_C0OAR					(0x140)
+#define U300_SYSCON_C0OAR_MASK					(0xFFFF)
+#define U300_SYSCON_C0OAR_VALUE					(0xFFFF)
+#define U300_SYSCON_C0OAR_BT_H_CLK				(0x8000)
+#define U300_SYSCON_C0OAR_ASPB_P_CLK				(0x4000)
+#define U300_SYSCON_C0OAR_APP_SEMI_H_CLK			(0x2000)
+#define U300_SYSCON_C0OAR_APP_SEMI_CLK				(0x1000)
+#define U300_SYSCON_C0OAR_APP_MMC_MSPRO_CLK			(0x0800)
+#define U300_SYSCON_C0OAR_APP_I2S1_CLK				(0x0400)
+#define U300_SYSCON_C0OAR_APP_I2S0_CLK				(0x0200)
+#define U300_SYSCON_C0OAR_APP_CPU_CLK				(0x0100)
+#define U300_SYSCON_C0OAR_APP_52_CLK				(0x0080)
+#define U300_SYSCON_C0OAR_APP_208_CLK				(0x0040)
+#define U300_SYSCON_C0OAR_APP_104_CLK				(0x0020)
+#define U300_SYSCON_C0OAR_APEX_CLK				(0x0010)
+#define U300_SYSCON_C0OAR_AHPB_M_H_CLK				(0x0008)
+#define U300_SYSCON_C0OAR_AHB_CLK				(0x0004)
+#define U300_SYSCON_C0OAR_AFPB_P_CLK				(0x0002)
+#define U300_SYSCON_C0OAR_AAIF_CLK				(0x0001)
+/* Clock activity observability register 1 */
+#define U300_SYSCON_C1OAR					(0x144)
+#define U300_SYSCON_C1OAR_MASK					(0x3FFE)
+#define U300_SYSCON_C1OAR_VALUE					(0x3FFE)
+#define U300_SYSCON_C1OAR_NFIF_F_CLK				(0x2000)
+#define U300_SYSCON_C1OAR_MSPRO_CLK				(0x1000)
+#define U300_SYSCON_C1OAR_MMC_P_CLK				(0x0800)
+#define U300_SYSCON_C1OAR_MMC_CLK				(0x0400)
+#define U300_SYSCON_C1OAR_KP_P_CLK				(0x0200)
+#define U300_SYSCON_C1OAR_I2C1_P_CLK				(0x0100)
+#define U300_SYSCON_C1OAR_I2C0_P_CLK				(0x0080)
+#define U300_SYSCON_C1OAR_GPIO_CLK				(0x0040)
+#define U300_SYSCON_C1OAR_EMIF_MPMC_CLK				(0x0020)
+#define U300_SYSCON_C1OAR_EMIF_H_CLK				(0x0010)
+#define U300_SYSCON_C1OAR_EVHIST_CLK				(0x0008)
+#define U300_SYSCON_C1OAR_PPM_CLK				(0x0004)
+#define U300_SYSCON_C1OAR_DMA_CLK				(0x0002)
+/* Clock activity observability register 2 */
+#define U300_SYSCON_C2OAR					(0x148)
+#define U300_SYSCON_C2OAR_MASK					(0x0FFF)
+#define U300_SYSCON_C2OAR_VALUE					(0x0FFF)
+#define U300_SYSCON_C2OAR_XGAM_CDI_CLK				(0x0800)
+#define U300_SYSCON_C2OAR_XGAM_CLK				(0x0400)
+#define U300_SYSCON_C2OAR_VC_H_CLK				(0x0200)
+#define U300_SYSCON_C2OAR_VC_CLK				(0x0100)
+#define U300_SYSCON_C2OAR_UA_P_CLK				(0x0080)
+#define U300_SYSCON_C2OAR_TMR1_CLK				(0x0040)
+#define U300_SYSCON_C2OAR_TMR0_CLK				(0x0020)
+#define U300_SYSCON_C2OAR_SPI_P_CLK				(0x0010)
+#define U300_SYSCON_C2OAR_PCM_I2S1_CORE_CLK			(0x0008)
+#define U300_SYSCON_C2OAR_PCM_I2S1_CLK				(0x0004)
+#define U300_SYSCON_C2OAR_PCM_I2S0_CORE_CLK			(0x0002)
+#define U300_SYSCON_C2OAR_PCM_I2S0_CLK				(0x0001)
+
+/* Chip ID register 16bit (R/-) */
+#define U300_SYSCON_CIDR					(0x400)
+/* Video IRQ clear 16bit (R/W) */
+#define U300_SYSCON_VICR					(0x404)
+#define U300_SYSCON_VICR_VIDEO1_IRQ_CLEAR_ENABLE		(0x0002)
+#define U300_SYSCON_VICR_VIDEO0_IRQ_CLEAR_ENABLE		(0x0001)
+/* SMCR */
+#define U300_SYSCON_SMCR					(0x4d0)
+#define U300_SYSCON_SMCR_FIELD_MASK				(0x000e)
+#define U300_SYSCON_SMCR_SEMI_SREFACK_IND			(0x0008)
+#define U300_SYSCON_SMCR_SEMI_SREFREQ_ENABLE			(0x0004)
+#define U300_SYSCON_SMCR_SEMI_EXT_BOOT_MODE_ENABLE		(0x0002)
+/* CPU_SW_DBGEN Software Debug Enable 16bit (R/W) */
+#define U300_SYSCON_CSDR					(0x4f0)
+#define U300_SYSCON_CSDR_SW_DEBUG_ENABLE			(0x0001)
+/* PRINT_CONTROL Print Control 16bit (R/-) */
+#define U300_SYSCON_PCR						(0x4f8)
+#define U300_SYSCON_PCR_SERV_IND				(0x0001)
+/* BOOT_CONTROL 16bit (R/-) */
+#define U300_SYSCON_BCR						(0x4fc)
+#define U300_SYSCON_BCR_ACC_CPU_SUBSYS_VINITHI_IND		(0x0400)
+#define U300_SYSCON_BCR_APP_CPU_SUBSYS_VINITHI_IND		(0x0200)
+#define U300_SYSCON_BCR_EXTRA_BOOT_OPTION_MASK			(0x01FC)
+#define U300_SYSCON_BCR_APP_BOOT_SERV_MASK			(0x0003)
+
+
+/* CPU clock defines */
+/**
+ * CPU high frequency in MHz
+ */
+#define SYSCON_CPU_CLOCK_HIGH    208
+/**
+ * CPU medium frequency in MHz
+ */
+#define SYSCON_CPU_CLOCK_MEDIUM  104
+/**
+ * CPU low frequency in MHz
+ */
+#define SYSCON_CPU_CLOCK_LOW      13
+
+/* EMIF clock defines */
+/**
+ * EMIF high frequency in MHz
+ */
+#define SYSCON_EMIF_CLOCK_HIGH   104
+/**
+ * EMIF medium frequency in MHz
+ */
+#define SYSCON_EMIF_CLOCK_MEDIUM 104
+/**
+ * EMIF low frequency in MHz
+ */
+#define SYSCON_EMIF_CLOCK_LOW     13
+
+/* AHB clock defines */
+/**
+ * AHB high frequency in MHz
+ */
+#define SYSCON_AHB_CLOCK_HIGH     52
+/**
+ * AHB medium frequency in MHz
+ */
+#define SYSCON_AHB_CLOCK_MEDIUM   52
+/**
+ * AHB low frequency in MHz
+ */
+#define SYSCON_AHB_CLOCK_LOW       7  /* i.e 13/2=6.5MHz */
+
+enum syscon_busmaster {
+  SYSCON_BM_DMAC,
+  SYSCON_BM_XGAM,
+  SYSCON_BM_VIDEO_ENC
+};
+
+/*
+ * Note that this array must match the order of the array "clk_reg"
+ * in syscon.c
+ */
+enum syscon_clk {
+  SYSCON_CLKCONTROL_SLOW_BRIDGE,
+  SYSCON_CLKCONTROL_UART,
+  SYSCON_CLKCONTROL_BTR,
+  SYSCON_CLKCONTROL_EH,
+  SYSCON_CLKCONTROL_GPIO,
+  SYSCON_CLKCONTROL_KEYPAD,
+  SYSCON_CLKCONTROL_APP_TIMER,
+  SYSCON_CLKCONTROL_ACC_TIMER,
+  SYSCON_CLKCONTROL_FAST_BRIDGE,
+  SYSCON_CLKCONTROL_I2C0,
+  SYSCON_CLKCONTROL_I2C1,
+  SYSCON_CLKCONTROL_I2S0,
+  SYSCON_CLKCONTROL_I2S1,
+  SYSCON_CLKCONTROL_MMC,
+  SYSCON_CLKCONTROL_SPI,
+  SYSCON_CLKCONTROL_I2S0_CORE,
+  SYSCON_CLKCONTROL_I2S1_CORE,
+  SYSCON_CLKCONTROL_AAIF,
+  SYSCON_CLKCONTROL_AHB,
+  SYSCON_CLKCONTROL_APEX,
+  SYSCON_CLKCONTROL_CPU,
+  SYSCON_CLKCONTROL_DMA,
+  SYSCON_CLKCONTROL_EMIF,
+  SYSCON_CLKCONTROL_NAND_IF,
+  SYSCON_CLKCONTROL_VIDEO_ENC,
+  SYSCON_CLKCONTROL_XGAM,
+  SYSCON_CLKCONTROL_SEMI,
+  SYSCON_CLKCONTROL_AHB_SUBSYS,
+  SYSCON_CLKCONTROL_MSPRO
+};
+
+enum syscon_sysclk_mode {
+  SYSCON_SYSCLK_DISABLED,
+  SYSCON_SYSCLK_M_CLK,
+  SYSCON_SYSCLK_ACC_FSM,
+  SYSCON_SYSCLK_PLL60_48,
+  SYSCON_SYSCLK_PLL60_60,
+  SYSCON_SYSCLK_ACC_PLL208,
+  SYSCON_SYSCLK_APP_PLL13,
+  SYSCON_SYSCLK_APP_FSM,
+  SYSCON_SYSCLK_RTC,
+  SYSCON_SYSCLK_APP_PLL208
+};
+
+enum syscon_sysclk_req {
+  SYSCON_SYSCLKREQ_DISABLED,
+  SYSCON_SYSCLKREQ_ACTIVE_LOW
+};
+
+enum syscon_clk_mode {
+  SYSCON_CLKMODE_OFF,
+  SYSCON_CLKMODE_DEFAULT,
+  SYSCON_CLKMODE_LOW,
+  SYSCON_CLKMODE_MEDIUM,
+  SYSCON_CLKMODE_HIGH,
+  SYSCON_CLKMODE_PERMANENT,
+  SYSCON_CLKMODE_ON,
+};
+
+enum syscon_call_mode {
+  SYSCON_CLKCALL_NOWAIT,
+  SYSCON_CLKCALL_WAIT,
+};
+
+int syscon_dc_on(bool keep_power_on);
+int syscon_set_busmaster_active_state(enum syscon_busmaster busmaster,
+				      bool active);
+bool syscon_get_busmaster_active_state(void);
+int syscon_set_sleep_mask(enum syscon_clk,
+			  bool sleep_ctrl);
+int syscon_config_sysclk(u32 sysclk,
+			 enum syscon_sysclk_mode sysclkmode,
+			 bool inverse,
+			 u32 divisor,
+			 enum syscon_sysclk_req sysclkreq);
+bool syscon_can_turn_off_semi_clock(void);
+
+/* This function is restricted to core.c */
+int syscon_request_normal_power(bool req);
+
+/* This function is restricted to be used by platform_speed.c */
+int syscon_speed_request(enum syscon_call_mode wait_mode,
+			 enum syscon_clk_mode req_clk_mode);
+#endif /* __MACH_SYSCON_H */
diff --git a/arch/arm/mach-u300/include/mach/system.h b/arch/arm/mach-u300/include/mach/system.h
new file mode 100644
index 0000000..8daf136
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/system.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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>
+ */
+#include <mach/hardware.h>
+#include <asm/io.h>
+#include <asm/hardware/vic.h>
+#include <asm/irq.h>
+
+/* Forward declare this function from the watchdog */
+void coh901327_watchdog_reset(void);
+
+static inline void arch_idle(void)
+{
+	cpu_do_idle();
+}
+
+static void arch_reset(char mode, const char *cmd)
+{
+	switch (mode) {
+	case 's':
+	case 'h':
+		printk(KERN_CRIT "RESET: shutting down/rebooting system\n");
+		/* Disable interrupts */
+		local_irq_disable();
+#ifdef CONFIG_COH901327_WATCHDOG
+		coh901327_watchdog_reset();
+#endif
+		break;
+	default:
+		/* Do nothing */
+		break;
+	}
+	/* Wait for system do die/reset. */
+	while (1);
+}
diff --git a/arch/arm/mach-u300/include/mach/timex.h b/arch/arm/mach-u300/include/mach/timex.h
new file mode 100644
index 0000000..f233b72
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/timex.h
@@ -0,0 +1,17 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/timex.h
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Platform tick rate definition.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#ifndef __MACH_TIMEX_H
+#define __MACH_TIMEX_H
+
+/* This is for the APP OS GP1 (General Purpose 1) timer */
+#define CLOCK_TICK_RATE		1000000
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/u300-regs.h b/arch/arm/mach-u300/include/mach/u300-regs.h
new file mode 100644
index 0000000..88333df
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/u300-regs.h
@@ -0,0 +1,187 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/u300-regs.h
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Basic register address definitions in physical memory and
+ * some block defintions for core devices like the timer.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+
+#ifndef __MACH_U300_REGS_H
+#define __MACH_U300_REGS_H
+
+/*
+ * These are the large blocks of memory allocated for I/O.
+ * the defines are used for setting up the I/O memory mapping.
+ */
+
+/* NAND Flash CS0 */
+#define U300_NAND_CS0_PHYS_BASE		0x80000000
+#define U300_NAND_CS0_VIRT_BASE		0xff040000
+
+/* NFIF */
+#define U300_NAND_IF_PHYS_BASE		0x9f800000
+#define U300_NAND_IF_VIRT_BASE		0xff030000
+
+/* AHB Peripherals */
+#define U300_AHB_PER_PHYS_BASE		0xa0000000
+#define U300_AHB_PER_VIRT_BASE		0xff010000
+
+/* FAST Peripherals */
+#define U300_FAST_PER_PHYS_BASE		0xc0000000
+#define U300_FAST_PER_VIRT_BASE		0xff020000
+
+/* SLOW Peripherals */
+#define U300_SLOW_PER_PHYS_BASE		0xc0010000
+#define U300_SLOW_PER_VIRT_BASE		0xff000000
+
+/* Boot ROM */
+#define U300_BOOTROM_PHYS_BASE		0xffff0000
+#define U300_BOOTROM_VIRT_BASE		0xffff0000
+
+/* SEMI config base */
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SEMI_CONFIG_BASE		0x2FFE0000
+#else
+#define U300_SEMI_CONFIG_BASE		0x30000000
+#endif
+
+/*
+ * All the following peripherals are specified at their PHYSICAL address,
+ * so if you need to access them (in the kernel), you MUST use the macros
+ * defined in <asm/io.h> to map to the IO_ADDRESS_AHB() IO_ADDRESS_FAST()
+ * etc.
+ */
+
+/*
+ * AHB peripherals
+ */
+
+/* AHB Peripherals Bridge Controller */
+#define U300_AHB_BRIDGE_BASE		(U300_AHB_PER_PHYS_BASE+0x0000)
+
+/* Vectored Interrupt Controller 0, servicing 32 interrupts */
+#define U300_INTCON0_BASE		(U300_AHB_PER_PHYS_BASE+0x1000)
+#define U300_INTCON0_VBASE		(U300_AHB_PER_VIRT_BASE+0x1000)
+
+/* Vectored Interrupt Controller 1, servicing 32 interrupts */
+#define U300_INTCON1_BASE		(U300_AHB_PER_PHYS_BASE+0x2000)
+#define U300_INTCON1_VBASE		(U300_AHB_PER_VIRT_BASE+0x2000)
+
+/* Memory Stick Pro (MSPRO) controller */
+#define U300_MSPRO_BASE			(U300_AHB_PER_PHYS_BASE+0x3000)
+
+/* EMIF Configuration Area */
+#define U300_EMIF_CFG_BASE		(U300_AHB_PER_PHYS_BASE+0x4000)
+
+
+/*
+ * FAST peripherals
+ */
+
+/* FAST bridge control */
+#define U300_FAST_BRIDGE_BASE		(U300_FAST_PER_PHYS_BASE+0x0000)
+
+/* MMC/SD controller */
+#define U300_MMCSD_BASE			(U300_FAST_PER_PHYS_BASE+0x1000)
+
+/* PCM I2S0 controller */
+#define U300_PCM_I2S0_BASE		(U300_FAST_PER_PHYS_BASE+0x2000)
+
+/* PCM I2S1 controller */
+#define U300_PCM_I2S1_BASE		(U300_FAST_PER_PHYS_BASE+0x3000)
+
+/* I2C0 controller */
+#define U300_I2C0_BASE			(U300_FAST_PER_PHYS_BASE+0x4000)
+
+/* I2C1 controller */
+#define U300_I2C1_BASE			(U300_FAST_PER_PHYS_BASE+0x5000)
+
+/* SPI controller */
+#define U300_SPI_BASE			(U300_FAST_PER_PHYS_BASE+0x6000)
+
+#ifdef CONFIG_MACH_U300_BS335
+/* Fast UART1 on U335 only */
+#define U300_UART1_BASE			(U300_SLOW_PER_PHYS_BASE+0x7000)
+#endif
+
+/*
+ * SLOW peripherals
+ */
+
+/* SLOW bridge control */
+#define U300_SLOW_BRIDGE_BASE		(U300_SLOW_PER_PHYS_BASE)
+
+/* SYSCON */
+#define U300_SYSCON_BASE		(U300_SLOW_PER_PHYS_BASE+0x1000)
+#define U300_SYSCON_VBASE		(U300_SLOW_PER_VIRT_BASE+0x1000)
+
+/* Watchdog */
+#define U300_WDOG_BASE			(U300_SLOW_PER_PHYS_BASE+0x2000)
+
+/* UART0 */
+#define U300_UART0_BASE			(U300_SLOW_PER_PHYS_BASE+0x3000)
+
+/* APP side special timer */
+#define U300_TIMER_APP_BASE		(U300_SLOW_PER_PHYS_BASE+0x4000)
+#define U300_TIMER_APP_VBASE		(U300_SLOW_PER_VIRT_BASE+0x4000)
+
+/* Keypad */
+#define U300_KEYPAD_BASE		(U300_SLOW_PER_PHYS_BASE+0x5000)
+
+/* GPIO */
+#define U300_GPIO_BASE			(U300_SLOW_PER_PHYS_BASE+0x6000)
+
+/* RTC */
+#define U300_RTC_BASE			(U300_SLOW_PER_PHYS_BASE+0x7000)
+
+/* Bus tracer */
+#define U300_BUSTR_BASE			(U300_SLOW_PER_PHYS_BASE+0x8000)
+
+/* Event handler (hardware queue) */
+#define U300_EVHIST_BASE		(U300_SLOW_PER_PHYS_BASE+0x9000)
+
+/* Genric Timer */
+#define U300_TIMER_BASE			(U300_SLOW_PER_PHYS_BASE+0xa000)
+
+/* PPM */
+#define U300_PPM_BASE			(U300_SLOW_PER_PHYS_BASE+0xb000)
+
+
+/*
+ * REST peripherals
+ */
+
+/* ISP (image signal processor) is only available in U335 */
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_ISP_BASE			(0xA0008000)
+#endif
+
+/* DMA Controller base */
+#define U300_DMAC_BASE			(0xC0020000)
+
+/* MSL Base */
+#define U300_MSL_BASE			(0xc0022000)
+
+/* APEX Base */
+#define U300_APEX_BASE			(0xc0030000)
+
+/* Video Encoder Base */
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_VIDEOENC_BASE		(0xc0080000)
+#else
+#define U300_VIDEOENC_BASE		(0xc0040000)
+#endif
+
+/* XGAM Base */
+#define U300_XGAM_BASE			(0xd0000000)
+
+/*
+ * Virtual accessor macros for static devices
+ */
+
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/uncompress.h b/arch/arm/mach-u300/include/mach/uncompress.h
new file mode 100644
index 0000000..29acb71
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/uncompress.h
@@ -0,0 +1,46 @@
+/*
+ * arch/arm/mach-u300/include/mach/uncompress.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
+ */
+#define AMBA_UART_DR	(*(volatile unsigned char *)0xc0013000)
+#define AMBA_UART_LCRH	(*(volatile unsigned char *)0xc001302C)
+#define AMBA_UART_CR	(*(volatile unsigned char *)0xc0013030)
+#define AMBA_UART_FR	(*(volatile unsigned char *)0xc0013018)
+
+/*
+ * This does not append a newline
+ */
+static inline void putc(int c)
+{
+	while (AMBA_UART_FR & (1 << 5))
+		barrier();
+
+	AMBA_UART_DR = c;
+}
+
+static inline void flush(void)
+{
+	while (AMBA_UART_FR & (1 << 3))
+		barrier();
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
diff --git a/arch/arm/mach-u300/include/mach/vmalloc.h b/arch/arm/mach-u300/include/mach/vmalloc.h
new file mode 100644
index 0000000..b00c51a
--- /dev/null
+++ b/arch/arm/mach-u300/include/mach/vmalloc.h
@@ -0,0 +1,12 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/vmalloc.h
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Virtual memory allocations
+ * End must be above the I/O registers and on an even 2MiB boundary.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#define VMALLOC_END	0xfe800000
diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c
new file mode 100644
index 0000000..3138d39
--- /dev/null
+++ b/arch/arm/mach-u300/mmc.c
@@ -0,0 +1,216 @@
+/*
+ *
+ * arch/arm/mach-u300/mmc.c
+ *
+ *
+ * Copyright (C) 2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ * Author: Johan Lundin <johan.lundin@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ */
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+#include <linux/mmc/host.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
+
+#include <asm/mach/mmc.h>
+#include "mmc.h"
+
+struct mmci_card_event {
+	struct input_dev *mmc_input;
+	int mmc_inserted;
+	struct work_struct workq;
+	struct mmc_platform_data mmc0_plat_data;
+};
+
+static unsigned int mmc_status(struct device *dev)
+{
+	struct mmci_card_event *mmci_card = container_of(
+		dev->platform_data,
+		struct mmci_card_event, mmc0_plat_data);
+
+	return mmci_card->mmc_inserted;
+}
+
+/*
+ * Here follows a large chunk of code which will only be enabled if you
+ * have both the AB3100 chip mounted and the MMC subsystem activated.
+ */
+
+static u32 mmc_translate_vdd(struct device *dev, unsigned int voltage)
+{
+	int v;
+
+	/*
+	 * MMC Spec:
+	 * bit 7:	1.70 - 1.95V
+	 * bit 8 - 14:	2.0 - 2.6V
+	 * bit 15 - 23:	2.7 - 3.6V
+	 *
+	 * ab3100 voltages:
+	 * 000 - 2.85V
+	 * 001 - 2.75V
+	 * 010 - 1.8V
+	 * 011 - 1.5V
+	 */
+	switch (voltage) {
+	case 8:
+		v = 3;
+		break;
+	case 9:
+	case 10:
+	case 11:
+	case 12:
+	case 13:
+	case 14:
+	case 15:
+		v = 1;
+		break;
+	case 16:
+		v = 1;
+		break;
+	case 17:
+	case 18:
+	case 19:
+	case 20:
+	case 21:
+	case 22:
+	case 23:
+	case 24:
+		v = 0;
+		break;
+	default:
+		v = 0;
+		break;
+	}
+
+	/* PL180 voltage register bits */
+	return v << 2;
+}
+
+
+
+static int mmci_callback(void *data)
+{
+	struct mmci_card_event *mmci_card = data;
+
+	disable_irq_on_gpio_pin(U300_GPIO_PIN_MMC_CD);
+	schedule_work(&mmci_card->workq);
+
+	return 0;
+}
+
+
+static ssize_t gpio_show(struct device *dev, struct device_attribute *attr,
+		  char *buf)
+{
+	struct mmci_card_event *mmci_card = container_of(
+		dev->platform_data,
+		struct mmci_card_event, mmc0_plat_data);
+
+
+	return sprintf(buf, "%d\n", !mmci_card->mmc_inserted);
+}
+
+static DEVICE_ATTR(mmc_inserted, S_IRUGO, gpio_show, NULL);
+
+static void _mmci_callback(struct work_struct *ws)
+{
+
+	struct mmci_card_event *mmci_card = container_of(
+		ws,
+		struct mmci_card_event, workq);
+
+	mdelay(20);
+
+	mmci_card->mmc_inserted = !!gpio_get_value(U300_GPIO_PIN_MMC_CD);
+
+	input_report_switch(mmci_card->mmc_input, KEY_INSERT,
+			    !mmci_card->mmc_inserted);
+	input_sync(mmci_card->mmc_input);
+
+	pr_debug("MMC/SD card was %s\n",
+		 mmci_card->mmc_inserted ? "removed" : "inserted");
+
+	enable_irq_on_gpio_pin(U300_GPIO_PIN_MMC_CD, !mmci_card->mmc_inserted);
+}
+
+int __devinit mmc_init(struct amba_device *adev)
+{
+	struct mmci_card_event *mmci_card;
+	struct device *mmcsd_device = &adev->dev;
+	int ret = 0;
+
+	mmci_card = kzalloc(sizeof(struct mmci_card_event), GFP_KERNEL);
+	if (!mmci_card)
+		return -ENOMEM;
+
+	/* Nominally 2.85V on our platform */
+	mmci_card->mmc0_plat_data.ocr_mask = MMC_VDD_28_29;
+	mmci_card->mmc0_plat_data.translate_vdd = mmc_translate_vdd;
+	mmci_card->mmc0_plat_data.status = mmc_status;
+
+	mmcsd_device->platform_data = (void *) &mmci_card->mmc0_plat_data;
+
+	INIT_WORK(&mmci_card->workq, _mmci_callback);
+
+	ret = gpio_request(U300_GPIO_PIN_MMC_CD, "MMC card detection");
+	if (ret) {
+		printk(KERN_CRIT "Could not allocate MMC card detection " \
+		       "GPIO pin\n");
+		goto out;
+	}
+
+	ret = gpio_direction_input(U300_GPIO_PIN_MMC_CD);
+	if (ret) {
+		printk(KERN_CRIT "Invalid GPIO pin requested\n");
+		goto out;
+	}
+
+	ret = sysfs_create_file(&mmcsd_device->kobj,
+			       &dev_attr_mmc_inserted.attr);
+	if (ret)
+		goto out;
+
+	mmci_card->mmc_input = input_allocate_device();
+	if (!mmci_card->mmc_input) {
+		printk(KERN_CRIT "Could not allocate MMC input device\n");
+		return -ENOMEM;
+	}
+
+	mmci_card->mmc_input->name = "MMC insert notification";
+	mmci_card->mmc_input->id.bustype = BUS_HOST;
+	mmci_card->mmc_input->id.vendor = 0;
+	mmci_card->mmc_input->id.product = 0;
+	mmci_card->mmc_input->id.version = 0x0100;
+	mmci_card->mmc_input->dev.parent = mmcsd_device;
+	input_set_capability(mmci_card->mmc_input, EV_SW, KEY_INSERT);
+
+	/*
+	 * Since this must always be compiled into the kernel, this input
+	 * is never unregistered or free:ed.
+	 */
+	ret = input_register_device(mmci_card->mmc_input);
+	if (ret) {
+		input_free_device(mmci_card->mmc_input);
+		goto out;
+	}
+
+	input_set_drvdata(mmci_card->mmc_input, mmci_card);
+
+	ret = gpio_register_callback(U300_GPIO_PIN_MMC_CD, mmci_callback,
+				     mmci_card);
+
+	schedule_work(&mmci_card->workq);
+
+	printk(KERN_INFO "Registered MMC insert/remove notification\n");
+out:
+	return ret;
+}
diff --git a/arch/arm/mach-u300/mmc.h b/arch/arm/mach-u300/mmc.h
new file mode 100644
index 0000000..92b8512
--- /dev/null
+++ b/arch/arm/mach-u300/mmc.h
@@ -0,0 +1,18 @@
+/*
+ *
+ * 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-u300/padmux.c b/arch/arm/mach-u300/padmux.c
new file mode 100644
index 0000000..f366456
--- /dev/null
+++ b/arch/arm/mach-u300/padmux.c
@@ -0,0 +1,58 @@
+/*
+ *
+ * arch/arm/mach-u300/padmux.c
+ *
+ *
+ * Copyright (C) 2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * U300 PADMUX functions
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ *
+ */
+#include <linux/io.h>
+#include <linux/err.h>
+#include <mach/u300-regs.h>
+#include <mach/syscon.h>
+
+#include "padmux.h"
+
+/* Set the PAD MUX to route the MMC reader correctly to GPIO0. */
+void pmx_set_mission_mode_mmc(void)
+{
+	u16 val;
+
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_PMC1LR);
+	val &= ~U300_SYSCON_PMC1LR_MMCSD_MASK;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_PMC1LR);
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_PMC1HR);
+	val &= ~U300_SYSCON_PMC1HR_APP_GPIO_1_MASK;
+	val |= U300_SYSCON_PMC1HR_APP_GPIO_1_MMC;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_PMC1HR);
+}
+
+void pmx_set_mission_mode_spi(void)
+{
+	u16 val;
+
+	/* Set up padmuxing so the SPI port and its chipselects are active */
+	val = readw(U300_SYSCON_VBASE + U300_SYSCON_PMC1HR);
+	/*
+	 * Activate the SPI port (disable the use of these pins for generic
+	 * GPIO, DSP, AAIF
+	 */
+	val &= ~U300_SYSCON_PMC1HR_APP_SPI_2_MASK;
+	val |= U300_SYSCON_PMC1HR_APP_SPI_2_SPI;
+	/*
+	 * Use GPIO pin SPI CS1 for CS1 actually (it can be used for other
+	 * things also)
+	 */
+	val &= ~U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK;
+	val |= U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI;
+	/*
+	 * Use GPIO pin SPI CS2 for CS2 actually (it can be used for other
+	 * things also)
+	 */
+	val &= ~U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK;
+	val |= U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI;
+	writew(val, U300_SYSCON_VBASE + U300_SYSCON_PMC1HR);
+}
diff --git a/arch/arm/mach-u300/padmux.h b/arch/arm/mach-u300/padmux.h
new file mode 100644
index 0000000..8c2099a
--- /dev/null
+++ b/arch/arm/mach-u300/padmux.h
@@ -0,0 +1,19 @@
+/*
+ *
+ * arch/arm/mach-u300/padmux.h
+ *
+ *
+ * Copyright (C) 2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * U300 PADMUX API
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ *
+ */
+
+#ifndef __MACH_U300_PADMUX_H
+#define __MACH_U300_PADMUX_H
+
+void pmx_set_mission_mode_mmc(void);
+void pmx_set_mission_mode_spi(void);
+
+#endif
diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c
new file mode 100644
index 0000000..cce5320
--- /dev/null
+++ b/arch/arm/mach-u300/timer.c
@@ -0,0 +1,422 @@
+/*
+ *
+ * arch/arm/mach-u300/timer.c
+ *
+ *
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Timer COH 901 328, runs the OS timer interrupt.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+
+/* Generic stuff */
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+
+#include "clock.h"
+
+/*
+ * APP side special timer registers
+ * This timer contains four timers which can fire an interrupt each.
+ * OS (operating system) timer @ 32768 Hz
+ * DD (device driver) timer @ 1 kHz
+ * GP1 (general purpose 1) timer @ 1MHz
+ * GP2 (general purpose 2) timer @ 1MHz
+ */
+
+/* Reset OS Timer 32bit (-/W) */
+#define U300_TIMER_APP_ROST					(0x0000)
+#define U300_TIMER_APP_ROST_TIMER_RESET				(0x00000000)
+/* Enable OS Timer 32bit (-/W) */
+#define U300_TIMER_APP_EOST					(0x0004)
+#define U300_TIMER_APP_EOST_TIMER_ENABLE			(0x00000000)
+/* Disable OS Timer 32bit (-/W) */
+#define U300_TIMER_APP_DOST					(0x0008)
+#define U300_TIMER_APP_DOST_TIMER_DISABLE			(0x00000000)
+/* OS Timer Mode Register 32bit (-/W) */
+#define U300_TIMER_APP_SOSTM					(0x000c)
+#define U300_TIMER_APP_SOSTM_MODE_CONTINUOUS			(0x00000000)
+#define U300_TIMER_APP_SOSTM_MODE_ONE_SHOT			(0x00000001)
+/* OS Timer Status Register 32bit (R/-) */
+#define U300_TIMER_APP_OSTS					(0x0010)
+#define U300_TIMER_APP_OSTS_TIMER_STATE_MASK			(0x0000000F)
+#define U300_TIMER_APP_OSTS_TIMER_STATE_IDLE			(0x00000001)
+#define U300_TIMER_APP_OSTS_TIMER_STATE_ACTIVE			(0x00000002)
+#define U300_TIMER_APP_OSTS_ENABLE_IND				(0x00000010)
+#define U300_TIMER_APP_OSTS_MODE_MASK				(0x00000020)
+#define U300_TIMER_APP_OSTS_MODE_CONTINUOUS			(0x00000000)
+#define U300_TIMER_APP_OSTS_MODE_ONE_SHOT			(0x00000020)
+#define U300_TIMER_APP_OSTS_IRQ_ENABLED_IND			(0x00000040)
+#define U300_TIMER_APP_OSTS_IRQ_PENDING_IND			(0x00000080)
+/* OS Timer Current Count Register 32bit (R/-) */
+#define U300_TIMER_APP_OSTCC					(0x0014)
+/* OS Timer Terminal Count Register 32bit (R/W) */
+#define U300_TIMER_APP_OSTTC					(0x0018)
+/* OS Timer Interrupt Enable Register 32bit (-/W) */
+#define U300_TIMER_APP_OSTIE					(0x001c)
+#define U300_TIMER_APP_OSTIE_IRQ_DISABLE			(0x00000000)
+#define U300_TIMER_APP_OSTIE_IRQ_ENABLE				(0x00000001)
+/* OS Timer Interrupt Acknowledge Register 32bit (-/W) */
+#define U300_TIMER_APP_OSTIA					(0x0020)
+#define U300_TIMER_APP_OSTIA_IRQ_ACK				(0x00000080)
+
+/* Reset DD Timer 32bit (-/W) */
+#define U300_TIMER_APP_RDDT					(0x0040)
+#define U300_TIMER_APP_RDDT_TIMER_RESET				(0x00000000)
+/* Enable DD Timer 32bit (-/W) */
+#define U300_TIMER_APP_EDDT					(0x0044)
+#define U300_TIMER_APP_EDDT_TIMER_ENABLE			(0x00000000)
+/* Disable DD Timer 32bit (-/W) */
+#define U300_TIMER_APP_DDDT					(0x0048)
+#define U300_TIMER_APP_DDDT_TIMER_DISABLE			(0x00000000)
+/* DD Timer Mode Register 32bit (-/W) */
+#define U300_TIMER_APP_SDDTM					(0x004c)
+#define U300_TIMER_APP_SDDTM_MODE_CONTINUOUS			(0x00000000)
+#define U300_TIMER_APP_SDDTM_MODE_ONE_SHOT			(0x00000001)
+/* DD Timer Status Register 32bit (R/-) */
+#define U300_TIMER_APP_DDTS					(0x0050)
+#define U300_TIMER_APP_DDTS_TIMER_STATE_MASK			(0x0000000F)
+#define U300_TIMER_APP_DDTS_TIMER_STATE_IDLE			(0x00000001)
+#define U300_TIMER_APP_DDTS_TIMER_STATE_ACTIVE			(0x00000002)
+#define U300_TIMER_APP_DDTS_ENABLE_IND				(0x00000010)
+#define U300_TIMER_APP_DDTS_MODE_MASK				(0x00000020)
+#define U300_TIMER_APP_DDTS_MODE_CONTINUOUS			(0x00000000)
+#define U300_TIMER_APP_DDTS_MODE_ONE_SHOT			(0x00000020)
+#define U300_TIMER_APP_DDTS_IRQ_ENABLED_IND			(0x00000040)
+#define U300_TIMER_APP_DDTS_IRQ_PENDING_IND			(0x00000080)
+/* DD Timer Current Count Register 32bit (R/-) */
+#define U300_TIMER_APP_DDTCC					(0x0054)
+/* DD Timer Terminal Count Register 32bit (R/W) */
+#define U300_TIMER_APP_DDTTC					(0x0058)
+/* DD Timer Interrupt Enable Register 32bit (-/W) */
+#define U300_TIMER_APP_DDTIE					(0x005c)
+#define U300_TIMER_APP_DDTIE_IRQ_DISABLE			(0x00000000)
+#define U300_TIMER_APP_DDTIE_IRQ_ENABLE				(0x00000001)
+/* DD Timer Interrupt Acknowledge Register 32bit (-/W) */
+#define U300_TIMER_APP_DDTIA					(0x0060)
+#define U300_TIMER_APP_DDTIA_IRQ_ACK				(0x00000080)
+
+/* Reset GP1 Timer 32bit (-/W) */
+#define U300_TIMER_APP_RGPT1					(0x0080)
+#define U300_TIMER_APP_RGPT1_TIMER_RESET			(0x00000000)
+/* Enable GP1 Timer 32bit (-/W) */
+#define U300_TIMER_APP_EGPT1					(0x0084)
+#define U300_TIMER_APP_EGPT1_TIMER_ENABLE			(0x00000000)
+/* Disable GP1 Timer 32bit (-/W) */
+#define U300_TIMER_APP_DGPT1					(0x0088)
+#define U300_TIMER_APP_DGPT1_TIMER_DISABLE			(0x00000000)
+/* GP1 Timer Mode Register 32bit (-/W) */
+#define U300_TIMER_APP_SGPT1M					(0x008c)
+#define U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS			(0x00000000)
+#define U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT			(0x00000001)
+/* GP1 Timer Status Register 32bit (R/-) */
+#define U300_TIMER_APP_GPT1S					(0x0090)
+#define U300_TIMER_APP_GPT1S_TIMER_STATE_MASK			(0x0000000F)
+#define U300_TIMER_APP_GPT1S_TIMER_STATE_IDLE			(0x00000001)
+#define U300_TIMER_APP_GPT1S_TIMER_STATE_ACTIVE			(0x00000002)
+#define U300_TIMER_APP_GPT1S_ENABLE_IND				(0x00000010)
+#define U300_TIMER_APP_GPT1S_MODE_MASK				(0x00000020)
+#define U300_TIMER_APP_GPT1S_MODE_CONTINUOUS			(0x00000000)
+#define U300_TIMER_APP_GPT1S_MODE_ONE_SHOT			(0x00000020)
+#define U300_TIMER_APP_GPT1S_IRQ_ENABLED_IND			(0x00000040)
+#define U300_TIMER_APP_GPT1S_IRQ_PENDING_IND			(0x00000080)
+/* GP1 Timer Current Count Register 32bit (R/-) */
+#define U300_TIMER_APP_GPT1CC					(0x0094)
+/* GP1 Timer Terminal Count Register 32bit (R/W) */
+#define U300_TIMER_APP_GPT1TC					(0x0098)
+/* GP1 Timer Interrupt Enable Register 32bit (-/W) */
+#define U300_TIMER_APP_GPT1IE					(0x009c)
+#define U300_TIMER_APP_GPT1IE_IRQ_DISABLE			(0x00000000)
+#define U300_TIMER_APP_GPT1IE_IRQ_ENABLE			(0x00000001)
+/* GP1 Timer Interrupt Acknowledge Register 32bit (-/W) */
+#define U300_TIMER_APP_GPT1IA					(0x00a0)
+#define U300_TIMER_APP_GPT1IA_IRQ_ACK				(0x00000080)
+
+/* Reset GP2 Timer 32bit (-/W) */
+#define U300_TIMER_APP_RGPT2					(0x00c0)
+#define U300_TIMER_APP_RGPT2_TIMER_RESET			(0x00000000)
+/* Enable GP2 Timer 32bit (-/W) */
+#define U300_TIMER_APP_EGPT2					(0x00c4)
+#define U300_TIMER_APP_EGPT2_TIMER_ENABLE			(0x00000000)
+/* Disable GP2 Timer 32bit (-/W) */
+#define U300_TIMER_APP_DGPT2					(0x00c8)
+#define U300_TIMER_APP_DGPT2_TIMER_DISABLE			(0x00000000)
+/* GP2 Timer Mode Register 32bit (-/W) */
+#define U300_TIMER_APP_SGPT2M					(0x00cc)
+#define U300_TIMER_APP_SGPT2M_MODE_CONTINUOUS			(0x00000000)
+#define U300_TIMER_APP_SGPT2M_MODE_ONE_SHOT			(0x00000001)
+/* GP2 Timer Status Register 32bit (R/-) */
+#define U300_TIMER_APP_GPT2S					(0x00d0)
+#define U300_TIMER_APP_GPT2S_TIMER_STATE_MASK			(0x0000000F)
+#define U300_TIMER_APP_GPT2S_TIMER_STATE_IDLE			(0x00000001)
+#define U300_TIMER_APP_GPT2S_TIMER_STATE_ACTIVE			(0x00000002)
+#define U300_TIMER_APP_GPT2S_ENABLE_IND				(0x00000010)
+#define U300_TIMER_APP_GPT2S_MODE_MASK				(0x00000020)
+#define U300_TIMER_APP_GPT2S_MODE_CONTINUOUS			(0x00000000)
+#define U300_TIMER_APP_GPT2S_MODE_ONE_SHOT			(0x00000020)
+#define U300_TIMER_APP_GPT2S_IRQ_ENABLED_IND			(0x00000040)
+#define U300_TIMER_APP_GPT2S_IRQ_PENDING_IND			(0x00000080)
+/* GP2 Timer Current Count Register 32bit (R/-) */
+#define U300_TIMER_APP_GPT2CC					(0x00d4)
+/* GP2 Timer Terminal Count Register 32bit (R/W) */
+#define U300_TIMER_APP_GPT2TC					(0x00d8)
+/* GP2 Timer Interrupt Enable Register 32bit (-/W) */
+#define U300_TIMER_APP_GPT2IE					(0x00dc)
+#define U300_TIMER_APP_GPT2IE_IRQ_DISABLE			(0x00000000)
+#define U300_TIMER_APP_GPT2IE_IRQ_ENABLE			(0x00000001)
+/* GP2 Timer Interrupt Acknowledge Register 32bit (-/W) */
+#define U300_TIMER_APP_GPT2IA					(0x00e0)
+#define U300_TIMER_APP_GPT2IA_IRQ_ACK				(0x00000080)
+
+/* Clock request control register - all four timers */
+#define U300_TIMER_APP_CRC					(0x100)
+#define U300_TIMER_APP_CRC_CLOCK_REQUEST_ENABLE			(0x00000001)
+
+#define TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ)
+#define US_PER_TICK ((1000000 + (HZ/2)) / HZ)
+
+/*
+ * The u300_set_mode() function is always called first, if we
+ * have oneshot timer active, the oneshot scheduling function
+ * u300_set_next_event() is called immediately after.
+ */
+static void u300_set_mode(enum clock_event_mode mode,
+			  struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		/* Disable interrupts on GPT1 */
+		writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
+		       U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
+		/* Disable GP1 while we're reprogramming it. */
+		writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
+		       U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1);
+		/*
+		 * Set the periodic mode to a certain number of ticks per
+		 * jiffy.
+		 */
+		writel(TICKS_PER_JIFFY,
+		       U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1TC);
+		/*
+		 * Set continuous mode, so the timer keeps triggering
+		 * interrupts.
+		 */
+		writel(U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS,
+		       U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT1M);
+		/* Enable timer interrupts */
+		writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
+		       U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
+		/* Then enable the OS timer again */
+		writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
+		       U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT1);
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		/* Just break; here? */
+		/*
+		 * The actual event will be programmed by the next event hook,
+		 * so we just set a dummy value somewhere at the end of the
+		 * universe here.
+		 */
+		/* Disable interrupts on GPT1 */
+		writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
+		       U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
+		/* Disable GP1 while we're reprogramming it. */
+		writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
+		       U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1);
+		/*
+		 * Expire far in the future, u300_set_next_event() will be
+		 * called soon...
+		 */
+		writel(0xFFFFFFFF, U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1TC);
+		/* We run one shot per tick here! */
+		writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT,
+		       U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT1M);
+		/* Enable interrupts for this timer */
+		writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
+		       U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
+		/* Enable timer */
+		writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
+		       U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT1);
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		/* Disable interrupts on GP1 */
+		writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
+		       U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
+		/* Disable GP1 */
+		writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
+		       U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1);
+		break;
+	case CLOCK_EVT_MODE_RESUME:
+		/* Ignore this call */
+		break;
+	}
+}
+
+/*
+ * The app timer in one shot mode obviously has to be reprogrammed
+ * in EXACTLY this sequence to work properly. Do NOT try to e.g. replace
+ * the interrupt disable + timer disable commands with a reset command,
+ * it will fail miserably. Apparently (and I found this the hard way)
+ * the timer is very sensitive to the instruction order, though you don't
+ * get that impression from the data sheet.
+ */
+static int u300_set_next_event(unsigned long cycles,
+			       struct clock_event_device *evt)
+
+{
+	/* Disable interrupts on GPT1 */
+	writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
+	       U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
+	/* Disable GP1 while we're reprogramming it. */
+	writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
+	       U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1);
+	/* Reset the General Purpose timer 1. */
+	writel(U300_TIMER_APP_RGPT1_TIMER_RESET,
+	       U300_TIMER_APP_VBASE + U300_TIMER_APP_RGPT1);
+	/* IRQ in n * cycles */
+	writel(cycles, U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1TC);
+	/*
+	 * We run one shot per tick here! (This is necessary to reconfigure,
+	 * the timer will tilt if you don't!)
+	 */
+	writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT,
+	       U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT1M);
+	/* Enable timer interrupts */
+	writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
+	       U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
+	/* Then enable the OS timer again */
+	writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
+	       U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT1);
+	return 0;
+}
+
+
+/* Use general purpose timer 1 as clock event */
+static struct clock_event_device clockevent_u300_1mhz = {
+	.name           = "GPT1",
+	.rating         = 300, /* Reasonably fast and accurate clock event */
+	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	/* 22 calculated using the algorithm in arch/mips/kernel/time.c */
+	.shift          = 22,
+	.set_next_event = u300_set_next_event,
+	.set_mode       = u300_set_mode,
+};
+
+/* Clock event timer interrupt handler */
+static irqreturn_t u300_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = &clockevent_u300_1mhz;
+	/* ACK/Clear timer IRQ for the APP GPT1 Timer */
+	writel(U300_TIMER_APP_GPT1IA_IRQ_ACK,
+		U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IA);
+	evt->event_handler(evt);
+	return IRQ_HANDLED;
+}
+
+static struct irqaction u300_timer_irq = {
+	.name           = "U300 Timer Tick",
+	.flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.handler        = u300_timer_interrupt,
+};
+
+/* Use general purpose timer 2 as clock source */
+static cycle_t u300_get_cycles(struct clocksource *cs)
+{
+	return (cycles_t) readl(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC);
+}
+
+static struct clocksource clocksource_u300_1mhz = {
+	.name           = "GPT2",
+	.rating         = 300, /* Reasonably fast and accurate clock source */
+	.read           = u300_get_cycles,
+	.mask           = CLOCKSOURCE_MASK(32), /* 32 bits */
+	/* 22 calculated using the algorithm in arch/mips/kernel/time.c */
+	.shift          = 22,
+	.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+
+/*
+ * This sets up the system timers, clock source and clock event.
+ */
+static void __init u300_timer_init(void)
+{
+	u300_enable_timer_clock();
+	/*
+	 * Disable the "OS" and "DD" timers - these are designed for Symbian!
+	 * Example usage in cnh1601578 cpu subsystem pd_timer_app.c
+	 */
+	writel(U300_TIMER_APP_CRC_CLOCK_REQUEST_ENABLE,
+		U300_TIMER_APP_VBASE + U300_TIMER_APP_CRC);
+	writel(U300_TIMER_APP_ROST_TIMER_RESET,
+		U300_TIMER_APP_VBASE + U300_TIMER_APP_ROST);
+	writel(U300_TIMER_APP_DOST_TIMER_DISABLE,
+		U300_TIMER_APP_VBASE + U300_TIMER_APP_DOST);
+	writel(U300_TIMER_APP_RDDT_TIMER_RESET,
+		U300_TIMER_APP_VBASE + U300_TIMER_APP_RDDT);
+	writel(U300_TIMER_APP_DDDT_TIMER_DISABLE,
+		U300_TIMER_APP_VBASE + U300_TIMER_APP_DDDT);
+
+	/* Reset the General Purpose timer 1. */
+	writel(U300_TIMER_APP_RGPT1_TIMER_RESET,
+		U300_TIMER_APP_VBASE + U300_TIMER_APP_RGPT1);
+
+	/* Set up the IRQ handler */
+	setup_irq(IRQ_U300_TIMER_APP_GP1, &u300_timer_irq);
+
+	/* Reset the General Purpose timer 2 */
+	writel(U300_TIMER_APP_RGPT2_TIMER_RESET,
+		U300_TIMER_APP_VBASE + U300_TIMER_APP_RGPT2);
+	/* Set this timer to run around forever */
+	writel(0xFFFFFFFFU, U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2TC);
+	/* Set continuous mode so it wraps around */
+	writel(U300_TIMER_APP_SGPT2M_MODE_CONTINUOUS,
+	       U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT2M);
+	/* Disable timer interrupts */
+	writel(U300_TIMER_APP_GPT2IE_IRQ_DISABLE,
+		U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2IE);
+	/* Then enable the GP2 timer to use as a free running us counter */
+	writel(U300_TIMER_APP_EGPT2_TIMER_ENABLE,
+		U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT2);
+
+	/* This is a pure microsecond clock source */
+	clocksource_u300_1mhz.mult =
+		clocksource_khz2mult(1000, clocksource_u300_1mhz.shift);
+	if (clocksource_register(&clocksource_u300_1mhz))
+		printk(KERN_ERR "timer: failed to initialize clock "
+		       "source %s\n", clocksource_u300_1mhz.name);
+
+	clockevent_u300_1mhz.mult =
+		div_sc(1000000, NSEC_PER_SEC, clockevent_u300_1mhz.shift);
+	/* 32bit counter, so 32bits delta is max */
+	clockevent_u300_1mhz.max_delta_ns =
+		clockevent_delta2ns(0xffffffff, &clockevent_u300_1mhz);
+	/* This timer is slow enough to set for 1 cycle == 1 MHz */
+	clockevent_u300_1mhz.min_delta_ns =
+		clockevent_delta2ns(1, &clockevent_u300_1mhz);
+	clockevent_u300_1mhz.cpumask = cpumask_of(0);
+	clockevents_register_device(&clockevent_u300_1mhz);
+	/*
+	 * TODO: init and register the rest of the timers too, they can be
+	 * used by hrtimers!
+	 */
+}
+
+/*
+ * Very simple system timer that only register the clock event and
+ * clock source.
+ */
+struct sys_timer u300_timer = {
+	.init		= u300_timer_init,
+};
diff --git a/arch/arm/mach-u300/u300.c b/arch/arm/mach-u300/u300.c
new file mode 100644
index 0000000..d2a0b88
--- /dev/null
+++ b/arch/arm/mach-u300/u300.c
@@ -0,0 +1,55 @@
+/*
+ *
+ * arch/arm/mach-u300/u300.c
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Platform machine definition.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include <mach/memory.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+static void __init u300_init_machine(void)
+{
+	u300_init_devices();
+}
+
+#ifdef CONFIG_MACH_U300_BS2X
+#define MACH_U300_STRING "Ericsson AB U300 S25/S26/B25/B26 Prototype Board"
+#endif
+
+#ifdef CONFIG_MACH_U300_BS330
+#define MACH_U300_STRING "Ericsson AB U330 S330/B330 Prototype Board"
+#endif
+
+#ifdef CONFIG_MACH_U300_BS335
+#define MACH_U300_STRING "Ericsson AB U335 S335/B335 Prototype Board"
+#endif
+
+#ifdef CONFIG_MACH_U300_BS365
+#define MACH_U300_STRING "Ericsson AB U365 S365/B365 Prototype Board"
+#endif
+
+MACHINE_START(U300, MACH_U300_STRING)
+	/* Maintainer: Linus Walleij <linus.walleij@stericsson.com> */
+	.phys_io	= U300_AHB_PER_PHYS_BASE,
+	.io_pg_offst	= ((U300_AHB_PER_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= BOOT_PARAMS_OFFSET,
+	.map_io		= u300_map_io,
+	.init_irq	= u300_init_irq,
+	.timer		= &u300_timer,
+	.init_machine	= u300_init_machine,
+MACHINE_END
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index b3bebcc..69214fc 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -116,7 +116,7 @@
 {
 	unsigned int i;
 
-	vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0);
+	vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0);
 
 	set_irq_chained_handler(IRQ_VICSOURCE31, sic_handle_irq);
 
diff --git a/arch/arm/mach-w90x900/Makefile b/arch/arm/mach-w90x900/Makefile
index 0c0c1d6..d50c94f 100644
--- a/arch/arm/mach-w90x900/Makefile
+++ b/arch/arm/mach-w90x900/Makefile
@@ -4,7 +4,7 @@
 
 # Object file lists.
 
-obj-y				:= irq.o time.o
+obj-y				:= irq.o time.o mfp-w90p910.o gpio.o clock.o
 
 # W90X900 CPU support files
 
diff --git a/arch/arm/mach-w90x900/clock.c b/arch/arm/mach-w90x900/clock.c
new file mode 100644
index 0000000..f420613
--- /dev/null
+++ b/arch/arm/mach-w90x900/clock.c
@@ -0,0 +1,77 @@
+/*
+ * linux/arch/arm/mach-w90x900/clock.c
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ *
+ * Wan ZongShun <mcuos.com@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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+
+#include "clock.h"
+
+static DEFINE_SPINLOCK(clocks_lock);
+
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clocks_lock, flags);
+	if (clk->enabled++ == 0)
+		(clk->enable)(clk, 1);
+	spin_unlock_irqrestore(&clocks_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	WARN_ON(clk->enabled == 0);
+
+	spin_lock_irqsave(&clocks_lock, flags);
+	if (--clk->enabled == 0)
+		(clk->enable)(clk, 0);
+	spin_unlock_irqrestore(&clocks_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+void w90x900_clk_enable(struct clk *clk, int enable)
+{
+	unsigned int clocks = clk->cken;
+	unsigned long clken;
+
+	clken = __raw_readl(W90X900_VA_CLKPWR);
+
+	if (enable)
+		clken |= clocks;
+	else
+		clken &= ~clocks;
+
+	__raw_writel(clken, W90X900_VA_CLKPWR);
+}
+
+void clks_register(struct clk_lookup *clks, size_t num)
+{
+	int i;
+
+	for (i = 0; i < num; i++)
+		clkdev_add(&clks[i]);
+}
diff --git a/arch/arm/mach-w90x900/clock.h b/arch/arm/mach-w90x900/clock.h
new file mode 100644
index 0000000..4f27bda
--- /dev/null
+++ b/arch/arm/mach-w90x900/clock.h
@@ -0,0 +1,36 @@
+/*
+ * linux/arch/arm/mach-w90x900/clock.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ *
+ * Wan ZongShun <mcuos.com@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.
+ */
+
+#include <asm/clkdev.h>
+
+void w90x900_clk_enable(struct clk *clk, int enable);
+void clks_register(struct clk_lookup *clks, size_t num);
+
+struct clk {
+	unsigned long		cken;
+	unsigned int		enabled;
+	void			(*enable)(struct clk *, int enable);
+};
+
+#define DEFINE_CLK(_name, _ctrlbit)			\
+struct clk clk_##_name = {				\
+		.enable	= w90x900_clk_enable,		\
+		.cken	= (1 << _ctrlbit),		\
+	}
+
+#define DEF_CLKLOOK(_clk, _devname, _conname)		\
+	{						\
+		.clk		= _clk,			\
+		.dev_id		= _devname,		\
+		.con_id		= _conname,		\
+	}
+
diff --git a/arch/arm/mach-w90x900/cpu.h b/arch/arm/mach-w90x900/cpu.h
index de29ddc..57b5dba 100644
--- a/arch/arm/mach-w90x900/cpu.h
+++ b/arch/arm/mach-w90x900/cpu.h
@@ -41,7 +41,7 @@
 extern void w90x900_init_irq(void);
 extern void w90p910_init_io(struct map_desc *mach_desc, int size);
 extern void w90p910_init_uarts(struct w90x900_uartcfg *cfg, int no);
-extern void w90p910_init_clocks(int xtal);
+extern void w90p910_init_clocks(void);
 extern void w90p910_map_io(struct map_desc *mach_desc, int size);
 extern struct platform_device w90p910_serial_device;
 extern struct sys_timer w90x900_timer;
diff --git a/arch/arm/mach-w90x900/gpio.c b/arch/arm/mach-w90x900/gpio.c
new file mode 100644
index 0000000..c72e0df
--- /dev/null
+++ b/arch/arm/mach-w90x900/gpio.c
@@ -0,0 +1,154 @@
+/*
+ * linux/arch/arm/mach-w90p910/gpio.c
+ *
+ * Generic w90p910 GPIO handling
+ *
+ *  Wan ZongShun <mcuos.com@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/clk.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+
+#define GPIO_BASE 		(W90X900_VA_GPIO)
+#define GPIO_DIR		(0x04)
+#define GPIO_OUT		(0x08)
+#define GPIO_IN			(0x0C)
+#define GROUPINERV		(0x10)
+#define GPIO_GPIO(Nb)		(0x00000001 << (Nb))
+#define to_w90p910_gpio_chip(c) container_of(c, struct w90p910_gpio_chip, chip)
+
+#define W90P910_GPIO_CHIP(name, base_gpio, nr_gpio)			\
+	{								\
+		.chip = {						\
+			.label		  = name,			\
+			.direction_input  = w90p910_dir_input,		\
+			.direction_output = w90p910_dir_output,		\
+			.get		  = w90p910_gpio_get,		\
+			.set		  = w90p910_gpio_set,		\
+			.base		  = base_gpio,			\
+			.ngpio		  = nr_gpio,			\
+		}							\
+	}
+
+struct w90p910_gpio_chip {
+	struct gpio_chip	chip;
+	void __iomem		*regbase;	/* Base of group register*/
+	spinlock_t 		gpio_lock;
+};
+
+static int w90p910_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct w90p910_gpio_chip *w90p910_gpio = to_w90p910_gpio_chip(chip);
+	void __iomem *pio = w90p910_gpio->regbase + GPIO_IN;
+	unsigned int regval;
+
+	regval = __raw_readl(pio);
+	regval &= GPIO_GPIO(offset);
+
+	return (regval != 0);
+}
+
+static void w90p910_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+	struct w90p910_gpio_chip *w90p910_gpio = to_w90p910_gpio_chip(chip);
+	void __iomem *pio = w90p910_gpio->regbase + GPIO_OUT;
+	unsigned int regval;
+	unsigned long flags;
+
+	spin_lock_irqsave(&w90p910_gpio->gpio_lock, flags);
+
+	regval = __raw_readl(pio);
+
+	if (val)
+		regval |= GPIO_GPIO(offset);
+	else
+		regval &= ~GPIO_GPIO(offset);
+
+	__raw_writel(regval, pio);
+
+	spin_unlock_irqrestore(&w90p910_gpio->gpio_lock, flags);
+}
+
+static int w90p910_dir_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct w90p910_gpio_chip *w90p910_gpio = to_w90p910_gpio_chip(chip);
+	void __iomem *pio = w90p910_gpio->regbase + GPIO_DIR;
+	unsigned int regval;
+	unsigned long flags;
+
+	spin_lock_irqsave(&w90p910_gpio->gpio_lock, flags);
+
+	regval = __raw_readl(pio);
+	regval &= ~GPIO_GPIO(offset);
+	__raw_writel(regval, pio);
+
+	spin_unlock_irqrestore(&w90p910_gpio->gpio_lock, flags);
+
+	return 0;
+}
+
+static int w90p910_dir_output(struct gpio_chip *chip, unsigned offset, int val)
+{
+	struct w90p910_gpio_chip *w90p910_gpio = to_w90p910_gpio_chip(chip);
+	void __iomem *outreg = w90p910_gpio->regbase + GPIO_OUT;
+	void __iomem *pio = w90p910_gpio->regbase + GPIO_DIR;
+	unsigned int regval;
+	unsigned long flags;
+
+	spin_lock_irqsave(&w90p910_gpio->gpio_lock, flags);
+
+	regval = __raw_readl(pio);
+	regval |= GPIO_GPIO(offset);
+	__raw_writel(regval, pio);
+
+	regval = __raw_readl(outreg);
+
+	if (val)
+		regval |= GPIO_GPIO(offset);
+	else
+		regval &= ~GPIO_GPIO(offset);
+
+	__raw_writel(regval, outreg);
+
+	spin_unlock_irqrestore(&w90p910_gpio->gpio_lock, flags);
+
+	return 0;
+}
+
+static struct w90p910_gpio_chip w90p910_gpio[] = {
+	W90P910_GPIO_CHIP("GROUPC", 0, 16),
+	W90P910_GPIO_CHIP("GROUPD", 16, 10),
+	W90P910_GPIO_CHIP("GROUPE", 26, 14),
+	W90P910_GPIO_CHIP("GROUPF", 40, 10),
+	W90P910_GPIO_CHIP("GROUPG", 50, 17),
+	W90P910_GPIO_CHIP("GROUPH", 67, 8),
+	W90P910_GPIO_CHIP("GROUPI", 75, 17),
+};
+
+void __init w90p910_init_gpio(int nr_group)
+{
+	unsigned	i;
+	struct w90p910_gpio_chip *gpio_chip;
+
+	for (i = 0; i < nr_group; i++) {
+		gpio_chip = &w90p910_gpio[i];
+		spin_lock_init(&gpio_chip->gpio_lock);
+		gpio_chip->regbase = GPIO_BASE + i * GROUPINERV;
+		gpiochip_add(&gpio_chip->chip);
+	}
+}
diff --git a/arch/arm/mach-w90x900/include/mach/clkdev.h b/arch/arm/mach-w90x900/include/mach/clkdev.h
new file mode 100644
index 0000000..04b37a8
--- /dev/null
+++ b/arch/arm/mach-w90x900/include/mach/clkdev.h
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
diff --git a/arch/arm/mach-w90x900/include/mach/gpio.h b/arch/arm/mach-w90x900/include/mach/gpio.h
new file mode 100644
index 0000000..034da3e
--- /dev/null
+++ b/arch/arm/mach-w90x900/include/mach/gpio.h
@@ -0,0 +1,34 @@
+/*
+ * linux/arch/arm/mach-w90p910/include/mach/gpio.h
+ *
+ * Generic w90p910 GPIO handling
+ *
+ *  Wan ZongShun <mcuos.com@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.
+ */
+
+#ifndef __ASM_ARCH_W90P910_GPIO_H
+#define __ASM_ARCH_W90P910_GPIO_H
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm-generic/gpio.h>
+
+#define gpio_get_value	__gpio_get_value
+#define gpio_set_value	__gpio_set_value
+#define gpio_cansleep	__gpio_cansleep
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+	return gpio;
+}
+
+static inline int irq_to_gpio(unsigned irq)
+{
+	return irq;
+}
+
+#endif
diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h b/arch/arm/mach-w90x900/include/mach/irqs.h
index 1c583f9..9d5cba3 100644
--- a/arch/arm/mach-w90x900/include/mach/irqs.h
+++ b/arch/arm/mach-w90x900/include/mach/irqs.h
@@ -1,8 +1,7 @@
 /*
  * arch/arm/mach-w90x900/include/mach/irqs.h
  *
- * Copyright (c) 2008 Nuvoton technology corporation
- * All rights reserved.
+ * Copyright (c) 2008 Nuvoton technology corporation.
  *
  * Wan ZongShun <mcuos.com@gmail.com>
  *
@@ -10,8 +9,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, or
- * (at your option) any later version.
+ * the Free Software Foundation;version 2 of the License.
  *
  */
 
@@ -31,6 +29,11 @@
 /* Main cpu interrupts */
 
 #define IRQ_WDT		W90X900_IRQ(1)
+#define IRQ_GROUP0	W90X900_IRQ(2)
+#define IRQ_GROUP1	W90X900_IRQ(3)
+#define IRQ_ACTL	W90X900_IRQ(4)
+#define IRQ_LCD		W90X900_IRQ(5)
+#define IRQ_RTC		W90X900_IRQ(6)
 #define IRQ_UART0	W90X900_IRQ(7)
 #define IRQ_UART1	W90X900_IRQ(8)
 #define IRQ_UART2	W90X900_IRQ(9)
@@ -39,7 +42,45 @@
 #define IRQ_TIMER0	W90X900_IRQ(12)
 #define IRQ_TIMER1	W90X900_IRQ(13)
 #define IRQ_T_INT_GROUP	W90X900_IRQ(14)
+#define IRQ_USBH	W90X900_IRQ(15)
+#define IRQ_EMCTX	W90X900_IRQ(16)
+#define IRQ_EMCRX	W90X900_IRQ(17)
+#define IRQ_GDMAGROUP	W90X900_IRQ(18)
+#define IRQ_DMAC	W90X900_IRQ(19)
+#define IRQ_FMI		W90X900_IRQ(20)
+#define IRQ_USBD	W90X900_IRQ(21)
+#define IRQ_ATAPI	W90X900_IRQ(22)
+#define IRQ_G2D		W90X900_IRQ(23)
+#define IRQ_PCI		W90X900_IRQ(24)
+#define IRQ_SCGROUP	W90X900_IRQ(25)
+#define IRQ_I2CGROUP	W90X900_IRQ(26)
+#define IRQ_SSP		W90X900_IRQ(27)
+#define IRQ_PWM		W90X900_IRQ(28)
+#define IRQ_KPI		W90X900_IRQ(29)
+#define IRQ_P2SGROUP	W90X900_IRQ(30)
 #define IRQ_ADC		W90X900_IRQ(31)
 #define NR_IRQS		(IRQ_ADC+1)
 
+/*for irq group*/
+
+#define	IRQ_PS2_PORT0	0x10000000
+#define	IRQ_PS2_PORT1	0x20000000
+#define	IRQ_I2C_LINE0	0x04000000
+#define	IRQ_I2C_LINE1	0x08000000
+#define	IRQ_SC_CARD0	0x01000000
+#define	IRQ_SC_CARD1	0x02000000
+#define	IRQ_GDMA_CH0	0x00100000
+#define	IRQ_GDMA_CH1	0x00200000
+#define	IRQ_TIMER2	0x00010000
+#define	IRQ_TIMER3	0x00020000
+#define	IRQ_TIMER4	0x00040000
+#define	IRQ_GROUP0_IRQ0	0x00000001
+#define	IRQ_GROUP0_IRQ1	0x00000002
+#define	IRQ_GROUP0_IRQ2	0x00000004
+#define	IRQ_GROUP0_IRQ3	0x00000008
+#define	IRQ_GROUP1_IRQ4	0x00000010
+#define	IRQ_GROUP1_IRQ5	0x00000020
+#define	IRQ_GROUP1_IRQ6	0x00000040
+#define	IRQ_GROUP1_IRQ7	0x00000080
+
 #endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-w90x900/include/mach/map.h b/arch/arm/mach-w90x900/include/mach/map.h
index 79320eb..1a20953 100644
--- a/arch/arm/mach-w90x900/include/mach/map.h
+++ b/arch/arm/mach-w90x900/include/mach/map.h
@@ -1,8 +1,7 @@
 /*
  * arch/arm/mach-w90x900/include/mach/map.h
  *
- * Copyright (c) 2008 Nuvoton technology corporation
- * All rights reserved.
+ * Copyright (c) 2008 Nuvoton technology corporation.
  *
  * Wan ZongShun <mcuos.com@gmail.com>
  *
@@ -10,8 +9,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, or
- * (at your option) any later version.
+ * the Free Software Foundation;version 2 of the License.
  *
  */
 
@@ -34,7 +32,6 @@
  * interrupt controller is the first thing we put in, to make
  * the assembly code for the irq detection easier
  */
-
 #define W90X900_VA_IRQ		W90X900_ADDR(0x00000000)
 #define W90X900_PA_IRQ		(0xB8002000)
 #define W90X900_SZ_IRQ		SZ_4K
@@ -44,33 +41,117 @@
 #define W90X900_SZ_GCR		SZ_4K
 
 /* Clock and Power management */
-
 #define W90X900_VA_CLKPWR	(W90X900_VA_GCR+0x200)
 #define W90X900_PA_CLKPWR	(0xB0000200)
 #define W90X900_SZ_CLKPWR	SZ_4K
 
 /* EBI management */
-
 #define W90X900_VA_EBI		W90X900_ADDR(0x00001000)
 #define W90X900_PA_EBI		(0xB0001000)
 #define W90X900_SZ_EBI		SZ_4K
 
 /* UARTs */
-
 #define W90X900_VA_UART		W90X900_ADDR(0x08000000)
 #define W90X900_PA_UART		(0xB8000000)
 #define W90X900_SZ_UART		SZ_4K
 
 /* Timers */
-
 #define W90X900_VA_TIMER	W90X900_ADDR(0x08001000)
 #define W90X900_PA_TIMER	(0xB8001000)
 #define W90X900_SZ_TIMER	SZ_4K
 
 /* GPIO ports */
-
 #define W90X900_VA_GPIO		W90X900_ADDR(0x08003000)
 #define W90X900_PA_GPIO		(0xB8003000)
 #define W90X900_SZ_GPIO		SZ_4K
 
+/* GDMA control */
+#define W90X900_VA_GDMA		W90X900_ADDR(0x00004000)
+#define W90X900_PA_GDMA		(0xB0004000)
+#define W90X900_SZ_GDMA		SZ_4K
+
+/* USB host controller*/
+#define W90X900_VA_USBEHCIHOST	W90X900_ADDR(0x00005000)
+#define W90X900_PA_USBEHCIHOST	(0xB0005000)
+#define W90X900_SZ_USBEHCIHOST	SZ_4K
+
+#define W90X900_VA_USBOHCIHOST	W90X900_ADDR(0x00007000)
+#define W90X900_PA_USBOHCIHOST	(0xB0007000)
+#define W90X900_SZ_USBOHCIHOST	SZ_4K
+
+/* I2C hardware controller */
+#define W90X900_VA_I2C		W90X900_ADDR(0x08006000)
+#define W90X900_PA_I2C		(0xB8006000)
+#define W90X900_SZ_I2C		SZ_4K
+
+/* Keypad Interface*/
+#define W90X900_VA_KPI		W90X900_ADDR(0x08008000)
+#define W90X900_PA_KPI		(0xB8008000)
+#define W90X900_SZ_KPI		SZ_4K
+
+/* Smart card host*/
+#define W90X900_VA_SC		W90X900_ADDR(0x08005000)
+#define W90X900_PA_SC		(0xB8005000)
+#define W90X900_SZ_SC		SZ_4K
+
+/* LCD controller*/
+#define W90X900_VA_LCD		W90X900_ADDR(0x00008000)
+#define W90X900_PA_LCD		(0xB0008000)
+#define W90X900_SZ_LCD		SZ_4K
+
+/* 2D controller*/
+#define W90X900_VA_GE		W90X900_ADDR(0x0000B000)
+#define W90X900_PA_GE		(0xB000B000)
+#define W90X900_SZ_GE		SZ_4K
+
+/* ATAPI */
+#define W90X900_VA_ATAPI	W90X900_ADDR(0x0000A000)
+#define W90X900_PA_ATAPI	(0xB000A000)
+#define W90X900_SZ_ATAPI	SZ_4K
+
+/* ADC */
+#define W90X900_VA_ADC		W90X900_ADDR(0x0800A000)
+#define W90X900_PA_ADC		(0xB800A000)
+#define W90X900_SZ_ADC		SZ_4K
+
+/* PS2 Interface*/
+#define W90X900_VA_PS2		W90X900_ADDR(0x08009000)
+#define W90X900_PA_PS2		(0xB8009000)
+#define W90X900_SZ_PS2		SZ_4K
+
+/* RTC */
+#define W90X900_VA_RTC		W90X900_ADDR(0x08004000)
+#define W90X900_PA_RTC		(0xB8004000)
+#define W90X900_SZ_RTC		SZ_4K
+
+/* Pulse Width Modulation(PWM) Registers */
+#define W90X900_VA_PWM		W90X900_ADDR(0x08007000)
+#define W90X900_PA_PWM		(0xB8007000)
+#define W90X900_SZ_PWM		SZ_4K
+
+/* Audio Controller controller */
+#define W90X900_VA_ACTL		W90X900_ADDR(0x00009000)
+#define W90X900_PA_ACTL		(0xB0009000)
+#define W90X900_SZ_ACTL		SZ_4K
+
+/* DMA controller */
+#define W90X900_VA_DMA		W90X900_ADDR(0x0000c000)
+#define W90X900_PA_DMA		(0xB000c000)
+#define W90X900_SZ_DMA		SZ_4K
+
+/* FMI controller */
+#define W90X900_VA_FMI		W90X900_ADDR(0x0000d000)
+#define W90X900_PA_FMI		(0xB000d000)
+#define W90X900_SZ_FMI		SZ_4K
+
+/* USB Device port */
+#define W90X900_VA_USBDEV	W90X900_ADDR(0x00006000)
+#define W90X900_PA_USBDEV	(0xB0006000)
+#define W90X900_SZ_USBDEV	SZ_4K
+
+/* External MAC control*/
+#define W90X900_VA_EMC		W90X900_ADDR(0x00003000)
+#define W90X900_PA_EMC		(0xB0003000)
+#define W90X900_SZ_EMC		SZ_4K
+
 #endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-w90x900/include/mach/regs-clock.h b/arch/arm/mach-w90x900/include/mach/regs-clock.h
new file mode 100644
index 0000000..f10b6a8
--- /dev/null
+++ b/arch/arm/mach-w90x900/include/mach/regs-clock.h
@@ -0,0 +1,31 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/regs-clock.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@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 __ASM_ARCH_REGS_CLOCK_H
+#define __ASM_ARCH_REGS_CLOCK_H
+
+/* Clock Control Registers  */
+#define CLK_BA		W90X900_VA_CLKPWR
+#define REG_CLKEN	(CLK_BA + 0x00)
+#define REG_CLKSEL	(CLK_BA + 0x04)
+#define REG_CLKDIV	(CLK_BA + 0x08)
+#define REG_PLLCON0	(CLK_BA + 0x0C)
+#define REG_PLLCON1	(CLK_BA + 0x10)
+#define REG_PMCON	(CLK_BA + 0x14)
+#define REG_IRQWAKECON	(CLK_BA + 0x18)
+#define REG_IRQWAKEFLAG	(CLK_BA + 0x1C)
+#define REG_IPSRST	(CLK_BA + 0x20)
+#define REG_CLKEN1	(CLK_BA + 0x24)
+#define REG_CLKDIV1	(CLK_BA + 0x28)
+
+#endif /*  __ASM_ARCH_REGS_CLOCK_H */
diff --git a/arch/arm/mach-w90x900/include/mach/regs-usb.h b/arch/arm/mach-w90x900/include/mach/regs-usb.h
new file mode 100644
index 0000000..ab74b0c
--- /dev/null
+++ b/arch/arm/mach-w90x900/include/mach/regs-usb.h
@@ -0,0 +1,35 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/regs-usb.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@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 __ASM_ARCH_REGS_USB_H
+#define __ASM_ARCH_REGS_USB_H
+
+/* usb Control Registers  */
+#define USBH_BA		W90X900_VA_USBEHCIHOST
+#define USBD_BA		W90X900_VA_USBDEV
+#define USBO_BA		W90X900_VA_USBOHCIHOST
+
+/* USB Host Control Registers */
+#define REG_UPSCR0	(USBH_BA+0x064)
+#define REG_UPSCR1	(USBH_BA+0x068)
+#define REG_USBPCR0	(USBH_BA+0x0C4)
+#define REG_USBPCR1	(USBH_BA+0x0C8)
+
+/* USBH OHCI Control Registers */
+#define REG_OpModEn	(USBO_BA+0x204)
+/*This bit controls the polarity of over
+*current flag from external power IC.
+*/
+#define OCALow		0x08
+
+#endif /*  __ASM_ARCH_REGS_USB_H */
diff --git a/arch/arm/mach-w90x900/mach-w90p910evb.c b/arch/arm/mach-w90x900/mach-w90p910evb.c
index 726ff67..7a62bd3 100644
--- a/arch/arm/mach-w90x900/mach-w90p910evb.c
+++ b/arch/arm/mach-w90x900/mach-w90p910evb.c
@@ -3,15 +3,13 @@
  *
  * Based on mach-s3c2410/mach-smdk2410.c by Jonas Dietsche
  *
- * Copyright (C) 2008 Nuvoton technology corporation
- * All rights reserved.
+ * Copyright (C) 2008 Nuvoton technology corporation.
  *
  * Wan ZongShun <mcuos.com@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.
+ * published by the Free Software Foundation;version 2 of the License.
  *
  */
 
@@ -80,6 +78,156 @@
 	.num_resources	=	ARRAY_SIZE(w90p910_flash_resources),
 };
 
+/* USB EHCI Host Controller */
+
+static struct resource w90x900_usb_ehci_resource[] = {
+	[0] = {
+		.start = W90X900_PA_USBEHCIHOST,
+		.end   = W90X900_PA_USBEHCIHOST + W90X900_SZ_USBEHCIHOST - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_USBH,
+		.end   = IRQ_USBH,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static u64 w90x900_device_usb_ehci_dmamask = 0xffffffffUL;
+
+struct platform_device w90x900_device_usb_ehci = {
+	.name		  = "w90x900-ehci",
+	.id		  = -1,
+	.num_resources	  = ARRAY_SIZE(w90x900_usb_ehci_resource),
+	.resource	  = w90x900_usb_ehci_resource,
+	.dev              = {
+		.dma_mask = &w90x900_device_usb_ehci_dmamask,
+		.coherent_dma_mask = 0xffffffffUL
+	}
+};
+EXPORT_SYMBOL(w90x900_device_usb_ehci);
+
+/* USB OHCI Host Controller */
+
+static struct resource w90x900_usb_ohci_resource[] = {
+	[0] = {
+		.start = W90X900_PA_USBOHCIHOST,
+		.end   = W90X900_PA_USBOHCIHOST + W90X900_SZ_USBOHCIHOST - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_USBH,
+		.end   = IRQ_USBH,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static u64 w90x900_device_usb_ohci_dmamask = 0xffffffffUL;
+struct platform_device w90x900_device_usb_ohci = {
+	.name		  = "w90x900-ohci",
+	.id		  = -1,
+	.num_resources	  = ARRAY_SIZE(w90x900_usb_ohci_resource),
+	.resource	  = w90x900_usb_ohci_resource,
+	.dev              = {
+		.dma_mask = &w90x900_device_usb_ohci_dmamask,
+		.coherent_dma_mask = 0xffffffffUL
+	}
+};
+EXPORT_SYMBOL(w90x900_device_usb_ohci);
+
+/*TouchScreen controller*/
+
+static struct resource w90x900_ts_resource[] = {
+	[0] = {
+		.start = W90X900_PA_ADC,
+		.end   = W90X900_PA_ADC + W90X900_SZ_ADC-1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_ADC,
+		.end   = IRQ_ADC,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device w90x900_device_ts = {
+	.name		= "w90x900-ts",
+	.id		= -1,
+	.resource	= w90x900_ts_resource,
+	.num_resources	= ARRAY_SIZE(w90x900_ts_resource),
+};
+EXPORT_SYMBOL(w90x900_device_ts);
+
+/* RTC controller*/
+
+static struct resource w90x900_rtc_resource[] = {
+	[0] = {
+		.start = W90X900_PA_RTC,
+		.end   = W90X900_PA_RTC + 0xff,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_RTC,
+		.end   = IRQ_RTC,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device w90x900_device_rtc = {
+	.name		= "w90x900-rtc",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(w90x900_rtc_resource),
+	.resource	= w90x900_rtc_resource,
+};
+EXPORT_SYMBOL(w90x900_device_rtc);
+
+/* KPI controller*/
+
+static struct resource w90x900_kpi_resource[] = {
+	[0] = {
+		.start = W90X900_PA_KPI,
+		.end   = W90X900_PA_KPI + W90X900_SZ_KPI - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_KPI,
+		.end   = IRQ_KPI,
+		.flags = IORESOURCE_IRQ,
+	}
+
+};
+
+struct platform_device w90x900_device_kpi = {
+	.name		= "w90x900-kpi",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(w90x900_kpi_resource),
+	.resource	= w90x900_kpi_resource,
+};
+EXPORT_SYMBOL(w90x900_device_kpi);
+
+/* USB Device (Gadget)*/
+
+static struct resource w90x900_usbgadget_resource[] = {
+	[0] = {
+		.start = W90X900_PA_USBDEV,
+		.end   = W90X900_PA_USBDEV + W90X900_SZ_USBDEV - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_USBD,
+		.end   = IRQ_USBD,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+struct platform_device w90x900_device_usbgadget = {
+	.name		= "w90x900-usbgadget",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(w90x900_usbgadget_resource),
+	.resource	= w90x900_usbgadget_resource,
+};
+EXPORT_SYMBOL(w90x900_device_usbgadget);
+
 static struct map_desc w90p910_iodesc[] __initdata = {
 };
 
@@ -88,12 +236,18 @@
 static struct platform_device *w90p910evb_dev[] __initdata = {
 	&w90p910_serial_device,
 	&w90p910_flash_device,
+	&w90x900_device_usb_ehci,
+	&w90x900_device_usb_ohci,
+	&w90x900_device_ts,
+	&w90x900_device_rtc,
+	&w90x900_device_kpi,
+	&w90x900_device_usbgadget,
 };
 
 static void __init w90p910evb_map_io(void)
 {
 	w90p910_map_io(w90p910_iodesc, ARRAY_SIZE(w90p910_iodesc));
-	w90p910_init_clocks(0);
+	w90p910_init_clocks();
 }
 
 static void __init w90p910evb_init(void)
diff --git a/arch/arm/mach-w90x900/mfp-w90p910.c b/arch/arm/mach-w90x900/mfp-w90p910.c
new file mode 100644
index 0000000..a3520fe
--- /dev/null
+++ b/arch/arm/mach-w90x900/mfp-w90p910.c
@@ -0,0 +1,116 @@
+/*
+ * linux/arch/arm/mach-w90x900/mfp-w90p910.c
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ *
+ * Wan ZongShun <mcuos.com@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/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+
+#define REG_MFSEL	(W90X900_VA_GCR + 0xC)
+
+#define GPSELF		(0x01 << 1)
+
+#define GPSELC		(0x03 << 2)
+#define ENKPI		(0x02 << 2)
+#define ENNAND		(0x01 << 2)
+
+#define GPSELEI0	(0x01 << 26)
+#define GPSELEI1	(0x01 << 27)
+
+static DECLARE_MUTEX(mfp_sem);
+
+void mfp_set_groupf(struct device *dev)
+{
+	unsigned long mfpen;
+	const char *dev_id;
+
+	BUG_ON(!dev);
+
+	down(&mfp_sem);
+
+	dev_id = dev_name(dev);
+
+	mfpen = __raw_readl(REG_MFSEL);
+
+	if (strcmp(dev_id, "w90p910-emc") == 0)
+		mfpen |= GPSELF;/*enable mac*/
+	else
+		mfpen &= ~GPSELF;/*GPIOF[9:0]*/
+
+	__raw_writel(mfpen, REG_MFSEL);
+
+	up(&mfp_sem);
+}
+EXPORT_SYMBOL(mfp_set_groupf);
+
+void mfp_set_groupc(struct device *dev)
+{
+	unsigned long mfpen;
+	const char *dev_id;
+
+	BUG_ON(!dev);
+
+	down(&mfp_sem);
+
+	dev_id = dev_name(dev);
+
+	mfpen = __raw_readl(REG_MFSEL);
+
+	if (strcmp(dev_id, "w90p910-lcd") == 0)
+		mfpen |= GPSELC;/*enable lcd*/
+	else if (strcmp(dev_id, "w90p910-kpi") == 0) {
+			mfpen &= (~GPSELC);/*enable kpi*/
+			mfpen |= ENKPI;
+		} else if (strcmp(dev_id, "w90p910-nand") == 0) {
+				mfpen &= (~GPSELC);/*enable nand*/
+				mfpen |= ENNAND;
+			} else
+				mfpen &= (~GPSELC);/*GPIOC[14:0]*/
+
+	__raw_writel(mfpen, REG_MFSEL);
+
+	up(&mfp_sem);
+}
+EXPORT_SYMBOL(mfp_set_groupc);
+
+void mfp_set_groupi(struct device *dev, int gpio)
+{
+	unsigned long mfpen;
+	const char *dev_id;
+
+	BUG_ON(!dev);
+
+	down(&mfp_sem);
+
+	dev_id = dev_name(dev);
+
+	mfpen = __raw_readl(REG_MFSEL);
+
+	if (strcmp(dev_id, "w90p910-wdog") == 0)
+		mfpen |= GPSELEI1;/*enable wdog*/
+		else if (strcmp(dev_id, "w90p910-atapi") == 0)
+			mfpen |= GPSELEI0;/*enable atapi*/
+
+	__raw_writel(mfpen, REG_MFSEL);
+
+	up(&mfp_sem);
+}
+EXPORT_SYMBOL(mfp_set_groupi);
+
diff --git a/arch/arm/mach-w90x900/w90p910.c b/arch/arm/mach-w90x900/w90p910.c
index 2bcbaa6..1c97e49 100644
--- a/arch/arm/mach-w90x900/w90p910.c
+++ b/arch/arm/mach-w90x900/w90p910.c
@@ -3,8 +3,7 @@
  *
  * Based on linux/arch/arm/plat-s3c24xx/s3c244x.c by Ben Dooks
  *
- * Copyright (c) 2008 Nuvoton technology corporation
- * All rights reserved.
+ * Copyright (c) 2008 Nuvoton technology corporation.
  *
  * Wan ZongShun <mcuos.com@gmail.com>
  *
@@ -12,8 +11,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, or
- * (at your option) any later version.
+ * the Free Software Foundation;version 2 of the License.
  *
  */
 
@@ -36,6 +34,7 @@
 #include <mach/regs-serial.h>
 
 #include "cpu.h"
+#include "clock.h"
 
 /* Initial IO mappings */
 
@@ -45,9 +44,52 @@
 	IODESC_ENT(UART),
 	IODESC_ENT(TIMER),
 	IODESC_ENT(EBI),
+	IODESC_ENT(USBEHCIHOST),
+	IODESC_ENT(USBOHCIHOST),
+	IODESC_ENT(ADC),
+	IODESC_ENT(RTC),
+	IODESC_ENT(KPI),
+	IODESC_ENT(USBDEV),
 	/*IODESC_ENT(LCD),*/
 };
 
+/* Initial clock declarations. */
+static DEFINE_CLK(lcd, 0);
+static DEFINE_CLK(audio, 1);
+static DEFINE_CLK(fmi, 4);
+static DEFINE_CLK(dmac, 5);
+static DEFINE_CLK(atapi, 6);
+static DEFINE_CLK(emc, 7);
+static DEFINE_CLK(usbd, 8);
+static DEFINE_CLK(usbh, 9);
+static DEFINE_CLK(g2d, 10);;
+static DEFINE_CLK(pwm, 18);
+static DEFINE_CLK(ps2, 24);
+static DEFINE_CLK(kpi, 25);
+static DEFINE_CLK(wdt, 26);
+static DEFINE_CLK(gdma, 27);
+static DEFINE_CLK(adc, 28);
+static DEFINE_CLK(usi, 29);
+
+static struct clk_lookup w90p910_clkregs[] = {
+	DEF_CLKLOOK(&clk_lcd, "w90p910-lcd", NULL),
+	DEF_CLKLOOK(&clk_audio, "w90p910-audio", NULL),
+	DEF_CLKLOOK(&clk_fmi, "w90p910-fmi", NULL),
+	DEF_CLKLOOK(&clk_dmac, "w90p910-dmac", NULL),
+	DEF_CLKLOOK(&clk_atapi, "w90p910-atapi", NULL),
+	DEF_CLKLOOK(&clk_emc, "w90p910-emc", NULL),
+	DEF_CLKLOOK(&clk_usbd, "w90p910-usbd", NULL),
+	DEF_CLKLOOK(&clk_usbh, "w90p910-usbh", NULL),
+	DEF_CLKLOOK(&clk_g2d, "w90p910-g2d", NULL),
+	DEF_CLKLOOK(&clk_pwm, "w90p910-pwm", NULL),
+	DEF_CLKLOOK(&clk_ps2, "w90p910-ps2", NULL),
+	DEF_CLKLOOK(&clk_kpi, "w90p910-kpi", NULL),
+	DEF_CLKLOOK(&clk_wdt, "w90p910-wdt", NULL),
+	DEF_CLKLOOK(&clk_gdma, "w90p910-gdma", NULL),
+	DEF_CLKLOOK(&clk_adc, "w90p910-adc", NULL),
+	DEF_CLKLOOK(&clk_usi, "w90p910-usi", NULL),
+};
+
 /* Initial serial platform data */
 
 struct plat_serial8250_port w90p910_uart_data[] = {
@@ -77,8 +119,9 @@
 
 /*Init W90P910 clock*/
 
-void __init w90p910_init_clocks(int xtal)
+void __init w90p910_init_clocks(void)
 {
+	clks_register(w90p910_clkregs, ARRAY_SIZE(w90p910_clkregs));
 }
 
 static int __init w90p910_init_cpu(void)
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 2097956..83c025e 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -391,7 +391,7 @@
 
 # ARMv6
 config CPU_V6
-	bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB
+	bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX
 	select CPU_32v6
 	select CPU_ABRT_EV6
 	select CPU_PABRT_NOIFAR
@@ -416,7 +416,7 @@
 
 # ARMv7
 config CPU_V7
-	bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB
+	bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX
 	select CPU_32v6K
 	select CPU_32v7
 	select CPU_ABRT_EV7
@@ -639,10 +639,23 @@
 	  port must properly enable any big-endian related features
 	  of your chipset/board/processor.
 
+config CPU_ENDIAN_BE8
+	bool
+	depends on CPU_BIG_ENDIAN
+	default CPU_V6 || CPU_V7
+	help
+	  Support for the BE-8 (big-endian) mode on ARMv6 and ARMv7 processors.
+
+config CPU_ENDIAN_BE32
+	bool
+	depends on CPU_BIG_ENDIAN
+	default !CPU_ENDIAN_BE8
+	help
+	  Support for the BE-32 (big-endian) mode on pre-ARMv6 processors.
+
 config CPU_HIGH_VECTOR
 	depends on !MMU && CPU_CP15 && !CPU_ARM740T
 	bool "Select the High exception vector"
-	default n
 	help
 	  Say Y here to select high exception vector(0xFFFF0000~).
 	  The exception vector can be vary depending on the platform
@@ -726,7 +739,6 @@
 
 config OUTER_CACHE
 	bool
-	default n
 
 config CACHE_FEROCEON_L2
 	bool "Enable the Feroceon L2 cache controller"
@@ -739,7 +751,6 @@
 config CACHE_FEROCEON_L2_WRITETHROUGH
 	bool "Force Feroceon L2 cache write through"
 	depends on CACHE_FEROCEON_L2
-	default n
 	help
 	  Say Y here to use the Feroceon L2 cache in writethrough mode.
 	  Unless you specifically require this, say N for writeback mode.
@@ -747,7 +758,7 @@
 config CACHE_L2X0
 	bool "Enable the L2x0 outer cache controller"
 	depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \
-		   REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31
+		   REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31 || MACH_REALVIEW_PBX
 	default y
 	select OUTER_CACHE
 	help
diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S
index 6f7e709..f332df7 100644
--- a/arch/arm/mm/abort-ev6.S
+++ b/arch/arm/mm/abort-ev6.S
@@ -37,6 +37,9 @@
 	movne	pc, lr
 	do_thumb_abort
 	ldreq	r3, [r2]			@ read aborted ARM instruction
+#ifdef CONFIG_CPU_ENDIAN_BE8
+	reveq	r3, r3
+#endif
 	do_ldrd_abort
 	tst	r3, #1 << 20			@ L = 0 -> write
 	orreq	r1, r1, #1 << 11		@ yes.
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 9f88dd3..0ab75c6 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -110,6 +110,12 @@
 	return err;
 }
 
+int ioremap_page(unsigned long virt, unsigned long phys,
+		 const struct mem_type *mtype)
+{
+	return remap_area_pages(virt, __phys_to_pfn(phys), PAGE_SIZE, mtype);
+}
+EXPORT_SYMBOL(ioremap_page);
 
 void __check_kvm_seq(struct mm_struct *mm)
 {
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index e6344ec..fdaa9bb 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -255,6 +255,7 @@
 {
 	return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL;
 }
+EXPORT_SYMBOL(get_mem_type);
 
 /*
  * Adjust the PMD section entries according to the CPU in use.
@@ -839,6 +840,20 @@
 		reserve_bootmem_node(pgdat, 0xa0200000, 0x1000,
 				BOOTMEM_EXCLUSIVE);
 
+	/*
+	 * U300 - This platform family can share physical memory
+	 * between two ARM cpus, one running Linux and the other
+	 * running another OS.
+	 */
+	if (machine_is_u300()) {
+#ifdef CONFIG_MACH_U300_SINGLE_RAM
+#if ((CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1) == 1) &&	\
+	CONFIG_MACH_U300_2MB_ALIGNMENT_FIX
+		res_size = 0x00100000;
+#endif
+#endif
+	}
+
 #ifdef CONFIG_SA1111
 	/*
 	 * Because of the SA1111 DMA bug, we want to preserve our
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 087e239..524ddae 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -170,6 +170,9 @@
 #endif /* CONFIG_MMU */
 	adr	r5, v6_crval
 	ldmia	r5, {r5, r6}
+#ifdef CONFIG_CPU_ENDIAN_BE8
+	orr	r6, r6, #1 << 25		@ big-endian page tables
+#endif
 	mrc	p15, 0, r0, c1, c0, 0		@ read control register
 	bic	r0, r0, r5			@ clear bits them
 	orr	r0, r0, r6			@ set them
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index a08d9d2..180a08d 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -19,17 +19,23 @@
 
 #include "proc-macros.S"
 
-#define TTB_C		(1 << 0)
 #define TTB_S		(1 << 1)
 #define TTB_RGN_NC	(0 << 3)
 #define TTB_RGN_OC_WBWA	(1 << 3)
 #define TTB_RGN_OC_WT	(2 << 3)
 #define TTB_RGN_OC_WB	(3 << 3)
+#define TTB_NOS		(1 << 5)
+#define TTB_IRGN_NC	((0 << 0) | (0 << 6))
+#define TTB_IRGN_WBWA	((0 << 0) | (1 << 6))
+#define TTB_IRGN_WT	((1 << 0) | (0 << 6))
+#define TTB_IRGN_WB	((1 << 0) | (1 << 6))
 
 #ifndef CONFIG_SMP
-#define TTB_FLAGS	TTB_C|TTB_RGN_OC_WB		@ mark PTWs cacheable, outer WB
+/* PTWs cacheable, inner WB not shareable, outer WB not shareable */
+#define TTB_FLAGS	TTB_IRGN_WB|TTB_RGN_OC_WB
 #else
-#define TTB_FLAGS	TTB_C|TTB_S|TTB_RGN_OC_WBWA	@ mark PTWs cacheable and shared, outer WBWA
+/* PTWs cacheable, inner WBWA shareable, outer WBWA not shareable */
+#define TTB_FLAGS	TTB_IRGN_WBWA|TTB_S|TTB_NOS|TTB_RGN_OC_WBWA
 #endif
 
 ENTRY(cpu_v7_proc_init)
@@ -176,8 +182,8 @@
  */
 __v7_setup:
 #ifdef CONFIG_SMP
-	mrc	p15, 0, r0, c1, c0, 1		@ Enable SMP/nAMP mode
-	orr	r0, r0, #(0x1 << 6)
+	mrc	p15, 0, r0, c1, c0, 1		@ Enable SMP/nAMP mode and
+	orr	r0, r0, #(1 << 6) | (1 << 0)	@ TLB ops broadcasting
 	mcr	p15, 0, r0, c1, c0, 1
 #endif
 	adr	r12, __v7_setup_stack		@ the local stack
@@ -227,12 +233,43 @@
 	mov	r10, #0x1f			@ domains 0, 1 = manager
 	mcr	p15, 0, r10, c3, c0, 0		@ load domain access register
 #endif
-	ldr	r5, =0xff0aa1a8
-	ldr	r6, =0x40e040e0
+	/*
+	 * Memory region attributes with SCTLR.TRE=1
+	 *
+	 *   n = TEX[0],C,B
+	 *   TR = PRRR[2n+1:2n]		- memory type
+	 *   IR = NMRR[2n+1:2n]		- inner cacheable property
+	 *   OR = NMRR[2n+17:2n+16]	- outer cacheable property
+	 *
+	 *			n	TR	IR	OR
+	 *   UNCACHED		000	00
+	 *   BUFFERABLE		001	10	00	00
+	 *   WRITETHROUGH	010	10	10	10
+	 *   WRITEBACK		011	10	11	11
+	 *   reserved		110
+	 *   WRITEALLOC		111	10	01	01
+	 *   DEV_SHARED		100	01
+	 *   DEV_NONSHARED	100	01
+	 *   DEV_WC		001	10
+	 *   DEV_CACHED		011	10
+	 *
+	 * Other attributes:
+	 *
+	 *   DS0 = PRRR[16] = 0		- device shareable property
+	 *   DS1 = PRRR[17] = 1		- device shareable property
+	 *   NS0 = PRRR[18] = 0		- normal shareable property
+	 *   NS1 = PRRR[19] = 1		- normal shareable property
+	 *   NOS = PRRR[24+n] = 1	- not outer shareable
+	 */
+	ldr	r5, =0xff0a81a8			@ PRRR
+	ldr	r6, =0x40e040e0			@ NMRR
 	mcr	p15, 0, r5, c10, c2, 0		@ write PRRR
 	mcr	p15, 0, r6, c10, c2, 1		@ write NMRR
 	adr	r5, v7_crval
 	ldmia	r5, {r5, r6}
+#ifdef CONFIG_CPU_ENDIAN_BE8
+	orr	r6, r6, #1 << 25		@ big-endian page tables
+#endif
    	mrc	p15, 0, r0, c1, c0, 0		@ read control register
 	bic	r0, r0, r5			@ clear bits them
 	orr	r0, r0, r6			@ set them
@@ -240,14 +277,14 @@
 ENDPROC(__v7_setup)
 
 	/*   AT
-	 *  TFR   EV X F   I D LR
-	 * .EEE ..EE PUI. .T.T 4RVI ZFRS BLDP WCAM
+	 *  TFR   EV X F   I D LR    S
+	 * .EEE ..EE PUI. .T.T 4RVI ZWRS BLDP WCAM
 	 * rxxx rrxx xxx0 0101 xxxx xxxx x111 xxxx < forced
-	 *    1    0 110       0011 1.00 .111 1101 < we want
+	 *    1    0 110       0011 1100 .111 1101 < we want
 	 */
 	.type	v7_crval, #object
 v7_crval:
-	crval	clear=0x0120c302, mmuset=0x10c0387d, ucset=0x00c0187c
+	crval	clear=0x0120c302, mmuset=0x10c03c7d, ucset=0x00c01c7c
 
 __v7_setup_stack:
 	.space	4 * 11				@ 11 registers
diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S
index b637e73..a26a605 100644
--- a/arch/arm/mm/tlb-v7.S
+++ b/arch/arm/mm/tlb-v7.S
@@ -42,9 +42,11 @@
 	mov	r1, r1, lsl #PAGE_SHIFT
 	vma_vm_flags r2, r2			@ get vma->vm_flags
 1:
-	mcr	p15, 0, r0, c8, c6, 1		@ TLB invalidate D MVA (was 1)
-	tst	r2, #VM_EXEC			@ Executable area ?
-	mcrne	p15, 0, r0, c8, c5, 1		@ TLB invalidate I MVA (was 1)
+#ifdef CONFIG_SMP
+	mcr	p15, 0, r0, c8, c3, 1		@ TLB invalidate U MVA (shareable) 
+#else
+	mcr	p15, 0, r0, c8, c7, 1		@ TLB invalidate U MVA
+#endif
 	add	r0, r0, #PAGE_SZ
 	cmp	r0, r1
 	blo	1b
@@ -69,8 +71,11 @@
 	mov	r0, r0, lsl #PAGE_SHIFT
 	mov	r1, r1, lsl #PAGE_SHIFT
 1:
-	mcr	p15, 0, r0, c8, c6, 1		@ TLB invalidate D MVA
-	mcr	p15, 0, r0, c8, c5, 1		@ TLB invalidate I MVA
+#ifdef CONFIG_SMP
+	mcr	p15, 0, r0, c8, c3, 1		@ TLB invalidate U MVA (shareable)
+#else
+	mcr	p15, 0, r0, c8, c7, 1		@ TLB invalidate U MVA
+#endif
 	add	r0, r0, #PAGE_SZ
 	cmp	r0, r1
 	blo	1b
@@ -87,5 +92,5 @@
 ENTRY(v7wbi_tlb_fns)
 	.long	v7wbi_flush_user_tlb_range
 	.long	v7wbi_flush_kern_tlb_range
-	.long	v6wbi_tlb_flags
+	.long	v7wbi_tlb_flags
 	.size	v7wbi_tlb_fns, . - v7wbi_tlb_fns
diff --git a/arch/arm/oprofile/op_model_mpcore.c b/arch/arm/oprofile/op_model_mpcore.c
index 853d42b..4ce0f98 100644
--- a/arch/arm/oprofile/op_model_mpcore.c
+++ b/arch/arm/oprofile/op_model_mpcore.c
@@ -41,6 +41,7 @@
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <mach/hardware.h>
+#include <mach/board-eb.h>
 #include <asm/system.h>
 
 #include "op_counter.h"
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
index 17d0e99..8986b74 100644
--- a/arch/arm/plat-mxc/Kconfig
+++ b/arch/arm/plat-mxc/Kconfig
@@ -48,7 +48,14 @@
 config MXC_PWM
 	tristate "Enable PWM driver"
 	depends on ARCH_MXC
+	select HAVE_PWM
 	help
 	  Enable support for the i.MX PWM controller(s).
 
+config ARCH_HAS_RNGA
+	bool
+	depends on ARCH_MXC
+
+config ARCH_MXC_IOMUX_V3
+	bool
 endif
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
index 0554063..e3212c8 100644
--- a/arch/arm/plat-mxc/Makefile
+++ b/arch/arm/plat-mxc/Makefile
@@ -7,4 +7,5 @@
 
 obj-$(CONFIG_ARCH_MX1) += iomux-mx1-mx2.o dma-mx1-mx2.o
 obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o
+obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
 obj-$(CONFIG_MXC_PWM)  += pwm.o
diff --git a/arch/arm/plat-mxc/gpio.c b/arch/arm/plat-mxc/gpio.c
index 89e9579..7506d96 100644
--- a/arch/arm/plat-mxc/gpio.c
+++ b/arch/arm/plat-mxc/gpio.c
@@ -64,6 +64,8 @@
 	_set_gpio_irqenable(&mxc_gpio_ports[gpio / 32], gpio & 0x1f, 1);
 }
 
+static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset);
+
 static int gpio_set_irq_type(u32 irq, u32 type)
 {
 	u32 gpio = irq_to_gpio(irq);
@@ -72,6 +74,7 @@
 	int edge;
 	void __iomem *reg = port->base;
 
+	port->both_edges &= ~(1 << (gpio & 31));
 	switch (type) {
 	case IRQ_TYPE_EDGE_RISING:
 		edge = GPIO_INT_RISE_EDGE;
@@ -79,13 +82,24 @@
 	case IRQ_TYPE_EDGE_FALLING:
 		edge = GPIO_INT_FALL_EDGE;
 		break;
+	case IRQ_TYPE_EDGE_BOTH:
+		val = mxc_gpio_get(&port->chip, gpio & 31);
+		if (val) {
+			edge = GPIO_INT_LOW_LEV;
+			pr_debug("mxc: set GPIO %d to low trigger\n", gpio);
+		} else {
+			edge = GPIO_INT_HIGH_LEV;
+			pr_debug("mxc: set GPIO %d to high trigger\n", gpio);
+		}
+		port->both_edges |= 1 << (gpio & 31);
+		break;
 	case IRQ_TYPE_LEVEL_LOW:
 		edge = GPIO_INT_LOW_LEV;
 		break;
 	case IRQ_TYPE_LEVEL_HIGH:
 		edge = GPIO_INT_HIGH_LEV;
 		break;
-	default:	/* this includes IRQ_TYPE_EDGE_BOTH */
+	default:
 		return -EINVAL;
 	}
 
@@ -98,6 +112,34 @@
 	return 0;
 }
 
+static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio)
+{
+	void __iomem *reg = port->base;
+	u32 bit, val;
+	int edge;
+
+	reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */
+	bit = gpio & 0xf;
+	val = __raw_readl(reg);
+	edge = (val >> (bit << 1)) & 3;
+	val &= ~(0x3 << (bit << 1));
+	switch (edge) {
+	case GPIO_INT_HIGH_LEV:
+		edge = GPIO_INT_LOW_LEV;
+		pr_debug("mxc: switch GPIO %d to low trigger\n", gpio);
+		break;
+	case GPIO_INT_LOW_LEV:
+		edge = GPIO_INT_HIGH_LEV;
+		pr_debug("mxc: switch GPIO %d to high trigger\n", gpio);
+		break;
+	default:
+		pr_err("mxc: invalid configuration for GPIO %d: %x\n",
+		       gpio, edge);
+		return;
+	}
+	__raw_writel(val | (edge << (bit << 1)), reg);
+}
+
 /* handle n interrupts in one status register */
 static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat)
 {
@@ -105,11 +147,16 @@
 
 	gpio_irq_no = port->virtual_irq_start;
 	for (; irq_stat != 0; irq_stat >>= 1, gpio_irq_no++) {
+		u32 gpio = irq_to_gpio(gpio_irq_no);
 
 		if ((irq_stat & 1) == 0)
 			continue;
 
 		BUG_ON(!(irq_desc[gpio_irq_no].handle_irq));
+
+		if (port->both_edges & (1 << (gpio & 31)))
+			mxc_flip_edge(port, gpio);
+
 		irq_desc[gpio_irq_no].handle_irq(gpio_irq_no,
 				&irq_desc[gpio_irq_no]);
 	}
diff --git a/arch/arm/plat-mxc/include/mach/board-armadillo5x0.h b/arch/arm/plat-mxc/include/mach/board-armadillo5x0.h
new file mode 100644
index 0000000..8769e91
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/board-armadillo5x0.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>.
+ * 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_ARMADILLO5X0_H__
+#define __ASM_ARCH_MXC_BOARD_ARMADILLO5X0_H__
+
+#include <mach/hardware.h>
+
+/* mandatory for CONFIG_DEBUG_LL */
+
+#define MXC_LL_UART_PADDR	UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR	AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
+
+#endif
diff --git a/arch/arm/plat-mxc/include/mach/board-mx21ads.h b/arch/arm/plat-mxc/include/mach/board-mx21ads.h
new file mode 100644
index 0000000..06701df
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/board-mx21ads.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2005-2007 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
+ */
+
+#ifndef __ASM_ARCH_MXC_BOARD_MX21ADS_H__
+#define __ASM_ARCH_MXC_BOARD_MX21ADS_H__
+
+/*
+ * MXC UART EVB board level configurations
+ */
+#define MXC_LL_UART_PADDR       UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR       AIPI_IO_ADDRESS(UART1_BASE_ADDR)
+
+/*
+ * Memory-mapped I/O on MX21ADS base board
+ */
+#define MX21ADS_MMIO_BASE_ADDR   0xF5000000
+#define MX21ADS_MMIO_SIZE        SZ_16M
+
+#define MX21ADS_REG_ADDR(offset)    (void __force __iomem *) \
+		(MX21ADS_MMIO_BASE_ADDR + (offset))
+
+#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)
+
+/* MX21ADS_IO_REG bit definitions */
+#define MX21ADS_IO_SD_WP        0x0001 /* read */
+#define MX21ADS_IO_TP6          0x0001 /* write */
+#define MX21ADS_IO_SW_SEL       0x0002 /* read */
+#define MX21ADS_IO_TP7          0x0002 /* write */
+#define MX21ADS_IO_RESET_E_UART 0x0004
+#define MX21ADS_IO_RESET_BASE   0x0008
+#define MX21ADS_IO_CSI_CTL2     0x0010
+#define MX21ADS_IO_CSI_CTL1     0x0020
+#define MX21ADS_IO_CSI_CTL0     0x0040
+#define MX21ADS_IO_UART1_EN     0x0080
+#define MX21ADS_IO_UART4_EN     0x0100
+#define MX21ADS_IO_LCDON        0x0200
+#define MX21ADS_IO_IRDA_EN      0x0400
+#define MX21ADS_IO_IRDA_FIR_SEL 0x0800
+#define MX21ADS_IO_IRDA_MD0_B   0x1000
+#define MX21ADS_IO_IRDA_MD1     0x2000
+#define MX21ADS_IO_LED4_ON      0x4000
+#define MX21ADS_IO_LED3_ON      0x8000
+
+#endif				/* __ASM_ARCH_MXC_BOARD_MX21ADS_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-mx27lite.h b/arch/arm/plat-mxc/include/mach/board-mx27lite.h
new file mode 100644
index 0000000..a870f8e
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/board-mx27lite.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef __ASM_ARCH_MXC_BOARD_MX27LITE_H__
+#define __ASM_ARCH_MXC_BOARD_MX27LITE_H__
+
+/* mandatory for CONFIG_DEBUG_LL */
+
+#define MXC_LL_UART_PADDR	UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR	AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
+
+#endif /* __ASM_ARCH_MXC_BOARD_MX27LITE_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-mx27pdk.h b/arch/arm/plat-mxc/include/mach/board-mx27pdk.h
new file mode 100644
index 0000000..552b55d
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/board-mx27pdk.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef __ASM_ARCH_MXC_BOARD_MX27PDK_H__
+#define __ASM_ARCH_MXC_BOARD_MX27PDK_H__
+
+/* mandatory for CONFIG_DEBUG_LL */
+
+#define MXC_LL_UART_PADDR	UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR	AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
+
+#endif /* __ASM_ARCH_MXC_BOARD_MX27PDK_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-mx31ads.h b/arch/arm/plat-mxc/include/mach/board-mx31ads.h
index 318c72a..06e6895 100644
--- a/arch/arm/plat-mxc/include/mach/board-mx31ads.h
+++ b/arch/arm/plat-mxc/include/mach/board-mx31ads.h
@@ -114,7 +114,7 @@
 
 #define MXC_MAX_EXP_IO_LINES	16
 
-/* mandatory for CONFIG_LL_DEBUG */
+/* mandatory for CONFIG_DEBUG_LL */
 
 #define MXC_LL_UART_PADDR	UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR	AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
diff --git a/arch/arm/plat-mxc/include/mach/board-mx31lilly.h b/arch/arm/plat-mxc/include/mach/board-mx31lilly.h
new file mode 100644
index 0000000..78cf31e
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/board-mx31lilly.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ * Based on code for mobots boards,
+ *   Copyright (C) 2009 Valentin Longchamp, EPFL Mobots group
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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 __ASM_ARCH_MXC_BOARD_MX31LILLY_H__
+#define __ASM_ARCH_MXC_BOARD_MX31LILLY_H__
+
+/* mandatory for CONFIG_LL_DEBUG */
+
+#define MXC_LL_UART_PADDR	UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR	(AIPI_BASE_ADDR_VIRT + 0x0A000)
+
+#ifndef __ASSEMBLY__
+
+enum mx31lilly_boards {
+	MX31LILLY_NOBOARD	= 0,
+	MX31LILLY_DB		= 1,
+};
+
+/*
+ * This CPU module needs a baseboard to work. After basic initializing
+ * its own devices, it calls baseboard's init function.
+ */
+
+extern void mx31lilly_db_init(void);
+
+#endif
+
+#endif /* __ASM_ARCH_MXC_BOARD_MX31LILLY_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-mx31lite.h b/arch/arm/plat-mxc/include/mach/board-mx31lite.h
index e4e5cf5..52fbdf2 100644
--- a/arch/arm/plat-mxc/include/mach/board-mx31lite.h
+++ b/arch/arm/plat-mxc/include/mach/board-mx31lite.h
@@ -11,28 +11,8 @@
 #ifndef __ASM_ARCH_MXC_BOARD_MX31LITE_H__
 #define __ASM_ARCH_MXC_BOARD_MX31LITE_H__
 
-#define MXC_MAX_EXP_IO_LINES	16
-
-
-/*
- * Memory Size parameters
- */
-
-/*
- * Size of SDRAM memory
- */
-#define SDRAM_MEM_SIZE		SZ_128M
-/*
- * Size of MBX buffer memory
- */
-#define MXC_MBX_MEM_SIZE	SZ_16M
-/*
- * Size of memory available to kernel
- */
-#define MEM_SIZE		(SDRAM_MEM_SIZE - MXC_MBX_MEM_SIZE)
-
 #define MXC_LL_UART_PADDR	UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR	AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
 
-#endif /* __ASM_ARCH_MXC_BOARD_MX31ADS_H__ */
+#endif /* __ASM_ARCH_MXC_BOARD_MX31LITE_H__ */
 
diff --git a/arch/arm/plat-mxc/include/mach/board-mx31moboard.h b/arch/arm/plat-mxc/include/mach/board-mx31moboard.h
index f8aef1b..303fd24 100644
--- a/arch/arm/plat-mxc/include/mach/board-mx31moboard.h
+++ b/arch/arm/plat-mxc/include/mach/board-mx31moboard.h
@@ -19,7 +19,7 @@
 #ifndef __ASM_ARCH_MXC_BOARD_MX31MOBOARD_H__
 #define __ASM_ARCH_MXC_BOARD_MX31MOBOARD_H__
 
-/* mandatory for CONFIG_LL_DEBUG */
+/* mandatory for CONFIG_DEBUG_LL */
 
 #define MXC_LL_UART_PADDR	UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR	(AIPI_BASE_ADDR_VIRT + 0x0A000)
diff --git a/arch/arm/plat-mxc/include/mach/board-mx31pdk.h b/arch/arm/plat-mxc/include/mach/board-mx31pdk.h
index 2b6b316..519bab3 100644
--- a/arch/arm/plat-mxc/include/mach/board-mx31pdk.h
+++ b/arch/arm/plat-mxc/include/mach/board-mx31pdk.h
@@ -11,9 +11,54 @@
 #ifndef __ASM_ARCH_MXC_BOARD_MX31PDK_H__
 #define __ASM_ARCH_MXC_BOARD_MX31PDK_H__
 
-/* mandatory for CONFIG_LL_DEBUG */
+/* mandatory for CONFIG_DEBUG_LL */
 
 #define MXC_LL_UART_PADDR	UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR	AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
 
+/* Definitions for components on the Debug board */
+
+/* Base address of CPLD controller on the Debug board */
+#define DEBUG_BASE_ADDRESS		CS5_IO_ADDRESS(CS5_BASE_ADDR)
+
+/* LAN9217 ethernet base address */
+#define LAN9217_BASE_ADDR		CS5_BASE_ADDR
+
+/* CPLD config and interrupt base address */
+#define CPLD_ADDR			(DEBUG_BASE_ADDRESS + 0x20000)
+
+/* LED switchs */
+#define CPLD_LED_REG			(CPLD_ADDR + 0x00)
+/* buttons */
+#define CPLD_SWITCH_BUTTONS_REG	(EXPIO_ADDR + 0x08)
+/* status, interrupt */
+#define CPLD_INT_STATUS_REG		(CPLD_ADDR + 0x10)
+#define CPLD_INT_MASK_REG		(CPLD_ADDR + 0x38)
+#define CPLD_INT_RESET_REG		(CPLD_ADDR + 0x20)
+/* magic word for debug CPLD */
+#define CPLD_MAGIC_NUMBER1_REG		(CPLD_ADDR + 0x40)
+#define CPLD_MAGIC_NUMBER2_REG		(CPLD_ADDR + 0x48)
+/* CPLD code version */
+#define CPLD_CODE_VER_REG		(CPLD_ADDR + 0x50)
+/* magic word for debug CPLD */
+#define CPLD_MAGIC_NUMBER3_REG		(CPLD_ADDR + 0x58)
+/* module reset register */
+#define CPLD_MODULE_RESET_REG		(CPLD_ADDR + 0x60)
+/* CPU ID and Personality ID */
+#define CPLD_MCU_BOARD_ID_REG		(CPLD_ADDR + 0x68)
+
+/* CPLD IRQ line for external uart, external ethernet etc */
+#define EXPIO_PARENT_INT	IOMUX_TO_IRQ(MX31_PIN_GPIO1_1)
+
+#define MXC_EXP_IO_BASE		(MXC_BOARD_IRQ_START)
+#define MXC_IRQ_TO_EXPIO(irq)	((irq) - MXC_EXP_IO_BASE)
+
+#define EXPIO_INT_ENET		(MXC_EXP_IO_BASE + 0)
+#define EXPIO_INT_XUART_A	(MXC_EXP_IO_BASE + 1)
+#define EXPIO_INT_XUART_B	(MXC_EXP_IO_BASE + 2)
+#define EXPIO_INT_BUTTON_A	(MXC_EXP_IO_BASE + 3)
+#define EXPIO_INT_BUTTON_B	(MXC_EXP_IO_BASE + 4)
+
+#define MXC_MAX_EXP_IO_LINES	16
+
 #endif /* __ASM_ARCH_MXC_BOARD_MX31PDK_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-mx35pdk.h b/arch/arm/plat-mxc/include/mach/board-mx35pdk.h
new file mode 100644
index 0000000..1111037
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/board-mx35pdk.h
@@ -0,0 +1,27 @@
+/*
+ *  Copyright 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 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_MXC_BOARD_MX35PDK_H__
+#define __ASM_ARCH_MXC_BOARD_MX35PDK_H__
+
+/* mandatory for CONFIG_DEBUG_LL */
+
+#define MXC_LL_UART_PADDR	UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR	AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
+
+#endif /* __ASM_ARCH_MXC_BOARD_MX35PDK_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-pcm037.h b/arch/arm/plat-mxc/include/mach/board-pcm037.h
index 82232ba..f0a1fa1 100644
--- a/arch/arm/plat-mxc/include/mach/board-pcm037.h
+++ b/arch/arm/plat-mxc/include/mach/board-pcm037.h
@@ -19,7 +19,7 @@
 #ifndef __ASM_ARCH_MXC_BOARD_PCM037_H__
 #define __ASM_ARCH_MXC_BOARD_PCM037_H__
 
-/* mandatory for CONFIG_LL_DEBUG */
+/* mandatory for CONFIG_DEBUG_LL */
 
 #define MXC_LL_UART_PADDR	UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR	AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
diff --git a/arch/arm/plat-mxc/include/mach/board-pcm038.h b/arch/arm/plat-mxc/include/mach/board-pcm038.h
index 750c62a..4fcd749 100644
--- a/arch/arm/plat-mxc/include/mach/board-pcm038.h
+++ b/arch/arm/plat-mxc/include/mach/board-pcm038.h
@@ -19,7 +19,7 @@
 #ifndef __ASM_ARCH_MXC_BOARD_PCM038_H__
 #define __ASM_ARCH_MXC_BOARD_PCM038_H__
 
-/* mandatory for CONFIG_LL_DEBUG */
+/* mandatory for CONFIG_DEBUG_LL */
 
 #define MXC_LL_UART_PADDR	UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR	(AIPI_BASE_ADDR_VIRT + 0x0A000)
diff --git a/arch/arm/plat-mxc/include/mach/board-pcm043.h b/arch/arm/plat-mxc/include/mach/board-pcm043.h
new file mode 100644
index 0000000..15fbdf1
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/board-pcm043.h
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (C) 2008 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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_MXC_BOARD_PCM043_H__
+#define __ASM_ARCH_MXC_BOARD_PCM043_H__
+
+/* mandatory for CONFIG_LL_DEBUG */
+
+#define MXC_LL_UART_PADDR	UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR	AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
+
+#endif /* __ASM_ARCH_MXC_BOARD_PCM043_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-qong.h b/arch/arm/plat-mxc/include/mach/board-qong.h
index 4ff762d..04033ec 100644
--- a/arch/arm/plat-mxc/include/mach/board-qong.h
+++ b/arch/arm/plat-mxc/include/mach/board-qong.h
@@ -11,7 +11,7 @@
 #ifndef __ASM_ARCH_MXC_BOARD_QONG_H__
 #define __ASM_ARCH_MXC_BOARD_QONG_H__
 
-/* mandatory for CONFIG_LL_DEBUG */
+/* mandatory for CONFIG_DEBUG_LL */
 
 #define MXC_LL_UART_PADDR	UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR	AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h
index b2f9b72..02c3cd0 100644
--- a/arch/arm/plat-mxc/include/mach/common.h
+++ b/arch/arm/plat-mxc/include/mach/common.h
@@ -14,7 +14,11 @@
 struct platform_device;
 struct clk;
 
-extern void mxc_map_io(void);
+extern void mx1_map_io(void);
+extern void mx21_map_io(void);
+extern void mx27_map_io(void);
+extern void mx31_map_io(void);
+extern void mx35_map_io(void);
 extern void mxc_init_irq(void);
 extern void mxc_timer_init(struct clk *timer_clk);
 extern int mx1_clocks_init(unsigned long fref);
diff --git a/arch/arm/plat-mxc/include/mach/debug-macro.S b/arch/arm/plat-mxc/include/mach/debug-macro.S
index 4f77314..bbc5f67 100644
--- a/arch/arm/plat-mxc/include/mach/debug-macro.S
+++ b/arch/arm/plat-mxc/include/mach/debug-macro.S
@@ -25,6 +25,9 @@
 #ifdef CONFIG_MACH_MX27ADS
 #include <mach/board-mx27ads.h>
 #endif
+#ifdef CONFIG_MACH_MX21ADS
+#include <mach/board-mx21ads.h>
+#endif
 #ifdef CONFIG_MACH_PCM038
 #include <mach/board-pcm038.h>
 #endif
@@ -34,6 +37,21 @@
 #ifdef CONFIG_MACH_QONG
 #include <mach/board-qong.h>
 #endif
+#ifdef CONFIG_MACH_PCM043
+#include <mach/board-pcm043.h>
+#endif
+#ifdef CONFIG_MACH_MX27_3DS
+#include <mach/board-mx27pdk.h>
+#endif
+#ifdef CONFIG_MACH_ARMADILLO5X0
+#include <mach/board-armadillo5x0.h>
+#endif
+#ifdef CONFIG_MACH_MX35_3DS
+#include <mach/board-mx35pdk.h>
+#endif
+#ifdef CONFIG_MACH_MX27LITE
+#include <mach/board-mx27lite.h>
+#endif
 		.macro	addruart,rx
 		mrc	p15, 0, \rx, c1, c0
 		tst	\rx, #1			@ MMU enabled?
diff --git a/arch/arm/plat-mxc/include/mach/gpio.h b/arch/arm/plat-mxc/include/mach/gpio.h
index ea509f1..894d2f8 100644
--- a/arch/arm/plat-mxc/include/mach/gpio.h
+++ b/arch/arm/plat-mxc/include/mach/gpio.h
@@ -35,6 +35,7 @@
 	int irq;
 	int virtual_irq_start;
 	struct gpio_chip chip;
+	u32 both_edges;
 };
 
 int mxc_gpio_init(struct mxc_gpio_port*, int);
diff --git a/arch/arm/plat-mxc/include/mach/imx-uart.h b/arch/arm/plat-mxc/include/mach/imx-uart.h
index f9bd17d..4adec9b 100644
--- a/arch/arm/plat-mxc/include/mach/imx-uart.h
+++ b/arch/arm/plat-mxc/include/mach/imx-uart.h
@@ -24,7 +24,7 @@
 
 struct imxuart_platform_data {
 	int (*init)(struct platform_device *pdev);
-	int (*exit)(struct platform_device *pdev);
+	void (*exit)(struct platform_device *pdev);
 	unsigned int flags;
 	void (*irda_enable)(int enable);
 	unsigned int irda_inv_rx:1;
diff --git a/arch/arm/plat-mxc/include/mach/imxfb.h b/arch/arm/plat-mxc/include/mach/imxfb.h
index 762a7b0..9f01011 100644
--- a/arch/arm/plat-mxc/include/mach/imxfb.h
+++ b/arch/arm/plat-mxc/include/mach/imxfb.h
@@ -76,8 +76,8 @@
 	u_char * fixed_screen_cpu;
 	dma_addr_t fixed_screen_dma;
 
-	int (*init)(struct platform_device*);
-	int (*exit)(struct platform_device*);
+	int (*init)(struct platform_device *);
+	void (*exit)(struct platform_device *);
 
 	void (*lcd_power)(int);
 	void (*backlight_power)(int);
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx3.h b/arch/arm/plat-mxc/include/mach/iomux-mx3.h
index 57e927a..27f8d1b 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx3.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx3.h
@@ -114,7 +114,7 @@
  * 	- setups the iomux according to the configuration
  * 	- if the pin is configured as a GPIO, we claim it throug kernel gpiolib
  */
-int mxc_iomux_setup_pin(const unsigned int pin, const char *label);
+int mxc_iomux_alloc_pin(const unsigned int pin, const char *label);
 /*
  * setups mutliple pins
  * convenient way to call the above function with tables
@@ -633,6 +633,40 @@
 #define MX31_PIN_USBOTG_DIR__USBOTG_DIR        IOMUX_MODE(MX31_PIN_USBOTG_DIR, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_USBOTG_NXT__USBOTG_NXT        IOMUX_MODE(MX31_PIN_USBOTG_NXT, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_USBOTG_STP__USBOTG_STP        IOMUX_MODE(MX31_PIN_USBOTG_STP, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_USB_OC__GPIO1_30	IOMUX_MODE(MX31_PIN_USB_OC, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_I2C_DAT__I2C1_SDA	IOMUX_MODE(MX31_PIN_I2C_DAT, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_I2C_CLK__I2C1_SCL	IOMUX_MODE(MX31_PIN_I2C_CLK, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_DCD_DTE1__I2C2_SDA	IOMUX_MODE(MX31_PIN_DCD_DTE1, IOMUX_CONFIG_ALT2)
+#define MX31_PIN_RI_DTE1__I2C2_SCL	IOMUX_MODE(MX31_PIN_RI_DTE1, IOMUX_CONFIG_ALT2)
+#define MX31_PIN_ATA_CS0__GPIO3_26	IOMUX_MODE(MX31_PIN_ATA_CS0, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_ATA_CS1__GPIO3_27	IOMUX_MODE(MX31_PIN_ATA_CS1, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_PC_PWRON__SD2_DATA3	IOMUX_MODE(MX31_PIN_PC_PWRON, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_PC_VS1__SD2_DATA2	IOMUX_MODE(MX31_PIN_PC_VS1, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_PC_READY__SD2_DATA1	IOMUX_MODE(MX31_PIN_PC_READY, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_PC_WAIT_B__SD2_DATA0	IOMUX_MODE(MX31_PIN_PC_WAIT_B, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_PC_CD2_B__SD2_CLK	IOMUX_MODE(MX31_PIN_PC_CD2_B, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_PC_CD1_B__SD2_CMD	IOMUX_MODE(MX31_PIN_PC_CD1_B, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_ATA_DIOR__GPIO3_28	IOMUX_MODE(MX31_PIN_ATA_DIOR, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_ATA_DIOW__GPIO3_29	IOMUX_MODE(MX31_PIN_ATA_DIOW, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_CSI_D4__CSI_D4		IOMUX_MODE(MX31_PIN_CSI_D4, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D5__CSI_D5		IOMUX_MODE(MX31_PIN_CSI_D5, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D6__CSI_D6		IOMUX_MODE(MX31_PIN_CSI_D6, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D7__CSI_D7		IOMUX_MODE(MX31_PIN_CSI_D7, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D8__CSI_D8		IOMUX_MODE(MX31_PIN_CSI_D8, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D9__CSI_D9		IOMUX_MODE(MX31_PIN_CSI_D9, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D10__CSI_D10	IOMUX_MODE(MX31_PIN_CSI_D10, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D11__CSI_D11	IOMUX_MODE(MX31_PIN_CSI_D11, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D12__CSI_D12	IOMUX_MODE(MX31_PIN_CSI_D12, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D13__CSI_D13	IOMUX_MODE(MX31_PIN_CSI_D13, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D14__CSI_D14	IOMUX_MODE(MX31_PIN_CSI_D14, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D15__CSI_D15	IOMUX_MODE(MX31_PIN_CSI_D15, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_HSYNC__CSI_HSYNC	IOMUX_MODE(MX31_PIN_CSI_HSYNC, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_MCLK__CSI_MCLK	IOMUX_MODE(MX31_PIN_CSI_MCLK, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_PIXCLK__CSI_PIXCLK	IOMUX_MODE(MX31_PIN_CSI_PIXCLK, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_VSYNC__CSI_VSYNC	IOMUX_MODE(MX31_PIN_CSI_VSYNC, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_GPIO3_0__GPIO3_0	IOMUX_MODE(MX31_PIN_GPIO3_0, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_GPIO3_1__GPIO3_1	IOMUX_MODE(MX31_PIN_GPIO3_1, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_TXD2__GPIO1_28		IOMUX_MODE(MX31_PIN_TXD2, IOMUX_CONFIG_GPIO)
 
 /*XXX: The SS0, SS1, SS2, SS3 lines of spi3 are multiplexed by cspi2_ss0, cspi2_ss1, cspi1_ss0
  * cspi1_ss1*/
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx35.h b/arch/arm/plat-mxc/include/mach/iomux-mx35.h
new file mode 100644
index 0000000..00b0ac1
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx35.h
@@ -0,0 +1,1267 @@
+/*
+ * Copyright (C, NO_PAD_CTRL) 2009 by Jan Weitzel Phytec Messtechnik GmbH <armlinux@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, NO_PAD_CTRL) 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_IOMUX_MX35_H__
+#define __MACH_IOMUX_MX35_H__
+
+#include <mach/iomux-v3.h>
+
+/*
+ * The naming convention for the pad modes is MX35_PAD_<padname>__<padmode>
+ * If <padname> or <padmode> refers to a GPIO, it is named
+ * GPIO_<unit>_<num> see also iomux-v3.h
+ */
+
+/*									  PAD    MUX   ALT INPSE PATH */
+#define MX35_PAD_CAPTURE__GPT_CAPIN1				IOMUX_PAD(0x328, 0x004, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CAPTURE__GPT_CMPOUT2				IOMUX_PAD(0x328, 0x004, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CAPTURE__CSPI2_SS1				IOMUX_PAD(0x328, 0x004, 2, 0x7f4, 0, NO_PAD_CTRL)
+#define MX35_PAD_CAPTURE__EPIT1_EPITO				IOMUX_PAD(0x328, 0x004, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CAPTURE__CCM_CLK32K				IOMUX_PAD(0x328, 0x004, 4, 0x7d0, 0, NO_PAD_CTRL)
+#define MX35_PAD_CAPTURE__GPIO1_4				IOMUX_PAD(0x328, 0x004, 5, 0x850, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_COMPARE__GPT_CMPOUT1				IOMUX_PAD(0x32c, 0x008, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_COMPARE__GPT_CAPIN2				IOMUX_PAD(0x32c, 0x008, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_COMPARE__GPT_CMPOUT3				IOMUX_PAD(0x32c, 0x008, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_COMPARE__EPIT2_EPITO				IOMUX_PAD(0x32c, 0x008, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_COMPARE__GPIO1_5				IOMUX_PAD(0x32c, 0x008, 5, 0x854, 0, NO_PAD_CTRL)
+#define MX35_PAD_COMPARE__SDMA_EXTDMA_2				IOMUX_PAD(0x32c, 0x008, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_WDOG_RST__WDOG_WDOG_B				IOMUX_PAD(0x330, 0x00c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_WDOG_RST__IPU_FLASH_STROBE			IOMUX_PAD(0x330, 0x00c, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_WDOG_RST__GPIO1_6				IOMUX_PAD(0x330, 0x00c, 5, 0x858, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_GPIO1_0__GPIO1_0				IOMUX_PAD(0x334, 0x010, 0, 0x82c, 0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO1_0__CCM_PMIC_RDY				IOMUX_PAD(0x334, 0x010, 1, 0x7d4, 0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO1_0__OWIRE_LINE				IOMUX_PAD(0x334, 0x010, 2, 0x990, 0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO1_0__SDMA_EXTDMA_0				IOMUX_PAD(0x334, 0x010, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_GPIO1_1__GPIO1_1				IOMUX_PAD(0x338, 0x014, 0, 0x838, 0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO1_1__PWM_PWMO				IOMUX_PAD(0x338, 0x014, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO1_1__CSPI1_SS2				IOMUX_PAD(0x338, 0x014, 3, 0x7d8, 0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO1_1__SCC_TAMPER_DETECT			IOMUX_PAD(0x338, 0x014, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO1_1__SDMA_EXTDMA_1				IOMUX_PAD(0x338, 0x014, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_GPIO2_0__GPIO2_0				IOMUX_PAD(0x33c, 0x018, 0, 0x868, 0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO2_0__USB_TOP_USBOTG_CLK			IOMUX_PAD(0x33c, 0x018, 1, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_GPIO3_0__GPIO3_0				IOMUX_PAD(0x340, 0x01c, 0, 0x8e8, 0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO3_0__USB_TOP_USBH2_CLK			IOMUX_PAD(0x340, 0x01c, 1, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_RESET_IN_B__CCM_RESET_IN_B			IOMUX_PAD(0x344, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_POR_B__CCM_POR_B				IOMUX_PAD(0x348, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CLKO__CCM_CLKO					IOMUX_PAD(0x34c, 0x020, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CLKO__GPIO1_8					IOMUX_PAD(0x34c, 0x020, 5, 0x860, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_BOOT_MODE0__CCM_BOOT_MODE_0			IOMUX_PAD(0x350, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_BOOT_MODE1__CCM_BOOT_MODE_1			IOMUX_PAD(0x354, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CLK_MODE0__CCM_CLK_MODE_0			IOMUX_PAD(0x358, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CLK_MODE1__CCM_CLK_MODE_1			IOMUX_PAD(0x35c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_POWER_FAIL__CCM_DSM_WAKEUP_INT_26		IOMUX_PAD(0x360, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_VSTBY__CCM_VSTBY				IOMUX_PAD(0x364, 0x024, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_VSTBY__GPIO1_7					IOMUX_PAD(0x364, 0x024, 5, 0x85c, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_A0__EMI_EIM_DA_L_0				IOMUX_PAD(0x368, 0x028, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A1__EMI_EIM_DA_L_1				IOMUX_PAD(0x36c, 0x02c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A2__EMI_EIM_DA_L_2				IOMUX_PAD(0x370, 0x030, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A3__EMI_EIM_DA_L_3				IOMUX_PAD(0x374, 0x034, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A4__EMI_EIM_DA_L_4				IOMUX_PAD(0x378, 0x038, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A5__EMI_EIM_DA_L_5				IOMUX_PAD(0x37c, 0x03c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A6__EMI_EIM_DA_L_6				IOMUX_PAD(0x380, 0x040, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A7__EMI_EIM_DA_L_7				IOMUX_PAD(0x384, 0x044, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A8__EMI_EIM_DA_H_8				IOMUX_PAD(0x388, 0x048, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A9__EMI_EIM_DA_H_9				IOMUX_PAD(0x38c, 0x04c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A10__EMI_EIM_DA_H_10				IOMUX_PAD(0x390, 0x050, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_MA10__EMI_MA10					IOMUX_PAD(0x394, 0x054, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A11__EMI_EIM_DA_H_11				IOMUX_PAD(0x398, 0x058, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A12__EMI_EIM_DA_H_12				IOMUX_PAD(0x39c, 0x05c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A13__EMI_EIM_DA_H_13				IOMUX_PAD(0x3a0, 0x060, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A14__EMI_EIM_DA_H2_14				IOMUX_PAD(0x3a4, 0x064, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A15__EMI_EIM_DA_H2_15				IOMUX_PAD(0x3a8, 0x068, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A16__EMI_EIM_A_16				IOMUX_PAD(0x3ac, 0x06c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A17__EMI_EIM_A_17				IOMUX_PAD(0x3b0, 0x070, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A18__EMI_EIM_A_18				IOMUX_PAD(0x3b4, 0x074, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A19__EMI_EIM_A_19				IOMUX_PAD(0x3b8, 0x078, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A20__EMI_EIM_A_20				IOMUX_PAD(0x3bc, 0x07c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A21__EMI_EIM_A_21				IOMUX_PAD(0x3c0, 0x080, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A22__EMI_EIM_A_22				IOMUX_PAD(0x3c4, 0x084, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A23__EMI_EIM_A_23				IOMUX_PAD(0x3c8, 0x088, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A24__EMI_EIM_A_24				IOMUX_PAD(0x3cc, 0x08c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A25__EMI_EIM_A_25				IOMUX_PAD(0x3d0, 0x090, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDBA1__EMI_EIM_SDBA1				IOMUX_PAD(0x3d4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDBA0__EMI_EIM_SDBA0				IOMUX_PAD(0x3d8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD0__EMI_DRAM_D_0				IOMUX_PAD(0x3dc, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD1__EMI_DRAM_D_1				IOMUX_PAD(0x3e0, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD2__EMI_DRAM_D_2				IOMUX_PAD(0x3e4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD3__EMI_DRAM_D_3				IOMUX_PAD(0x3e8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD4__EMI_DRAM_D_4				IOMUX_PAD(0x3ec, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD5__EMI_DRAM_D_5				IOMUX_PAD(0x3f0, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD6__EMI_DRAM_D_6				IOMUX_PAD(0x3f4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD7__EMI_DRAM_D_7				IOMUX_PAD(0x3f8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD8__EMI_DRAM_D_8				IOMUX_PAD(0x3fc, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD9__EMI_DRAM_D_9				IOMUX_PAD(0x400, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD10__EMI_DRAM_D_10				IOMUX_PAD(0x404, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD11__EMI_DRAM_D_11				IOMUX_PAD(0x408, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD12__EMI_DRAM_D_12				IOMUX_PAD(0x40c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD13__EMI_DRAM_D_13				IOMUX_PAD(0x410, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD14__EMI_DRAM_D_14				IOMUX_PAD(0x414, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD15__EMI_DRAM_D_15				IOMUX_PAD(0x418, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD16__EMI_DRAM_D_16				IOMUX_PAD(0x41c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD17__EMI_DRAM_D_17				IOMUX_PAD(0x420, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD18__EMI_DRAM_D_18				IOMUX_PAD(0x424, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD19__EMI_DRAM_D_19				IOMUX_PAD(0x428, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD20__EMI_DRAM_D_20				IOMUX_PAD(0x42c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD21__EMI_DRAM_D_21				IOMUX_PAD(0x430, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD22__EMI_DRAM_D_22				IOMUX_PAD(0x434, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD23__EMI_DRAM_D_23				IOMUX_PAD(0x438, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD24__EMI_DRAM_D_24				IOMUX_PAD(0x43c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD25__EMI_DRAM_D_25				IOMUX_PAD(0x440, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD26__EMI_DRAM_D_26				IOMUX_PAD(0x444, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD27__EMI_DRAM_D_27				IOMUX_PAD(0x448, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD28__EMI_DRAM_D_28				IOMUX_PAD(0x44c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD29__EMI_DRAM_D_29				IOMUX_PAD(0x450, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD30__EMI_DRAM_D_30				IOMUX_PAD(0x454, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD31__EMI_DRAM_D_31				IOMUX_PAD(0x458, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_DQM0__EMI_DRAM_DQM_0				IOMUX_PAD(0x45c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_DQM1__EMI_DRAM_DQM_1				IOMUX_PAD(0x460, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_DQM2__EMI_DRAM_DQM_2				IOMUX_PAD(0x464, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_DQM3__EMI_DRAM_DQM_3				IOMUX_PAD(0x468, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_EB0__EMI_EIM_EB0_B				IOMUX_PAD(0x46c, 0x094, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_EB1__EMI_EIM_EB1_B				IOMUX_PAD(0x470, 0x098, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_OE__EMI_EIM_OE					IOMUX_PAD(0x474, 0x09c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CS0__EMI_EIM_CS0				IOMUX_PAD(0x478, 0x0a0, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CS1__EMI_EIM_CS1				IOMUX_PAD(0x47c, 0x0a4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CS1__EMI_NANDF_CE3				IOMUX_PAD(0x47c, 0x0a4, 3, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CS2__EMI_EIM_CS2				IOMUX_PAD(0x480, 0x0a8, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CS3__EMI_EIM_CS3				IOMUX_PAD(0x484, 0x0ac, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CS4__EMI_EIM_CS4				IOMUX_PAD(0x488, 0x0b0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CS4__EMI_DTACK_B				IOMUX_PAD(0x488, 0x0b0, 1, 0x800, 0, NO_PAD_CTRL)
+#define MX35_PAD_CS4__EMI_NANDF_CE1				IOMUX_PAD(0x488, 0x0b0, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CS4__GPIO1_20					IOMUX_PAD(0x488, 0x0b0, 5, 0x83c, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_CS5__EMI_EIM_CS5				IOMUX_PAD(0x48c, 0x0b4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CS5__CSPI2_SS2					IOMUX_PAD(0x48c, 0x0b4, 1, 0x7f8, 0, NO_PAD_CTRL)
+#define MX35_PAD_CS5__CSPI1_SS2					IOMUX_PAD(0x48c, 0x0b4, 2, 0x7d8, 1, NO_PAD_CTRL)
+#define MX35_PAD_CS5__EMI_NANDF_CE2				IOMUX_PAD(0x48c, 0x0b4, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CS5__GPIO1_21					IOMUX_PAD(0x48c, 0x0b4, 5, 0x840, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_NF_CE0__EMI_NANDF_CE0				IOMUX_PAD(0x490, 0x0b8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NF_CE0__GPIO1_22				IOMUX_PAD(0x490, 0x0b8, 5, 0x844, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_ECB__EMI_EIM_ECB				IOMUX_PAD(0x494, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LBA__EMI_EIM_LBA				IOMUX_PAD(0x498, 0x0bc, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_BCLK__EMI_EIM_BCLK				IOMUX_PAD(0x49c, 0x0c0, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_RW__EMI_EIM_RW					IOMUX_PAD(0x4a0, 0x0c4, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_RAS__EMI_DRAM_RAS				IOMUX_PAD(0x4a4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CAS__EMI_DRAM_CAS				IOMUX_PAD(0x4a8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDWE__EMI_DRAM_SDWE				IOMUX_PAD(0x4ac, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDCKE0__EMI_DRAM_SDCKE_0			IOMUX_PAD(0x4b0, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDCKE1__EMI_DRAM_SDCKE_1			IOMUX_PAD(0x4b4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDCLK__EMI_DRAM_SDCLK				IOMUX_PAD(0x4b8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDQS0__EMI_DRAM_SDQS_0				IOMUX_PAD(0x4bc, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDQS1__EMI_DRAM_SDQS_1				IOMUX_PAD(0x4c0, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDQS2__EMI_DRAM_SDQS_2				IOMUX_PAD(0x4c4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDQS3__EMI_DRAM_SDQS_3				IOMUX_PAD(0x4c8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_NFWE_B__EMI_NANDF_WE_B				IOMUX_PAD(0x4cc, 0x0c8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFWE_B__USB_TOP_USBH2_DATA_3			IOMUX_PAD(0x4cc, 0x0c8, 1, 0x9d8, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFWE_B__IPU_DISPB_D0_VSYNC			IOMUX_PAD(0x4cc, 0x0c8, 2, 0x924, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFWE_B__GPIO2_18				IOMUX_PAD(0x4cc, 0x0c8, 5, 0x88c, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFWE_B__ARM11P_TOP_TRACE_0			IOMUX_PAD(0x4cc, 0x0c8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_NFRE_B__EMI_NANDF_RE_B				IOMUX_PAD(0x4d0, 0x0cc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFRE_B__USB_TOP_USBH2_DIR			IOMUX_PAD(0x4d0, 0x0cc, 1, 0x9ec, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFRE_B__IPU_DISPB_BCLK				IOMUX_PAD(0x4d0, 0x0cc, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFRE_B__GPIO2_19				IOMUX_PAD(0x4d0, 0x0cc, 5, 0x890, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFRE_B__ARM11P_TOP_TRACE_1			IOMUX_PAD(0x4d0, 0x0cc, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_NFALE__EMI_NANDF_ALE				IOMUX_PAD(0x4d4, 0x0d0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFALE__USB_TOP_USBH2_STP			IOMUX_PAD(0x4d4, 0x0d0, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFALE__IPU_DISPB_CS0				IOMUX_PAD(0x4d4, 0x0d0, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFALE__GPIO2_20				IOMUX_PAD(0x4d4, 0x0d0, 5, 0x898, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFALE__ARM11P_TOP_TRACE_2			IOMUX_PAD(0x4d4, 0x0d0, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_NFCLE__EMI_NANDF_CLE				IOMUX_PAD(0x4d8, 0x0d4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFCLE__USB_TOP_USBH2_NXT			IOMUX_PAD(0x4d8, 0x0d4, 1, 0x9f0, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFCLE__IPU_DISPB_PAR_RS			IOMUX_PAD(0x4d8, 0x0d4, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFCLE__GPIO2_21				IOMUX_PAD(0x4d8, 0x0d4, 5, 0x89c, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFCLE__ARM11P_TOP_TRACE_3			IOMUX_PAD(0x4d8, 0x0d4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_NFWP_B__EMI_NANDF_WP_B				IOMUX_PAD(0x4dc, 0x0d8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFWP_B__USB_TOP_USBH2_DATA_7			IOMUX_PAD(0x4dc, 0x0d8, 1, 0x9e8, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFWP_B__IPU_DISPB_WR				IOMUX_PAD(0x4dc, 0x0d8, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFWP_B__GPIO2_22				IOMUX_PAD(0x4dc, 0x0d8, 5, 0x8a0, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFWP_B__ARM11P_TOP_TRCTL			IOMUX_PAD(0x4dc, 0x0d8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_NFRB__EMI_NANDF_RB				IOMUX_PAD(0x4e0, 0x0dc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFRB__IPU_DISPB_RD				IOMUX_PAD(0x4e0, 0x0dc, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFRB__GPIO2_23					IOMUX_PAD(0x4e0, 0x0dc, 5, 0x8a4, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFRB__ARM11P_TOP_TRCLK				IOMUX_PAD(0x4e0, 0x0dc, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D15__EMI_EIM_D_15				IOMUX_PAD(0x4e4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D14__EMI_EIM_D_14				IOMUX_PAD(0x4e8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D13__EMI_EIM_D_13				IOMUX_PAD(0x4ec, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D12__EMI_EIM_D_12				IOMUX_PAD(0x4f0, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D11__EMI_EIM_D_11				IOMUX_PAD(0x4f4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D10__EMI_EIM_D_10				IOMUX_PAD(0x4f8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D9__EMI_EIM_D_9				IOMUX_PAD(0x4fc, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D8__EMI_EIM_D_8				IOMUX_PAD(0x500, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D7__EMI_EIM_D_7				IOMUX_PAD(0x504, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D6__EMI_EIM_D_6				IOMUX_PAD(0x508, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D5__EMI_EIM_D_5				IOMUX_PAD(0x50c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D4__EMI_EIM_D_4				IOMUX_PAD(0x510, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3__EMI_EIM_D_3				IOMUX_PAD(0x514, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D2__EMI_EIM_D_2				IOMUX_PAD(0x518, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D1__EMI_EIM_D_1				IOMUX_PAD(0x51c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D0__EMI_EIM_D_0				IOMUX_PAD(0x520, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D8__IPU_CSI_D_8				IOMUX_PAD(0x524, 0x0e0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D8__KPP_COL_0				IOMUX_PAD(0x524, 0x0e0, 1, 0x950, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D8__GPIO1_20				IOMUX_PAD(0x524, 0x0e0, 5, 0x83c, 1, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D8__ARM11P_TOP_EVNTBUS_13			IOMUX_PAD(0x524, 0x0e0, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D9__IPU_CSI_D_9				IOMUX_PAD(0x528, 0x0e4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D9__KPP_COL_1				IOMUX_PAD(0x528, 0x0e4, 1, 0x954, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D9__GPIO1_21				IOMUX_PAD(0x528, 0x0e4, 5, 0x840, 1, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D9__ARM11P_TOP_EVNTBUS_14			IOMUX_PAD(0x528, 0x0e4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D10__IPU_CSI_D_10				IOMUX_PAD(0x52c, 0x0e8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D10__KPP_COL_2				IOMUX_PAD(0x52c, 0x0e8, 1, 0x958, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D10__GPIO1_22				IOMUX_PAD(0x52c, 0x0e8, 5, 0x844, 1, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D10__ARM11P_TOP_EVNTBUS_15			IOMUX_PAD(0x52c, 0x0e8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D11__IPU_CSI_D_11				IOMUX_PAD(0x530, 0x0ec, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D11__KPP_COL_3				IOMUX_PAD(0x530, 0x0ec, 1, 0x95c, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D11__GPIO1_23				IOMUX_PAD(0x530, 0x0ec, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D12__IPU_CSI_D_12				IOMUX_PAD(0x534, 0x0f0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D12__KPP_ROW_0				IOMUX_PAD(0x534, 0x0f0, 1, 0x970, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D12__GPIO1_24				IOMUX_PAD(0x534, 0x0f0, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D13__IPU_CSI_D_13				IOMUX_PAD(0x538, 0x0f4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D13__KPP_ROW_1				IOMUX_PAD(0x538, 0x0f4, 1, 0x974, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D13__GPIO1_25				IOMUX_PAD(0x538, 0x0f4, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D14__IPU_CSI_D_14				IOMUX_PAD(0x53c, 0x0f8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D14__KPP_ROW_2				IOMUX_PAD(0x53c, 0x0f8, 1, 0x978, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D14__GPIO1_26				IOMUX_PAD(0x53c, 0x0f8, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D15__IPU_CSI_D_15				IOMUX_PAD(0x540, 0x0fc, 0, 0x97c, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D15__KPP_ROW_3				IOMUX_PAD(0x540, 0x0fc, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D15__GPIO1_27				IOMUX_PAD(0x540, 0x0fc, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_MCLK__IPU_CSI_MCLK				IOMUX_PAD(0x544, 0x100, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_MCLK__GPIO1_28				IOMUX_PAD(0x544, 0x100, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_VSYNC__IPU_CSI_VSYNC			IOMUX_PAD(0x548, 0x104, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_VSYNC__GPIO1_29				IOMUX_PAD(0x548, 0x104, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_HSYNC__IPU_CSI_HSYNC			IOMUX_PAD(0x54c, 0x108, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_HSYNC__GPIO1_30				IOMUX_PAD(0x54c, 0x108, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_PIXCLK__IPU_CSI_PIXCLK			IOMUX_PAD(0x550, 0x10c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_PIXCLK__GPIO1_31				IOMUX_PAD(0x550, 0x10c, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_I2C1_CLK__I2C1_SCL				IOMUX_PAD(0x554, 0x110, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_I2C1_CLK__GPIO2_24				IOMUX_PAD(0x554, 0x110, 5, 0x8a8, 0, NO_PAD_CTRL)
+#define MX35_PAD_I2C1_CLK__CCM_USB_BYP_CLK			IOMUX_PAD(0x554, 0x110, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_I2C1_DAT__I2C1_SDA				IOMUX_PAD(0x558, 0x114, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_I2C1_DAT__GPIO2_25				IOMUX_PAD(0x558, 0x114, 5, 0x8ac, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_I2C2_CLK__I2C2_SCL				IOMUX_PAD(0x55c, 0x118, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_CLK__CAN1_TXCAN				IOMUX_PAD(0x55c, 0x118, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR			IOMUX_PAD(0x55c, 0x118, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_CLK__GPIO2_26				IOMUX_PAD(0x55c, 0x118, 5, 0x8b0, 0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_CLK__SDMA_DEBUG_BUS_DEVICE_2		IOMUX_PAD(0x55c, 0x118, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_I2C2_DAT__I2C2_SDA				IOMUX_PAD(0x560, 0x11c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_DAT__CAN1_RXCAN				IOMUX_PAD(0x560, 0x11c, 1, 0x7c8, 0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC			IOMUX_PAD(0x560, 0x11c, 2, 0x9f4, 0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_DAT__GPIO2_27				IOMUX_PAD(0x560, 0x11c, 5, 0x8b4, 0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_DAT__SDMA_DEBUG_BUS_DEVICE_3		IOMUX_PAD(0x560, 0x11c, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_STXD4__AUDMUX_AUD4_TXD				IOMUX_PAD(0x564, 0x120, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_STXD4__GPIO2_28				IOMUX_PAD(0x564, 0x120, 5, 0x8b8, 0, NO_PAD_CTRL)
+#define MX35_PAD_STXD4__ARM11P_TOP_ARM_COREASID0		IOMUX_PAD(0x564, 0x120, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SRXD4__AUDMUX_AUD4_RXD				IOMUX_PAD(0x568, 0x124, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SRXD4__GPIO2_29				IOMUX_PAD(0x568, 0x124, 5, 0x8bc, 0, NO_PAD_CTRL)
+#define MX35_PAD_SRXD4__ARM11P_TOP_ARM_COREASID1		IOMUX_PAD(0x568, 0x124, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SCK4__AUDMUX_AUD4_TXC				IOMUX_PAD(0x56c, 0x128, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SCK4__GPIO2_30					IOMUX_PAD(0x56c, 0x128, 5, 0x8c4, 0, NO_PAD_CTRL)
+#define MX35_PAD_SCK4__ARM11P_TOP_ARM_COREASID2			IOMUX_PAD(0x56c, 0x128, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS			IOMUX_PAD(0x570, 0x12c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_STXFS4__GPIO2_31				IOMUX_PAD(0x570, 0x12c, 5, 0x8c8, 0, NO_PAD_CTRL)
+#define MX35_PAD_STXFS4__ARM11P_TOP_ARM_COREASID3		IOMUX_PAD(0x570, 0x12c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_STXD5__AUDMUX_AUD5_TXD				IOMUX_PAD(0x574, 0x130, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_STXD5__SPDIF_SPDIF_OUT1			IOMUX_PAD(0x574, 0x130, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_STXD5__CSPI2_MOSI				IOMUX_PAD(0x574, 0x130, 2, 0x7ec, 0, NO_PAD_CTRL)
+#define MX35_PAD_STXD5__GPIO1_0					IOMUX_PAD(0x574, 0x130, 5, 0x82c, 1, NO_PAD_CTRL)
+#define MX35_PAD_STXD5__ARM11P_TOP_ARM_COREASID4		IOMUX_PAD(0x574, 0x130, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SRXD5__AUDMUX_AUD5_RXD				IOMUX_PAD(0x578, 0x134, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SRXD5__SPDIF_SPDIF_IN1				IOMUX_PAD(0x578, 0x134, 1, 0x998, 0, NO_PAD_CTRL)
+#define MX35_PAD_SRXD5__CSPI2_MISO				IOMUX_PAD(0x578, 0x134, 2, 0x7e8, 0, NO_PAD_CTRL)
+#define MX35_PAD_SRXD5__GPIO1_1					IOMUX_PAD(0x578, 0x134, 5, 0x838, 1, NO_PAD_CTRL)
+#define MX35_PAD_SRXD5__ARM11P_TOP_ARM_COREASID5		IOMUX_PAD(0x578, 0x134, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SCK5__AUDMUX_AUD5_TXC				IOMUX_PAD(0x57c, 0x138, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SCK5__SPDIF_SPDIF_EXTCLK			IOMUX_PAD(0x57c, 0x138, 1, 0x994, 0, NO_PAD_CTRL)
+#define MX35_PAD_SCK5__CSPI2_SCLK				IOMUX_PAD(0x57c, 0x138, 2, 0x7e0, 0, NO_PAD_CTRL)
+#define MX35_PAD_SCK5__GPIO1_2					IOMUX_PAD(0x57c, 0x138, 5, 0x848, 0, NO_PAD_CTRL)
+#define MX35_PAD_SCK5__ARM11P_TOP_ARM_COREASID6			IOMUX_PAD(0x57c, 0x138, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_STXFS5__AUDMUX_AUD5_TXFS			IOMUX_PAD(0x580, 0x13c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_STXFS5__CSPI2_RDY				IOMUX_PAD(0x580, 0x13c, 2, 0x7e4, 0, NO_PAD_CTRL)
+#define MX35_PAD_STXFS5__GPIO1_3				IOMUX_PAD(0x580, 0x13c, 5, 0x84c, 0, NO_PAD_CTRL)
+#define MX35_PAD_STXFS5__ARM11P_TOP_ARM_COREASID7		IOMUX_PAD(0x580, 0x13c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SCKR__ESAI_SCKR				IOMUX_PAD(0x584, 0x140, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SCKR__GPIO1_4					IOMUX_PAD(0x584, 0x140, 5, 0x850, 1, NO_PAD_CTRL)
+#define MX35_PAD_SCKR__ARM11P_TOP_EVNTBUS_10			IOMUX_PAD(0x584, 0x140, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FSR__ESAI_FSR					IOMUX_PAD(0x588, 0x144, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FSR__GPIO1_5					IOMUX_PAD(0x588, 0x144, 5, 0x854, 1, NO_PAD_CTRL)
+#define MX35_PAD_FSR__ARM11P_TOP_EVNTBUS_11			IOMUX_PAD(0x588, 0x144, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_HCKR__ESAI_HCKR				IOMUX_PAD(0x58c, 0x148, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_HCKR__AUDMUX_AUD5_RXFS				IOMUX_PAD(0x58c, 0x148, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_HCKR__CSPI2_SS0				IOMUX_PAD(0x58c, 0x148, 2, 0x7f0, 0, NO_PAD_CTRL)
+#define MX35_PAD_HCKR__IPU_FLASH_STROBE				IOMUX_PAD(0x58c, 0x148, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_HCKR__GPIO1_6					IOMUX_PAD(0x58c, 0x148, 5, 0x858, 1, NO_PAD_CTRL)
+#define MX35_PAD_HCKR__ARM11P_TOP_EVNTBUS_12			IOMUX_PAD(0x58c, 0x148, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SCKT__ESAI_SCKT				IOMUX_PAD(0x590, 0x14c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SCKT__GPIO1_7					IOMUX_PAD(0x590, 0x14c, 5, 0x85c, 1, NO_PAD_CTRL)
+#define MX35_PAD_SCKT__IPU_CSI_D_0				IOMUX_PAD(0x590, 0x14c, 6, 0x930, 0, NO_PAD_CTRL)
+#define MX35_PAD_SCKT__KPP_ROW_2				IOMUX_PAD(0x590, 0x14c, 7, 0x978, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_FST__ESAI_FST					IOMUX_PAD(0x594, 0x150, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FST__GPIO1_8					IOMUX_PAD(0x594, 0x150, 5, 0x860, 1, NO_PAD_CTRL)
+#define MX35_PAD_FST__IPU_CSI_D_1				IOMUX_PAD(0x594, 0x150, 6, 0x934, 0, NO_PAD_CTRL)
+#define MX35_PAD_FST__KPP_ROW_3					IOMUX_PAD(0x594, 0x150, 7, 0x97c, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_HCKT__ESAI_HCKT				IOMUX_PAD(0x598, 0x154, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_HCKT__AUDMUX_AUD5_RXC				IOMUX_PAD(0x598, 0x154, 1, 0x7a8, 0, NO_PAD_CTRL)
+#define MX35_PAD_HCKT__GPIO1_9					IOMUX_PAD(0x598, 0x154, 5, 0x864, 0, NO_PAD_CTRL)
+#define MX35_PAD_HCKT__IPU_CSI_D_2				IOMUX_PAD(0x598, 0x154, 6, 0x938, 0, NO_PAD_CTRL)
+#define MX35_PAD_HCKT__KPP_COL_3				IOMUX_PAD(0x598, 0x154, 7, 0x95c, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_TX5_RX0__ESAI_TX5_RX0				IOMUX_PAD(0x59c, 0x158, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX5_RX0__AUDMUX_AUD4_RXC			IOMUX_PAD(0x59c, 0x158, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX5_RX0__CSPI2_SS2				IOMUX_PAD(0x59c, 0x158, 2, 0x7f8, 1, NO_PAD_CTRL)
+#define MX35_PAD_TX5_RX0__CAN2_TXCAN				IOMUX_PAD(0x59c, 0x158, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX5_RX0__UART2_DTR				IOMUX_PAD(0x59c, 0x158, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX5_RX0__GPIO1_10				IOMUX_PAD(0x59c, 0x158, 5, 0x830, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX5_RX0__EMI_M3IF_CHOSEN_MASTER_0		IOMUX_PAD(0x59c, 0x158, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TX4_RX1__ESAI_TX4_RX1				IOMUX_PAD(0x5a0, 0x15c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX4_RX1__AUDMUX_AUD4_RXFS			IOMUX_PAD(0x5a0, 0x15c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX4_RX1__CSPI2_SS3				IOMUX_PAD(0x5a0, 0x15c, 2, 0x7fc, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX4_RX1__CAN2_RXCAN				IOMUX_PAD(0x5a0, 0x15c, 3, 0x7cc, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX4_RX1__UART2_DSR				IOMUX_PAD(0x5a0, 0x15c, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX4_RX1__GPIO1_11				IOMUX_PAD(0x5a0, 0x15c, 5, 0x834, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX4_RX1__IPU_CSI_D_3				IOMUX_PAD(0x5a0, 0x15c, 6, 0x93c, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX4_RX1__KPP_ROW_0				IOMUX_PAD(0x5a0, 0x15c, 7, 0x970, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_TX3_RX2__ESAI_TX3_RX2				IOMUX_PAD(0x5a4, 0x160, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX3_RX2__I2C3_SCL				IOMUX_PAD(0x5a4, 0x160, 1, 0x91c, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX3_RX2__EMI_NANDF_CE1				IOMUX_PAD(0x5a4, 0x160, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX3_RX2__GPIO1_12				IOMUX_PAD(0x5a4, 0x160, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX3_RX2__IPU_CSI_D_4				IOMUX_PAD(0x5a4, 0x160, 6, 0x940, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX3_RX2__KPP_ROW_1				IOMUX_PAD(0x5a4, 0x160, 7, 0x974, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_TX2_RX3__ESAI_TX2_RX3				IOMUX_PAD(0x5a8, 0x164, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX2_RX3__I2C3_SDA				IOMUX_PAD(0x5a8, 0x164, 1, 0x920, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX2_RX3__EMI_NANDF_CE2				IOMUX_PAD(0x5a8, 0x164, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX2_RX3__GPIO1_13				IOMUX_PAD(0x5a8, 0x164, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX2_RX3__IPU_CSI_D_5				IOMUX_PAD(0x5a8, 0x164, 6, 0x944, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX2_RX3__KPP_COL_0				IOMUX_PAD(0x5a8, 0x164, 7, 0x950, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_TX1__ESAI_TX1					IOMUX_PAD(0x5ac, 0x168, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX1__CCM_PMIC_RDY				IOMUX_PAD(0x5ac, 0x168, 1, 0x7d4, 1, NO_PAD_CTRL)
+#define MX35_PAD_TX1__CSPI1_SS2					IOMUX_PAD(0x5ac, 0x168, 2, 0x7d8, 2, NO_PAD_CTRL)
+#define MX35_PAD_TX1__EMI_NANDF_CE3				IOMUX_PAD(0x5ac, 0x168, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX1__UART2_RI					IOMUX_PAD(0x5ac, 0x168, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX1__GPIO1_14					IOMUX_PAD(0x5ac, 0x168, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX1__IPU_CSI_D_6				IOMUX_PAD(0x5ac, 0x168, 6, 0x948, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX1__KPP_COL_1					IOMUX_PAD(0x5ac, 0x168, 7, 0x954, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_TX0__ESAI_TX0					IOMUX_PAD(0x5b0, 0x16c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX0__SPDIF_SPDIF_EXTCLK			IOMUX_PAD(0x5b0, 0x16c, 1, 0x994, 1, NO_PAD_CTRL)
+#define MX35_PAD_TX0__CSPI1_SS3					IOMUX_PAD(0x5b0, 0x16c, 2, 0x7dc, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX0__EMI_DTACK_B				IOMUX_PAD(0x5b0, 0x16c, 3, 0x800, 1, NO_PAD_CTRL)
+#define MX35_PAD_TX0__UART2_DCD					IOMUX_PAD(0x5b0, 0x16c, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX0__GPIO1_15					IOMUX_PAD(0x5b0, 0x16c, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX0__IPU_CSI_D_7				IOMUX_PAD(0x5b0, 0x16c, 6, 0x94c, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX0__KPP_COL_2					IOMUX_PAD(0x5b0, 0x16c, 7, 0x958, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_CSPI1_MOSI__CSPI1_MOSI				IOMUX_PAD(0x5b4, 0x170, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_MOSI__GPIO1_16				IOMUX_PAD(0x5b4, 0x170, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_MOSI__ECT_CTI_TRIG_OUT1_2		IOMUX_PAD(0x5b4, 0x170, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSPI1_MISO__CSPI1_MISO				IOMUX_PAD(0x5b8, 0x174, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_MISO__GPIO1_17				IOMUX_PAD(0x5b8, 0x174, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_MISO__ECT_CTI_TRIG_OUT1_3		IOMUX_PAD(0x5b8, 0x174, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSPI1_SS0__CSPI1_SS0				IOMUX_PAD(0x5bc, 0x178, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS0__OWIRE_LINE				IOMUX_PAD(0x5bc, 0x178, 1, 0x990, 1, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS0__CSPI2_SS3				IOMUX_PAD(0x5bc, 0x178, 2, 0x7fc, 1, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS0__GPIO1_18				IOMUX_PAD(0x5bc, 0x178, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS0__ECT_CTI_TRIG_OUT1_4			IOMUX_PAD(0x5bc, 0x178, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSPI1_SS1__CSPI1_SS1				IOMUX_PAD(0x5c0, 0x17c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS1__PWM_PWMO				IOMUX_PAD(0x5c0, 0x17c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS1__CCM_CLK32K				IOMUX_PAD(0x5c0, 0x17c, 2, 0x7d0, 1, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS1__GPIO1_19				IOMUX_PAD(0x5c0, 0x17c, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS1__IPU_DIAGB_29			IOMUX_PAD(0x5c0, 0x17c, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS1__ECT_CTI_TRIG_OUT1_5			IOMUX_PAD(0x5c0, 0x17c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSPI1_SCLK__CSPI1_SCLK				IOMUX_PAD(0x5c4, 0x180, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SCLK__GPIO3_4				IOMUX_PAD(0x5c4, 0x180, 5, 0x904, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SCLK__IPU_DIAGB_30			IOMUX_PAD(0x5c4, 0x180, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SCLK__EMI_M3IF_CHOSEN_MASTER_1		IOMUX_PAD(0x5c4, 0x180, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSPI1_SPI_RDY__CSPI1_RDY			IOMUX_PAD(0x5c8, 0x184, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SPI_RDY__GPIO3_5				IOMUX_PAD(0x5c8, 0x184, 5, 0x908, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SPI_RDY__IPU_DIAGB_31			IOMUX_PAD(0x5c8, 0x184, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SPI_RDY__EMI_M3IF_CHOSEN_MASTER_2	IOMUX_PAD(0x5c8, 0x184, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_RXD1__UART1_RXD_MUX				IOMUX_PAD(0x5cc, 0x188, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_RXD1__CSPI2_MOSI				IOMUX_PAD(0x5cc, 0x188, 1, 0x7ec, 1, NO_PAD_CTRL)
+#define MX35_PAD_RXD1__KPP_COL_4				IOMUX_PAD(0x5cc, 0x188, 4, 0x960, 0, NO_PAD_CTRL)
+#define MX35_PAD_RXD1__GPIO3_6					IOMUX_PAD(0x5cc, 0x188, 5, 0x90c, 0, NO_PAD_CTRL)
+#define MX35_PAD_RXD1__ARM11P_TOP_EVNTBUS_16			IOMUX_PAD(0x5cc, 0x188, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TXD1__UART1_TXD_MUX				IOMUX_PAD(0x5d0, 0x18c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TXD1__CSPI2_MISO				IOMUX_PAD(0x5d0, 0x18c, 1, 0x7e8, 1, NO_PAD_CTRL)
+#define MX35_PAD_TXD1__KPP_COL_5				IOMUX_PAD(0x5d0, 0x18c, 4, 0x964, 0, NO_PAD_CTRL)
+#define MX35_PAD_TXD1__GPIO3_7					IOMUX_PAD(0x5d0, 0x18c, 5, 0x910, 0, NO_PAD_CTRL)
+#define MX35_PAD_TXD1__ARM11P_TOP_EVNTBUS_17			IOMUX_PAD(0x5d0, 0x18c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_RTS1__UART1_RTS				IOMUX_PAD(0x5d4, 0x190, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_RTS1__CSPI2_SCLK				IOMUX_PAD(0x5d4, 0x190, 1, 0x7e0, 1, NO_PAD_CTRL)
+#define MX35_PAD_RTS1__I2C3_SCL					IOMUX_PAD(0x5d4, 0x190, 2, 0x91c, 1, NO_PAD_CTRL)
+#define MX35_PAD_RTS1__IPU_CSI_D_0				IOMUX_PAD(0x5d4, 0x190, 3, 0x930, 1, NO_PAD_CTRL)
+#define MX35_PAD_RTS1__KPP_COL_6				IOMUX_PAD(0x5d4, 0x190, 4, 0x968, 0, NO_PAD_CTRL)
+#define MX35_PAD_RTS1__GPIO3_8					IOMUX_PAD(0x5d4, 0x190, 5, 0x914, 0, NO_PAD_CTRL)
+#define MX35_PAD_RTS1__EMI_NANDF_CE1				IOMUX_PAD(0x5d4, 0x190, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_RTS1__ARM11P_TOP_EVNTBUS_18			IOMUX_PAD(0x5d4, 0x190, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CTS1__UART1_CTS				IOMUX_PAD(0x5d8, 0x194, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CTS1__CSPI2_RDY				IOMUX_PAD(0x5d8, 0x194, 1, 0x7e4, 1, NO_PAD_CTRL)
+#define MX35_PAD_CTS1__I2C3_SDA					IOMUX_PAD(0x5d8, 0x194, 2, 0x920, 1, NO_PAD_CTRL)
+#define MX35_PAD_CTS1__IPU_CSI_D_1				IOMUX_PAD(0x5d8, 0x194, 3, 0x934, 1, NO_PAD_CTRL)
+#define MX35_PAD_CTS1__KPP_COL_7				IOMUX_PAD(0x5d8, 0x194, 4, 0x96c, 0, NO_PAD_CTRL)
+#define MX35_PAD_CTS1__GPIO3_9					IOMUX_PAD(0x5d8, 0x194, 5, 0x918, 0, NO_PAD_CTRL)
+#define MX35_PAD_CTS1__EMI_NANDF_CE2				IOMUX_PAD(0x5d8, 0x194, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CTS1__ARM11P_TOP_EVNTBUS_19			IOMUX_PAD(0x5d8, 0x194, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_RXD2__UART2_RXD_MUX				IOMUX_PAD(0x5dc, 0x198, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_RXD2__KPP_ROW_4				IOMUX_PAD(0x5dc, 0x198, 4, 0x980, 0, NO_PAD_CTRL)
+#define MX35_PAD_RXD2__GPIO3_10					IOMUX_PAD(0x5dc, 0x198, 5, 0x8ec, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_TXD2__UART2_TXD_MUX				IOMUX_PAD(0x5e0, 0x19c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TXD2__SPDIF_SPDIF_EXTCLK			IOMUX_PAD(0x5e0, 0x19c, 1, 0x994, 2, NO_PAD_CTRL)
+#define MX35_PAD_TXD2__KPP_ROW_5				IOMUX_PAD(0x5e0, 0x19c, 4, 0x984, 0, NO_PAD_CTRL)
+#define MX35_PAD_TXD2__GPIO3_11					IOMUX_PAD(0x5e0, 0x19c, 5, 0x8f0, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_RTS2__UART2_RTS				IOMUX_PAD(0x5e4, 0x1a0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_RTS2__SPDIF_SPDIF_IN1				IOMUX_PAD(0x5e4, 0x1a0, 1, 0x998, 1, NO_PAD_CTRL)
+#define MX35_PAD_RTS2__CAN2_RXCAN				IOMUX_PAD(0x5e4, 0x1a0, 2, 0x7cc, 1, NO_PAD_CTRL)
+#define MX35_PAD_RTS2__IPU_CSI_D_2				IOMUX_PAD(0x5e4, 0x1a0, 3, 0x938, 1, NO_PAD_CTRL)
+#define MX35_PAD_RTS2__KPP_ROW_6				IOMUX_PAD(0x5e4, 0x1a0, 4, 0x988, 0, NO_PAD_CTRL)
+#define MX35_PAD_RTS2__GPIO3_12					IOMUX_PAD(0x5e4, 0x1a0, 5, 0x8f4, 0, NO_PAD_CTRL)
+#define MX35_PAD_RTS2__AUDMUX_AUD5_RXC				IOMUX_PAD(0x5e4, 0x1a0, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_RTS2__UART3_RXD_MUX				IOMUX_PAD(0x5e4, 0x1a0, 7, 0x9a0, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_CTS2__UART2_CTS				IOMUX_PAD(0x5e8, 0x1a4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CTS2__SPDIF_SPDIF_OUT1				IOMUX_PAD(0x5e8, 0x1a4, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CTS2__CAN2_TXCAN				IOMUX_PAD(0x5e8, 0x1a4, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CTS2__IPU_CSI_D_3				IOMUX_PAD(0x5e8, 0x1a4, 3, 0x93c, 1, NO_PAD_CTRL)
+#define MX35_PAD_CTS2__KPP_ROW_7				IOMUX_PAD(0x5e8, 0x1a4, 4, 0x98c, 0, NO_PAD_CTRL)
+#define MX35_PAD_CTS2__GPIO3_13					IOMUX_PAD(0x5e8, 0x1a4, 5, 0x8f8, 0, NO_PAD_CTRL)
+#define MX35_PAD_CTS2__AUDMUX_AUD5_RXFS				IOMUX_PAD(0x5e8, 0x1a4, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CTS2__UART3_TXD_MUX				IOMUX_PAD(0x5e8, 0x1a4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_RTCK__ARM11P_TOP_RTCK				IOMUX_PAD(0x5ec, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TCK__SJC_TCK					IOMUX_PAD(0x5f0, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TMS__SJC_TMS					IOMUX_PAD(0x5f4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TDI__SJC_TDI					IOMUX_PAD(0x5f8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TDO__SJC_TDO					IOMUX_PAD(0x5fc, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TRSTB__SJC_TRSTB				IOMUX_PAD(0x600, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_DE_B__SJC_DE_B					IOMUX_PAD(0x604, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SJC_MOD__SJC_MOD				IOMUX_PAD(0x608, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_USBOTG_PWR__USB_TOP_USBOTG_PWR			IOMUX_PAD(0x60c, 0x1a8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_USBOTG_PWR__USB_TOP_USBH2_PWR			IOMUX_PAD(0x60c, 0x1a8, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_USBOTG_PWR__GPIO3_14				IOMUX_PAD(0x60c, 0x1a8, 5, 0x8fc, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_USBOTG_OC__USB_TOP_USBOTG_OC			IOMUX_PAD(0x610, 0x1ac, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_USBOTG_OC__USB_TOP_USBH2_OC			IOMUX_PAD(0x610, 0x1ac, 1, 0x9f4, 1, NO_PAD_CTRL)
+#define MX35_PAD_USBOTG_OC__GPIO3_15				IOMUX_PAD(0x610, 0x1ac, 5, 0x900, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD0__IPU_DISPB_DAT_0				IOMUX_PAD(0x614, 0x1b0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD0__GPIO2_0					IOMUX_PAD(0x614, 0x1b0, 5, 0x868, 1, NO_PAD_CTRL)
+#define MX35_PAD_LD0__SDMA_SDMA_DEBUG_PC_0			IOMUX_PAD(0x614, 0x1b0, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD1__IPU_DISPB_DAT_1				IOMUX_PAD(0x618, 0x1b4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD1__GPIO2_1					IOMUX_PAD(0x618, 0x1b4, 5, 0x894, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD1__SDMA_SDMA_DEBUG_PC_1			IOMUX_PAD(0x618, 0x1b4, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD2__IPU_DISPB_DAT_2				IOMUX_PAD(0x61c, 0x1b8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD2__GPIO2_2					IOMUX_PAD(0x61c, 0x1b8, 5, 0x8c0, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD2__SDMA_SDMA_DEBUG_PC_2			IOMUX_PAD(0x61c, 0x1b8, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD3__IPU_DISPB_DAT_3				IOMUX_PAD(0x620, 0x1bc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD3__GPIO2_3					IOMUX_PAD(0x620, 0x1bc, 5, 0x8cc, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD3__SDMA_SDMA_DEBUG_PC_3			IOMUX_PAD(0x620, 0x1bc, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD4__IPU_DISPB_DAT_4				IOMUX_PAD(0x624, 0x1c0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD4__GPIO2_4					IOMUX_PAD(0x624, 0x1c0, 5, 0x8d0, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD4__SDMA_SDMA_DEBUG_PC_4			IOMUX_PAD(0x624, 0x1c0, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD5__IPU_DISPB_DAT_5				IOMUX_PAD(0x628, 0x1c4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD5__GPIO2_5					IOMUX_PAD(0x628, 0x1c4, 5, 0x8d4, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD5__SDMA_SDMA_DEBUG_PC_5			IOMUX_PAD(0x628, 0x1c4, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD6__IPU_DISPB_DAT_6				IOMUX_PAD(0x62c, 0x1c8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD6__GPIO2_6					IOMUX_PAD(0x62c, 0x1c8, 5, 0x8d8, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD6__SDMA_SDMA_DEBUG_PC_6			IOMUX_PAD(0x62c, 0x1c8, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD7__IPU_DISPB_DAT_7				IOMUX_PAD(0x630, 0x1cc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD7__GPIO2_7					IOMUX_PAD(0x630, 0x1cc, 5, 0x8dc, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD7__SDMA_SDMA_DEBUG_PC_7			IOMUX_PAD(0x630, 0x1cc, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD8__IPU_DISPB_DAT_8				IOMUX_PAD(0x634, 0x1d0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD8__GPIO2_8					IOMUX_PAD(0x634, 0x1d0, 5, 0x8e0, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD8__SDMA_SDMA_DEBUG_PC_8			IOMUX_PAD(0x634, 0x1d0, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD9__IPU_DISPB_DAT_9				IOMUX_PAD(0x638, 0x1d4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD9__GPIO2_9					IOMUX_PAD(0x638, 0x1d4, 5, 0x8e4  0, NO_PAD_CTRL)
+#define MX35_PAD_LD9__SDMA_SDMA_DEBUG_PC_9			IOMUX_PAD(0x638, 0x1d4, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD10__IPU_DISPB_DAT_10				IOMUX_PAD(0x63c, 0x1d8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD10__GPIO2_10					IOMUX_PAD(0x63c, 0x1d8, 5, 0x86c, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD10__SDMA_SDMA_DEBUG_PC_10			IOMUX_PAD(0x63c, 0x1d8, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD11__IPU_DISPB_DAT_11				IOMUX_PAD(0x640, 0x1dc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD11__GPIO2_11					IOMUX_PAD(0x640, 0x1dc, 5, 0x870, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD11__SDMA_SDMA_DEBUG_PC_11			IOMUX_PAD(0x640, 0x1dc, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD11__ARM11P_TOP_TRACE_4			IOMUX_PAD(0x640, 0x1dc, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD12__IPU_DISPB_DAT_12				IOMUX_PAD(0x644, 0x1e0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD12__GPIO2_12					IOMUX_PAD(0x644, 0x1e0, 5, 0x874, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD12__SDMA_SDMA_DEBUG_PC_12			IOMUX_PAD(0x644, 0x1e0, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD12__ARM11P_TOP_TRACE_5			IOMUX_PAD(0x644, 0x1e0, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD13__IPU_DISPB_DAT_13				IOMUX_PAD(0x648, 0x1e4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD13__GPIO2_13					IOMUX_PAD(0x648, 0x1e4, 5, 0x878, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD13__SDMA_SDMA_DEBUG_PC_13			IOMUX_PAD(0x648, 0x1e4, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD13__ARM11P_TOP_TRACE_6			IOMUX_PAD(0x648, 0x1e4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD14__IPU_DISPB_DAT_14				IOMUX_PAD(0x64c, 0x1e8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD14__GPIO2_14					IOMUX_PAD(0x64c, 0x1e8, 5, 0x87c, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD14__SDMA_SDMA_DEBUG_EVENT_CHANNEL_0		IOMUX_PAD(0x64c, 0x1e8, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD14__ARM11P_TOP_TRACE_7			IOMUX_PAD(0x64c, 0x1e8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD15__IPU_DISPB_DAT_15				IOMUX_PAD(0x650, 0x1ec, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD15__GPIO2_15					IOMUX_PAD(0x650, 0x1ec, 5, 0x880, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD15__SDMA_SDMA_DEBUG_EVENT_CHANNEL_1		IOMUX_PAD(0x650, 0x1ec, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD15__ARM11P_TOP_TRACE_8			IOMUX_PAD(0x650, 0x1ec, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD16__IPU_DISPB_DAT_16				IOMUX_PAD(0x654, 0x1f0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD16__IPU_DISPB_D12_VSYNC			IOMUX_PAD(0x654, 0x1f0, 2, 0x928, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD16__GPIO2_16					IOMUX_PAD(0x654, 0x1f0, 5, 0x884, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD16__SDMA_SDMA_DEBUG_EVENT_CHANNEL_2		IOMUX_PAD(0x654, 0x1f0, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD16__ARM11P_TOP_TRACE_9			IOMUX_PAD(0x654, 0x1f0, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD17__IPU_DISPB_DAT_17				IOMUX_PAD(0x658, 0x1f4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD17__IPU_DISPB_CS2				IOMUX_PAD(0x658, 0x1f4, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD17__GPIO2_17					IOMUX_PAD(0x658, 0x1f4, 5, 0x888, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD17__SDMA_SDMA_DEBUG_EVENT_CHANNEL_3		IOMUX_PAD(0x658, 0x1f4, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD17__ARM11P_TOP_TRACE_10			IOMUX_PAD(0x658, 0x1f4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD18__IPU_DISPB_DAT_18				IOMUX_PAD(0x65c, 0x1f8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD18__IPU_DISPB_D0_VSYNC			IOMUX_PAD(0x65c, 0x1f8, 1, 0x924, 1, NO_PAD_CTRL)
+#define MX35_PAD_LD18__IPU_DISPB_D12_VSYNC			IOMUX_PAD(0x65c, 0x1f8, 2, 0x928, 1, NO_PAD_CTRL)
+#define MX35_PAD_LD18__ESDHC3_CMD				IOMUX_PAD(0x65c, 0x1f8, 3, 0x818, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD18__USB_TOP_USBOTG_DATA_3			IOMUX_PAD(0x65c, 0x1f8, 4, 0x9b0, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD18__GPIO3_24					IOMUX_PAD(0x65c, 0x1f8, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD18__SDMA_SDMA_DEBUG_EVENT_CHANNEL_4		IOMUX_PAD(0x65c, 0x1f8, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD18__ARM11P_TOP_TRACE_11			IOMUX_PAD(0x65c, 0x1f8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD19__IPU_DISPB_DAT_19				IOMUX_PAD(0x660, 0x1fc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD19__IPU_DISPB_BCLK				IOMUX_PAD(0x660, 0x1fc, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD19__IPU_DISPB_CS1				IOMUX_PAD(0x660, 0x1fc, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD19__ESDHC3_CLK				IOMUX_PAD(0x660, 0x1fc, 3, 0x814, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD19__USB_TOP_USBOTG_DIR			IOMUX_PAD(0x660, 0x1fc, 4, 0x9c4, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD19__GPIO3_25					IOMUX_PAD(0x660, 0x1fc, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD19__SDMA_SDMA_DEBUG_EVENT_CHANNEL_5		IOMUX_PAD(0x660, 0x1fc, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD19__ARM11P_TOP_TRACE_12			IOMUX_PAD(0x660, 0x1fc, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD20__IPU_DISPB_DAT_20				IOMUX_PAD(0x664, 0x200, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD20__IPU_DISPB_CS0				IOMUX_PAD(0x664, 0x200, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD20__IPU_DISPB_SD_CLK				IOMUX_PAD(0x664, 0x200, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD20__ESDHC3_DAT0				IOMUX_PAD(0x664, 0x200, 3, 0x81c, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD20__GPIO3_26					IOMUX_PAD(0x664, 0x200, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD20__SDMA_SDMA_DEBUG_CORE_STATUS_3		IOMUX_PAD(0x664, 0x200, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD20__ARM11P_TOP_TRACE_13			IOMUX_PAD(0x664, 0x200, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD21__IPU_DISPB_DAT_21				IOMUX_PAD(0x668, 0x204, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD21__IPU_DISPB_PAR_RS				IOMUX_PAD(0x668, 0x204, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD21__IPU_DISPB_SER_RS				IOMUX_PAD(0x668, 0x204, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD21__ESDHC3_DAT1				IOMUX_PAD(0x668, 0x204, 3, 0x820, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD21__USB_TOP_USBOTG_STP			IOMUX_PAD(0x668, 0x204, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD21__GPIO3_27					IOMUX_PAD(0x668, 0x204, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD21__SDMA_DEBUG_EVENT_CHANNEL_SEL		IOMUX_PAD(0x668, 0x204, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD21__ARM11P_TOP_TRACE_14			IOMUX_PAD(0x668, 0x204, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD22__IPU_DISPB_DAT_22				IOMUX_PAD(0x66c, 0x208, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD22__IPU_DISPB_WR				IOMUX_PAD(0x66c, 0x208, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD22__IPU_DISPB_SD_D_I				IOMUX_PAD(0x66c, 0x208, 2, 0x92c, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD22__ESDHC3_DAT2				IOMUX_PAD(0x66c, 0x208, 3, 0x824, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD22__USB_TOP_USBOTG_NXT			IOMUX_PAD(0x66c, 0x208, 4, 0x9c8, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD22__GPIO3_28					IOMUX_PAD(0x66c, 0x208, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD22__SDMA_DEBUG_BUS_ERROR			IOMUX_PAD(0x66c, 0x208, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD22__ARM11P_TOP_TRCTL				IOMUX_PAD(0x66c, 0x208, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD23__IPU_DISPB_DAT_23				IOMUX_PAD(0x670, 0x20c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD23__IPU_DISPB_RD				IOMUX_PAD(0x670, 0x20c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD23__IPU_DISPB_SD_D_IO			IOMUX_PAD(0x670, 0x20c, 2, 0x92c, 1, NO_PAD_CTRL)
+#define MX35_PAD_LD23__ESDHC3_DAT3				IOMUX_PAD(0x670, 0x20c, 3, 0x828, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD23__USB_TOP_USBOTG_DATA_7			IOMUX_PAD(0x670, 0x20c, 4, 0x9c0, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD23__GPIO3_29					IOMUX_PAD(0x670, 0x20c, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD23__SDMA_DEBUG_MATCHED_DMBUS			IOMUX_PAD(0x670, 0x20c, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD23__ARM11P_TOP_TRCLK				IOMUX_PAD(0x670, 0x20c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC			IOMUX_PAD(0x674, 0x210, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_HSYNC__IPU_DISPB_SD_D_IO			IOMUX_PAD(0x674, 0x210, 2, 0x92c, 2, NO_PAD_CTRL)
+#define MX35_PAD_D3_HSYNC__GPIO3_30				IOMUX_PAD(0x674, 0x210, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_HSYNC__SDMA_DEBUG_RTBUFFER_WRITE		IOMUX_PAD(0x674, 0x210, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_HSYNC__ARM11P_TOP_TRACE_15			IOMUX_PAD(0x674, 0x210, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK			IOMUX_PAD(0x678, 0x214, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_FPSHIFT__IPU_DISPB_SD_CLK			IOMUX_PAD(0x678, 0x214, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_FPSHIFT__GPIO3_31				IOMUX_PAD(0x678, 0x214, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_FPSHIFT__SDMA_SDMA_DEBUG_CORE_STATUS_0	IOMUX_PAD(0x678, 0x214, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_FPSHIFT__ARM11P_TOP_TRACE_16		IOMUX_PAD(0x678, 0x214, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY			IOMUX_PAD(0x67c, 0x218, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_DRDY__IPU_DISPB_SD_D_O			IOMUX_PAD(0x67c, 0x218, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_DRDY__GPIO1_0				IOMUX_PAD(0x67c, 0x218, 5, 0x82c, 2, NO_PAD_CTRL)
+#define MX35_PAD_D3_DRDY__SDMA_SDMA_DEBUG_CORE_STATUS_1		IOMUX_PAD(0x67c, 0x218, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_DRDY__ARM11P_TOP_TRACE_17			IOMUX_PAD(0x67c, 0x218, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CONTRAST__IPU_DISPB_CONTR			IOMUX_PAD(0x680, 0x21c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CONTRAST__GPIO1_1				IOMUX_PAD(0x680, 0x21c, 5, 0x838, 2, NO_PAD_CTRL)
+#define MX35_PAD_CONTRAST__SDMA_SDMA_DEBUG_CORE_STATUS_2	IOMUX_PAD(0x680, 0x21c, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CONTRAST__ARM11P_TOP_TRACE_18			IOMUX_PAD(0x680, 0x21c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC			IOMUX_PAD(0x684, 0x220, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_VSYNC__IPU_DISPB_CS1			IOMUX_PAD(0x684, 0x220, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_VSYNC__GPIO1_2				IOMUX_PAD(0x684, 0x220, 5, 0x848, 1, NO_PAD_CTRL)
+#define MX35_PAD_D3_VSYNC__SDMA_DEBUG_YIELD			IOMUX_PAD(0x684, 0x220, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_VSYNC__ARM11P_TOP_TRACE_19			IOMUX_PAD(0x684, 0x220, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3_REV__IPU_DISPB_D3_REV			IOMUX_PAD(0x688, 0x224, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_REV__IPU_DISPB_SER_RS			IOMUX_PAD(0x688, 0x224, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_REV__GPIO1_3				IOMUX_PAD(0x688, 0x224, 5, 0x84c, 1, NO_PAD_CTRL)
+#define MX35_PAD_D3_REV__SDMA_DEBUG_BUS_RWB			IOMUX_PAD(0x688, 0x224, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_REV__ARM11P_TOP_TRACE_20			IOMUX_PAD(0x688, 0x224, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS			IOMUX_PAD(0x68c, 0x228, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_CLS__IPU_DISPB_CS2				IOMUX_PAD(0x68c, 0x228, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_CLS__GPIO1_4				IOMUX_PAD(0x68c, 0x228, 5, 0x850, 2, NO_PAD_CTRL)
+#define MX35_PAD_D3_CLS__SDMA_DEBUG_BUS_DEVICE_0		IOMUX_PAD(0x68c, 0x228, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_CLS__ARM11P_TOP_TRACE_21			IOMUX_PAD(0x68c, 0x228, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3_SPL__IPU_DISPB_D3_SPL			IOMUX_PAD(0x690, 0x22c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_SPL__IPU_DISPB_D12_VSYNC			IOMUX_PAD(0x690, 0x22c, 2, 0x928, 2, NO_PAD_CTRL)
+#define MX35_PAD_D3_SPL__GPIO1_5				IOMUX_PAD(0x690, 0x22c, 5, 0x854, 2, NO_PAD_CTRL)
+#define MX35_PAD_D3_SPL__SDMA_DEBUG_BUS_DEVICE_1		IOMUX_PAD(0x690, 0x22c, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_SPL__ARM11P_TOP_TRACE_22			IOMUX_PAD(0x690, 0x22c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD1_CMD__ESDHC1_CMD				IOMUX_PAD(0x694, 0x230, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CMD__MSHC_SCLK				IOMUX_PAD(0x694, 0x230, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CMD__IPU_DISPB_D0_VSYNC			IOMUX_PAD(0x694, 0x230, 3, 0x924, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CMD__USB_TOP_USBOTG_DATA_4			IOMUX_PAD(0x694, 0x230, 4, 0x9b4, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CMD__GPIO1_6				IOMUX_PAD(0x694, 0x230, 5, 0x858, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CMD__ARM11P_TOP_TRCTL			IOMUX_PAD(0x694, 0x230, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD1_CLK__ESDHC1_CLK				IOMUX_PAD(0x698, 0x234, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CLK__MSHC_BS				IOMUX_PAD(0x698, 0x234, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CLK__IPU_DISPB_BCLK			IOMUX_PAD(0x698, 0x234, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CLK__USB_TOP_USBOTG_DATA_5			IOMUX_PAD(0x698, 0x234, 4, 0x9b8, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CLK__GPIO1_7				IOMUX_PAD(0x698, 0x234, 5, 0x85c, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CLK__ARM11P_TOP_TRCLK			IOMUX_PAD(0x698, 0x234, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD1_DATA0__ESDHC1_DAT0				IOMUX_PAD(0x69c, 0x238, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA0__MSHC_DATA_0				IOMUX_PAD(0x69c, 0x238, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA0__IPU_DISPB_CS0			IOMUX_PAD(0x69c, 0x238, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA0__USB_TOP_USBOTG_DATA_6		IOMUX_PAD(0x69c, 0x238, 4, 0x9bc, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA0__GPIO1_8				IOMUX_PAD(0x69c, 0x238, 5, 0x860, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA0__ARM11P_TOP_TRACE_23			IOMUX_PAD(0x69c, 0x238, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD1_DATA1__ESDHC1_DAT1				IOMUX_PAD(0x6a0, 0x23c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA1__MSHC_DATA_1				IOMUX_PAD(0x6a0, 0x23c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA1__IPU_DISPB_PAR_RS			IOMUX_PAD(0x6a0, 0x23c, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA1__USB_TOP_USBOTG_DATA_0		IOMUX_PAD(0x6a0, 0x23c, 4, 0x9a4, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA1__GPIO1_9				IOMUX_PAD(0x6a0, 0x23c, 5, 0x864, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA1__ARM11P_TOP_TRACE_24			IOMUX_PAD(0x6a0, 0x23c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD1_DATA2__ESDHC1_DAT2				IOMUX_PAD(0x6a4, 0x240, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA2__MSHC_DATA_2				IOMUX_PAD(0x6a4, 0x240, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA2__IPU_DISPB_WR			IOMUX_PAD(0x6a4, 0x240, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA2__USB_TOP_USBOTG_DATA_1		IOMUX_PAD(0x6a4, 0x240, 4, 0x9a8, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA2__GPIO1_10				IOMUX_PAD(0x6a4, 0x240, 5, 0x830, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA2__ARM11P_TOP_TRACE_25			IOMUX_PAD(0x6a4, 0x240, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD1_DATA3__ESDHC1_DAT3				IOMUX_PAD(0x6a8, 0x244, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA3__MSHC_DATA_3				IOMUX_PAD(0x6a8, 0x244, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA3__IPU_DISPB_RD			IOMUX_PAD(0x6a8, 0x244, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA3__USB_TOP_USBOTG_DATA_2		IOMUX_PAD(0x6a8, 0x244, 4, 0x9ac, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA3__GPIO1_11				IOMUX_PAD(0x6a8, 0x244, 5, 0x834, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA3__ARM11P_TOP_TRACE_26			IOMUX_PAD(0x6a8, 0x244, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD2_CMD__ESDHC2_CMD				IOMUX_PAD(0x6ac, 0x248, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CMD__I2C3_SCL				IOMUX_PAD(0x6ac, 0x248, 1, 0x91c, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CMD__ESDHC1_DAT4				IOMUX_PAD(0x6ac, 0x248, 2, 0x804, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CMD__IPU_CSI_D_2				IOMUX_PAD(0x6ac, 0x248, 3, 0x938, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CMD__USB_TOP_USBH2_DATA_4			IOMUX_PAD(0x6ac, 0x248, 4, 0x9dc, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CMD__GPIO2_0				IOMUX_PAD(0x6ac, 0x248, 5, 0x868, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CMD__SPDIF_SPDIF_OUT1			IOMUX_PAD(0x6ac, 0x248, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CMD__IPU_DISPB_D12_VSYNC			IOMUX_PAD(0x6ac, 0x248, 7, 0x928, 3, NO_PAD_CTRL)
+
+#define MX35_PAD_SD2_CLK__ESDHC2_CLK				IOMUX_PAD(0x6b0, 0x24c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CLK__I2C3_SDA				IOMUX_PAD(0x6b0, 0x24c, 1, 0x920, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CLK__ESDHC1_DAT5				IOMUX_PAD(0x6b0, 0x24c, 2, 0x808, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CLK__IPU_CSI_D_3				IOMUX_PAD(0x6b0, 0x24c, 3, 0x93c, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CLK__USB_TOP_USBH2_DATA_5			IOMUX_PAD(0x6b0, 0x24c, 4, 0x9e0, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CLK__GPIO2_1				IOMUX_PAD(0x6b0, 0x24c, 5, 0x894, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CLK__SPDIF_SPDIF_IN1			IOMUX_PAD(0x6b0, 0x24c, 6, 0x998, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CLK__IPU_DISPB_CS2				IOMUX_PAD(0x6b0, 0x24c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD2_DATA0__ESDHC2_DAT0				IOMUX_PAD(0x6b4, 0x250, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA0__UART3_RXD_MUX			IOMUX_PAD(0x6b4, 0x250, 1, 0x9a0, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA0__ESDHC1_DAT6				IOMUX_PAD(0x6b4, 0x250, 2, 0x80c, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA0__IPU_CSI_D_4				IOMUX_PAD(0x6b4, 0x250, 3, 0x940, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA0__USB_TOP_USBH2_DATA_6		IOMUX_PAD(0x6b4, 0x250, 4, 0x9e4, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA0__GPIO2_2				IOMUX_PAD(0x6b4, 0x250, 5, 0x8c0, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA0__SPDIF_SPDIF_EXTCLK			IOMUX_PAD(0x6b4, 0x250, 6, 0x994, 3, NO_PAD_CTRL)
+
+#define MX35_PAD_SD2_DATA1__ESDHC2_DAT1				IOMUX_PAD(0x6b8, 0x254, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA1__UART3_TXD_MUX			IOMUX_PAD(0x6b8, 0x254, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA1__ESDHC1_DAT7				IOMUX_PAD(0x6b8, 0x254, 2, 0x810, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA1__IPU_CSI_D_5				IOMUX_PAD(0x6b8, 0x254, 3, 0x944, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA1__USB_TOP_USBH2_DATA_0		IOMUX_PAD(0x6b8, 0x254, 4, 0x9cc, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA1__GPIO2_3				IOMUX_PAD(0x6b8, 0x254, 5, 0x8cc, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_SD2_DATA2__ESDHC2_DAT2				IOMUX_PAD(0x6bc, 0x258, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA2__UART3_RTS				IOMUX_PAD(0x6bc, 0x258, 1, 0x99c, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA2__CAN1_RXCAN				IOMUX_PAD(0x6bc, 0x258, 2, 0x7c8, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA2__IPU_CSI_D_6				IOMUX_PAD(0x6bc, 0x258, 3, 0x948, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA2__USB_TOP_USBH2_DATA_1		IOMUX_PAD(0x6bc, 0x258, 4, 0x9d0, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA2__GPIO2_4				IOMUX_PAD(0x6bc, 0x258, 5, 0x8d0, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_SD2_DATA3__ESDHC2_DAT3				IOMUX_PAD(0x6c0, 0x25c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA3__UART3_CTS				IOMUX_PAD(0x6c0, 0x25c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA3__CAN1_TXCAN				IOMUX_PAD(0x6c0, 0x25c, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA3__IPU_CSI_D_7				IOMUX_PAD(0x6c0, 0x25c, 3, 0x94c, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA3__USB_TOP_USBH2_DATA_2		IOMUX_PAD(0x6c0, 0x25c, 4, 0x9d4, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA3__GPIO2_5				IOMUX_PAD(0x6c0, 0x25c, 5, 0x8d4, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_CS0__ATA_CS0				IOMUX_PAD(0x6c4, 0x260, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS0__CSPI1_SS3				IOMUX_PAD(0x6c4, 0x260, 1, 0x7dc, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS0__IPU_DISPB_CS1				IOMUX_PAD(0x6c4, 0x260, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS0__GPIO2_6				IOMUX_PAD(0x6c4, 0x260, 5, 0x8d8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS0__IPU_DIAGB_0				IOMUX_PAD(0x6c4, 0x260, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS0__ARM11P_TOP_MAX1_HMASTER_0		IOMUX_PAD(0x6c4, 0x260, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_CS1__ATA_CS1				IOMUX_PAD(0x6c8, 0x264, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS1__IPU_DISPB_CS2				IOMUX_PAD(0x6c8, 0x264, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS1__CSPI2_SS0				IOMUX_PAD(0x6c8, 0x264, 4, 0x7f0, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS1__GPIO2_7				IOMUX_PAD(0x6c8, 0x264, 5, 0x8dc, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS1__IPU_DIAGB_1				IOMUX_PAD(0x6c8, 0x264, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS1__ARM11P_TOP_MAX1_HMASTER_1		IOMUX_PAD(0x6c8, 0x264, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DIOR__ATA_DIOR				IOMUX_PAD(0x6cc, 0x268, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOR__ESDHC3_DAT0				IOMUX_PAD(0x6cc, 0x268, 1, 0x81c, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOR__USB_TOP_USBOTG_DIR			IOMUX_PAD(0x6cc, 0x268, 2, 0x9c4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOR__IPU_DISPB_BE0			IOMUX_PAD(0x6cc, 0x268, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOR__CSPI2_SS1				IOMUX_PAD(0x6cc, 0x268, 4, 0x7f4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOR__GPIO2_8				IOMUX_PAD(0x6cc, 0x268, 5, 0x8e0, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOR__IPU_DIAGB_2				IOMUX_PAD(0x6cc, 0x268, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOR__ARM11P_TOP_MAX1_HMASTER_2		IOMUX_PAD(0x6cc, 0x268, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DIOW__ATA_DIOW				IOMUX_PAD(0x6d0, 0x26c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOW__ESDHC3_DAT1				IOMUX_PAD(0x6d0, 0x26c, 1, 0x820, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOW__USB_TOP_USBOTG_STP			IOMUX_PAD(0x6d0, 0x26c, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOW__IPU_DISPB_BE1			IOMUX_PAD(0x6d0, 0x26c, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOW__CSPI2_MOSI				IOMUX_PAD(0x6d0, 0x26c, 4, 0x7ec, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOW__GPIO2_9				IOMUX_PAD(0x6d0, 0x26c, 5, 0x8e4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOW__IPU_DIAGB_3				IOMUX_PAD(0x6d0, 0x26c, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOW__ARM11P_TOP_MAX1_HMASTER_3		IOMUX_PAD(0x6d0, 0x26c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DMACK__ATA_DMACK				IOMUX_PAD(0x6d4, 0x270, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMACK__ESDHC3_DAT2				IOMUX_PAD(0x6d4, 0x270, 1, 0x824, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMACK__USB_TOP_USBOTG_NXT			IOMUX_PAD(0x6d4, 0x270, 2, 0x9c8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMACK__CSPI2_MISO				IOMUX_PAD(0x6d4, 0x270, 4, 0x7e8, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMACK__GPIO2_10				IOMUX_PAD(0x6d4, 0x270, 5, 0x86c, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMACK__IPU_DIAGB_4				IOMUX_PAD(0x6d4, 0x270, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMACK__ARM11P_TOP_MAX0_HMASTER_0		IOMUX_PAD(0x6d4, 0x270, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_RESET_B__ATA_RESET_B			IOMUX_PAD(0x6d8, 0x274, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_RESET_B__ESDHC3_DAT3			IOMUX_PAD(0x6d8, 0x274, 1, 0x828, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_RESET_B__USB_TOP_USBOTG_DATA_0		IOMUX_PAD(0x6d8, 0x274, 2, 0x9a4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_RESET_B__IPU_DISPB_SD_D_O			IOMUX_PAD(0x6d8, 0x274, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_RESET_B__CSPI2_RDY				IOMUX_PAD(0x6d8, 0x274, 4, 0x7e4, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_RESET_B__GPIO2_11				IOMUX_PAD(0x6d8, 0x274, 5, 0x870, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_RESET_B__IPU_DIAGB_5			IOMUX_PAD(0x6d8, 0x274, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_RESET_B__ARM11P_TOP_MAX0_HMASTER_1		IOMUX_PAD(0x6d8, 0x274, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_IORDY__ATA_IORDY				IOMUX_PAD(0x6dc, 0x278, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_IORDY__ESDHC3_DAT4				IOMUX_PAD(0x6dc, 0x278, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_IORDY__USB_TOP_USBOTG_DATA_1		IOMUX_PAD(0x6dc, 0x278, 2, 0x9a8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_IORDY__IPU_DISPB_SD_D_IO			IOMUX_PAD(0x6dc, 0x278, 3, 0x92c, 3, NO_PAD_CTRL)
+#define MX35_PAD_ATA_IORDY__ESDHC2_DAT4				IOMUX_PAD(0x6dc, 0x278, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_IORDY__GPIO2_12				IOMUX_PAD(0x6dc, 0x278, 5, 0x874, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_IORDY__IPU_DIAGB_6				IOMUX_PAD(0x6dc, 0x278, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_IORDY__ARM11P_TOP_MAX0_HMASTER_2		IOMUX_PAD(0x6dc, 0x278, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA0__ATA_DATA_0				IOMUX_PAD(0x6e0, 0x27c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA0__ESDHC3_DAT5				IOMUX_PAD(0x6e0, 0x27c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA0__USB_TOP_USBOTG_DATA_2		IOMUX_PAD(0x6e0, 0x27c, 2, 0x9ac, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA0__IPU_DISPB_D12_VSYNC			IOMUX_PAD(0x6e0, 0x27c, 3, 0x928, 4, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA0__ESDHC2_DAT5				IOMUX_PAD(0x6e0, 0x27c, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA0__GPIO2_13				IOMUX_PAD(0x6e0, 0x27c, 5, 0x878, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA0__IPU_DIAGB_7				IOMUX_PAD(0x6e0, 0x27c, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA0__ARM11P_TOP_MAX0_HMASTER_3		IOMUX_PAD(0x6e0, 0x27c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA1__ATA_DATA_1				IOMUX_PAD(0x6e4, 0x280, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA1__ESDHC3_DAT6				IOMUX_PAD(0x6e4, 0x280, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA1__USB_TOP_USBOTG_DATA_3		IOMUX_PAD(0x6e4, 0x280, 2, 0x9b0, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA1__IPU_DISPB_SD_CLK			IOMUX_PAD(0x6e4, 0x280, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA1__ESDHC2_DAT6				IOMUX_PAD(0x6e4, 0x280, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA1__GPIO2_14				IOMUX_PAD(0x6e4, 0x280, 5, 0x87c, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA1__IPU_DIAGB_8				IOMUX_PAD(0x6e4, 0x280, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA1__ARM11P_TOP_TRACE_27			IOMUX_PAD(0x6e4, 0x280, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA2__ATA_DATA_2				IOMUX_PAD(0x6e8, 0x284, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA2__ESDHC3_DAT7				IOMUX_PAD(0x6e8, 0x284, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA2__USB_TOP_USBOTG_DATA_4		IOMUX_PAD(0x6e8, 0x284, 2, 0x9b4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA2__IPU_DISPB_SER_RS			IOMUX_PAD(0x6e8, 0x284, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA2__ESDHC2_DAT7				IOMUX_PAD(0x6e8, 0x284, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA2__GPIO2_15				IOMUX_PAD(0x6e8, 0x284, 5, 0x880, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA2__IPU_DIAGB_9				IOMUX_PAD(0x6e8, 0x284, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA2__ARM11P_TOP_TRACE_28			IOMUX_PAD(0x6e8, 0x284, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA3__ATA_DATA_3				IOMUX_PAD(0x6e8, 0x288, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__ESDHC3_CLK				IOMUX_PAD(0x6e8, 0x288, 1, 0x814, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__USB_TOP_USBOTG_DATA_5		IOMUX_PAD(0x6e8, 0x288, 2, 0x9b8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__CSPI2_SCLK				IOMUX_PAD(0x6e8, 0x288, 4, 0x7e0, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__GPIO2_16				IOMUX_PAD(0x6e8, 0x288, 5, 0x884, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__IPU_DIAGB_10			IOMUX_PAD(0x6e8, 0x288, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__ARM11P_TOP_TRACE_29			IOMUX_PAD(0x6e8, 0x288, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA4__ATA_DATA_4				IOMUX_PAD(0x6f0, 0x28c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA4__ESDHC3_CMD				IOMUX_PAD(0x6f0, 0x28c, 1, 0x818, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA4__USB_TOP_USBOTG_DATA_6		IOMUX_PAD(0x6f0, 0x28c, 2, 0x9bc, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA4__GPIO2_17				IOMUX_PAD(0x6f0, 0x28c, 5, 0x888, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA4__IPU_DIAGB_11			IOMUX_PAD(0x6f0, 0x28c, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA4__ARM11P_TOP_TRACE_30			IOMUX_PAD(0x6f0, 0x28c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA5__ATA_DATA_5				IOMUX_PAD(0x6f4, 0x290, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA5__USB_TOP_USBOTG_DATA_7		IOMUX_PAD(0x6f4, 0x290, 2, 0x9c0, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA5__GPIO2_18				IOMUX_PAD(0x6f4, 0x290, 5, 0x88c, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA5__IPU_DIAGB_12			IOMUX_PAD(0x6f4, 0x290, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA5__ARM11P_TOP_TRACE_31			IOMUX_PAD(0x6f4, 0x290, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA6__ATA_DATA_6				IOMUX_PAD(0x6f8, 0x294, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA6__CAN1_TXCAN				IOMUX_PAD(0x6f8, 0x294, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA6__UART1_DTR				IOMUX_PAD(0x6f8, 0x294, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA6__AUDMUX_AUD6_TXD			IOMUX_PAD(0x6f8, 0x294, 3, 0x7b4, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA6__GPIO2_19				IOMUX_PAD(0x6f8, 0x294, 5, 0x890, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA6__IPU_DIAGB_13			IOMUX_PAD(0x6f8, 0x294, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA7__ATA_DATA_7				IOMUX_PAD(0x6fc, 0x298, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA7__CAN1_RXCAN				IOMUX_PAD(0x6fc, 0x298, 1, 0x7c8, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA7__UART1_DSR				IOMUX_PAD(0x6fc, 0x298, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA7__AUDMUX_AUD6_RXD			IOMUX_PAD(0x6fc, 0x298, 3, 0x7b0, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA7__GPIO2_20				IOMUX_PAD(0x6fc, 0x298, 5, 0x898, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA7__IPU_DIAGB_14			IOMUX_PAD(0x6fc, 0x298, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA8__ATA_DATA_8				IOMUX_PAD(0x700, 0x29c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA8__UART3_RTS				IOMUX_PAD(0x700, 0x29c, 1, 0x99c, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA8__UART1_RI				IOMUX_PAD(0x700, 0x29c, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA8__AUDMUX_AUD6_TXC			IOMUX_PAD(0x700, 0x29c, 3, 0x7c0, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA8__GPIO2_21				IOMUX_PAD(0x700, 0x29c, 5, 0x89c, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA8__IPU_DIAGB_15			IOMUX_PAD(0x700, 0x29c, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA9__ATA_DATA_9				IOMUX_PAD(0x704, 0x2a0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA9__UART3_CTS				IOMUX_PAD(0x704, 0x2a0, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA9__UART1_DCD				IOMUX_PAD(0x704, 0x2a0, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA9__AUDMUX_AUD6_TXFS			IOMUX_PAD(0x704, 0x2a0, 3, 0x7c4, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA9__GPIO2_22				IOMUX_PAD(0x704, 0x2a0, 5, 0x8a0, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA9__IPU_DIAGB_16			IOMUX_PAD(0x704, 0x2a0, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA10__ATA_DATA_10			IOMUX_PAD(0x708, 0x2a4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA10__UART3_RXD_MUX			IOMUX_PAD(0x708, 0x2a4, 1, 0x9a0, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA10__AUDMUX_AUD6_RXC			IOMUX_PAD(0x708, 0x2a4, 3, 0x7b8, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA10__GPIO2_23				IOMUX_PAD(0x708, 0x2a4, 5, 0x8a4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA10__IPU_DIAGB_17			IOMUX_PAD(0x708, 0x2a4, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA11__ATA_DATA_11			IOMUX_PAD(0x70c, 0x2a8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA11__UART3_TXD_MUX			IOMUX_PAD(0x70c, 0x2a8, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA11__AUDMUX_AUD6_RXFS			IOMUX_PAD(0x70c, 0x2a8, 3, 0x7bc, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA11__GPIO2_24				IOMUX_PAD(0x70c, 0x2a8, 5, 0x8a8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA11__IPU_DIAGB_18			IOMUX_PAD(0x70c, 0x2a8, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA12__ATA_DATA_12			IOMUX_PAD(0x710, 0x2ac, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA12__I2C3_SCL				IOMUX_PAD(0x710, 0x2ac, 1, 0x91c, 3, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA12__GPIO2_25				IOMUX_PAD(0x710, 0x2ac, 5, 0x8ac, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA12__IPU_DIAGB_19			IOMUX_PAD(0x710, 0x2ac, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA13__ATA_DATA_13			IOMUX_PAD(0x714, 0x2b0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA13__I2C3_SDA				IOMUX_PAD(0x714, 0x2b0, 1, 0x920, 3, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA13__GPIO2_26				IOMUX_PAD(0x714, 0x2b0, 5, 0x8b0, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA13__IPU_DIAGB_20			IOMUX_PAD(0x714, 0x2b0, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA14__ATA_DATA_14			IOMUX_PAD(0x718, 0x2b4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA14__IPU_CSI_D_0			IOMUX_PAD(0x718, 0x2b4, 1, 0x930, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA14__KPP_ROW_0				IOMUX_PAD(0x718, 0x2b4, 3, 0x970, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA14__GPIO2_27				IOMUX_PAD(0x718, 0x2b4, 5, 0x8b4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA14__IPU_DIAGB_21			IOMUX_PAD(0x718, 0x2b4, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA15__ATA_DATA_15			IOMUX_PAD(0x71c, 0x2b8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA15__IPU_CSI_D_1			IOMUX_PAD(0x71c, 0x2b8, 1, 0x934, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA15__KPP_ROW_1				IOMUX_PAD(0x71c, 0x2b8, 3, 0x974, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA15__GPIO2_28				IOMUX_PAD(0x71c, 0x2b8, 5, 0x8b8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA15__IPU_DIAGB_22			IOMUX_PAD(0x71c, 0x2b8, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_INTRQ__ATA_INTRQ				IOMUX_PAD(0x720, 0x2bc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_INTRQ__IPU_CSI_D_2				IOMUX_PAD(0x720, 0x2bc, 1, 0x938, 3, NO_PAD_CTRL)
+#define MX35_PAD_ATA_INTRQ__KPP_ROW_2				IOMUX_PAD(0x720, 0x2bc, 3, 0x978, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_INTRQ__GPIO2_29				IOMUX_PAD(0x720, 0x2bc, 5, 0x8bc, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_INTRQ__IPU_DIAGB_23			IOMUX_PAD(0x720, 0x2bc, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_BUFF_EN__ATA_BUFFER_EN			IOMUX_PAD(0x724, 0x2c0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_BUFF_EN__IPU_CSI_D_3			IOMUX_PAD(0x724, 0x2c0, 1, 0x93c, 3, NO_PAD_CTRL)
+#define MX35_PAD_ATA_BUFF_EN__KPP_ROW_3				IOMUX_PAD(0x724, 0x2c0, 3, 0x97c, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_BUFF_EN__GPIO2_30				IOMUX_PAD(0x724, 0x2c0, 5, 0x8c4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_BUFF_EN__IPU_DIAGB_24			IOMUX_PAD(0x724, 0x2c0, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DMARQ__ATA_DMARQ				IOMUX_PAD(0x728, 0x2c4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMARQ__IPU_CSI_D_4				IOMUX_PAD(0x728, 0x2c4, 1, 0x940, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMARQ__KPP_COL_0				IOMUX_PAD(0x728, 0x2c4, 3, 0x950, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMARQ__GPIO2_31				IOMUX_PAD(0x728, 0x2c4, 5, 0x8c8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMARQ__IPU_DIAGB_25			IOMUX_PAD(0x728, 0x2c4, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMARQ__ECT_CTI_TRIG_IN1_4			IOMUX_PAD(0x728, 0x2c4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DA0__ATA_DA_0				IOMUX_PAD(0x72c, 0x2c8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA0__IPU_CSI_D_5				IOMUX_PAD(0x72c, 0x2c8, 1, 0x944, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA0__KPP_COL_1				IOMUX_PAD(0x72c, 0x2c8, 3, 0x954, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA0__GPIO3_0				IOMUX_PAD(0x72c, 0x2c8, 5, 0x8e8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA0__IPU_DIAGB_26				IOMUX_PAD(0x72c, 0x2c8, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA0__ECT_CTI_TRIG_IN1_5			IOMUX_PAD(0x72c, 0x2c8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DA1__ATA_DA_1				IOMUX_PAD(0x730, 0x2cc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA1__IPU_CSI_D_6				IOMUX_PAD(0x730, 0x2cc, 1, 0x948, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA1__KPP_COL_2				IOMUX_PAD(0x730, 0x2cc, 3, 0x958, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA1__GPIO3_1				IOMUX_PAD(0x730, 0x2cc, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA1__IPU_DIAGB_27				IOMUX_PAD(0x730, 0x2cc, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA1__ECT_CTI_TRIG_IN1_6			IOMUX_PAD(0x730, 0x2cc, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DA2__ATA_DA_2				IOMUX_PAD(0x734, 0x2d0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA2__IPU_CSI_D_7				IOMUX_PAD(0x734, 0x2d0, 1, 0x94c, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA2__KPP_COL_3				IOMUX_PAD(0x734, 0x2d0, 3, 0x95c, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA2__GPIO3_2				IOMUX_PAD(0x734, 0x2d0, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA2__IPU_DIAGB_28				IOMUX_PAD(0x734, 0x2d0, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA2__ECT_CTI_TRIG_IN1_7			IOMUX_PAD(0x734, 0x2d0, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_MLB_CLK__MLB_MLBCLK				IOMUX_PAD(0x738, 0x2d4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_MLB_CLK__GPIO3_3				IOMUX_PAD(0x738, 0x2d4, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_MLB_DAT__MLB_MLBDAT				IOMUX_PAD(0x73c, 0x2d8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_MLB_DAT__GPIO3_4				IOMUX_PAD(0x73c, 0x2d8, 5, 0x904, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_MLB_SIG__MLB_MLBSIG				IOMUX_PAD(0x740, 0x2dc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_MLB_SIG__GPIO3_5				IOMUX_PAD(0x740, 0x2dc, 5, 0x908, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_TX_CLK__FEC_TX_CLK				IOMUX_PAD(0x744, 0x2e0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_CLK__ESDHC1_DAT4			IOMUX_PAD(0x744, 0x2e0, 1, 0x804, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_CLK__UART3_RXD_MUX			IOMUX_PAD(0x744, 0x2e0, 2, 0x9a0, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_CLK__USB_TOP_USBH2_DIR			IOMUX_PAD(0x744, 0x2e0, 3, 0x9ec, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_CLK__CSPI2_MOSI				IOMUX_PAD(0x744, 0x2e0, 4, 0x7ec, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_CLK__GPIO3_6				IOMUX_PAD(0x744, 0x2e0, 5, 0x90c, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_CLK__IPU_DISPB_D12_VSYNC		IOMUX_PAD(0x744, 0x2e0, 6, 0x928, 5, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_CLK__ARM11P_TOP_EVNTBUS_0		IOMUX_PAD(0x744, 0x2e0, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_RX_CLK__FEC_RX_CLK				IOMUX_PAD(0x748, 0x2e4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_CLK__ESDHC1_DAT5			IOMUX_PAD(0x748, 0x2e4, 1, 0x808, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_CLK__UART3_TXD_MUX			IOMUX_PAD(0x748, 0x2e4, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_CLK__USB_TOP_USBH2_STP			IOMUX_PAD(0x748, 0x2e4, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_CLK__CSPI2_MISO				IOMUX_PAD(0x748, 0x2e4, 4, 0x7e8, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_CLK__GPIO3_7				IOMUX_PAD(0x748, 0x2e4, 5, 0x910, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_CLK__IPU_DISPB_SD_D_I			IOMUX_PAD(0x748, 0x2e4, 6, 0x92c, 4, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_CLK__ARM11P_TOP_EVNTBUS_1		IOMUX_PAD(0x748, 0x2e4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_RX_DV__FEC_RX_DV				IOMUX_PAD(0x74c, 0x2e8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_DV__ESDHC1_DAT6				IOMUX_PAD(0x74c, 0x2e8, 1, 0x80c, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_DV__UART3_RTS				IOMUX_PAD(0x74c, 0x2e8, 2, 0x99c, 2, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_DV__USB_TOP_USBH2_NXT			IOMUX_PAD(0x74c, 0x2e8, 3, 0x9f0, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_DV__CSPI2_SCLK				IOMUX_PAD(0x74c, 0x2e8, 4, 0x7e0, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_DV__GPIO3_8				IOMUX_PAD(0x74c, 0x2e8, 5, 0x914, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_DV__IPU_DISPB_SD_CLK			IOMUX_PAD(0x74c, 0x2e8, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_DV__ARM11P_TOP_EVNTBUS_2		IOMUX_PAD(0x74c, 0x2e8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_COL__FEC_COL				IOMUX_PAD(0x750, 0x2ec, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_COL__ESDHC1_DAT7				IOMUX_PAD(0x750, 0x2ec, 1, 0x810, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_COL__UART3_CTS				IOMUX_PAD(0x750, 0x2ec, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_COL__USB_TOP_USBH2_DATA_0			IOMUX_PAD(0x750, 0x2ec, 3, 0x9cc, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_COL__CSPI2_RDY				IOMUX_PAD(0x750, 0x2ec, 4, 0x7e4, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_COL__GPIO3_9				IOMUX_PAD(0x750, 0x2ec, 5, 0x918, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_COL__IPU_DISPB_SER_RS			IOMUX_PAD(0x750, 0x2ec, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_COL__ARM11P_TOP_EVNTBUS_3			IOMUX_PAD(0x750, 0x2ec, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_RDATA0__FEC_RDATA_0			IOMUX_PAD(0x754, 0x2f0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA0__PWM_PWMO				IOMUX_PAD(0x754, 0x2f0, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA0__UART3_DTR				IOMUX_PAD(0x754, 0x2f0, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA0__USB_TOP_USBH2_DATA_1		IOMUX_PAD(0x754, 0x2f0, 3, 0x9d0, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA0__CSPI2_SS0				IOMUX_PAD(0x754, 0x2f0, 4, 0x7f0, 2, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA0__GPIO3_10				IOMUX_PAD(0x754, 0x2f0, 5, 0x8ec, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA0__IPU_DISPB_CS1			IOMUX_PAD(0x754, 0x2f0, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA0__ARM11P_TOP_EVNTBUS_4		IOMUX_PAD(0x754, 0x2f0, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_TDATA0__FEC_TDATA_0			IOMUX_PAD(0x758, 0x2f4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA0__SPDIF_SPDIF_OUT1			IOMUX_PAD(0x758, 0x2f4, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA0__UART3_DSR				IOMUX_PAD(0x758, 0x2f4, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA0__USB_TOP_USBH2_DATA_2		IOMUX_PAD(0x758, 0x2f4, 3, 0x9d4, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA0__CSPI2_SS1				IOMUX_PAD(0x758, 0x2f4, 4, 0x7f4, 2, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA0__GPIO3_11				IOMUX_PAD(0x758, 0x2f4, 5, 0x8f0, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA0__IPU_DISPB_CS0			IOMUX_PAD(0x758, 0x2f4, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA0__ARM11P_TOP_EVNTBUS_5		IOMUX_PAD(0x758, 0x2f4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_TX_EN__FEC_TX_EN				IOMUX_PAD(0x75c, 0x2f8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_EN__SPDIF_SPDIF_IN1			IOMUX_PAD(0x75c, 0x2f8, 1, 0x998, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_EN__UART3_RI				IOMUX_PAD(0x75c, 0x2f8, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_EN__USB_TOP_USBH2_DATA_3		IOMUX_PAD(0x75c, 0x2f8, 3, 0x9d8, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_EN__GPIO3_12				IOMUX_PAD(0x75c, 0x2f8, 5, 0x8f4, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_EN__IPU_DISPB_PAR_RS			IOMUX_PAD(0x75c, 0x2f8, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_EN__ARM11P_TOP_EVNTBUS_6		IOMUX_PAD(0x75c, 0x2f8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_MDC__FEC_MDC				IOMUX_PAD(0x760, 0x2fc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDC__CAN2_TXCAN				IOMUX_PAD(0x760, 0x2fc, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDC__UART3_DCD				IOMUX_PAD(0x760, 0x2fc, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDC__USB_TOP_USBH2_DATA_4			IOMUX_PAD(0x760, 0x2fc, 3, 0x9dc, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDC__GPIO3_13				IOMUX_PAD(0x760, 0x2fc, 5, 0x8f8, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDC__IPU_DISPB_WR				IOMUX_PAD(0x760, 0x2fc, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDC__ARM11P_TOP_EVNTBUS_7			IOMUX_PAD(0x760, 0x2fc, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_MDIO__FEC_MDIO				IOMUX_PAD(0x764, 0x300, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDIO__CAN2_RXCAN				IOMUX_PAD(0x764, 0x300, 1, 0x7cc, 2, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDIO__USB_TOP_USBH2_DATA_5			IOMUX_PAD(0x764, 0x300, 3, 0x9e0, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDIO__GPIO3_14				IOMUX_PAD(0x764, 0x300, 5, 0x8fc, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDIO__IPU_DISPB_RD				IOMUX_PAD(0x764, 0x300, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDIO__ARM11P_TOP_EVNTBUS_8			IOMUX_PAD(0x764, 0x300, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_TX_ERR__FEC_TX_ERR				IOMUX_PAD(0x768, 0x304, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_ERR__OWIRE_LINE				IOMUX_PAD(0x768, 0x304, 1, 0x990, 2, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_ERR__SPDIF_SPDIF_EXTCLK			IOMUX_PAD(0x768, 0x304, 2, 0x994, 4, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_ERR__USB_TOP_USBH2_DATA_6		IOMUX_PAD(0x768, 0x304, 3, 0x9e4, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_ERR__GPIO3_15				IOMUX_PAD(0x768, 0x304, 5, 0x900, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_ERR__IPU_DISPB_D0_VSYNC			IOMUX_PAD(0x768, 0x304, 6, 0x924, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_ERR__ARM11P_TOP_EVNTBUS_9		IOMUX_PAD(0x768, 0x304, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_RX_ERR__FEC_RX_ERR				IOMUX_PAD(0x76c, 0x308, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_ERR__IPU_CSI_D_0			IOMUX_PAD(0x76c, 0x308, 1, 0x930, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_ERR__USB_TOP_USBH2_DATA_7		IOMUX_PAD(0x76c, 0x308, 3, 0x9e8, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_ERR__KPP_COL_4				IOMUX_PAD(0x76c, 0x308, 4, 0x960, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_ERR__GPIO3_16				IOMUX_PAD(0x76c, 0x308, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_ERR__IPU_DISPB_SD_D_IO			IOMUX_PAD(0x76c, 0x308, 6, 0x92c, 5, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_CRS__FEC_CRS				IOMUX_PAD(0x770, 0x30c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_CRS__IPU_CSI_D_1				IOMUX_PAD(0x770, 0x30c, 1, 0x934, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_CRS__USB_TOP_USBH2_PWR			IOMUX_PAD(0x770, 0x30c, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_CRS__KPP_COL_5				IOMUX_PAD(0x770, 0x30c, 4, 0x964, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_CRS__GPIO3_17				IOMUX_PAD(0x770, 0x30c, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_CRS__IPU_FLASH_STROBE			IOMUX_PAD(0x770, 0x30c, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_RDATA1__FEC_RDATA_1			IOMUX_PAD(0x774, 0x310, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA1__IPU_CSI_D_2			IOMUX_PAD(0x774, 0x310, 1, 0x938, 4, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA1__AUDMUX_AUD6_RXC			IOMUX_PAD(0x774, 0x310, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA1__USB_TOP_USBH2_OC			IOMUX_PAD(0x774, 0x310, 3, 0x9f4, 2, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA1__KPP_COL_6				IOMUX_PAD(0x774, 0x310, 4, 0x968, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA1__GPIO3_18				IOMUX_PAD(0x774, 0x310, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA1__IPU_DISPB_BE0			IOMUX_PAD(0x774, 0x310, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_TDATA1__FEC_TDATA_1			IOMUX_PAD(0x778, 0x314, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA1__IPU_CSI_D_3			IOMUX_PAD(0x778, 0x314, 1, 0x93c, 4, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA1__AUDMUX_AUD6_RXFS			IOMUX_PAD(0x778, 0x314, 2, 0x7bc, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA1__KPP_COL_7				IOMUX_PAD(0x778, 0x314, 4, 0x96c, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA1__GPIO3_19				IOMUX_PAD(0x778, 0x314, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA1__IPU_DISPB_BE1			IOMUX_PAD(0x778, 0x314, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_RDATA2__FEC_RDATA_2			IOMUX_PAD(0x77c, 0x318, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA2__IPU_CSI_D_4			IOMUX_PAD(0x77c, 0x318, 1, 0x940, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA2__AUDMUX_AUD6_TXD			IOMUX_PAD(0x77c, 0x318, 2, 0x7b4, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA2__KPP_ROW_4				IOMUX_PAD(0x77c, 0x318, 4, 0x980, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA2__GPIO3_20				IOMUX_PAD(0x77c, 0x318, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_TDATA2__FEC_TDATA_2			IOMUX_PAD(0x780, 0x31c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA2__IPU_CSI_D_5			IOMUX_PAD(0x780, 0x31c, 1, 0x944, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA2__AUDMUX_AUD6_RXD			IOMUX_PAD(0x780, 0x31c, 2, 0x7b0, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA2__KPP_ROW_5				IOMUX_PAD(0x780, 0x31c, 4, 0x984, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA2__GPIO3_21				IOMUX_PAD(0x780, 0x31c, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_RDATA3__FEC_RDATA_3			IOMUX_PAD(0x784, 0x320, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA3__IPU_CSI_D_6			IOMUX_PAD(0x784, 0x320, 1, 0x948, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA3__AUDMUX_AUD6_TXC			IOMUX_PAD(0x784, 0x320, 2, 0x7c0, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA3__KPP_ROW_6				IOMUX_PAD(0x784, 0x320, 4, 0x988, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA3__GPIO3_22				IOMUX_PAD(0x784, 0x320, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_TDATA3__FEC_TDATA_3			IOMUX_PAD(0x788, 0x324, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA3__IPU_CSI_D_7			IOMUX_PAD(0x788, 0x324, 1, 0x94c, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA3__AUDMUX_AUD6_TXFS			IOMUX_PAD(0x788, 0x324, 2, 0x7c4, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA3__KPP_ROW_7				IOMUX_PAD(0x788, 0x324, 4, 0x98c, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA3__GPIO3_23				IOMUX_PAD(0x788, 0x324, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_EXT_ARMCLK__CCM_EXT_ARMCLK			IOMUX_PAD(0x78c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TEST_MODE__TCU_TEST_MODE			IOMUX_PAD(0x790, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+
+#endif /* __MACH_IOMUX_MX35_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/iomux-v3.h b/arch/arm/plat-mxc/include/mach/iomux-v3.h
new file mode 100644
index 0000000..7cd8454
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/iomux-v3.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH,
+ *			<armlinux@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.
+ *
+ * You 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_IOMUX_V3_H__
+#define __MACH_IOMUX_V3_H__
+
+/*
+ *	build IOMUX_PAD structure
+ *
+ * This iomux scheme is based around pads, which are the physical balls
+ * on the processor.
+ *
+ * - Each pad has a pad control register (IOMUXC_SW_PAD_CTRL_x) which controls
+ *   things like driving strength and pullup/pulldown.
+ * - Each pad can have but not necessarily does have an output routing register
+ *   (IOMUXC_SW_MUX_CTL_PAD_x).
+ * - Each pad can have but not necessarily does have an input routing register
+ *   (IOMUXC_x_SELECT_INPUT)
+ *
+ * The three register sets do not have a fixed offset to each other,
+ * hence we order this table by pad control registers (which all pads
+ * have) and put the optional i/o routing registers into additional
+ * fields.
+ *
+ * The naming convention for the pad modes is MX35_PAD_<padname>__<padmode>
+ * If <padname> or <padmode> refers to a GPIO, it is named
+ * GPIO_<unit>_<num>
+ *
+ */
+
+struct pad_desc {
+	unsigned mux_ctrl_ofs:12; /* IOMUXC_SW_MUX_CTL_PAD offset */
+	unsigned mux_mode:8;
+	unsigned pad_ctrl_ofs:12; /* IOMUXC_SW_PAD_CTRL offset */
+#define	NO_PAD_CTRL	(1 << 16)
+	unsigned pad_ctrl:17;
+	unsigned select_input_ofs:12; /* IOMUXC_SELECT_INPUT offset */
+	unsigned select_input:3;
+};
+
+#define IOMUX_PAD(_pad_ctrl_ofs, _mux_ctrl_ofs, _mux_mode, _select_input_ofs, \
+		_select_input, _pad_ctrl)				\
+		{							\
+			.mux_ctrl_ofs     = _mux_ctrl_ofs,		\
+			.mux_mode         = _mux_mode,			\
+			.pad_ctrl_ofs     = _pad_ctrl_ofs,		\
+			.pad_ctrl         = _pad_ctrl,			\
+			.select_input_ofs = _select_input_ofs,		\
+			.select_input     = _select_input,		\
+		}
+
+/*
+ * Use to set PAD control
+ */
+#define PAD_CTL_DRIVE_VOLTAGE_3_3_V	0
+#define PAD_CTL_DRIVE_VOLTAGE_1_8_V	1
+
+#define PAD_CTL_NO_HYSTERESIS		0
+#define PAD_CTL_HYSTERESIS		1
+
+#define PAD_CTL_PULL_DISABLED		0x0
+#define PAD_CTL_PULL_KEEPER		0xa
+#define PAD_CTL_PULL_DOWN_100K		0xc
+#define PAD_CTL_PULL_UP_47K		0xd
+#define PAD_CTL_PULL_UP_100K		0xe
+#define PAD_CTL_PULL_UP_22K		0xf
+
+#define PAD_CTL_OUTPUT_CMOS		0
+#define PAD_CTL_OUTPUT_OPEN_DRAIN	1
+
+#define PAD_CTL_DRIVE_STRENGTH_NORM	0
+#define PAD_CTL_DRIVE_STRENGTH_HIGH	1
+#define PAD_CTL_DRIVE_STRENGTH_MAX	2
+
+#define PAD_CTL_SLEW_RATE_SLOW		0
+#define PAD_CTL_SLEW_RATE_FAST		1
+
+/*
+ * setups a single pad:
+ * 	- reserves the pad so that it is not claimed by another driver
+ * 	- setups the iomux according to the configuration
+ */
+int mxc_iomux_v3_setup_pad(struct pad_desc *pad);
+
+/*
+ * setups mutliple pads
+ * convenient way to call the above function with tables
+ */
+int mxc_iomux_v3_setup_multiple_pads(struct pad_desc *pad_list, unsigned count);
+
+/*
+ * releases a single pad:
+ * 	- make it available for a future use by another driver
+ * 	- DOES NOT reconfigure the IOMUX in its reset state
+ */
+void mxc_iomux_v3_release_pad(struct pad_desc *pad);
+
+/*
+ * releases multiple pads
+ * convenvient way to call the above function with tables
+ */
+void mxc_iomux_v3_release_multiple_pads(struct pad_desc *pad_list, int count);
+
+#endif /* __MACH_IOMUX_V3_H__*/
+
diff --git a/arch/arm/plat-mxc/include/mach/memory.h b/arch/arm/plat-mxc/include/mach/memory.h
index eca37d0..6065e00 100644
--- a/arch/arm/plat-mxc/include/mach/memory.h
+++ b/arch/arm/plat-mxc/include/mach/memory.h
@@ -32,4 +32,12 @@
 #define CONSISTENT_DMA_SIZE SZ_4M
 #endif /* CONFIG_MX1_VIDEO */
 
+#if defined(CONFIG_MX3_VIDEO)
+/*
+ * Increase size of DMA-consistent memory region.
+ * This is required for mx3 camera driver to capture at least two QXGA frames.
+ */
+#define CONSISTENT_DMA_SIZE SZ_8M
+#endif /* CONFIG_MX3_VIDEO */
+
 #endif /* __ASM_ARCH_MXC_MEMORY_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/mx1.h b/arch/arm/plat-mxc/include/mach/mx1.h
index b92e023..1000bf3 100644
--- a/arch/arm/plat-mxc/include/mach/mx1.h
+++ b/arch/arm/plat-mxc/include/mach/mx1.h
@@ -179,7 +179,7 @@
 #define DMA_REQ_UART1_T		30
 #define DMA_REQ_UART1_R		31
 
-/* mandatory for CONFIG_LL_DEBUG */
+/* mandatory for CONFIG_DEBUG_LL */
 #define MXC_LL_UART_PADDR	UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR	IO_ADDRESS(UART1_BASE_ADDR)
 
diff --git a/arch/arm/plat-mxc/include/mach/mx3x.h b/arch/arm/plat-mxc/include/mach/mx3x.h
index 3878c60..b559a4b 100644
--- a/arch/arm/plat-mxc/include/mach/mx3x.h
+++ b/arch/arm/plat-mxc/include/mach/mx3x.h
@@ -48,6 +48,9 @@
 #define CS4_SIZE		SZ_32M
 
 #define CS5_BASE_ADDR		0xB6000000
+#define CS5_BASE_ADDR_VIRT	0xF6000000
+#define CS5_SIZE		SZ_32M
+
 #define PCMCIA_MEM_BASE_ADDR	0xBC000000
 
 /*
@@ -191,6 +194,9 @@
 #define CS4_IO_ADDRESS(x)  \
 	(((x) - CS4_BASE_ADDR) + CS4_BASE_ADDR_VIRT)
 
+#define CS5_IO_ADDRESS(x)  \
+	(((x) - CS5_BASE_ADDR) + CS5_BASE_ADDR_VIRT)
+
 #define X_MEMC_IO_ADDRESS(x)  \
 	(((x) - X_MEMC_BASE_ADDR) + X_MEMC_BASE_ADDR_VIRT)
 
diff --git a/arch/arm/plat-mxc/include/mach/mxc_timer.h b/arch/arm/plat-mxc/include/mach/mxc_timer.h
deleted file mode 100644
index 6c19a13..0000000
--- a/arch/arm/plat-mxc/include/mach/mxc_timer.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * mxc_timer.h
- *
- * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
- *
- * Platform independent (i.MX1, i.MX2, i.MX3) definition for timer handling.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the 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 __PLAT_MXC_TIMER_H
-#define __PLAT_MXC_TIMER_H
-
-#include <linux/clk.h>
-#include <mach/hardware.h>
-
-#ifdef CONFIG_ARCH_MX1
-#define TIMER_BASE		IO_ADDRESS(TIM1_BASE_ADDR)
-#define TIMER_INTERRUPT		TIM1_INT
-
-#define TCTL_VAL		TCTL_CLK_PCLK1
-#define TCTL_IRQEN		(1<<4)
-#define TCTL_FRR		(1<<8)
-#define TCTL_CLK_PCLK1		(1<<1)
-#define TCTL_CLK_PCLK1_4	(2<<1)
-#define TCTL_CLK_TIN		(3<<1)
-#define TCTL_CLK_32		(4<<1)
-
-#define MXC_TCTL   0x00
-#define MXC_TPRER  0x04
-#define MXC_TCMP   0x08
-#define MXC_TCR    0x0c
-#define MXC_TCN    0x10
-#define MXC_TSTAT  0x14
-#define TSTAT_CAPT		(1<<1)
-#define TSTAT_COMP		(1<<0)
-
-static inline void gpt_irq_disable(void)
-{
-	unsigned int tmp;
-
-	tmp = __raw_readl(TIMER_BASE + MXC_TCTL);
-	__raw_writel(tmp & ~TCTL_IRQEN, TIMER_BASE + MXC_TCTL);
-}
-
-static inline void gpt_irq_enable(void)
-{
-	__raw_writel(__raw_readl(TIMER_BASE + MXC_TCTL) | TCTL_IRQEN,
-				TIMER_BASE + MXC_TCTL);
-}
-
-static void gpt_irq_acknowledge(void)
-{
-	__raw_writel(0, TIMER_BASE + MXC_TSTAT);
-}
-#endif /* CONFIG_ARCH_MX1 */
-
-#ifdef CONFIG_ARCH_MX2
-#define TIMER_BASE		IO_ADDRESS(GPT1_BASE_ADDR)
-#define TIMER_INTERRUPT		MXC_INT_GPT1
-
-#define MXC_TCTL   0x00
-#define TCTL_VAL		TCTL_CLK_PCLK1
-#define TCTL_CLK_PCLK1		(1<<1)
-#define TCTL_CLK_PCLK1_4	(2<<1)
-#define TCTL_IRQEN		(1<<4)
-#define TCTL_FRR		(1<<8)
-#define MXC_TPRER  0x04
-#define MXC_TCMP   0x08
-#define MXC_TCR    0x0c
-#define MXC_TCN    0x10
-#define MXC_TSTAT  0x14
-#define TSTAT_CAPT		(1<<1)
-#define TSTAT_COMP		(1<<0)
-
-static inline void gpt_irq_disable(void)
-{
-	unsigned int tmp;
-
-	tmp = __raw_readl(TIMER_BASE + MXC_TCTL);
-	__raw_writel(tmp & ~TCTL_IRQEN, TIMER_BASE + MXC_TCTL);
-}
-
-static inline void gpt_irq_enable(void)
-{
-	__raw_writel(__raw_readl(TIMER_BASE + MXC_TCTL) | TCTL_IRQEN,
-				TIMER_BASE + MXC_TCTL);
-}
-
-static void gpt_irq_acknowledge(void)
-{
-	__raw_writel(TSTAT_CAPT | TSTAT_COMP, TIMER_BASE + MXC_TSTAT);
-}
-#endif /* CONFIG_ARCH_MX2 */
-
-#ifdef CONFIG_ARCH_MX3
-#define TIMER_BASE		IO_ADDRESS(GPT1_BASE_ADDR)
-#define TIMER_INTERRUPT		MXC_INT_GPT
-
-#define MXC_TCTL   0x00
-#define TCTL_VAL		(TCTL_CLK_IPG | TCTL_WAITEN)
-#define TCTL_CLK_IPG		(1<<6)
-#define TCTL_FRR		(1<<9)
-#define TCTL_WAITEN		(1<<3)
-
-#define MXC_TPRER  0x04
-#define MXC_TSTAT  0x08
-#define TSTAT_OF1		(1<<0)
-#define TSTAT_OF2		(1<<1)
-#define TSTAT_OF3		(1<<2)
-#define TSTAT_IF1		(1<<3)
-#define TSTAT_IF2		(1<<4)
-#define TSTAT_ROV		(1<<5)
-#define MXC_IR     0x0c
-#define MXC_TCMP   0x10
-#define MXC_TCMP2  0x14
-#define MXC_TCMP3  0x18
-#define MXC_TCR    0x1c
-#define MXC_TCN    0x24
-
-static inline void gpt_irq_disable(void)
-{
-	__raw_writel(0, TIMER_BASE + MXC_IR);
-}
-
-static inline void gpt_irq_enable(void)
-{
-	__raw_writel(1<<0, TIMER_BASE + MXC_IR);
-}
-
-static inline void gpt_irq_acknowledge(void)
-{
-	__raw_writel(TSTAT_OF1, TIMER_BASE + MXC_TSTAT);
-}
-#endif /* CONFIG_ARCH_MX3 */
-
-#define TCTL_SWR		(1<<15)
-#define TCTL_CC			(1<<10)
-#define TCTL_OM			(1<<9)
-#define TCTL_CAP_RIS		(1<<6)
-#define TCTL_CAP_FAL		(2<<6)
-#define TCTL_CAP_RIS_FAL	(3<<6)
-#define TCTL_CAP_ENA		(1<<5)
-#define TCTL_TEN		(1<<0)
-
-#endif
diff --git a/arch/arm/plat-mxc/include/mach/usb.h b/arch/arm/plat-mxc/include/mach/usb.h
index 2dacb30..be27337 100644
--- a/arch/arm/plat-mxc/include/mach/usb.h
+++ b/arch/arm/plat-mxc/include/mach/usb.h
@@ -17,7 +17,7 @@
 
 struct imxusb_platform_data {
 	int (*init)(struct device *);
-	int (*exit)(struct device *);
+	void (*exit)(struct device *);
 };
 
 #endif /* __ASM_ARCH_MXC_USB */
diff --git a/arch/arm/plat-mxc/iomux-v3.c b/arch/arm/plat-mxc/iomux-v3.c
new file mode 100644
index 0000000..77a078f
--- /dev/null
+++ b/arch/arm/plat-mxc/iomux-v3.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de>
+ * Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH,
+ *                       <armlinux@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.
+ *
+ * You 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/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <asm/mach/map.h>
+#include <mach/iomux-v3.h>
+
+#define IOMUX_BASE	IO_ADDRESS(IOMUXC_BASE_ADDR)
+
+static unsigned long iomux_v3_pad_alloc_map[0x200 / BITS_PER_LONG];
+
+/*
+ * setups a single pin:
+ * 	- reserves the pin so that it is not claimed by another driver
+ * 	- setups the iomux according to the configuration
+ */
+int mxc_iomux_v3_setup_pad(struct pad_desc *pad)
+{
+	unsigned int pad_ofs = pad->pad_ctrl_ofs;
+
+	if (test_and_set_bit(pad_ofs >> 2, iomux_v3_pad_alloc_map))
+		return -EBUSY;
+	if (pad->mux_ctrl_ofs)
+		__raw_writel(pad->mux_mode, IOMUX_BASE + pad->mux_ctrl_ofs);
+
+	if (pad->select_input_ofs)
+		__raw_writel(pad->select_input,
+				IOMUX_BASE + pad->select_input_ofs);
+
+	if (!(pad->pad_ctrl & NO_PAD_CTRL))
+		__raw_writel(pad->pad_ctrl, IOMUX_BASE + pad->pad_ctrl_ofs);
+	return 0;
+}
+EXPORT_SYMBOL(mxc_iomux_v3_setup_pad);
+
+int mxc_iomux_v3_setup_multiple_pads(struct pad_desc *pad_list, unsigned count)
+{
+	struct pad_desc *p = pad_list;
+	int i;
+	int ret;
+
+	for (i = 0; i < count; i++) {
+		ret = mxc_iomux_v3_setup_pad(p);
+		if (ret)
+			goto setup_error;
+		p++;
+	}
+	return 0;
+
+setup_error:
+	mxc_iomux_v3_release_multiple_pads(pad_list, i);
+	return ret;
+}
+EXPORT_SYMBOL(mxc_iomux_v3_setup_multiple_pads);
+
+void mxc_iomux_v3_release_pad(struct pad_desc *pad)
+{
+	unsigned int pad_ofs = pad->pad_ctrl_ofs;
+
+	clear_bit(pad_ofs >> 2, iomux_v3_pad_alloc_map);
+}
+EXPORT_SYMBOL(mxc_iomux_v3_release_pad);
+
+void mxc_iomux_v3_release_multiple_pads(struct pad_desc *pad_list, int count)
+{
+	struct pad_desc *p = pad_list;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		mxc_iomux_v3_release_pad(p);
+		p++;
+	}
+}
+EXPORT_SYMBOL(mxc_iomux_v3_release_multiple_pads);
diff --git a/arch/arm/plat-mxc/irq.c b/arch/arm/plat-mxc/irq.c
index 0fb68a5..8aee763 100644
--- a/arch/arm/plat-mxc/irq.c
+++ b/arch/arm/plat-mxc/irq.c
@@ -24,31 +24,27 @@
 #include <asm/mach/irq.h>
 #include <mach/hardware.h>
 
-#define AVIC_BASE		IO_ADDRESS(AVIC_BASE_ADDR)
-#define AVIC_INTCNTL		(AVIC_BASE + 0x00)	/* int control reg */
-#define AVIC_NIMASK		(AVIC_BASE + 0x04)	/* int mask reg */
-#define AVIC_INTENNUM		(AVIC_BASE + 0x08)	/* int enable number reg */
-#define AVIC_INTDISNUM		(AVIC_BASE + 0x0C)	/* int disable number reg */
-#define AVIC_INTENABLEH		(AVIC_BASE + 0x10)	/* int enable reg high */
-#define AVIC_INTENABLEL		(AVIC_BASE + 0x14)	/* int enable reg low */
-#define AVIC_INTTYPEH		(AVIC_BASE + 0x18)	/* int type reg high */
-#define AVIC_INTTYPEL		(AVIC_BASE + 0x1C)	/* int type reg low */
-#define AVIC_NIPRIORITY(x)	(AVIC_BASE + (0x20 + 4 * (7 - (x)))) /* int priority */
-#define AVIC_NIVECSR		(AVIC_BASE + 0x40)	/* norm int vector/status */
-#define AVIC_FIVECSR		(AVIC_BASE + 0x44)	/* fast int vector/status */
-#define AVIC_INTSRCH		(AVIC_BASE + 0x48)	/* int source reg high */
-#define AVIC_INTSRCL		(AVIC_BASE + 0x4C)	/* int source reg low */
-#define AVIC_INTFRCH		(AVIC_BASE + 0x50)	/* int force reg high */
-#define AVIC_INTFRCL		(AVIC_BASE + 0x54)	/* int force reg low */
-#define AVIC_NIPNDH		(AVIC_BASE + 0x58)	/* norm int pending high */
-#define AVIC_NIPNDL		(AVIC_BASE + 0x5C)	/* norm int pending low */
-#define AVIC_FIPNDH		(AVIC_BASE + 0x60)	/* fast int pending high */
-#define AVIC_FIPNDL		(AVIC_BASE + 0x64)	/* fast int pending low */
+#define AVIC_INTCNTL		0x00	/* int control reg */
+#define AVIC_NIMASK		0x04	/* int mask reg */
+#define AVIC_INTENNUM		0x08	/* int enable number reg */
+#define AVIC_INTDISNUM		0x0C	/* int disable number reg */
+#define AVIC_INTENABLEH		0x10	/* int enable reg high */
+#define AVIC_INTENABLEL		0x14	/* int enable reg low */
+#define AVIC_INTTYPEH		0x18	/* int type reg high */
+#define AVIC_INTTYPEL		0x1C	/* int type reg low */
+#define AVIC_NIPRIORITY(x)	(0x20 + 4 * (7 - (x))) /* int priority */
+#define AVIC_NIVECSR		0x40	/* norm int vector/status */
+#define AVIC_FIVECSR		0x44	/* fast int vector/status */
+#define AVIC_INTSRCH		0x48	/* int source reg high */
+#define AVIC_INTSRCL		0x4C	/* int source reg low */
+#define AVIC_INTFRCH		0x50	/* int force reg high */
+#define AVIC_INTFRCL		0x54	/* int force reg low */
+#define AVIC_NIPNDH		0x58	/* norm int pending high */
+#define AVIC_NIPNDL		0x5C	/* norm int pending low */
+#define AVIC_FIPNDH		0x60	/* fast int pending high */
+#define AVIC_FIPNDL		0x64	/* fast int pending low */
 
-#define SYSTEM_PREV_REG		IO_ADDRESS(IIM_BASE_ADDR + 0x20)
-#define SYSTEM_SREV_REG		IO_ADDRESS(IIM_BASE_ADDR + 0x24)
-#define IIM_PROD_REV_SH		3
-#define IIM_PROD_REV_LEN	5
+static void __iomem *avic_base;
 
 int imx_irq_set_priority(unsigned char irq, unsigned char prio)
 {
@@ -59,11 +55,11 @@
 	if (irq >= MXC_INTERNAL_IRQS)
 		return -EINVAL;;
 
-	temp = __raw_readl(AVIC_NIPRIORITY(irq / 8));
+	temp = __raw_readl(avic_base + AVIC_NIPRIORITY(irq / 8));
 	temp &= ~mask;
 	temp |= prio & mask;
 
-	__raw_writel(temp, AVIC_NIPRIORITY(irq / 8));
+	__raw_writel(temp, avic_base + AVIC_NIPRIORITY(irq / 8));
 
 	return 0;
 #else
@@ -81,12 +77,12 @@
 		return -EINVAL;
 
 	if (irq < MXC_INTERNAL_IRQS / 2) {
-		irqt = __raw_readl(AVIC_INTTYPEL) & ~(1 << irq);
-		__raw_writel(irqt | (!!type << irq), AVIC_INTTYPEL);
+		irqt = __raw_readl(avic_base + AVIC_INTTYPEL) & ~(1 << irq);
+		__raw_writel(irqt | (!!type << irq), avic_base + AVIC_INTTYPEL);
 	} else {
 		irq -= MXC_INTERNAL_IRQS / 2;
-		irqt = __raw_readl(AVIC_INTTYPEH) & ~(1 << irq);
-		__raw_writel(irqt | (!!type << irq), AVIC_INTTYPEH);
+		irqt = __raw_readl(avic_base + AVIC_INTTYPEH) & ~(1 << irq);
+		__raw_writel(irqt | (!!type << irq), avic_base + AVIC_INTTYPEH);
 	}
 
 	return 0;
@@ -97,13 +93,13 @@
 /* Disable interrupt number "irq" in the AVIC */
 static void mxc_mask_irq(unsigned int irq)
 {
-	__raw_writel(irq, AVIC_INTDISNUM);
+	__raw_writel(irq, avic_base + AVIC_INTDISNUM);
 }
 
 /* Enable interrupt number "irq" in the AVIC */
 static void mxc_unmask_irq(unsigned int irq)
 {
-	__raw_writel(irq, AVIC_INTENNUM);
+	__raw_writel(irq, avic_base + AVIC_INTENNUM);
 }
 
 static struct irq_chip mxc_avic_chip = {
@@ -121,19 +117,21 @@
 {
 	int i;
 
+	avic_base = IO_ADDRESS(AVIC_BASE_ADDR);
+
 	/* put the AVIC into the reset value with
 	 * all interrupts disabled
 	 */
-	__raw_writel(0, AVIC_INTCNTL);
-	__raw_writel(0x1f, AVIC_NIMASK);
+	__raw_writel(0, avic_base + AVIC_INTCNTL);
+	__raw_writel(0x1f, avic_base + AVIC_NIMASK);
 
 	/* disable all interrupts */
-	__raw_writel(0, AVIC_INTENABLEH);
-	__raw_writel(0, AVIC_INTENABLEL);
+	__raw_writel(0, avic_base + AVIC_INTENABLEH);
+	__raw_writel(0, avic_base + AVIC_INTENABLEL);
 
 	/* all IRQ no FIQ */
-	__raw_writel(0, AVIC_INTTYPEH);
-	__raw_writel(0, AVIC_INTTYPEL);
+	__raw_writel(0, avic_base + AVIC_INTTYPEH);
+	__raw_writel(0, avic_base + AVIC_INTTYPEL);
 	for (i = 0; i < MXC_INTERNAL_IRQS; i++) {
 		set_irq_chip(i, &mxc_avic_chip);
 		set_irq_handler(i, handle_level_irq);
@@ -142,7 +140,7 @@
 
 	/* Set default priority value (0) for all IRQ's */
 	for (i = 0; i < 8; i++)
-		__raw_writel(0, AVIC_NIPRIORITY(i));
+		__raw_writel(0, avic_base + AVIC_NIPRIORITY(i));
 
 	/* init architectures chained interrupt handler */
 	mxc_register_gpios();
@@ -154,3 +152,4 @@
 
 	printk(KERN_INFO "MXC IRQ initialized\n");
 }
+
diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c
index 9bffbc5..ae34198 100644
--- a/arch/arm/plat-mxc/pwm.c
+++ b/arch/arm/plat-mxc/pwm.c
@@ -15,65 +15,26 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/pwm.h>
+#include <mach/hardware.h>
 
-#if defined CONFIG_ARCH_MX1 || defined CONFIG_ARCH_MX21
-#define PWM_VER_1
 
-#define PWMCR	0x00	/* PWM Control Register		*/
-#define PWMSR	0x04	/* PWM Sample Register		*/
-#define PWMPR	0x08	/* PWM Period Register		*/
-#define PWMCNR	0x0C	/* PWM Counter Register		*/
+/* i.MX1 and i.MX21 share the same PWM function block: */
 
-#define PWMCR_HCTR		(1 << 18)		/* Halfword FIFO Data Swapping	*/
-#define PWMCR_BCTR		(1 << 17)		/* Byte FIFO Data Swapping	*/
-#define PWMCR_SWR		(1 << 16)		/* Software Reset		*/
-#define PWMCR_CLKSRC_PERCLK	(0 << 15)		/* PERCLK Clock Source		*/
-#define PWMCR_CLKSRC_CLK32	(1 << 15)		/* 32KHz Clock Source		*/
-#define PWMCR_PRESCALER(x)	(((x - 1) & 0x7F) << 8)	/* PRESCALER			*/
-#define PWMCR_IRQ		(1 << 7)		/* Interrupt Request		*/
-#define PWMCR_IRQEN		(1 << 6)		/* Interrupt Request Enable	*/
-#define PWMCR_FIFOAV		(1 << 5)		/* FIFO Available		*/
-#define PWMCR_EN		(1 << 4)		/* Enables/Disables the PWM	*/
-#define PWMCR_REPEAT(x)		(((x) & 0x03) << 2)	/* Sample Repeats		*/
-#define PWMCR_DIV(x)		(((x) & 0x03) << 0)	/* Clock divider 2/4/8/16	*/
+#define MX1_PWMC    0x00   /* PWM Control Register */
+#define MX1_PWMS    0x04   /* PWM Sample Register */
+#define MX1_PWMP    0x08   /* PWM Period Register */
 
-#define MAX_DIV			(128 * 16)
-#endif
 
-#if defined CONFIG_MACH_MX27 || defined CONFIG_ARCH_MX31
-#define PWM_VER_2
+/* i.MX27, i.MX31, i.MX35 share the same PWM function block: */
 
-#define PWMCR	0x00	/* PWM Control Register		*/
-#define PWMSR	0x04	/* PWM Status Register		*/
-#define PWMIR	0x08	/* PWM Interrupt Register	*/
-#define PWMSAR	0x0C	/* PWM Sample Register		*/
-#define PWMPR	0x10	/* PWM Period Register		*/
-#define PWMCNR	0x14	/* PWM Counter Register		*/
+#define MX3_PWMCR                 0x00    /* PWM Control Register */
+#define MX3_PWMSAR                0x0C    /* PWM Sample Register */
+#define MX3_PWMPR                 0x10    /* PWM Period Register */
+#define MX3_PWMCR_PRESCALER(x)    (((x - 1) & 0xFFF) << 4)
+#define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16)
+#define MX3_PWMCR_EN              (1 << 0)
 
-#define PWMCR_EN		(1 << 0)		/* Enables/Disables the PWM	*/
-#define PWMCR_REPEAT(x)		(((x) & 0x03) << 1)	/* Sample Repeats		*/
-#define PWMCR_SWR		(1 << 3)		/* Software Reset		*/
-#define PWMCR_PRESCALER(x)	(((x - 1) & 0xFFF) << 4)/* PRESCALER			*/
-#define PWMCR_CLKSRC(x)		(((x) & 0x3) << 16)
-#define PWMCR_CLKSRC_OFF	(0 << 16)
-#define PWMCR_CLKSRC_IPG	(1 << 16)
-#define PWMCR_CLKSRC_IPG_HIGH	(2 << 16)
-#define PWMCR_CLKSRC_CLK32	(3 << 16)
-#define PWMCR_POUTC
-#define PWMCR_HCTR		(1 << 20)		/* Halfword FIFO Data Swapping	*/
-#define PWMCR_BCTR		(1 << 21)		/* Byte FIFO Data Swapping	*/
-#define PWMCR_DBGEN		(1 << 22)		/* Debug Mode			*/
-#define PWMCR_WAITEN		(1 << 23)		/* Wait Mode			*/
-#define PWMCR_DOZEN		(1 << 24)		/* Doze Mode			*/
-#define PWMCR_STOPEN		(1 << 25)		/* Stop Mode			*/
-#define PWMCR_FWM(x)		(((x) & 0x3) << 26)	/* FIFO Water Mark		*/
 
-#define MAX_DIV 4096
-#endif
-
-#define PWMS_SAMPLE(x)		((x) & 0xFFFF)		/* Contains a two-sample word	*/
-#define PWMP_PERIOD(x)		((x) & 0xFFFF)		/* Represents the PWM's period	*/
-#define PWMC_COUNTER(x)		((x) & 0xFFFF)		/* Represents the current count value	*/
 
 struct pwm_device {
 	struct list_head	node;
@@ -91,32 +52,52 @@
 
 int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
 {
-	unsigned long long c;
-	unsigned long period_cycles, duty_cycles, prescale;
-
 	if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
 		return -EINVAL;
 
-	c = clk_get_rate(pwm->clk);
-	c = c * period_ns;
-	do_div(c, 1000000000);
-	period_cycles = c;
+	if (cpu_is_mx27() || cpu_is_mx3()) {
+		unsigned long long c;
+		unsigned long period_cycles, duty_cycles, prescale;
+		c = clk_get_rate(pwm->clk);
+		c = c * period_ns;
+		do_div(c, 1000000000);
+		period_cycles = c;
 
-	prescale = period_cycles / 0x10000 + 1;
+		prescale = period_cycles / 0x10000 + 1;
 
-	period_cycles /= prescale;
-	c = (unsigned long long)period_cycles * duty_ns;
-	do_div(c, period_ns);
-	duty_cycles = c;
+		period_cycles /= prescale;
+		c = (unsigned long long)period_cycles * duty_ns;
+		do_div(c, period_ns);
+		duty_cycles = c;
 
-#ifdef PWM_VER_2
-	writel(duty_cycles, pwm->mmio_base + PWMSAR);
-	writel(period_cycles, pwm->mmio_base + PWMPR);
-	writel(PWMCR_PRESCALER(prescale - 1) | PWMCR_CLKSRC_IPG_HIGH | PWMCR_EN,
-			pwm->mmio_base + PWMCR);
-#elif defined PWM_VER_1
-#error PWM not yet working on MX1 / MX21
-#endif
+		writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR);
+		writel(period_cycles, pwm->mmio_base + MX3_PWMPR);
+		writel(MX3_PWMCR_PRESCALER(prescale - 1) |
+			MX3_PWMCR_CLKSRC_IPG_HIGH | MX3_PWMCR_EN,
+			pwm->mmio_base + MX3_PWMCR);
+	} else if (cpu_is_mx1() || cpu_is_mx21()) {
+		/* The PWM subsystem allows for exact frequencies. However,
+		 * I cannot connect a scope on my device to the PWM line and
+		 * thus cannot provide the program the PWM controller
+		 * exactly. Instead, I'm relying on the fact that the
+		 * Bootloader (u-boot or WinCE+haret) has programmed the PWM
+		 * function group already. So I'll just modify the PWM sample
+		 * register to follow the ratio of duty_ns vs. period_ns
+		 * accordingly.
+		 *
+		 * This is good enought for programming the brightness of
+		 * the LCD backlight.
+		 *
+		 * The real implementation would divide PERCLK[0] first by
+		 * both the prescaler (/1 .. /128) and then by CLKSEL
+		 * (/2 .. /16).
+		 */
+		u32 max = readl(pwm->mmio_base + MX1_PWMP);
+		u32 p = max * duty_ns / period_ns;
+		writel(max - p, pwm->mmio_base + MX1_PWMS);
+	} else {
+		BUG();
+	}
 
 	return 0;
 }
@@ -297,4 +278,3 @@
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-
diff --git a/arch/arm/plat-mxc/time.c b/arch/arm/plat-mxc/time.c
index dab3357..88fb3a5 100644
--- a/arch/arm/plat-mxc/time.c
+++ b/arch/arm/plat-mxc/time.c
@@ -29,22 +29,85 @@
 #include <mach/hardware.h>
 #include <asm/mach/time.h>
 #include <mach/common.h>
-#include <mach/mxc_timer.h>
+
+/* defines common for all i.MX */
+#define MXC_TCTL		0x00
+#define MXC_TCTL_TEN		(1 << 0)
+#define MXC_TPRER		0x04
+
+/* MX1, MX21, MX27 */
+#define MX1_2_TCTL_CLK_PCLK1	(1 << 1)
+#define MX1_2_TCTL_IRQEN	(1 << 4)
+#define MX1_2_TCTL_FRR		(1 << 8)
+#define MX1_2_TCMP		0x08
+#define MX1_2_TCN		0x10
+#define MX1_2_TSTAT		0x14
+
+/* MX21, MX27 */
+#define MX2_TSTAT_CAPT		(1 << 1)
+#define MX2_TSTAT_COMP		(1 << 0)
+
+/* MX31, MX35 */
+#define MX3_TCTL_WAITEN		(1 << 3)
+#define MX3_TCTL_CLK_IPG	(1 << 6)
+#define MX3_TCTL_FRR		(1 << 9)
+#define MX3_IR			0x0c
+#define MX3_TSTAT		0x08
+#define MX3_TSTAT_OF1		(1 << 0)
+#define MX3_TCN			0x24
+#define MX3_TCMP		0x10
 
 static struct clock_event_device clockevent_mxc;
 static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
 
-/* clock source */
+static void __iomem *timer_base;
 
-static cycle_t mxc_get_cycles(struct clocksource *cs)
+static inline void gpt_irq_disable(void)
 {
-	return __raw_readl(TIMER_BASE + MXC_TCN);
+	unsigned int tmp;
+
+	if (cpu_is_mx3())
+		__raw_writel(0, timer_base + MX3_IR);
+	else {
+		tmp = __raw_readl(timer_base + MXC_TCTL);
+		__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL);
+	}
+}
+
+static inline void gpt_irq_enable(void)
+{
+	if (cpu_is_mx3())
+		__raw_writel(1<<0, timer_base + MX3_IR);
+	else {
+		__raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
+			timer_base + MXC_TCTL);
+	}
+}
+
+static void gpt_irq_acknowledge(void)
+{
+	if (cpu_is_mx1())
+		__raw_writel(0, timer_base + MX1_2_TSTAT);
+	if (cpu_is_mx2())
+		__raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP, timer_base + MX1_2_TSTAT);
+	if (cpu_is_mx3())
+		__raw_writel(MX3_TSTAT_OF1, timer_base + MX3_TSTAT);
+}
+
+static cycle_t mx1_2_get_cycles(struct clocksource *cs)
+{
+	return __raw_readl(timer_base + MX1_2_TCN);
+}
+
+static cycle_t mx3_get_cycles(struct clocksource *cs)
+{
+	return __raw_readl(timer_base + MX3_TCN);
 }
 
 static struct clocksource clocksource_mxc = {
 	.name 		= "mxc_timer1",
 	.rating		= 200,
-	.read		= mxc_get_cycles,
+	.read		= mx1_2_get_cycles,
 	.mask		= CLOCKSOURCE_MASK(32),
 	.shift 		= 20,
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
@@ -54,6 +117,9 @@
 {
 	unsigned int c = clk_get_rate(timer_clk);
 
+	if (cpu_is_mx3())
+		clocksource_mxc.read = mx3_get_cycles;
+
 	clocksource_mxc.mult = clocksource_hz2mult(c,
 					clocksource_mxc.shift);
 	clocksource_register(&clocksource_mxc);
@@ -63,15 +129,29 @@
 
 /* clock event */
 
-static int mxc_set_next_event(unsigned long evt,
+static int mx1_2_set_next_event(unsigned long evt,
 			      struct clock_event_device *unused)
 {
 	unsigned long tcmp;
 
-	tcmp = __raw_readl(TIMER_BASE + MXC_TCN) + evt;
-	__raw_writel(tcmp, TIMER_BASE + MXC_TCMP);
+	tcmp = __raw_readl(timer_base + MX1_2_TCN) + evt;
 
-	return (int)(tcmp - __raw_readl(TIMER_BASE + MXC_TCN)) < 0 ?
+	__raw_writel(tcmp, timer_base + MX1_2_TCMP);
+
+	return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ?
+				-ETIME : 0;
+}
+
+static int mx3_set_next_event(unsigned long evt,
+			      struct clock_event_device *unused)
+{
+	unsigned long tcmp;
+
+	tcmp = __raw_readl(timer_base + MX3_TCN) + evt;
+
+	__raw_writel(tcmp, timer_base + MX3_TCMP);
+
+	return (int)(tcmp - __raw_readl(timer_base + MX3_TCN)) < 0 ?
 				-ETIME : 0;
 }
 
@@ -100,8 +180,13 @@
 
 	if (mode != clockevent_mode) {
 		/* Set event time into far-far future */
-		__raw_writel(__raw_readl(TIMER_BASE + MXC_TCN) - 3,
-				TIMER_BASE + MXC_TCMP);
+		if (cpu_is_mx3())
+			__raw_writel(__raw_readl(timer_base + MX3_TCN) - 3,
+					timer_base + MX3_TCMP);
+		else
+			__raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3,
+					timer_base + MX1_2_TCMP);
+
 		/* Clear pending interrupt */
 		gpt_irq_acknowledge();
 	}
@@ -148,7 +233,10 @@
 	struct clock_event_device *evt = &clockevent_mxc;
 	uint32_t tstat;
 
-	tstat = __raw_readl(TIMER_BASE + MXC_TSTAT);
+	if (cpu_is_mx3())
+		tstat = __raw_readl(timer_base + MX3_TSTAT);
+	else
+		tstat = __raw_readl(timer_base + MX1_2_TSTAT);
 
 	gpt_irq_acknowledge();
 
@@ -168,7 +256,7 @@
 	.features	= CLOCK_EVT_FEAT_ONESHOT,
 	.shift		= 32,
 	.set_mode	= mxc_set_mode,
-	.set_next_event	= mxc_set_next_event,
+	.set_next_event	= mx1_2_set_next_event,
 	.rating		= 200,
 };
 
@@ -176,6 +264,9 @@
 {
 	unsigned int c = clk_get_rate(timer_clk);
 
+	if (cpu_is_mx3())
+		clockevent_mxc.set_next_event = mx3_set_next_event;
+
 	clockevent_mxc.mult = div_sc(c, NSEC_PER_SEC,
 					clockevent_mxc.shift);
 	clockevent_mxc.max_delta_ns =
@@ -192,23 +283,47 @@
 
 void __init mxc_timer_init(struct clk *timer_clk)
 {
+	uint32_t tctl_val;
+	int irq;
+
 	clk_enable(timer_clk);
 
+	if (cpu_is_mx1()) {
+#ifdef CONFIG_ARCH_MX1
+		timer_base = IO_ADDRESS(TIM1_BASE_ADDR);
+		irq = TIM1_INT;
+#endif
+	} else if (cpu_is_mx2()) {
+#ifdef CONFIG_ARCH_MX2
+		timer_base = IO_ADDRESS(GPT1_BASE_ADDR);
+		irq = MXC_INT_GPT1;
+#endif
+	} else if (cpu_is_mx3()) {
+#ifdef CONFIG_ARCH_MX3
+		timer_base = IO_ADDRESS(GPT1_BASE_ADDR);
+		irq = MXC_INT_GPT;
+#endif
+	} else
+		BUG();
+
 	/*
 	 * Initialise to a known state (all timers off, and timing reset)
 	 */
-	__raw_writel(0, TIMER_BASE + MXC_TCTL);
-	__raw_writel(0, TIMER_BASE + MXC_TPRER); /* see datasheet note */
 
-	__raw_writel(TCTL_FRR |	/* free running */
-		     TCTL_VAL |	/* set clocksource and arch specific bits */
-		     TCTL_TEN,	/* start the timer */
-		     TIMER_BASE + MXC_TCTL);
+	__raw_writel(0, timer_base + MXC_TCTL);
+	__raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */
+
+	if (cpu_is_mx3())
+		tctl_val = MX3_TCTL_CLK_IPG | MX3_TCTL_FRR | MX3_TCTL_WAITEN | MXC_TCTL_TEN;
+	else
+		tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
+
+	__raw_writel(tctl_val, timer_base + MXC_TCTL);
 
 	/* init and register the timer to the framework */
 	mxc_clocksource_init(timer_clk);
 	mxc_clockevent_init(timer_clk);
 
 	/* Make irqs happen */
-	setup_irq(TIMER_INTERRUPT, &mxc_timer_irq);
+	setup_irq(irq, &mxc_timer_irq);
 }
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 9dd68fa..efe85d0 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -23,6 +23,11 @@
 	select CPU_V7
 	select COMMON_CLKDEV
 
+config ARCH_OMAP4
+	bool "TI OMAP4"
+	select CPU_V7
+	select ARM_GIC
+
 endchoice
 
 comment "OMAP Feature Selections"
@@ -40,7 +45,6 @@
 config OMAP_DEBUG_POWERDOMAIN
 	bool "Emit debug messages from powerdomain layer"
 	depends on ARCH_OMAP2 || ARCH_OMAP3
-	default n
 	help
 	  Say Y here if you want to compile in powerdomain layer
 	  debugging messages for OMAP2/3.   These messages can
@@ -52,7 +56,6 @@
 config OMAP_DEBUG_CLOCKDOMAIN
 	bool "Emit debug messages from clockdomain layer"
 	depends on ARCH_OMAP2 || ARCH_OMAP3
-	default n
 	help
 	  Say Y here if you want to compile in clockdomain layer
 	  debugging messages for OMAP2/3.   These messages can
@@ -110,11 +113,13 @@
 config OMAP_MBOX_FWK
 	tristate "Mailbox framework support"
 	depends on ARCH_OMAP
-	default n
 	help
 	  Say Y here if you want to use OMAP Mailbox framework support for
 	  DSP, IVA1.0 and IVA2 in OMAP1/2/3.
 
+config OMAP_IOMMU
+	tristate
+
 choice
         prompt "System timer"
 	default OMAP_MPU_TIMER
@@ -128,13 +133,13 @@
 
 config OMAP_32K_TIMER
 	bool "Use 32KHz timer"
-	depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
+	depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX || ARCH_OMAP4
 	help
 	  Select this option if you want to enable the OMAP 32KHz timer.
 	  This timer saves power compared to the OMAP_MPU_TIMER, and has
 	  support for no tick during idle. The 32KHz timer provides less
 	  intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
-	  currently only available for OMAP16XX, 24XX and 34XX.
+	  currently only available for OMAP16XX, 24XX, 34XX and OMAP4.
 
 endchoice
 
@@ -149,7 +154,7 @@
 
 config OMAP_DM_TIMER
 	bool "Use dual-mode timer"
-	depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
+	depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX || ARCH_OMAP4
 	help
 	 Select this option if you want to use OMAP Dual-Mode timers.
 
@@ -171,7 +176,7 @@
 
 config OMAP_SERIAL_WAKE
 	bool "Enable wake-up events for serial ports"
-	depends on OMAP_MUX
+	depends on ARCH_OMAP1 && OMAP_MUX
 	default y
 	help
 	  Select this option if you want to have your system wake up
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 04a100c..a832795 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -13,6 +13,7 @@
 obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
+obj-$(CONFIG_OMAP_IOMMU) += iommu.o iovmm.o
 
 obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
 obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index 29efc27..e8c327a 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -36,10 +36,40 @@
  * Standard clock functions defined in include/linux/clk.h
  *-------------------------------------------------------------------------*/
 
+/* This functions is moved to arch/arm/common/clkdev.c. For OMAP4 since
+ * clock framework is not up , it is defined here to avoid rework in
+ * every driver. Also dummy prcm reset function is added */
+
+/* Dummy hooks only for OMAP4.For rest OMAPs, common clkdev is used */
+#if defined(CONFIG_ARCH_OMAP4)
+struct clk *clk_get(struct device *dev, const char *id)
+{
+	return NULL;
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_put);
+
+void omap2_clk_prepare_for_reboot(void)
+{
+}
+EXPORT_SYMBOL(omap2_clk_prepare_for_reboot);
+
+void omap_prcm_arch_reset(char mode)
+{
+}
+EXPORT_SYMBOL(omap_prcm_arch_reset);
+#endif
 int clk_enable(struct clk *clk)
 {
 	unsigned long flags;
 	int ret = 0;
+	if (cpu_is_omap44xx())
+		/* OMAP4 clk framework not supported yet */
+		return 0;
 
 	if (clk == NULL || IS_ERR(clk))
 		return -EINVAL;
@@ -140,6 +170,9 @@
 	unsigned long flags;
 	int ret = -EINVAL;
 
+	if (cpu_is_omap44xx())
+	/* OMAP4 clk framework not supported yet */
+		return 0;
 	if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
 		return ret;
 
@@ -240,13 +273,13 @@
 }
 
 /**
- * clk_init_one - initialize any fields in the struct clk before clk init
+ * clk_preinit - initialize any fields in the struct clk before clk init
  * @clk: struct clk * to initialize
  *
  * Initialize any struct clk fields needed before normal clk initialization
  * can run.  No return value.
  */
-void clk_init_one(struct clk *clk)
+void clk_preinit(struct clk *clk)
 {
 	INIT_LIST_HEAD(&clk->children);
 }
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index 433021f..ebcf006 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -2,6 +2,10 @@
  * linux/arch/arm/plat-omap/common.c
  *
  * Code common to all OMAP machines.
+ * The file is created by Tony Lindgren <tony@atomide.com>
+ *
+ * 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 version 2 as
@@ -11,7 +15,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/pm.h>
 #include <linux/console.h>
 #include <linux/serial.h>
 #include <linux/tty.h>
@@ -175,25 +178,70 @@
  * but systems won't necessarily want to spend resources that way.
  */
 
-#if defined(CONFIG_ARCH_OMAP16XX)
-#define TIMER_32K_SYNCHRONIZED		0xfffbc410
-#elif defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
-#define TIMER_32K_SYNCHRONIZED		(OMAP2_32KSYNCT_BASE + 0x10)
-#endif
+#define OMAP16XX_TIMER_32K_SYNCHRONIZED		0xfffbc410
 
-#ifdef	TIMER_32K_SYNCHRONIZED
+#if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX))
 
 #include <linux/clocksource.h>
 
-static cycle_t omap_32k_read(struct clocksource *cs)
+#ifdef CONFIG_ARCH_OMAP16XX
+static cycle_t omap16xx_32k_read(struct clocksource *cs)
 {
-	return omap_readl(TIMER_32K_SYNCHRONIZED);
+	return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED);
+}
+#else
+#define omap16xx_32k_read	NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2420
+static cycle_t omap2420_32k_read(struct clocksource *cs)
+{
+	return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10);
+}
+#else
+#define omap2420_32k_read	NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+static cycle_t omap2430_32k_read(struct clocksource *cs)
+{
+	return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10);
+}
+#else
+#define omap2430_32k_read	NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+static cycle_t omap34xx_32k_read(struct clocksource *cs)
+{
+	return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10);
+}
+#else
+#define omap34xx_32k_read	NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP4
+static cycle_t omap44xx_32k_read(struct clocksource *cs)
+{
+	return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10);
+}
+#else
+#define omap44xx_32k_read	NULL
+#endif
+
+/*
+ * Kernel assumes that sched_clock can be called early but may not have
+ * things ready yet.
+ */
+static cycle_t omap_32k_read_dummy(struct clocksource *cs)
+{
+	return 0;
 }
 
 static struct clocksource clocksource_32k = {
 	.name		= "32k_counter",
 	.rating		= 250,
-	.read		= omap_32k_read,
+	.read		= omap_32k_read_dummy,
 	.mask		= CLOCKSOURCE_MASK(32),
 	.shift		= 10,
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
@@ -207,7 +255,7 @@
 {
 	unsigned long long ret;
 
-	ret = (unsigned long long)omap_32k_read(&clocksource_32k);
+	ret = (unsigned long long)clocksource_32k.read(&clocksource_32k);
 	ret = (ret * clocksource_32k.mult_orig) >> clocksource_32k.shift;
 	return ret;
 }
@@ -220,6 +268,19 @@
 	if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
 		struct clk *sync_32k_ick;
 
+		if (cpu_is_omap16xx())
+			clocksource_32k.read = omap16xx_32k_read;
+		else if (cpu_is_omap2420())
+			clocksource_32k.read = omap2420_32k_read;
+		else if (cpu_is_omap2430())
+			clocksource_32k.read = omap2430_32k_read;
+		else if (cpu_is_omap34xx())
+			clocksource_32k.read = omap34xx_32k_read;
+		else if (cpu_is_omap44xx())
+			clocksource_32k.read = omap44xx_32k_read;
+		else
+			return -ENODEV;
+
 		sync_32k_ick = clk_get(NULL, "omap_32ksync_ick");
 		if (sync_32k_ick)
 			clk_enable(sync_32k_ick);
@@ -234,15 +295,13 @@
 }
 arch_initcall(omap_init_clocksource_32k);
 
-#endif	/* TIMER_32K_SYNCHRONIZED */
+#endif	/* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */
 
 /* Global address base setup code */
 
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 
-static struct omap_globals *omap2_globals;
-
-static void __init __omap2_set_globals(void)
+static void __init __omap2_set_globals(struct omap_globals *omap2_globals)
 {
 	omap2_set_globals_tap(omap2_globals);
 	omap2_set_globals_sdrc(omap2_globals);
@@ -266,8 +325,7 @@
 
 void __init omap2_set_globals_242x(void)
 {
-	omap2_globals = &omap242x_globals;
-	__omap2_set_globals();
+	__omap2_set_globals(&omap242x_globals);
 }
 #endif
 
@@ -285,8 +343,7 @@
 
 void __init omap2_set_globals_243x(void)
 {
-	omap2_globals = &omap243x_globals;
-	__omap2_set_globals();
+	__omap2_set_globals(&omap243x_globals);
 }
 #endif
 
@@ -304,8 +361,23 @@
 
 void __init omap2_set_globals_343x(void)
 {
-	omap2_globals = &omap343x_globals;
-	__omap2_set_globals();
+	__omap2_set_globals(&omap343x_globals);
+}
+#endif
+
+#if defined(CONFIG_ARCH_OMAP4)
+static struct omap_globals omap4_globals = {
+	.class	= OMAP443X_CLASS,
+	.tap	= OMAP2_IO_ADDRESS(0x4830a000),
+	.ctrl	= OMAP2_IO_ADDRESS(OMAP443X_CTRL_BASE),
+	.prm	= OMAP2_IO_ADDRESS(OMAP4430_PRM_BASE),
+	.cm	= OMAP2_IO_ADDRESS(OMAP4430_CM_BASE),
+};
+
+void __init omap2_set_globals_443x(void)
+{
+	omap2_set_globals_tap(&omap4_globals);
+	omap2_set_globals_control(&omap4_globals);
 }
 #endif
 
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index 87fb7ff..a64b692 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -311,6 +311,8 @@
 		wdt_resources[0].start = 0x49016000; /* WDT2 */
 	else if (cpu_is_omap343x())
 		wdt_resources[0].start = 0x48314000; /* WDT2 */
+	else if (cpu_is_omap44xx())
+		wdt_resources[0].start = 0x4a314000;
 	else
 		return;
 
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 7fc8c04..def14ec 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -10,6 +10,9 @@
  * Merged to support both OMAP1 and OMAP2 by Tony Lindgren <tony@atomide.com>
  * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc.
  *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
  * Support functions for the OMAP internal DMA channels.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -310,41 +313,62 @@
 
 void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color)
 {
-	u16 w;
-
 	BUG_ON(omap_dma_in_1510_mode());
 
+	if (cpu_class_is_omap1()) {
+		u16 w;
+
+		w = dma_read(CCR2(lch));
+		w &= ~0x03;
+
+		switch (mode) {
+		case OMAP_DMA_CONSTANT_FILL:
+			w |= 0x01;
+			break;
+		case OMAP_DMA_TRANSPARENT_COPY:
+			w |= 0x02;
+			break;
+		case OMAP_DMA_COLOR_DIS:
+			break;
+		default:
+			BUG();
+		}
+		dma_write(w, CCR2(lch));
+
+		w = dma_read(LCH_CTRL(lch));
+		w &= ~0x0f;
+		/* Default is channel type 2D */
+		if (mode) {
+			dma_write((u16)color, COLOR_L(lch));
+			dma_write((u16)(color >> 16), COLOR_U(lch));
+			w |= 1;		/* Channel type G */
+		}
+		dma_write(w, LCH_CTRL(lch));
+	}
+
 	if (cpu_class_is_omap2()) {
-		REVISIT_24XX();
-		return;
-	}
+		u32 val;
 
-	w = dma_read(CCR2(lch));
-	w &= ~0x03;
+		val = dma_read(CCR(lch));
+		val &= ~((1 << 17) | (1 << 16));
 
-	switch (mode) {
-	case OMAP_DMA_CONSTANT_FILL:
-		w |= 0x01;
-		break;
-	case OMAP_DMA_TRANSPARENT_COPY:
-		w |= 0x02;
-		break;
-	case OMAP_DMA_COLOR_DIS:
-		break;
-	default:
-		BUG();
-	}
-	dma_write(w, CCR2(lch));
+		switch (mode) {
+		case OMAP_DMA_CONSTANT_FILL:
+			val |= 1 << 16;
+			break;
+		case OMAP_DMA_TRANSPARENT_COPY:
+			val |= 1 << 17;
+			break;
+		case OMAP_DMA_COLOR_DIS:
+			break;
+		default:
+			BUG();
+		}
+		dma_write(val, CCR(lch));
 
-	w = dma_read(LCH_CTRL(lch));
-	w &= ~0x0f;
-	/* Default is channel type 2D */
-	if (mode) {
-		dma_write((u16)color, COLOR_L(lch));
-		dma_write((u16)(color >> 16), COLOR_U(lch));
-		w |= 1;		/* Channel type G */
+		color &= 0xffffff;
+		dma_write(color, COLOR(lch));
 	}
-	dma_write(w, LCH_CTRL(lch));
 }
 EXPORT_SYMBOL(omap_set_dma_color_mode);
 
@@ -851,7 +875,7 @@
 	}
 	l = dma_read(CCR(lch));
 	l &= ~((1 << 6) | (1 << 26));
-	if (cpu_is_omap2430() || cpu_is_omap34xx())
+	if (cpu_is_omap2430() || cpu_is_omap34xx() ||  cpu_is_omap44xx())
 		l |= ((read_prio & 0x1) << 6) | ((write_prio & 0x1) << 26);
 	else
 		l |= ((read_prio & 0x1) << 6);
@@ -1199,7 +1223,7 @@
  * 	     Failure: -EINVAL/-ENOMEM
  */
 int omap_request_dma_chain(int dev_id, const char *dev_name,
-			   void (*callback) (int chain_id, u16 ch_status,
+			   void (*callback) (int lch, u16 ch_status,
 					     void *data),
 			   int *chain_id, int no_of_chans, int chain_mode,
 			   struct omap_dma_channel_params params)
@@ -1823,7 +1847,8 @@
 #define omap1_dma_irq_handler	NULL
 #endif
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+			defined(CONFIG_ARCH_OMAP4)
 
 static int omap2_dma_handle_ch(int ch)
 {
@@ -2318,6 +2343,9 @@
 	} else if (cpu_is_omap34xx()) {
 		omap_dma_base = IO_ADDRESS(OMAP34XX_DMA4_BASE);
 		dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
+	} else if (cpu_is_omap44xx()) {
+		omap_dma_base = IO_ADDRESS(OMAP44XX_DMA4_BASE);
+		dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
 	} else {
 		pr_err("DMA init failed for unsupported omap\n");
 		return -ENODEV;
@@ -2416,12 +2444,18 @@
 		}
 	}
 
-	if (cpu_is_omap2430() || cpu_is_omap34xx())
+	if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx())
 		omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE,
 				DMA_DEFAULT_FIFO_DEPTH, 0);
 
-	if (cpu_class_is_omap2())
-		setup_irq(INT_24XX_SDMA_IRQ0, &omap24xx_dma_irq);
+	if (cpu_class_is_omap2()) {
+		int irq;
+		if (cpu_is_omap44xx())
+			irq = INT_44XX_SDMA_IRQ0;
+		else
+			irq = INT_24XX_SDMA_IRQ0;
+		setup_irq(irq, &omap24xx_dma_irq);
+	}
 
 	/* FIXME: Update LCD DMA to work on 24xx */
 	if (cpu_class_is_omap1()) {
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 55bb996..7f50b61 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -7,6 +7,9 @@
  * OMAP2 support by Juha Yrjola
  * API improvements and OMAP2 clock framework support by Timo Teras
  *
+ * 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
@@ -150,7 +153,8 @@
 struct omap_dm_timer {
 	unsigned long phys_base;
 	int irq;
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+			defined(CONFIG_ARCH_OMAP4)
 	struct clk *iclk, *fclk;
 #endif
 	void __iomem *io_base;
@@ -169,6 +173,9 @@
 #define omap3_dm_timers			NULL
 #define omap3_dm_source_names		NULL
 #define omap3_dm_source_clocks		NULL
+#define omap4_dm_timers			NULL
+#define omap4_dm_source_names		NULL
+#define omap4_dm_source_clocks		NULL
 
 static struct omap_dm_timer omap1_dm_timers[] = {
 	{ .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 },
@@ -191,6 +198,9 @@
 #define omap3_dm_timers			NULL
 #define omap3_dm_source_names		NULL
 #define omap3_dm_source_clocks		NULL
+#define omap4_dm_timers			NULL
+#define omap4_dm_source_names		NULL
+#define omap4_dm_source_clocks		NULL
 
 static struct omap_dm_timer omap2_dm_timers[] = {
 	{ .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
@@ -214,7 +224,7 @@
 	NULL
 };
 
-static struct clk **omap2_dm_source_clocks[3];
+static struct clk *omap2_dm_source_clocks[3];
 static const int dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
 
 #elif defined(CONFIG_ARCH_OMAP3)
@@ -225,6 +235,9 @@
 #define omap2_dm_timers			NULL
 #define omap2_dm_source_names		NULL
 #define omap2_dm_source_clocks		NULL
+#define omap4_dm_timers			NULL
+#define omap4_dm_source_names		NULL
+#define omap4_dm_source_clocks		NULL
 
 static struct omap_dm_timer omap3_dm_timers[] = {
 	{ .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
@@ -247,9 +260,43 @@
 	NULL
 };
 
-static struct clk **omap3_dm_source_clocks[2];
+static struct clk *omap3_dm_source_clocks[2];
 static const int dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
 
+#elif defined(CONFIG_ARCH_OMAP4)
+
+#define omap_dm_clk_enable(x)		clk_enable(x)
+#define omap_dm_clk_disable(x)		clk_disable(x)
+#define omap1_dm_timers			NULL
+#define omap2_dm_timers			NULL
+#define omap2_dm_source_names		NULL
+#define omap2_dm_source_clocks		NULL
+#define omap3_dm_timers			NULL
+#define omap3_dm_source_names		NULL
+#define omap3_dm_source_clocks		NULL
+
+static struct omap_dm_timer omap4_dm_timers[] = {
+	{ .phys_base = 0x4a318000, .irq = INT_44XX_GPTIMER1 },
+	{ .phys_base = 0x48032000, .irq = INT_44XX_GPTIMER2 },
+	{ .phys_base = 0x48034000, .irq = INT_44XX_GPTIMER3 },
+	{ .phys_base = 0x48036000, .irq = INT_44XX_GPTIMER4 },
+	{ .phys_base = 0x40138000, .irq = INT_44XX_GPTIMER5 },
+	{ .phys_base = 0x4013a000, .irq = INT_44XX_GPTIMER6 },
+	{ .phys_base = 0x4013a000, .irq = INT_44XX_GPTIMER7 },
+	{ .phys_base = 0x4013e000, .irq = INT_44XX_GPTIMER8 },
+	{ .phys_base = 0x4803e000, .irq = INT_44XX_GPTIMER9 },
+	{ .phys_base = 0x48086000, .irq = INT_44XX_GPTIMER10 },
+	{ .phys_base = 0x48088000, .irq = INT_44XX_GPTIMER11 },
+	{ .phys_base = 0x4a320000, .irq = INT_44XX_GPTIMER12 },
+};
+static const char *omap4_dm_source_names[] __initdata = {
+	"sys_ck",
+	"omap_32k_fck",
+	NULL
+};
+static struct clk *omap4_dm_source_clocks[2];
+static const int dm_timer_count = ARRAY_SIZE(omap4_dm_timers);
+
 #else
 
 #error OMAP architecture not supported!
@@ -257,7 +304,7 @@
 #endif
 
 static struct omap_dm_timer *dm_timers;
-static char **dm_source_names;
+static const char **dm_source_names;
 static struct clk **dm_source_clocks;
 
 static spinlock_t dm_timer_lock;
@@ -459,7 +506,8 @@
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 
-#elif defined(CONFIG_ARCH_OMAP2) || defined (CONFIG_ARCH_OMAP3)
+#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+				defined(CONFIG_ARCH_OMAP4)
 
 struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
 {
@@ -705,12 +753,16 @@
 		dm_timers = omap1_dm_timers;
 	else if (cpu_is_omap24xx()) {
 		dm_timers = omap2_dm_timers;
-		dm_source_names = (char **)omap2_dm_source_names;
-		dm_source_clocks = (struct clk **)omap2_dm_source_clocks;
+		dm_source_names = omap2_dm_source_names;
+		dm_source_clocks = omap2_dm_source_clocks;
 	} else if (cpu_is_omap34xx()) {
 		dm_timers = omap3_dm_timers;
-		dm_source_names = (char **)omap3_dm_source_names;
-		dm_source_clocks = (struct clk **)omap3_dm_source_clocks;
+		dm_source_names = omap3_dm_source_names;
+		dm_source_clocks = omap3_dm_source_clocks;
+	} else if (cpu_is_omap44xx()) {
+		dm_timers = omap4_dm_timers;
+		dm_source_names = omap4_dm_source_names;
+		dm_source_clocks = omap4_dm_source_clocks;
 	}
 
 	if (cpu_class_is_omap2())
@@ -723,7 +775,8 @@
 	for (i = 0; i < dm_timer_count; i++) {
 		timer = &dm_timers[i];
 		timer->io_base = IO_ADDRESS(timer->phys_base);
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+					defined(CONFIG_ARCH_OMAP4)
 		if (cpu_class_is_omap2()) {
 			char clk_name[16];
 			sprintf(clk_name, "gpt%d_ick", i + 1);
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index ee0b21f..7fd89ba 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -6,6 +6,9 @@
  * Copyright (C) 2003-2005 Nokia Corporation
  * Written by Juha Yrjölä <juha.yrjola@nokia.com>
  *
+ * 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 version 2 as
  * published by the Free Software Foundation.
@@ -146,6 +149,16 @@
 #define OMAP34XX_GPIO5_BASE		IO_ADDRESS(0x49056000)
 #define OMAP34XX_GPIO6_BASE		IO_ADDRESS(0x49058000)
 
+/*
+ * OMAP44XX  specific GPIO registers
+ */
+#define OMAP44XX_GPIO1_BASE             IO_ADDRESS(0x4a310000)
+#define OMAP44XX_GPIO2_BASE             IO_ADDRESS(0x48055000)
+#define OMAP44XX_GPIO3_BASE             IO_ADDRESS(0x48057000)
+#define OMAP44XX_GPIO4_BASE             IO_ADDRESS(0x48059000)
+#define OMAP44XX_GPIO5_BASE             IO_ADDRESS(0x4805B000)
+#define OMAP44XX_GPIO6_BASE             IO_ADDRESS(0x4805D000)
+
 #define OMAP_MPUIO_VBASE		IO_ADDRESS(OMAP_MPUIO_BASE)
 
 struct gpio_bank {
@@ -153,11 +166,13 @@
 	u16 irq;
 	u16 virtual_irq_start;
 	int method;
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) ||  \
+		defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4)
 	u32 suspend_wakeup;
 	u32 saved_wakeup;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+			defined(CONFIG_ARCH_OMAP4)
 	u32 non_wakeup_gpios;
 	u32 enabled_non_wakeup_gpios;
 
@@ -251,6 +266,24 @@
 
 #endif
 
+#ifdef CONFIG_ARCH_OMAP4
+static struct gpio_bank gpio_bank_44xx[6] = {
+	{ OMAP44XX_GPIO1_BASE, INT_44XX_GPIO_BANK1, IH_GPIO_BASE,	\
+		METHOD_GPIO_24XX },
+	{ OMAP44XX_GPIO2_BASE, INT_44XX_GPIO_BANK2, IH_GPIO_BASE + 32,	\
+		METHOD_GPIO_24XX },
+	{ OMAP44XX_GPIO3_BASE, INT_44XX_GPIO_BANK3, IH_GPIO_BASE + 64,	\
+		METHOD_GPIO_24XX },
+	{ OMAP44XX_GPIO4_BASE, INT_44XX_GPIO_BANK4, IH_GPIO_BASE + 96,	\
+		METHOD_GPIO_24XX },
+	{ OMAP44XX_GPIO5_BASE, INT_44XX_GPIO_BANK5, IH_GPIO_BASE + 128, \
+		METHOD_GPIO_24XX },
+	{ OMAP44XX_GPIO6_BASE, INT_44XX_GPIO_BANK6, IH_GPIO_BASE + 160, \
+		METHOD_GPIO_24XX },
+};
+
+#endif
+
 static struct gpio_bank *gpio_bank;
 static int gpio_bank_count;
 
@@ -273,7 +306,7 @@
 	}
 	if (cpu_is_omap24xx())
 		return &gpio_bank[gpio >> 5];
-	if (cpu_is_omap34xx())
+	if (cpu_is_omap34xx() || cpu_is_omap44xx())
 		return &gpio_bank[gpio >> 5];
 	BUG();
 	return NULL;
@@ -285,7 +318,7 @@
 		return gpio & 0x1f;
 	if (cpu_is_omap24xx())
 		return gpio & 0x1f;
-	if (cpu_is_omap34xx())
+	if (cpu_is_omap34xx() || cpu_is_omap44xx())
 		return gpio & 0x1f;
 	return gpio & 0x0f;
 }
@@ -307,7 +340,7 @@
 		return 0;
 	if (cpu_is_omap24xx() && gpio < 128)
 		return 0;
-	if (cpu_is_omap34xx() && gpio < 192)
+	if ((cpu_is_omap34xx() || cpu_is_omap44xx()) && gpio < 192)
 		return 0;
 	return -1;
 }
@@ -353,7 +386,8 @@
 		reg += OMAP850_GPIO_DIR_CONTROL;
 		break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+			defined(CONFIG_ARCH_OMAP4)
 	case METHOD_GPIO_24XX:
 		reg += OMAP24XX_GPIO_OE;
 		break;
@@ -425,7 +459,8 @@
 			l &= ~(1 << gpio);
 		break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+			defined(CONFIG_ARCH_OMAP4)
 	case METHOD_GPIO_24XX:
 		if (enable)
 			reg += OMAP24XX_GPIO_SETDATAOUT;
@@ -476,7 +511,8 @@
 		reg += OMAP850_GPIO_DATA_INPUT;
 		break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+			defined(CONFIG_ARCH_OMAP4)
 	case METHOD_GPIO_24XX:
 		reg += OMAP24XX_GPIO_DATAIN;
 		break;
@@ -520,7 +556,7 @@
 	else
 		goto done;
 
-	if (cpu_is_omap34xx()) {
+	if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
 		if (enable)
 			clk_enable(bank->dbck);
 		else
@@ -550,7 +586,8 @@
 }
 EXPORT_SYMBOL(omap_set_gpio_debounce_time);
 
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+				defined(CONFIG_ARCH_OMAP4)
 static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
 						int trigger)
 {
@@ -660,7 +697,8 @@
 			goto bad;
 		break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+				defined(CONFIG_ARCH_OMAP4)
 	case METHOD_GPIO_24XX:
 		set_24xx_gpio_triggering(bank, gpio, trigger);
 		break;
@@ -745,7 +783,8 @@
 		reg += OMAP850_GPIO_INT_STATUS;
 		break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+				defined(CONFIG_ARCH_OMAP4)
 	case METHOD_GPIO_24XX:
 		reg += OMAP24XX_GPIO_IRQSTATUS1;
 		break;
@@ -814,7 +853,8 @@
 		inv = 1;
 		break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+				defined(CONFIG_ARCH_OMAP4)
 	case METHOD_GPIO_24XX:
 		reg += OMAP24XX_GPIO_IRQENABLE1;
 		mask = 0xffffffff;
@@ -887,7 +927,8 @@
 			l |= gpio_mask;
 		break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+		defined(CONFIG_ARCH_OMAP4)
 	case METHOD_GPIO_24XX:
 		if (enable)
 			reg += OMAP24XX_GPIO_SETIRQENABLE1;
@@ -932,7 +973,8 @@
 		spin_unlock_irqrestore(&bank->lock, flags);
 		return 0;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+				defined(CONFIG_ARCH_OMAP4)
 	case METHOD_GPIO_24XX:
 		if (bank->non_wakeup_gpios & (1 << gpio)) {
 			printk(KERN_ERR "Unable to modify wakeup on "
@@ -1017,7 +1059,8 @@
 		__raw_writel(1 << offset, reg);
 	}
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+				defined(CONFIG_ARCH_OMAP4)
 	if (bank->method == METHOD_GPIO_24XX) {
 		/* Disable wake-up during idle for dynamic tick */
 		void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
@@ -1069,7 +1112,8 @@
 	if (bank->method == METHOD_GPIO_850)
 		isr_reg = bank->base + OMAP850_GPIO_INT_STATUS;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+				defined(CONFIG_ARCH_OMAP4)
 	if (bank->method == METHOD_GPIO_24XX)
 		isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1;
 #endif
@@ -1346,7 +1390,7 @@
 /*---------------------------------------------------------------------*/
 
 static int initialized;
-#if !defined(CONFIG_ARCH_OMAP3)
+#if !(defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4))
 static struct clk * gpio_ick;
 #endif
 
@@ -1359,7 +1403,7 @@
 static struct clk * gpio5_fck;
 #endif
 
-#if defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
 static struct clk *gpio_iclks[OMAP34XX_NR_GPIOS];
 #endif
 
@@ -1419,8 +1463,8 @@
 	}
 #endif
 
-#if defined(CONFIG_ARCH_OMAP3)
-	if (cpu_is_omap34xx()) {
+#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
+	if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
 		for (i = 0; i < OMAP34XX_NR_GPIOS; i++) {
 			sprintf(clk_name, "gpio%d_ick", i + 1);
 			gpio_iclks[i] = clk_get(NULL, clk_name);
@@ -1497,6 +1541,17 @@
 			(rev >> 4) & 0x0f, rev & 0x0f);
 	}
 #endif
+#ifdef CONFIG_ARCH_OMAP4
+	if (cpu_is_omap44xx()) {
+		int rev;
+
+		gpio_bank_count = OMAP34XX_NR_GPIOS;
+		gpio_bank = gpio_bank_44xx;
+		rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
+		printk(KERN_INFO "OMAP44xx GPIO hardware version %d.%d\n",
+			(rev >> 4) & 0x0f, rev & 0x0f);
+	}
+#endif
 	for (i = 0; i < gpio_bank_count; i++) {
 		int j, gpio_count = 16;
 
@@ -1520,7 +1575,8 @@
 			gpio_count = 32; /* 730 has 32-bit GPIOs */
 		}
 
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+				defined(CONFIG_ARCH_OMAP4)
 		if (bank->method == METHOD_GPIO_24XX) {
 			static const u32 non_wakeup_gpios[] = {
 				0xe203ffc0, 0x08700040
@@ -1577,7 +1633,7 @@
 		set_irq_chained_handler(bank->irq, gpio_irq_handler);
 		set_irq_data(bank->irq, bank);
 
-		if (cpu_is_omap34xx()) {
+		if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
 			sprintf(clk_name, "gpio%d_dbck", i + 1);
 			bank->dbck = clk_get(NULL, clk_name);
 			if (IS_ERR(bank->dbck))
@@ -1599,7 +1655,8 @@
 	return 0;
 }
 
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || \
+		defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4)
 static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg)
 {
 	int i;
@@ -1622,7 +1679,8 @@
 			wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
 			break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+				defined(CONFIG_ARCH_OMAP4)
 		case METHOD_GPIO_24XX:
 			wake_status = bank->base + OMAP24XX_GPIO_WAKE_EN;
 			wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
@@ -1663,7 +1721,8 @@
 			wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
 			break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+			defined(CONFIG_ARCH_OMAP4)
 		case METHOD_GPIO_24XX:
 			wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
 			wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
@@ -1695,7 +1754,8 @@
 
 #endif
 
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+				defined(CONFIG_ARCH_OMAP4)
 
 static int workaround_enabled;
 
@@ -1711,7 +1771,8 @@
 
 		if (!(bank->enabled_non_wakeup_gpios))
 			continue;
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+				defined(CONFIG_ARCH_OMAP4)
 		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);
@@ -1720,7 +1781,8 @@
 		bank->saved_risingdetect = l2;
 		l1 &= ~bank->enabled_non_wakeup_gpios;
 		l2 &= ~bank->enabled_non_wakeup_gpios;
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+			defined(CONFIG_ARCH_OMAP4)
 		__raw_writel(l1, bank->base + OMAP24XX_GPIO_FALLINGDETECT);
 		__raw_writel(l2, bank->base + OMAP24XX_GPIO_RISINGDETECT);
 #endif
@@ -1745,7 +1807,8 @@
 
 		if (!(bank->enabled_non_wakeup_gpios))
 			continue;
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+			defined(CONFIG_ARCH_OMAP4)
 		__raw_writel(bank->saved_fallingdetect,
 				 bank->base + OMAP24XX_GPIO_FALLINGDETECT);
 		__raw_writel(bank->saved_risingdetect,
@@ -1755,14 +1818,16 @@
 		 * 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. */
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+			defined(CONFIG_ARCH_OMAP4)
 		l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
 #endif
 		l ^= bank->saved_datain;
 		l &= bank->non_wakeup_gpios;
 		if (l) {
 			u32 old0, old1;
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+			defined(CONFIG_ARCH_OMAP4)
 			old0 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
 			old1 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
 			__raw_writel(old0 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT0);
@@ -1798,7 +1863,8 @@
 
 	mpuio_init();
 
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || \
+		defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4)
 	if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
 		if (ret == 0) {
 			ret = sysdev_class_register(&omap_gpio_sysclass);
@@ -1887,7 +1953,7 @@
 
 			irqstat = irq_desc[irq].status;
 #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) ||	\
-		defined(CONFIG_ARCH_OMAP34XX)
+		defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4)
 			if (is_in && ((bank->suspend_wakeup & mask)
 					|| irqstat & IRQ_TYPE_SENSE_MASK)) {
 				char	*trigger = NULL;
diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c
index a303071..8b84839 100644
--- a/arch/arm/plat-omap/i2c.c
+++ b/arch/arm/plat-omap/i2c.c
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2007 Nokia Corporation.
  *
- * Contact: Jarkko Nikula <jarkko.nikula@nokia.com>
+ * Contact: Jarkko Nikula <jhnikula@gmail.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/arch/arm/plat-omap/include/mach/clock.h b/arch/arm/plat-omap/include/mach/clock.h
index 073a2c5..f9f65e1 100644
--- a/arch/arm/plat-omap/include/mach/clock.h
+++ b/arch/arm/plat-omap/include/mach/clock.h
@@ -22,7 +22,8 @@
 	void			(*disable)(struct clk *);
 };
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+		defined(CONFIG_ARCH_OMAP4)
 
 struct clksel_rate {
 	u32			val;
@@ -51,7 +52,7 @@
 	u8			max_divider;
 	u32			max_tolerance;
 	u16			max_multiplier;
-#  if defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
 	u8			modes;
 	void __iomem		*autoidle_reg;
 	void __iomem		*idlest_reg;
@@ -83,7 +84,8 @@
 	void			(*init)(struct clk *);
 	__u8			enable_bit;
 	__s8			usecount;
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+		defined(CONFIG_ARCH_OMAP4)
 	u8			fixed_div;
 	void __iomem		*clksel_reg;
 	u32			clksel_mask;
@@ -119,7 +121,7 @@
 extern unsigned int mpurate;
 
 extern int clk_init(struct clk_functions *custom_clocks);
-extern void clk_init_one(struct clk *clk);
+extern void clk_preinit(struct clk *clk);
 extern int clk_register(struct clk *clk);
 extern void clk_reparent(struct clk *child, struct clk *parent);
 extern void clk_unregister(struct clk *clk);
diff --git a/arch/arm/plat-omap/include/mach/common.h b/arch/arm/plat-omap/include/mach/common.h
index 0ecf36d..fdeab42 100644
--- a/arch/arm/plat-omap/include/mach/common.h
+++ b/arch/arm/plat-omap/include/mach/common.h
@@ -33,8 +33,6 @@
 
 extern void omap_map_common_io(void);
 extern struct sys_timer omap_timer;
-extern void omap_serial_init(void);
-extern void omap_serial_enable_clocks(int enable);
 #if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
 extern int omap_register_i2c_bus(int bus_id, u32 clkrate,
 				 struct i2c_board_info const *info,
@@ -62,6 +60,7 @@
 void omap2_set_globals_242x(void);
 void omap2_set_globals_243x(void);
 void omap2_set_globals_343x(void);
+void omap2_set_globals_443x(void);
 
 /* These get called from omap2_set_globals_xxxx(), do not call these */
 void omap2_set_globals_tap(struct omap_globals *);
diff --git a/arch/arm/plat-omap/include/mach/control.h b/arch/arm/plat-omap/include/mach/control.h
index 269147f..8140dbc 100644
--- a/arch/arm/plat-omap/include/mach/control.h
+++ b/arch/arm/plat-omap/include/mach/control.h
@@ -1,9 +1,9 @@
 /*
  * arch/arm/plat-omap/include/mach/control.h
  *
- * OMAP2/3 System Control Module definitions
+ * OMAP2/3/4 System Control Module definitions
  *
- * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2009 Texas Instruments, Inc.
  * Copyright (C) 2007-2008 Nokia Corporation
  *
  * Written by Paul Walmsley
@@ -144,6 +144,10 @@
 #define OMAP343X_CONTROL_PBIAS_LITE	(OMAP2_CONTROL_GENERAL + 0x02b0)
 #define OMAP343X_CONTROL_TEMP_SENSOR	(OMAP2_CONTROL_GENERAL + 0x02b4)
 
+/* 34xx D2D idle-related pins, handled by PM core */
+#define OMAP3_PADCONF_SAD2D_MSTANDBY   0x250
+#define OMAP3_PADCONF_SAD2D_IDLEACK    0x254
+
 /*
  * REVISIT: This list of registers is not comprehensive - there are more
  * that should be added.
@@ -189,8 +193,18 @@
 #define OMAP2_PBIASLITEPWRDNZ0		(1 << 1)
 #define OMAP2_PBIASLITEVMODE0		(1 << 0)
 
+/* CONTROL_IVA2_BOOTMOD bits */
+#define OMAP3_IVA2_BOOTMOD_SHIFT	0
+#define OMAP3_IVA2_BOOTMOD_MASK		(0xf << 0)
+#define OMAP3_IVA2_BOOTMOD_IDLE		(0x1 << 0)
+
+/* CONTROL_PADCONF_X bits */
+#define OMAP3_PADCONF_WAKEUPEVENT0	(1 << 15)
+#define OMAP3_PADCONF_WAKEUPENABLE0	(1 << 14)
+
 #ifndef __ASSEMBLY__
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+		defined(CONFIG_ARCH_OMAP4)
 extern void __iomem *omap_ctrl_base_get(void);
 extern u8 omap_ctrl_readb(u16 offset);
 extern u16 omap_ctrl_readw(u16 offset);
diff --git a/arch/arm/plat-omap/include/mach/cpu.h b/arch/arm/plat-omap/include/mach/cpu.h
index 98b1442..fc60c4e 100644
--- a/arch/arm/plat-omap/include/mach/cpu.h
+++ b/arch/arm/plat-omap/include/mach/cpu.h
@@ -5,8 +5,12 @@
  *
  * Copyright (C) 2004, 2008 Nokia Corporation
  *
+ * Copyright (C) 2009 Texas Instruments.
+ *
  * Written by Tony Lindgren <tony.lindgren@nokia.com>
  *
+ * Added OMAP4 specific defines - 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
@@ -155,6 +159,8 @@
 #define cpu_is_omap243x()		0
 #define cpu_is_omap34xx()		0
 #define cpu_is_omap343x()		0
+#define cpu_is_omap44xx()		0
+#define cpu_is_omap443x()		0
 
 #if defined(MULTI_OMAP1)
 # if defined(CONFIG_ARCH_OMAP730)
@@ -348,12 +354,21 @@
 # define cpu_is_omap3430()		is_omap3430()
 #endif
 
+# if defined(CONFIG_ARCH_OMAP4)
+# undef cpu_is_omap44xx
+# undef cpu_is_omap443x
+# define cpu_is_omap44xx()		1
+# define cpu_is_omap443x()		1
+# endif
+
 /* Macros to detect if we have OMAP1 or OMAP2 */
 #define cpu_class_is_omap1()	(cpu_is_omap7xx() || cpu_is_omap15xx() || \
 				cpu_is_omap16xx())
-#define cpu_class_is_omap2()	(cpu_is_omap24xx() || cpu_is_omap34xx())
+#define cpu_class_is_omap2()	(cpu_is_omap24xx() || cpu_is_omap34xx() || \
+				cpu_is_omap44xx())
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+			defined(CONFIG_ARCH_OMAP4)
 
 /* Various silicon revisions for omap2 */
 #define OMAP242X_CLASS		0x24200024
@@ -370,6 +385,8 @@
 #define OMAP3430_REV_ES3_0	0x34303034
 #define OMAP3430_REV_ES3_1	0x34304034
 
+#define OMAP443X_CLASS		0x44300034
+
 /*
  * omap_chip bits
  *
diff --git a/arch/arm/plat-omap/include/mach/debug-macro.S b/arch/arm/plat-omap/include/mach/debug-macro.S
index 1b11f5c..ac24050 100644
--- a/arch/arm/plat-omap/include/mach/debug-macro.S
+++ b/arch/arm/plat-omap/include/mach/debug-macro.S
@@ -36,7 +36,7 @@
 		add	\rx, \rx, #0x00004000	@ UART 3
 #endif
 
-#elif	CONFIG_ARCH_OMAP3
+#elif defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
 		moveq	\rx, #0x48000000	@ physical base address
 		movne	\rx, #0xd8000000	@ virtual base
 		orr	\rx, \rx, #0x0006a000
diff --git a/arch/arm/plat-omap/include/mach/dma.h b/arch/arm/plat-omap/include/mach/dma.h
index 54fe966..8c1eae8 100644
--- a/arch/arm/plat-omap/include/mach/dma.h
+++ b/arch/arm/plat-omap/include/mach/dma.h
@@ -48,6 +48,7 @@
 /* Hardware registers for omap2 and omap3 */
 #define OMAP24XX_DMA4_BASE		(L4_24XX_BASE + 0x56000)
 #define OMAP34XX_DMA4_BASE		(L4_34XX_BASE + 0x56000)
+#define OMAP44XX_DMA4_BASE		(L4_44XX_BASE + 0x56000)
 
 #define OMAP_DMA4_REVISION		0x00
 #define OMAP_DMA4_GCR			0x78
@@ -144,6 +145,7 @@
 #define OMAP_DMA4_CSSA_U(n)		0
 #define OMAP_DMA4_CDSA_L(n)		0
 #define OMAP_DMA4_CDSA_U(n)		0
+#define OMAP1_DMA_COLOR(n)		0
 
 /*----------------------------------------------------------------------------*/
 
@@ -531,7 +533,7 @@
 /* Chaining APIs */
 #ifndef CONFIG_ARCH_OMAP1
 extern int omap_request_dma_chain(int dev_id, const char *dev_name,
-				  void (*callback) (int chain_id, u16 ch_status,
+				  void (*callback) (int lch, u16 ch_status,
 						    void *data),
 				  int *chain_id, int no_of_chans,
 				  int chain_mode,
diff --git a/arch/arm/plat-omap/include/mach/entry-macro.S b/arch/arm/plat-omap/include/mach/entry-macro.S
index 2276f89..56426ed 100644
--- a/arch/arm/plat-omap/include/mach/entry-macro.S
+++ b/arch/arm/plat-omap/include/mach/entry-macro.S
@@ -3,6 +3,9 @@
  *
  * 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.
@@ -10,6 +13,7 @@
 #include <mach/hardware.h>
 #include <mach/io.h>
 #include <mach/irqs.h>
+#include <asm/hardware/gic.h>
 
 #if defined(CONFIG_ARCH_OMAP1)
 
@@ -56,15 +60,21 @@
 		.endm
 
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+			defined(CONFIG_ARCH_OMAP4)
 
-#if defined(CONFIG_ARCH_OMAP24XX)
 #include <mach/omap24xx.h>
-#endif
-#if defined(CONFIG_ARCH_OMAP34XX)
 #include <mach/omap34xx.h>
-#endif
 
+/* REVISIT: This should be set dynamically if CONFIG_MULTI_OMAP2 is selected */
+#if defined(CONFIG_ARCH_OMAP2420) || defined(CONFIG_ARCH_OMAP2430)
+#define OMAP2_VA_IC_BASE		IO_ADDRESS(OMAP24XX_IC_BASE)
+#elif defined(CONFIG_ARCH_OMAP34XX)
+#define OMAP2_VA_IC_BASE		IO_ADDRESS(OMAP34XX_IC_BASE)
+#endif
+#if defined(CONFIG_ARCH_OMAP4)
+#include <mach/omap44xx.h>
+#endif
 #define INTCPS_SIR_IRQ_OFFSET	0x0040		/* Active interrupt offset */
 #define	ACTIVEIRQ_MASK		0x7f		/* Active interrupt bits */
 
@@ -77,6 +87,7 @@
 		.macro  arch_ret_to_user, tmp1, tmp2
 		.endm
 
+#ifndef CONFIG_ARCH_OMAP4
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 		ldr	\base, =OMAP2_VA_IC_BASE
 		ldr	\irqnr, [\base, #0x98] /* IRQ pending reg 1 */
@@ -92,6 +103,68 @@
 		and	\irqnr, \irqnr, #ACTIVEIRQ_MASK /* Clear spurious bits */
 
 		.endm
+#else
+		/*
+		 * The interrupt numbering scheme is defined in the
+		 * interrupt controller spec.  To wit:
+		 *
+		 * Interrupts 0-15 are IPI
+		 * 16-28 are reserved
+		 * 29-31 are local.  We allow 30 to be used for the watchdog.
+		 * 32-1020 are global
+		 * 1021-1022 are reserved
+		 * 1023 is "spurious" (no interrupt)
+		 *
+		 * For now, we ignore all local interrupts so only return an
+		 * interrupt if it's between 30 and 1020.  The test_for_ipi
+		 * routine below will pick up on IPIs.
+		 * A simple read from the controller will tell us the number
+		 * of the highest priority enabled interrupt.
+		 * We then just need to check whether it is in the
+		 * valid range for an IRQ (30-1020 inclusive).
+		 */
+		.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+		ldr     \base, =OMAP44XX_VA_GIC_CPU_BASE
+		ldr     \irqstat, [\base, #GIC_CPU_INTACK]
+
+		ldr     \tmp, =1021
+
+		bic     \irqnr, \irqstat, #0x1c00
+
+		cmp     \irqnr, #29
+		cmpcc   \irqnr, \irqnr
+		cmpne   \irqnr, \tmp
+		cmpcs   \irqnr, \irqnr
+		.endm
+
+		/* We assume that irqstat (the raw value of the IRQ acknowledge
+		 * register) is preserved from the macro above.
+		 * If there is an IPI, we immediately signal end of interrupt
+		 * on the controller, since this requires the original irqstat
+		 * value which we won't easily be able to recreate later.
+		 */
+
+		.macro test_for_ipi, irqnr, irqstat, base, tmp
+		bic	\irqnr, \irqstat, #0x1c00
+		cmp	\irqnr, #16
+		it	cc
+		strcc	\irqstat, [\base, #GIC_CPU_EOI]
+		it	cs
+		cmpcs	\irqnr, \irqnr
+		.endm
+
+		/* As above, this assumes that irqstat and base are preserved */
+
+		.macro test_for_ltirq, irqnr, irqstat, base, tmp
+		bic	\irqnr, \irqstat, #0x1c00
+		mov 	\tmp, #0
+		cmp	\irqnr, #29
+		itt	eq
+		moveq	\tmp, #1
+		streq	\irqstat, [\base, #GIC_CPU_EOI]
+		cmp	\tmp, #0
+		.endm
+#endif
 
 		.macro	irq_prio_table
 		.endm
diff --git a/arch/arm/plat-omap/include/mach/gpmc-smc91x.h b/arch/arm/plat-omap/include/mach/gpmc-smc91x.h
new file mode 100644
index 0000000..b64fbee
--- /dev/null
+++ b/arch/arm/plat-omap/include/mach/gpmc-smc91x.h
@@ -0,0 +1,42 @@
+/*
+ * arch/arm/plat-omap/include/mach/gpmc-smc91x.h
+ *
+ * Copyright (C) 2009 Nokia 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_ARCH_OMAP_GPMC_SMC91X_H__
+
+#define GPMC_TIMINGS_SMC91C96	(1 << 4)
+#define GPMC_MUX_ADD_DATA	(1 << 5) /* GPMC_CONFIG1_MUXADDDATA */
+#define GPMC_READ_MON		(1 << 6) /* GPMC_CONFIG1_WAIT_READ_MON */
+#define GPMC_WRITE_MON		(1 << 7) /* GPMC_CONFIG1_WAIT_WRITE_MON */
+
+struct omap_smc91x_platform_data {
+	int	cs;
+	int	gpio_irq;
+	int	gpio_pwrdwn;
+	int	gpio_reset;
+	int	wait_pin;	/* Optional GPMC_CONFIG1_WAITPINSELECT */
+	u32	flags;
+	int	(*retime)(void);
+};
+
+#if defined(CONFIG_SMC91X) || \
+	defined(CONFIG_SMC91X_MODULE)
+
+extern void gpmc_smc91x_init(struct omap_smc91x_platform_data *d);
+
+#else
+
+#define board_smc91x_data	NULL
+
+static inline void gpmc_smc91x_init(struct omap_smc91x_platform_data *d)
+{
+}
+
+#endif
+#endif
diff --git a/arch/arm/plat-omap/include/mach/hardware.h b/arch/arm/plat-omap/include/mach/hardware.h
index 3dc423e..26c1fbf 100644
--- a/arch/arm/plat-omap/include/mach/hardware.h
+++ b/arch/arm/plat-omap/include/mach/hardware.h
@@ -285,5 +285,6 @@
 #include "omap16xx.h"
 #include "omap24xx.h"
 #include "omap34xx.h"
+#include "omap44xx.h"
 
 #endif	/* __ASM_ARCH_OMAP_HARDWARE_H */
diff --git a/arch/arm/plat-omap/include/mach/hwa742.h b/arch/arm/plat-omap/include/mach/hwa742.h
index 577f492..886248d 100644
--- a/arch/arm/plat-omap/include/mach/hwa742.h
+++ b/arch/arm/plat-omap/include/mach/hwa742.h
@@ -2,10 +2,6 @@
 #define _HWA742_H
 
 struct hwa742_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;
 };
 
diff --git a/arch/arm/plat-omap/include/mach/io.h b/arch/arm/plat-omap/include/mach/io.h
index 0610d7e..3b28147 100644
--- a/arch/arm/plat-omap/include/mach/io.h
+++ b/arch/arm/plat-omap/include/mach/io.h
@@ -6,6 +6,9 @@
  * 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
@@ -157,6 +160,40 @@
 #define DSP_MMU_34XX_VIRT	0xe2000000
 #define DSP_MMU_34XX_SIZE	SZ_4K
 
+
+#elif defined(CONFIG_ARCH_OMAP4)
+/* We map both L3 and L4 on OMAP4 */
+#define L3_44XX_PHYS		L3_44XX_BASE
+#define L3_44XX_VIRT		0xd4000000
+#define L3_44XX_SIZE		SZ_1M
+
+#define L4_44XX_PHYS		L4_44XX_BASE
+#define L4_44XX_VIRT		0xda000000
+#define L4_44XX_SIZE		SZ_4M
+
+
+#define L4_WK_44XX_PHYS		L4_WK_44XX_BASE
+#define L4_WK_44XX_VIRT		0xda300000
+#define L4_WK_44XX_SIZE		SZ_1M
+
+#define L4_PER_44XX_PHYS	L4_PER_44XX_BASE
+#define L4_PER_44XX_VIRT	0xd8000000
+#define L4_PER_44XX_SIZE	SZ_4M
+
+#define L4_EMU_44XX_PHYS	L4_EMU_44XX_BASE
+#define L4_EMU_44XX_VIRT	0xe4000000
+#define L4_EMU_44XX_SIZE	SZ_64M
+
+#define OMAP44XX_GPMC_PHYS	OMAP44XX_GPMC_BASE
+#define OMAP44XX_GPMC_VIRT	0xe0000000
+#define OMAP44XX_GPMC_SIZE	SZ_1M
+
+
+#define IO_OFFSET		0x90000000
+#define __IO_ADDRESS(pa)	((pa) + IO_OFFSET)/* Works for L3 and L4 */
+#define __OMAP2_IO_ADDRESS(pa)	((pa) + IO_OFFSET)/* Works for L3 and L4 */
+#define io_v2p(va)		((va) - IO_OFFSET)/* Works for L3 and L4 */
+
 #endif
 
 #define IO_ADDRESS(pa)		IOMEM(__IO_ADDRESS(pa))
diff --git a/arch/arm/plat-omap/include/mach/iommu.h b/arch/arm/plat-omap/include/mach/iommu.h
new file mode 100644
index 0000000..769b00b
--- /dev/null
+++ b/arch/arm/plat-omap/include/mach/iommu.h
@@ -0,0 +1,168 @@
+/*
+ * omap iommu: main structures
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@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.
+ */
+
+#ifndef __MACH_IOMMU_H
+#define __MACH_IOMMU_H
+
+struct iotlb_entry {
+	u32 da;
+	u32 pa;
+	u32 pgsz, prsvd, valid;
+	union {
+		u16 ap;
+		struct {
+			u32 endian, elsz, mixed;
+		};
+	};
+};
+
+struct iommu {
+	const char	*name;
+	struct module	*owner;
+	struct clk	*clk;
+	void __iomem	*regbase;
+	struct device	*dev;
+
+	unsigned int	refcount;
+	struct mutex	iommu_lock;	/* global for this whole object */
+
+	/*
+	 * We don't change iopgd for a situation like pgd for a task,
+	 * but share it globally for each iommu.
+	 */
+	u32		*iopgd;
+	spinlock_t	page_table_lock; /* protect iopgd */
+
+	int		nr_tlb_entries;
+
+	struct list_head	mmap;
+	struct mutex		mmap_lock; /* protect mmap */
+
+	int (*isr)(struct iommu *obj);
+
+	void *ctx; /* iommu context: registres saved area */
+};
+
+struct cr_regs {
+	union {
+		struct {
+			u16 cam_l;
+			u16 cam_h;
+		};
+		u32 cam;
+	};
+	union {
+		struct {
+			u16 ram_l;
+			u16 ram_h;
+		};
+		u32 ram;
+	};
+};
+
+struct iotlb_lock {
+	short base;
+	short vict;
+};
+
+/* architecture specific functions */
+struct iommu_functions {
+	unsigned long	version;
+
+	int (*enable)(struct iommu *obj);
+	void (*disable)(struct iommu *obj);
+	u32 (*fault_isr)(struct iommu *obj, u32 *ra);
+
+	void (*tlb_read_cr)(struct iommu *obj, struct cr_regs *cr);
+	void (*tlb_load_cr)(struct iommu *obj, struct cr_regs *cr);
+
+	struct cr_regs *(*alloc_cr)(struct iommu *obj, struct iotlb_entry *e);
+	int (*cr_valid)(struct cr_regs *cr);
+	u32 (*cr_to_virt)(struct cr_regs *cr);
+	void (*cr_to_e)(struct cr_regs *cr, struct iotlb_entry *e);
+	ssize_t (*dump_cr)(struct iommu *obj, struct cr_regs *cr, char *buf);
+
+	u32 (*get_pte_attr)(struct iotlb_entry *e);
+
+	void (*save_ctx)(struct iommu *obj);
+	void (*restore_ctx)(struct iommu *obj);
+	ssize_t (*dump_ctx)(struct iommu *obj, char *buf);
+};
+
+struct iommu_platform_data {
+	const char *name;
+	const char *clk_name;
+	const int nr_tlb_entries;
+};
+
+#if defined(CONFIG_ARCH_OMAP1)
+#error "iommu for this processor not implemented yet"
+#else
+#include <mach/iommu2.h>
+#endif
+
+/*
+ * utilities for super page(16MB, 1MB, 64KB and 4KB)
+ */
+
+#define iopgsz_max(bytes)			\
+	(((bytes) >= SZ_16M) ? SZ_16M :		\
+	 ((bytes) >= SZ_1M)  ? SZ_1M  :		\
+	 ((bytes) >= SZ_64K) ? SZ_64K :		\
+	 ((bytes) >= SZ_4K)  ? SZ_4K  :	0)
+
+#define bytes_to_iopgsz(bytes)				\
+	(((bytes) == SZ_16M) ? MMU_CAM_PGSZ_16M :	\
+	 ((bytes) == SZ_1M)  ? MMU_CAM_PGSZ_1M  :	\
+	 ((bytes) == SZ_64K) ? MMU_CAM_PGSZ_64K :	\
+	 ((bytes) == SZ_4K)  ? MMU_CAM_PGSZ_4K  : -1)
+
+#define iopgsz_to_bytes(iopgsz)				\
+	(((iopgsz) == MMU_CAM_PGSZ_16M)	? SZ_16M :	\
+	 ((iopgsz) == MMU_CAM_PGSZ_1M)	? SZ_1M  :	\
+	 ((iopgsz) == MMU_CAM_PGSZ_64K)	? SZ_64K :	\
+	 ((iopgsz) == MMU_CAM_PGSZ_4K)	? SZ_4K  : 0)
+
+#define iopgsz_ok(bytes) (bytes_to_iopgsz(bytes) >= 0)
+
+/*
+ * global functions
+ */
+extern u32 iommu_arch_version(void);
+
+extern void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e);
+extern u32 iotlb_cr_to_virt(struct cr_regs *cr);
+
+extern int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e);
+extern void flush_iotlb_page(struct iommu *obj, u32 da);
+extern void flush_iotlb_range(struct iommu *obj, u32 start, u32 end);
+extern void flush_iotlb_all(struct iommu *obj);
+
+extern int iopgtable_store_entry(struct iommu *obj, struct iotlb_entry *e);
+extern size_t iopgtable_clear_entry(struct iommu *obj, u32 iova);
+
+extern struct iommu *iommu_get(const char *name);
+extern void iommu_put(struct iommu *obj);
+
+extern void iommu_save_ctx(struct iommu *obj);
+extern void iommu_restore_ctx(struct iommu *obj);
+
+extern int install_iommu_arch(const struct iommu_functions *ops);
+extern void uninstall_iommu_arch(const struct iommu_functions *ops);
+
+extern int foreach_iommu_device(void *data,
+				int (*fn)(struct device *, void *));
+
+extern ssize_t iommu_dump_ctx(struct iommu *obj, char *buf);
+extern size_t dump_tlb_entries(struct iommu *obj, char *buf);
+
+#endif /* __MACH_IOMMU_H */
diff --git a/arch/arm/plat-omap/include/mach/iommu2.h b/arch/arm/plat-omap/include/mach/iommu2.h
new file mode 100644
index 0000000..10ad05f
--- /dev/null
+++ b/arch/arm/plat-omap/include/mach/iommu2.h
@@ -0,0 +1,96 @@
+/*
+ * omap iommu: omap2 architecture specific definitions
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@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.
+ */
+
+#ifndef __MACH_IOMMU2_H
+#define __MACH_IOMMU2_H
+
+#include <linux/io.h>
+
+/*
+ * MMU Register offsets
+ */
+#define MMU_REVISION		0x00
+#define MMU_SYSCONFIG		0x10
+#define MMU_SYSSTATUS		0x14
+#define MMU_IRQSTATUS		0x18
+#define MMU_IRQENABLE		0x1c
+#define MMU_WALKING_ST		0x40
+#define MMU_CNTL		0x44
+#define MMU_FAULT_AD		0x48
+#define MMU_TTB			0x4c
+#define MMU_LOCK		0x50
+#define MMU_LD_TLB		0x54
+#define MMU_CAM			0x58
+#define MMU_RAM			0x5c
+#define MMU_GFLUSH		0x60
+#define MMU_FLUSH_ENTRY		0x64
+#define MMU_READ_CAM		0x68
+#define MMU_READ_RAM		0x6c
+#define MMU_EMU_FAULT_AD	0x70
+
+#define MMU_REG_SIZE		256
+
+/*
+ * MMU Register bit definitions
+ */
+#define MMU_LOCK_BASE_SHIFT	10
+#define MMU_LOCK_BASE_MASK	(0x1f << MMU_LOCK_BASE_SHIFT)
+#define MMU_LOCK_BASE(x)	\
+	((x & MMU_LOCK_BASE_MASK) >> MMU_LOCK_BASE_SHIFT)
+
+#define MMU_LOCK_VICT_SHIFT	4
+#define MMU_LOCK_VICT_MASK	(0x1f << MMU_LOCK_VICT_SHIFT)
+#define MMU_LOCK_VICT(x)	\
+	((x & MMU_LOCK_VICT_MASK) >> MMU_LOCK_VICT_SHIFT)
+
+#define MMU_CAM_VATAG_SHIFT	12
+#define MMU_CAM_VATAG_MASK \
+	((~0UL >> MMU_CAM_VATAG_SHIFT) << MMU_CAM_VATAG_SHIFT)
+#define MMU_CAM_P		(1 << 3)
+#define MMU_CAM_V		(1 << 2)
+#define MMU_CAM_PGSZ_MASK	3
+#define MMU_CAM_PGSZ_1M		(0 << 0)
+#define MMU_CAM_PGSZ_64K	(1 << 0)
+#define MMU_CAM_PGSZ_4K		(2 << 0)
+#define MMU_CAM_PGSZ_16M	(3 << 0)
+
+#define MMU_RAM_PADDR_SHIFT	12
+#define MMU_RAM_PADDR_MASK \
+	((~0UL >> MMU_RAM_PADDR_SHIFT) << MMU_RAM_PADDR_SHIFT)
+#define MMU_RAM_ENDIAN_SHIFT	9
+#define MMU_RAM_ENDIAN_MASK	(1 << MMU_RAM_ENDIAN_SHIFT)
+#define MMU_RAM_ENDIAN_BIG	(1 << MMU_RAM_ENDIAN_SHIFT)
+#define MMU_RAM_ENDIAN_LITTLE	(0 << MMU_RAM_ENDIAN_SHIFT)
+#define MMU_RAM_ELSZ_SHIFT	7
+#define MMU_RAM_ELSZ_MASK	(3 << MMU_RAM_ELSZ_SHIFT)
+#define MMU_RAM_ELSZ_8		(0 << MMU_RAM_ELSZ_SHIFT)
+#define MMU_RAM_ELSZ_16		(1 << MMU_RAM_ELSZ_SHIFT)
+#define MMU_RAM_ELSZ_32		(2 << MMU_RAM_ELSZ_SHIFT)
+#define MMU_RAM_ELSZ_NONE	(3 << MMU_RAM_ELSZ_SHIFT)
+#define MMU_RAM_MIXED_SHIFT	6
+#define MMU_RAM_MIXED_MASK	(1 << MMU_RAM_MIXED_SHIFT)
+#define MMU_RAM_MIXED		MMU_RAM_MIXED_MASK
+
+/*
+ * register accessors
+ */
+static inline u32 iommu_read_reg(struct iommu *obj, size_t offs)
+{
+	return __raw_readl(obj->regbase + offs);
+}
+
+static inline void iommu_write_reg(struct iommu *obj, u32 val, size_t offs)
+{
+	__raw_writel(val, obj->regbase + offs);
+}
+
+#endif /* __MACH_IOMMU2_H */
diff --git a/arch/arm/plat-omap/include/mach/iovmm.h b/arch/arm/plat-omap/include/mach/iovmm.h
new file mode 100644
index 0000000..bdc7ce5
--- /dev/null
+++ b/arch/arm/plat-omap/include/mach/iovmm.h
@@ -0,0 +1,94 @@
+/*
+ * omap iommu: simple virtual address space management
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@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.
+ */
+
+#ifndef __IOMMU_MMAP_H
+#define __IOMMU_MMAP_H
+
+struct iovm_struct {
+	struct iommu		*iommu;	/* iommu object which this belongs to */
+	u32			da_start; /* area definition */
+	u32			da_end;
+	u32			flags; /* IOVMF_: see below */
+	struct list_head	list; /* linked in ascending order */
+	const struct sg_table	*sgt; /* keep 'page' <-> 'da' mapping */
+	void			*va; /* mpu side mapped address */
+};
+
+/*
+ * IOVMF_FLAGS: attribute for iommu virtual memory area(iovma)
+ *
+ * lower 16 bit is used for h/w and upper 16 bit is for s/w.
+ */
+#define IOVMF_SW_SHIFT		16
+#define IOVMF_HW_SIZE		(1 << IOVMF_SW_SHIFT)
+#define IOVMF_HW_MASK		(IOVMF_HW_SIZE - 1)
+#define IOVMF_SW_MASK		(~IOVMF_HW_MASK)UL
+
+/*
+ * iovma: h/w flags derived from cam and ram attribute
+ */
+#define IOVMF_CAM_MASK		(~((1 << 10) - 1))
+#define IOVMF_RAM_MASK		(~IOVMF_CAM_MASK)
+
+#define IOVMF_PGSZ_MASK		(3 << 0)
+#define IOVMF_PGSZ_1M		MMU_CAM_PGSZ_1M
+#define IOVMF_PGSZ_64K		MMU_CAM_PGSZ_64K
+#define IOVMF_PGSZ_4K		MMU_CAM_PGSZ_4K
+#define IOVMF_PGSZ_16M		MMU_CAM_PGSZ_16M
+
+#define IOVMF_ENDIAN_MASK	(1 << 9)
+#define IOVMF_ENDIAN_BIG	MMU_RAM_ENDIAN_BIG
+#define IOVMF_ENDIAN_LITTLE	MMU_RAM_ENDIAN_LITTLE
+
+#define IOVMF_ELSZ_MASK		(3 << 7)
+#define IOVMF_ELSZ_8		MMU_RAM_ELSZ_8
+#define IOVMF_ELSZ_16		MMU_RAM_ELSZ_16
+#define IOVMF_ELSZ_32		MMU_RAM_ELSZ_32
+#define IOVMF_ELSZ_NONE		MMU_RAM_ELSZ_NONE
+
+#define IOVMF_MIXED_MASK	(1 << 6)
+#define IOVMF_MIXED		MMU_RAM_MIXED
+
+/*
+ * iovma: s/w flags, used for mapping and umapping internally.
+ */
+#define IOVMF_MMIO		(1 << IOVMF_SW_SHIFT)
+#define IOVMF_ALLOC		(2 << IOVMF_SW_SHIFT)
+#define IOVMF_ALLOC_MASK	(3 << IOVMF_SW_SHIFT)
+
+/* "superpages" is supported just with physically linear pages */
+#define IOVMF_DISCONT		(1 << (2 + IOVMF_SW_SHIFT))
+#define IOVMF_LINEAR		(2 << (2 + IOVMF_SW_SHIFT))
+#define IOVMF_LINEAR_MASK	(3 << (2 + IOVMF_SW_SHIFT))
+
+#define IOVMF_DA_FIXED		(1 << (4 + IOVMF_SW_SHIFT))
+#define IOVMF_DA_ANON		(2 << (4 + IOVMF_SW_SHIFT))
+#define IOVMF_DA_MASK		(3 << (4 + IOVMF_SW_SHIFT))
+
+
+extern struct iovm_struct *find_iovm_area(struct iommu *obj, u32 da);
+extern u32 iommu_vmap(struct iommu *obj, u32 da,
+			const struct sg_table *sgt, u32 flags);
+extern struct sg_table *iommu_vunmap(struct iommu *obj, u32 da);
+extern u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes,
+			   u32 flags);
+extern void iommu_vfree(struct iommu *obj, const u32 da);
+extern u32 iommu_kmap(struct iommu *obj, u32 da, u32 pa, size_t bytes,
+			u32 flags);
+extern void iommu_kunmap(struct iommu *obj, u32 da);
+extern u32 iommu_kmalloc(struct iommu *obj, u32 da, size_t bytes,
+			   u32 flags);
+extern void iommu_kfree(struct iommu *obj, u32 da);
+
+extern void *da_to_va(struct iommu *obj, u32 da);
+
+#endif /* __IOMMU_MMAP_H */
diff --git a/arch/arm/plat-omap/include/mach/irqs.h b/arch/arm/plat-omap/include/mach/irqs.h
index 7f57ee6..fb7cb77 100644
--- a/arch/arm/plat-omap/include/mach/irqs.h
+++ b/arch/arm/plat-omap/include/mach/irqs.h
@@ -4,6 +4,9 @@
  *  Copyright (C) Greg Lonnon 2001
  *  Updated for OMAP-1610 by Tony Lindgren <tony@atomide.com>
  *
+ * 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
@@ -422,6 +425,94 @@
 
 #define	INT_34XX_BENCH_MPU_EMUL	3
 
+
+#define IRQ_GIC_START		32
+#define INT_44XX_LOCALTIMER_IRQ	29
+#define INT_44XX_LOCALWDT_IRQ	30
+
+#define INT_44XX_BENCH_MPU_EMUL	(3 + IRQ_GIC_START)
+#define INT_44XX_SSM_ABORT_IRQ	(6 + IRQ_GIC_START)
+#define INT_44XX_SYS_NIRQ	(7 + IRQ_GIC_START)
+#define INT_44XX_D2D_FW_IRQ	(8 + IRQ_GIC_START)
+#define INT_44XX_PRCM_MPU_IRQ	(11 + IRQ_GIC_START)
+#define INT_44XX_SDMA_IRQ0	(12 + IRQ_GIC_START)
+#define INT_44XX_SDMA_IRQ1	(13 + IRQ_GIC_START)
+#define INT_44XX_SDMA_IRQ2	(14 + IRQ_GIC_START)
+#define INT_44XX_SDMA_IRQ3	(15 + IRQ_GIC_START)
+#define INT_44XX_ISS_IRQ	(24 + IRQ_GIC_START)
+#define INT_44XX_DSS_IRQ	(25 + IRQ_GIC_START)
+#define INT_44XX_MAIL_U0_MPU	(26 + IRQ_GIC_START)
+#define INT_44XX_DSP_MMU	(28 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER1	(37 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER2	(38 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER3	(39 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER4	(40 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER5	(41 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER6	(42 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER7	(43 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER8	(44 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER9	(45 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER10	(46 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER11	(47 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER12	(95 + IRQ_GIC_START)
+#define INT_44XX_SHA1MD5	(51 + IRQ_GIC_START)
+#define INT_44XX_I2C1_IRQ	(56 + IRQ_GIC_START)
+#define INT_44XX_I2C2_IRQ	(57 + IRQ_GIC_START)
+#define INT_44XX_HDQ_IRQ	(58 + IRQ_GIC_START)
+#define INT_44XX_SPI1_IRQ	(65 + IRQ_GIC_START)
+#define INT_44XX_SPI2_IRQ	(66 + IRQ_GIC_START)
+#define INT_44XX_HSI_1_IRQ0	(67 + IRQ_GIC_START)
+#define INT_44XX_HSI_2_IRQ1	(68 + IRQ_GIC_START)
+#define INT_44XX_HSI_1_DMAIRQ	(71 + IRQ_GIC_START)
+#define INT_44XX_UART1_IRQ	(72 + IRQ_GIC_START)
+#define INT_44XX_UART2_IRQ	(73 + IRQ_GIC_START)
+#define INT_44XX_UART3_IRQ	(74 + IRQ_GIC_START)
+#define INT_44XX_UART4_IRQ	(70 + IRQ_GIC_START)
+#define INT_44XX_USB_IRQ_NISO	(76 + IRQ_GIC_START)
+#define INT_44XX_USB_IRQ_ISO	(77 + IRQ_GIC_START)
+#define INT_44XX_USB_IRQ_HGEN	(78 + IRQ_GIC_START)
+#define INT_44XX_USB_IRQ_HSOF	(79 + IRQ_GIC_START)
+#define INT_44XX_USB_IRQ_OTG	(80 + IRQ_GIC_START)
+#define INT_44XX_MCBSP4_IRQ_TX	(81 + IRQ_GIC_START)
+#define INT_44XX_MCBSP4_IRQ_RX	(82 + IRQ_GIC_START)
+#define INT_44XX_MMC_IRQ	(83 + IRQ_GIC_START)
+#define INT_44XX_MMC2_IRQ	(86 + IRQ_GIC_START)
+#define INT_44XX_MCBSP2_IRQ_TX	(89 + IRQ_GIC_START)
+#define INT_44XX_MCBSP2_IRQ_RX	(90 + IRQ_GIC_START)
+#define INT_44XX_SPI3_IRQ	(91 + IRQ_GIC_START)
+#define INT_44XX_SPI5_IRQ	(69 + IRQ_GIC_START)
+
+#define INT_44XX_MCBSP5_IRQ	(16 + IRQ_GIC_START)
+#define INT_44xX_MCBSP1_IRQ	(17 + IRQ_GIC_START)
+#define INT_44XX_MCBSP2_IRQ	(22 + IRQ_GIC_START)
+#define INT_44XX_MCBSP3_IRQ	(23 + IRQ_GIC_START)
+#define INT_44XX_MCBSP4_IRQ	(27 + IRQ_GIC_START)
+#define INT_44XX_HS_USB_MC	(92 + IRQ_GIC_START)
+#define INT_44XX_HS_USB_DMA	(93 + IRQ_GIC_START)
+
+#define INT_44XX_GPIO_BANK1	(29 + IRQ_GIC_START)
+#define INT_44XX_GPIO_BANK2	(30 + IRQ_GIC_START)
+#define INT_44XX_GPIO_BANK3	(31 + IRQ_GIC_START)
+#define INT_44XX_GPIO_BANK4	(32 + IRQ_GIC_START)
+#define INT_44XX_GPIO_BANK5	(33 + IRQ_GIC_START)
+#define INT_44XX_GPIO_BANK6	(34 + IRQ_GIC_START)
+#define INT_44XX_USIM_IRQ	(35 + IRQ_GIC_START)
+#define INT_44XX_WDT3_IRQ	(36 + IRQ_GIC_START)
+#define INT_44XX_SPI4_IRQ	(48 + IRQ_GIC_START)
+#define INT_44XX_SHA1MD52_IRQ	(49 + IRQ_GIC_START)
+#define INT_44XX_FPKA_READY_IRQ	(50 + IRQ_GIC_START)
+#define INT_44XX_SHA1MD51_IRQ	(51 + IRQ_GIC_START)
+#define INT_44XX_RNG_IRQ	(52 + IRQ_GIC_START)
+#define INT_44XX_I2C3_IRQ	(61 + IRQ_GIC_START)
+#define INT_44XX_FPKA_ERROR_IRQ	(64 + IRQ_GIC_START)
+#define INT_44XX_PBIAS_IRQ	(75 + IRQ_GIC_START)
+#define INT_44XX_OHCI_IRQ	(76 + IRQ_GIC_START)
+#define INT_44XX_EHCI_IRQ	(77 + IRQ_GIC_START)
+#define INT_44XX_TLL_IRQ	(78 + IRQ_GIC_START)
+#define INT_44XX_PARTHASH_IRQ	(79 + IRQ_GIC_START)
+#define INT_44XX_MMC3_IRQ	(94 + IRQ_GIC_START)
+
+
 /* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730/850) and
  * 16 MPUIO lines */
 #define OMAP_MAX_GPIO_LINES	192
@@ -467,6 +558,7 @@
 
 #ifndef __ASSEMBLY__
 extern void omap_init_irq(void);
+extern int omap_irq_pending(void);
 #endif
 
 #include <mach/hardware.h>
diff --git a/arch/arm/plat-omap/include/mach/keypad.h b/arch/arm/plat-omap/include/mach/keypad.h
index 232923a..45ea3ae 100644
--- a/arch/arm/plat-omap/include/mach/keypad.h
+++ b/arch/arm/plat-omap/include/mach/keypad.h
@@ -33,7 +33,11 @@
 #define GROUP_3		(3 << 16)
 #define GROUP_MASK	GROUP_3
 
+#define KEY_PERSISTENT		0x00800000
+#define KEYNUM_MASK		0x00EFFFFF
 #define KEY(col, row, val) (((col) << 28) | ((row) << 24) | (val))
+#define PERSISTENT_KEY(col, row) (((col) << 28) | ((row) << 24) | \
+						KEY_PERSISTENT)
 
 #endif
 
diff --git a/arch/arm/plat-omap/include/mach/memory.h b/arch/arm/plat-omap/include/mach/memory.h
index 99ed564..9ad41dc 100644
--- a/arch/arm/plat-omap/include/mach/memory.h
+++ b/arch/arm/plat-omap/include/mach/memory.h
@@ -38,7 +38,8 @@
  */
 #if defined(CONFIG_ARCH_OMAP1)
 #define PHYS_OFFSET		UL(0x10000000)
-#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+			defined(CONFIG_ARCH_OMAP4)
 #define PHYS_OFFSET		UL(0x80000000)
 #endif
 
diff --git a/arch/arm/plat-omap/include/mach/omap24xx.h b/arch/arm/plat-omap/include/mach/omap24xx.h
index 24335d4..696edfc 100644
--- a/arch/arm/plat-omap/include/mach/omap24xx.h
+++ b/arch/arm/plat-omap/include/mach/omap24xx.h
@@ -85,23 +85,5 @@
 #define OMAP24XX_SEC_AES_BASE	(OMAP24XX_SEC_BASE + 0x6000)
 #define OMAP24XX_SEC_PKA_BASE	(OMAP24XX_SEC_BASE + 0x8000)
 
-#if defined(CONFIG_ARCH_OMAP2420)
-
-#define OMAP2_32KSYNCT_BASE	OMAP2420_32KSYNCT_BASE
-#define OMAP2_PRCM_BASE		OMAP2420_PRCM_BASE
-#define OMAP2_CM_BASE		OMAP2420_CM_BASE
-#define OMAP2_PRM_BASE		OMAP2420_PRM_BASE
-#define OMAP2_VA_IC_BASE	IO_ADDRESS(OMAP24XX_IC_BASE)
-
-#elif defined(CONFIG_ARCH_OMAP2430)
-
-#define OMAP2_32KSYNCT_BASE	OMAP2430_32KSYNCT_BASE
-#define OMAP2_PRCM_BASE		OMAP2430_PRCM_BASE
-#define OMAP2_CM_BASE		OMAP2430_CM_BASE
-#define OMAP2_PRM_BASE		OMAP2430_PRM_BASE
-#define OMAP2_VA_IC_BASE	IO_ADDRESS(OMAP24XX_IC_BASE)
-
-#endif
-
 #endif /* __ASM_ARCH_OMAP24XX_H */
 
diff --git a/arch/arm/plat-omap/include/mach/omap34xx.h b/arch/arm/plat-omap/include/mach/omap34xx.h
index ab64015..f8d186a 100644
--- a/arch/arm/plat-omap/include/mach/omap34xx.h
+++ b/arch/arm/plat-omap/include/mach/omap34xx.h
@@ -31,13 +31,9 @@
 
 #define L4_34XX_BASE		0x48000000
 #define L4_WK_34XX_BASE		0x48300000
-#define L4_WK_OMAP_BASE		L4_WK_34XX_BASE
 #define L4_PER_34XX_BASE	0x49000000
-#define L4_PER_OMAP_BASE	L4_PER_34XX_BASE
 #define L4_EMU_34XX_BASE	0x54000000
-#define L4_EMU_BASE		L4_EMU_34XX_BASE
 #define L3_34XX_BASE		0x68000000
-#define L3_OMAP_BASE		L3_34XX_BASE
 
 #define OMAP3430_32KSYNCT_BASE	0x48320000
 #define OMAP3430_CM_BASE	0x48004800
@@ -83,15 +79,6 @@
 
 #define OMAP34XX_MAILBOX_BASE		(L4_34XX_BASE + 0x94000)
 
-#if defined(CONFIG_ARCH_OMAP3430)
-
-#define OMAP2_32KSYNCT_BASE		OMAP3430_32KSYNCT_BASE
-#define OMAP2_CM_BASE			OMAP3430_CM_BASE
-#define OMAP2_PRM_BASE			OMAP3430_PRM_BASE
-#define OMAP2_VA_IC_BASE		IO_ADDRESS(OMAP34XX_IC_BASE)
-
-#endif
-
 #define OMAP34XX_DSP_BASE	0x58000000
 #define OMAP34XX_DSP_MEM_BASE	(OMAP34XX_DSP_BASE + 0x0)
 #define OMAP34XX_DSP_IPI_BASE	(OMAP34XX_DSP_BASE + 0x1000000)
diff --git a/arch/arm/plat-omap/include/mach/omap44xx.h b/arch/arm/plat-omap/include/mach/omap44xx.h
new file mode 100644
index 0000000..15dec7f
--- /dev/null
+++ b/arch/arm/plat-omap/include/mach/omap44xx.h
@@ -0,0 +1,46 @@
+/*:
+ * Address mappings and base address for OMAP4 interconnects
+ * and peripherals.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * Author: 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARCH_OMAP44XX_H
+#define __ASM_ARCH_OMAP44XX_H
+
+/*
+ * Please place only base defines here and put the rest in device
+ * specific headers.
+ */
+#define L4_44XX_BASE			0x4a000000
+#define L4_WK_44XX_BASE			0x4a300000
+#define L4_PER_44XX_BASE		0x48000000
+#define L4_EMU_44XX_BASE		0x54000000
+#define L3_44XX_BASE			0x44000000
+#define OMAP4430_32KSYNCT_BASE		0x4a304000
+#define OMAP4430_CM_BASE		0x4a004000
+#define OMAP4430_PRM_BASE		0x48306000
+#define OMAP44XX_GPMC_BASE		0x50000000
+#define OMAP443X_SCM_BASE		0x4a002000
+#define OMAP443X_CTRL_BASE		OMAP443X_SCM_BASE
+#define OMAP44XX_IC_BASE		0x48200000
+#define OMAP44XX_IVA_INTC_BASE		0x40000000
+#define IRQ_SIR_IRQ			0x0040
+#define OMAP44XX_GIC_DIST_BASE		0x48241000
+#define OMAP44XX_GIC_CPU_BASE		0x48240100
+#define OMAP44XX_VA_GIC_CPU_BASE	IO_ADDRESS(OMAP44XX_GIC_CPU_BASE)
+#define OMAP44XX_SCU_BASE		0x48240000
+#define OMAP44XX_VA_SCU_BASE		IO_ADDRESS(OMAP44XX_SCU_BASE)
+#define OMAP44XX_LOCAL_TWD_BASE		0x48240600
+#define OMAP44XX_VA_LOCAL_TWD_BASE	IO_ADDRESS(OMAP44XX_LOCAL_TWD_BASE)
+#define OMAP44XX_LOCAL_TWD_SIZE		0x00000100
+#define OMAP44XX_WKUPGEN_BASE		0x48281000
+#define OMAP44XX_VA_WKUPGEN_BASE	IO_ADDRESS(OMAP44XX_WKUPGEN_BASE)
+
+#endif /* __ASM_ARCH_OMAP44XX_H */
+
diff --git a/arch/arm/plat-omap/include/mach/onenand.h b/arch/arm/plat-omap/include/mach/onenand.h
index 4649d30..72f433d 100644
--- a/arch/arm/plat-omap/include/mach/onenand.h
+++ b/arch/arm/plat-omap/include/mach/onenand.h
@@ -9,8 +9,12 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
+#define ONENAND_SYNC_READ	(1 << 0)
+#define ONENAND_SYNC_READWRITE	(1 << 1)
+
 struct omap_onenand_platform_data {
 	int			cs;
 	int			gpio_irq;
@@ -18,8 +22,22 @@
 	int			nr_parts;
 	int                     (*onenand_setup)(void __iomem *, int freq);
 	int			dma_channel;
+	u8			flags;
 };
 
-int omap2_onenand_rephase(void);
-
 #define ONENAND_MAX_PARTITIONS 8
+
+#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
+	defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
+
+extern void gpmc_onenand_init(struct omap_onenand_platform_data *d);
+
+#else
+
+#define board_onenand_data	NULL
+
+static inline void gpmc_onenand_init(struct omap_onenand_platform_data *d)
+{
+}
+
+#endif
diff --git a/arch/arm/plat-omap/include/mach/pm.h b/arch/arm/plat-omap/include/mach/pm.h
deleted file mode 100644
index ce6ee79..0000000
--- a/arch/arm/plat-omap/include/mach/pm.h
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * arch/arm/plat-omap/include/mach/pm.h
- *
- * Header file for OMAP Power Management Routines
- *
- * Author: MontaVista Software, Inc.
- *	   support@mvista.com
- *
- * Copyright 2002 MontaVista Software Inc.
- *
- * Cleanup 2004 for Linux 2.6 by Dirk Behme <dirk.behme@de.bosch.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.
- */
-
-#ifndef __ASM_ARCH_OMAP_PM_H
-#define __ASM_ARCH_OMAP_PM_H
-
-/*
- * ----------------------------------------------------------------------------
- * Register and offset definitions to be used in PM assembler code
- * ----------------------------------------------------------------------------
- */
-#define CLKGEN_REG_ASM_BASE		IO_ADDRESS(0xfffece00)
-#define ARM_IDLECT1_ASM_OFFSET		0x04
-#define ARM_IDLECT2_ASM_OFFSET		0x08
-
-#define TCMIF_ASM_BASE			IO_ADDRESS(0xfffecc00)
-#define EMIFS_CONFIG_ASM_OFFSET		0x0c
-#define EMIFF_SDRAM_CONFIG_ASM_OFFSET	0x20
-
-/*
- * ----------------------------------------------------------------------------
- * Power management bitmasks
- * ----------------------------------------------------------------------------
- */
-#define IDLE_WAIT_CYCLES		0x00000fff
-#define PERIPHERAL_ENABLE		0x2
-
-#define SELF_REFRESH_MODE		0x0c000001
-#define IDLE_EMIFS_REQUEST		0xc
-#define MODEM_32K_EN			0x1
-#define PER_EN				0x1
-
-#define CPU_SUSPEND_SIZE		200
-#define ULPD_LOW_PWR_EN			0x0001
-#define ULPD_DEEP_SLEEP_TRANSITION_EN	0x0010
-#define ULPD_SETUP_ANALOG_CELL_3_VAL	0
-#define ULPD_POWER_CTRL_REG_VAL		0x0219
-
-#define DSP_IDLE_DELAY			10
-#define DSP_IDLE			0x0040
-#define DSP_RST				0x0004
-#define DSP_ENABLE			0x0002
-#define SUFFICIENT_DSP_RESET_TIME	1000
-#define DEFAULT_MPUI_CONFIG		0x05cf
-#define ENABLE_XORCLK			0x2
-#define DSP_CLOCK_ENABLE		0x2000
-#define DSP_IDLE_MODE			0x2
-#define TC_IDLE_REQUEST			(0x0000000c)
-
-#define IRQ_LEVEL2			(1<<0)
-#define IRQ_KEYBOARD			(1<<1)
-#define IRQ_UART2			(1<<15)
-
-#define PDE_BIT				0x08
-#define PWD_EN_BIT			0x04
-#define EN_PERCK_BIT			0x04
-
-#define OMAP1510_DEEP_SLEEP_REQUEST	0x0ec7
-#define OMAP1510_BIG_SLEEP_REQUEST	0x0cc5
-#define OMAP1510_IDLE_LOOP_REQUEST	0x0c00
-#define OMAP1510_IDLE_CLOCK_DOMAINS	0x2
-
-/* Both big sleep and deep sleep use same values. Difference is in ULPD. */
-#define OMAP1610_IDLECT1_SLEEP_VAL	0x13c7
-#define OMAP1610_IDLECT2_SLEEP_VAL	0x09c7
-#define OMAP1610_IDLECT3_VAL		0x3f
-#define OMAP1610_IDLECT3_SLEEP_ORMASK	0x2c
-#define OMAP1610_IDLECT3		0xfffece24
-#define OMAP1610_IDLE_LOOP_REQUEST	0x0400
-
-#define OMAP730_IDLECT1_SLEEP_VAL	0x16c7
-#define OMAP730_IDLECT2_SLEEP_VAL	0x09c7
-#define OMAP730_IDLECT3_VAL		0x3f
-#define OMAP730_IDLECT3		0xfffece24
-#define OMAP730_IDLE_LOOP_REQUEST	0x0C00
-
-#if     !defined(CONFIG_ARCH_OMAP730) && \
-	!defined(CONFIG_ARCH_OMAP15XX) && \
-	!defined(CONFIG_ARCH_OMAP16XX) && \
-	!defined(CONFIG_ARCH_OMAP24XX)
-#warning "Power management for this processor not implemented yet"
-#endif
-
-#ifndef __ASSEMBLER__
-
-#include <linux/clk.h>
-
-extern void prevent_idle_sleep(void);
-extern void allow_idle_sleep(void);
-
-extern void omap_pm_idle(void);
-extern void omap_pm_suspend(void);
-extern void omap730_cpu_suspend(unsigned short, unsigned short);
-extern void omap1510_cpu_suspend(unsigned short, unsigned short);
-extern void omap1610_cpu_suspend(unsigned short, unsigned short);
-extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl,
-					void __iomem *sdrc_power);
-extern void omap730_idle_loop_suspend(void);
-extern void omap1510_idle_loop_suspend(void);
-extern void omap1610_idle_loop_suspend(void);
-extern void omap24xx_idle_loop_suspend(void);
-
-extern unsigned int omap730_cpu_suspend_sz;
-extern unsigned int omap1510_cpu_suspend_sz;
-extern unsigned int omap1610_cpu_suspend_sz;
-extern unsigned int omap24xx_cpu_suspend_sz;
-extern unsigned int omap730_idle_loop_suspend_sz;
-extern unsigned int omap1510_idle_loop_suspend_sz;
-extern unsigned int omap1610_idle_loop_suspend_sz;
-extern unsigned int omap24xx_idle_loop_suspend_sz;
-
-#ifdef CONFIG_OMAP_SERIAL_WAKE
-extern void omap_serial_wake_trigger(int enable);
-#else
-#define omap_serial_wakeup_init()	{}
-#define omap_serial_wake_trigger(x)	{}
-#endif	/* CONFIG_OMAP_SERIAL_WAKE */
-
-#define ARM_SAVE(x) arm_sleep_save[ARM_SLEEP_SAVE_##x] = omap_readl(x)
-#define ARM_RESTORE(x) omap_writel((arm_sleep_save[ARM_SLEEP_SAVE_##x]), (x))
-#define ARM_SHOW(x) arm_sleep_save[ARM_SLEEP_SAVE_##x]
-
-#define DSP_SAVE(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x] = __raw_readw(x)
-#define DSP_RESTORE(x) __raw_writew((dsp_sleep_save[DSP_SLEEP_SAVE_##x]), (x))
-#define DSP_SHOW(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x]
-
-#define ULPD_SAVE(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] = omap_readw(x)
-#define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x))
-#define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]
-
-#define MPUI730_SAVE(x) mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x] = omap_readl(x)
-#define MPUI730_RESTORE(x) omap_writel((mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x]), (x))
-#define MPUI730_SHOW(x) mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x]
-
-#define MPUI1510_SAVE(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x] = omap_readl(x)
-#define MPUI1510_RESTORE(x) omap_writel((mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]), (x))
-#define MPUI1510_SHOW(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]
-
-#define MPUI1610_SAVE(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x] = omap_readl(x)
-#define MPUI1610_RESTORE(x) omap_writel((mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]), (x))
-#define MPUI1610_SHOW(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]
-
-#define OMAP24XX_SAVE(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x] = x
-#define OMAP24XX_RESTORE(x) x = omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x]
-#define OMAP24XX_SHOW(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x]
-
-/*
- * List of global OMAP registers to preserve.
- * More ones like CP and general purpose register values are preserved
- * with the stack pointer in sleep.S.
- */
-
-enum arm_save_state {
-	ARM_SLEEP_SAVE_START = 0,
-	/*
-	 * MPU control registers 32 bits
-	 */
-	ARM_SLEEP_SAVE_ARM_CKCTL,
-	ARM_SLEEP_SAVE_ARM_IDLECT1,
-	ARM_SLEEP_SAVE_ARM_IDLECT2,
-	ARM_SLEEP_SAVE_ARM_IDLECT3,
-	ARM_SLEEP_SAVE_ARM_EWUPCT,
-	ARM_SLEEP_SAVE_ARM_RSTCT1,
-	ARM_SLEEP_SAVE_ARM_RSTCT2,
-	ARM_SLEEP_SAVE_ARM_SYSST,
-	ARM_SLEEP_SAVE_SIZE
-};
-
-enum dsp_save_state {
-	DSP_SLEEP_SAVE_START = 0,
-	/*
-	 * DSP registers 16 bits
-	 */
-	DSP_SLEEP_SAVE_DSP_IDLECT2,
-	DSP_SLEEP_SAVE_SIZE
-};
-
-enum ulpd_save_state {
-	ULPD_SLEEP_SAVE_START = 0,
-	/*
-	 * ULPD registers 16 bits
-	 */
-	ULPD_SLEEP_SAVE_ULPD_IT_STATUS,
-	ULPD_SLEEP_SAVE_ULPD_CLOCK_CTRL,
-	ULPD_SLEEP_SAVE_ULPD_SOFT_REQ,
-	ULPD_SLEEP_SAVE_ULPD_STATUS_REQ,
-	ULPD_SLEEP_SAVE_ULPD_DPLL_CTRL,
-	ULPD_SLEEP_SAVE_ULPD_POWER_CTRL,
-	ULPD_SLEEP_SAVE_SIZE
-};
-
-enum mpui1510_save_state {
-	MPUI1510_SLEEP_SAVE_START = 0,
-	/*
-	 * MPUI registers 32 bits
-	 */
-	MPUI1510_SLEEP_SAVE_MPUI_CTRL,
-	MPUI1510_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
-	MPUI1510_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
-	MPUI1510_SLEEP_SAVE_MPUI_DSP_STATUS,
-	MPUI1510_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
-	MPUI1510_SLEEP_SAVE_EMIFS_CONFIG,
-	MPUI1510_SLEEP_SAVE_OMAP_IH1_MIR,
-	MPUI1510_SLEEP_SAVE_OMAP_IH2_MIR,
-#if defined(CONFIG_ARCH_OMAP15XX)
-	MPUI1510_SLEEP_SAVE_SIZE
-#else
-	MPUI1510_SLEEP_SAVE_SIZE = 0
-#endif
-};
-
-enum mpui730_save_state {
-	MPUI730_SLEEP_SAVE_START = 0,
-	/*
-	 * MPUI registers 32 bits
-	 */
-	MPUI730_SLEEP_SAVE_MPUI_CTRL,
-	MPUI730_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
-	MPUI730_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
-	MPUI730_SLEEP_SAVE_MPUI_DSP_STATUS,
-	MPUI730_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
-	MPUI730_SLEEP_SAVE_EMIFS_CONFIG,
-	MPUI730_SLEEP_SAVE_OMAP_IH1_MIR,
-	MPUI730_SLEEP_SAVE_OMAP_IH2_0_MIR,
-	MPUI730_SLEEP_SAVE_OMAP_IH2_1_MIR,
-#if defined(CONFIG_ARCH_OMAP730)
-	MPUI730_SLEEP_SAVE_SIZE
-#else
-	MPUI730_SLEEP_SAVE_SIZE = 0
-#endif
-};
-
-enum mpui1610_save_state {
-	MPUI1610_SLEEP_SAVE_START = 0,
-	/*
-	 * MPUI registers 32 bits
-	 */
-	MPUI1610_SLEEP_SAVE_MPUI_CTRL,
-	MPUI1610_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
-	MPUI1610_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
-	MPUI1610_SLEEP_SAVE_MPUI_DSP_STATUS,
-	MPUI1610_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
-	MPUI1610_SLEEP_SAVE_EMIFS_CONFIG,
-	MPUI1610_SLEEP_SAVE_OMAP_IH1_MIR,
-	MPUI1610_SLEEP_SAVE_OMAP_IH2_0_MIR,
-	MPUI1610_SLEEP_SAVE_OMAP_IH2_1_MIR,
-	MPUI1610_SLEEP_SAVE_OMAP_IH2_2_MIR,
-	MPUI1610_SLEEP_SAVE_OMAP_IH2_3_MIR,
-#if defined(CONFIG_ARCH_OMAP16XX)
-	MPUI1610_SLEEP_SAVE_SIZE
-#else
-	MPUI1610_SLEEP_SAVE_SIZE = 0
-#endif
-};
-
-enum omap24xx_save_state {
-	OMAP24XX_SLEEP_SAVE_START = 0,
-	OMAP24XX_SLEEP_SAVE_INTC_MIR0,
-	OMAP24XX_SLEEP_SAVE_INTC_MIR1,
-	OMAP24XX_SLEEP_SAVE_INTC_MIR2,
-
-	OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_MPU,
-	OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_GFX,
-	OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_DSP,
-	OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_MDM,
-
-	OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_MPU,
-	OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_CORE,
-	OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_GFX,
-	OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_DSP,
-	OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_MDM,
-
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST1_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST2_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST3_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST4_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST_GFX,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST_WKUP,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST_CKGEN,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST_DSP,
-	OMAP24XX_SLEEP_SAVE_CM_IDLEST_MDM,
-
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE1_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE2_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE3_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE4_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_WKUP,
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_PLL,
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_DSP,
-	OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_MDM,
-
-	OMAP24XX_SLEEP_SAVE_CM_FCLKEN1_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_FCLKEN2_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_ICLKEN1_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_ICLKEN2_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_ICLKEN3_CORE,
-	OMAP24XX_SLEEP_SAVE_CM_ICLKEN4_CORE,
-	OMAP24XX_SLEEP_SAVE_GPIO1_IRQENABLE1,
-	OMAP24XX_SLEEP_SAVE_GPIO2_IRQENABLE1,
-	OMAP24XX_SLEEP_SAVE_GPIO3_IRQENABLE1,
-	OMAP24XX_SLEEP_SAVE_GPIO4_IRQENABLE1,
-	OMAP24XX_SLEEP_SAVE_GPIO3_OE,
-	OMAP24XX_SLEEP_SAVE_GPIO4_OE,
-	OMAP24XX_SLEEP_SAVE_GPIO3_RISINGDETECT,
-	OMAP24XX_SLEEP_SAVE_GPIO3_FALLINGDETECT,
-	OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SPI1_NCS2,
-	OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_MCBSP1_DX,
-	OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SSI1_FLAG_TX,
-	OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SYS_NIRQW0,
-	OMAP24XX_SLEEP_SAVE_SIZE
-};
-
-#endif /* ASSEMBLER */
-#endif /* __ASM_ARCH_OMAP_PM_H */
diff --git a/arch/arm/plat-omap/include/mach/serial.h b/arch/arm/plat-omap/include/mach/serial.h
index 8a676a0..13abd02 100644
--- a/arch/arm/plat-omap/include/mach/serial.h
+++ b/arch/arm/plat-omap/include/mach/serial.h
@@ -1,5 +1,8 @@
 /*
- *  arch/arm/plat-omap/include/mach/serial.h
+ * arch/arm/plat-omap/include/mach/serial.h
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Addded OMAP4 support- Santosh Shilimkar <santosh.shilimkar@ti.com>
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -15,19 +18,28 @@
 #define OMAP_UART1_BASE		0xfffb0000
 #define OMAP_UART2_BASE		0xfffb0800
 #define OMAP_UART3_BASE		0xfffb9800
+#define OMAP_MAX_NR_PORTS	3
 #elif defined(CONFIG_ARCH_OMAP2)
 /* OMAP2 serial ports */
 #define OMAP_UART1_BASE		0x4806a000
 #define OMAP_UART2_BASE		0x4806c000
 #define OMAP_UART3_BASE		0x4806e000
+#define OMAP_MAX_NR_PORTS	3
 #elif defined(CONFIG_ARCH_OMAP3)
 /* OMAP3 serial ports */
 #define OMAP_UART1_BASE		0x4806a000
 #define OMAP_UART2_BASE		0x4806c000
 #define OMAP_UART3_BASE		0x49020000
+#define OMAP_MAX_NR_PORTS	3
+#elif defined(CONFIG_ARCH_OMAP4)
+/* OMAP4 serial ports */
+#define OMAP_UART1_BASE		0x4806a000
+#define OMAP_UART2_BASE		0x4806c000
+#define OMAP_UART3_BASE		0x48020000
+#define OMAP_UART4_BASE		0x4806e000
+#define OMAP_MAX_NR_PORTS	4
 #endif
 
-#define OMAP_MAX_NR_PORTS	3
 #define OMAP1510_BASE_BAUD	(12000000/16)
 #define OMAP16XX_BASE_BAUD	(48000000/16)
 #define OMAP24XX_BASE_BAUD	(48000000/16)
@@ -40,4 +52,13 @@
 			__ret;						\
 			})
 
+#ifndef __ASSEMBLER__
+extern void omap_serial_init(void);
+extern int omap_uart_can_sleep(void);
+extern void omap_uart_check_wakeup(void);
+extern void omap_uart_prepare_suspend(void);
+extern void omap_uart_prepare_idle(int num);
+extern void omap_uart_resume_idle(int num);
+#endif
+
 #endif
diff --git a/arch/arm/plat-omap/include/mach/smp.h b/arch/arm/plat-omap/include/mach/smp.h
new file mode 100644
index 0000000..dcaa8fd
--- /dev/null
+++ b/arch/arm/plat-omap/include/mach/smp.h
@@ -0,0 +1,51 @@
+/*
+ * OMAP4 machine specific smp.h
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Author:
+ *	Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * Interface functions needed for the SMP. This file is based on arm
+ * realview smp platform.
+ * 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef OMAP_ARCH_SMP_H
+#define OMAP_ARCH_SMP_H
+
+#include <asm/hardware/gic.h>
+
+/*
+ * set_event() is used to wake up secondary core from wfe using sev. ROM
+ * code puts the second core into wfe(standby).
+ *
+ */
+#define set_event()	__asm__ __volatile__ ("sev" : : : "memory")
+
+/* Needed for secondary core boot */
+extern void omap_secondary_startup(void);
+
+/*
+ * We use Soft IRQ1 as the IPI
+ */
+static inline void smp_cross_call(const struct cpumask *mask)
+{
+	gic_raise_softirq(mask, 1);
+}
+
+/*
+ * Read MPIDR: Multiprocessor affinity register
+ */
+#define hard_smp_processor_id()			\
+	({						\
+		unsigned int cpunum;			\
+		__asm__("mrc p15, 0, %0, c0, c0, 5"	\
+			: "=r" (cpunum));		\
+		cpunum &= 0x0F;				\
+	})
+
+#endif
diff --git a/arch/arm/plat-omap/include/mach/sram.h b/arch/arm/plat-omap/include/mach/sram.h
index ab35d62..dca7c16 100644
--- a/arch/arm/plat-omap/include/mach/sram.h
+++ b/arch/arm/plat-omap/include/mach/sram.h
@@ -23,7 +23,8 @@
 
 extern u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl,
 				     u32 sdrc_actim_ctrla,
-				     u32 sdrc_actim_ctrlb, u32 m2);
+				     u32 sdrc_actim_ctrlb, u32 m2,
+				     u32 unlock_dll);
 
 /* Do not use these */
 extern void omap1_sram_reprogram_clock(u32 ckctl, u32 dpllctl);
@@ -60,7 +61,8 @@
 
 extern u32 omap3_sram_configure_core_dpll(u32 sdrc_rfr_ctrl,
 					  u32 sdrc_actim_ctrla,
-					  u32 sdrc_actim_ctrlb, u32 m2);
+					  u32 sdrc_actim_ctrlb, u32 m2,
+					  u32 unlock_dll);
 extern unsigned long omap3_sram_configure_core_dpll_sz;
 
 #endif
diff --git a/arch/arm/plat-omap/include/mach/usb.h b/arch/arm/plat-omap/include/mach/usb.h
index 69f0cee..f337e17 100644
--- a/arch/arm/plat-omap/include/mach/usb.h
+++ b/arch/arm/plat-omap/include/mach/usb.h
@@ -27,13 +27,7 @@
 #define UDC_BASE			OMAP2_UDC_BASE
 #define OMAP_OHCI_BASE			OMAP2_OHCI_BASE
 
-#ifdef CONFIG_USB_MUSB_SOC
 extern void usb_musb_init(void);
-#else
-static inline void usb_musb_init(void)
-{
-}
-#endif
 
 #endif
 
diff --git a/arch/arm/plat-omap/include/mach/vmalloc.h b/arch/arm/plat-omap/include/mach/vmalloc.h
index dc104cd..b97dfaf 100644
--- a/arch/arm/plat-omap/include/mach/vmalloc.h
+++ b/arch/arm/plat-omap/include/mach/vmalloc.h
@@ -17,5 +17,5 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-#define VMALLOC_END	  (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END	  (PAGE_OFFSET + 0x18000000)
 
diff --git a/arch/arm/plat-omap/io.c b/arch/arm/plat-omap/io.c
index af326ef..9b42d72 100644
--- a/arch/arm/plat-omap/io.c
+++ b/arch/arm/plat-omap/io.c
@@ -1,3 +1,14 @@
+/*
+ * Common io.c file
+ * This file is created by Russell King <rmk+kernel@arm.linux.org.uk>
+ *
+ * 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 version 2 as
+ * published by the Free Software Foundation.
+ */
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/mm.h>
@@ -7,6 +18,7 @@
 #include <mach/omap16xx.h>
 #include <mach/omap24xx.h>
 #include <mach/omap34xx.h>
+#include <mach/omap44xx.h>
 
 #define BETWEEN(p,st,sz)	((p) >= (st) && (p) < ((st) + (sz)))
 #define XLATE(p,pst,vst)	((void __iomem *)((p) - (pst) + (vst)))
@@ -92,7 +104,22 @@
 			return XLATE(p, L4_EMU_34XX_PHYS, L4_EMU_34XX_VIRT);
 	}
 #endif
-
+#ifdef CONFIG_ARCH_OMAP4
+	if (cpu_is_omap44xx()) {
+		if (BETWEEN(p, L3_44XX_PHYS, L3_44XX_SIZE))
+			return XLATE(p, L3_44XX_PHYS, L3_44XX_VIRT);
+		if (BETWEEN(p, L4_44XX_PHYS, L4_44XX_SIZE))
+			return XLATE(p, L4_44XX_PHYS, L4_44XX_VIRT);
+		if (BETWEEN(p, L4_WK_44XX_PHYS, L4_WK_44XX_SIZE))
+			return XLATE(p, L4_WK_44XX_PHYS, L4_WK_44XX_VIRT);
+		if (BETWEEN(p, OMAP44XX_GPMC_PHYS, OMAP44XX_GPMC_SIZE))
+			return XLATE(p, OMAP44XX_GPMC_PHYS, OMAP44XX_GPMC_VIRT);
+		if (BETWEEN(p, L4_PER_44XX_PHYS, L4_PER_44XX_SIZE))
+			return XLATE(p, L4_PER_44XX_PHYS, L4_PER_44XX_VIRT);
+		if (BETWEEN(p, L4_EMU_44XX_PHYS, L4_EMU_44XX_SIZE))
+			return XLATE(p, L4_EMU_44XX_PHYS, L4_EMU_44XX_VIRT);
+	}
+#endif
 	return __arm_ioremap(p, size, type);
 }
 EXPORT_SYMBOL(omap_ioremap);
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c
new file mode 100644
index 0000000..4cf449f
--- /dev/null
+++ b/arch/arm/plat-omap/iommu.c
@@ -0,0 +1,996 @@
+/*
+ * omap iommu: tlb and pagetable primitives
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>,
+ *		Paul Mundt and Toshihiro Kobayashi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <asm/cacheflush.h>
+
+#include <mach/iommu.h>
+
+#include "iopgtable.h"
+
+/* accommodate the difference between omap1 and omap2/3 */
+static const struct iommu_functions *arch_iommu;
+
+static struct platform_driver omap_iommu_driver;
+static struct kmem_cache *iopte_cachep;
+
+/**
+ * install_iommu_arch - Install archtecure specific iommu functions
+ * @ops:	a pointer to architecture specific iommu functions
+ *
+ * There are several kind of iommu algorithm(tlb, pagetable) among
+ * omap series. This interface installs such an iommu algorighm.
+ **/
+int install_iommu_arch(const struct iommu_functions *ops)
+{
+	if (arch_iommu)
+		return -EBUSY;
+
+	arch_iommu = ops;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(install_iommu_arch);
+
+/**
+ * uninstall_iommu_arch - Uninstall archtecure specific iommu functions
+ * @ops:	a pointer to architecture specific iommu functions
+ *
+ * This interface uninstalls the iommu algorighm installed previously.
+ **/
+void uninstall_iommu_arch(const struct iommu_functions *ops)
+{
+	if (arch_iommu != ops)
+		pr_err("%s: not your arch\n", __func__);
+
+	arch_iommu = NULL;
+}
+EXPORT_SYMBOL_GPL(uninstall_iommu_arch);
+
+/**
+ * iommu_save_ctx - Save registers for pm off-mode support
+ * @obj:	target iommu
+ **/
+void iommu_save_ctx(struct iommu *obj)
+{
+	arch_iommu->save_ctx(obj);
+}
+EXPORT_SYMBOL_GPL(iommu_save_ctx);
+
+/**
+ * iommu_restore_ctx - Restore registers for pm off-mode support
+ * @obj:	target iommu
+ **/
+void iommu_restore_ctx(struct iommu *obj)
+{
+	arch_iommu->restore_ctx(obj);
+}
+EXPORT_SYMBOL_GPL(iommu_restore_ctx);
+
+/**
+ * iommu_arch_version - Return running iommu arch version
+ **/
+u32 iommu_arch_version(void)
+{
+	return arch_iommu->version;
+}
+EXPORT_SYMBOL_GPL(iommu_arch_version);
+
+static int iommu_enable(struct iommu *obj)
+{
+	int err;
+
+	if (!obj)
+		return -EINVAL;
+
+	clk_enable(obj->clk);
+
+	err = arch_iommu->enable(obj);
+
+	clk_disable(obj->clk);
+	return err;
+}
+
+static void iommu_disable(struct iommu *obj)
+{
+	if (!obj)
+		return;
+
+	clk_enable(obj->clk);
+
+	arch_iommu->disable(obj);
+
+	clk_disable(obj->clk);
+}
+
+/*
+ *	TLB operations
+ */
+void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
+{
+	BUG_ON(!cr || !e);
+
+	arch_iommu->cr_to_e(cr, e);
+}
+EXPORT_SYMBOL_GPL(iotlb_cr_to_e);
+
+static inline int iotlb_cr_valid(struct cr_regs *cr)
+{
+	if (!cr)
+		return -EINVAL;
+
+	return arch_iommu->cr_valid(cr);
+}
+
+static inline struct cr_regs *iotlb_alloc_cr(struct iommu *obj,
+					     struct iotlb_entry *e)
+{
+	if (!e)
+		return NULL;
+
+	return arch_iommu->alloc_cr(obj, e);
+}
+
+u32 iotlb_cr_to_virt(struct cr_regs *cr)
+{
+	return arch_iommu->cr_to_virt(cr);
+}
+EXPORT_SYMBOL_GPL(iotlb_cr_to_virt);
+
+static u32 get_iopte_attr(struct iotlb_entry *e)
+{
+	return arch_iommu->get_pte_attr(e);
+}
+
+static u32 iommu_report_fault(struct iommu *obj, u32 *da)
+{
+	return arch_iommu->fault_isr(obj, da);
+}
+
+static void iotlb_lock_get(struct iommu *obj, struct iotlb_lock *l)
+{
+	u32 val;
+
+	val = iommu_read_reg(obj, MMU_LOCK);
+
+	l->base = MMU_LOCK_BASE(val);
+	l->vict = MMU_LOCK_VICT(val);
+
+	BUG_ON(l->base != 0); /* Currently no preservation is used */
+}
+
+static void iotlb_lock_set(struct iommu *obj, struct iotlb_lock *l)
+{
+	u32 val;
+
+	BUG_ON(l->base != 0); /* Currently no preservation is used */
+
+	val = (l->base << MMU_LOCK_BASE_SHIFT);
+	val |= (l->vict << MMU_LOCK_VICT_SHIFT);
+
+	iommu_write_reg(obj, val, MMU_LOCK);
+}
+
+static void iotlb_read_cr(struct iommu *obj, struct cr_regs *cr)
+{
+	arch_iommu->tlb_read_cr(obj, cr);
+}
+
+static void iotlb_load_cr(struct iommu *obj, struct cr_regs *cr)
+{
+	arch_iommu->tlb_load_cr(obj, cr);
+
+	iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
+	iommu_write_reg(obj, 1, MMU_LD_TLB);
+}
+
+/**
+ * iotlb_dump_cr - Dump an iommu tlb entry into buf
+ * @obj:	target iommu
+ * @cr:		contents of cam and ram register
+ * @buf:	output buffer
+ **/
+static inline ssize_t iotlb_dump_cr(struct iommu *obj, struct cr_regs *cr,
+				    char *buf)
+{
+	BUG_ON(!cr || !buf);
+
+	return arch_iommu->dump_cr(obj, cr, buf);
+}
+
+/**
+ * load_iotlb_entry - Set an iommu tlb entry
+ * @obj:	target iommu
+ * @e:		an iommu tlb entry info
+ **/
+int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
+{
+	int i;
+	int err = 0;
+	struct iotlb_lock l;
+	struct cr_regs *cr;
+
+	if (!obj || !obj->nr_tlb_entries || !e)
+		return -EINVAL;
+
+	clk_enable(obj->clk);
+
+	for (i = 0; i < obj->nr_tlb_entries; i++) {
+		struct cr_regs tmp;
+
+		iotlb_lock_get(obj, &l);
+		l.vict = i;
+		iotlb_lock_set(obj, &l);
+		iotlb_read_cr(obj, &tmp);
+		if (!iotlb_cr_valid(&tmp))
+			break;
+	}
+
+	if (i == obj->nr_tlb_entries) {
+		dev_dbg(obj->dev, "%s: full: no entry\n", __func__);
+		err = -EBUSY;
+		goto out;
+	}
+
+	cr = iotlb_alloc_cr(obj, e);
+	if (IS_ERR(cr)) {
+		clk_disable(obj->clk);
+		return PTR_ERR(cr);
+	}
+
+	iotlb_load_cr(obj, cr);
+	kfree(cr);
+
+	/* increment victim for next tlb load */
+	if (++l.vict == obj->nr_tlb_entries)
+		l.vict = 0;
+	iotlb_lock_set(obj, &l);
+out:
+	clk_disable(obj->clk);
+	return err;
+}
+EXPORT_SYMBOL_GPL(load_iotlb_entry);
+
+/**
+ * flush_iotlb_page - Clear an iommu tlb entry
+ * @obj:	target iommu
+ * @da:		iommu device virtual address
+ *
+ * Clear an iommu tlb entry which includes 'da' address.
+ **/
+void flush_iotlb_page(struct iommu *obj, u32 da)
+{
+	struct iotlb_lock l;
+	int i;
+
+	clk_enable(obj->clk);
+
+	for (i = 0; i < obj->nr_tlb_entries; i++) {
+		struct cr_regs cr;
+		u32 start;
+		size_t bytes;
+
+		iotlb_lock_get(obj, &l);
+		l.vict = i;
+		iotlb_lock_set(obj, &l);
+		iotlb_read_cr(obj, &cr);
+		if (!iotlb_cr_valid(&cr))
+			continue;
+
+		start = iotlb_cr_to_virt(&cr);
+		bytes = iopgsz_to_bytes(cr.cam & 3);
+
+		if ((start <= da) && (da < start + bytes)) {
+			dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n",
+				__func__, start, da, bytes);
+
+			iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
+		}
+	}
+	clk_disable(obj->clk);
+
+	if (i == obj->nr_tlb_entries)
+		dev_dbg(obj->dev, "%s: no page for %08x\n", __func__, da);
+}
+EXPORT_SYMBOL_GPL(flush_iotlb_page);
+
+/**
+ * flush_iotlb_range - Clear an iommu tlb entries
+ * @obj:	target iommu
+ * @start:	iommu device virtual address(start)
+ * @end:	iommu device virtual address(end)
+ *
+ * Clear an iommu tlb entry which includes 'da' address.
+ **/
+void flush_iotlb_range(struct iommu *obj, u32 start, u32 end)
+{
+	u32 da = start;
+
+	while (da < end) {
+		flush_iotlb_page(obj, da);
+		/* FIXME: Optimize for multiple page size */
+		da += IOPTE_SIZE;
+	}
+}
+EXPORT_SYMBOL_GPL(flush_iotlb_range);
+
+/**
+ * flush_iotlb_all - Clear all iommu tlb entries
+ * @obj:	target iommu
+ **/
+void flush_iotlb_all(struct iommu *obj)
+{
+	struct iotlb_lock l;
+
+	clk_enable(obj->clk);
+
+	l.base = 0;
+	l.vict = 0;
+	iotlb_lock_set(obj, &l);
+
+	iommu_write_reg(obj, 1, MMU_GFLUSH);
+
+	clk_disable(obj->clk);
+}
+EXPORT_SYMBOL_GPL(flush_iotlb_all);
+
+#if defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE)
+
+ssize_t iommu_dump_ctx(struct iommu *obj, char *buf)
+{
+	ssize_t bytes;
+
+	if (!obj || !buf)
+		return -EINVAL;
+
+	clk_enable(obj->clk);
+
+	bytes = arch_iommu->dump_ctx(obj, buf);
+
+	clk_disable(obj->clk);
+
+	return bytes;
+}
+EXPORT_SYMBOL_GPL(iommu_dump_ctx);
+
+static int __dump_tlb_entries(struct iommu *obj, struct cr_regs *crs)
+{
+	int i;
+	struct iotlb_lock saved, l;
+	struct cr_regs *p = crs;
+
+	clk_enable(obj->clk);
+
+	iotlb_lock_get(obj, &saved);
+	memcpy(&l, &saved, sizeof(saved));
+
+	for (i = 0; i < obj->nr_tlb_entries; i++) {
+		struct cr_regs tmp;
+
+		iotlb_lock_get(obj, &l);
+		l.vict = i;
+		iotlb_lock_set(obj, &l);
+		iotlb_read_cr(obj, &tmp);
+		if (!iotlb_cr_valid(&tmp))
+			continue;
+
+		*p++ = tmp;
+	}
+	iotlb_lock_set(obj, &saved);
+	clk_disable(obj->clk);
+
+	return  p - crs;
+}
+
+/**
+ * dump_tlb_entries - dump cr arrays to given buffer
+ * @obj:	target iommu
+ * @buf:	output buffer
+ **/
+size_t dump_tlb_entries(struct iommu *obj, char *buf)
+{
+	int i, n;
+	struct cr_regs *cr;
+	char *p = buf;
+
+	cr = kcalloc(obj->nr_tlb_entries, sizeof(*cr), GFP_KERNEL);
+	if (!cr)
+		return 0;
+
+	n = __dump_tlb_entries(obj, cr);
+	for (i = 0; i < n; i++)
+		p += iotlb_dump_cr(obj, cr + i, p);
+	kfree(cr);
+
+	return p - buf;
+}
+EXPORT_SYMBOL_GPL(dump_tlb_entries);
+
+int foreach_iommu_device(void *data, int (*fn)(struct device *, void *))
+{
+	return driver_for_each_device(&omap_iommu_driver.driver,
+				      NULL, data, fn);
+}
+EXPORT_SYMBOL_GPL(foreach_iommu_device);
+
+#endif /* CONFIG_OMAP_IOMMU_DEBUG_MODULE */
+
+/*
+ *	H/W pagetable operations
+ */
+static void flush_iopgd_range(u32 *first, u32 *last)
+{
+	/* FIXME: L2 cache should be taken care of if it exists */
+	do {
+		asm("mcr	p15, 0, %0, c7, c10, 1 @ flush_pgd"
+		    : : "r" (first));
+		first += L1_CACHE_BYTES / sizeof(*first);
+	} while (first <= last);
+}
+
+static void flush_iopte_range(u32 *first, u32 *last)
+{
+	/* FIXME: L2 cache should be taken care of if it exists */
+	do {
+		asm("mcr	p15, 0, %0, c7, c10, 1 @ flush_pte"
+		    : : "r" (first));
+		first += L1_CACHE_BYTES / sizeof(*first);
+	} while (first <= last);
+}
+
+static void iopte_free(u32 *iopte)
+{
+	/* Note: freed iopte's must be clean ready for re-use */
+	kmem_cache_free(iopte_cachep, iopte);
+}
+
+static u32 *iopte_alloc(struct iommu *obj, u32 *iopgd, u32 da)
+{
+	u32 *iopte;
+
+	/* a table has already existed */
+	if (*iopgd)
+		goto pte_ready;
+
+	/*
+	 * do the allocation outside the page table lock
+	 */
+	spin_unlock(&obj->page_table_lock);
+	iopte = kmem_cache_zalloc(iopte_cachep, GFP_KERNEL);
+	spin_lock(&obj->page_table_lock);
+
+	if (!*iopgd) {
+		if (!iopte)
+			return ERR_PTR(-ENOMEM);
+
+		*iopgd = virt_to_phys(iopte) | IOPGD_TABLE;
+		flush_iopgd_range(iopgd, iopgd);
+
+		dev_vdbg(obj->dev, "%s: a new pte:%p\n", __func__, iopte);
+	} else {
+		/* We raced, free the reduniovant table */
+		iopte_free(iopte);
+	}
+
+pte_ready:
+	iopte = iopte_offset(iopgd, da);
+
+	dev_vdbg(obj->dev,
+		 "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n",
+		 __func__, da, iopgd, *iopgd, iopte, *iopte);
+
+	return iopte;
+}
+
+static int iopgd_alloc_section(struct iommu *obj, u32 da, u32 pa, u32 prot)
+{
+	u32 *iopgd = iopgd_offset(obj, da);
+
+	*iopgd = (pa & IOSECTION_MASK) | prot | IOPGD_SECTION;
+	flush_iopgd_range(iopgd, iopgd);
+	return 0;
+}
+
+static int iopgd_alloc_super(struct iommu *obj, u32 da, u32 pa, u32 prot)
+{
+	u32 *iopgd = iopgd_offset(obj, da);
+	int i;
+
+	for (i = 0; i < 16; i++)
+		*(iopgd + i) = (pa & IOSUPER_MASK) | prot | IOPGD_SUPER;
+	flush_iopgd_range(iopgd, iopgd + 15);
+	return 0;
+}
+
+static int iopte_alloc_page(struct iommu *obj, u32 da, u32 pa, u32 prot)
+{
+	u32 *iopgd = iopgd_offset(obj, da);
+	u32 *iopte = iopte_alloc(obj, iopgd, da);
+
+	if (IS_ERR(iopte))
+		return PTR_ERR(iopte);
+
+	*iopte = (pa & IOPAGE_MASK) | prot | IOPTE_SMALL;
+	flush_iopte_range(iopte, iopte);
+
+	dev_vdbg(obj->dev, "%s: da:%08x pa:%08x pte:%p *pte:%08x\n",
+		 __func__, da, pa, iopte, *iopte);
+
+	return 0;
+}
+
+static int iopte_alloc_large(struct iommu *obj, u32 da, u32 pa, u32 prot)
+{
+	u32 *iopgd = iopgd_offset(obj, da);
+	u32 *iopte = iopte_alloc(obj, iopgd, da);
+	int i;
+
+	if (IS_ERR(iopte))
+		return PTR_ERR(iopte);
+
+	for (i = 0; i < 16; i++)
+		*(iopte + i) = (pa & IOLARGE_MASK) | prot | IOPTE_LARGE;
+	flush_iopte_range(iopte, iopte + 15);
+	return 0;
+}
+
+static int iopgtable_store_entry_core(struct iommu *obj, struct iotlb_entry *e)
+{
+	int (*fn)(struct iommu *, u32, u32, u32);
+	u32 prot;
+	int err;
+
+	if (!obj || !e)
+		return -EINVAL;
+
+	switch (e->pgsz) {
+	case MMU_CAM_PGSZ_16M:
+		fn = iopgd_alloc_super;
+		break;
+	case MMU_CAM_PGSZ_1M:
+		fn = iopgd_alloc_section;
+		break;
+	case MMU_CAM_PGSZ_64K:
+		fn = iopte_alloc_large;
+		break;
+	case MMU_CAM_PGSZ_4K:
+		fn = iopte_alloc_page;
+		break;
+	default:
+		fn = NULL;
+		BUG();
+		break;
+	}
+
+	prot = get_iopte_attr(e);
+
+	spin_lock(&obj->page_table_lock);
+	err = fn(obj, e->da, e->pa, prot);
+	spin_unlock(&obj->page_table_lock);
+
+	return err;
+}
+
+/**
+ * iopgtable_store_entry - Make an iommu pte entry
+ * @obj:	target iommu
+ * @e:		an iommu tlb entry info
+ **/
+int iopgtable_store_entry(struct iommu *obj, struct iotlb_entry *e)
+{
+	int err;
+
+	flush_iotlb_page(obj, e->da);
+	err = iopgtable_store_entry_core(obj, e);
+#ifdef PREFETCH_IOTLB
+	if (!err)
+		load_iotlb_entry(obj, e);
+#endif
+	return err;
+}
+EXPORT_SYMBOL_GPL(iopgtable_store_entry);
+
+/**
+ * iopgtable_lookup_entry - Lookup an iommu pte entry
+ * @obj:	target iommu
+ * @da:		iommu device virtual address
+ * @ppgd:	iommu pgd entry pointer to be returned
+ * @ppte:	iommu pte entry pointer to be returned
+ **/
+void iopgtable_lookup_entry(struct iommu *obj, u32 da, u32 **ppgd, u32 **ppte)
+{
+	u32 *iopgd, *iopte = NULL;
+
+	iopgd = iopgd_offset(obj, da);
+	if (!*iopgd)
+		goto out;
+
+	if (*iopgd & IOPGD_TABLE)
+		iopte = iopte_offset(iopgd, da);
+out:
+	*ppgd = iopgd;
+	*ppte = iopte;
+}
+EXPORT_SYMBOL_GPL(iopgtable_lookup_entry);
+
+static size_t iopgtable_clear_entry_core(struct iommu *obj, u32 da)
+{
+	size_t bytes;
+	u32 *iopgd = iopgd_offset(obj, da);
+	int nent = 1;
+
+	if (!*iopgd)
+		return 0;
+
+	if (*iopgd & IOPGD_TABLE) {
+		int i;
+		u32 *iopte = iopte_offset(iopgd, da);
+
+		bytes = IOPTE_SIZE;
+		if (*iopte & IOPTE_LARGE) {
+			nent *= 16;
+			/* rewind to the 1st entry */
+			iopte = (u32 *)((u32)iopte & IOLARGE_MASK);
+		}
+		bytes *= nent;
+		memset(iopte, 0, nent * sizeof(*iopte));
+		flush_iopte_range(iopte, iopte + (nent - 1) * sizeof(*iopte));
+
+		/*
+		 * do table walk to check if this table is necessary or not
+		 */
+		iopte = iopte_offset(iopgd, 0);
+		for (i = 0; i < PTRS_PER_IOPTE; i++)
+			if (iopte[i])
+				goto out;
+
+		iopte_free(iopte);
+		nent = 1; /* for the next L1 entry */
+	} else {
+		bytes = IOPGD_SIZE;
+		if (*iopgd & IOPGD_SUPER) {
+			nent *= 16;
+			/* rewind to the 1st entry */
+			iopgd = (u32 *)((u32)iopgd & IOSUPER_MASK);
+		}
+		bytes *= nent;
+	}
+	memset(iopgd, 0, nent * sizeof(*iopgd));
+	flush_iopgd_range(iopgd, iopgd + (nent - 1) * sizeof(*iopgd));
+out:
+	return bytes;
+}
+
+/**
+ * iopgtable_clear_entry - Remove an iommu pte entry
+ * @obj:	target iommu
+ * @da:		iommu device virtual address
+ **/
+size_t iopgtable_clear_entry(struct iommu *obj, u32 da)
+{
+	size_t bytes;
+
+	spin_lock(&obj->page_table_lock);
+
+	bytes = iopgtable_clear_entry_core(obj, da);
+	flush_iotlb_page(obj, da);
+
+	spin_unlock(&obj->page_table_lock);
+
+	return bytes;
+}
+EXPORT_SYMBOL_GPL(iopgtable_clear_entry);
+
+static void iopgtable_clear_entry_all(struct iommu *obj)
+{
+	int i;
+
+	spin_lock(&obj->page_table_lock);
+
+	for (i = 0; i < PTRS_PER_IOPGD; i++) {
+		u32 da;
+		u32 *iopgd;
+
+		da = i << IOPGD_SHIFT;
+		iopgd = iopgd_offset(obj, da);
+
+		if (!*iopgd)
+			continue;
+
+		if (*iopgd & IOPGD_TABLE)
+			iopte_free(iopte_offset(iopgd, 0));
+
+		*iopgd = 0;
+		flush_iopgd_range(iopgd, iopgd);
+	}
+
+	flush_iotlb_all(obj);
+
+	spin_unlock(&obj->page_table_lock);
+}
+
+/*
+ *	Device IOMMU generic operations
+ */
+static irqreturn_t iommu_fault_handler(int irq, void *data)
+{
+	u32 stat, da;
+	u32 *iopgd, *iopte;
+	int err = -EIO;
+	struct iommu *obj = data;
+
+	if (!obj->refcount)
+		return IRQ_NONE;
+
+	/* Dynamic loading TLB or PTE */
+	if (obj->isr)
+		err = obj->isr(obj);
+
+	if (!err)
+		return IRQ_HANDLED;
+
+	clk_enable(obj->clk);
+	stat = iommu_report_fault(obj, &da);
+	clk_disable(obj->clk);
+	if (!stat)
+		return IRQ_HANDLED;
+
+	iopgd = iopgd_offset(obj, da);
+
+	if (!(*iopgd & IOPGD_TABLE)) {
+		dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x\n", __func__,
+			da, iopgd, *iopgd);
+		return IRQ_NONE;
+	}
+
+	iopte = iopte_offset(iopgd, da);
+
+	dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n",
+		__func__, da, iopgd, *iopgd, iopte, *iopte);
+
+	return IRQ_NONE;
+}
+
+static int device_match_by_alias(struct device *dev, void *data)
+{
+	struct iommu *obj = to_iommu(dev);
+	const char *name = data;
+
+	pr_debug("%s: %s %s\n", __func__, obj->name, name);
+
+	return strcmp(obj->name, name) == 0;
+}
+
+/**
+ * iommu_get - Get iommu handler
+ * @name:	target iommu name
+ **/
+struct iommu *iommu_get(const char *name)
+{
+	int err = -ENOMEM;
+	struct device *dev;
+	struct iommu *obj;
+
+	dev = driver_find_device(&omap_iommu_driver.driver, NULL, (void *)name,
+				 device_match_by_alias);
+	if (!dev)
+		return ERR_PTR(-ENODEV);
+
+	obj = to_iommu(dev);
+
+	mutex_lock(&obj->iommu_lock);
+
+	if (obj->refcount++ == 0) {
+		err = iommu_enable(obj);
+		if (err)
+			goto err_enable;
+		flush_iotlb_all(obj);
+	}
+
+	if (!try_module_get(obj->owner))
+		goto err_module;
+
+	mutex_unlock(&obj->iommu_lock);
+
+	dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name);
+	return obj;
+
+err_module:
+	if (obj->refcount == 1)
+		iommu_disable(obj);
+err_enable:
+	obj->refcount--;
+	mutex_unlock(&obj->iommu_lock);
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(iommu_get);
+
+/**
+ * iommu_put - Put back iommu handler
+ * @obj:	target iommu
+ **/
+void iommu_put(struct iommu *obj)
+{
+	if (!obj && IS_ERR(obj))
+		return;
+
+	mutex_lock(&obj->iommu_lock);
+
+	if (--obj->refcount == 0)
+		iommu_disable(obj);
+
+	module_put(obj->owner);
+
+	mutex_unlock(&obj->iommu_lock);
+
+	dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name);
+}
+EXPORT_SYMBOL_GPL(iommu_put);
+
+/*
+ *	OMAP Device MMU(IOMMU) detection
+ */
+static int __devinit omap_iommu_probe(struct platform_device *pdev)
+{
+	int err = -ENODEV;
+	void *p;
+	int irq;
+	struct iommu *obj;
+	struct resource *res;
+	struct iommu_platform_data *pdata = pdev->dev.platform_data;
+
+	if (pdev->num_resources != 2)
+		return -EINVAL;
+
+	obj = kzalloc(sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL);
+	if (!obj)
+		return -ENOMEM;
+
+	obj->clk = clk_get(&pdev->dev, pdata->clk_name);
+	if (IS_ERR(obj->clk))
+		goto err_clk;
+
+	obj->nr_tlb_entries = pdata->nr_tlb_entries;
+	obj->name = pdata->name;
+	obj->dev = &pdev->dev;
+	obj->ctx = (void *)obj + sizeof(*obj);
+
+	mutex_init(&obj->iommu_lock);
+	mutex_init(&obj->mmap_lock);
+	spin_lock_init(&obj->page_table_lock);
+	INIT_LIST_HEAD(&obj->mmap);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		err = -ENODEV;
+		goto err_mem;
+	}
+	obj->regbase = ioremap(res->start, resource_size(res));
+	if (!obj->regbase) {
+		err = -ENOMEM;
+		goto err_mem;
+	}
+
+	res = request_mem_region(res->start, resource_size(res),
+				 dev_name(&pdev->dev));
+	if (!res) {
+		err = -EIO;
+		goto err_mem;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		err = -ENODEV;
+		goto err_irq;
+	}
+	err = request_irq(irq, iommu_fault_handler, IRQF_SHARED,
+			  dev_name(&pdev->dev), obj);
+	if (err < 0)
+		goto err_irq;
+	platform_set_drvdata(pdev, obj);
+
+	p = (void *)__get_free_pages(GFP_KERNEL, get_order(IOPGD_TABLE_SIZE));
+	if (!p) {
+		err = -ENOMEM;
+		goto err_pgd;
+	}
+	memset(p, 0, IOPGD_TABLE_SIZE);
+	clean_dcache_area(p, IOPGD_TABLE_SIZE);
+	obj->iopgd = p;
+
+	BUG_ON(!IS_ALIGNED((unsigned long)obj->iopgd, IOPGD_TABLE_SIZE));
+
+	dev_info(&pdev->dev, "%s registered\n", obj->name);
+	return 0;
+
+err_pgd:
+	free_irq(irq, obj);
+err_irq:
+	release_mem_region(res->start, resource_size(res));
+	iounmap(obj->regbase);
+err_mem:
+	clk_put(obj->clk);
+err_clk:
+	kfree(obj);
+	return err;
+}
+
+static int __devexit omap_iommu_remove(struct platform_device *pdev)
+{
+	int irq;
+	struct resource *res;
+	struct iommu *obj = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	iopgtable_clear_entry_all(obj);
+	free_pages((unsigned long)obj->iopgd, get_order(IOPGD_TABLE_SIZE));
+
+	irq = platform_get_irq(pdev, 0);
+	free_irq(irq, obj);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, resource_size(res));
+	iounmap(obj->regbase);
+
+	clk_put(obj->clk);
+	dev_info(&pdev->dev, "%s removed\n", obj->name);
+	kfree(obj);
+	return 0;
+}
+
+static struct platform_driver omap_iommu_driver = {
+	.probe	= omap_iommu_probe,
+	.remove	= __devexit_p(omap_iommu_remove),
+	.driver	= {
+		.name	= "omap-iommu",
+	},
+};
+
+static void iopte_cachep_ctor(void *iopte)
+{
+	clean_dcache_area(iopte, IOPTE_TABLE_SIZE);
+}
+
+static int __init omap_iommu_init(void)
+{
+	struct kmem_cache *p;
+	const unsigned long flags = SLAB_HWCACHE_ALIGN;
+	size_t align = 1 << 10; /* L2 pagetable alignement */
+
+	p = kmem_cache_create("iopte_cache", IOPTE_TABLE_SIZE, align, flags,
+			      iopte_cachep_ctor);
+	if (!p)
+		return -ENOMEM;
+	iopte_cachep = p;
+
+	return platform_driver_register(&omap_iommu_driver);
+}
+module_init(omap_iommu_init);
+
+static void __exit omap_iommu_exit(void)
+{
+	kmem_cache_destroy(iopte_cachep);
+
+	platform_driver_unregister(&omap_iommu_driver);
+}
+module_exit(omap_iommu_exit);
+
+MODULE_DESCRIPTION("omap iommu: tlb and pagetable primitives");
+MODULE_ALIAS("platform:omap-iommu");
+MODULE_AUTHOR("Hiroshi DOYU, Paul Mundt and Toshihiro Kobayashi");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/plat-omap/iopgtable.h b/arch/arm/plat-omap/iopgtable.h
new file mode 100644
index 0000000..37dac43
--- /dev/null
+++ b/arch/arm/plat-omap/iopgtable.h
@@ -0,0 +1,72 @@
+/*
+ * omap iommu: pagetable definitions
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@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.
+ */
+
+#ifndef __PLAT_OMAP_IOMMU_H
+#define __PLAT_OMAP_IOMMU_H
+
+#define IOPGD_SHIFT		20
+#define IOPGD_SIZE		(1 << IOPGD_SHIFT)
+#define IOPGD_MASK		(~(IOPGD_SIZE - 1))
+#define IOSECTION_MASK		IOPGD_MASK
+#define PTRS_PER_IOPGD		(1 << (32 - IOPGD_SHIFT))
+#define IOPGD_TABLE_SIZE	(PTRS_PER_IOPGD * sizeof(u32))
+
+#define IOSUPER_SIZE		(IOPGD_SIZE << 4)
+#define IOSUPER_MASK		(~(IOSUPER_SIZE - 1))
+
+#define IOPTE_SHIFT		12
+#define IOPTE_SIZE		(1 << IOPTE_SHIFT)
+#define IOPTE_MASK		(~(IOPTE_SIZE - 1))
+#define IOPAGE_MASK		IOPTE_MASK
+#define PTRS_PER_IOPTE		(1 << (IOPGD_SHIFT - IOPTE_SHIFT))
+#define IOPTE_TABLE_SIZE	(PTRS_PER_IOPTE * sizeof(u32))
+
+#define IOLARGE_SIZE		(IOPTE_SIZE << 4)
+#define IOLARGE_MASK		(~(IOLARGE_SIZE - 1))
+
+#define IOPGD_TABLE		(1 << 0)
+#define IOPGD_SECTION		(2 << 0)
+#define IOPGD_SUPER		(1 << 18 | 2 << 0)
+
+#define IOPTE_SMALL		(2 << 0)
+#define IOPTE_LARGE		(1 << 0)
+
+#define iopgd_index(da)		(((da) >> IOPGD_SHIFT) & (PTRS_PER_IOPGD - 1))
+#define iopgd_offset(obj, da)	((obj)->iopgd + iopgd_index(da))
+
+#define iopte_paddr(iopgd)	(*iopgd & ~((1 << 10) - 1))
+#define iopte_vaddr(iopgd)	((u32 *)phys_to_virt(iopte_paddr(iopgd)))
+
+#define iopte_index(da)		(((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1))
+#define iopte_offset(iopgd, da)	(iopte_vaddr(iopgd) + iopte_index(da))
+
+static inline u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa,
+				   u32 flags)
+{
+	memset(e, 0, sizeof(*e));
+
+	e->da		= da;
+	e->pa		= pa;
+	e->valid	= 1;
+	/* FIXME: add OMAP1 support */
+	e->pgsz		= flags & MMU_CAM_PGSZ_MASK;
+	e->endian	= flags & MMU_RAM_ENDIAN_MASK;
+	e->elsz		= flags & MMU_RAM_ELSZ_MASK;
+	e->mixed	= flags & MMU_RAM_MIXED_MASK;
+
+	return iopgsz_to_bytes(e->pgsz);
+}
+
+#define to_iommu(dev)							\
+	(struct iommu *)platform_get_drvdata(to_platform_device(dev))
+
+#endif /* __PLAT_OMAP_IOMMU_H */
diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c
new file mode 100644
index 0000000..2fce2c1
--- /dev/null
+++ b/arch/arm/plat-omap/iovmm.c
@@ -0,0 +1,896 @@
+/*
+ * omap iommu: simple virtual address space management
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@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.
+ */
+
+#include <linux/err.h>
+#include <linux/vmalloc.h>
+#include <linux/device.h>
+#include <linux/scatterlist.h>
+
+#include <asm/cacheflush.h>
+#include <asm/mach/map.h>
+
+#include <mach/iommu.h>
+#include <mach/iovmm.h>
+
+#include "iopgtable.h"
+
+/*
+ * A device driver needs to create address mappings between:
+ *
+ * - iommu/device address
+ * - physical address
+ * - mpu virtual address
+ *
+ * There are 4 possible patterns for them:
+ *
+ *    |iova/			  mapping		iommu_		page
+ *    | da	pa	va	(d)-(p)-(v)		function	type
+ *  ---------------------------------------------------------------------------
+ *  1 | c	c	c	 1 - 1 - 1	  _kmap() / _kunmap()	s
+ *  2 | c	c,a	c	 1 - 1 - 1	_kmalloc()/ _kfree()	s
+ *  3 | c	d	c	 1 - n - 1	  _vmap() / _vunmap()	s
+ *  4 | c	d,a	c	 1 - n - 1	_vmalloc()/ _vfree()	n*
+ *
+ *
+ *	'iova':	device iommu virtual address
+ *	'da':	alias of 'iova'
+ *	'pa':	physical address
+ *	'va':	mpu virtual address
+ *
+ *	'c':	contiguous memory area
+ *	'd':	dicontiguous memory area
+ *	'a':	anonymous memory allocation
+ *	'()':	optional feature
+ *
+ *	'n':	a normal page(4KB) size is used.
+ *	's':	multiple iommu superpage(16MB, 1MB, 64KB, 4KB) size is used.
+ *
+ *	'*':	not yet, but feasible.
+ */
+
+static struct kmem_cache *iovm_area_cachep;
+
+/* return total bytes of sg buffers */
+static size_t sgtable_len(const struct sg_table *sgt)
+{
+	unsigned int i, total = 0;
+	struct scatterlist *sg;
+
+	if (!sgt)
+		return 0;
+
+	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+		size_t bytes;
+
+		bytes = sg_dma_len(sg);
+
+		if (!iopgsz_ok(bytes)) {
+			pr_err("%s: sg[%d] not iommu pagesize(%x)\n",
+			       __func__, i, bytes);
+			return 0;
+		}
+
+		total += bytes;
+	}
+
+	return total;
+}
+#define sgtable_ok(x)	(!!sgtable_len(x))
+
+/*
+ * calculate the optimal number sg elements from total bytes based on
+ * iommu superpages
+ */
+static unsigned int sgtable_nents(size_t bytes)
+{
+	int i;
+	unsigned int nr_entries;
+	const unsigned long pagesize[] = { SZ_16M, SZ_1M, SZ_64K, SZ_4K, };
+
+	if (!IS_ALIGNED(bytes, PAGE_SIZE)) {
+		pr_err("%s: wrong size %08x\n", __func__, bytes);
+		return 0;
+	}
+
+	nr_entries = 0;
+	for (i = 0; i < ARRAY_SIZE(pagesize); i++) {
+		if (bytes >= pagesize[i]) {
+			nr_entries += (bytes / pagesize[i]);
+			bytes %= pagesize[i];
+		}
+	}
+	BUG_ON(bytes);
+
+	return nr_entries;
+}
+
+/* allocate and initialize sg_table header(a kind of 'superblock') */
+static struct sg_table *sgtable_alloc(const size_t bytes, u32 flags)
+{
+	unsigned int nr_entries;
+	int err;
+	struct sg_table *sgt;
+
+	if (!bytes)
+		return ERR_PTR(-EINVAL);
+
+	if (!IS_ALIGNED(bytes, PAGE_SIZE))
+		return ERR_PTR(-EINVAL);
+
+	/* FIXME: IOVMF_DA_FIXED should support 'superpages' */
+	if ((flags & IOVMF_LINEAR) && (flags & IOVMF_DA_ANON)) {
+		nr_entries = sgtable_nents(bytes);
+		if (!nr_entries)
+			return ERR_PTR(-EINVAL);
+	} else
+		nr_entries =  bytes / PAGE_SIZE;
+
+	sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
+	if (!sgt)
+		return ERR_PTR(-ENOMEM);
+
+	err = sg_alloc_table(sgt, nr_entries, GFP_KERNEL);
+	if (err)
+		return ERR_PTR(err);
+
+	pr_debug("%s: sgt:%p(%d entries)\n", __func__, sgt, nr_entries);
+
+	return sgt;
+}
+
+/* free sg_table header(a kind of superblock) */
+static void sgtable_free(struct sg_table *sgt)
+{
+	if (!sgt)
+		return;
+
+	sg_free_table(sgt);
+	kfree(sgt);
+
+	pr_debug("%s: sgt:%p\n", __func__, sgt);
+}
+
+/* map 'sglist' to a contiguous mpu virtual area and return 'va' */
+static void *vmap_sg(const struct sg_table *sgt)
+{
+	u32 va;
+	size_t total;
+	unsigned int i;
+	struct scatterlist *sg;
+	struct vm_struct *new;
+	const struct mem_type *mtype;
+
+	mtype = get_mem_type(MT_DEVICE);
+	if (!mtype)
+		return ERR_PTR(-EINVAL);
+
+	total = sgtable_len(sgt);
+	if (!total)
+		return ERR_PTR(-EINVAL);
+
+	new = __get_vm_area(total, VM_IOREMAP, VMALLOC_START, VMALLOC_END);
+	if (!new)
+		return ERR_PTR(-ENOMEM);
+	va = (u32)new->addr;
+
+	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+		size_t bytes;
+		u32 pa;
+		int err;
+
+		pa = sg_phys(sg);
+		bytes = sg_dma_len(sg);
+
+		BUG_ON(bytes != PAGE_SIZE);
+
+		err = ioremap_page(va,  pa, mtype);
+		if (err)
+			goto err_out;
+
+		va += bytes;
+	}
+
+	flush_cache_vmap(new->addr, total);
+	return new->addr;
+
+err_out:
+	WARN_ON(1); /* FIXME: cleanup some mpu mappings */
+	vunmap(new->addr);
+	return ERR_PTR(-EAGAIN);
+}
+
+static inline void vunmap_sg(const void *va)
+{
+	vunmap(va);
+}
+
+static struct iovm_struct *__find_iovm_area(struct iommu *obj, const u32 da)
+{
+	struct iovm_struct *tmp;
+
+	list_for_each_entry(tmp, &obj->mmap, list) {
+		if ((da >= tmp->da_start) && (da < tmp->da_end)) {
+			size_t len;
+
+			len = tmp->da_end - tmp->da_start;
+
+			dev_dbg(obj->dev, "%s: %08x-%08x-%08x(%x) %08x\n",
+				__func__, tmp->da_start, da, tmp->da_end, len,
+				tmp->flags);
+
+			return tmp;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * find_iovm_area  -  find iovma which includes @da
+ * @da:		iommu device virtual address
+ *
+ * Find the existing iovma starting at @da
+ */
+struct iovm_struct *find_iovm_area(struct iommu *obj, u32 da)
+{
+	struct iovm_struct *area;
+
+	mutex_lock(&obj->mmap_lock);
+	area = __find_iovm_area(obj, da);
+	mutex_unlock(&obj->mmap_lock);
+
+	return area;
+}
+EXPORT_SYMBOL_GPL(find_iovm_area);
+
+/*
+ * This finds the hole(area) which fits the requested address and len
+ * in iovmas mmap, and returns the new allocated iovma.
+ */
+static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da,
+					   size_t bytes, u32 flags)
+{
+	struct iovm_struct *new, *tmp;
+	u32 start, prev_end, alignement;
+
+	if (!obj || !bytes)
+		return ERR_PTR(-EINVAL);
+
+	start = da;
+	alignement = PAGE_SIZE;
+
+	if (flags & IOVMF_DA_ANON) {
+		/*
+		 * Reserve the first page for NULL
+		 */
+		start = PAGE_SIZE;
+		if (flags & IOVMF_LINEAR)
+			alignement = iopgsz_max(bytes);
+		start = roundup(start, alignement);
+	}
+
+	tmp = NULL;
+	if (list_empty(&obj->mmap))
+		goto found;
+
+	prev_end = 0;
+	list_for_each_entry(tmp, &obj->mmap, list) {
+
+		if ((prev_end <= start) && (start + bytes < tmp->da_start))
+			goto found;
+
+		if (flags & IOVMF_DA_ANON)
+			start = roundup(tmp->da_end, alignement);
+
+		prev_end = tmp->da_end;
+	}
+
+	if ((start >= prev_end) && (ULONG_MAX - start >= bytes))
+		goto found;
+
+	dev_dbg(obj->dev, "%s: no space to fit %08x(%x) flags: %08x\n",
+		__func__, da, bytes, flags);
+
+	return ERR_PTR(-EINVAL);
+
+found:
+	new = kmem_cache_zalloc(iovm_area_cachep, GFP_KERNEL);
+	if (!new)
+		return ERR_PTR(-ENOMEM);
+
+	new->iommu = obj;
+	new->da_start = start;
+	new->da_end = start + bytes;
+	new->flags = flags;
+
+	/*
+	 * keep ascending order of iovmas
+	 */
+	if (tmp)
+		list_add_tail(&new->list, &tmp->list);
+	else
+		list_add(&new->list, &obj->mmap);
+
+	dev_dbg(obj->dev, "%s: found %08x-%08x-%08x(%x) %08x\n",
+		__func__, new->da_start, start, new->da_end, bytes, flags);
+
+	return new;
+}
+
+static void free_iovm_area(struct iommu *obj, struct iovm_struct *area)
+{
+	size_t bytes;
+
+	BUG_ON(!obj || !area);
+
+	bytes = area->da_end - area->da_start;
+
+	dev_dbg(obj->dev, "%s: %08x-%08x(%x) %08x\n",
+		__func__, area->da_start, area->da_end, bytes, area->flags);
+
+	list_del(&area->list);
+	kmem_cache_free(iovm_area_cachep, area);
+}
+
+/**
+ * da_to_va - convert (d) to (v)
+ * @obj:	objective iommu
+ * @da:		iommu device virtual address
+ * @va:		mpu virtual address
+ *
+ * Returns mpu virtual addr which corresponds to a given device virtual addr
+ */
+void *da_to_va(struct iommu *obj, u32 da)
+{
+	void *va = NULL;
+	struct iovm_struct *area;
+
+	mutex_lock(&obj->mmap_lock);
+
+	area = __find_iovm_area(obj, da);
+	if (!area) {
+		dev_dbg(obj->dev, "%s: no da area(%08x)\n", __func__, da);
+		goto out;
+	}
+	va = area->va;
+	mutex_unlock(&obj->mmap_lock);
+out:
+	return va;
+}
+EXPORT_SYMBOL_GPL(da_to_va);
+
+static void sgtable_fill_vmalloc(struct sg_table *sgt, void *_va)
+{
+	unsigned int i;
+	struct scatterlist *sg;
+	void *va = _va;
+	void *va_end;
+
+	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+		struct page *pg;
+		const size_t bytes = PAGE_SIZE;
+
+		/*
+		 * iommu 'superpage' isn't supported with 'iommu_vmalloc()'
+		 */
+		pg = vmalloc_to_page(va);
+		BUG_ON(!pg);
+		sg_set_page(sg, pg, bytes, 0);
+
+		va += bytes;
+	}
+
+	va_end = _va + PAGE_SIZE * i;
+	flush_cache_vmap(_va, va_end);
+}
+
+static inline void sgtable_drain_vmalloc(struct sg_table *sgt)
+{
+	/*
+	 * Actually this is not necessary at all, just exists for
+	 * consistency of the code readibility.
+	 */
+	BUG_ON(!sgt);
+}
+
+static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len)
+{
+	unsigned int i;
+	struct scatterlist *sg;
+	void *va;
+
+	va = phys_to_virt(pa);
+
+	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+		size_t bytes;
+
+		bytes = iopgsz_max(len);
+
+		BUG_ON(!iopgsz_ok(bytes));
+
+		sg_set_buf(sg, phys_to_virt(pa), bytes);
+		/*
+		 * 'pa' is cotinuous(linear).
+		 */
+		pa += bytes;
+		len -= bytes;
+	}
+	BUG_ON(len);
+
+	clean_dcache_area(va, len);
+}
+
+static inline void sgtable_drain_kmalloc(struct sg_table *sgt)
+{
+	/*
+	 * Actually this is not necessary at all, just exists for
+	 * consistency of the code readibility
+	 */
+	BUG_ON(!sgt);
+}
+
+/* create 'da' <-> 'pa' mapping from 'sgt' */
+static int map_iovm_area(struct iommu *obj, struct iovm_struct *new,
+			 const struct sg_table *sgt, u32 flags)
+{
+	int err;
+	unsigned int i, j;
+	struct scatterlist *sg;
+	u32 da = new->da_start;
+
+	if (!obj || !new || !sgt)
+		return -EINVAL;
+
+	BUG_ON(!sgtable_ok(sgt));
+
+	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+		u32 pa;
+		int pgsz;
+		size_t bytes;
+		struct iotlb_entry e;
+
+		pa = sg_phys(sg);
+		bytes = sg_dma_len(sg);
+
+		flags &= ~IOVMF_PGSZ_MASK;
+		pgsz = bytes_to_iopgsz(bytes);
+		if (pgsz < 0)
+			goto err_out;
+		flags |= pgsz;
+
+		pr_debug("%s: [%d] %08x %08x(%x)\n", __func__,
+			 i, da, pa, bytes);
+
+		iotlb_init_entry(&e, da, pa, flags);
+		err = iopgtable_store_entry(obj, &e);
+		if (err)
+			goto err_out;
+
+		da += bytes;
+	}
+	return 0;
+
+err_out:
+	da = new->da_start;
+
+	for_each_sg(sgt->sgl, sg, i, j) {
+		size_t bytes;
+
+		bytes = iopgtable_clear_entry(obj, da);
+
+		BUG_ON(!iopgsz_ok(bytes));
+
+		da += bytes;
+	}
+	return err;
+}
+
+/* release 'da' <-> 'pa' mapping */
+static void unmap_iovm_area(struct iommu *obj, struct iovm_struct *area)
+{
+	u32 start;
+	size_t total = area->da_end - area->da_start;
+
+	BUG_ON((!total) || !IS_ALIGNED(total, PAGE_SIZE));
+
+	start = area->da_start;
+	while (total > 0) {
+		size_t bytes;
+
+		bytes = iopgtable_clear_entry(obj, start);
+		if (bytes == 0)
+			bytes = PAGE_SIZE;
+		else
+			dev_dbg(obj->dev, "%s: unmap %08x(%x) %08x\n",
+				__func__, start, bytes, area->flags);
+
+		BUG_ON(!IS_ALIGNED(bytes, PAGE_SIZE));
+
+		total -= bytes;
+		start += bytes;
+	}
+	BUG_ON(total);
+}
+
+/* template function for all unmapping */
+static struct sg_table *unmap_vm_area(struct iommu *obj, const u32 da,
+				      void (*fn)(const void *), u32 flags)
+{
+	struct sg_table *sgt = NULL;
+	struct iovm_struct *area;
+
+	if (!IS_ALIGNED(da, PAGE_SIZE)) {
+		dev_err(obj->dev, "%s: alignment err(%08x)\n", __func__, da);
+		return NULL;
+	}
+
+	mutex_lock(&obj->mmap_lock);
+
+	area = __find_iovm_area(obj, da);
+	if (!area) {
+		dev_dbg(obj->dev, "%s: no da area(%08x)\n", __func__, da);
+		goto out;
+	}
+
+	if ((area->flags & flags) != flags) {
+		dev_err(obj->dev, "%s: wrong flags(%08x)\n", __func__,
+			area->flags);
+		goto out;
+	}
+	sgt = (struct sg_table *)area->sgt;
+
+	unmap_iovm_area(obj, area);
+
+	fn(area->va);
+
+	dev_dbg(obj->dev, "%s: %08x-%08x-%08x(%x) %08x\n", __func__,
+		area->da_start, da, area->da_end,
+		area->da_end - area->da_start, area->flags);
+
+	free_iovm_area(obj, area);
+out:
+	mutex_unlock(&obj->mmap_lock);
+
+	return sgt;
+}
+
+static u32 map_iommu_region(struct iommu *obj, u32 da,
+	      const struct sg_table *sgt, void *va, size_t bytes, u32 flags)
+{
+	int err = -ENOMEM;
+	struct iovm_struct *new;
+
+	mutex_lock(&obj->mmap_lock);
+
+	new = alloc_iovm_area(obj, da, bytes, flags);
+	if (IS_ERR(new)) {
+		err = PTR_ERR(new);
+		goto err_alloc_iovma;
+	}
+	new->va = va;
+	new->sgt = sgt;
+
+	if (map_iovm_area(obj, new, sgt, new->flags))
+		goto err_map;
+
+	mutex_unlock(&obj->mmap_lock);
+
+	dev_dbg(obj->dev, "%s: da:%08x(%x) flags:%08x va:%p\n",
+		__func__, new->da_start, bytes, new->flags, va);
+
+	return new->da_start;
+
+err_map:
+	free_iovm_area(obj, new);
+err_alloc_iovma:
+	mutex_unlock(&obj->mmap_lock);
+	return err;
+}
+
+static inline u32 __iommu_vmap(struct iommu *obj, u32 da,
+		 const struct sg_table *sgt, void *va, size_t bytes, u32 flags)
+{
+	return map_iommu_region(obj, da, sgt, va, bytes, flags);
+}
+
+/**
+ * iommu_vmap  -  (d)-(p)-(v) address mapper
+ * @obj:	objective iommu
+ * @sgt:	address of scatter gather table
+ * @flags:	iovma and page property
+ *
+ * Creates 1-n-1 mapping with given @sgt and returns @da.
+ * All @sgt element must be io page size aligned.
+ */
+u32 iommu_vmap(struct iommu *obj, u32 da, const struct sg_table *sgt,
+		 u32 flags)
+{
+	size_t bytes;
+	void *va;
+
+	if (!obj || !obj->dev || !sgt)
+		return -EINVAL;
+
+	bytes = sgtable_len(sgt);
+	if (!bytes)
+		return -EINVAL;
+	bytes = PAGE_ALIGN(bytes);
+
+	va = vmap_sg(sgt);
+	if (IS_ERR(va))
+		return PTR_ERR(va);
+
+	flags &= IOVMF_HW_MASK;
+	flags |= IOVMF_DISCONT;
+	flags |= IOVMF_MMIO;
+	flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
+
+	da = __iommu_vmap(obj, da, sgt, va, bytes, flags);
+	if (IS_ERR_VALUE(da))
+		vunmap_sg(va);
+
+	return da;
+}
+EXPORT_SYMBOL_GPL(iommu_vmap);
+
+/**
+ * iommu_vunmap  -  release virtual mapping obtained by 'iommu_vmap()'
+ * @obj:	objective iommu
+ * @da:		iommu device virtual address
+ *
+ * Free the iommu virtually contiguous memory area starting at
+ * @da, which was returned by 'iommu_vmap()'.
+ */
+struct sg_table *iommu_vunmap(struct iommu *obj, u32 da)
+{
+	struct sg_table *sgt;
+	/*
+	 * 'sgt' is allocated before 'iommu_vmalloc()' is called.
+	 * Just returns 'sgt' to the caller to free
+	 */
+	sgt = unmap_vm_area(obj, da, vunmap_sg, IOVMF_DISCONT | IOVMF_MMIO);
+	if (!sgt)
+		dev_dbg(obj->dev, "%s: No sgt\n", __func__);
+	return sgt;
+}
+EXPORT_SYMBOL_GPL(iommu_vunmap);
+
+/**
+ * iommu_vmalloc  -  (d)-(p)-(v) address allocator and mapper
+ * @obj:	objective iommu
+ * @da:		contiguous iommu virtual memory
+ * @bytes:	allocation size
+ * @flags:	iovma and page property
+ *
+ * Allocate @bytes linearly and creates 1-n-1 mapping and returns
+ * @da again, which might be adjusted if 'IOVMF_DA_ANON' is set.
+ */
+u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
+{
+	void *va;
+	struct sg_table *sgt;
+
+	if (!obj || !obj->dev || !bytes)
+		return -EINVAL;
+
+	bytes = PAGE_ALIGN(bytes);
+
+	va = vmalloc(bytes);
+	if (!va)
+		return -ENOMEM;
+
+	sgt = sgtable_alloc(bytes, flags);
+	if (IS_ERR(sgt)) {
+		da = PTR_ERR(sgt);
+		goto err_sgt_alloc;
+	}
+	sgtable_fill_vmalloc(sgt, va);
+
+	flags &= IOVMF_HW_MASK;
+	flags |= IOVMF_DISCONT;
+	flags |= IOVMF_ALLOC;
+	flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
+
+	da = __iommu_vmap(obj, da, sgt, va, bytes, flags);
+	if (IS_ERR_VALUE(da))
+		goto err_iommu_vmap;
+
+	return da;
+
+err_iommu_vmap:
+	sgtable_drain_vmalloc(sgt);
+	sgtable_free(sgt);
+err_sgt_alloc:
+	vfree(va);
+	return da;
+}
+EXPORT_SYMBOL_GPL(iommu_vmalloc);
+
+/**
+ * iommu_vfree  -  release memory allocated by 'iommu_vmalloc()'
+ * @obj:	objective iommu
+ * @da:		iommu device virtual address
+ *
+ * Frees the iommu virtually continuous memory area starting at
+ * @da, as obtained from 'iommu_vmalloc()'.
+ */
+void iommu_vfree(struct iommu *obj, const u32 da)
+{
+	struct sg_table *sgt;
+
+	sgt = unmap_vm_area(obj, da, vfree, IOVMF_DISCONT | IOVMF_ALLOC);
+	if (!sgt)
+		dev_dbg(obj->dev, "%s: No sgt\n", __func__);
+	sgtable_free(sgt);
+}
+EXPORT_SYMBOL_GPL(iommu_vfree);
+
+static u32 __iommu_kmap(struct iommu *obj, u32 da, u32 pa, void *va,
+			  size_t bytes, u32 flags)
+{
+	struct sg_table *sgt;
+
+	sgt = sgtable_alloc(bytes, flags);
+	if (IS_ERR(sgt))
+		return PTR_ERR(sgt);
+
+	sgtable_fill_kmalloc(sgt, pa, bytes);
+
+	da = map_iommu_region(obj, da, sgt, va, bytes, flags);
+	if (IS_ERR_VALUE(da)) {
+		sgtable_drain_kmalloc(sgt);
+		sgtable_free(sgt);
+	}
+
+	return da;
+}
+
+/**
+ * iommu_kmap  -  (d)-(p)-(v) address mapper
+ * @obj:	objective iommu
+ * @da:		contiguous iommu virtual memory
+ * @pa:		contiguous physical memory
+ * @flags:	iovma and page property
+ *
+ * Creates 1-1-1 mapping and returns @da again, which can be
+ * adjusted if 'IOVMF_DA_ANON' is set.
+ */
+u32 iommu_kmap(struct iommu *obj, u32 da, u32 pa, size_t bytes,
+		 u32 flags)
+{
+	void *va;
+
+	if (!obj || !obj->dev || !bytes)
+		return -EINVAL;
+
+	bytes = PAGE_ALIGN(bytes);
+
+	va = ioremap(pa, bytes);
+	if (!va)
+		return -ENOMEM;
+
+	flags &= IOVMF_HW_MASK;
+	flags |= IOVMF_LINEAR;
+	flags |= IOVMF_MMIO;
+	flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
+
+	da = __iommu_kmap(obj, da, pa, va, bytes, flags);
+	if (IS_ERR_VALUE(da))
+		iounmap(va);
+
+	return da;
+}
+EXPORT_SYMBOL_GPL(iommu_kmap);
+
+/**
+ * iommu_kunmap  -  release virtual mapping obtained by 'iommu_kmap()'
+ * @obj:	objective iommu
+ * @da:		iommu device virtual address
+ *
+ * Frees the iommu virtually contiguous memory area starting at
+ * @da, which was passed to and was returned by'iommu_kmap()'.
+ */
+void iommu_kunmap(struct iommu *obj, u32 da)
+{
+	struct sg_table *sgt;
+	typedef void (*func_t)(const void *);
+
+	sgt = unmap_vm_area(obj, da, (func_t)__iounmap,
+			    IOVMF_LINEAR | IOVMF_MMIO);
+	if (!sgt)
+		dev_dbg(obj->dev, "%s: No sgt\n", __func__);
+	sgtable_free(sgt);
+}
+EXPORT_SYMBOL_GPL(iommu_kunmap);
+
+/**
+ * iommu_kmalloc  -  (d)-(p)-(v) address allocator and mapper
+ * @obj:	objective iommu
+ * @da:		contiguous iommu virtual memory
+ * @bytes:	bytes for allocation
+ * @flags:	iovma and page property
+ *
+ * Allocate @bytes linearly and creates 1-1-1 mapping and returns
+ * @da again, which might be adjusted if 'IOVMF_DA_ANON' is set.
+ */
+u32 iommu_kmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
+{
+	void *va;
+	u32 pa;
+
+	if (!obj || !obj->dev || !bytes)
+		return -EINVAL;
+
+	bytes = PAGE_ALIGN(bytes);
+
+	va = kmalloc(bytes, GFP_KERNEL | GFP_DMA);
+	if (!va)
+		return -ENOMEM;
+	pa = virt_to_phys(va);
+
+	flags &= IOVMF_HW_MASK;
+	flags |= IOVMF_LINEAR;
+	flags |= IOVMF_ALLOC;
+	flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
+
+	da = __iommu_kmap(obj, da, pa, va, bytes, flags);
+	if (IS_ERR_VALUE(da))
+		kfree(va);
+
+	return da;
+}
+EXPORT_SYMBOL_GPL(iommu_kmalloc);
+
+/**
+ * iommu_kfree  -  release virtual mapping obtained by 'iommu_kmalloc()'
+ * @obj:	objective iommu
+ * @da:		iommu device virtual address
+ *
+ * Frees the iommu virtually contiguous memory area starting at
+ * @da, which was passed to and was returned by'iommu_kmalloc()'.
+ */
+void iommu_kfree(struct iommu *obj, u32 da)
+{
+	struct sg_table *sgt;
+
+	sgt = unmap_vm_area(obj, da, kfree, IOVMF_LINEAR | IOVMF_ALLOC);
+	if (!sgt)
+		dev_dbg(obj->dev, "%s: No sgt\n", __func__);
+	sgtable_free(sgt);
+}
+EXPORT_SYMBOL_GPL(iommu_kfree);
+
+
+static int __init iovmm_init(void)
+{
+	const unsigned long flags = SLAB_HWCACHE_ALIGN;
+	struct kmem_cache *p;
+
+	p = kmem_cache_create("iovm_area_cache", sizeof(struct iovm_struct), 0,
+			      flags, NULL);
+	if (!p)
+		return -ENOMEM;
+	iovm_area_cachep = p;
+
+	return 0;
+}
+module_init(iovmm_init);
+
+static void __exit iovmm_exit(void)
+{
+	kmem_cache_destroy(iovm_area_cachep);
+}
+module_exit(iovmm_exit);
+
+MODULE_DESCRIPTION("omap iommu: simple virtual address space management");
+MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index 28b0a82..efa0e01 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -91,11 +91,20 @@
 static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
 {
 	struct omap_mcbsp *mcbsp_tx = dev_id;
+	u16 irqst_spcr2;
 
-	dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n",
-		OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));
+	irqst_spcr2 = OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2);
+	dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
 
-	complete(&mcbsp_tx->tx_irq_completion);
+	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 */
+		OMAP_MCBSP_WRITE(mcbsp_tx->io_base, SPCR2,
+			irqst_spcr2 & ~(XSYNC_ERR));
+	} else {
+		complete(&mcbsp_tx->tx_irq_completion);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -103,11 +112,20 @@
 static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
 {
 	struct omap_mcbsp *mcbsp_rx = dev_id;
+	u16 irqst_spcr1;
 
-	dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n",
-		OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));
+	irqst_spcr1 = OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR1);
+	dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
 
-	complete(&mcbsp_rx->rx_irq_completion);
+	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 */
+		OMAP_MCBSP_WRITE(mcbsp_rx->io_base, SPCR1,
+			irqst_spcr1 & ~(RSYNC_ERR));
+	} else {
+		complete(&mcbsp_rx->tx_irq_completion);
+	}
 
 	return IRQ_HANDLED;
 }
diff --git a/arch/arm/plat-omap/mux.c b/arch/arm/plat-omap/mux.c
index 80b040f..8d329fb 100644
--- a/arch/arm/plat-omap/mux.c
+++ b/arch/arm/plat-omap/mux.c
@@ -54,6 +54,9 @@
 {
 	struct pin_config *reg;
 
+	if (cpu_is_omap44xx())
+		return 0;
+
 	if (mux_cfg == NULL) {
 		printk(KERN_ERR "Pin mux table not initialized\n");
 		return -ENODEV;
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index fa5297d..a5b9bcd 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -6,6 +6,9 @@
  * Copyright (C) 2005 Nokia Corporation
  * Written by Tony Lindgren <tony@atomide.com>
  *
+ * 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 version 2 as
  * published by the Free Software Foundation.
@@ -38,12 +41,14 @@
 #define OMAP1_SRAM_VA		VMALLOC_END
 #define OMAP2_SRAM_PA		0x40200000
 #define OMAP2_SRAM_PUB_PA	0x4020f800
-#define OMAP2_SRAM_VA		VMALLOC_END
-#define OMAP2_SRAM_PUB_VA	(VMALLOC_END + 0x800)
+#define OMAP2_SRAM_VA		0xe3000000
+#define OMAP2_SRAM_PUB_VA	(OMAP2_SRAM_VA + 0x800)
 #define OMAP3_SRAM_PA           0x40200000
 #define OMAP3_SRAM_VA           0xd7000000
 #define OMAP3_SRAM_PUB_PA       0x40208000
 #define OMAP3_SRAM_PUB_VA       0xd7008000
+#define OMAP4_SRAM_PA		0x40200000		/*0x402f0000*/
+#define OMAP4_SRAM_VA		0xd7000000		/*0xd70f0000*/
 
 #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
 #define SRAM_BOOTLOADER_SZ	0x00
@@ -87,6 +92,10 @@
 {
 	int type = 0;
 
+	if (cpu_is_omap44xx())
+		/* Not yet supported */
+		return 0;
+
 	if (cpu_is_omap242x())
 		type = omap_rev() & OMAP2_DEVICETYPE_MASK;
 
@@ -135,6 +144,10 @@
 				omap_sram_base = OMAP3_SRAM_VA;
 				omap_sram_start = OMAP3_SRAM_PA;
 				omap_sram_size = 0x10000; /* 64K */
+			} else if (cpu_is_omap44xx()) {
+				omap_sram_base = OMAP4_SRAM_VA;
+				omap_sram_start = OMAP4_SRAM_PA;
+				omap_sram_size = 0x8000; /* 32K */
 			} else {
 				omap_sram_base = OMAP2_SRAM_VA;
 				omap_sram_start = OMAP2_SRAM_PA;
@@ -201,8 +214,23 @@
 		base = OMAP3_SRAM_PA;
 		base = ROUND_DOWN(base, PAGE_SIZE);
 		omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
+
+		/*
+		 * SRAM must be marked as non-cached on OMAP3 since the
+		 * CORE DPLL M2 divider change code (in SRAM) runs with the
+		 * SDRAM controller disabled, and if it is marked cached,
+		 * the ARM may attempt to write cache lines back to SDRAM
+		 * which will cause the system to hang.
+		 */
+		omap_sram_io_desc[0].type = MT_MEMORY_NONCACHED;
 	}
 
+	if (cpu_is_omap44xx()) {
+		omap_sram_io_desc[0].virtual = OMAP4_SRAM_VA;
+		base = OMAP4_SRAM_PA;
+		base = ROUND_DOWN(base, PAGE_SIZE);
+		omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
+	}
 	omap_sram_io_desc[0].length = 1024 * 1024;	/* Use section desc */
 	iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc));
 
@@ -242,20 +270,13 @@
 	return (void *)omap_sram_ceil;
 }
 
-static void omap_sram_error(void)
-{
-	panic("Uninitialized SRAM function\n");
-}
-
 #ifdef CONFIG_ARCH_OMAP1
 
 static void (*_omap_sram_reprogram_clock)(u32 dpllctl, u32 ckctl);
 
 void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl)
 {
-	if (!_omap_sram_reprogram_clock)
-		omap_sram_error();
-
+	BUG_ON(!_omap_sram_reprogram_clock);
 	_omap_sram_reprogram_clock(dpllctl, ckctl);
 }
 
@@ -280,9 +301,7 @@
 void omap2_sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
 		   u32 base_cs, u32 force_unlock)
 {
-	if (!_omap2_sram_ddr_init)
-		omap_sram_error();
-
+	BUG_ON(!_omap2_sram_ddr_init);
 	_omap2_sram_ddr_init(slow_dll_ctrl, fast_dll_ctrl,
 			     base_cs, force_unlock);
 }
@@ -292,9 +311,7 @@
 
 void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val, u32 mem_type)
 {
-	if (!_omap2_sram_reprogram_sdrc)
-		omap_sram_error();
-
+	BUG_ON(!_omap2_sram_reprogram_sdrc);
 	_omap2_sram_reprogram_sdrc(perf_level, dll_val, mem_type);
 }
 
@@ -302,9 +319,7 @@
 
 u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass)
 {
-	if (!_omap2_set_prcm)
-		omap_sram_error();
-
+	BUG_ON(!_omap2_set_prcm);
 	return _omap2_set_prcm(dpll_ctrl_val, sdrc_rfr_val, bypass);
 }
 #endif
@@ -356,16 +371,15 @@
 static u32 (*_omap3_sram_configure_core_dpll)(u32 sdrc_rfr_ctrl,
 					      u32 sdrc_actim_ctrla,
 					      u32 sdrc_actim_ctrlb,
-					      u32 m2);
+					      u32 m2, u32 unlock_dll);
 u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl, u32 sdrc_actim_ctrla,
-			      u32 sdrc_actim_ctrlb, u32 m2)
+			      u32 sdrc_actim_ctrlb, u32 m2, u32 unlock_dll)
 {
-	if (!_omap3_sram_configure_core_dpll)
-		omap_sram_error();
-
+	BUG_ON(!_omap3_sram_configure_core_dpll);
 	return _omap3_sram_configure_core_dpll(sdrc_rfr_ctrl,
 					       sdrc_actim_ctrla,
-					       sdrc_actim_ctrlb, m2);
+					       sdrc_actim_ctrlb, m2,
+					       unlock_dll);
 }
 
 /* REVISIT: Should this be same as omap34xx_sram_init() after off-idle? */
@@ -406,6 +420,8 @@
 		omap243x_sram_init();
 	else if (cpu_is_omap34xx())
 		omap34xx_sram_init();
+	else if (cpu_is_omap44xx())
+		omap34xx_sram_init(); /* FIXME: */
 
 	return 0;
 }
diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c
index 32eb9e3..e814803 100644
--- a/arch/arm/plat-orion/gpio.c
+++ b/arch/arm/plat-orion/gpio.c
@@ -15,10 +15,9 @@
 #include <linux/spinlock.h>
 #include <linux/bitops.h>
 #include <linux/io.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
 
 static DEFINE_SPINLOCK(gpio_lock);
-static const char *gpio_label[GPIO_MAX];  /* non null for allocated GPIOs */
 static unsigned long gpio_valid_input[BITS_TO_LONGS(GPIO_MAX)];
 static unsigned long gpio_valid_output[BITS_TO_LONGS(GPIO_MAX)];
 
@@ -46,82 +45,54 @@
 	writel(u, GPIO_OUT(pin));
 }
 
+static inline void __set_blinking(unsigned pin, int blink)
+{
+	u32 u;
+
+	u = readl(GPIO_BLINK_EN(pin));
+	if (blink)
+		u |= 1 << (pin & 31);
+	else
+		u &= ~(1 << (pin & 31));
+	writel(u, GPIO_BLINK_EN(pin));
+}
+
+static inline int orion_gpio_is_valid(unsigned pin, int mode)
+{
+	if (pin < GPIO_MAX) {
+		if ((mode & GPIO_INPUT_OK) && !test_bit(pin, gpio_valid_input))
+			goto err_out;
+		if ((mode & GPIO_OUTPUT_OK) && !test_bit(pin, gpio_valid_output))
+			goto err_out;
+		return true;
+	}
+
+err_out:
+	pr_debug("%s: invalid GPIO %d\n", __func__, pin);
+	return false;
+}
 
 /*
  * GENERIC_GPIO primitives.
  */
-int gpio_direction_input(unsigned pin)
+static int orion_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
 {
 	unsigned long flags;
 
-	if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid_input)) {
-		pr_debug("%s: invalid GPIO %d\n", __func__, pin);
+	if (!orion_gpio_is_valid(pin, GPIO_INPUT_OK))
 		return -EINVAL;
-	}
 
 	spin_lock_irqsave(&gpio_lock, flags);
 
-	/*
-	 * Some callers might not have used gpio_request(),
-	 * so flag this pin as requested now.
-	 */
-	if (gpio_label[pin] == NULL)
-		gpio_label[pin] = "?";
-
-	/*
-	 * Configure GPIO direction.
-	 */
+	/* Configure GPIO direction. */
 	__set_direction(pin, 1);
 
 	spin_unlock_irqrestore(&gpio_lock, flags);
 
 	return 0;
 }
-EXPORT_SYMBOL(gpio_direction_input);
 
-int gpio_direction_output(unsigned pin, int value)
-{
-	unsigned long flags;
-	u32 u;
-
-	if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid_output)) {
-		pr_debug("%s: invalid GPIO %d\n", __func__, pin);
-		return -EINVAL;
-	}
-
-	spin_lock_irqsave(&gpio_lock, flags);
-
-	/*
-	 * Some callers might not have used gpio_request(),
-	 * so flag this pin as requested now.
-	 */
-	if (gpio_label[pin] == NULL)
-		gpio_label[pin] = "?";
-
-	/*
-	 * Disable blinking.
-	 */
-	u = readl(GPIO_BLINK_EN(pin));
-	u &= ~(1 << (pin & 31));
-	writel(u, GPIO_BLINK_EN(pin));
-
-	/*
-	 * Configure GPIO output value.
-	 */
-	__set_level(pin, value);
-
-	/*
-	 * Configure GPIO direction.
-	 */
-	__set_direction(pin, 0);
-
-	spin_unlock_irqrestore(&gpio_lock, flags);
-
-	return 0;
-}
-EXPORT_SYMBOL(gpio_direction_output);
-
-int gpio_get_value(unsigned pin)
+static int orion_gpio_get_value(struct gpio_chip *chip, unsigned pin)
 {
 	int val;
 
@@ -132,83 +103,75 @@
 
 	return (val >> (pin & 31)) & 1;
 }
-EXPORT_SYMBOL(gpio_get_value);
 
-void gpio_set_value(unsigned pin, int value)
+static int orion_gpio_direction_output(struct gpio_chip *chip, unsigned pin,
+	int value)
 {
 	unsigned long flags;
-	u32 u;
+
+	if (!orion_gpio_is_valid(pin, GPIO_OUTPUT_OK))
+		return -EINVAL;
 
 	spin_lock_irqsave(&gpio_lock, flags);
 
-	/*
-	 * Disable blinking.
-	 */
-	u = readl(GPIO_BLINK_EN(pin));
-	u &= ~(1 << (pin & 31));
-	writel(u, GPIO_BLINK_EN(pin));
+	/* Disable blinking. */
+	__set_blinking(pin, 0);
 
-	/*
-	 * Configure GPIO output value.
-	 */
+	/* Configure GPIO output value. */
+	__set_level(pin, value);
+
+	/* Configure GPIO direction. */
+	__set_direction(pin, 0);
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+
+	return 0;
+}
+
+static void orion_gpio_set_value(struct gpio_chip *chip, unsigned pin,
+	int value)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	/* Configure GPIO output value. */
 	__set_level(pin, value);
 
 	spin_unlock_irqrestore(&gpio_lock, flags);
 }
-EXPORT_SYMBOL(gpio_set_value);
 
-int gpio_request(unsigned pin, const char *label)
+static int orion_gpio_request(struct gpio_chip *chip, unsigned pin)
 {
-	unsigned long flags;
-	int ret;
-
-	if (pin >= GPIO_MAX ||
-	    !(test_bit(pin, gpio_valid_input) ||
-	      test_bit(pin, gpio_valid_output))) {
-		pr_debug("%s: invalid GPIO %d\n", __func__, pin);
-		return -EINVAL;
-	}
-
-	spin_lock_irqsave(&gpio_lock, flags);
-	if (gpio_label[pin] == NULL) {
-		gpio_label[pin] = label ? label : "?";
-		ret = 0;
-	} else {
-		pr_debug("%s: GPIO %d already used as %s\n",
-			 __func__, pin, gpio_label[pin]);
-		ret = -EBUSY;
-	}
-	spin_unlock_irqrestore(&gpio_lock, flags);
-
-	return ret;
+	if (orion_gpio_is_valid(pin, GPIO_INPUT_OK) ||
+	    orion_gpio_is_valid(pin, GPIO_OUTPUT_OK))
+		return 0;
+	return -EINVAL;
 }
-EXPORT_SYMBOL(gpio_request);
 
-void gpio_free(unsigned pin)
+static struct gpio_chip orion_gpiochip = {
+	.label			= "orion_gpio",
+	.direction_input	= orion_gpio_direction_input,
+	.get			= orion_gpio_get_value,
+	.direction_output	= orion_gpio_direction_output,
+	.set			= orion_gpio_set_value,
+	.request		= orion_gpio_request,
+	.base			= 0,
+	.ngpio			= GPIO_MAX,
+	.can_sleep		= 0,
+};
+
+void __init orion_gpio_init(void)
 {
-	if (pin >= GPIO_MAX ||
-	    !(test_bit(pin, gpio_valid_input) ||
-	      test_bit(pin, gpio_valid_output))) {
-		pr_debug("%s: invalid GPIO %d\n", __func__, pin);
-		return;
-	}
-
-	if (gpio_label[pin] == NULL)
-		pr_warning("%s: GPIO %d already freed\n", __func__, pin);
-	else
-		gpio_label[pin] = NULL;
+	gpiochip_add(&orion_gpiochip);
 }
-EXPORT_SYMBOL(gpio_free);
-
 
 /*
  * Orion-specific GPIO API extensions.
  */
 void __init orion_gpio_set_unused(unsigned pin)
 {
-	/*
-	 * Configure as output, drive low.
-	 */
+	/* Configure as output, drive low. */
 	__set_level(pin, 0);
 	__set_direction(pin, 0);
 }
@@ -230,21 +193,14 @@
 void orion_gpio_set_blink(unsigned pin, int blink)
 {
 	unsigned long flags;
-	u32 u;
 
 	spin_lock_irqsave(&gpio_lock, flags);
 
-	/*
-	 * Set output value to zero.
-	 */
+	/* Set output value to zero. */
 	__set_level(pin, 0);
 
-	u = readl(GPIO_BLINK_EN(pin));
-	if (blink)
-		u |= 1 << (pin & 31);
-	else
-		u &= ~(1 << (pin & 31));
-	writel(u, GPIO_BLINK_EN(pin));
+	/* Set blinking. */
+	__set_blinking(pin, blink);
 
 	spin_unlock_irqrestore(&gpio_lock, flags);
 }
@@ -368,7 +324,7 @@
 }
 
 struct irq_chip orion_gpio_irq_chip = {
-	.name		= "orion_gpio",
+	.name		= "orion_gpio_irq",
 	.ack		= gpio_irq_ack,
 	.mask		= gpio_irq_mask,
 	.unmask		= gpio_irq_unmask,
diff --git a/arch/arm/plat-orion/include/plat/gpio.h b/arch/arm/plat-orion/include/plat/gpio.h
index 33f6c6a..9646a94 100644
--- a/arch/arm/plat-orion/include/plat/gpio.h
+++ b/arch/arm/plat-orion/include/plat/gpio.h
@@ -14,12 +14,9 @@
 /*
  * GENERIC_GPIO primitives.
  */
-int gpio_request(unsigned pin, const char *label);
-void gpio_free(unsigned pin);
-int gpio_direction_input(unsigned pin);
-int gpio_direction_output(unsigned pin, int value);
-int gpio_get_value(unsigned pin);
-void gpio_set_value(unsigned pin, int value);
+#define gpio_get_value  __gpio_get_value
+#define gpio_set_value  __gpio_set_value
+#define gpio_cansleep   __gpio_cansleep
 
 /*
  * Orion-specific GPIO API extensions.
@@ -27,11 +24,13 @@
 void orion_gpio_set_unused(unsigned pin);
 void orion_gpio_set_blink(unsigned pin, int blink);
 
-#define GPIO_BIDI_OK		(1 << 0)
-#define GPIO_INPUT_OK		(1 << 1)
-#define GPIO_OUTPUT_OK		(1 << 2)
+#define GPIO_INPUT_OK		(1 << 0)
+#define GPIO_OUTPUT_OK		(1 << 1)
 void orion_gpio_set_valid(unsigned pin, int mode);
 
+/* Initialize gpiolib. */
+void __init orion_gpio_init(void);
+
 /*
  * GPIO interrupt handling.
  */
diff --git a/arch/arm/plat-orion/include/plat/orion5x_wdt.h b/arch/arm/plat-orion/include/plat/orion5x_wdt.h
deleted file mode 100644
index 3c9cf6a3..0000000
--- a/arch/arm/plat-orion/include/plat/orion5x_wdt.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * arch/arm/plat-orion/include/plat/orion5x_wdt.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 __PLAT_ORION5X_WDT_H
-#define __PLAT_ORION5X_WDT_H
-
-struct orion5x_wdt_platform_data {
-	u32	tclk;		/* no <linux/clk.h> support yet */
-};
-
-
-#endif
-
diff --git a/arch/arm/plat-orion/include/plat/orion_wdt.h b/arch/arm/plat-orion/include/plat/orion_wdt.h
new file mode 100644
index 0000000..665c362
--- /dev/null
+++ b/arch/arm/plat-orion/include/plat/orion_wdt.h
@@ -0,0 +1,18 @@
+/*
+ * arch/arm/plat-orion/include/plat/orion_wdt.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 __PLAT_ORION_WDT_H
+#define __PLAT_ORION_WDT_H
+
+struct orion_wdt_platform_data {
+	u32	tclk;		/* no <linux/clk.h> support yet */
+};
+
+
+#endif
+
diff --git a/arch/arm/plat-orion/time.c b/arch/arm/plat-orion/time.c
index de8a001..715a301 100644
--- a/arch/arm/plat-orion/time.c
+++ b/arch/arm/plat-orion/time.c
@@ -12,11 +12,15 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cnt32_to_63.h>
+#include <linux/timer.h>
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <asm/mach/time.h>
 #include <mach/bridge-regs.h>
+#include <mach/hardware.h>
 
 /*
  * Number of timer ticks per jiffy.
@@ -39,6 +43,56 @@
 
 
 /*
+ * Orion's sched_clock implementation. It has a resolution of
+ * at least 7.5ns (133MHz TCLK) and a maximum value of 834 days.
+ *
+ * Because the hardware timer period is quite short (21 secs if
+ * 200MHz TCLK) and because cnt32_to_63() needs to be called at
+ * least once per half period to work properly, a kernel timer is
+ * set up to ensure this requirement is always met.
+ */
+#define TCLK2NS_SCALE_FACTOR 8
+
+static unsigned long tclk2ns_scale;
+
+unsigned long long sched_clock(void)
+{
+	unsigned long long v = cnt32_to_63(0xffffffff - readl(TIMER0_VAL));
+	return (v * tclk2ns_scale) >> TCLK2NS_SCALE_FACTOR;
+}
+
+static struct timer_list cnt32_to_63_keepwarm_timer;
+
+static void cnt32_to_63_keepwarm(unsigned long data)
+{
+	mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data));
+	(void) sched_clock();
+}
+
+static void __init setup_sched_clock(unsigned long tclk)
+{
+	unsigned long long v;
+	unsigned long data;
+
+	v = NSEC_PER_SEC;
+	v <<= TCLK2NS_SCALE_FACTOR;
+	v += tclk/2;
+	do_div(v, tclk);
+	/*
+	 * We want an even value to automatically clear the top bit
+	 * returned by cnt32_to_63() without an additional run time
+	 * instruction. So if the LSB is 1 then round it up.
+	 */
+	if (v & 1)
+		v++;
+	tclk2ns_scale = v;
+
+	data = (0xffffffffUL / tclk / 2 - 2) * HZ;
+	setup_timer(&cnt32_to_63_keepwarm_timer, cnt32_to_63_keepwarm, data);
+	mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data));
+}
+
+/*
  * Clocksource handling.
  */
 static cycle_t orion_clksrc_read(struct clocksource *cs)
@@ -176,6 +230,10 @@
 
 	ticks_per_jiffy = (tclk + HZ/2) / HZ;
 
+	/*
+	 * Set scale and timer for sched_clock
+	 */
+	setup_sched_clock(tclk);
 
 	/*
 	 * Setup free-running clocksource timer (interrupts
@@ -190,7 +248,6 @@
 	orion_clksrc.mult = clocksource_hz2mult(tclk, orion_clksrc.shift);
 	clocksource_register(&orion_clksrc);
 
-
 	/*
 	 * Setup clockevent timer (interrupt-driven.)
 	 */
diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile
index 8f2c4c7..0264bfb 100644
--- a/arch/arm/plat-pxa/Makefile
+++ b/arch/arm/plat-pxa/Makefile
@@ -7,3 +7,5 @@
 obj-$(CONFIG_GENERIC_GPIO)	+= gpio.o
 obj-$(CONFIG_PXA3xx)		+= mfp.o
 obj-$(CONFIG_ARCH_MMP)		+= mfp.o
+
+obj-$(CONFIG_HAVE_PWM)		+= pwm.o
diff --git a/arch/arm/mach-pxa/include/mach/i2c.h b/arch/arm/plat-pxa/include/plat/i2c.h
similarity index 100%
rename from arch/arm/mach-pxa/include/mach/i2c.h
rename to arch/arm/plat-pxa/include/plat/i2c.h
diff --git a/arch/arm/plat-pxa/pwm.c b/arch/arm/plat-pxa/pwm.c
new file mode 100644
index 0000000..a9eabdc
--- /dev/null
+++ b/arch/arm/plat-pxa/pwm.c
@@ -0,0 +1,303 @@
+/*
+ * linux/arch/arm/mach-pxa/pwm.c
+ *
+ * simple driver for PWM (Pulse Width Modulator) controller
+ *
+ * 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.
+ *
+ * 2008-02-13	initial version
+ * 		eric miao <eric.miao@marvell.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pwm.h>
+
+#include <asm/div64.h>
+
+#define HAS_SECONDARY_PWM	0x10
+#define PWM_ID_BASE(d)		((d) & 0xf)
+
+static const struct platform_device_id pwm_id_table[] = {
+	/*   PWM    has_secondary_pwm? */
+	{ "pxa25x-pwm", 0 },
+	{ "pxa27x-pwm", 0 | HAS_SECONDARY_PWM },
+	{ "pxa168-pwm", 1 },
+	{ "pxa910-pwm", 1 },
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, pwm_id_table);
+
+/* PWM registers and bits definitions */
+#define PWMCR		(0x00)
+#define PWMDCR		(0x04)
+#define PWMPCR		(0x08)
+
+#define PWMCR_SD	(1 << 6)
+#define PWMDCR_FD	(1 << 10)
+
+struct pwm_device {
+	struct list_head	node;
+	struct pwm_device	*secondary;
+	struct platform_device	*pdev;
+
+	const char	*label;
+	struct clk	*clk;
+	int		clk_enabled;
+	void __iomem	*mmio_base;
+
+	unsigned int	use_count;
+	unsigned int	pwm_id;
+};
+
+/*
+ * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
+ * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
+ */
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+	unsigned long long c;
+	unsigned long period_cycles, prescale, pv, dc;
+
+	if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
+		return -EINVAL;
+
+	c = clk_get_rate(pwm->clk);
+	c = c * period_ns;
+	do_div(c, 1000000000);
+	period_cycles = c;
+
+	if (period_cycles < 1)
+		period_cycles = 1;
+	prescale = (period_cycles - 1) / 1024;
+	pv = period_cycles / (prescale + 1) - 1;
+
+	if (prescale > 63)
+		return -EINVAL;
+
+	if (duty_ns == period_ns)
+		dc = PWMDCR_FD;
+	else
+		dc = (pv + 1) * duty_ns / period_ns;
+
+	/* NOTE: the clock to PWM has to be enabled first
+	 * before writing to the registers
+	 */
+	clk_enable(pwm->clk);
+	__raw_writel(prescale, pwm->mmio_base + PWMCR);
+	__raw_writel(dc, pwm->mmio_base + PWMDCR);
+	__raw_writel(pv, pwm->mmio_base + PWMPCR);
+	clk_disable(pwm->clk);
+
+	return 0;
+}
+EXPORT_SYMBOL(pwm_config);
+
+int pwm_enable(struct pwm_device *pwm)
+{
+	int rc = 0;
+
+	if (!pwm->clk_enabled) {
+		rc = clk_enable(pwm->clk);
+		if (!rc)
+			pwm->clk_enabled = 1;
+	}
+	return rc;
+}
+EXPORT_SYMBOL(pwm_enable);
+
+void pwm_disable(struct pwm_device *pwm)
+{
+	if (pwm->clk_enabled) {
+		clk_disable(pwm->clk);
+		pwm->clk_enabled = 0;
+	}
+}
+EXPORT_SYMBOL(pwm_disable);
+
+static DEFINE_MUTEX(pwm_lock);
+static LIST_HEAD(pwm_list);
+
+struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+	struct pwm_device *pwm;
+	int found = 0;
+
+	mutex_lock(&pwm_lock);
+
+	list_for_each_entry(pwm, &pwm_list, node) {
+		if (pwm->pwm_id == pwm_id) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found) {
+		if (pwm->use_count == 0) {
+			pwm->use_count++;
+			pwm->label = label;
+		} else
+			pwm = ERR_PTR(-EBUSY);
+	} else
+		pwm = ERR_PTR(-ENOENT);
+
+	mutex_unlock(&pwm_lock);
+	return pwm;
+}
+EXPORT_SYMBOL(pwm_request);
+
+void pwm_free(struct pwm_device *pwm)
+{
+	mutex_lock(&pwm_lock);
+
+	if (pwm->use_count) {
+		pwm->use_count--;
+		pwm->label = NULL;
+	} else
+		pr_warning("PWM device already freed\n");
+
+	mutex_unlock(&pwm_lock);
+}
+EXPORT_SYMBOL(pwm_free);
+
+static inline void __add_pwm(struct pwm_device *pwm)
+{
+	mutex_lock(&pwm_lock);
+	list_add_tail(&pwm->node, &pwm_list);
+	mutex_unlock(&pwm_lock);
+}
+
+static int __devinit pwm_probe(struct platform_device *pdev)
+{
+	struct platform_device_id *id = platform_get_device_id(pdev);
+	struct pwm_device *pwm, *secondary = NULL;
+	struct resource *r;
+	int ret = 0;
+
+	pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
+	if (pwm == NULL) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	pwm->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pwm->clk)) {
+		ret = PTR_ERR(pwm->clk);
+		goto err_free;
+	}
+	pwm->clk_enabled = 0;
+
+	pwm->use_count = 0;
+	pwm->pwm_id = PWM_ID_BASE(id->driver_data) + pdev->id;
+	pwm->pdev = pdev;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (r == NULL) {
+		dev_err(&pdev->dev, "no memory resource defined\n");
+		ret = -ENODEV;
+		goto err_free_clk;
+	}
+
+	r = request_mem_region(r->start, r->end - r->start + 1, pdev->name);
+	if (r == NULL) {
+		dev_err(&pdev->dev, "failed to request memory resource\n");
+		ret = -EBUSY;
+		goto err_free_clk;
+	}
+
+	pwm->mmio_base = ioremap(r->start, r->end - r->start + 1);
+	if (pwm->mmio_base == NULL) {
+		dev_err(&pdev->dev, "failed to ioremap() registers\n");
+		ret = -ENODEV;
+		goto err_free_mem;
+	}
+
+	if (id->driver_data & HAS_SECONDARY_PWM) {
+		secondary = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
+		if (secondary == NULL) {
+			ret = -ENOMEM;
+			goto err_free_mem;
+		}
+
+		*secondary = *pwm;
+		pwm->secondary = secondary;
+
+		/* registers for the second PWM has offset of 0x10 */
+		secondary->mmio_base = pwm->mmio_base + 0x10;
+		secondary->pwm_id = pdev->id + 2;
+	}
+
+	__add_pwm(pwm);
+	if (secondary)
+		__add_pwm(secondary);
+
+	platform_set_drvdata(pdev, pwm);
+	return 0;
+
+err_free_mem:
+	release_mem_region(r->start, r->end - r->start + 1);
+err_free_clk:
+	clk_put(pwm->clk);
+err_free:
+	kfree(pwm);
+	return ret;
+}
+
+static int __devexit pwm_remove(struct platform_device *pdev)
+{
+	struct pwm_device *pwm;
+	struct resource *r;
+
+	pwm = platform_get_drvdata(pdev);
+	if (pwm == NULL)
+		return -ENODEV;
+
+	mutex_lock(&pwm_lock);
+
+	if (pwm->secondary) {
+		list_del(&pwm->secondary->node);
+		kfree(pwm->secondary);
+	}
+
+	list_del(&pwm->node);
+	mutex_unlock(&pwm_lock);
+
+	iounmap(pwm->mmio_base);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(r->start, r->end - r->start + 1);
+
+	clk_put(pwm->clk);
+	kfree(pwm);
+	return 0;
+}
+
+static struct platform_driver pwm_driver = {
+	.driver		= {
+		.name	= "pxa25x-pwm",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= pwm_probe,
+	.remove		= __devexit_p(pwm_remove),
+	.id_table	= pwm_id_table,
+};
+
+static int __init pwm_init(void)
+{
+	return platform_driver_register(&pwm_driver);
+}
+arch_initcall(pwm_init);
+
+static void __exit pwm_exit(void)
+{
+	platform_driver_unregister(&pwm_driver);
+}
+module_exit(pwm_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig
index de93838..935c755 100644
--- a/arch/arm/plat-s3c/Kconfig
+++ b/arch/arm/plat-s3c/Kconfig
@@ -71,6 +71,15 @@
 	  Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
 	  for more information.
 
+config S3C_PM_DEBUG_LED_SMDK
+       bool "SMDK LED suspend/resume debugging"
+       depends on PM && (MACH_SMDK6410)
+       help
+         Say Y here to enable the use of the SMDK LEDs on the baseboard
+	 for debugging of the state of the suspend and resume process.
+
+	 Note, this currently only works for S3C64XX based SMDK boards.
+
 config S3C2410_PM_CHECK
 	bool "S3C2410 PM Suspend Memory CRC"
 	depends on PM && CRC32
@@ -150,6 +159,13 @@
 	  Internal configuration to enable S3C64XX style GPIO configuration
 	  functions.
 
+# DMA
+
+config S3C_DMA
+	bool
+	help
+	  Internal configuration for S3C DMA core
+
 # device definitions to compile in
 
 config S3C_DEV_HSMMC
@@ -172,4 +188,14 @@
 	help
 	  Compile in platform device definition for framebuffer
 
+config S3C_DEV_USB_HOST
+	bool
+	help
+	  Compile in platform device definition for USB host.
+
+config S3C_DEV_USB_HSOTG
+	bool
+	help
+	  Compile in platform device definition for USB high-speed OtG
+
 endif
diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile
index 8d7815d..6106514 100644
--- a/arch/arm/plat-s3c/Makefile
+++ b/arch/arm/plat-s3c/Makefile
@@ -18,9 +18,14 @@
 obj-y				+= gpio.o
 obj-y				+= gpio-config.o
 
+# DMA support
+
+obj-$(CONFIG_S3C_DMA)		+= dma.o
+
 # PM support
 
 obj-$(CONFIG_PM)		+= pm.o
+obj-$(CONFIG_PM)		+= pm-gpio.o
 obj-$(CONFIG_S3C2410_PM_CHECK)	+= pm-check.o
 
 # devices
@@ -30,3 +35,5 @@
 obj-y				+= dev-i2c0.o
 obj-$(CONFIG_S3C_DEV_I2C1)	+= dev-i2c1.o
 obj-$(CONFIG_S3C_DEV_FB)	+= dev-fb.o
+obj-$(CONFIG_S3C_DEV_USB_HOST)	+= dev-usb.o
+obj-$(CONFIG_S3C_DEV_USB_HSOTG)	+= dev-usb-hsotg.o
diff --git a/arch/arm/plat-s3c/dev-usb-hsotg.c b/arch/arm/plat-s3c/dev-usb-hsotg.c
new file mode 100644
index 0000000..e2f604b
--- /dev/null
+++ b/arch/arm/plat-s3c/dev-usb-hsotg.c
@@ -0,0 +1,41 @@
+/* linux/arch/arm/plat-s3c/dev-usb-hsotg.c
+ *
+ * Copyright 2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * S3C series device definition for USB high-speed UDC/OtG block
+ *
+ * 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/string.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include <plat/devs.h>
+
+static struct resource s3c_usb_hsotg_resources[] = {
+	[0] = {
+		.start	= S3C_PA_USB_HSOTG,
+		.end	= S3C_PA_USB_HSOTG + 0x10000 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_OTG,
+		.end	= IRQ_OTG,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device s3c_device_usb_hsotg = {
+	.name		= "s3c-hsotg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(s3c_usb_hsotg_resources),
+	.resource	= s3c_usb_hsotg_resources,
+};
diff --git a/arch/arm/plat-s3c/dev-usb.c b/arch/arm/plat-s3c/dev-usb.c
new file mode 100644
index 0000000..2ee85ab
--- /dev/null
+++ b/arch/arm/plat-s3c/dev-usb.c
@@ -0,0 +1,50 @@
+/* linux/arch/arm/plat-s3c/dev-usb.c
+ *
+ * Copyright 2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * S3C series device definition for USB host
+ *
+ * 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/string.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include <plat/devs.h>
+
+
+static struct resource s3c_usb_resource[] = {
+	[0] = {
+		.start = S3C_PA_USBHOST,
+		.end   = S3C_PA_USBHOST + 0x100 - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_USBH,
+		.end   = IRQ_USBH,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static u64 s3c_device_usb_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_usb = {
+	.name		  = "s3c2410-ohci",
+	.id		  = -1,
+	.num_resources	  = ARRAY_SIZE(s3c_usb_resource),
+	.resource	  = s3c_usb_resource,
+	.dev              = {
+		.dma_mask = &s3c_device_usb_dmamask,
+		.coherent_dma_mask = 0xffffffffUL
+	}
+};
+
+EXPORT_SYMBOL(s3c_device_usb);
diff --git a/arch/arm/plat-s3c/dma.c b/arch/arm/plat-s3c/dma.c
new file mode 100644
index 0000000..c9db75c
--- /dev/null
+++ b/arch/arm/plat-s3c/dma.c
@@ -0,0 +1,86 @@
+/* linux/arch/arm/plat-s3c/dma.c
+ *
+ * Copyright (c) 2003-2005,2006,2009 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * S3C DMA core
+ *
+ * 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 s3c2410_dma_buf;
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+
+#include <mach/dma.h>
+#include <mach/irqs.h>
+
+#include <plat/dma-plat.h>
+
+/* dma channel state information */
+struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS];
+struct s3c2410_dma_chan *s3c_dma_chan_map[DMACH_MAX];
+
+/* s3c_dma_lookup_channel
+ *
+ * change the dma channel number given into a real dma channel id
+*/
+
+struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel)
+{
+	if (channel & DMACH_LOW_LEVEL)
+		return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
+	else
+		return s3c_dma_chan_map[channel];
+}
+
+/* do we need to protect the settings of the fields from
+ * irq?
+*/
+
+int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn)
+{
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+	if (chan == NULL)
+		return -EINVAL;
+
+	pr_debug("%s: chan=%p, op rtn=%p\n", __func__, chan, rtn);
+
+	chan->op_fn = rtn;
+
+	return 0;
+}
+EXPORT_SYMBOL(s3c2410_dma_set_opfn);
+
+int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn)
+{
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+	if (chan == NULL)
+		return -EINVAL;
+
+	pr_debug("%s: chan=%p, callback rtn=%p\n", __func__, chan, rtn);
+
+	chan->callback_fn = rtn;
+
+	return 0;
+}
+EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
+
+int s3c2410_dma_setflags(unsigned int channel, unsigned int flags)
+{
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+	if (chan == NULL)
+		return -EINVAL;
+
+	chan->flags = flags;
+	return 0;
+}
+EXPORT_SYMBOL(s3c2410_dma_setflags);
diff --git a/arch/arm/plat-s3c/gpio.c b/arch/arm/plat-s3c/gpio.c
index d71dd6d..260fdc6 100644
--- a/arch/arm/plat-s3c/gpio.c
+++ b/arch/arm/plat-s3c/gpio.c
@@ -16,7 +16,7 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 
-#include <plat/gpio-core.h>
+#include <mach/gpio-core.h>
 
 #ifdef CONFIG_S3C_GPIO_TRACK
 struct s3c_gpio_chip *s3c_gpios[S3C_GPIO_END];
@@ -140,6 +140,15 @@
 	if (!gc->get)
 		gc->get = s3c_gpiolib_get;
 
+#ifdef CONFIG_PM
+	if (chip->pm != NULL) {
+		if (!chip->pm->save || !chip->pm->resume)
+			printk(KERN_ERR "gpio: %s has missing PM functions\n",
+			       gc->label);
+	} else
+		printk(KERN_ERR "gpio: %s has no PM function\n", gc->label);
+#endif
+
 	/* gpiochip_add() prints own failure message on error. */
 	ret = gpiochip_add(gc);
 	if (ret >= 0)
diff --git a/arch/arm/plat-s3c/include/plat/adc.h b/arch/arm/plat-s3c/include/plat/adc.h
index 43df2a4..d847bd4 100644
--- a/arch/arm/plat-s3c/include/plat/adc.h
+++ b/arch/arm/plat-s3c/include/plat/adc.h
@@ -19,10 +19,12 @@
 extern int s3c_adc_start(struct s3c_adc_client *client,
 			 unsigned int channel, unsigned int nr_samples);
 
-extern struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
-					       void (*select)(unsigned selected),
-					       void (*conv)(unsigned d0, unsigned d1),
-					       unsigned int is_ts);
+extern struct s3c_adc_client *
+	s3c_adc_register(struct platform_device *pdev,
+			 void (*select)(unsigned selected),
+			 void (*conv)(unsigned d0, unsigned d1,
+				      unsigned *samples_left),
+			 unsigned int is_ts);
 
 extern void s3c_adc_release(struct s3c_adc_client *client);
 
diff --git a/arch/arm/plat-s3c/include/plat/clock.h b/arch/arm/plat-s3c/include/plat/clock.h
index a10622e..d86af84 100644
--- a/arch/arm/plat-s3c/include/plat/clock.h
+++ b/arch/arm/plat-s3c/include/plat/clock.h
@@ -50,6 +50,7 @@
 extern struct clk clk_ext;
 
 /* S3C64XX specific clocks */
+extern struct clk clk_h2;
 extern struct clk clk_27m;
 extern struct clk clk_48m;
 
diff --git a/arch/arm/plat-s3c/include/plat/cpu.h b/arch/arm/plat-s3c/include/plat/cpu.h
index e62ae0f..be541cb 100644
--- a/arch/arm/plat-s3c/include/plat/cpu.h
+++ b/arch/arm/plat-s3c/include/plat/cpu.h
@@ -69,3 +69,6 @@
 extern struct sysdev_class s3c2440_sysclass;
 extern struct sysdev_class s3c2442_sysclass;
 extern struct sysdev_class s3c2443_sysclass;
+extern struct sysdev_class s3c6410_sysclass;
+extern struct sysdev_class s3c64xx_sysclass;
+
diff --git a/arch/arm/plat-s3c/include/plat/devs.h b/arch/arm/plat-s3c/include/plat/devs.h
index 26f0cec..a0b6768 100644
--- a/arch/arm/plat-s3c/include/plat/devs.h
+++ b/arch/arm/plat-s3c/include/plat/devs.h
@@ -45,6 +45,7 @@
 extern struct platform_device s3c_device_nand;
 
 extern struct platform_device s3c_device_usbgadget;
+extern struct platform_device s3c_device_usb_hsotg;
 
 /* s3c2440 specific devices */
 
diff --git a/arch/arm/plat-s3c/include/plat/dma-core.h b/arch/arm/plat-s3c/include/plat/dma-core.h
new file mode 100644
index 0000000..32ff2a9
--- /dev/null
+++ b/arch/arm/plat-s3c/include/plat/dma-core.h
@@ -0,0 +1,22 @@
+/* arch/arm/plat-s3c/include/plat/dma.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * Samsung S3C DMA core 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.
+*/
+
+extern struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel);
+
+extern struct s3c2410_dma_chan *s3c_dma_chan_map[];
+
+/* the currently allocated channel information */
+extern struct s3c2410_dma_chan s3c2410_chans[];
+
+
diff --git a/arch/arm/plat-s3c/include/plat/dma.h b/arch/arm/plat-s3c/include/plat/dma.h
new file mode 100644
index 0000000..34dba98
--- /dev/null
+++ b/arch/arm/plat-s3c/include/plat/dma.h
@@ -0,0 +1,127 @@
+/* arch/arm/plat-s3c/include/plat/dma.h
+ *
+ * Copyright (C) 2003,2004,2006 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C DMA 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.
+*/
+
+enum s3c2410_dma_buffresult {
+	S3C2410_RES_OK,
+	S3C2410_RES_ERR,
+	S3C2410_RES_ABORT
+};
+
+enum s3c2410_dmasrc {
+	S3C2410_DMASRC_HW,		/* source is memory */
+	S3C2410_DMASRC_MEM		/* source is hardware */
+};
+
+/* enum s3c2410_chan_op
+ *
+ * operation codes passed to the DMA code by the user, and also used
+ * to inform the current channel owner of any changes to the system state
+*/
+
+enum s3c2410_chan_op {
+	S3C2410_DMAOP_START,
+	S3C2410_DMAOP_STOP,
+	S3C2410_DMAOP_PAUSE,
+	S3C2410_DMAOP_RESUME,
+	S3C2410_DMAOP_FLUSH,
+	S3C2410_DMAOP_TIMEOUT,		/* internal signal to handler */
+	S3C2410_DMAOP_STARTED,		/* indicate channel started */
+};
+
+struct s3c2410_dma_client {
+	char                *name;
+};
+
+struct s3c2410_dma_chan;
+
+/* s3c2410_dma_cbfn_t
+ *
+ * buffer callback routine type
+*/
+
+typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *,
+				   void *buf, int size,
+				   enum s3c2410_dma_buffresult result);
+
+typedef int  (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *,
+				   enum s3c2410_chan_op );
+
+
+
+/* s3c2410_dma_request
+ *
+ * request a dma channel exclusivley
+*/
+
+extern int s3c2410_dma_request(unsigned int channel,
+			       struct s3c2410_dma_client *, void *dev);
+
+
+/* s3c2410_dma_ctrl
+ *
+ * change the state of the dma channel
+*/
+
+extern int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op);
+
+/* s3c2410_dma_setflags
+ *
+ * set the channel's flags to a given state
+*/
+
+extern int s3c2410_dma_setflags(unsigned int channel,
+				unsigned int flags);
+
+/* s3c2410_dma_free
+ *
+ * free the dma channel (will also abort any outstanding operations)
+*/
+
+extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *);
+
+/* s3c2410_dma_enqueue
+ *
+ * place the given buffer onto the queue of operations for the channel.
+ * The buffer must be allocated from dma coherent memory, or the Dcache/WB
+ * drained before the buffer is given to the DMA system.
+*/
+
+extern int s3c2410_dma_enqueue(unsigned int channel, void *id,
+			       dma_addr_t data, int size);
+
+/* s3c2410_dma_config
+ *
+ * configure the dma channel
+*/
+
+extern int s3c2410_dma_config(unsigned int channel, int xferunit);
+
+/* s3c2410_dma_devconfig
+ *
+ * configure the device we're talking to
+*/
+
+extern int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source,
+				 unsigned long devaddr);
+
+/* s3c2410_dma_getposition
+ *
+ * get the position that the dma transfer is currently at
+*/
+
+extern int s3c2410_dma_getposition(unsigned int channel,
+				   dma_addr_t *src, dma_addr_t *dest);
+
+extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn);
+extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn);
+
+
diff --git a/arch/arm/plat-s3c/include/plat/gpio-core.h b/arch/arm/plat-s3c/include/plat/gpio-core.h
index 2fc60a5..32af612 100644
--- a/arch/arm/plat-s3c/include/plat/gpio-core.h
+++ b/arch/arm/plat-s3c/include/plat/gpio-core.h
@@ -20,6 +20,18 @@
  * specific code.
 */
 
+struct s3c_gpio_chip;
+
+/**
+ * struct s3c_gpio_pm - power management (suspend/resume) information
+ * @save: Routine to save the state of the GPIO block
+ * @resume: Routine to resume the GPIO block.
+ */
+struct s3c_gpio_pm {
+	void (*save)(struct s3c_gpio_chip *chip);
+	void (*resume)(struct s3c_gpio_chip *chip);
+};
+
 struct s3c_gpio_cfg;
 
 /**
@@ -27,6 +39,7 @@
  * @chip: The chip structure to be exported via gpiolib.
  * @base: The base pointer to the gpio configuration registers.
  * @config: special function and pull-resistor control information.
+ * @pm_save: Save information for suspend/resume support.
  *
  * This wrapper provides the necessary information for the Samsung
  * specific gpios being registered with gpiolib.
@@ -34,7 +47,11 @@
 struct s3c_gpio_chip {
 	struct gpio_chip	chip;
 	struct s3c_gpio_cfg	*config;
+	struct s3c_gpio_pm	*pm;
 	void __iomem		*base;
+#ifdef CONFIG_PM
+	u32			pm_save[4];
+#endif
 };
 
 static inline struct s3c_gpio_chip *to_s3c_gpio(struct gpio_chip *gpc)
@@ -75,3 +92,16 @@
 
 static inline void s3c_gpiolib_track(struct s3c_gpio_chip *chip) { }
 #endif
+
+#ifdef CONFIG_PM
+extern struct s3c_gpio_pm s3c_gpio_pm_1bit;
+extern struct s3c_gpio_pm s3c_gpio_pm_2bit;
+extern struct s3c_gpio_pm s3c_gpio_pm_4bit;
+#define __gpio_pm(x) x
+#else
+#define s3c_gpio_pm_1bit NULL
+#define s3c_gpio_pm_2bit NULL
+#define s3c_gpio_pm_4bit NULL
+#define __gpio_pm(x) NULL
+
+#endif /* CONFIG_PM */
diff --git a/arch/arm/plat-s3c/include/plat/pm.h b/arch/arm/plat-s3c/include/plat/pm.h
index 3779775..7a79719 100644
--- a/arch/arm/plat-s3c/include/plat/pm.h
+++ b/arch/arm/plat-s3c/include/plat/pm.h
@@ -44,6 +44,8 @@
 
 extern unsigned long s3c_pm_flags;
 
+extern unsigned char pm_uart_udivslot;  /* true to save UART UDIVSLOT */
+
 /* from sleep.S */
 
 extern int  s3c_cpu_save(unsigned long *saveblk);
@@ -88,6 +90,7 @@
 	u32	ufcon;
 	u32	umcon;
 	u32	ubrdiv;
+	u32	udivslot;
 };
 
 /* helper functions to save/restore lists of registers. */
@@ -124,6 +127,18 @@
 #define S3C_PMDBG(fmt...) printk(KERN_DEBUG fmt)
 #endif
 
+#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
+/**
+ * s3c_pm_debug_smdkled() - Debug PM suspend/resume via SMDK Board LEDs
+ * @set: set bits for the state of the LEDs
+ * @clear: clear bits for the state of the LEDs.
+ */
+extern void s3c_pm_debug_smdkled(u32 set, u32 clear);
+
+#else
+static inline void s3c_pm_debug_smdkled(u32 set, u32 clear) { }
+#endif /* CONFIG_S3C_PM_DEBUG_LED_SMDK */
+
 /* suspend memory checking */
 
 #ifdef CONFIG_S3C2410_PM_CHECK
diff --git a/arch/arm/plat-s3c/include/plat/regs-serial.h b/arch/arm/plat-s3c/include/plat/regs-serial.h
index 487d7d2..66af75a 100644
--- a/arch/arm/plat-s3c/include/plat/regs-serial.h
+++ b/arch/arm/plat-s3c/include/plat/regs-serial.h
@@ -189,6 +189,11 @@
 
 #define S3C2443_DIVSLOT		  (0x2C)
 
+/* S3C64XX interrupt registers. */
+#define S3C64XX_UINTP		0x30
+#define S3C64XX_UINTSP		0x34
+#define S3C64XX_UINTM		0x38
+
 #ifndef __ASSEMBLY__
 
 /* struct s3c24xx_uart_clksrc
diff --git a/arch/arm/plat-s3c/include/plat/sdhci.h b/arch/arm/plat-s3c/include/plat/sdhci.h
index c4ca392..f615308 100644
--- a/arch/arm/plat-s3c/include/plat/sdhci.h
+++ b/arch/arm/plat-s3c/include/plat/sdhci.h
@@ -67,12 +67,52 @@
 
 /* Helper function availablity */
 
+extern void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
+extern void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
+
+/* S3C6400 SDHCI setup */
+
+#ifdef CONFIG_S3C6400_SETUP_SDHCI
+extern char *s3c6400_hsmmc_clksrcs[4];
+
+#ifdef CONFIG_S3C_DEV_HSMMC
+extern void s3c6400_setup_sdhci_cfg_card(struct platform_device *dev,
+					 void __iomem *r,
+					 struct mmc_ios *ios,
+					 struct mmc_card *card);
+
+static inline void s3c6400_default_sdhci0(void)
+{
+	s3c_hsmmc0_def_platdata.clocks = s3c6400_hsmmc_clksrcs;
+	s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio;
+	s3c_hsmmc0_def_platdata.cfg_card = s3c6400_setup_sdhci_cfg_card;
+}
+
+#else
+static inline void s3c6400_default_sdhci0(void) { }
+#endif  /* CONFIG_S3C_DEV_HSMMC */
+
+#ifdef CONFIG_S3C_DEV_HSMMC1
+static inline void s3c6400_default_sdhci1(void)
+{
+	s3c_hsmmc1_def_platdata.clocks = s3c6400_hsmmc_clksrcs;
+	s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio;
+	s3c_hsmmc1_def_platdata.cfg_card = s3c6400_setup_sdhci_cfg_card;
+}
+#else
+static inline void s3c6400_default_sdhci1(void) { }
+#endif /* CONFIG_S3C_DEV_HSMMC1 */
+
+#else
+static inline void s3c6400_default_sdhci0(void) { }
+static inline void s3c6400_default_sdhci1(void) { }
+#endif /* CONFIG_S3C6400_SETUP_SDHCI */
+
+/* S3C6410 SDHCI setup */
+
 #ifdef CONFIG_S3C6410_SETUP_SDHCI
 extern char *s3c6410_hsmmc_clksrcs[4];
 
-extern void s3c6410_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
-extern void s3c6410_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
-
 extern void s3c6410_setup_sdhci0_cfg_card(struct platform_device *dev,
 					   void __iomem *r,
 					   struct mmc_ios *ios,
@@ -82,7 +122,7 @@
 static inline void s3c6410_default_sdhci0(void)
 {
 	s3c_hsmmc0_def_platdata.clocks = s3c6410_hsmmc_clksrcs;
-	s3c_hsmmc0_def_platdata.cfg_gpio = s3c6410_setup_sdhci0_cfg_gpio;
+	s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio;
 	s3c_hsmmc0_def_platdata.cfg_card = s3c6410_setup_sdhci0_cfg_card;
 }
 #else
@@ -93,7 +133,7 @@
 static inline void s3c6410_default_sdhci1(void)
 {
 	s3c_hsmmc1_def_platdata.clocks = s3c6410_hsmmc_clksrcs;
-	s3c_hsmmc1_def_platdata.cfg_gpio = s3c6410_setup_sdhci1_cfg_gpio;
+	s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio;
 	s3c_hsmmc1_def_platdata.cfg_card = s3c6410_setup_sdhci0_cfg_card;
 }
 #else
diff --git a/arch/arm/plat-s3c/include/plat/udc-hs.h b/arch/arm/plat-s3c/include/plat/udc-hs.h
new file mode 100644
index 0000000..dd04db0
--- /dev/null
+++ b/arch/arm/plat-s3c/include/plat/udc-hs.h
@@ -0,0 +1,29 @@
+/* arch/arm/plat-s3c/include/plat/udc-hs.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C USB2.0 High-speed / OtG platform information
+ *
+ * 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.
+*/
+
+enum s3c_hostg_dmamode {
+	S3C_HSOTG_DMA_NONE,	/* do not use DMA at-all */
+	S3C_HSOTG_DMA_ONLY,	/* always use DMA */
+	S3C_HSOTG_DMA_DRV,	/* DMA is chosen by driver */
+};
+
+/**
+ * struct s3c_hsotg_plat - platform data for high-speed otg/udc
+ * @dma: Whether to use DMA or not.
+ * @is_osc: The clock source is an oscillator, not a crystal
+ */
+struct s3c_hsotg_plat {
+	enum s3c_hostg_dmamode	dma;
+	unsigned int		is_osc : 1;
+};
diff --git a/arch/arm/plat-s3c/include/plat/watchdog-reset.h b/arch/arm/plat-s3c/include/plat/watchdog-reset.h
new file mode 100644
index 0000000..54b762a
--- /dev/null
+++ b/arch/arm/plat-s3c/include/plat/watchdog-reset.h
@@ -0,0 +1,49 @@
+/* arch/arm/plat-s3c/include/plat/watchdog-reset.h
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - System define for arch_reset() function
+ *
+ * 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 <plat/regs-watchdog.h>
+#include <mach/map.h>
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+static inline void arch_wdt_reset(void)
+{
+	struct clk *wdtclk;
+
+	printk("arch_reset: attempting watchdog reset\n");
+
+	__raw_writel(0, S3C2410_WTCON);	  /* disable watchdog, to be safe  */
+
+	wdtclk = clk_get(NULL, "watchdog");
+	if (!IS_ERR(wdtclk)) {
+		clk_enable(wdtclk);
+	} else
+		printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__);
+
+	/* put initial values into count and data */
+	__raw_writel(0x80, S3C2410_WTCNT);
+	__raw_writel(0x80, S3C2410_WTDAT);
+
+	/* set the watchdog to go and reset... */
+	__raw_writel(S3C2410_WTCON_ENABLE|S3C2410_WTCON_DIV16|S3C2410_WTCON_RSTEN |
+		     S3C2410_WTCON_PRESCALE(0x20), S3C2410_WTCON);
+
+	/* wait for reset to assert... */
+	mdelay(500);
+
+	printk(KERN_ERR "Watchdog reset failed to assert reset\n");
+
+	/* delay to allow the serial port to show the message */
+	mdelay(50);
+}
diff --git a/arch/arm/plat-s3c/pm-gpio.c b/arch/arm/plat-s3c/pm-gpio.c
new file mode 100644
index 0000000..cfd326a
--- /dev/null
+++ b/arch/arm/plat-s3c/pm-gpio.c
@@ -0,0 +1,380 @@
+
+/* linux/arch/arm/plat-s3c/pm-gpio.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * S3C series GPIO PM 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
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/sysdev.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <mach/gpio-core.h>
+#include <plat/pm.h>
+
+/* PM GPIO helpers */
+
+#define OFFS_CON	(0x00)
+#define OFFS_DAT	(0x04)
+#define OFFS_UP		(0x08)
+
+static void s3c_gpio_pm_1bit_save(struct s3c_gpio_chip *chip)
+{
+	chip->pm_save[0] = __raw_readl(chip->base + OFFS_CON);
+	chip->pm_save[1] = __raw_readl(chip->base + OFFS_DAT);
+}
+
+static void s3c_gpio_pm_1bit_resume(struct s3c_gpio_chip *chip)
+{
+	void __iomem *base = chip->base;
+	u32 old_gpcon = __raw_readl(base + OFFS_CON);
+	u32 old_gpdat = __raw_readl(base + OFFS_DAT);
+	u32 gps_gpcon = chip->pm_save[0];
+	u32 gps_gpdat = chip->pm_save[1];
+	u32 gpcon;
+
+	/* GPACON only has one bit per control / data and no PULLUPs.
+	 * GPACON[x] = 0 => Output, 1 => SFN */
+
+	/* first set all SFN bits to SFN */
+
+	gpcon = old_gpcon | gps_gpcon;
+	__raw_writel(gpcon, base + OFFS_CON);
+
+	/* now set all the other bits */
+
+	__raw_writel(gps_gpdat, base + OFFS_DAT);
+	__raw_writel(gps_gpcon, base + OFFS_CON);
+
+	S3C_PMDBG("%s: CON %08x => %08x, DAT %08x => %08x\n",
+		  chip->chip.label, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat);
+}
+
+struct s3c_gpio_pm s3c_gpio_pm_1bit = {
+	.save	= s3c_gpio_pm_1bit_save,
+	.resume = s3c_gpio_pm_1bit_resume,
+};
+
+static void s3c_gpio_pm_2bit_save(struct s3c_gpio_chip *chip)
+{
+	chip->pm_save[0] = __raw_readl(chip->base + OFFS_CON);
+	chip->pm_save[1] = __raw_readl(chip->base + OFFS_DAT);
+	chip->pm_save[2] = __raw_readl(chip->base + OFFS_UP);
+}
+
+/* Test whether the given masked+shifted bits of an GPIO configuration
+ * are one of the SFN (special function) modes. */
+
+static inline int is_sfn(unsigned long con)
+{
+	return con >= 2;
+}
+
+/* Test if the given masked+shifted GPIO configuration is an input */
+
+static inline int is_in(unsigned long con)
+{
+	return con == 0;
+}
+
+/* Test if the given masked+shifted GPIO configuration is an output */
+
+static inline int is_out(unsigned long con)
+{
+	return con == 1;
+}
+
+/**
+ * s3c_gpio_pm_2bit_resume() - restore the given GPIO bank
+ * @chip: The chip information to resume.
+ *
+ * Restore one of the GPIO banks that was saved during suspend. This is
+ * not as simple as once thought, due to the possibility of glitches
+ * from the order that the CON and DAT registers are set in.
+ *
+ * The three states the pin can be are {IN,OUT,SFN} which gives us 9
+ * combinations of changes to check. Three of these, if the pin stays
+ * in the same configuration can be discounted. This leaves us with
+ * the following:
+ *
+ * { IN => OUT }  Change DAT first
+ * { IN => SFN }  Change CON first
+ * { OUT => SFN } Change CON first, so new data will not glitch
+ * { OUT => IN }  Change CON first, so new data will not glitch
+ * { SFN => IN }  Change CON first
+ * { SFN => OUT } Change DAT first, so new data will not glitch [1]
+ *
+ * We do not currently deal with the UP registers as these control
+ * weak resistors, so a small delay in change should not need to bring
+ * these into the calculations.
+ *
+ * [1] this assumes that writing to a pin DAT whilst in SFN will set the
+ *     state for when it is next output.
+ */
+static void s3c_gpio_pm_2bit_resume(struct s3c_gpio_chip *chip)
+{
+	void __iomem *base = chip->base;
+	u32 old_gpcon = __raw_readl(base + OFFS_CON);
+	u32 old_gpdat = __raw_readl(base + OFFS_DAT);
+	u32 gps_gpcon = chip->pm_save[0];
+	u32 gps_gpdat = chip->pm_save[1];
+	u32 gpcon, old, new, mask;
+	u32 change_mask = 0x0;
+	int nr;
+
+	/* restore GPIO pull-up settings */
+	__raw_writel(chip->pm_save[2], base + OFFS_UP);
+
+	/* Create a change_mask of all the items that need to have
+	 * their CON value changed before their DAT value, so that
+	 * we minimise the work between the two settings.
+	 */
+
+	for (nr = 0, mask = 0x03; nr < 32; nr += 2, mask <<= 2) {
+		old = (old_gpcon & mask) >> nr;
+		new = (gps_gpcon & mask) >> nr;
+
+		/* If there is no change, then skip */
+
+		if (old == new)
+			continue;
+
+		/* If both are special function, then skip */
+
+		if (is_sfn(old) && is_sfn(new))
+			continue;
+
+		/* Change is IN => OUT, do not change now */
+
+		if (is_in(old) && is_out(new))
+			continue;
+
+		/* Change is SFN => OUT, do not change now */
+
+		if (is_sfn(old) && is_out(new))
+			continue;
+
+		/* We should now be at the case of IN=>SFN,
+		 * OUT=>SFN, OUT=>IN, SFN=>IN. */
+
+		change_mask |= mask;
+	}
+
+
+	/* Write the new CON settings */
+
+	gpcon = old_gpcon & ~change_mask;
+	gpcon |= gps_gpcon & change_mask;
+
+	__raw_writel(gpcon, base + OFFS_CON);
+
+	/* Now change any items that require DAT,CON */
+
+	__raw_writel(gps_gpdat, base + OFFS_DAT);
+	__raw_writel(gps_gpcon, base + OFFS_CON);
+
+	S3C_PMDBG("%s: CON %08x => %08x, DAT %08x => %08x\n",
+		  chip->chip.label, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat);
+}
+
+struct s3c_gpio_pm s3c_gpio_pm_2bit = {
+	.save	= s3c_gpio_pm_2bit_save,
+	.resume = s3c_gpio_pm_2bit_resume,
+};
+
+#ifdef CONFIG_ARCH_S3C64XX
+static void s3c_gpio_pm_4bit_save(struct s3c_gpio_chip *chip)
+{
+	chip->pm_save[1] = __raw_readl(chip->base + OFFS_CON);
+	chip->pm_save[2] = __raw_readl(chip->base + OFFS_DAT);
+	chip->pm_save[3] = __raw_readl(chip->base + OFFS_UP);
+
+	if (chip->chip.ngpio > 8)
+		chip->pm_save[0] = __raw_readl(chip->base - 4);
+}
+
+static u32 s3c_gpio_pm_4bit_mask(u32 old_gpcon, u32 gps_gpcon)
+{
+	u32 old, new, mask;
+	u32 change_mask = 0x0;
+	int nr;
+
+	for (nr = 0, mask = 0x0f; nr < 16; nr += 4, mask <<= 4) {
+		old = (old_gpcon & mask) >> nr;
+		new = (gps_gpcon & mask) >> nr;
+
+		/* If there is no change, then skip */
+
+		if (old == new)
+			continue;
+
+		/* If both are special function, then skip */
+
+		if (is_sfn(old) && is_sfn(new))
+			continue;
+
+		/* Change is IN => OUT, do not change now */
+
+		if (is_in(old) && is_out(new))
+			continue;
+
+		/* Change is SFN => OUT, do not change now */
+
+		if (is_sfn(old) && is_out(new))
+			continue;
+
+		/* We should now be at the case of IN=>SFN,
+		 * OUT=>SFN, OUT=>IN, SFN=>IN. */
+
+		change_mask |= mask;
+	}
+
+	return change_mask;
+}
+
+static void s3c_gpio_pm_4bit_con(struct s3c_gpio_chip *chip, int index)
+{
+	void __iomem *con = chip->base + (index * 4);
+	u32 old_gpcon = __raw_readl(con);
+	u32 gps_gpcon = chip->pm_save[index + 1];
+	u32 gpcon, mask;
+
+	mask = s3c_gpio_pm_4bit_mask(old_gpcon, gps_gpcon);
+
+	gpcon = old_gpcon & ~mask;
+	gpcon |= gps_gpcon & mask;
+
+	__raw_writel(gpcon, con);
+}
+
+static void s3c_gpio_pm_4bit_resume(struct s3c_gpio_chip *chip)
+{
+	void __iomem *base = chip->base;
+	u32 old_gpcon[2];
+	u32 old_gpdat = __raw_readl(base + OFFS_DAT);
+	u32 gps_gpdat = chip->pm_save[2];
+
+	/* First, modify the CON settings */
+
+	old_gpcon[0] = 0;
+	old_gpcon[1] = __raw_readl(base + OFFS_CON);
+
+	s3c_gpio_pm_4bit_con(chip, 0);
+	if (chip->chip.ngpio > 8) {
+		old_gpcon[0] = __raw_readl(base - 4);
+		s3c_gpio_pm_4bit_con(chip, -1);
+	}
+
+	/* Now change the configurations that require DAT,CON */
+
+	__raw_writel(chip->pm_save[2], base + OFFS_DAT);
+	__raw_writel(chip->pm_save[1], base + OFFS_CON);
+	if (chip->chip.ngpio > 8)
+		__raw_writel(chip->pm_save[0], base - 4);
+
+	__raw_writel(chip->pm_save[2], base + OFFS_DAT);
+	__raw_writel(chip->pm_save[3], base + OFFS_UP);
+
+	if (chip->chip.ngpio > 8) {
+		S3C_PMDBG("%s: CON4 %08x,%08x => %08x,%08x, DAT %08x => %08x\n",
+			  chip->chip.label, old_gpcon[0], old_gpcon[1],
+			  __raw_readl(base - 4),
+			  __raw_readl(base + OFFS_CON),
+			  old_gpdat, gps_gpdat);
+	} else
+		S3C_PMDBG("%s: CON4 %08x => %08x, DAT %08x => %08x\n",
+			  chip->chip.label, old_gpcon[1],
+			  __raw_readl(base + OFFS_CON),
+			  old_gpdat, gps_gpdat);
+}
+
+struct s3c_gpio_pm s3c_gpio_pm_4bit = {
+	.save	= s3c_gpio_pm_4bit_save,
+	.resume = s3c_gpio_pm_4bit_resume,
+};
+#endif /* CONFIG_ARCH_S3C64XX */
+
+/**
+ * s3c_pm_save_gpio() - save gpio chip data for suspend
+ * @ourchip: The chip for suspend.
+ */
+static void s3c_pm_save_gpio(struct s3c_gpio_chip *ourchip)
+{
+	struct s3c_gpio_pm *pm = ourchip->pm;
+
+	if (pm == NULL || pm->save == NULL)
+		S3C_PMDBG("%s: no pm for %s\n", __func__, ourchip->chip.label);
+	else
+		pm->save(ourchip);
+}
+
+/**
+ * s3c_pm_save_gpios() - Save the state of the GPIO banks.
+ *
+ * For all the GPIO banks, save the state of each one ready for going
+ * into a suspend mode.
+ */
+void s3c_pm_save_gpios(void)
+{
+	struct s3c_gpio_chip *ourchip;
+	unsigned int gpio_nr;
+
+	for (gpio_nr = 0; gpio_nr < S3C_GPIO_END; gpio_nr++) {
+		ourchip = s3c_gpiolib_getchip(gpio_nr);
+		if (!ourchip)
+			continue;
+
+		s3c_pm_save_gpio(ourchip);
+
+		S3C_PMDBG("%s: save %08x,%08x,%08x,%08x\n",
+			  ourchip->chip.label,
+			  ourchip->pm_save[0],
+			  ourchip->pm_save[1],
+			  ourchip->pm_save[2],
+			  ourchip->pm_save[3]);
+
+		gpio_nr += ourchip->chip.ngpio;
+		gpio_nr += CONFIG_S3C_GPIO_SPACE;
+	}
+}
+
+/**
+ * s3c_pm_resume_gpio() - restore gpio chip data after suspend
+ * @ourchip: The suspended chip.
+ */
+static void s3c_pm_resume_gpio(struct s3c_gpio_chip *ourchip)
+{
+	struct s3c_gpio_pm *pm = ourchip->pm;
+
+	if (pm == NULL || pm->resume == NULL)
+		S3C_PMDBG("%s: no pm for %s\n", __func__, ourchip->chip.label);
+	else
+		pm->resume(ourchip);
+}
+
+void s3c_pm_restore_gpios(void)
+{
+	struct s3c_gpio_chip *ourchip;
+	unsigned int gpio_nr;
+
+	for (gpio_nr = 0; gpio_nr < S3C_GPIO_END; gpio_nr++) {
+		ourchip = s3c_gpiolib_getchip(gpio_nr);
+		if (!ourchip)
+			continue;
+
+		s3c_pm_resume_gpio(ourchip);
+
+		gpio_nr += ourchip->chip.ngpio;
+		gpio_nr += CONFIG_S3C_GPIO_SPACE;
+	}
+}
diff --git a/arch/arm/plat-s3c/pm.c b/arch/arm/plat-s3c/pm.c
index 061182c..8d97db2 100644
--- a/arch/arm/plat-s3c/pm.c
+++ b/arch/arm/plat-s3c/pm.c
@@ -21,11 +21,10 @@
 
 #include <asm/cacheflush.h>
 #include <mach/hardware.h>
+#include <mach/map.h>
 
 #include <plat/regs-serial.h>
 #include <mach/regs-clock.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
 #include <mach/regs-irq.h>
 #include <asm/irq.h>
 
@@ -70,6 +69,8 @@
 
 /* Save the UART configurations if we are configured for debug. */
 
+unsigned char pm_uart_udivslot;
+
 #ifdef CONFIG_S3C2410_PM_DEBUG
 
 struct pm_uart_save uart_save[CONFIG_SERIAL_SAMSUNG_UARTS];
@@ -83,6 +84,12 @@
 	save->ufcon = __raw_readl(regs + S3C2410_UFCON);
 	save->umcon = __raw_readl(regs + S3C2410_UMCON);
 	save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV);
+
+	if (pm_uart_udivslot)
+		save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT);
+
+	S3C_PMDBG("UART[%d]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n",
+		  uart, save->ulcon, save->ucon, save->ufcon, save->ubrdiv);
 }
 
 static void s3c_pm_save_uarts(void)
@@ -98,11 +105,16 @@
 {
 	void __iomem *regs = S3C_VA_UARTx(uart);
 
+	s3c_pm_arch_update_uart(regs, save);
+
 	__raw_writel(save->ulcon, regs + S3C2410_ULCON);
 	__raw_writel(save->ucon,  regs + S3C2410_UCON);
 	__raw_writel(save->ufcon, regs + S3C2410_UFCON);
 	__raw_writel(save->umcon, regs + S3C2410_UMCON);
 	__raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV);
+
+	if (pm_uart_udivslot)
+		__raw_writel(save->udivslot, regs + S3C2443_DIVSLOT);
 }
 
 static void s3c_pm_restore_uarts(void)
@@ -313,6 +325,9 @@
 
 	S3C_PMDBG("%s: post sleep, preparing to return\n", __func__);
 
+	/* LEDs should now be 1110 */
+	s3c_pm_debug_smdkled(1 << 1, 0);
+
 	s3c_pm_check_restore();
 
 	/* ok, let's return from sleep */
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
index 2c8a2f5..5b0bc91 100644
--- a/arch/arm/plat-s3c24xx/Kconfig
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -71,6 +71,7 @@
 config S3C2410_DMA
 	bool "S3C2410 DMA support"
 	depends on ARCH_S3C2410
+	select S3C_DMA
 	help
 	  S3C2410 DMA support. This is needed for drivers like sound which
 	  use the S3C2410's DMA system to move data to and from the
diff --git a/arch/arm/plat-s3c24xx/adc.c b/arch/arm/plat-s3c24xx/adc.c
index 91adfa7..ee1baf1 100644
--- a/arch/arm/plat-s3c24xx/adc.c
+++ b/arch/arm/plat-s3c24xx/adc.c
@@ -45,7 +45,8 @@
 	unsigned char		 channel;
 
 	void	(*select_cb)(unsigned selected);
-	void	(*convert_cb)(unsigned val1, unsigned val2);
+	void	(*convert_cb)(unsigned val1, unsigned val2,
+			      unsigned *samples_left);
 };
 
 struct adc_device {
@@ -158,7 +159,8 @@
 
 struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
 					void (*select)(unsigned int selected),
-					void (*conv)(unsigned d0, unsigned d1),
+					void (*conv)(unsigned d0, unsigned d1,
+						     unsigned *samples_left),
 					unsigned int is_ts)
 {
 	struct s3c_adc_client *client;
@@ -227,9 +229,10 @@
 	data1 = readl(adc->regs + S3C2410_ADCDAT1);
 	adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);
 
-	(client->convert_cb)(data0 & 0x3ff, data1 & 0x3ff);
+	client->nr_samples--;
+	(client->convert_cb)(data0 & 0x3ff, data1 & 0x3ff, &client->nr_samples);
 
-	if (--client->nr_samples > 0) {
+	if (client->nr_samples > 0) {
 		/* fire another conversion for this */
 
 		client->select_cb(1);
diff --git a/arch/arm/plat-s3c24xx/common-smdk.c b/arch/arm/plat-s3c24xx/common-smdk.c
index 1a8347c..aa11986 100644
--- a/arch/arm/plat-s3c24xx/common-smdk.c
+++ b/arch/arm/plat-s3c24xx/common-smdk.c
@@ -18,6 +18,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/sysdev.h>
 #include <linux/platform_device.h>
 
@@ -47,27 +48,27 @@
 /* LED devices */
 
 static struct s3c24xx_led_platdata smdk_pdata_led4 = {
-	.gpio		= S3C2410_GPF4,
+	.gpio		= S3C2410_GPF(4),
 	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
 	.name		= "led4",
 	.def_trigger	= "timer",
 };
 
 static struct s3c24xx_led_platdata smdk_pdata_led5 = {
-	.gpio		= S3C2410_GPF5,
+	.gpio		= S3C2410_GPF(5),
 	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
 	.name		= "led5",
 	.def_trigger	= "nand-disk",
 };
 
 static struct s3c24xx_led_platdata smdk_pdata_led6 = {
-	.gpio		= S3C2410_GPF6,
+	.gpio		= S3C2410_GPF(6),
 	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
 	.name		= "led6",
 };
 
 static struct s3c24xx_led_platdata smdk_pdata_led7 = {
-	.gpio		= S3C2410_GPF7,
+	.gpio		= S3C2410_GPF(7),
 	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
 	.name		= "led7",
 };
@@ -184,15 +185,15 @@
 {
 	/* Configure the LEDs (even if we have no LED support)*/
 
-	s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);
-	s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
-	s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP);
-	s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP);
+	s3c2410_gpio_cfgpin(S3C2410_GPF(4), S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_cfgpin(S3C2410_GPF(5), S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_cfgpin(S3C2410_GPF(6), S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_cfgpin(S3C2410_GPF(7), S3C2410_GPIO_OUTPUT);
 
-	s3c2410_gpio_setpin(S3C2410_GPF4, 1);
-	s3c2410_gpio_setpin(S3C2410_GPF5, 1);
-	s3c2410_gpio_setpin(S3C2410_GPF6, 1);
-	s3c2410_gpio_setpin(S3C2410_GPF7, 1);
+	s3c2410_gpio_setpin(S3C2410_GPF(4), 1);
+	s3c2410_gpio_setpin(S3C2410_GPF(5), 1);
+	s3c2410_gpio_setpin(S3C2410_GPF(6), 1);
+	s3c2410_gpio_setpin(S3C2410_GPF(7), 1);
 
 	if (machine_is_smdk2443())
 		smdk_nand_info.twrph0 = 50;
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index 16ac01d..4eb378c 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -136,36 +136,6 @@
 struct platform_device *s3c24xx_uart_devs[4] = {
 };
 
-/* USB Host Controller */
-
-static struct resource s3c_usb_resource[] = {
-	[0] = {
-		.start = S3C24XX_PA_USBHOST,
-		.end   = S3C24XX_PA_USBHOST + S3C24XX_SZ_USBHOST - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = IRQ_USBH,
-		.end   = IRQ_USBH,
-		.flags = IORESOURCE_IRQ,
-	}
-};
-
-static u64 s3c_device_usb_dmamask = 0xffffffffUL;
-
-struct platform_device s3c_device_usb = {
-	.name		  = "s3c2410-ohci",
-	.id		  = -1,
-	.num_resources	  = ARRAY_SIZE(s3c_usb_resource),
-	.resource	  = s3c_usb_resource,
-	.dev              = {
-		.dma_mask = &s3c_device_usb_dmamask,
-		.coherent_dma_mask = 0xffffffffUL
-	}
-};
-
-EXPORT_SYMBOL(s3c_device_usb);
-
 /* LCD Controller */
 
 static struct resource s3c_lcd_resource[] = {
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index 07326f6..196b191 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -31,10 +31,10 @@
 #include <asm/irq.h>
 #include <mach/hardware.h>
 #include <mach/dma.h>
-
 #include <mach/map.h>
 
-#include <plat/dma.h>
+#include <plat/dma-plat.h>
+#include <plat/regs-dma.h>
 
 /* io map for dma */
 static void __iomem *dma_base;
@@ -44,8 +44,6 @@
 
 static struct s3c24xx_dma_selection dma_sel;
 
-/* dma channel state information */
-struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
 
 /* debugging functions */
 
@@ -135,21 +133,6 @@
 #define dbg_showchan(chan) do { } while(0)
 #endif /* CONFIG_S3C2410_DMA_DEBUG */
 
-static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX];
-
-/* lookup_dma_channel
- *
- * change the dma channel number given into a real dma channel id
-*/
-
-static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel)
-{
-	if (channel & DMACH_LOW_LEVEL)
-		return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
-	else
-		return dma_chan_map[channel];
-}
-
 /* s3c2410_dma_stats_timeout
  *
  * Update DMA stats from timeout info
@@ -214,8 +197,6 @@
 	return 0;
 }
 
-
-
 /* s3c2410_dma_loadbuffer
  *
  * load a buffer, and update the channel state
@@ -453,7 +434,7 @@
 int s3c2410_dma_enqueue(unsigned int channel, void *id,
 			dma_addr_t data, int size)
 {
-	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
 	struct s3c2410_dma_buf *buf;
 	unsigned long flags;
 
@@ -804,7 +785,7 @@
 
 int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client)
 {
-	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
 	unsigned long flags;
 
 	if (chan == NULL)
@@ -836,7 +817,7 @@
 	chan->irq_claimed = 0;
 
 	if (!(channel & DMACH_LOW_LEVEL))
-		dma_chan_map[channel] = NULL;
+		s3c_dma_chan_map[channel] = NULL;
 
 	local_irq_restore(flags);
 
@@ -995,7 +976,7 @@
 int
 s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op)
 {
-	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
 
 	if (chan == NULL)
 		return -EINVAL;
@@ -1038,14 +1019,13 @@
 /* s3c2410_dma_config
  *
  * xfersize:     size of unit in bytes (1,2,4)
- * dcon:         base value of the DCONx register
 */
 
 int s3c2410_dma_config(unsigned int channel,
-		       int xferunit,
-		       int dcon)
+		       int xferunit)
 {
-	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+	unsigned int dcon;
 
 	pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
 		 __func__, channel, xferunit, dcon);
@@ -1055,10 +1035,33 @@
 
 	pr_debug("%s: Initial dcon is %08x\n", __func__, dcon);
 
-	dcon |= chan->dcon & dma_sel.dcon_mask;
+	dcon = chan->dcon & dma_sel.dcon_mask;
 
 	pr_debug("%s: New dcon is %08x\n", __func__, dcon);
 
+	switch (chan->req_ch) {
+	case DMACH_I2S_IN:
+	case DMACH_I2S_OUT:
+	case DMACH_PCM_IN:
+	case DMACH_PCM_OUT:
+	case DMACH_MIC_IN:
+	default:
+		dcon |= S3C2410_DCON_HANDSHAKE;
+		dcon |= S3C2410_DCON_SYNC_PCLK;
+		break;
+
+	case DMACH_SDI:
+		/* note, ensure if need HANDSHAKE or not */
+		dcon |= S3C2410_DCON_SYNC_PCLK;
+		break;
+
+	case DMACH_XD0:
+	case DMACH_XD1:
+		dcon |= S3C2410_DCON_HANDSHAKE;
+		dcon |= S3C2410_DCON_SYNC_HCLK;
+		break;
+	}
+
 	switch (xferunit) {
 	case 1:
 		dcon |= S3C2410_DCON_BYTE;
@@ -1090,58 +1093,6 @@
 
 EXPORT_SYMBOL(s3c2410_dma_config);
 
-int s3c2410_dma_setflags(unsigned int channel, unsigned int flags)
-{
-	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
-
-	if (chan == NULL)
-		return -EINVAL;
-
-	pr_debug("%s: chan=%p, flags=%08x\n", __func__, chan, flags);
-
-	chan->flags = flags;
-
-	return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_setflags);
-
-
-/* do we need to protect the settings of the fields from
- * irq?
-*/
-
-int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn)
-{
-	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
-
-	if (chan == NULL)
-		return -EINVAL;
-
-	pr_debug("%s: chan=%p, op rtn=%p\n", __func__, chan, rtn);
-
-	chan->op_fn = rtn;
-
-	return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_set_opfn);
-
-int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn)
-{
-	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
-
-	if (chan == NULL)
-		return -EINVAL;
-
-	pr_debug("%s: chan=%p, callback rtn=%p\n", __func__, chan, rtn);
-
-	chan->callback_fn = rtn;
-
-	return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
 
 /* s3c2410_dma_devconfig
  *
@@ -1150,29 +1101,38 @@
  * source:    S3C2410_DMASRC_HW: source is hardware
  *            S3C2410_DMASRC_MEM: source is memory
  *
- * hwcfg:     the value for xxxSTCn register,
- *            bit 0: 0=increment pointer, 1=leave pointer
- *            bit 1: 0=source is AHB, 1=source is APB
- *
  * devaddr:   physical address of the source
 */
 
 int s3c2410_dma_devconfig(int channel,
 			  enum s3c2410_dmasrc source,
-			  int hwcfg,
 			  unsigned long devaddr)
 {
-	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+	unsigned int hwcfg;
 
 	if (chan == NULL)
 		return -EINVAL;
 
-	pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
-		 __func__, (int)source, hwcfg, devaddr);
+	pr_debug("%s: source=%d, devaddr=%08lx\n",
+		 __func__, (int)source, devaddr);
 
 	chan->source = source;
 	chan->dev_addr = devaddr;
-	chan->hw_cfg = hwcfg;
+
+	switch (chan->req_ch) {
+	case DMACH_XD0:
+	case DMACH_XD1:
+		hwcfg = 0; /* AHB */
+		break;
+
+	default:
+		hwcfg = S3C2410_DISRCC_APB;
+	}
+
+	/* always assume our peripheral desintation is a fixed
+	 * address in memory. */
+	 hwcfg |= S3C2410_DISRCC_INC;
 
 	switch (source) {
 	case S3C2410_DMASRC_HW:
@@ -1219,7 +1179,7 @@
 
 int s3c2410_dma_getposition(unsigned int channel, dma_addr_t *src, dma_addr_t *dst)
 {
- 	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
 
 	if (chan == NULL)
 		return -EINVAL;
@@ -1278,8 +1238,8 @@
 
 	printk(KERN_INFO "dma%d: restoring configuration\n", cp->number);
 
-	s3c2410_dma_config(no, cp->xfer_unit, cp->dcon);
-	s3c2410_dma_devconfig(no, cp->source, cp->hw_cfg, cp->dev_addr);
+	s3c2410_dma_config(no, cp->xfer_unit);
+	s3c2410_dma_devconfig(no, cp->source, cp->dev_addr);
 
 	/* re-select the dma source for this channel */
 
@@ -1476,7 +1436,8 @@
  found:
 	dmach = &s3c2410_chans[ch];
 	dmach->map = ch_map;
-	dma_chan_map[channel] = dmach;
+	dmach->req_ch = channel;
+	s3c_dma_chan_map[channel] = dmach;
 
 	/* select the channel */
 
diff --git a/arch/arm/plat-s3c24xx/gpio.c b/arch/arm/plat-s3c24xx/gpio.c
index 4a899c2..95df059 100644
--- a/arch/arm/plat-s3c24xx/gpio.c
+++ b/arch/arm/plat-s3c24xx/gpio.c
@@ -183,35 +183,19 @@
 
 int s3c2410_gpio_getirq(unsigned int pin)
 {
-	if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15)
-		return -1;	/* not valid interrupts */
+	if (pin < S3C2410_GPF(0) || pin > S3C2410_GPG(15))
+		return -EINVAL;	/* not valid interrupts */
 
-	if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
-		return -1;	/* not valid pin */
+	if (pin < S3C2410_GPG(0) && pin > S3C2410_GPF(7))
+		return -EINVAL;	/* not valid pin */
 
-	if (pin < S3C2410_GPF4)
-		return (pin - S3C2410_GPF0) + IRQ_EINT0;
+	if (pin < S3C2410_GPF(4))
+		return (pin - S3C2410_GPF(0)) + IRQ_EINT0;
 
-	if (pin < S3C2410_GPG0)
-		return (pin - S3C2410_GPF4) + IRQ_EINT4;
+	if (pin < S3C2410_GPG(0))
+		return (pin - S3C2410_GPF(4)) + IRQ_EINT4;
 
-	return (pin - S3C2410_GPG0) + IRQ_EINT8;
+	return (pin - S3C2410_GPG(0)) + IRQ_EINT8;
 }
 
 EXPORT_SYMBOL(s3c2410_gpio_getirq);
-
-int s3c2410_gpio_irq2pin(unsigned int irq)
-{
-	if (irq >= IRQ_EINT0 && irq <= IRQ_EINT3)
-		return S3C2410_GPF0 + (irq - IRQ_EINT0);
-
-	if (irq >= IRQ_EINT4 && irq <= IRQ_EINT7)
-		return S3C2410_GPF4 + (irq - IRQ_EINT4);
-
-	if (irq >= IRQ_EINT8 && irq <= IRQ_EINT23)
-		return S3C2410_GPG0 + (irq - IRQ_EINT8);
-
-	return -EINVAL;
-}
-
-EXPORT_SYMBOL(s3c2410_gpio_irq2pin);
diff --git a/arch/arm/plat-s3c24xx/gpiolib.c b/arch/arm/plat-s3c24xx/gpiolib.c
index 5c0491b..6d7a961 100644
--- a/arch/arm/plat-s3c24xx/gpiolib.c
+++ b/arch/arm/plat-s3c24xx/gpiolib.c
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/sysdev.h>
 #include <linux/ioport.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
@@ -22,6 +23,7 @@
 #include <mach/gpio-core.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
+#include <plat/pm.h>
 
 #include <mach/regs-gpio.h>
 
@@ -77,9 +79,10 @@
 
 struct s3c_gpio_chip s3c24xx_gpios[] = {
 	[0] = {
-		.base	= S3C24XX_GPIO_BASE(S3C2410_GPA0),
+		.base	= S3C2410_GPACON,
+		.pm	= __gpio_pm(&s3c_gpio_pm_1bit),
 		.chip	= {
-			.base			= S3C2410_GPA0,
+			.base			= S3C2410_GPA(0),
 			.owner			= THIS_MODULE,
 			.label			= "GPIOA",
 			.ngpio			= 24,
@@ -88,45 +91,50 @@
 		},
 	},
 	[1] = {
-		.base	= S3C24XX_GPIO_BASE(S3C2410_GPB0),
+		.base	= S3C2410_GPBCON,
+		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
 		.chip	= {
-			.base			= S3C2410_GPB0,
+			.base			= S3C2410_GPB(0),
 			.owner			= THIS_MODULE,
 			.label			= "GPIOB",
 			.ngpio			= 16,
 		},
 	},
 	[2] = {
-		.base	= S3C24XX_GPIO_BASE(S3C2410_GPC0),
+		.base	= S3C2410_GPCCON,
+		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
 		.chip	= {
-			.base			= S3C2410_GPC0,
+			.base			= S3C2410_GPC(0),
 			.owner			= THIS_MODULE,
 			.label			= "GPIOC",
 			.ngpio			= 16,
 		},
 	},
 	[3] = {
-		.base	= S3C24XX_GPIO_BASE(S3C2410_GPD0),
+		.base	= S3C2410_GPDCON,
+		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
 		.chip	= {
-			.base			= S3C2410_GPD0,
+			.base			= S3C2410_GPD(0),
 			.owner			= THIS_MODULE,
 			.label			= "GPIOD",
 			.ngpio			= 16,
 		},
 	},
 	[4] = {
-		.base	= S3C24XX_GPIO_BASE(S3C2410_GPE0),
+		.base	= S3C2410_GPECON,
+		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
 		.chip	= {
-			.base			= S3C2410_GPE0,
+			.base			= S3C2410_GPE(0),
 			.label			= "GPIOE",
 			.owner			= THIS_MODULE,
 			.ngpio			= 16,
 		},
 	},
 	[5] = {
-		.base	= S3C24XX_GPIO_BASE(S3C2410_GPF0),
+		.base	= S3C2410_GPFCON,
+		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
 		.chip	= {
-			.base			= S3C2410_GPF0,
+			.base			= S3C2410_GPF(0),
 			.owner			= THIS_MODULE,
 			.label			= "GPIOF",
 			.ngpio			= 8,
@@ -134,14 +142,24 @@
 		},
 	},
 	[6] = {
-		.base	= S3C24XX_GPIO_BASE(S3C2410_GPG0),
+		.base	= S3C2410_GPGCON,
+		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
 		.chip	= {
-			.base			= S3C2410_GPG0,
+			.base			= S3C2410_GPG(0),
 			.owner			= THIS_MODULE,
 			.label			= "GPIOG",
-			.ngpio			= 10,
+			.ngpio			= 16,
 			.to_irq			= s3c24xx_gpiolib_bankg_toirq,
 		},
+	}, {
+		.base	= S3C2410_GPHCON,
+		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
+		.chip	= {
+			.base			= S3C2410_GPH(0),
+			.owner			= THIS_MODULE,
+			.label			= "GPIOH",
+			.ngpio			= 11,
+		},
 	},
 };
 
@@ -156,4 +174,4 @@
 	return 0;
 }
 
-arch_initcall(s3c24xx_gpiolib_init);
+core_initcall(s3c24xx_gpiolib_init);
diff --git a/arch/arm/plat-s3c24xx/include/plat/dma-plat.h b/arch/arm/plat-s3c24xx/include/plat/dma-plat.h
new file mode 100644
index 0000000..9565ead
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/include/plat/dma-plat.h
@@ -0,0 +1,84 @@
+/* linux/arch/arm/plat-s3c24xx/include/plat/dma-plat.h
+ *
+ * Copyright (C) 2006 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C24XX DMA 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 <plat/dma-core.h>
+
+extern struct sysdev_class dma_sysclass;
+extern struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS];
+
+#define DMA_CH_VALID		(1<<31)
+#define DMA_CH_NEVER		(1<<30)
+
+struct s3c24xx_dma_addr {
+	unsigned long		from;
+	unsigned long		to;
+};
+
+/* struct s3c24xx_dma_map
+ *
+ * this holds the mapping information for the channel selected
+ * to be connected to the specified device
+*/
+
+struct s3c24xx_dma_map {
+	const char		*name;
+	struct s3c24xx_dma_addr  hw_addr;
+
+	unsigned long		 channels[S3C_DMA_CHANNELS];
+	unsigned long		 channels_rx[S3C_DMA_CHANNELS];
+};
+
+struct s3c24xx_dma_selection {
+	struct s3c24xx_dma_map	*map;
+	unsigned long		 map_size;
+	unsigned long		 dcon_mask;
+
+	void	(*select)(struct s3c2410_dma_chan *chan,
+			  struct s3c24xx_dma_map *map);
+
+	void	(*direction)(struct s3c2410_dma_chan *chan,
+			     struct s3c24xx_dma_map *map,
+			     enum s3c2410_dmasrc dir);
+};
+
+extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
+
+/* struct s3c24xx_dma_order_ch
+ *
+ * channel map for one of the `enum dma_ch` dma channels. the list
+ * entry contains a set of low-level channel numbers, orred with
+ * DMA_CH_VALID, which are checked in the order in the array.
+*/
+
+struct s3c24xx_dma_order_ch {
+	unsigned int	list[S3C_DMA_CHANNELS];	/* list of channels */
+	unsigned int	flags;				/* flags */
+};
+
+/* struct s3c24xx_dma_order
+ *
+ * information provided by either the core or the board to give the
+ * dma system a hint on how to allocate channels
+*/
+
+struct s3c24xx_dma_order {
+	struct s3c24xx_dma_order_ch	channels[DMACH_MAX];
+};
+
+extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map);
+
+/* DMA init code, called from the cpu support code */
+
+extern int s3c2410_dma_init(void);
+
+extern int s3c24xx_dma_init(unsigned int channels, unsigned int irq,
+			    unsigned int stride);
diff --git a/arch/arm/plat-s3c24xx/include/plat/dma.h b/arch/arm/plat-s3c24xx/include/plat/dma.h
deleted file mode 100644
index c78efe3..0000000
--- a/arch/arm/plat-s3c24xx/include/plat/dma.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* linux/include/asm-arm/plat-s3c24xx/dma.h
- *
- * Copyright (C) 2006 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * Samsung S3C24XX DMA 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.
-*/
-
-extern struct sysdev_class dma_sysclass;
-extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
-
-#define DMA_CH_VALID		(1<<31)
-#define DMA_CH_NEVER		(1<<30)
-
-struct s3c24xx_dma_addr {
-	unsigned long		from;
-	unsigned long		to;
-};
-
-/* struct s3c24xx_dma_map
- *
- * this holds the mapping information for the channel selected
- * to be connected to the specified device
-*/
-
-struct s3c24xx_dma_map {
-	const char		*name;
-	struct s3c24xx_dma_addr  hw_addr;
-
-	unsigned long		 channels[S3C2410_DMA_CHANNELS];
-	unsigned long		 channels_rx[S3C2410_DMA_CHANNELS];
-};
-
-struct s3c24xx_dma_selection {
-	struct s3c24xx_dma_map	*map;
-	unsigned long		 map_size;
-	unsigned long		 dcon_mask;
-
-	void	(*select)(struct s3c2410_dma_chan *chan,
-			  struct s3c24xx_dma_map *map);
-
-	void	(*direction)(struct s3c2410_dma_chan *chan,
-			     struct s3c24xx_dma_map *map,
-			     enum s3c2410_dmasrc dir);
-};
-
-extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
-
-/* struct s3c24xx_dma_order_ch
- *
- * channel map for one of the `enum dma_ch` dma channels. the list
- * entry contains a set of low-level channel numbers, orred with
- * DMA_CH_VALID, which are checked in the order in the array.
-*/
-
-struct s3c24xx_dma_order_ch {
-	unsigned int	list[S3C2410_DMA_CHANNELS];	/* list of channels */
-	unsigned int	flags;				/* flags */
-};
-
-/* struct s3c24xx_dma_order
- *
- * information provided by either the core or the board to give the
- * dma system a hint on how to allocate channels
-*/
-
-struct s3c24xx_dma_order {
-	struct s3c24xx_dma_order_ch	channels[DMACH_MAX];
-};
-
-extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map);
-
-/* DMA init code, called from the cpu support code */
-
-extern int s3c2410_dma_init(void);
-
-extern int s3c24xx_dma_init(unsigned int channels, unsigned int irq,
-			    unsigned int stride);
diff --git a/arch/arm/plat-s3c24xx/include/plat/map.h b/arch/arm/plat-s3c24xx/include/plat/map.h
index eed8f78..c4d1334 100644
--- a/arch/arm/plat-s3c24xx/include/plat/map.h
+++ b/arch/arm/plat-s3c24xx/include/plat/map.h
@@ -58,7 +58,6 @@
 #define S3C24XX_SZ_SPI		SZ_1M
 #define S3C24XX_SZ_SDI		SZ_1M
 #define S3C24XX_SZ_NAND		SZ_1M
-#define S3C24XX_SZ_USBHOST	SZ_1M
 
 /* GPIO ports */
 
diff --git a/arch/arm/plat-s3c24xx/include/plat/pm-core.h b/arch/arm/plat-s3c24xx/include/plat/pm-core.h
index c758821..fb45dd9 100644
--- a/arch/arm/plat-s3c24xx/include/plat/pm-core.h
+++ b/arch/arm/plat-s3c24xx/include/plat/pm-core.h
@@ -57,3 +57,8 @@
 	s3c_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
 				s3c_irqwake_eintmask);
 }
+
+static inline void s3c_pm_arch_update_uart(void __iomem *regs,
+					   struct pm_uart_save *save)
+{
+}
diff --git a/arch/arm/plat-s3c24xx/include/plat/regs-dma.h b/arch/arm/plat-s3c24xx/include/plat/regs-dma.h
new file mode 100644
index 0000000..3bc0a21
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/include/plat/regs-dma.h
@@ -0,0 +1,145 @@
+/* arch/arm/mach-s3c2410/include/mach/dma.h
+ *
+ * Copyright (C) 2003,2004,2006 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C24XX DMA 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.
+*/
+
+/* DMA Register definitions */
+
+#define S3C2410_DMA_DISRC		(0x00)
+#define S3C2410_DMA_DISRCC		(0x04)
+#define S3C2410_DMA_DIDST		(0x08)
+#define S3C2410_DMA_DIDSTC		(0x0C)
+#define S3C2410_DMA_DCON		(0x10)
+#define S3C2410_DMA_DSTAT		(0x14)
+#define S3C2410_DMA_DCSRC		(0x18)
+#define S3C2410_DMA_DCDST		(0x1C)
+#define S3C2410_DMA_DMASKTRIG		(0x20)
+#define S3C2412_DMA_DMAREQSEL		(0x24)
+#define S3C2443_DMA_DMAREQSEL		(0x24)
+
+#define S3C2410_DISRCC_INC		(1<<0)
+#define S3C2410_DISRCC_APB		(1<<1)
+
+#define S3C2410_DMASKTRIG_STOP		(1<<2)
+#define S3C2410_DMASKTRIG_ON		(1<<1)
+#define S3C2410_DMASKTRIG_SWTRIG	(1<<0)
+
+#define S3C2410_DCON_DEMAND		(0<<31)
+#define S3C2410_DCON_HANDSHAKE		(1<<31)
+#define S3C2410_DCON_SYNC_PCLK		(0<<30)
+#define S3C2410_DCON_SYNC_HCLK		(1<<30)
+
+#define S3C2410_DCON_INTREQ		(1<<29)
+
+#define S3C2410_DCON_CH0_XDREQ0		(0<<24)
+#define S3C2410_DCON_CH0_UART0		(1<<24)
+#define S3C2410_DCON_CH0_SDI		(2<<24)
+#define S3C2410_DCON_CH0_TIMER		(3<<24)
+#define S3C2410_DCON_CH0_USBEP1		(4<<24)
+
+#define S3C2410_DCON_CH1_XDREQ1		(0<<24)
+#define S3C2410_DCON_CH1_UART1		(1<<24)
+#define S3C2410_DCON_CH1_I2SSDI		(2<<24)
+#define S3C2410_DCON_CH1_SPI		(3<<24)
+#define S3C2410_DCON_CH1_USBEP2		(4<<24)
+
+#define S3C2410_DCON_CH2_I2SSDO		(0<<24)
+#define S3C2410_DCON_CH2_I2SSDI		(1<<24)
+#define S3C2410_DCON_CH2_SDI		(2<<24)
+#define S3C2410_DCON_CH2_TIMER		(3<<24)
+#define S3C2410_DCON_CH2_USBEP3		(4<<24)
+
+#define S3C2410_DCON_CH3_UART2		(0<<24)
+#define S3C2410_DCON_CH3_SDI		(1<<24)
+#define S3C2410_DCON_CH3_SPI		(2<<24)
+#define S3C2410_DCON_CH3_TIMER		(3<<24)
+#define S3C2410_DCON_CH3_USBEP4		(4<<24)
+
+#define S3C2410_DCON_SRCSHIFT		(24)
+#define S3C2410_DCON_SRCMASK		(7<<24)
+
+#define S3C2410_DCON_BYTE		(0<<20)
+#define S3C2410_DCON_HALFWORD		(1<<20)
+#define S3C2410_DCON_WORD		(2<<20)
+
+#define S3C2410_DCON_AUTORELOAD		(0<<22)
+#define S3C2410_DCON_NORELOAD		(1<<22)
+#define S3C2410_DCON_HWTRIG		(1<<23)
+
+#ifdef CONFIG_CPU_S3C2440
+#define S3C2440_DIDSTC_CHKINT		(1<<2)
+
+#define S3C2440_DCON_CH0_I2SSDO		(5<<24)
+#define S3C2440_DCON_CH0_PCMIN		(6<<24)
+
+#define S3C2440_DCON_CH1_PCMOUT		(5<<24)
+#define S3C2440_DCON_CH1_SDI		(6<<24)
+
+#define S3C2440_DCON_CH2_PCMIN		(5<<24)
+#define S3C2440_DCON_CH2_MICIN		(6<<24)
+
+#define S3C2440_DCON_CH3_MICIN		(5<<24)
+#define S3C2440_DCON_CH3_PCMOUT		(6<<24)
+#endif
+
+#ifdef CONFIG_CPU_S3C2412
+
+#define S3C2412_DMAREQSEL_SRC(x)	((x)<<1)
+
+#define S3C2412_DMAREQSEL_HW		(1)
+
+#define S3C2412_DMAREQSEL_SPI0TX	S3C2412_DMAREQSEL_SRC(0)
+#define S3C2412_DMAREQSEL_SPI0RX	S3C2412_DMAREQSEL_SRC(1)
+#define S3C2412_DMAREQSEL_SPI1TX	S3C2412_DMAREQSEL_SRC(2)
+#define S3C2412_DMAREQSEL_SPI1RX	S3C2412_DMAREQSEL_SRC(3)
+#define S3C2412_DMAREQSEL_I2STX		S3C2412_DMAREQSEL_SRC(4)
+#define S3C2412_DMAREQSEL_I2SRX		S3C2412_DMAREQSEL_SRC(5)
+#define S3C2412_DMAREQSEL_TIMER		S3C2412_DMAREQSEL_SRC(9)
+#define S3C2412_DMAREQSEL_SDI		S3C2412_DMAREQSEL_SRC(10)
+#define S3C2412_DMAREQSEL_USBEP1	S3C2412_DMAREQSEL_SRC(13)
+#define S3C2412_DMAREQSEL_USBEP2	S3C2412_DMAREQSEL_SRC(14)
+#define S3C2412_DMAREQSEL_USBEP3	S3C2412_DMAREQSEL_SRC(15)
+#define S3C2412_DMAREQSEL_USBEP4	S3C2412_DMAREQSEL_SRC(16)
+#define S3C2412_DMAREQSEL_XDREQ0	S3C2412_DMAREQSEL_SRC(17)
+#define S3C2412_DMAREQSEL_XDREQ1	S3C2412_DMAREQSEL_SRC(18)
+#define S3C2412_DMAREQSEL_UART0_0	S3C2412_DMAREQSEL_SRC(19)
+#define S3C2412_DMAREQSEL_UART0_1	S3C2412_DMAREQSEL_SRC(20)
+#define S3C2412_DMAREQSEL_UART1_0	S3C2412_DMAREQSEL_SRC(21)
+#define S3C2412_DMAREQSEL_UART1_1	S3C2412_DMAREQSEL_SRC(22)
+#define S3C2412_DMAREQSEL_UART2_0	S3C2412_DMAREQSEL_SRC(23)
+#define S3C2412_DMAREQSEL_UART2_1	S3C2412_DMAREQSEL_SRC(24)
+
+#endif
+
+#define S3C2443_DMAREQSEL_SRC(x)	((x)<<1)
+
+#define S3C2443_DMAREQSEL_HW		(1)
+
+#define S3C2443_DMAREQSEL_SPI0TX	S3C2443_DMAREQSEL_SRC(0)
+#define S3C2443_DMAREQSEL_SPI0RX	S3C2443_DMAREQSEL_SRC(1)
+#define S3C2443_DMAREQSEL_SPI1TX	S3C2443_DMAREQSEL_SRC(2)
+#define S3C2443_DMAREQSEL_SPI1RX	S3C2443_DMAREQSEL_SRC(3)
+#define S3C2443_DMAREQSEL_I2STX		S3C2443_DMAREQSEL_SRC(4)
+#define S3C2443_DMAREQSEL_I2SRX		S3C2443_DMAREQSEL_SRC(5)
+#define S3C2443_DMAREQSEL_TIMER		S3C2443_DMAREQSEL_SRC(9)
+#define S3C2443_DMAREQSEL_SDI		S3C2443_DMAREQSEL_SRC(10)
+#define S3C2443_DMAREQSEL_XDREQ0	S3C2443_DMAREQSEL_SRC(17)
+#define S3C2443_DMAREQSEL_XDREQ1	S3C2443_DMAREQSEL_SRC(18)
+#define S3C2443_DMAREQSEL_UART0_0	S3C2443_DMAREQSEL_SRC(19)
+#define S3C2443_DMAREQSEL_UART0_1	S3C2443_DMAREQSEL_SRC(20)
+#define S3C2443_DMAREQSEL_UART1_0	S3C2443_DMAREQSEL_SRC(21)
+#define S3C2443_DMAREQSEL_UART1_1	S3C2443_DMAREQSEL_SRC(22)
+#define S3C2443_DMAREQSEL_UART2_0	S3C2443_DMAREQSEL_SRC(23)
+#define S3C2443_DMAREQSEL_UART2_1	S3C2443_DMAREQSEL_SRC(24)
+#define S3C2443_DMAREQSEL_UART3_0	S3C2443_DMAREQSEL_SRC(25)
+#define S3C2443_DMAREQSEL_UART3_1	S3C2443_DMAREQSEL_SRC(26)
+#define S3C2443_DMAREQSEL_PCMOUT	S3C2443_DMAREQSEL_SRC(27)
+#define S3C2443_DMAREQSEL_PCMIN 	S3C2443_DMAREQSEL_SRC(28)
+#define S3C2443_DMAREQSEL_MICIN		S3C2443_DMAREQSEL_SRC(29)
diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c
index 062a293..56e5253 100644
--- a/arch/arm/plat-s3c24xx/pm.c
+++ b/arch/arm/plat-s3c24xx/pm.c
@@ -30,6 +30,7 @@
 #include <linux/suspend.h>
 #include <linux/errno.h>
 #include <linux/time.h>
+#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/serial_core.h>
 #include <linux/io.h>
@@ -75,43 +76,10 @@
 	SAVE_ITEM(S3C2410_CLKSLOW),
 };
 
-static struct gpio_sleep {
-	void __iomem	*base;
-	unsigned int	 gpcon;
-	unsigned int	 gpdat;
-	unsigned int	 gpup;
-} gpio_save[] = {
-	[0] = {
-		.base	= S3C2410_GPACON,
-	},
-	[1] = {
-		.base	= S3C2410_GPBCON,
-	},
-	[2] = {
-		.base	= S3C2410_GPCCON,
-	},
-	[3] = {
-		.base	= S3C2410_GPDCON,
-	},
-	[4] = {
-		.base	= S3C2410_GPECON,
-	},
-	[5] = {
-		.base	= S3C2410_GPFCON,
-	},
-	[6] = {
-		.base	= S3C2410_GPGCON,
-	},
-	[7] = {
-		.base	= S3C2410_GPHCON,
-	},
-};
-
 static struct sleep_save misc_save[] = {
 	SAVE_ITEM(S3C2410_DCLKCON),
 };
 
-
 /* s3c_pm_check_resume_pin
  *
  * check to see if the pin is configured correctly for sleep mode, and
@@ -156,195 +124,15 @@
 	 * and then configure it as an input if it is not
 	*/
 
-	for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) {
-		s3c_pm_check_resume_pin(pin, pin - S3C2410_GPF0);
+	for (pin = S3C2410_GPF(0); pin <= S3C2410_GPF(7); pin++) {
+		s3c_pm_check_resume_pin(pin, pin - S3C2410_GPF(0));
 	}
 
-	for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) {
-		s3c_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8);
+	for (pin = S3C2410_GPG(0); pin <= S3C2410_GPG(7); pin++) {
+		s3c_pm_check_resume_pin(pin, (pin - S3C2410_GPG(0))+8);
 	}
 }
 
-/* offsets for CON/DAT/UP registers */
-
-#define OFFS_CON	(S3C2410_GPACON - S3C2410_GPACON)
-#define OFFS_DAT	(S3C2410_GPADAT - S3C2410_GPACON)
-#define OFFS_UP		(S3C2410_GPBUP  - S3C2410_GPBCON)
-
-/* s3c_pm_save_gpios()
- *
- * Save the state of the GPIOs
- */
-
-void s3c_pm_save_gpios(void)
-{
-	struct gpio_sleep *gps = gpio_save;
-	unsigned int gpio;
-
-	for (gpio = 0; gpio < ARRAY_SIZE(gpio_save); gpio++, gps++) {
-		void __iomem *base = gps->base;
-
-		gps->gpcon = __raw_readl(base + OFFS_CON);
-		gps->gpdat = __raw_readl(base + OFFS_DAT);
-
-		if (gpio > 0)
-			gps->gpup = __raw_readl(base + OFFS_UP);
-
-	}
-}
-
-/* Test whether the given masked+shifted bits of an GPIO configuration
- * are one of the SFN (special function) modes. */
-
-static inline int is_sfn(unsigned long con)
-{
-	return (con == 2 || con == 3);
-}
-
-/* Test if the given masked+shifted GPIO configuration is an input */
-
-static inline int is_in(unsigned long con)
-{
-	return con == 0;
-}
-
-/* Test if the given masked+shifted GPIO configuration is an output */
-
-static inline int is_out(unsigned long con)
-{
-	return con == 1;
-}
-
-/**
- * s3c2410_pm_restore_gpio() - restore the given GPIO bank
- * @index: The number of the GPIO bank being resumed.
- * @gps: The sleep confgiuration for the bank.
- *
- * Restore one of the GPIO banks that was saved during suspend. This is
- * not as simple as once thought, due to the possibility of glitches
- * from the order that the CON and DAT registers are set in.
- *
- * The three states the pin can be are {IN,OUT,SFN} which gives us 9
- * combinations of changes to check. Three of these, if the pin stays
- * in the same configuration can be discounted. This leaves us with
- * the following:
- *
- * { IN => OUT }  Change DAT first
- * { IN => SFN }  Change CON first
- * { OUT => SFN } Change CON first, so new data will not glitch
- * { OUT => IN }  Change CON first, so new data will not glitch
- * { SFN => IN }  Change CON first
- * { SFN => OUT } Change DAT first, so new data will not glitch [1]
- *
- * We do not currently deal with the UP registers as these control
- * weak resistors, so a small delay in change should not need to bring
- * these into the calculations.
- *
- * [1] this assumes that writing to a pin DAT whilst in SFN will set the
- *     state for when it is next output.
- */
-
-static void s3c2410_pm_restore_gpio(int index, struct gpio_sleep *gps)
-{
-	void __iomem *base = gps->base;
-	unsigned long gps_gpcon = gps->gpcon;
-	unsigned long gps_gpdat = gps->gpdat;
-	unsigned long old_gpcon;
-	unsigned long old_gpdat;
-	unsigned long old_gpup = 0x0;
-	unsigned long gpcon;
-	int nr;
-
-	old_gpcon = __raw_readl(base + OFFS_CON);
-	old_gpdat = __raw_readl(base + OFFS_DAT);
-
-	if (base == S3C2410_GPACON) {
-		/* GPACON only has one bit per control / data and no PULLUPs.
-		 * GPACON[x] = 0 => Output, 1 => SFN */
-
-		/* first set all SFN bits to SFN */
-
-		gpcon = old_gpcon | gps->gpcon;
-		__raw_writel(gpcon, base + OFFS_CON);
-
-		/* now set all the other bits */
-
-		__raw_writel(gps_gpdat, base + OFFS_DAT);
-		__raw_writel(gps_gpcon, base + OFFS_CON);
-	} else {
-		unsigned long old, new, mask;
-		unsigned long change_mask = 0x0;
-
-		old_gpup = __raw_readl(base + OFFS_UP);
-
-		/* Create a change_mask of all the items that need to have
-		 * their CON value changed before their DAT value, so that
-		 * we minimise the work between the two settings.
-		 */
-
-		for (nr = 0, mask = 0x03; nr < 32; nr += 2, mask <<= 2) {
-			old = (old_gpcon & mask) >> nr;
-			new = (gps_gpcon & mask) >> nr;
-
-			/* If there is no change, then skip */
-
-			if (old == new)
-				continue;
-
-			/* If both are special function, then skip */
-
-			if (is_sfn(old) && is_sfn(new))
-				continue;
-
-			/* Change is IN => OUT, do not change now */
-
-			if (is_in(old) && is_out(new))
-				continue;
-
-			/* Change is SFN => OUT, do not change now */
-
-			if (is_sfn(old) && is_out(new))
-				continue;
-
-			/* We should now be at the case of IN=>SFN,
-			 * OUT=>SFN, OUT=>IN, SFN=>IN. */
-
-			change_mask |= mask;
-		}
-
-		/* Write the new CON settings */
-
-		gpcon = old_gpcon & ~change_mask;
-		gpcon |= gps_gpcon & change_mask;
-
-		__raw_writel(gpcon, base + OFFS_CON);
-
-		/* Now change any items that require DAT,CON */
-
-		__raw_writel(gps_gpdat, base + OFFS_DAT);
-		__raw_writel(gps_gpcon, base + OFFS_CON);
-		__raw_writel(gps->gpup, base + OFFS_UP);
-	}
-
-	S3C_PMDBG("GPIO[%d] CON %08lx => %08lx, DAT %08lx => %08lx\n",
-		  index, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat);
-}
-
-
-/** s3c2410_pm_restore_gpios()
- *
- * Restore the state of the GPIOs
- */
-
-void s3c_pm_restore_gpios(void)
-{
-	struct gpio_sleep *gps = gpio_save;
-	int gpio;
-
-	for (gpio = 0; gpio < ARRAY_SIZE(gpio_save); gpio++, gps++) {
-		s3c2410_pm_restore_gpio(gpio, gps);
-	}
-}
 
 void s3c_pm_restore_core(void)
 {
diff --git a/arch/arm/plat-s3c24xx/setup-i2c.c b/arch/arm/plat-s3c24xx/setup-i2c.c
index d62b7e7..71a6acc 100644
--- a/arch/arm/plat-s3c24xx/setup-i2c.c
+++ b/arch/arm/plat-s3c24xx/setup-i2c.c
@@ -11,6 +11,7 @@
 */
 
 #include <linux/kernel.h>
+#include <linux/gpio.h>
 
 struct platform_device;
 
@@ -20,6 +21,6 @@
 
 void s3c_i2c0_cfg_gpio(struct platform_device *dev)
 {
-	s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_IICSDA);
-	s3c2410_gpio_cfgpin(S3C2410_GPE14, S3C2410_GPE14_IICSCL);
+	s3c2410_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA);
+	s3c2410_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL);
 }
diff --git a/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c b/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
index 8b403cb..9edf789 100644
--- a/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
+++ b/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
@@ -22,16 +22,16 @@
 					  int enable)
 {
 	if (enable) {
-		s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_SPICLK0);
-		s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_SPIMOSI0);
-		s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_SPIMISO0);
-		s3c2410_gpio_pullup(S3C2410_GPE11, 0);
-		s3c2410_gpio_pullup(S3C2410_GPE13, 0);
+		s3c2410_gpio_cfgpin(S3C2410_GPE(13), S3C2410_GPE13_SPICLK0);
+		s3c2410_gpio_cfgpin(S3C2410_GPE(12), S3C2410_GPE12_SPIMOSI0);
+		s3c2410_gpio_cfgpin(S3C2410_GPE(11), S3C2410_GPE11_SPIMISO0);
+		s3c2410_gpio_pullup(S3C2410_GPE(11), 0);
+		s3c2410_gpio_pullup(S3C2410_GPE(13), 0);
 	} else {
-		s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPIO_INPUT);
-		s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPIO_INPUT);
-		s3c2410_gpio_pullup(S3C2410_GPE11, 1);
-		s3c2410_gpio_pullup(S3C2410_GPE12, 1);
-		s3c2410_gpio_pullup(S3C2410_GPE13, 1);
+		s3c2410_gpio_cfgpin(S3C2410_GPE(13), S3C2410_GPIO_INPUT);
+		s3c2410_gpio_cfgpin(S3C2410_GPE(11), S3C2410_GPIO_INPUT);
+		s3c2410_gpio_pullup(S3C2410_GPE(11), 1);
+		s3c2410_gpio_pullup(S3C2410_GPE(12), 1);
+		s3c2410_gpio_pullup(S3C2410_GPE(13), 1);
 	}
 }
diff --git a/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c b/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
index 8fccd4e..f34d0fc 100644
--- a/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
+++ b/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
@@ -22,16 +22,16 @@
 				       int enable)
 {
 	if (enable) {
-		s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_SPICLK1);
-		s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_SPIMOSI1);
-		s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPG5_SPIMISO1);
-		s3c2410_gpio_pullup(S3C2410_GPG5, 0);
-		s3c2410_gpio_pullup(S3C2410_GPG6, 0);
+		s3c2410_gpio_cfgpin(S3C2410_GPG(7), S3C2410_GPG7_SPICLK1);
+		s3c2410_gpio_cfgpin(S3C2410_GPG(6), S3C2410_GPG6_SPIMOSI1);
+		s3c2410_gpio_cfgpin(S3C2410_GPG(5), S3C2410_GPG5_SPIMISO1);
+		s3c2410_gpio_pullup(S3C2410_GPG(5), 0);
+		s3c2410_gpio_pullup(S3C2410_GPG(6), 0);
 	} else {
-		s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPIO_INPUT);
-		s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPIO_INPUT);
-		s3c2410_gpio_pullup(S3C2410_GPG5, 1);
-		s3c2410_gpio_pullup(S3C2410_GPG6, 1);
-		s3c2410_gpio_pullup(S3C2410_GPG7, 1);
+		s3c2410_gpio_cfgpin(S3C2410_GPG(7), S3C2410_GPIO_INPUT);
+		s3c2410_gpio_cfgpin(S3C2410_GPG(5), S3C2410_GPIO_INPUT);
+		s3c2410_gpio_pullup(S3C2410_GPG(5), 1);
+		s3c2410_gpio_pullup(S3C2410_GPG(6), 1);
+		s3c2410_gpio_pullup(S3C2410_GPG(7), 1);
 	}
 }
diff --git a/arch/arm/plat-s3c64xx/Kconfig b/arch/arm/plat-s3c64xx/Kconfig
index 54375a0..5ebd8b4 100644
--- a/arch/arm/plat-s3c64xx/Kconfig
+++ b/arch/arm/plat-s3c64xx/Kconfig
@@ -19,6 +19,7 @@
 	select S3C_GPIO_PULL_UPDOWN
 	select S3C_GPIO_CFG_S3C24XX
 	select S3C_GPIO_CFG_S3C64XX
+	select USB_ARCH_HAS_OHCI
 	help
 	  Base platform code for any Samsung S3C64XX device
 
@@ -38,6 +39,10 @@
 	  Common clock support code for the S3C6400 that is shared
 	  by other CPUs in the series, such as the S3C6410.
 
+config S3C64XX_DMA
+	bool "S3C64XX DMA"
+	select S3C_DMA
+
 # platform specific device setup
 
 config S3C64XX_SETUP_I2C0
@@ -59,4 +64,9 @@
 	help
 	  Common setup code for S3C64XX with an 24bpp RGB display helper.
 
+config S3C64XX_SETUP_SDHCI_GPIO
+	bool
+	help
+	  Common setup code for S3C64XX SDHCI GPIO configurations
+
 endif
diff --git a/arch/arm/plat-s3c64xx/Makefile b/arch/arm/plat-s3c64xx/Makefile
index 2e6d79b..2ed5df3 100644
--- a/arch/arm/plat-s3c64xx/Makefile
+++ b/arch/arm/plat-s3c64xx/Makefile
@@ -24,8 +24,19 @@
 obj-$(CONFIG_CPU_S3C6400_INIT)	+= s3c6400-init.o
 obj-$(CONFIG_CPU_S3C6400_CLOCK)	+= s3c6400-clock.o
 
+# PM support
+
+obj-$(CONFIG_PM)		+= pm.o
+obj-$(CONFIG_PM)		+= sleep.o
+obj-$(CONFIG_PM)		+= irq-pm.o
+
+# DMA support
+
+obj-$(CONFIG_S3C64XX_DMA)	+= dma.o
+
 # Device setup
 
 obj-$(CONFIG_S3C64XX_SETUP_I2C0) += setup-i2c0.o
 obj-$(CONFIG_S3C64XX_SETUP_I2C1) += setup-i2c1.o
 obj-$(CONFIG_S3C64XX_SETUP_FB_24BPP) += setup-fb-24bpp.o
+obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
\ No newline at end of file
diff --git a/arch/arm/plat-s3c64xx/clock.c b/arch/arm/plat-s3c64xx/clock.c
index ad1b968..0bc2fa1 100644
--- a/arch/arm/plat-s3c64xx/clock.c
+++ b/arch/arm/plat-s3c64xx/clock.c
@@ -27,6 +27,12 @@
 #include <plat/devs.h>
 #include <plat/clock.h>
 
+struct clk clk_h2 = {
+	.name		= "hclk2",
+	.id		= -1,
+	.rate		= 0,
+};
+
 struct clk clk_27m = {
 	.name		= "clk_27m",
 	.id		= -1,
@@ -152,6 +158,18 @@
 		.parent		= &clk_48m,
 		.enable		= s3c64xx_sclk_ctrl,
 		.ctrlbit	= S3C_CLKCON_SCLK_MMC2_48,
+	}, {
+		.name		= "dma0",
+		.id		= -1,
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_DMA0,
+	}, {
+		.name		= "dma1",
+		.id		= -1,
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_DMA1,
 	},
 };
 
@@ -246,6 +264,7 @@
 	&clk_epll,
 	&clk_27m,
 	&clk_48m,
+	&clk_h2,
 };
 
 void __init s3c64xx_register_clocks(void)
diff --git a/arch/arm/plat-s3c64xx/cpu.c b/arch/arm/plat-s3c64xx/cpu.c
index 91f49a3..b1fdd83 100644
--- a/arch/arm/plat-s3c64xx/cpu.c
+++ b/arch/arm/plat-s3c64xx/cpu.c
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
+#include <linux/sysdev.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
@@ -101,9 +102,24 @@
 		.pfn		= __phys_to_pfn(S3C64XX_PA_MODEM),
 		.length		= SZ_4K,
 		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S3C_VA_WATCHDOG,
+		.pfn		= __phys_to_pfn(S3C64XX_PA_WATCHDOG),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
 	},
 };
 
+
+struct sysdev_class s3c64xx_sysclass = {
+	.name	= "s3c64xx-core",
+};
+
+static struct sys_device s3c64xx_sysdev = {
+	.cls	= &s3c64xx_sysclass,
+};
+
+
 /* read cpu identification code */
 
 void __init s3c64xx_init_io(struct map_desc *mach_desc, int size)
@@ -115,5 +131,21 @@
 	iotable_init(mach_desc, size);
 
 	idcode = __raw_readl(S3C_VA_SYS + 0x118);
+	if (!idcode) {
+		/* S3C6400 has the ID register in a different place,
+		 * and needs a write before it can be read. */
+
+		__raw_writel(0x0, S3C_VA_SYS + 0xA1C);
+		idcode = __raw_readl(S3C_VA_SYS + 0xA1C);
+	}
+
 	s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids));
 }
+
+static __init int s3c64xx_sysdev_init(void)
+{
+	sysdev_class_register(&s3c64xx_sysclass);
+	return sysdev_register(&s3c64xx_sysdev);
+}
+
+core_initcall(s3c64xx_sysdev_init);
diff --git a/arch/arm/plat-s3c64xx/dma.c b/arch/arm/plat-s3c64xx/dma.c
new file mode 100644
index 0000000..67aa93d
--- /dev/null
+++ b/arch/arm/plat-s3c64xx/dma.c
@@ -0,0 +1,722 @@
+/* linux/arch/arm/plat-s3c64xx/dma.c
+ *
+ * Copyright 2009 Openmoko, Inc.
+ * Copyright 2009 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX DMA core
+ *
+ * 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/interrupt.h>
+#include <linux/dmapool.h>
+#include <linux/sysdev.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/dma.h>
+#include <mach/map.h>
+#include <mach/irqs.h>
+
+#include <plat/dma-plat.h>
+#include <plat/regs-sys.h>
+
+#include <asm/hardware/pl080.h>
+
+/* dma channel state information */
+
+struct s3c64xx_dmac {
+	struct sys_device	 sysdev;
+	struct clk		*clk;
+	void __iomem		*regs;
+	struct s3c2410_dma_chan *channels;
+	enum dma_ch		 chanbase;
+};
+
+/* pool to provide LLI buffers */
+static struct dma_pool *dma_pool;
+
+/* Debug configuration and code */
+
+static unsigned char debug_show_buffs = 0;
+
+static void dbg_showchan(struct s3c2410_dma_chan *chan)
+{
+	pr_debug("DMA%d: %08x->%08x L %08x C %08x,%08x S %08x\n",
+		 chan->number,
+		 readl(chan->regs + PL080_CH_SRC_ADDR),
+		 readl(chan->regs + PL080_CH_DST_ADDR),
+		 readl(chan->regs + PL080_CH_LLI),
+		 readl(chan->regs + PL080_CH_CONTROL),
+		 readl(chan->regs + PL080S_CH_CONTROL2),
+		 readl(chan->regs + PL080S_CH_CONFIG));
+}
+
+static void show_lli(struct pl080s_lli *lli)
+{
+	pr_debug("LLI[%p] %08x->%08x, NL %08x C %08x,%08x\n",
+		 lli, lli->src_addr, lli->dst_addr, lli->next_lli,
+		 lli->control0, lli->control1);
+}
+
+static void dbg_showbuffs(struct s3c2410_dma_chan *chan)
+{
+	struct s3c64xx_dma_buff *ptr;
+	struct s3c64xx_dma_buff *end;
+
+	pr_debug("DMA%d: buffs next %p, curr %p, end %p\n",
+		 chan->number, chan->next, chan->curr, chan->end);
+
+	ptr = chan->next;
+	end = chan->end;
+
+	if (debug_show_buffs) {
+		for (; ptr != NULL; ptr = ptr->next) {
+			pr_debug("DMA%d: %08x ",
+				 chan->number, ptr->lli_dma);
+			show_lli(ptr->lli);
+		}
+	}
+}
+
+/* End of Debug */
+
+static struct s3c2410_dma_chan *s3c64xx_dma_map_channel(unsigned int channel)
+{
+	struct s3c2410_dma_chan *chan;
+	unsigned int start, offs;
+
+	start = 0;
+
+	if (channel >= DMACH_PCM1_TX)
+		start = 8;
+
+	for (offs = 0; offs < 8; offs++) {
+		chan = &s3c2410_chans[start + offs];
+		if (!chan->in_use)
+			goto found;
+	}
+
+	return NULL;
+
+found:
+	s3c_dma_chan_map[channel] = chan;
+	return chan;
+}
+
+int s3c2410_dma_config(unsigned int channel, int xferunit)
+{
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+	if (chan == NULL)
+		return -EINVAL;
+
+	switch (xferunit) {
+	case 1:
+		chan->hw_width = 0;
+		break;
+	case 2:
+		chan->hw_width = 1;
+		break;
+	case 4:
+		chan->hw_width = 2;
+		break;
+	default:
+		printk(KERN_ERR "%s: illegal width %d\n", __func__, xferunit);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(s3c2410_dma_config);
+
+static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan,
+				 struct pl080s_lli *lli,
+				 dma_addr_t data, int size)
+{
+	dma_addr_t src, dst;
+	u32 control0, control1;
+
+	switch (chan->source) {
+	case S3C2410_DMASRC_HW:
+		src = chan->dev_addr;
+		dst = data;
+		control0 = PL080_CONTROL_SRC_AHB2;
+		control0 |= (u32)chan->hw_width << PL080_CONTROL_SWIDTH_SHIFT;
+		control0 |= 2 << PL080_CONTROL_DWIDTH_SHIFT;
+		control0 |= PL080_CONTROL_DST_INCR;
+		break;
+
+	case S3C2410_DMASRC_MEM:
+		src = data;
+		dst = chan->dev_addr;
+		control0 = PL080_CONTROL_DST_AHB2;
+		control0 |= (u32)chan->hw_width << PL080_CONTROL_DWIDTH_SHIFT;
+		control0 |= 2 << PL080_CONTROL_SWIDTH_SHIFT;
+		control0 |= PL080_CONTROL_SRC_INCR;
+		break;
+	default:
+		BUG();
+	}
+
+	/* note, we do not currently setup any of the burst controls */
+
+	control1 = size >> chan->hw_width;	/* size in no of xfers */
+	control0 |= PL080_CONTROL_PROT_SYS;	/* always in priv. mode */
+	control0 |= PL080_CONTROL_TC_IRQ_EN;	/* always fire IRQ */
+
+	lli->src_addr = src;
+	lli->dst_addr = dst;
+	lli->next_lli = 0;
+	lli->control0 = control0;
+	lli->control1 = control1;
+}
+
+static void s3c64xx_lli_to_regs(struct s3c2410_dma_chan *chan,
+				struct pl080s_lli *lli)
+{
+	void __iomem *regs = chan->regs;
+
+	pr_debug("%s: LLI %p => regs\n", __func__, lli);
+	show_lli(lli);
+
+	writel(lli->src_addr, regs + PL080_CH_SRC_ADDR);
+	writel(lli->dst_addr, regs + PL080_CH_DST_ADDR);
+	writel(lli->next_lli, regs + PL080_CH_LLI);
+	writel(lli->control0, regs + PL080_CH_CONTROL);
+	writel(lli->control1, regs + PL080S_CH_CONTROL2);
+}
+
+static int s3c64xx_dma_start(struct s3c2410_dma_chan *chan)
+{
+	struct s3c64xx_dmac *dmac = chan->dmac;
+	u32 config;
+	u32 bit = chan->bit;
+
+	dbg_showchan(chan);
+
+	pr_debug("%s: clearing interrupts\n", __func__);
+
+	/* clear interrupts */
+	writel(bit, dmac->regs + PL080_TC_CLEAR);
+	writel(bit, dmac->regs + PL080_ERR_CLEAR);
+
+	pr_debug("%s: starting channel\n", __func__);
+
+	config = readl(chan->regs + PL080S_CH_CONFIG);
+	config |= PL080_CONFIG_ENABLE;
+
+	pr_debug("%s: writing config %08x\n", __func__, config);
+	writel(config, chan->regs + PL080S_CH_CONFIG);
+
+	return 0;
+}
+
+static int s3c64xx_dma_stop(struct s3c2410_dma_chan *chan)
+{
+	u32 config;
+	int timeout;
+
+	pr_debug("%s: stopping channel\n", __func__);
+
+	dbg_showchan(chan);
+
+	config = readl(chan->regs + PL080S_CH_CONFIG);
+	config |= PL080_CONFIG_HALT;
+	writel(config, chan->regs + PL080S_CH_CONFIG);
+
+	timeout = 1000;
+	do {
+		config = readl(chan->regs + PL080S_CH_CONFIG);
+		pr_debug("%s: %d - config %08x\n", __func__, timeout, config);
+		if (config & PL080_CONFIG_ACTIVE)
+			udelay(10);
+		else
+			break;
+		} while (--timeout > 0);
+
+	if (config & PL080_CONFIG_ACTIVE) {
+		printk(KERN_ERR "%s: channel still active\n", __func__);
+		return -EFAULT;
+	}
+
+	config = readl(chan->regs + PL080S_CH_CONFIG);
+	config &= ~PL080_CONFIG_ENABLE;
+	writel(config, chan->regs + PL080S_CH_CONFIG);
+
+	return 0;
+}
+
+static inline void s3c64xx_dma_bufffdone(struct s3c2410_dma_chan *chan,
+					 struct s3c64xx_dma_buff *buf,
+					 enum s3c2410_dma_buffresult result)
+{
+	if (chan->callback_fn != NULL)
+		(chan->callback_fn)(chan, buf->pw, 0, result);
+}
+
+static void s3c64xx_dma_freebuff(struct s3c64xx_dma_buff *buff)
+{
+	dma_pool_free(dma_pool, buff->lli, buff->lli_dma);
+	kfree(buff);
+}
+
+static int s3c64xx_dma_flush(struct s3c2410_dma_chan *chan)
+{
+	struct s3c64xx_dma_buff *buff, *next;
+	u32 config;
+
+	dbg_showchan(chan);
+
+	pr_debug("%s: flushing channel\n", __func__);
+
+	config = readl(chan->regs + PL080S_CH_CONFIG);
+	config &= ~PL080_CONFIG_ENABLE;
+	writel(config, chan->regs + PL080S_CH_CONFIG);
+
+	/* dump all the buffers associated with this channel */
+
+	for (buff = chan->curr; buff != NULL; buff = next) {
+		next = buff->next;
+		pr_debug("%s: buff %p (next %p)\n", __func__, buff, buff->next);
+
+		s3c64xx_dma_bufffdone(chan, buff, S3C2410_RES_ABORT);
+		s3c64xx_dma_freebuff(buff);
+	}
+
+	chan->curr = chan->next = chan->end = NULL;
+
+	return 0;
+}
+
+int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op)
+{
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+	WARN_ON(!chan);
+	if (!chan)
+		return -EINVAL;
+
+	switch (op) {
+	case S3C2410_DMAOP_START:
+		return s3c64xx_dma_start(chan);
+
+	case S3C2410_DMAOP_STOP:
+		return s3c64xx_dma_stop(chan);
+
+	case S3C2410_DMAOP_FLUSH:
+		return s3c64xx_dma_flush(chan);
+
+	/* belive PAUSE/RESUME are no-ops */
+	case S3C2410_DMAOP_PAUSE:
+	case S3C2410_DMAOP_RESUME:
+	case S3C2410_DMAOP_STARTED:
+	case S3C2410_DMAOP_TIMEOUT:
+		return 0;
+	}
+
+	return -ENOENT;
+}
+EXPORT_SYMBOL(s3c2410_dma_ctrl);
+
+/* s3c2410_dma_enque
+ *
+ */
+
+int s3c2410_dma_enqueue(unsigned int channel, void *id,
+			dma_addr_t data, int size)
+{
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+	struct s3c64xx_dma_buff *next;
+	struct s3c64xx_dma_buff *buff;
+	struct pl080s_lli *lli;
+	int ret;
+
+	WARN_ON(!chan);
+	if (!chan)
+		return -EINVAL;
+
+	buff = kzalloc(sizeof(struct s3c64xx_dma_buff), GFP_KERNEL);
+	if (!buff) {
+		printk(KERN_ERR "%s: no memory for buffer\n", __func__);
+		return -ENOMEM;
+	}
+
+	lli = dma_pool_alloc(dma_pool, GFP_KERNEL, &buff->lli_dma);
+	if (!lli) {
+		printk(KERN_ERR "%s: no memory for lli\n", __func__);
+		ret = -ENOMEM;
+		goto err_buff;
+	}
+
+	pr_debug("%s: buff %p, dp %08x lli (%p, %08x) %d\n",
+		 __func__, buff, data, lli, (u32)buff->lli_dma, size);
+
+	buff->lli = lli;
+	buff->pw = id;
+
+	s3c64xx_dma_fill_lli(chan, lli, data, size);
+
+	if ((next = chan->next) != NULL) {
+		struct s3c64xx_dma_buff *end = chan->end;
+		struct pl080s_lli *endlli = end->lli;
+
+		pr_debug("enquing onto channel\n");
+
+		end->next = buff;
+		endlli->next_lli = buff->lli_dma;
+
+		if (chan->flags & S3C2410_DMAF_CIRCULAR) {
+			struct s3c64xx_dma_buff *curr = chan->curr;
+			lli->next_lli = curr->lli_dma;
+		}
+
+		if (next == chan->curr) {
+			writel(buff->lli_dma, chan->regs + PL080_CH_LLI);
+			chan->next = buff;
+		}
+
+		show_lli(endlli);
+		chan->end = buff;
+	} else {
+		pr_debug("enquing onto empty channel\n");
+
+		chan->curr = buff;
+		chan->next = buff;
+		chan->end = buff;
+
+		s3c64xx_lli_to_regs(chan, lli);
+	}
+
+	show_lli(lli);
+
+	dbg_showchan(chan);
+	dbg_showbuffs(chan);
+	return 0;
+
+err_buff:
+	kfree(buff);
+	return ret;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_enqueue);
+
+
+int s3c2410_dma_devconfig(int channel,
+			  enum s3c2410_dmasrc source,
+			  unsigned long devaddr)
+{
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+	u32 peripheral;
+	u32 config = 0;
+
+	pr_debug("%s: channel %d, source %d, dev %08lx, chan %p\n",
+		 __func__, channel, source, devaddr, chan);
+
+	WARN_ON(!chan);
+	if (!chan)
+		return -EINVAL;
+
+	peripheral = (chan->peripheral & 0xf);
+	chan->source = source;
+	chan->dev_addr = devaddr;
+
+	pr_debug("%s: peripheral %d\n", __func__, peripheral);
+
+	switch (source) {
+	case S3C2410_DMASRC_HW:
+		config = 2 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+		config |= peripheral << PL080_CONFIG_SRC_SEL_SHIFT;
+		break;
+	case S3C2410_DMASRC_MEM:
+		config = 1 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+		config |= peripheral << PL080_CONFIG_DST_SEL_SHIFT;
+		break;
+	default:
+		printk(KERN_ERR "%s: bad source\n", __func__);
+		return -EINVAL;
+	}
+
+	/* allow TC and ERR interrupts */
+	config |= PL080_CONFIG_TC_IRQ_MASK;
+	config |= PL080_CONFIG_ERR_IRQ_MASK;
+
+	pr_debug("%s: config %08x\n", __func__, config);
+
+	writel(config, chan->regs + PL080S_CH_CONFIG);
+
+	return 0;
+}
+EXPORT_SYMBOL(s3c2410_dma_devconfig);
+
+
+int s3c2410_dma_getposition(unsigned int channel,
+			    dma_addr_t *src, dma_addr_t *dst)
+{
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+	WARN_ON(!chan);
+	if (!chan)
+		return -EINVAL;
+
+	if (src != NULL)
+		*src = readl(chan->regs + PL080_CH_SRC_ADDR);
+
+	if (dst != NULL)
+		*dst = readl(chan->regs + PL080_CH_DST_ADDR);
+
+	return 0;
+}
+EXPORT_SYMBOL(s3c2410_dma_getposition);
+
+/* s3c2410_request_dma
+ *
+ * get control of an dma channel
+*/
+
+int s3c2410_dma_request(unsigned int channel,
+			struct s3c2410_dma_client *client,
+			void *dev)
+{
+	struct s3c2410_dma_chan *chan;
+	unsigned long flags;
+
+	pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
+		 channel, client->name, dev);
+
+	local_irq_save(flags);
+
+	chan = s3c64xx_dma_map_channel(channel);
+	if (chan == NULL) {
+		local_irq_restore(flags);
+		return -EBUSY;
+	}
+
+	dbg_showchan(chan);
+
+	chan->client = client;
+	chan->in_use = 1;
+	chan->peripheral = channel;
+
+	local_irq_restore(flags);
+
+	/* need to setup */
+
+	pr_debug("%s: channel initialised, %p\n", __func__, chan);
+
+	return chan->number | DMACH_LOW_LEVEL;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_request);
+
+/* s3c2410_dma_free
+ *
+ * release the given channel back to the system, will stop and flush
+ * any outstanding transfers, and ensure the channel is ready for the
+ * next claimant.
+ *
+ * Note, although a warning is currently printed if the freeing client
+ * info is not the same as the registrant's client info, the free is still
+ * allowed to go through.
+*/
+
+int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client)
+{
+	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+	unsigned long flags;
+
+	if (chan == NULL)
+		return -EINVAL;
+
+	local_irq_save(flags);
+
+	if (chan->client != client) {
+		printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
+		       channel, chan->client, client);
+	}
+
+	/* sort out stopping and freeing the channel */
+
+
+	chan->client = NULL;
+	chan->in_use = 0;
+
+	if (!(channel & DMACH_LOW_LEVEL))
+		s3c_dma_chan_map[channel] = NULL;
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_free);
+
+
+static void s3c64xx_dma_tcirq(struct s3c64xx_dmac *dmac, int offs)
+{
+	struct s3c2410_dma_chan *chan = dmac->channels + offs;
+
+	/* note, we currently do not bother to work out which buffer
+	 * or buffers have been completed since the last tc-irq. */
+
+	if (chan->callback_fn)
+		(chan->callback_fn)(chan, chan->curr->pw, 0, S3C2410_RES_OK);
+}
+
+static void s3c64xx_dma_errirq(struct s3c64xx_dmac *dmac, int offs)
+{
+	printk(KERN_DEBUG "%s: offs %d\n", __func__, offs);
+}
+
+static irqreturn_t s3c64xx_dma_irq(int irq, void *pw)
+{
+	struct s3c64xx_dmac *dmac = pw;
+	u32 tcstat, errstat;
+	u32 bit;
+	int offs;
+
+	tcstat = readl(dmac->regs + PL080_TC_STATUS);
+	errstat = readl(dmac->regs + PL080_ERR_STATUS);
+
+	for (offs = 0, bit = 1; offs < 8; offs++, bit <<= 1) {
+		if (tcstat & bit) {
+			writel(bit, dmac->regs + PL080_TC_CLEAR);
+			s3c64xx_dma_tcirq(dmac, offs);
+		}
+
+		if (errstat & bit) {
+			s3c64xx_dma_errirq(dmac, offs);
+			writel(bit, dmac->regs + PL080_ERR_CLEAR);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct sysdev_class dma_sysclass = {
+	.name		= "s3c64xx-dma",
+};
+
+static int s3c64xx_dma_init1(int chno, enum dma_ch chbase,
+			     int irq, unsigned int base)
+{
+	struct s3c2410_dma_chan *chptr = &s3c2410_chans[chno];
+	struct s3c64xx_dmac *dmac;
+	char clkname[16];
+	void __iomem *regs;
+	void __iomem *regptr;
+	int err, ch;
+
+	dmac = kzalloc(sizeof(struct s3c64xx_dmac), GFP_KERNEL);
+	if (!dmac) {
+		printk(KERN_ERR "%s: failed to alloc mem\n", __func__);
+		return -ENOMEM;
+	}
+
+	dmac->sysdev.id = chno / 8;
+	dmac->sysdev.cls = &dma_sysclass;
+
+	err = sysdev_register(&dmac->sysdev);
+	if (err) {
+		printk(KERN_ERR "%s: failed to register sysdevice\n", __func__);
+		goto err_alloc;
+	}
+
+	regs = ioremap(base, 0x200);
+	if (!regs) {
+		printk(KERN_ERR "%s: failed to ioremap()\n", __func__);
+		err = -ENXIO;
+		goto err_dev;
+	}
+
+	snprintf(clkname, sizeof(clkname), "dma%d", dmac->sysdev.id);
+
+	dmac->clk = clk_get(NULL, clkname);
+	if (IS_ERR(dmac->clk)) {
+		printk(KERN_ERR "%s: failed to get clock %s\n", __func__, clkname);
+		err = PTR_ERR(dmac->clk);
+		goto err_map;
+	}
+
+	clk_enable(dmac->clk);
+
+	dmac->regs = regs;
+	dmac->chanbase = chbase;
+	dmac->channels = chptr;
+
+	err = request_irq(irq, s3c64xx_dma_irq, 0, "DMA", dmac);
+	if (err < 0) {
+		printk(KERN_ERR "%s: failed to get irq\n", __func__);
+		goto err_clk;
+	}
+
+	regptr = regs + PL080_Cx_BASE(0);
+
+	for (ch = 0; ch < 8; ch++, chno++, chptr++) {
+		printk(KERN_INFO "%s: registering DMA %d (%p)\n",
+		       __func__, chno, regptr);
+
+		chptr->bit = 1 << ch;
+		chptr->number = chno;
+		chptr->dmac = dmac;
+		chptr->regs = regptr;
+		regptr += PL008_Cx_STRIDE;
+	}
+
+	/* for the moment, permanently enable the controller */
+	writel(PL080_CONFIG_ENABLE, regs + PL080_CONFIG);
+
+	printk(KERN_INFO "PL080: IRQ %d, at %p\n", irq, regs);
+
+	return 0;
+
+err_clk:
+	clk_disable(dmac->clk);
+	clk_put(dmac->clk);
+err_map:
+	iounmap(regs);
+err_dev:
+	sysdev_unregister(&dmac->sysdev);
+err_alloc:
+	kfree(dmac);
+	return err;
+}
+
+static int __init s3c64xx_dma_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "%s: Registering DMA channels\n", __func__);
+
+	dma_pool = dma_pool_create("DMA-LLI", NULL, 32, 16, 0);
+	if (!dma_pool) {
+		printk(KERN_ERR "%s: failed to create pool\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret = sysdev_class_register(&dma_sysclass);
+	if (ret) {
+		printk(KERN_ERR "%s: failed to create sysclass\n", __func__);
+		return -ENOMEM;
+	}
+
+	/* Set all DMA configuration to be DMA, not SDMA */
+	writel(0xffffff, S3C_SYSREG(0x110));
+
+	/* Register standard DMA controlers */
+	s3c64xx_dma_init1(0, DMACH_UART0, IRQ_DMA0, 0x75000000);
+	s3c64xx_dma_init1(8, DMACH_PCM1_TX, IRQ_DMA1, 0x75100000);
+
+	return 0;
+}
+
+arch_initcall(s3c64xx_dma_init);
diff --git a/arch/arm/plat-s3c64xx/gpiolib.c b/arch/arm/plat-s3c64xx/gpiolib.c
index 78ee52c..da7b60e 100644
--- a/arch/arm/plat-s3c64xx/gpiolib.c
+++ b/arch/arm/plat-s3c64xx/gpiolib.c
@@ -385,12 +385,19 @@
 {
 	chip->chip.direction_input = s3c64xx_gpiolib_4bit_input;
 	chip->chip.direction_output = s3c64xx_gpiolib_4bit_output;
+	chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
 }
 
 static __init void s3c64xx_gpiolib_add_4bit2(struct s3c_gpio_chip *chip)
 {
 	chip->chip.direction_input = s3c64xx_gpiolib_4bit2_input;
 	chip->chip.direction_output = s3c64xx_gpiolib_4bit2_output;
+	chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
+}
+
+static __init void s3c64xx_gpiolib_add_2bit(struct s3c_gpio_chip *chip)
+{
+	chip->pm = __gpio_pm(&s3c_gpio_pm_2bit);
 }
 
 static __init void s3c64xx_gpiolib_add(struct s3c_gpio_chip *chips,
@@ -412,7 +419,8 @@
 	s3c64xx_gpiolib_add(gpio_4bit2, ARRAY_SIZE(gpio_4bit2),
 			    s3c64xx_gpiolib_add_4bit2);
 
-	s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit), NULL);
+	s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit),
+			    s3c64xx_gpiolib_add_2bit);
 
 	return 0;
 }
diff --git a/arch/arm/plat-s3c64xx/include/plat/dma-plat.h b/arch/arm/plat-s3c64xx/include/plat/dma-plat.h
new file mode 100644
index 0000000..0c30dd9
--- /dev/null
+++ b/arch/arm/plat-s3c64xx/include/plat/dma-plat.h
@@ -0,0 +1,70 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/dma-plat.h
+ *
+ * Copyright 2009 Openmoko, Inc.
+ * Copyright 2009 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX DMA core
+ *
+ * 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 DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */
+
+struct s3c64xx_dma_buff;
+
+/** s3c64xx_dma_buff - S3C64XX DMA buffer descriptor
+ * @next: Pointer to next buffer in queue or ring.
+ * @pw: Client provided identifier
+ * @lli: Pointer to hardware descriptor this buffer is associated with.
+ * @lli_dma: Hardare address of the descriptor.
+ */
+struct s3c64xx_dma_buff {
+	struct s3c64xx_dma_buff *next;
+
+	void			*pw;
+	struct pl080_lli	*lli;
+	dma_addr_t		 lli_dma;
+};
+
+struct s3c64xx_dmac;
+
+struct s3c2410_dma_chan {
+	unsigned char		 number;      /* number of this dma channel */
+	unsigned char		 in_use;      /* channel allocated */
+	unsigned char		 bit;	      /* bit for enable/disable/etc */
+	unsigned char		 hw_width;
+	unsigned char		 peripheral;
+
+	unsigned int		 flags;
+	enum s3c2410_dmasrc	 source;
+
+
+	dma_addr_t		dev_addr;
+
+	struct s3c2410_dma_client *client;
+	struct s3c64xx_dmac	*dmac;		/* pointer to controller */
+
+	void __iomem		*regs;
+
+	/* cdriver callbacks */
+	s3c2410_dma_cbfn_t	 callback_fn;	/* buffer done callback */
+	s3c2410_dma_opfn_t	 op_fn;		/* channel op callback */
+
+	/* buffer list and information */
+	struct s3c64xx_dma_buff	*curr;		/* current dma buffer */
+	struct s3c64xx_dma_buff	*next;		/* next buffer to load */
+	struct s3c64xx_dma_buff	*end;		/* end of queue */
+
+	/* note, when channel is running in circular mode, curr is the
+	 * first buffer enqueued, end is the last and curr is where the
+	 * last buffer-done event is set-at. The buffers are not freed
+	 * and the last buffer hardware descriptor points back to the
+	 * first.
+	 */
+};
+
+#include <plat/dma-core.h>
diff --git a/arch/arm/plat-s3c64xx/include/plat/irqs.h b/arch/arm/plat-s3c64xx/include/plat/irqs.h
index f865bf4..743a700 100644
--- a/arch/arm/plat-s3c64xx/include/plat/irqs.h
+++ b/arch/arm/plat-s3c64xx/include/plat/irqs.h
@@ -157,6 +157,7 @@
 
 #define S3C_EINT(x)		((x) + S3C_IRQ_EINT_BASE)
 #define IRQ_EINT(x)		S3C_EINT(x)
+#define IRQ_EINT_BIT(x)		((x) - S3C_EINT(0))
 
 /* Next the external interrupt groups. These are similar to the IRQ_EINT(x)
  * that they are sourced from the GPIO pins but with a different scheme for
diff --git a/arch/arm/plat-s3c64xx/include/plat/pm-core.h b/arch/arm/plat-s3c64xx/include/plat/pm-core.h
new file mode 100644
index 0000000..d347de3
--- /dev/null
+++ b/arch/arm/plat-s3c64xx/include/plat/pm-core.h
@@ -0,0 +1,98 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/pm-core.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX - PM core support for arch/arm/plat-s3c/pm.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
+ * published by the Free Software Foundation.
+ */
+
+#include <plat/regs-gpio.h>
+
+static inline void s3c_pm_debug_init_uart(void)
+{
+	u32 tmp = __raw_readl(S3C_PCLK_GATE);
+
+	/* As a note, since the S3C64XX UARTs generally have multiple
+	 * clock sources, we simply enable PCLK at the moment and hope
+	 * that the resume settings for the UART are suitable for the
+	 * use with PCLK.
+	 */
+
+	tmp |= S3C_CLKCON_PCLK_UART0;
+	tmp |= S3C_CLKCON_PCLK_UART1;
+	tmp |= S3C_CLKCON_PCLK_UART2;
+	tmp |= S3C_CLKCON_PCLK_UART3;
+
+	__raw_writel(tmp, S3C_PCLK_GATE);
+	udelay(10);
+}
+
+static inline void s3c_pm_arch_prepare_irqs(void)
+{
+	/* VIC should have already been taken care of */
+
+	/* clear any pending EINT0 interrupts */
+	__raw_writel(__raw_readl(S3C64XX_EINT0PEND), S3C64XX_EINT0PEND);
+}
+
+static inline void s3c_pm_arch_stop_clocks(void)
+{
+}
+
+static inline void s3c_pm_arch_show_resume_irqs(void)
+{
+}
+
+/* make these defines, we currently do not have any need to change
+ * the IRQ wake controls depending on the CPU we are running on */
+
+#define s3c_irqwake_eintallow	((1 << 28) - 1)
+#define s3c_irqwake_intallow	(0)
+
+static inline void s3c_pm_arch_update_uart(void __iomem *regs,
+					   struct pm_uart_save *save)
+{
+	u32 ucon = __raw_readl(regs + S3C2410_UCON);
+	u32 ucon_clk = ucon & S3C6400_UCON_CLKMASK;
+	u32 save_clk = save->ucon & S3C6400_UCON_CLKMASK;
+	u32 new_ucon;
+	u32 delta;
+
+	/* S3C64XX UART blocks only support level interrupts, so ensure that
+	 * when we restore unused UART blocks we force the level interrupt
+	 * settigs. */
+	save->ucon |= S3C2410_UCON_TXILEVEL | S3C2410_UCON_RXILEVEL;
+
+	/* We have a constraint on changing the clock type of the UART
+	 * between UCLKx and PCLK, so ensure that when we restore UCON
+	 * that the CLK field is correctly modified if the bootloader
+	 * has changed anything.
+	 */
+	if (ucon_clk != save_clk) {
+		new_ucon = save->ucon;
+		delta = ucon_clk ^ save_clk;
+
+		/* change from UCLKx => wrong PCLK,
+		 * either UCLK can be tested for by a bit-test
+		 * with UCLK0 */
+		if (ucon_clk & S3C6400_UCON_UCLK0 &&
+		    !(save_clk & S3C6400_UCON_UCLK0) &&
+		    delta & S3C6400_UCON_PCLK2) {
+			new_ucon &= ~S3C6400_UCON_UCLK0;
+		} else if (delta == S3C6400_UCON_PCLK2) {
+			/* as an precaution, don't change from
+			 * PCLK2 => PCLK or vice-versa */
+			new_ucon ^= S3C6400_UCON_PCLK2;
+		}
+
+		S3C_PMDBG("ucon change %04x => %04x (save=%04x)\n",
+			  ucon, new_ucon, save->ucon);
+		save->ucon = new_ucon;
+	}
+}
diff --git a/arch/arm/plat-s3c64xx/include/plat/regs-clock.h b/arch/arm/plat-s3c64xx/include/plat/regs-clock.h
index b1082c1..52836d4 100644
--- a/arch/arm/plat-s3c64xx/include/plat/regs-clock.h
+++ b/arch/arm/plat-s3c64xx/include/plat/regs-clock.h
@@ -32,6 +32,7 @@
 #define S3C_HCLK_GATE		S3C_CLKREG(0x30)
 #define S3C_PCLK_GATE		S3C_CLKREG(0x34)
 #define S3C_SCLK_GATE		S3C_CLKREG(0x38)
+#define S3C_MEM0_GATE		S3C_CLKREG(0x3C)
 
 /* CLKDIV0 */
 #define S3C6400_CLKDIV0_MFC_MASK	(0xf << 28)
diff --git a/arch/arm/plat-s3c64xx/include/plat/s3c6400.h b/arch/arm/plat-s3c64xx/include/plat/s3c6400.h
index 571eaa2..11f2e1e 100644
--- a/arch/arm/plat-s3c64xx/include/plat/s3c6400.h
+++ b/arch/arm/plat-s3c64xx/include/plat/s3c6400.h
@@ -15,12 +15,13 @@
 /* Common init code for S3C6400 related SoCs */
 
 extern void s3c6400_common_init_uarts(struct s3c2410_uartcfg *cfg, int no);
-extern void s3c6400_register_clocks(void);
+extern void s3c6400_register_clocks(unsigned armclk_divlimit);
 extern void s3c6400_setup_clocks(void);
 
 #ifdef CONFIG_CPU_S3C6400
 
 extern  int s3c6400_init(void);
+extern void s3c6400_init_irq(void);
 extern void s3c6400_map_io(void);
 extern void s3c6400_init_clocks(int xtal);
 
diff --git a/arch/arm/plat-s3c64xx/irq-eint.c b/arch/arm/plat-s3c64xx/irq-eint.c
index 47e5155..f81b7b8 100644
--- a/arch/arm/plat-s3c64xx/irq-eint.c
+++ b/arch/arm/plat-s3c64xx/irq-eint.c
@@ -14,6 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/sysdev.h>
 #include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/io.h>
@@ -26,6 +27,7 @@
 
 #include <mach/map.h>
 #include <plat/cpu.h>
+#include <plat/pm.h>
 
 #define eint_offset(irq)	((irq) - IRQ_EINT(0))
 #define eint_irq_to_bit(irq)	(1 << eint_offset(irq))
@@ -134,6 +136,7 @@
 	.mask_ack	= s3c_irq_eint_maskack,
 	.ack		= s3c_irq_eint_ack,
 	.set_type	= s3c_irq_eint_set_type,
+	.set_wake	= s3c_irqext_wake,
 };
 
 /* s3c_irq_demux_eint
diff --git a/arch/arm/plat-s3c64xx/irq-pm.c b/arch/arm/plat-s3c64xx/irq-pm.c
new file mode 100644
index 0000000..ca523b5
--- /dev/null
+++ b/arch/arm/plat-s3c64xx/irq-pm.c
@@ -0,0 +1,111 @@
+/* arch/arm/plat-s3c64xx/irq-pm.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX - Interrupt handling Power Management
+ *
+ * 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/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/serial_core.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+
+#include <plat/regs-serial.h>
+#include <plat/regs-timer.h>
+#include <plat/regs-gpio.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+
+/* We handled all the IRQ types in this code, to save having to make several
+ * small files to handle each different type separately. Having the EINT_GRP
+ * code here shouldn't be as much bloat as the IRQ table space needed when
+ * they are enabled. The added benefit is we ensure that these registers are
+ * in the same state as we suspended.
+ */
+
+static struct sleep_save irq_save[] = {
+	SAVE_ITEM(S3C64XX_PRIORITY),
+	SAVE_ITEM(S3C64XX_EINT0CON0),
+	SAVE_ITEM(S3C64XX_EINT0CON1),
+	SAVE_ITEM(S3C64XX_EINT0FLTCON0),
+	SAVE_ITEM(S3C64XX_EINT0FLTCON1),
+	SAVE_ITEM(S3C64XX_EINT0FLTCON2),
+	SAVE_ITEM(S3C64XX_EINT0FLTCON3),
+	SAVE_ITEM(S3C64XX_EINT0MASK),
+	SAVE_ITEM(S3C64XX_TINT_CSTAT),
+};
+
+static struct irq_grp_save {
+	u32	fltcon;
+	u32	con;
+	u32	mask;
+} eint_grp_save[5];
+
+static u32 irq_uart_mask[CONFIG_SERIAL_SAMSUNG_UARTS];
+
+static int s3c64xx_irq_pm_suspend(struct sys_device *dev, pm_message_t state)
+{
+	struct irq_grp_save *grp = eint_grp_save;
+	int i;
+
+	S3C_PMDBG("%s: suspending IRQs\n", __func__);
+
+	s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
+
+	for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++)
+		irq_uart_mask[i] = __raw_readl(S3C_VA_UARTx(i) + S3C64XX_UINTM);
+
+	for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) {
+		grp->con = __raw_readl(S3C64XX_EINT12CON + (i * 4));
+		grp->mask = __raw_readl(S3C64XX_EINT12MASK + (i * 4));
+		grp->fltcon = __raw_readl(S3C64XX_EINT12FLTCON + (i * 4));
+	}
+
+	return 0;
+}
+
+static int s3c64xx_irq_pm_resume(struct sys_device *dev)
+{
+	struct irq_grp_save *grp = eint_grp_save;
+	int i;
+
+	S3C_PMDBG("%s: resuming IRQs\n", __func__);
+
+	s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
+
+	for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++)
+		__raw_writel(irq_uart_mask[i], S3C_VA_UARTx(i) + S3C64XX_UINTM);
+
+	for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) {
+		__raw_writel(grp->con, S3C64XX_EINT12CON + (i * 4));
+		__raw_writel(grp->mask, S3C64XX_EINT12MASK + (i * 4));
+		__raw_writel(grp->fltcon, S3C64XX_EINT12FLTCON + (i * 4));
+	}
+
+	S3C_PMDBG("%s: IRQ configuration restored\n", __func__);
+	return 0;
+}
+
+static struct sysdev_driver s3c64xx_irq_driver = {
+	.suspend = s3c64xx_irq_pm_suspend,
+	.resume	 = s3c64xx_irq_pm_resume,
+};
+
+static int __init s3c64xx_irq_pm_init(void)
+{
+	return sysdev_driver_register(&s3c64xx_sysclass, &s3c64xx_irq_driver);
+}
+
+arch_initcall(s3c64xx_irq_pm_init);
+
diff --git a/arch/arm/plat-s3c64xx/irq.c b/arch/arm/plat-s3c64xx/irq.c
index f22edf7..8dc5b6d 100644
--- a/arch/arm/plat-s3c64xx/irq.c
+++ b/arch/arm/plat-s3c64xx/irq.c
@@ -14,12 +14,14 @@
 
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/serial_core.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 
 #include <asm/hardware/vic.h>
 
 #include <mach/map.h>
+#include <plat/regs-serial.h>
 #include <plat/regs-timer.h>
 #include <plat/cpu.h>
 
@@ -135,9 +137,6 @@
 }
 
 /* UART interrupt registers, not worth adding to seperate include header */
-#define S3C64XX_UINTP	0x30
-#define S3C64XX_UINTSP	0x34
-#define S3C64XX_UINTM	0x38
 
 static void s3c_irq_uart_mask(unsigned int irq)
 {
@@ -233,8 +232,8 @@
 	printk(KERN_DEBUG "%s: initialising interrupts\n", __func__);
 
 	/* initialise the pair of VICs */
-	vic_init(S3C_VA_VIC0, S3C_VIC0_BASE, vic0_valid);
-	vic_init(S3C_VA_VIC1, S3C_VIC1_BASE, vic1_valid);
+	vic_init(S3C_VA_VIC0, S3C_VIC0_BASE, vic0_valid, 0);
+	vic_init(S3C_VA_VIC1, S3C_VIC1_BASE, vic1_valid, 0);
 
 	/* add the timer sub-irqs */
 
diff --git a/arch/arm/plat-s3c64xx/pm.c b/arch/arm/plat-s3c64xx/pm.c
new file mode 100644
index 0000000..07a6516
--- /dev/null
+++ b/arch/arm/plat-s3c64xx/pm.c
@@ -0,0 +1,175 @@
+/* linux/arch/arm/plat-s3c64xx/pm.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX CPU PM 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/init.h>
+#include <linux/suspend.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+
+#include <plat/pm.h>
+#include <plat/regs-sys.h>
+#include <plat/regs-gpio.h>
+#include <plat/regs-clock.h>
+#include <plat/regs-syscon-power.h>
+#include <plat/regs-gpio-memport.h>
+
+#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
+#include <plat/gpio-bank-n.h>
+
+void s3c_pm_debug_smdkled(u32 set, u32 clear)
+{
+	unsigned long flags;
+	u32 reg;
+
+	local_irq_save(flags);
+	reg = __raw_readl(S3C64XX_GPNCON);
+	reg &= ~(S3C64XX_GPN_CONMASK(12) | S3C64XX_GPN_CONMASK(13) |
+		 S3C64XX_GPN_CONMASK(14) | S3C64XX_GPN_CONMASK(15));
+	reg |= S3C64XX_GPN_OUTPUT(12) | S3C64XX_GPN_OUTPUT(13) |
+	       S3C64XX_GPN_OUTPUT(14) | S3C64XX_GPN_OUTPUT(15);
+	__raw_writel(reg, S3C64XX_GPNCON);
+
+	reg = __raw_readl(S3C64XX_GPNDAT);
+	reg &= ~(clear << 12);
+	reg |= set << 12;
+	__raw_writel(reg, S3C64XX_GPNDAT);
+
+	local_irq_restore(flags);
+}
+#endif
+
+static struct sleep_save core_save[] = {
+	SAVE_ITEM(S3C_APLL_LOCK),
+	SAVE_ITEM(S3C_MPLL_LOCK),
+	SAVE_ITEM(S3C_EPLL_LOCK),
+	SAVE_ITEM(S3C_CLK_SRC),
+	SAVE_ITEM(S3C_CLK_DIV0),
+	SAVE_ITEM(S3C_CLK_DIV1),
+	SAVE_ITEM(S3C_CLK_DIV2),
+	SAVE_ITEM(S3C_CLK_OUT),
+	SAVE_ITEM(S3C_HCLK_GATE),
+	SAVE_ITEM(S3C_PCLK_GATE),
+	SAVE_ITEM(S3C_SCLK_GATE),
+	SAVE_ITEM(S3C_MEM0_GATE),
+
+	SAVE_ITEM(S3C_EPLL_CON1),
+	SAVE_ITEM(S3C_EPLL_CON0),
+
+	SAVE_ITEM(S3C64XX_MEM0DRVCON),
+	SAVE_ITEM(S3C64XX_MEM1DRVCON),
+
+#ifndef CONFIG_CPU_FREQ
+	SAVE_ITEM(S3C_APLL_CON),
+	SAVE_ITEM(S3C_MPLL_CON),
+#endif
+};
+
+static struct sleep_save misc_save[] = {
+	SAVE_ITEM(S3C64XX_AHB_CON0),
+	SAVE_ITEM(S3C64XX_AHB_CON1),
+	SAVE_ITEM(S3C64XX_AHB_CON2),
+	
+	SAVE_ITEM(S3C64XX_SPCON),
+
+	SAVE_ITEM(S3C64XX_MEM0CONSTOP),
+	SAVE_ITEM(S3C64XX_MEM1CONSTOP),
+	SAVE_ITEM(S3C64XX_MEM0CONSLP0),
+	SAVE_ITEM(S3C64XX_MEM0CONSLP1),
+	SAVE_ITEM(S3C64XX_MEM1CONSLP),
+};
+
+void s3c_pm_configure_extint(void)
+{
+	__raw_writel(s3c_irqwake_eintmask, S3C64XX_EINT_MASK);
+}
+
+void s3c_pm_restore_core(void)
+{
+	__raw_writel(0, S3C64XX_EINT_MASK);
+
+	s3c_pm_debug_smdkled(1 << 2, 0);
+
+	s3c_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
+	s3c_pm_do_restore(misc_save, ARRAY_SIZE(misc_save));
+}
+
+void s3c_pm_save_core(void)
+{
+	s3c_pm_do_save(misc_save, ARRAY_SIZE(misc_save));
+	s3c_pm_do_save(core_save, ARRAY_SIZE(core_save));
+}
+
+/* since both s3c6400 and s3c6410 share the same sleep pm calls, we
+ * put the per-cpu code in here until any new cpu comes along and changes
+ * this.
+ */
+
+#include <plat/regs-gpio.h>
+
+static void s3c64xx_cpu_suspend(void)
+{
+	unsigned long tmp;
+
+	/* set our standby method to sleep */
+
+	tmp = __raw_readl(S3C64XX_PWR_CFG);
+	tmp &= ~S3C64XX_PWRCFG_CFG_WFI_MASK;
+	tmp |= S3C64XX_PWRCFG_CFG_WFI_SLEEP;
+	__raw_writel(tmp, S3C64XX_PWR_CFG);
+
+	/* clear any old wakeup */
+
+	__raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT),
+		     S3C64XX_WAKEUP_STAT);
+
+	/* set the LED state to 0110 over sleep */
+	s3c_pm_debug_smdkled(3 << 1, 0xf);
+
+	/* issue the standby signal into the pm unit. Note, we
+	 * issue a write-buffer drain just in case */
+
+	tmp = 0;
+
+	asm("b 1f\n\t"
+	    ".align 5\n\t"
+	    "1:\n\t"
+	    "mcr p15, 0, %0, c7, c10, 5\n\t"
+	    "mcr p15, 0, %0, c7, c10, 4\n\t"
+	    "mcr p15, 0, %0, c7, c0, 4" :: "r" (tmp));
+
+	/* we should never get past here */
+
+	panic("sleep resumed to originator?");
+}
+
+static void s3c64xx_pm_prepare(void)
+{
+	/* store address of resume. */
+	__raw_writel(virt_to_phys(s3c_cpu_resume), S3C64XX_INFORM0);
+
+	/* ensure previous wakeup state is cleared before sleeping */
+	__raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT), S3C64XX_WAKEUP_STAT);
+}
+
+static int s3c64xx_pm_init(void)
+{
+	pm_cpu_prep = s3c64xx_pm_prepare;
+	pm_cpu_sleep = s3c64xx_cpu_suspend;
+	pm_uart_udivslot = 1;
+	return 0;
+}
+
+arch_initcall(s3c64xx_pm_init);
diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c
index 05b1752..1debc1f 100644
--- a/arch/arm/plat-s3c64xx/s3c6400-clock.c
+++ b/arch/arm/plat-s3c64xx/s3c6400-clock.c
@@ -133,6 +133,65 @@
 	.sources	= &clk_src_mpll,
 };
 
+static unsigned int armclk_mask;
+
+static unsigned long s3c64xx_clk_arm_get_rate(struct clk *clk)
+{
+	unsigned long rate = clk_get_rate(clk->parent);
+	u32 clkdiv;
+
+	/* divisor mask starts at bit0, so no need to shift */
+	clkdiv = __raw_readl(S3C_CLK_DIV0) & armclk_mask;
+
+	return rate / (clkdiv + 1);
+}
+
+static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk,
+						unsigned long rate)
+{
+	unsigned long parent = clk_get_rate(clk->parent);
+	u32 div;
+
+	if (parent < rate)
+		return rate;
+
+	div = (parent / rate) - 1;
+	if (div > armclk_mask)
+		div = armclk_mask;
+
+	return parent / (div + 1);
+}
+
+static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long parent = clk_get_rate(clk->parent);
+	u32 div;
+	u32 val;
+
+	if (rate < parent / (armclk_mask + 1))
+		return -EINVAL;
+
+	rate = clk_round_rate(clk, rate);
+	div = clk_get_rate(clk->parent) / rate;
+
+	val = __raw_readl(S3C_CLK_DIV0);
+	val &= armclk_mask;
+	val |= (div - 1);
+	__raw_writel(val, S3C_CLK_DIV0);
+
+	return 0;
+
+}
+
+static struct clk clk_arm = {
+	.name		= "armclk",
+	.id		= -1,
+	.parent		= &clk_mout_apll.clk,
+	.get_rate	= s3c64xx_clk_arm_get_rate,
+	.set_rate	= s3c64xx_clk_arm_set_rate,
+	.round_rate	= s3c64xx_clk_arm_round_rate,
+};
+
 static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk)
 {
 	unsigned long rate = clk_get_rate(clk->parent);
@@ -520,6 +579,33 @@
 	.reg_divider	= S3C_CLK_DIV2,
 };
 
+static struct clk *clkset_camif_list[] = {
+	&clk_h2,
+};
+
+static struct clk_sources clkset_camif = {
+	.sources	= clkset_camif_list,
+	.nr_sources	= ARRAY_SIZE(clkset_camif_list),
+};
+
+static struct clksrc_clk clk_camif = {
+	.clk	= {
+		.name		= "camera",
+		.id		= -1,
+		.ctrlbit        = S3C_CLKCON_SCLK_CAM,
+		.enable		= s3c64xx_sclk_ctrl,
+		.set_parent	= s3c64xx_setparent_clksrc,
+		.get_rate	= s3c64xx_getrate_clksrc,
+		.set_rate	= s3c64xx_setrate_clksrc,
+		.round_rate	= s3c64xx_roundrate_clksrc,
+	},
+	.shift		= 0,
+	.mask		= 0,
+	.sources	= &clkset_camif,
+	.divider_shift	= S3C6400_CLKDIV0_CAM_SHIFT,
+	.reg_divider	= S3C_CLK_DIV0,
+};
+
 /* Clock initialisation code */
 
 static struct clksrc_clk *init_parents[] = {
@@ -536,6 +622,7 @@
 	&clk_audio0,
 	&clk_audio1,
 	&clk_irda,
+	&clk_camif,
 };
 
 static void __init_or_cpufreq s3c6400_set_clksrc(struct clksrc_clk *clk)
@@ -608,6 +695,7 @@
 	clk_fout_epll.rate = epll;
 	clk_fout_apll.rate = apll;
 
+	clk_h2.rate = hclk2;
 	clk_h.rate = hclk;
 	clk_p.rate = pclk;
 	clk_f.rate = fclk;
@@ -635,14 +723,30 @@
 	&clk_audio0.clk,
 	&clk_audio1.clk,
 	&clk_irda.clk,
+	&clk_camif.clk,
+	&clk_arm,
 };
 
-void __init s3c6400_register_clocks(void)
+/**
+ * s3c6400_register_clocks - register clocks for s3c6400 and above
+ * @armclk_divlimit: Divisor mask for ARMCLK
+ *
+ * Register the clocks for the S3C6400 and above SoC range, such
+ * as ARMCLK and the clocks which have divider chains attached.
+ *
+ * This call does not setup the clocks, which is left to the
+ * s3c6400_setup_clocks() call which may be needed by the cpufreq
+ * or resume code to re-set the clocks if the bootloader has changed
+ * them.
+ */
+void __init s3c6400_register_clocks(unsigned armclk_divlimit)
 {
 	struct clk *clkp;
 	int ret;
 	int ptr;
 
+	armclk_mask = armclk_divlimit;
+
 	for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
 		clkp = clks[ptr];
 		ret = s3c24xx_register_clock(clkp);
diff --git a/arch/arm/plat-s3c64xx/setup-sdhci-gpio.c b/arch/arm/plat-s3c64xx/setup-sdhci-gpio.c
new file mode 100644
index 0000000..5417123
--- /dev/null
+++ b/arch/arm/plat-s3c64xx/setup-sdhci-gpio.c
@@ -0,0 +1,55 @@
+/* linux/arch/arm/plat-s3c64xx/setup-sdhci-gpio.c
+ *
+ * Copyright 2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX - Helper functions for setting up SDHCI device(s) GPIO (HSMMC)
+ *
+ * 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/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/gpio.h>
+#include <plat/gpio-cfg.h>
+
+void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
+{
+	unsigned int gpio;
+	unsigned int end;
+
+	end = S3C64XX_GPG(2 + width);
+
+	/* Set all the necessary GPG pins to special-function 0 */
+	for (gpio = S3C64XX_GPG(0); gpio < end; gpio++) {
+		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+	}
+
+	s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
+	s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(2));
+}
+
+void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
+{
+	unsigned int gpio;
+	unsigned int end;
+
+	end = S3C64XX_GPH(2 + width);
+
+	/* Set all the necessary GPG pins to special-function 0 */
+	for (gpio = S3C64XX_GPH(0); gpio < end; gpio++) {
+		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+	}
+
+	s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
+	s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(3));
+}
diff --git a/arch/arm/plat-s3c64xx/sleep.S b/arch/arm/plat-s3c64xx/sleep.S
new file mode 100644
index 0000000..8e71fe9
--- /dev/null
+++ b/arch/arm/plat-s3c64xx/sleep.S
@@ -0,0 +1,144 @@
+/* linux/0arch/arm/plat-s3c64xx/sleep.S
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX CPU sleep 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
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/map.h>
+
+#undef S3C64XX_VA_GPIO
+#define S3C64XX_VA_GPIO (0x0)
+
+#include <plat/regs-gpio.h>
+#include <plat/gpio-bank-n.h>
+
+#define LL_UART (S3C_PA_UART + (0x400 * CONFIG_S3C_LOWLEVEL_UART_PORT))
+
+	.text
+
+	/* s3c_cpu_save
+	 *
+	 * Save enough processor state to allow the restart of the pm.c
+	 * code after resume.
+	 *
+	 * entry:
+	 *	r0 = pointer to the save block
+	*/
+
+ENTRY(s3c_cpu_save)
+	stmfd	sp!, { r4 - r12, lr }
+
+	mrc	p15, 0, r4, c13, c0, 0	@ FCSE/PID
+	mrc	p15, 0, r5, c3, c0, 0	@ Domain ID
+	mrc	p15, 0, r6, c2, c0, 0	@ Translation Table BASE0
+	mrc	p15, 0, r7, c2, c0, 1	@ Translation Table BASE1
+	mrc	p15, 0, r8, c2, c0, 2	@ Translation Table Control
+	mrc	p15, 0, r9, c1, c0, 0	@ Control register
+	mrc	p15, 0, r10, c1, c0, 1	@ Auxiliary control register
+	mrc	p15, 0, r11, c1, c0, 2	@ Co-processor access controls
+
+	stmia	r0, { r4 - r13 }	@ Save CP registers and SP
+
+	@@ save our state to ram
+	bl	s3c_pm_cb_flushcache
+
+	@@ call final suspend code
+	ldr	r0, =pm_cpu_sleep
+	ldr	pc, [r0]
+	
+	@@ return to the caller, after the MMU is turned on.
+	@@ restore the last bits of the stack and return.
+resume_with_mmu:
+	ldmfd	sp!, { r4 - r12, pc }	@ return, from sp from s3c_cpu_save
+
+	.data
+
+	/* the next bit is code, but it requires easy access to the
+	 * s3c_sleep_save_phys data before the MMU is switched on, so
+	 * we store the code that needs this variable in the .data where
+	 * the value can be written to (the .text segment is RO).
+	*/
+
+	.global	s3c_sleep_save_phys
+s3c_sleep_save_phys:
+	.word	0
+
+	/* Sleep magic, the word before the resume entry point so that the
+	 * bootloader can check for a resumeable image. */
+
+	.word	0x2bedf00d
+
+	/* s3c_cpu_reusme
+	 *
+	 * This is the entry point, stored by whatever method the bootloader
+	 * requires to get the kernel runnign again. This code expects to be
+	 * entered with no caches live and the MMU disabled. It will then
+	 * restore the MMU and other basic CP registers saved and restart
+	 * the kernel C code to finish the resume code.
+	*/
+
+ENTRY(s3c_cpu_resume)
+	msr	cpsr_c, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
+	ldr	r2, =LL_UART		/* for debug */
+
+#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
+	/* Initialise the GPIO state if we are debugging via the SMDK LEDs,
+	 * as the uboot version supplied resets these to inputs during the
+	 * resume checks.
+	*/
+
+	ldr	r3, =S3C64XX_PA_GPIO
+	ldr	r0, [ r3, #S3C64XX_GPNCON ]
+	bic	r0, r0, #(S3C64XX_GPN_CONMASK(12) | S3C64XX_GPN_CONMASK(13) | \
+			  S3C64XX_GPN_CONMASK(14) | S3C64XX_GPN_CONMASK(15))
+	orr	r0, r0, #(S3C64XX_GPN_OUTPUT(12) | S3C64XX_GPN_OUTPUT(13) | \
+			  S3C64XX_GPN_OUTPUT(14) | S3C64XX_GPN_OUTPUT(15))
+	str	r0, [ r3, #S3C64XX_GPNCON ]
+
+	ldr	r0, [ r3, #S3C64XX_GPNDAT ]
+	bic	r0, r0, #0xf << 12			@ GPN12..15
+	orr	r0, r0, #1 << 15			@ GPN15
+	str	r0, [ r3, #S3C64XX_GPNDAT ]
+#endif
+
+	/* __v6_setup from arch/arm/mm/proc-v6.S, ensure that the caches
+	 * are thoroughly cleaned just in case the bootloader didn't do it
+	 * for us. */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0		@ clean+invalidate D cache
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mcr	p15, 0, r0, c7, c15, 0		@ clean+invalidate cache
+	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer
+	@@mcr	p15, 0, r0, c8, c7, 0		@ invalidate I + D TLBs
+	@@mcr	p15, 0, r0, c7, c7, 0		@ Invalidate I + D caches
+
+	ldr	r0, s3c_sleep_save_phys
+	ldmia	r0, { r4 - r13 }
+
+	mcr	p15, 0, r4, c13, c0, 0	@ FCSE/PID
+	mcr	p15, 0, r5, c3, c0, 0	@ Domain ID
+	mcr	p15, 0, r6, c2, c0, 0	@ Translation Table BASE0
+	mcr	p15, 0, r7, c2, c0, 1	@ Translation Table BASE1
+	mcr	p15, 0, r8, c2, c0, 2	@ Translation Table Control
+	mcr	p15, 0, r10, c1, c0, 1	@ Auxiliary control register
+
+	mov	r0, #0			@ restore copro access controls
+	mcr	p15, 0, r11, c1, c0, 2	@ Co-processor access controls
+	mcr 	p15, 0, r0, c7, c5, 4
+
+	ldr	r2, =resume_with_mmu
+	mcr	p15, 0, r9, c1, c0, 0		/* turn mmu back on */
+	nop
+	mov	pc, r2				/* jump back */
+
+	.end
diff --git a/arch/arm/plat-stmp3xxx/Kconfig b/arch/arm/plat-stmp3xxx/Kconfig
new file mode 100644
index 0000000..2cf37c3
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/Kconfig
@@ -0,0 +1,37 @@
+if ARCH_STMP3XXX
+
+menu "Freescale STMP3xxx implementations"
+
+choice
+	prompt "Select STMP3xxx chip family"
+
+config ARCH_STMP37XX
+	bool "Freescale SMTP37xx"
+	select CPU_ARM926T
+	---help---
+	 STMP37xx refers to 3700 through 3769 chips
+
+config ARCH_STMP378X
+	bool "Freescale STMP378x"
+	select CPU_ARM926T
+	---help---
+	 STMP378x refers to 3780 through 3789 chips
+
+endchoice
+
+choice
+	prompt "Select STMP3xxx board type"
+
+config MACH_STMP37XX
+	depends on ARCH_STMP37XX
+	bool "Freescale STMP37xx development board"
+
+config MACH_STMP378X
+	depends on ARCH_STMP378X
+	bool "Freescale STMP378x development board"
+
+endchoice
+
+endmenu
+
+endif
diff --git a/arch/arm/plat-stmp3xxx/Makefile b/arch/arm/plat-stmp3xxx/Makefile
new file mode 100644
index 0000000..31dd518
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the linux kernel.
+#
+# Object file lists.
+obj-y += core.o timer.o irq.o dma.o clock.o pinmux.o devices.o
diff --git a/arch/arm/plat-stmp3xxx/clock.c b/arch/arm/plat-stmp3xxx/clock.c
new file mode 100644
index 0000000..5d2f19a
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/clock.c
@@ -0,0 +1,1135 @@
+/*
+ * Clock manipulation routines for Freescale STMP37XX/STMP378X
+ *
+ * Author: Vitaly Wool <vital@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define DEBUG
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <asm/mach-types.h>
+#include <asm/clkdev.h>
+#include <mach/platform.h>
+#include <mach/regs-clkctrl.h>
+
+#include "clock.h"
+
+static DEFINE_SPINLOCK(clocks_lock);
+
+static struct clk osc_24M;
+static struct clk pll_clk;
+static struct clk cpu_clk;
+static struct clk hclk;
+
+static int propagate_rate(struct clk *);
+
+static inline int clk_is_busy(struct clk *clk)
+{
+	return __raw_readl(clk->busy_reg) & (1 << clk->busy_bit);
+}
+
+static inline int clk_good(struct clk *clk)
+{
+	return clk && !IS_ERR(clk) && clk->ops;
+}
+
+static int std_clk_enable(struct clk *clk)
+{
+	if (clk->enable_reg) {
+		u32 clk_reg = __raw_readl(clk->enable_reg);
+		if (clk->enable_negate)
+			clk_reg &= ~(1 << clk->enable_shift);
+		else
+			clk_reg |= (1 << clk->enable_shift);
+		__raw_writel(clk_reg, clk->enable_reg);
+		if (clk->enable_wait)
+			udelay(clk->enable_wait);
+		return 0;
+	} else
+		return -EINVAL;
+}
+
+static int std_clk_disable(struct clk *clk)
+{
+	if (clk->enable_reg) {
+		u32 clk_reg = __raw_readl(clk->enable_reg);
+		if (clk->enable_negate)
+			clk_reg |= (1 << clk->enable_shift);
+		else
+			clk_reg &= ~(1 << clk->enable_shift);
+		__raw_writel(clk_reg, clk->enable_reg);
+		return 0;
+	} else
+		return -EINVAL;
+}
+
+static int io_set_rate(struct clk *clk, u32 rate)
+{
+	u32 reg_frac, clkctrl_frac;
+	int i, ret = 0, mask = 0x1f;
+
+	clkctrl_frac = (clk->parent->rate * 18 + rate - 1) / rate;
+
+	if (clkctrl_frac < 18 || clkctrl_frac > 35) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	reg_frac = __raw_readl(clk->scale_reg);
+	reg_frac &= ~(mask << clk->scale_shift);
+	__raw_writel(reg_frac | (clkctrl_frac << clk->scale_shift),
+				clk->scale_reg);
+	if (clk->busy_reg) {
+		for (i = 10000; i; i--)
+			if (!clk_is_busy(clk))
+				break;
+		if (!i)
+			ret = -ETIMEDOUT;
+		else
+			ret = 0;
+	}
+out:
+	return ret;
+}
+
+static long io_get_rate(struct clk *clk)
+{
+	long rate = clk->parent->rate * 18;
+	int mask = 0x1f;
+
+	rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
+	clk->rate = rate;
+
+	return rate;
+}
+
+static long per_get_rate(struct clk *clk)
+{
+	long rate = clk->parent->rate;
+	long div;
+	const int mask = 0xff;
+
+	if (clk->enable_reg &&
+			!(__raw_readl(clk->enable_reg) & clk->enable_shift))
+		clk->rate = 0;
+	else {
+		div = (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
+		if (div)
+			rate /= div;
+		clk->rate = rate;
+	}
+
+	return clk->rate;
+}
+
+static int per_set_rate(struct clk *clk, u32 rate)
+{
+	int ret = -EINVAL;
+	int div = (clk->parent->rate + rate - 1) / rate;
+	u32 reg_frac;
+	const int mask = 0xff;
+	int try = 10;
+	int i = -1;
+
+	if (div == 0 || div > mask)
+		goto out;
+
+	reg_frac = __raw_readl(clk->scale_reg);
+	reg_frac &= ~(mask << clk->scale_shift);
+
+	while (try--) {
+		__raw_writel(reg_frac | (div << clk->scale_shift),
+				clk->scale_reg);
+
+		if (clk->busy_reg) {
+			for (i = 10000; i; i--)
+				if (!clk_is_busy(clk))
+					break;
+		}
+		if (i)
+			break;
+	}
+
+	if (!i)
+		ret = -ETIMEDOUT;
+	else
+		ret = 0;
+
+out:
+	if (ret != 0)
+		printk(KERN_ERR "%s: error %d\n", __func__, ret);
+	return ret;
+}
+
+static long lcdif_get_rate(struct clk *clk)
+{
+	long rate = clk->parent->rate;
+	long div;
+	const int mask = 0xff;
+
+	div = (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
+	if (div) {
+		rate /= div;
+		div = (__raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC) &
+			BM_CLKCTRL_FRAC_PIXFRAC) >> BP_CLKCTRL_FRAC_PIXFRAC;
+		rate /= div;
+	}
+	clk->rate = rate;
+
+	return rate;
+}
+
+static int lcdif_set_rate(struct clk *clk, u32 rate)
+{
+	int ret = 0;
+	/*
+	 * On 3700, we can get most timings exact by modifying ref_pix
+	 * and the divider, but keeping the phase timings at 1 (2
+	 * phases per cycle).
+	 *
+	 * ref_pix can be between 480e6*18/35=246.9MHz and 480e6*18/18=480MHz,
+	 * which is between 18/(18*480e6)=2.084ns and 35/(18*480e6)=4.050ns.
+	 *
+	 * ns_cycle >= 2*18e3/(18*480) = 25/6
+	 * ns_cycle <= 2*35e3/(18*480) = 875/108
+	 *
+	 * Multiply the ns_cycle by 'div' to lengthen it until it fits the
+	 * bounds. This is the divider we'll use after ref_pix.
+	 *
+	 * 6 * ns_cycle >= 25 * div
+	 * 108 * ns_cycle <= 875 * div
+	 */
+	u32 ns_cycle = 1000000 / rate;
+	u32 div, reg_val;
+	u32 lowest_result = (u32) -1;
+	u32 lowest_div = 0, lowest_fracdiv = 0;
+
+	for (div = 1; div < 256; ++div) {
+		u32 fracdiv;
+		u32 ps_result;
+		int lower_bound = 6 * ns_cycle >= 25 * div;
+		int upper_bound = 108 * ns_cycle <= 875 * div;
+		if (!lower_bound)
+			break;
+		if (!upper_bound)
+			continue;
+		/*
+		 * Found a matching div. Calculate fractional divider needed,
+		 * rounded up.
+		 */
+		fracdiv = ((clk->parent->rate / 1000 * 18 / 2) *
+				ns_cycle + 1000 * div - 1) /
+				(1000 * div);
+		if (fracdiv < 18 || fracdiv > 35) {
+			ret = -EINVAL;
+			goto out;
+		}
+		/* Calculate the actual cycle time this results in */
+		ps_result = 6250 * div * fracdiv / 27;
+
+		/* Use the fastest result that doesn't break ns_cycle */
+		if (ps_result <= lowest_result) {
+			lowest_result = ps_result;
+			lowest_div = div;
+			lowest_fracdiv = fracdiv;
+		}
+	}
+
+	if (div >= 256 || lowest_result == (u32) -1) {
+		ret = -EINVAL;
+		goto out;
+	}
+	pr_debug("Programming PFD=%u,DIV=%u ref_pix=%uMHz "
+			"PIXCLK=%uMHz cycle=%u.%03uns\n",
+			lowest_fracdiv, lowest_div,
+			480*18/lowest_fracdiv, 480*18/lowest_fracdiv/lowest_div,
+			lowest_result / 1000, lowest_result % 1000);
+
+	/* Program ref_pix phase fractional divider */
+	reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC);
+	reg_val &= ~BM_CLKCTRL_FRAC_PIXFRAC;
+	reg_val |= BF(lowest_fracdiv, CLKCTRL_FRAC_PIXFRAC);
+	__raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC);
+
+	/* Ungate PFD */
+	stmp3xxx_clearl(BM_CLKCTRL_FRAC_CLKGATEPIX,
+			REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC);
+
+	/* Program pix divider */
+	reg_val = __raw_readl(clk->scale_reg);
+	reg_val &= ~(BM_CLKCTRL_PIX_DIV | BM_CLKCTRL_PIX_CLKGATE);
+	reg_val |= BF(lowest_div, CLKCTRL_PIX_DIV);
+	__raw_writel(reg_val, clk->scale_reg);
+
+	/* Wait for divider update */
+	if (clk->busy_reg) {
+		int i;
+		for (i = 10000; i; i--)
+			if (!clk_is_busy(clk))
+				break;
+		if (!i) {
+			ret = -ETIMEDOUT;
+			goto out;
+		}
+	}
+
+	/* Switch to ref_pix source */
+	reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ);
+	reg_val &= ~BM_CLKCTRL_CLKSEQ_BYPASS_PIX;
+	__raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ);
+
+out:
+	return ret;
+}
+
+
+static int cpu_set_rate(struct clk *clk, u32 rate)
+{
+	u32 reg_val;
+
+	if (rate < 24000)
+		return -EINVAL;
+	else if (rate == 24000) {
+		/* switch to the 24M source */
+		clk_set_parent(clk, &osc_24M);
+	} else {
+		int i;
+		u32 clkctrl_cpu = 1;
+		u32 c = clkctrl_cpu;
+		u32 clkctrl_frac = 1;
+		u32 val;
+		for ( ; c < 0x40; c++) {
+			u32 f = (pll_clk.rate*18/c + rate/2) / rate;
+			int s1, s2;
+
+			if (f < 18 || f > 35)
+				continue;
+			s1 = pll_clk.rate*18/clkctrl_frac/clkctrl_cpu - rate;
+			s2 = pll_clk.rate*18/c/f - rate;
+			pr_debug("%s: s1 %d, s2 %d\n", __func__, s1, s2);
+			if (abs(s1) > abs(s2)) {
+				clkctrl_cpu = c;
+				clkctrl_frac = f;
+			}
+			if (s2 == 0)
+				break;
+		};
+		pr_debug("%s: clkctrl_cpu %d, clkctrl_frac %d\n", __func__,
+				clkctrl_cpu, clkctrl_frac);
+		if (c == 0x40) {
+			int  d = pll_clk.rate*18/clkctrl_frac/clkctrl_cpu -
+				rate;
+			if (abs(d) > 100 ||
+			    clkctrl_frac < 18 || clkctrl_frac > 35)
+				return -EINVAL;
+		}
+
+		/* 4.6.2 */
+		val = __raw_readl(clk->scale_reg);
+		val &= ~(0x3f << clk->scale_shift);
+		val |= clkctrl_frac;
+		clk_set_parent(clk, &osc_24M);
+		udelay(10);
+		__raw_writel(val, clk->scale_reg);
+		/* ungate */
+		__raw_writel(1<<7, clk->scale_reg + 8);
+		/* write clkctrl_cpu */
+		clk->saved_div = clkctrl_cpu;
+
+		reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
+		reg_val &= ~0x3F;
+		reg_val |= clkctrl_cpu;
+		__raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
+
+		for (i = 10000; i; i--)
+			if (!clk_is_busy(clk))
+				break;
+		if (!i) {
+			printk(KERN_ERR "couldn't set up CPU divisor\n");
+			return -ETIMEDOUT;
+		}
+		clk_set_parent(clk, &pll_clk);
+		clk->saved_div = 0;
+		udelay(10);
+	}
+	return 0;
+}
+
+static long cpu_get_rate(struct clk *clk)
+{
+	long rate = clk->parent->rate * 18;
+
+	rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f;
+	rate /= __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU) & 0x3f;
+	rate = ((rate + 9) / 10) * 10;
+	clk->rate = rate;
+
+	return rate;
+}
+
+static long cpu_round_rate(struct clk *clk, u32 rate)
+{
+	unsigned long r = 0;
+
+	if (rate <= 24000)
+		r = 24000;
+	else {
+		u32 clkctrl_cpu = 1;
+		u32 clkctrl_frac;
+		do {
+			clkctrl_frac =
+				(pll_clk.rate*18 / clkctrl_cpu + rate/2) / rate;
+			if (clkctrl_frac > 35)
+				continue;
+			if (pll_clk.rate*18 / clkctrl_frac / clkctrl_cpu/10 ==
+			    rate / 10)
+				break;
+		} while (pll_clk.rate / 2  >= clkctrl_cpu++ * rate);
+		if (pll_clk.rate / 2 < (clkctrl_cpu - 1) * rate)
+			clkctrl_cpu--;
+		pr_debug("%s: clkctrl_cpu %d, clkctrl_frac %d\n", __func__,
+				clkctrl_cpu, clkctrl_frac);
+		if (clkctrl_frac < 18)
+			clkctrl_frac = 18;
+		if (clkctrl_frac > 35)
+			clkctrl_frac = 35;
+
+		r = pll_clk.rate * 18;
+		r /= clkctrl_frac;
+		r /= clkctrl_cpu;
+		r = 10 * ((r + 9) / 10);
+	}
+	return r;
+}
+
+static long emi_get_rate(struct clk *clk)
+{
+	long rate = clk->parent->rate * 18;
+
+	rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f;
+	rate /= __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI) & 0x3f;
+	clk->rate = rate;
+
+	return rate;
+}
+
+static int clkseq_set_parent(struct clk *clk, struct clk *parent)
+{
+	int ret = -EINVAL;
+	int shift = 8;
+
+	/* bypass? */
+	if (parent == &osc_24M)
+		shift = 4;
+
+	if (clk->bypass_reg) {
+#ifdef CONFIG_ARCH_STMP378X
+		u32 hbus_val, cpu_val;
+
+		if (clk == &cpu_clk && shift == 4) {
+			hbus_val = __raw_readl(REGS_CLKCTRL_BASE +
+					HW_CLKCTRL_HBUS);
+			cpu_val = __raw_readl(REGS_CLKCTRL_BASE +
+					HW_CLKCTRL_CPU);
+
+			hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN |
+				      BM_CLKCTRL_HBUS_DIV);
+			clk->saved_div = cpu_val & BM_CLKCTRL_CPU_DIV_CPU;
+			cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU;
+			cpu_val |= 1;
+
+			if (machine_is_stmp378x()) {
+				__raw_writel(hbus_val,
+					REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS);
+				__raw_writel(cpu_val,
+					REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
+				hclk.rate = 0;
+			}
+		} else if (clk == &cpu_clk && shift == 8) {
+			hbus_val = __raw_readl(REGS_CLKCTRL_BASE +
+							HW_CLKCTRL_HBUS);
+			cpu_val = __raw_readl(REGS_CLKCTRL_BASE +
+							HW_CLKCTRL_CPU);
+			hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN |
+				      BM_CLKCTRL_HBUS_DIV);
+			hbus_val |= 2;
+			cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU;
+			if (clk->saved_div)
+				cpu_val |= clk->saved_div;
+			else
+				cpu_val |= 2;
+
+			if (machine_is_stmp378x()) {
+				__raw_writel(hbus_val,
+					REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS);
+				__raw_writel(cpu_val,
+					REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
+				hclk.rate = 0;
+			}
+		}
+#endif
+		__raw_writel(1 << clk->bypass_shift, clk->bypass_reg + shift);
+
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int hbus_set_rate(struct clk *clk, u32 rate)
+{
+	u8 div = 0;
+	int is_frac = 0;
+	u32 clkctrl_hbus;
+	struct clk *parent = clk->parent;
+
+	pr_debug("%s: rate %d, parent rate %d\n", __func__, rate,
+			parent->rate);
+
+	if (rate > parent->rate)
+		return -EINVAL;
+
+	if (((parent->rate + rate/2) / rate) * rate != parent->rate &&
+	    parent->rate / rate < 32) {
+		pr_debug("%s: switching to fractional mode\n", __func__);
+		is_frac = 1;
+	}
+
+	if (is_frac)
+		div = (32 * rate + parent->rate / 2) / parent->rate;
+	else
+		div = (parent->rate + rate - 1) / rate;
+	pr_debug("%s: div calculated is %d\n", __func__, div);
+	if (!div || div > 0x1f)
+		return -EINVAL;
+
+	clk_set_parent(&cpu_clk, &osc_24M);
+	udelay(10);
+	clkctrl_hbus = __raw_readl(clk->scale_reg);
+	clkctrl_hbus &= ~0x3f;
+	clkctrl_hbus |= div;
+	clkctrl_hbus |= (is_frac << 5);
+
+	__raw_writel(clkctrl_hbus, clk->scale_reg);
+	if (clk->busy_reg) {
+		int i;
+		for (i = 10000; i; i--)
+			if (!clk_is_busy(clk))
+				break;
+		if (!i) {
+			printk(KERN_ERR "couldn't set up CPU divisor\n");
+			return -ETIMEDOUT;
+		}
+	}
+	clk_set_parent(&cpu_clk, &pll_clk);
+	__raw_writel(clkctrl_hbus, clk->scale_reg);
+	udelay(10);
+	return 0;
+}
+
+static long hbus_get_rate(struct clk *clk)
+{
+	long rate = clk->parent->rate;
+
+	if (__raw_readl(clk->scale_reg) & 0x20) {
+		rate *= __raw_readl(clk->scale_reg) & 0x1f;
+		rate /= 32;
+	} else
+		rate /= __raw_readl(clk->scale_reg) & 0x1f;
+	clk->rate = rate;
+
+	return rate;
+}
+
+static int xbus_set_rate(struct clk *clk, u32 rate)
+{
+	u16 div = 0;
+	u32 clkctrl_xbus;
+
+	pr_debug("%s: rate %d, parent rate %d\n", __func__, rate,
+			clk->parent->rate);
+
+	div = (clk->parent->rate + rate - 1) / rate;
+	pr_debug("%s: div calculated is %d\n", __func__, div);
+	if (!div || div > 0x3ff)
+		return -EINVAL;
+
+	clkctrl_xbus = __raw_readl(clk->scale_reg);
+	clkctrl_xbus &= ~0x3ff;
+	clkctrl_xbus |= div;
+	__raw_writel(clkctrl_xbus, clk->scale_reg);
+	if (clk->busy_reg) {
+		int i;
+		for (i = 10000; i; i--)
+			if (!clk_is_busy(clk))
+				break;
+		if (!i) {
+			printk(KERN_ERR "couldn't set up xbus divisor\n");
+			return -ETIMEDOUT;
+		}
+	}
+	return 0;
+}
+
+static long xbus_get_rate(struct clk *clk)
+{
+	long rate = clk->parent->rate;
+
+	rate /= __raw_readl(clk->scale_reg) & 0x3ff;
+	clk->rate = rate;
+
+	return rate;
+}
+
+
+/* Clock ops */
+
+static struct clk_ops std_ops = {
+	.enable		= std_clk_enable,
+	.disable	= std_clk_disable,
+	.get_rate	= per_get_rate,
+	.set_rate	= per_set_rate,
+	.set_parent	= clkseq_set_parent,
+};
+
+static struct clk_ops min_ops = {
+	.enable		= std_clk_enable,
+	.disable	= std_clk_disable,
+};
+
+static struct clk_ops cpu_ops = {
+	.enable		= std_clk_enable,
+	.disable	= std_clk_disable,
+	.get_rate	= cpu_get_rate,
+	.set_rate	= cpu_set_rate,
+	.round_rate	= cpu_round_rate,
+	.set_parent	= clkseq_set_parent,
+};
+
+static struct clk_ops io_ops = {
+	.enable		= std_clk_enable,
+	.disable	= std_clk_disable,
+	.get_rate	= io_get_rate,
+	.set_rate	= io_set_rate,
+};
+
+static struct clk_ops hbus_ops = {
+	.get_rate	= hbus_get_rate,
+	.set_rate	= hbus_set_rate,
+};
+
+static struct clk_ops xbus_ops = {
+	.get_rate	= xbus_get_rate,
+	.set_rate	= xbus_set_rate,
+};
+
+static struct clk_ops lcdif_ops = {
+	.enable		= std_clk_enable,
+	.disable	= std_clk_disable,
+	.get_rate	= lcdif_get_rate,
+	.set_rate	= lcdif_set_rate,
+	.set_parent	= clkseq_set_parent,
+};
+
+static struct clk_ops emi_ops = {
+	.get_rate	= emi_get_rate,
+};
+
+/* List of on-chip clocks */
+
+static struct clk osc_24M = {
+	.flags		= FIXED_RATE | ENABLED,
+	.rate		= 24000,
+};
+
+static struct clk pll_clk = {
+	.parent		= &osc_24M,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0,
+	.enable_shift	= 16,
+	.enable_wait	= 10,
+	.flags		= FIXED_RATE | ENABLED,
+	.rate		= 480000,
+	.ops		= &min_ops,
+};
+
+static struct clk cpu_clk = {
+	.parent		= &pll_clk,
+	.scale_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
+	.scale_shift	= 0,
+	.bypass_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+	.bypass_shift	= 7,
+	.busy_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU,
+	.busy_bit	= 28,
+	.flags		= RATE_PROPAGATES | ENABLED,
+	.ops		= &cpu_ops,
+};
+
+static struct clk io_clk = {
+	.parent		= &pll_clk,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
+	.enable_shift	= 31,
+	.enable_negate	= 1,
+	.scale_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
+	.scale_shift	= 24,
+	.flags		= RATE_PROPAGATES | ENABLED,
+	.ops		= &io_ops,
+};
+
+static struct clk hclk = {
+	.parent		= &cpu_clk,
+	.scale_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS,
+	.bypass_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+	.bypass_shift	= 7,
+	.busy_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS,
+	.busy_bit	= 29,
+	.flags		= RATE_PROPAGATES | ENABLED,
+	.ops		= &hbus_ops,
+};
+
+static struct clk xclk = {
+	.parent		= &osc_24M,
+	.scale_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_XBUS,
+	.busy_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_XBUS,
+	.busy_bit	= 31,
+	.flags		= RATE_PROPAGATES | ENABLED,
+	.ops		= &xbus_ops,
+};
+
+static struct clk uart_clk = {
+	.parent		= &xclk,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
+	.enable_shift	= 31,
+	.enable_negate	= 1,
+	.flags		= ENABLED,
+	.ops		= &min_ops,
+};
+
+static struct clk audio_clk = {
+	.parent		= &xclk,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
+	.enable_shift	= 30,
+	.enable_negate	= 1,
+	.ops		= &min_ops,
+};
+
+static struct clk pwm_clk = {
+	.parent		= &xclk,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
+	.enable_shift	= 29,
+	.enable_negate	= 1,
+	.ops		= &min_ops,
+};
+
+static struct clk dri_clk = {
+	.parent		= &xclk,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
+	.enable_shift	= 28,
+	.enable_negate	= 1,
+	.ops		= &min_ops,
+};
+
+static struct clk digctl_clk = {
+	.parent		= &xclk,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
+	.enable_shift	= 27,
+	.enable_negate	= 1,
+	.ops		= &min_ops,
+};
+
+static struct clk timer_clk = {
+	.parent		= &xclk,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
+	.enable_shift	= 26,
+	.enable_negate	= 1,
+	.flags		= ENABLED,
+	.ops		= &min_ops,
+};
+
+static struct clk lcdif_clk = {
+	.parent		= &pll_clk,
+	.scale_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX,
+	.busy_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX,
+	.busy_bit	= 29,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX,
+	.enable_shift	= 31,
+	.enable_negate	= 1,
+	.bypass_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+	.bypass_shift	= 1,
+	.flags		= NEEDS_SET_PARENT,
+	.ops		= &lcdif_ops,
+};
+
+static struct clk ssp_clk = {
+	.parent		= &io_clk,
+	.scale_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP,
+	.busy_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP,
+	.busy_bit	= 29,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP,
+	.enable_shift	= 31,
+	.bypass_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+	.bypass_shift	= 5,
+	.enable_negate	= 1,
+	.flags		= NEEDS_SET_PARENT,
+	.ops		= &std_ops,
+};
+
+static struct clk gpmi_clk = {
+	.parent		= &io_clk,
+	.scale_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI,
+	.busy_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI,
+	.busy_bit	= 29,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI,
+	.enable_shift	= 31,
+	.enable_negate	= 1,
+	.bypass_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+	.bypass_shift	= 4,
+	.flags		= NEEDS_SET_PARENT,
+	.ops		= &std_ops,
+};
+
+static struct clk spdif_clk = {
+	.parent		= &pll_clk,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_SPDIF,
+	.enable_shift	= 31,
+	.enable_negate	= 1,
+	.ops		= &min_ops,
+};
+
+static struct clk emi_clk = {
+	.parent		= &pll_clk,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI,
+	.enable_shift	= 31,
+	.enable_negate	= 1,
+	.scale_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
+	.scale_shift	= 8,
+	.busy_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI,
+	.busy_bit	= 28,
+	.bypass_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+	.bypass_shift	= 6,
+	.flags		= ENABLED,
+	.ops		= &emi_ops,
+};
+
+static struct clk ir_clk = {
+	.parent		= &io_clk,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_IR,
+	.enable_shift	= 31,
+	.enable_negate	= 1,
+	.bypass_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+	.bypass_shift	= 3,
+	.ops		= &min_ops,
+};
+
+static struct clk saif_clk = {
+	.parent		= &pll_clk,
+	.scale_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF,
+	.busy_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF,
+	.busy_bit	= 29,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF,
+	.enable_shift	= 31,
+	.enable_negate	= 1,
+	.bypass_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+	.bypass_shift	= 0,
+	.ops		= &std_ops,
+};
+
+static struct clk usb_clk = {
+	.parent		= &pll_clk,
+	.enable_reg	= REGS_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0,
+	.enable_shift	= 18,
+	.enable_negate	= 1,
+	.ops		= &min_ops,
+};
+
+/* list of all the clocks */
+static struct clk_lookup onchip_clks[] = {
+	{
+		.con_id = "osc_24M",
+		.clk = &osc_24M,
+	}, {
+		.con_id = "pll",
+		.clk = &pll_clk,
+	}, {
+		.con_id = "cpu",
+		.clk = &cpu_clk,
+	}, {
+		.con_id = "hclk",
+		.clk = &hclk,
+	}, {
+		.con_id = "xclk",
+		.clk = &xclk,
+	}, {
+		.con_id = "io",
+		.clk = &io_clk,
+	}, {
+		.con_id = "uart",
+		.clk = &uart_clk,
+	}, {
+		.con_id = "audio",
+		.clk = &audio_clk,
+	}, {
+		.con_id = "pwm",
+		.clk = &pwm_clk,
+	}, {
+		.con_id = "dri",
+		.clk = &dri_clk,
+	}, {
+		.con_id = "digctl",
+		.clk = &digctl_clk,
+	}, {
+		.con_id = "timer",
+		.clk = &timer_clk,
+	}, {
+		.con_id = "lcdif",
+		.clk = &lcdif_clk,
+	}, {
+		.con_id = "ssp",
+		.clk = &ssp_clk,
+	}, {
+		.con_id = "gpmi",
+		.clk = &gpmi_clk,
+	}, {
+		.con_id = "spdif",
+		.clk = &spdif_clk,
+	}, {
+		.con_id = "emi",
+		.clk = &emi_clk,
+	}, {
+		.con_id = "ir",
+		.clk = &ir_clk,
+	}, {
+		.con_id = "saif",
+		.clk = &saif_clk,
+	}, {
+		.con_id = "usb",
+		.clk = &usb_clk,
+	},
+};
+
+static int __init propagate_rate(struct clk *clk)
+{
+	struct clk_lookup *cl;
+
+	for (cl = onchip_clks; cl < onchip_clks + ARRAY_SIZE(onchip_clks);
+	     cl++) {
+		if (unlikely(!clk_good(cl->clk)))
+			continue;
+		if (cl->clk->parent == clk && cl->clk->ops->get_rate) {
+			cl->clk->ops->get_rate(cl->clk);
+			if (cl->clk->flags & RATE_PROPAGATES)
+				propagate_rate(cl->clk);
+		}
+	}
+
+	return 0;
+}
+
+/* Exported API */
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (unlikely(!clk_good(clk)))
+		return 0;
+
+	if (clk->rate != 0)
+		return clk->rate;
+
+	if (clk->ops->get_rate != NULL)
+		return clk->ops->get_rate(clk);
+
+	return clk_get_rate(clk->parent);
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (unlikely(!clk_good(clk)))
+		return 0;
+
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+
+	return 0;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+static inline int close_enough(long rate1, long rate2)
+{
+	return rate1 && !((rate2 - rate1) * 1000 / rate1);
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	int ret = -EINVAL;
+
+	if (unlikely(!clk_good(clk)))
+		goto out;
+
+	if (clk->flags & FIXED_RATE || !clk->ops->set_rate)
+		goto out;
+
+	else if (!close_enough(clk->rate, rate)) {
+		ret = clk->ops->set_rate(clk, rate);
+		if (ret < 0)
+			goto out;
+		clk->rate = rate;
+		if (clk->flags & RATE_PROPAGATES)
+			propagate_rate(clk);
+	} else
+		ret = 0;
+
+out:
+	return ret;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+int clk_enable(struct clk *clk)
+{
+	unsigned long clocks_flags;
+
+	if (unlikely(!clk_good(clk)))
+		return -EINVAL;
+
+	if (clk->parent)
+		clk_enable(clk->parent);
+
+	spin_lock_irqsave(&clocks_lock, clocks_flags);
+
+	clk->usage++;
+	if (clk->ops && clk->ops->enable)
+		clk->ops->enable(clk);
+
+	spin_unlock_irqrestore(&clocks_lock, clocks_flags);
+	return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+static void local_clk_disable(struct clk *clk)
+{
+	if (unlikely(!clk_good(clk)))
+		return;
+
+	if (clk->usage == 0 && clk->ops->disable)
+		clk->ops->disable(clk);
+
+	if (clk->parent)
+		local_clk_disable(clk->parent);
+}
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long clocks_flags;
+
+	if (unlikely(!clk_good(clk)))
+		return;
+
+	spin_lock_irqsave(&clocks_lock, clocks_flags);
+
+	if ((--clk->usage) == 0 && clk->ops->disable)
+		clk->ops->disable(clk);
+
+	spin_unlock_irqrestore(&clocks_lock, clocks_flags);
+	if (clk->parent)
+		clk_disable(clk->parent);
+}
+EXPORT_SYMBOL(clk_disable);
+
+/* Some additional API */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	int ret = -ENODEV;
+	unsigned long clocks_flags;
+
+	if (unlikely(!clk_good(clk)))
+		goto out;
+
+	if (!clk->ops->set_parent)
+		goto out;
+
+	spin_lock_irqsave(&clocks_lock, clocks_flags);
+
+	ret = clk->ops->set_parent(clk, parent);
+	if (!ret) {
+		/* disable if usage count is 0 */
+		local_clk_disable(parent);
+
+		parent->usage += clk->usage;
+		clk->parent->usage -= clk->usage;
+
+		/* disable if new usage count is 0 */
+		local_clk_disable(clk->parent);
+
+		clk->parent = parent;
+	}
+	spin_unlock_irqrestore(&clocks_lock, clocks_flags);
+
+out:
+	return ret;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (unlikely(!clk_good(clk)))
+		return NULL;
+	return clk->parent;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+static int __init clk_init(void)
+{
+	struct clk_lookup *cl;
+	struct clk_ops *ops;
+
+	spin_lock_init(&clocks_lock);
+
+	for (cl = onchip_clks; cl < onchip_clks + ARRAY_SIZE(onchip_clks);
+	     cl++) {
+		if (cl->clk->flags & ENABLED)
+			clk_enable(cl->clk);
+		else
+			local_clk_disable(cl->clk);
+
+		ops = cl->clk->ops;
+
+		if ((cl->clk->flags & NEEDS_INITIALIZATION) &&
+				ops && ops->set_rate)
+			ops->set_rate(cl->clk, cl->clk->rate);
+
+		if (cl->clk->flags & FIXED_RATE) {
+			if (cl->clk->flags & RATE_PROPAGATES)
+				propagate_rate(cl->clk);
+		} else {
+			if (ops && ops->get_rate)
+				ops->get_rate(cl->clk);
+		}
+
+		if (cl->clk->flags & NEEDS_SET_PARENT) {
+			if (ops && ops->set_parent)
+				ops->set_parent(cl->clk, cl->clk->parent);
+		}
+
+		clkdev_add(cl);
+	}
+	return 0;
+}
+
+arch_initcall(clk_init);
diff --git a/arch/arm/plat-stmp3xxx/clock.h b/arch/arm/plat-stmp3xxx/clock.h
new file mode 100644
index 0000000..a6611e1
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/clock.h
@@ -0,0 +1,61 @@
+/*
+ * Clock control driver for Freescale STMP37XX/STMP378X - internal header file
+ *
+ * Author: Vitaly Wool <vital@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __ARCH_ARM_STMX3XXX_CLOCK_H__
+#define __ARCH_ARM_STMX3XXX_CLOCK_H__
+
+#ifndef __ASSEMBLER__
+
+struct clk_ops {
+	int (*enable) (struct clk *);
+	int (*disable) (struct clk *);
+	long (*get_rate) (struct clk *);
+	long (*round_rate) (struct clk *, u32);
+	int (*set_rate) (struct clk *, u32);
+	int (*set_parent) (struct clk *, struct clk *);
+};
+
+struct clk {
+	struct clk *parent;
+	u32 rate;
+	u32 flags;
+	u8 scale_shift;
+	u8 enable_shift;
+	u8 bypass_shift;
+	u8 busy_bit;
+	s8 usage;
+	int enable_wait;
+	int enable_negate;
+	u32 saved_div;
+	void __iomem *enable_reg;
+	void __iomem *scale_reg;
+	void __iomem *bypass_reg;
+	void __iomem *busy_reg;
+	struct clk_ops *ops;
+};
+
+#endif /* __ASSEMBLER__ */
+
+/* Flags */
+#define RATE_PROPAGATES      (1<<0)
+#define NEEDS_INITIALIZATION (1<<1)
+#define PARENT_SET_RATE      (1<<2)
+#define FIXED_RATE           (1<<3)
+#define ENABLED	             (1<<4)
+#define NEEDS_SET_PARENT     (1<<5)
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/core.c b/arch/arm/plat-stmp3xxx/core.c
new file mode 100644
index 0000000..37b8a09
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/core.c
@@ -0,0 +1,128 @@
+/*
+ * Freescale STMP37XX/STMP378X core routines
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <mach/stmp3xxx.h>
+#include <mach/platform.h>
+#include <mach/dma.h>
+#include <mach/regs-clkctrl.h>
+
+static int __stmp3xxx_reset_block(void __iomem *hwreg, int just_enable)
+{
+	u32 c;
+	int timeout;
+
+	/* the process of software reset of IP block is done
+	   in several steps:
+
+	   - clear SFTRST and wait for block is enabled;
+	   - clear clock gating (CLKGATE bit);
+	   - set the SFTRST again and wait for block is in reset;
+	   - clear SFTRST and wait for reset completion.
+	*/
+	c = __raw_readl(hwreg);
+	c &= ~(1<<31);		/* clear SFTRST */
+	__raw_writel(c, hwreg);
+	for (timeout = 1000000; timeout > 0; timeout--)
+		/* still in SFTRST state ? */
+		if ((__raw_readl(hwreg) & (1<<31)) == 0)
+			break;
+	if (timeout <= 0) {
+		printk(KERN_ERR"%s(%p): timeout when enabling\n",
+				__func__, hwreg);
+		return -ETIME;
+	}
+
+	c = __raw_readl(hwreg);
+	c &= ~(1<<30);		/* clear CLKGATE */
+	__raw_writel(c, hwreg);
+
+	if (!just_enable) {
+		c = __raw_readl(hwreg);
+		c |= (1<<31);		/* now again set SFTRST */
+		__raw_writel(c, hwreg);
+		for (timeout = 1000000; timeout > 0; timeout--)
+			/* poll until CLKGATE set */
+			if (__raw_readl(hwreg) & (1<<30))
+				break;
+		if (timeout <= 0) {
+			printk(KERN_ERR"%s(%p): timeout when resetting\n",
+					__func__, hwreg);
+			return -ETIME;
+		}
+
+		c = __raw_readl(hwreg);
+		c &= ~(1<<31);		/* clear SFTRST */
+		__raw_writel(c, hwreg);
+		for (timeout = 1000000; timeout > 0; timeout--)
+			/* still in SFTRST state ? */
+			if ((__raw_readl(hwreg) & (1<<31)) == 0)
+				break;
+		if (timeout <= 0) {
+			printk(KERN_ERR"%s(%p): timeout when enabling "
+					"after reset\n", __func__, hwreg);
+			return -ETIME;
+		}
+
+		c = __raw_readl(hwreg);
+		c &= ~(1<<30);		/* clear CLKGATE */
+		__raw_writel(c, hwreg);
+	}
+	for (timeout = 1000000; timeout > 0; timeout--)
+		/* still in SFTRST state ? */
+		if ((__raw_readl(hwreg) & (1<<30)) == 0)
+			break;
+
+	if (timeout <= 0) {
+		printk(KERN_ERR"%s(%p): timeout when unclockgating\n",
+				__func__, hwreg);
+		return -ETIME;
+	}
+
+	return 0;
+}
+
+int stmp3xxx_reset_block(void __iomem *hwreg, int just_enable)
+{
+	int try = 10;
+	int r;
+
+	while (try--) {
+		r = __stmp3xxx_reset_block(hwreg, just_enable);
+		if (!r)
+			break;
+		pr_debug("%s: try %d failed\n", __func__, 10 - try);
+	}
+	return r;
+}
+EXPORT_SYMBOL(stmp3xxx_reset_block);
+
+struct platform_device stmp3xxx_dbguart = {
+	.name = "stmp3xxx-dbguart",
+	.id = -1,
+};
+
+void __init stmp3xxx_init(void)
+{
+	/* Turn off auto-slow and other tricks */
+	stmp3xxx_clearl(0x7f00000, REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS);
+
+	stmp3xxx_dma_init();
+}
diff --git a/arch/arm/plat-stmp3xxx/devices.c b/arch/arm/plat-stmp3xxx/devices.c
new file mode 100644
index 0000000..68fed4b
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/devices.c
@@ -0,0 +1,389 @@
+/*
+* Freescale STMP37XX/STMP378X platform devices
+*
+* Embedded Alley Solutions, Inc <source@embeddedalley.com>
+*
+* Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+* Copyright 2008 Embedded Alley Solutions, 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/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/dma.h>
+#include <mach/platform.h>
+#include <mach/stmp3xxx.h>
+#include <mach/regs-lcdif.h>
+#include <mach/regs-uartapp.h>
+#include <mach/regs-gpmi.h>
+#include <mach/regs-usbctrl.h>
+#include <mach/regs-ssp.h>
+#include <mach/regs-rtc.h>
+
+static u64 common_dmamask = DMA_BIT_MASK(32);
+
+static struct resource appuart_resources[] = {
+	{
+		.start = IRQ_UARTAPP_INTERNAL,
+		.end = IRQ_UARTAPP_INTERNAL,
+		.flags = IORESOURCE_IRQ,
+	}, {
+		.start = IRQ_UARTAPP_RX_DMA,
+		.end = IRQ_UARTAPP_RX_DMA,
+		.flags = IORESOURCE_IRQ,
+	}, {
+		.start = IRQ_UARTAPP_TX_DMA,
+		.end = IRQ_UARTAPP_TX_DMA,
+		.flags = IORESOURCE_IRQ,
+	}, {
+		.start = REGS_UARTAPP1_PHYS,
+		.end = REGS_UARTAPP1_PHYS + REGS_UARTAPP_SIZE,
+		.flags = IORESOURCE_MEM,
+	}, {
+		/* Rx DMA channel */
+		.start = STMP3XXX_DMA(6, STMP3XXX_BUS_APBX),
+		.end = STMP3XXX_DMA(6, STMP3XXX_BUS_APBX),
+		.flags = IORESOURCE_DMA,
+	}, {
+		/* Tx DMA channel */
+		.start = STMP3XXX_DMA(7, STMP3XXX_BUS_APBX),
+		.end = STMP3XXX_DMA(7, STMP3XXX_BUS_APBX),
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+struct platform_device stmp3xxx_appuart = {
+	.name = "stmp3xxx-appuart",
+	.id = 0,
+	.resource = appuart_resources,
+	.num_resources = ARRAY_SIZE(appuart_resources),
+	.dev = {
+		.dma_mask	= &common_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+struct platform_device stmp3xxx_watchdog = {
+      .name   = "stmp3xxx_wdt",
+      .id     = -1,
+};
+
+static struct resource ts_resource[] = {
+	{
+		.flags  = IORESOURCE_IRQ,
+		.start  = IRQ_TOUCH_DETECT,
+		.end    = IRQ_TOUCH_DETECT,
+	}, {
+		.flags  = IORESOURCE_IRQ,
+		.start  = IRQ_LRADC_CH5,
+		.end    = IRQ_LRADC_CH5,
+	},
+};
+
+struct platform_device stmp3xxx_touchscreen = {
+	.name		= "stmp3xxx_ts",
+	.id		= -1,
+	.resource	= ts_resource,
+	.num_resources	= ARRAY_SIZE(ts_resource),
+};
+
+/*
+* Keypad device
+*/
+struct platform_device stmp3xxx_keyboard = {
+	.name		= "stmp3xxx-keyboard",
+	.id		= -1,
+};
+
+static struct resource gpmi_resources[] = {
+	{
+		.flags = IORESOURCE_MEM,
+		.start = REGS_GPMI_PHYS,
+		.end = REGS_GPMI_PHYS + REGS_GPMI_SIZE,
+	}, {
+		.flags = IORESOURCE_IRQ,
+		.start = IRQ_GPMI_DMA,
+		.end = IRQ_GPMI_DMA,
+	}, {
+		.flags = IORESOURCE_DMA,
+		.start = STMP3XXX_DMA(4, STMP3XXX_BUS_APBH),
+		.end = STMP3XXX_DMA(8, STMP3XXX_BUS_APBH),
+	},
+};
+
+struct platform_device stmp3xxx_gpmi = {
+	.name = "gpmi",
+	.id = -1,
+	.dev	= {
+		.dma_mask	= &common_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.resource = gpmi_resources,
+	.num_resources = ARRAY_SIZE(gpmi_resources),
+};
+
+static struct resource mmc1_resource[] = {
+	{
+		.flags	= IORESOURCE_MEM,
+		.start	= REGS_SSP1_PHYS,
+		.end	= REGS_SSP1_PHYS + REGS_SSP_SIZE,
+	}, {
+		.flags	= IORESOURCE_DMA,
+		.start	= STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
+		.end	= STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
+	}, {
+		.flags	= IORESOURCE_IRQ,
+		.start	= IRQ_SSP1_DMA,
+		.end	= IRQ_SSP1_DMA,
+	}, {
+		.flags	= IORESOURCE_IRQ,
+		.start	= IRQ_SSP_ERROR,
+		.end	= IRQ_SSP_ERROR,
+	},
+};
+
+struct platform_device stmp3xxx_mmc = {
+	.name	= "stmp3xxx-mmc",
+	.id	= 1,
+	.dev	= {
+		.dma_mask	= &common_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.resource = mmc1_resource,
+	.num_resources = ARRAY_SIZE(mmc1_resource),
+};
+
+static struct resource usb_resources[] = {
+	{
+		.start	= REGS_USBCTRL_PHYS,
+		.end	= REGS_USBCTRL_PHYS + SZ_4K,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_USB_CTRL,
+		.end	= IRQ_USB_CTRL,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device stmp3xxx_udc = {
+	.name		= "fsl-usb2-udc",
+	.id		= -1,
+	.dev		= {
+		.dma_mask		= &common_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource = usb_resources,
+	.num_resources = ARRAY_SIZE(usb_resources),
+};
+
+struct platform_device stmp3xxx_ehci = {
+	.name		= "fsl-ehci",
+	.id		= -1,
+	.dev		= {
+		.dma_mask		= &common_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= usb_resources,
+	.num_resources	= ARRAY_SIZE(usb_resources),
+};
+
+static struct resource rtc_resources[] = {
+	{
+		.start	= REGS_RTC_PHYS,
+		.end	= REGS_RTC_PHYS + REGS_RTC_SIZE,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_RTC_ALARM,
+		.end	= IRQ_RTC_ALARM,
+		.flags	= IORESOURCE_IRQ,
+	}, {
+		.start	= IRQ_RTC_1MSEC,
+		.end	= IRQ_RTC_1MSEC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device stmp3xxx_rtc = {
+	.name		= "stmp3xxx-rtc",
+	.id		= -1,
+	.resource	= rtc_resources,
+	.num_resources	= ARRAY_SIZE(rtc_resources),
+};
+
+static struct resource ssp1_resources[] = {
+	{
+		.start	= REGS_SSP1_PHYS,
+		.end	= REGS_SSP1_PHYS + REGS_SSP_SIZE,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_SSP1_DMA,
+		.end	= IRQ_SSP1_DMA,
+		.flags	= IORESOURCE_IRQ,
+	}, {
+		.start	= STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
+		.end	= STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource ssp2_resources[] = {
+	{
+		.start	= REGS_SSP2_PHYS,
+		.end	= REGS_SSP2_PHYS + REGS_SSP_SIZE,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_SSP2_DMA,
+		.end	= IRQ_SSP2_DMA,
+		.flags	= IORESOURCE_IRQ,
+	}, {
+		.start	= STMP3XXX_DMA(2, STMP3XXX_BUS_APBH),
+		.end	= STMP3XXX_DMA(2, STMP3XXX_BUS_APBH),
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device stmp3xxx_spi1 = {
+	.name	= "stmp3xxx_ssp",
+	.id	= 1,
+	.dev	= {
+		.dma_mask	= &common_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.resource = ssp1_resources,
+	.num_resources = ARRAY_SIZE(ssp1_resources),
+};
+
+struct platform_device stmp3xxx_spi2 = {
+	.name	= "stmp3xxx_ssp",
+	.id	= 2,
+	.dev	= {
+		.dma_mask	= &common_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.resource = ssp2_resources,
+	.num_resources = ARRAY_SIZE(ssp2_resources),
+};
+
+static struct resource fb_resource[] = {
+	{
+		.flags	= IORESOURCE_IRQ,
+		.start	= IRQ_LCDIF_DMA,
+		.end	= IRQ_LCDIF_DMA,
+	}, {
+		.flags	= IORESOURCE_IRQ,
+		.start	= IRQ_LCDIF_ERROR,
+		.end	= IRQ_LCDIF_ERROR,
+	}, {
+		.flags	= IORESOURCE_MEM,
+		.start	= REGS_LCDIF_PHYS,
+		.end	= REGS_LCDIF_PHYS + REGS_LCDIF_SIZE,
+	},
+};
+
+struct platform_device stmp3xxx_framebuffer = {
+	.name		= "stmp3xxx-fb",
+	.id		= -1,
+	.dev		= {
+		.dma_mask		= &common_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.num_resources	= ARRAY_SIZE(fb_resource),
+	.resource	= fb_resource,
+};
+
+#define CMDLINE_DEVICE_CHOOSE(name, dev1, dev2)			\
+	static char *cmdline_device_##name;			\
+	static int cmdline_device_##name##_setup(char *dev)	\
+	{							\
+		cmdline_device_##name = dev + 1;		\
+		return 0;					\
+	}							\
+	__setup(#name, cmdline_device_##name##_setup);		\
+	int stmp3xxx_##name##_device_register(void)		\
+	{							\
+		struct platform_device *d = NULL;		\
+		if (!cmdline_device_##name ||			\
+			!strcmp(cmdline_device_##name, #dev1))	\
+				d = &stmp3xxx_##dev1;		\
+		else if (!strcmp(cmdline_device_##name, #dev2))	\
+				d = &stmp3xxx_##dev2;		\
+		else						\
+			printk(KERN_ERR"Unknown %s assignment '%s'.\n",	\
+				#name, cmdline_device_##name);	\
+		return d ? platform_device_register(d) : -ENOENT;	\
+	}
+
+CMDLINE_DEVICE_CHOOSE(ssp1, mmc, spi1)
+CMDLINE_DEVICE_CHOOSE(ssp2, gpmi, spi2)
+
+struct platform_device stmp3xxx_backlight = {
+	.name		= "stmp3xxx-bl",
+	.id		= -1,
+};
+
+struct platform_device stmp3xxx_rotdec = {
+	.name	= "stmp3xxx-rotdec",
+	.id	= -1,
+};
+
+struct platform_device stmp3xxx_persistent = {
+	.name			= "stmp3xxx-persistent",
+	.id			= -1,
+};
+
+struct platform_device stmp3xxx_dcp_bootstream = {
+	.name			= "stmp3xxx-dcpboot",
+	.id			= -1,
+	.dev	= {
+		.dma_mask	= &common_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource dcp_resources[] = {
+	{
+		.start = IRQ_DCP_VMI,
+		.end = IRQ_DCP_VMI,
+		.flags = IORESOURCE_IRQ,
+	}, {
+		.start = IRQ_DCP,
+		.end = IRQ_DCP,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device stmp3xxx_dcp = {
+	.name			= "stmp3xxx-dcp",
+	.id			= -1,
+	.resource		= dcp_resources,
+	.num_resources		= ARRAY_SIZE(dcp_resources),
+	.dev	= {
+		.dma_mask	= &common_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource battery_resource[] = {
+	{
+		.flags  = IORESOURCE_IRQ,
+		.start  = IRQ_VDD5V,
+		.end    = IRQ_VDD5V,
+	},
+};
+
+struct platform_device stmp3xxx_battery = {
+	.name   = "stmp3xxx-battery",
+	.resource = battery_resource,
+	.num_resources = ARRAY_SIZE(battery_resource),
+};
diff --git a/arch/arm/plat-stmp3xxx/dma.c b/arch/arm/plat-stmp3xxx/dma.c
new file mode 100644
index 0000000..d2f4977
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/dma.c
@@ -0,0 +1,463 @@
+/*
+ * DMA helper routines for Freescale STMP37XX/STMP378X
+ *
+ * Author: dmitry pervushin <dpervushin@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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/kernel.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/sysdev.h>
+#include <linux/cpufreq.h>
+
+#include <asm/page.h>
+
+#include <mach/platform.h>
+#include <mach/dma.h>
+#include <mach/regs-apbx.h>
+#include <mach/regs-apbh.h>
+
+static const size_t pool_item_size = sizeof(struct stmp3xxx_dma_command);
+static const size_t pool_alignment = 8;
+static struct stmp3xxx_dma_user {
+	void *pool;
+	int inuse;
+	const char *name;
+} channels[MAX_DMA_CHANNELS];
+
+#define IS_VALID_CHANNEL(ch) ((ch) >= 0 && (ch) < MAX_DMA_CHANNELS)
+#define IS_USED(ch) (channels[ch].inuse)
+
+int stmp3xxx_dma_request(int ch, struct device *dev, const char *name)
+{
+	struct stmp3xxx_dma_user *user;
+	int err = 0;
+
+	user = channels + ch;
+	if (!IS_VALID_CHANNEL(ch)) {
+		err = -ENODEV;
+		goto out;
+	}
+	if (IS_USED(ch)) {
+		err = -EBUSY;
+		goto out;
+	}
+	/* Create a pool to allocate dma commands from */
+	user->pool = dma_pool_create(name, dev, pool_item_size,
+				     pool_alignment, PAGE_SIZE);
+	if (user->pool == NULL) {
+		err = -ENOMEM;
+		goto out;
+	}
+	user->name = name;
+	user->inuse++;
+out:
+	return err;
+}
+EXPORT_SYMBOL(stmp3xxx_dma_request);
+
+int stmp3xxx_dma_release(int ch)
+{
+	struct stmp3xxx_dma_user *user = channels + ch;
+	int err = 0;
+
+	if (!IS_VALID_CHANNEL(ch)) {
+		err = -ENODEV;
+		goto out;
+	}
+	if (!IS_USED(ch)) {
+		err = -EBUSY;
+		goto out;
+	}
+	BUG_ON(user->pool == NULL);
+	dma_pool_destroy(user->pool);
+	user->inuse--;
+out:
+	return err;
+}
+EXPORT_SYMBOL(stmp3xxx_dma_release);
+
+int stmp3xxx_dma_read_semaphore(int channel)
+{
+	int sem = -1;
+
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		sem = __raw_readl(REGS_APBH_BASE + HW_APBH_CHn_SEMA +
+				STMP3XXX_DMA_CHANNEL(channel) * 0x70);
+		sem &= BM_APBH_CHn_SEMA_PHORE;
+		sem >>= BP_APBH_CHn_SEMA_PHORE;
+		break;
+
+	case STMP3XXX_BUS_APBX:
+		sem = __raw_readl(REGS_APBX_BASE + HW_APBX_CHn_SEMA +
+				STMP3XXX_DMA_CHANNEL(channel) * 0x70);
+		sem &= BM_APBX_CHn_SEMA_PHORE;
+		sem >>= BP_APBX_CHn_SEMA_PHORE;
+		break;
+	default:
+		BUG();
+	}
+	return sem;
+}
+EXPORT_SYMBOL(stmp3xxx_dma_read_semaphore);
+
+int stmp3xxx_dma_allocate_command(int channel,
+				  struct stmp3xxx_dma_descriptor *descriptor)
+{
+	struct stmp3xxx_dma_user *user = channels + channel;
+	int err = 0;
+
+	if (!IS_VALID_CHANNEL(channel)) {
+		err = -ENODEV;
+		goto out;
+	}
+	if (!IS_USED(channel)) {
+		err = -EBUSY;
+		goto out;
+	}
+	if (descriptor == NULL) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	/* Allocate memory for a command from the buffer */
+	descriptor->command =
+	    dma_pool_alloc(user->pool, GFP_KERNEL, &descriptor->handle);
+
+	/* Check it worked */
+	if (!descriptor->command) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	memset(descriptor->command, 0, pool_item_size);
+out:
+	WARN_ON(err);
+	return err;
+}
+EXPORT_SYMBOL(stmp3xxx_dma_allocate_command);
+
+int stmp3xxx_dma_free_command(int channel,
+			      struct stmp3xxx_dma_descriptor *descriptor)
+{
+	int err = 0;
+
+	if (!IS_VALID_CHANNEL(channel)) {
+		err = -ENODEV;
+		goto out;
+	}
+	if (!IS_USED(channel)) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	/* Return the command memory to the pool */
+	dma_pool_free(channels[channel].pool, descriptor->command,
+		      descriptor->handle);
+
+	/* Initialise descriptor so we're not tempted to use it */
+	descriptor->command = NULL;
+	descriptor->handle = 0;
+	descriptor->virtual_buf_ptr = NULL;
+	descriptor->next_descr = NULL;
+
+	WARN_ON(err);
+out:
+	return err;
+}
+EXPORT_SYMBOL(stmp3xxx_dma_free_command);
+
+void stmp3xxx_dma_go(int channel,
+		     struct stmp3xxx_dma_descriptor *head, u32 semaphore)
+{
+	int ch = STMP3XXX_DMA_CHANNEL(channel);
+	void __iomem *c, *s;
+
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		c = REGS_APBH_BASE + HW_APBH_CHn_NXTCMDAR + 0x70 * ch;
+		s = REGS_APBH_BASE + HW_APBH_CHn_SEMA + 0x70 * ch;
+		break;
+
+	case STMP3XXX_BUS_APBX:
+		c = REGS_APBX_BASE + HW_APBX_CHn_NXTCMDAR + 0x70 * ch;
+		s = REGS_APBX_BASE + HW_APBX_CHn_SEMA + 0x70 * ch;
+		break;
+
+	default:
+		return;
+	}
+
+	/* Set next command */
+	__raw_writel(head->handle, c);
+	/* Set counting semaphore (kicks off transfer). Assumes
+	   peripheral has been set up correctly */
+	__raw_writel(semaphore, s);
+}
+EXPORT_SYMBOL(stmp3xxx_dma_go);
+
+int stmp3xxx_dma_running(int channel)
+{
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		return (__raw_readl(REGS_APBH_BASE + HW_APBH_CHn_SEMA +
+			0x70 * STMP3XXX_DMA_CHANNEL(channel))) &
+			    BM_APBH_CHn_SEMA_PHORE;
+
+	case STMP3XXX_BUS_APBX:
+		return (__raw_readl(REGS_APBX_BASE + HW_APBX_CHn_SEMA +
+			0x70 * STMP3XXX_DMA_CHANNEL(channel))) &
+			    BM_APBX_CHn_SEMA_PHORE;
+	default:
+		BUG();
+		return 0;
+	}
+}
+EXPORT_SYMBOL(stmp3xxx_dma_running);
+
+/*
+ * Circular dma chain management
+ */
+void stmp3xxx_dma_free_chain(struct stmp37xx_circ_dma_chain *chain)
+{
+	int i;
+
+	for (i = 0; i < chain->total_count; i++)
+		stmp3xxx_dma_free_command(
+			STMP3XXX_DMA(chain->channel, chain->bus),
+			&chain->chain[i]);
+}
+EXPORT_SYMBOL(stmp3xxx_dma_free_chain);
+
+int stmp3xxx_dma_make_chain(int ch, struct stmp37xx_circ_dma_chain *chain,
+			    struct stmp3xxx_dma_descriptor descriptors[],
+			    unsigned items)
+{
+	int i;
+	int err = 0;
+
+	if (items == 0)
+		return err;
+
+	for (i = 0; i < items; i++) {
+		err = stmp3xxx_dma_allocate_command(ch, &descriptors[i]);
+		if (err) {
+			WARN_ON(err);
+			/*
+			 * Couldn't allocate the whole chain.
+			 * deallocate what has been allocated
+			 */
+			if (i) {
+				do {
+					stmp3xxx_dma_free_command(ch,
+								  &descriptors
+								  [i]);
+				} while (i-- >= 0);
+			}
+			return err;
+		}
+
+		/* link them! */
+		if (i > 0) {
+			descriptors[i - 1].next_descr = &descriptors[i];
+			descriptors[i - 1].command->next =
+						descriptors[i].handle;
+		}
+	}
+
+	/* make list circular */
+	descriptors[items - 1].next_descr = &descriptors[0];
+	descriptors[items - 1].command->next = descriptors[0].handle;
+
+	chain->total_count = items;
+	chain->chain = descriptors;
+	chain->free_index = 0;
+	chain->active_index = 0;
+	chain->cooked_index = 0;
+	chain->free_count = items;
+	chain->active_count = 0;
+	chain->cooked_count = 0;
+	chain->bus = STMP3XXX_DMA_BUS(ch);
+	chain->channel = STMP3XXX_DMA_CHANNEL(ch);
+	return err;
+}
+EXPORT_SYMBOL(stmp3xxx_dma_make_chain);
+
+void stmp37xx_circ_clear_chain(struct stmp37xx_circ_dma_chain *chain)
+{
+	BUG_ON(stmp3xxx_dma_running(STMP3XXX_DMA(chain->channel, chain->bus)));
+	chain->free_index = 0;
+	chain->active_index = 0;
+	chain->cooked_index = 0;
+	chain->free_count = chain->total_count;
+	chain->active_count = 0;
+	chain->cooked_count = 0;
+}
+EXPORT_SYMBOL(stmp37xx_circ_clear_chain);
+
+void stmp37xx_circ_advance_free(struct stmp37xx_circ_dma_chain *chain,
+		unsigned count)
+{
+	BUG_ON(chain->cooked_count < count);
+
+	chain->cooked_count -= count;
+	chain->cooked_index += count;
+	chain->cooked_index %= chain->total_count;
+	chain->free_count += count;
+}
+EXPORT_SYMBOL(stmp37xx_circ_advance_free);
+
+void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain,
+		unsigned count)
+{
+	void __iomem *c;
+	u32 mask_clr, mask;
+	BUG_ON(chain->free_count < count);
+
+	chain->free_count -= count;
+	chain->free_index += count;
+	chain->free_index %= chain->total_count;
+	chain->active_count += count;
+
+	switch (chain->bus) {
+	case STMP3XXX_BUS_APBH:
+		c = REGS_APBH_BASE + HW_APBH_CHn_SEMA + 0x70 * chain->channel;
+		mask_clr = BM_APBH_CHn_SEMA_INCREMENT_SEMA;
+		mask = BF(count, APBH_CHn_SEMA_INCREMENT_SEMA);
+		break;
+	case STMP3XXX_BUS_APBX:
+		c = REGS_APBX_BASE + HW_APBX_CHn_SEMA + 0x70 * chain->channel;
+		mask_clr = BM_APBX_CHn_SEMA_INCREMENT_SEMA;
+		mask = BF(count, APBX_CHn_SEMA_INCREMENT_SEMA);
+		break;
+	default:
+		BUG();
+		return;
+	}
+
+	/* Set counting semaphore (kicks off transfer). Assumes
+	   peripheral has been set up correctly */
+	stmp3xxx_clearl(mask_clr, c);
+	stmp3xxx_setl(mask, c);
+}
+EXPORT_SYMBOL(stmp37xx_circ_advance_active);
+
+unsigned stmp37xx_circ_advance_cooked(struct stmp37xx_circ_dma_chain *chain)
+{
+	unsigned cooked;
+
+	cooked = chain->active_count -
+	  stmp3xxx_dma_read_semaphore(STMP3XXX_DMA(chain->channel, chain->bus));
+
+	chain->active_count -= cooked;
+	chain->active_index += cooked;
+	chain->active_index %= chain->total_count;
+
+	chain->cooked_count += cooked;
+
+	return cooked;
+}
+EXPORT_SYMBOL(stmp37xx_circ_advance_cooked);
+
+void stmp3xxx_dma_set_alt_target(int channel, int function)
+{
+#if defined(CONFIG_ARCH_STMP37XX)
+	unsigned bits = 4;
+#elif defined(CONFIG_ARCH_STMP378X)
+	unsigned bits = 2;
+#else
+#error wrong arch
+#endif
+	int shift = STMP3XXX_DMA_CHANNEL(channel) * bits;
+	unsigned mask = (1<<bits) - 1;
+	void __iomem *c;
+
+	BUG_ON(function < 0 || function >= (1<<bits));
+	pr_debug("%s: channel = %d, using mask %x, "
+		 "shift = %d\n", __func__, channel, mask, shift);
+
+	switch (STMP3XXX_DMA_BUS(channel)) {
+	case STMP3XXX_BUS_APBH:
+		c = REGS_APBH_BASE + HW_APBH_DEVSEL;
+		break;
+	case STMP3XXX_BUS_APBX:
+		c = REGS_APBX_BASE + HW_APBX_DEVSEL;
+		break;
+	default:
+		BUG();
+	}
+	stmp3xxx_clearl(mask << shift, c);
+	stmp3xxx_setl(mask << shift, c);
+}
+EXPORT_SYMBOL(stmp3xxx_dma_set_alt_target);
+
+void stmp3xxx_dma_suspend(void)
+{
+	stmp3xxx_setl(BM_APBH_CTRL0_CLKGATE, REGS_APBH_BASE + HW_APBH_CTRL0);
+	stmp3xxx_setl(BM_APBX_CTRL0_CLKGATE, REGS_APBX_BASE + HW_APBX_CTRL0);
+}
+
+void stmp3xxx_dma_resume(void)
+{
+	stmp3xxx_clearl(BM_APBH_CTRL0_CLKGATE | BM_APBH_CTRL0_SFTRST,
+			REGS_APBH_BASE + HW_APBH_CTRL0);
+	stmp3xxx_clearl(BM_APBX_CTRL0_CLKGATE | BM_APBX_CTRL0_SFTRST,
+			REGS_APBX_BASE + HW_APBX_CTRL0);
+}
+
+#ifdef CONFIG_CPU_FREQ
+
+struct dma_notifier_block {
+	struct notifier_block nb;
+	void *data;
+};
+
+static int dma_cpufreq_notifier(struct notifier_block *self,
+				unsigned long phase, void *p)
+{
+	switch (phase) {
+	case CPUFREQ_POSTCHANGE:
+		stmp3xxx_dma_resume();
+		break;
+
+	case CPUFREQ_PRECHANGE:
+		stmp3xxx_dma_suspend();
+		break;
+
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct dma_notifier_block dma_cpufreq_nb = {
+	.nb = {
+		.notifier_call = dma_cpufreq_notifier,
+	},
+};
+#endif /* CONFIG_CPU_FREQ */
+
+void __init stmp3xxx_dma_init(void)
+{
+	stmp3xxx_clearl(BM_APBH_CTRL0_CLKGATE | BM_APBH_CTRL0_SFTRST,
+			REGS_APBH_BASE + HW_APBH_CTRL0);
+	stmp3xxx_clearl(BM_APBX_CTRL0_CLKGATE | BM_APBX_CTRL0_SFTRST,
+			REGS_APBX_BASE + HW_APBX_CTRL0);
+#ifdef CONFIG_CPU_FREQ
+	cpufreq_register_notifier(&dma_cpufreq_nb.nb,
+				CPUFREQ_TRANSITION_NOTIFIER);
+#endif /* CONFIG_CPU_FREQ */
+}
diff --git a/arch/arm/plat-stmp3xxx/include/mach/clkdev.h b/arch/arm/plat-stmp3xxx/include/mach/clkdev.h
new file mode 100644
index 0000000..f9c3977
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/clkdev.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/cputype.h b/arch/arm/plat-stmp3xxx/include/mach/cputype.h
new file mode 100644
index 0000000..b4e205b
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/cputype.h
@@ -0,0 +1,33 @@
+/*
+ * Freescale STMP37XX/STMP378X CPU type detection
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __ASM_PLAT_CPU_H
+#define __ASM_PLAT_CPU_H
+
+#ifdef CONFIG_ARCH_STMP37XX
+#define cpu_is_stmp37xx()	(1)
+#else
+#define cpu_is_stmp37xx()	(0)
+#endif
+
+#ifdef CONFIG_ARCH_STMP378X
+#define cpu_is_stmp378x()	(1)
+#else
+#define cpu_is_stmp378x()	(0)
+#endif
+
+#endif /* __ASM_PLAT_CPU_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S b/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S
new file mode 100644
index 0000000..fb3b969
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S
@@ -0,0 +1,42 @@
+/*
+ * Debugging macro include header
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+
+		.macro	addruart,rx
+		mrc	p15, 0, \rx, c1, c0
+		tst	\rx, #1			@ MMU enabled?
+		moveq	\rx, #0x80000000	@ physical base address
+		addeq	\rx, \rx, #0x00070000
+		movne	\rx, #0xf0000000	@ virtual base
+		addne	\rx, \rx, #0x00070000
+		.endm
+
+		.macro	senduart,rd,rx
+		strb	\rd, [\rx, #0]		@ data register at 0
+		.endm
+
+		.macro	waituart,rd,rx
+1001:		ldr	\rd, [\rx, #0x18]	@ UARTFLG
+		tst	\rd, #1 << 5		@ UARTFLGUTXFF - 1 when full
+		bne	1001b
+		.endm
+
+		.macro	busyuart,rd,rx
+1001:		ldr	\rd, [\rx, #0x18]	@ UARTFLG
+		tst	\rd, #1 << 3		@ UARTFLGUBUSY - 1 when busy
+		bne	1001b
+		.endm
diff --git a/arch/arm/plat-stmp3xxx/include/mach/dma.h b/arch/arm/plat-stmp3xxx/include/mach/dma.h
new file mode 100644
index 0000000..7c58557
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/dma.h
@@ -0,0 +1,153 @@
+/*
+ * Freescale STMP37XX/STMP378X DMA helper interface
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __ASM_PLAT_STMP3XXX_DMA_H
+#define __ASM_PLAT_STMP3XXX_DMA_H
+
+#include <linux/platform_device.h>
+#include <linux/dmapool.h>
+
+#if !defined(MAX_PIO_WORDS)
+#define MAX_PIO_WORDS   (15)
+#endif
+
+#define STMP3XXX_BUS_APBH		0
+#define STMP3XXX_BUS_APBX		1
+#define STMP3XXX_DMA_MAX_CHANNEL	16
+#define STMP3XXX_DMA_BUS(dma)		((dma) / 16)
+#define STMP3XXX_DMA_CHANNEL(dma)	((dma) % 16)
+#define STMP3XXX_DMA(channel, bus)	((bus) * 16 + (channel))
+#define MAX_DMA_ADDRESS			0xffffffff
+#define MAX_DMA_CHANNELS		32
+
+struct stmp3xxx_dma_command {
+	u32 next;
+	u32 cmd;
+	union {
+		u32 buf_ptr;
+		u32 alternate;
+	};
+	u32 pio_words[MAX_PIO_WORDS];
+};
+
+struct stmp3xxx_dma_descriptor {
+	struct stmp3xxx_dma_command *command;
+	dma_addr_t handle;
+
+	/* The virtual address of the buffer pointer */
+	void *virtual_buf_ptr;
+	/* The next descriptor in a the DMA chain (optional) */
+	struct stmp3xxx_dma_descriptor *next_descr;
+};
+
+struct stmp37xx_circ_dma_chain {
+	unsigned total_count;
+	struct stmp3xxx_dma_descriptor *chain;
+
+	unsigned free_index;
+	unsigned free_count;
+	unsigned active_index;
+	unsigned active_count;
+	unsigned cooked_index;
+	unsigned cooked_count;
+
+	int bus;
+	unsigned channel;
+};
+
+static inline struct stmp3xxx_dma_descriptor
+    *stmp3xxx_dma_circ_get_free_head(struct stmp37xx_circ_dma_chain *chain)
+{
+	return &(chain->chain[chain->free_index]);
+}
+
+static inline struct stmp3xxx_dma_descriptor
+    *stmp3xxx_dma_circ_get_cooked_head(struct stmp37xx_circ_dma_chain *chain)
+{
+	return &(chain->chain[chain->cooked_index]);
+}
+
+int stmp3xxx_dma_request(int ch, struct device *dev, const char *name);
+int stmp3xxx_dma_release(int ch);
+int stmp3xxx_dma_allocate_command(int ch,
+				  struct stmp3xxx_dma_descriptor *descriptor);
+int stmp3xxx_dma_free_command(int ch,
+			      struct stmp3xxx_dma_descriptor *descriptor);
+void stmp3xxx_dma_continue(int channel, u32 semaphore);
+void stmp3xxx_dma_go(int ch, struct stmp3xxx_dma_descriptor *head,
+		     u32 semaphore);
+int stmp3xxx_dma_running(int ch);
+int stmp3xxx_dma_make_chain(int ch, struct stmp37xx_circ_dma_chain *chain,
+			    struct stmp3xxx_dma_descriptor descriptors[],
+			    unsigned items);
+void stmp3xxx_dma_free_chain(struct stmp37xx_circ_dma_chain *chain);
+void stmp37xx_circ_clear_chain(struct stmp37xx_circ_dma_chain *chain);
+void stmp37xx_circ_advance_free(struct stmp37xx_circ_dma_chain *chain,
+		unsigned count);
+void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain,
+		unsigned count);
+unsigned stmp37xx_circ_advance_cooked(struct stmp37xx_circ_dma_chain *chain);
+int stmp3xxx_dma_read_semaphore(int ch);
+void stmp3xxx_dma_init(void);
+void stmp3xxx_dma_set_alt_target(int ch, int target);
+void stmp3xxx_dma_suspend(void);
+void stmp3xxx_dma_resume(void);
+
+/*
+ * STMP37xx and STMP378x have different DMA control
+ * registers layout
+ */
+
+void stmp3xxx_arch_dma_freeze(int ch);
+void stmp3xxx_arch_dma_unfreeze(int ch);
+void stmp3xxx_arch_dma_reset_channel(int ch);
+void stmp3xxx_arch_dma_enable_interrupt(int ch);
+void stmp3xxx_arch_dma_clear_interrupt(int ch);
+int stmp3xxx_arch_dma_is_interrupt(int ch);
+
+static inline void stmp3xxx_dma_reset_channel(int ch)
+{
+	stmp3xxx_arch_dma_reset_channel(ch);
+}
+
+
+static inline void stmp3xxx_dma_freeze(int ch)
+{
+	stmp3xxx_arch_dma_freeze(ch);
+}
+
+static inline void stmp3xxx_dma_unfreeze(int ch)
+{
+	stmp3xxx_arch_dma_unfreeze(ch);
+}
+
+static inline void stmp3xxx_dma_enable_interrupt(int ch)
+{
+	stmp3xxx_arch_dma_enable_interrupt(ch);
+}
+
+static inline void stmp3xxx_dma_clear_interrupt(int ch)
+{
+	stmp3xxx_arch_dma_clear_interrupt(ch);
+}
+
+static inline int stmp3xxx_dma_is_interrupt(int ch)
+{
+	return stmp3xxx_arch_dma_is_interrupt(ch);
+}
+
+#endif /* __ASM_PLAT_STMP3XXX_DMA_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/gpio.h b/arch/arm/plat-stmp3xxx/include/mach/gpio.h
new file mode 100644
index 0000000..a8b5792
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/gpio.h
@@ -0,0 +1,28 @@
+/*
+ * Freescale STMP37XX/STMP378X GPIO interface
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __ASM_PLAT_GPIO_H
+#define __ASM_PLAT_GPIO_H
+
+#define ARCH_NR_GPIOS	(32 * 3)
+#define gpio_to_irq(gpio) __gpio_to_irq(gpio)
+#define gpio_get_value(gpio) __gpio_get_value(gpio)
+#define gpio_set_value(gpio, value) __gpio_set_value(gpio, value)
+
+#include <asm-generic/gpio.h>
+
+#endif /* __ASM_PLAT_GPIO_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/gpmi.h b/arch/arm/plat-stmp3xxx/include/mach/gpmi.h
new file mode 100644
index 0000000..e166432
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/gpmi.h
@@ -0,0 +1,12 @@
+#ifndef __MACH_GPMI_H
+
+#include <linux/mtd/partitions.h>
+#include <mach/regs-gpmi.h>
+
+struct gpmi_platform_data {
+	void *pins;
+	int nr_parts;
+	struct mtd_partition *parts;
+	const char *part_types[];
+};
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/hardware.h b/arch/arm/plat-stmp3xxx/include/mach/hardware.h
new file mode 100644
index 0000000..47b8978
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/hardware.h
@@ -0,0 +1,32 @@
+/*
+ * This file contains the hardware definitions of the Freescale STMP3XXX
+ *
+ * Copyright (C) 2005 Sigmatel Inc
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+/*
+ * Where in virtual memory the IO devices (timers, system controllers
+ * and so on)
+ */
+#define IO_BASE			0xF0000000                 /* VA of IO  */
+#define IO_SIZE			0x00100000                 /* How much? */
+#define IO_START		0x80000000                 /* PA of IO  */
+
+/* macro to get at IO space when running virtually */
+#define IO_ADDRESS(x) (((x) & 0x000fffff) | IO_BASE)
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/io.h b/arch/arm/plat-stmp3xxx/include/mach/io.h
new file mode 100644
index 0000000..d08b1b7
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/io.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2005 Sigmatel Inc
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#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)
+#define __mem_isa(a)	(a)
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/memory.h b/arch/arm/plat-stmp3xxx/include/mach/memory.h
new file mode 100644
index 0000000..7b875a0
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/memory.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Physical DRAM offset.
+ */
+#define PHYS_OFFSET	UL(0x40000000)
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/mmc.h b/arch/arm/plat-stmp3xxx/include/mach/mmc.h
new file mode 100644
index 0000000..ba81e15
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/mmc.h
@@ -0,0 +1,14 @@
+#ifndef _MACH_MMC_H
+#define _MACH_MMC_H
+
+#include <mach/regs-ssp.h>
+
+struct stmp3xxxmmc_platform_data {
+	int (*get_wp)(void);
+	unsigned long (*setclock)(void __iomem *base, unsigned long);
+	void (*cmd_pullup)(int);
+	int  (*hw_init)(void);
+	void (*hw_release)(void);
+};
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/pinmux.h b/arch/arm/plat-stmp3xxx/include/mach/pinmux.h
new file mode 100644
index 0000000..cc5af82
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/pinmux.h
@@ -0,0 +1,157 @@
+/*
+ * Freescale STMP37XX/STMP378X Pin Multiplexing
+ *
+ * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __PINMUX_H
+#define __PINMUX_H
+
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/gpio.h>
+#include <asm-generic/gpio.h>
+
+/* Pin definitions */
+#include "pins.h"
+#include <mach/pins.h>
+
+/*
+ * Each pin may be routed up to four different HW interfaces
+ * including GPIO
+ */
+enum pin_fun {
+	PIN_FUN1 = 0,
+	PIN_FUN2,
+	PIN_FUN3,
+	PIN_GPIO,
+};
+
+/*
+ * Each pin may have different output drive strength in range from
+ * 4mA to 20mA. The most common case is 4, 8 and 12 mA strengths.
+ */
+enum pin_strength {
+	PIN_4MA = 0,
+	PIN_8MA,
+	PIN_12MA,
+	PIN_16MA,
+	PIN_20MA,
+};
+
+/*
+ * Each pin can be programmed for 1.8V or 3.3V
+ */
+enum pin_voltage {
+	PIN_1_8V = 0,
+	PIN_3_3V,
+};
+
+/*
+ * Structure to define a group of pins and their parameters
+ */
+struct pin_desc {
+	unsigned id;
+	enum pin_fun fun;
+	enum pin_strength strength;
+	enum pin_voltage voltage;
+	unsigned pullup:1;
+};
+
+struct pin_group {
+	struct pin_desc *pins;
+	int nr_pins;
+};
+
+/* Set pin drive strength */
+void stmp3xxx_pin_strength(unsigned id, enum pin_strength strength,
+			   const char *label);
+
+/* Set pin voltage */
+void stmp3xxx_pin_voltage(unsigned id, enum pin_voltage voltage,
+			   const char *label);
+
+/* Enable pull-up resistor for a pin */
+void stmp3xxx_pin_pullup(unsigned id, int enable, const char *label);
+
+/*
+ * Request a pin ownership, only one module (identified by @label)
+ * may own a pin.
+ */
+int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, const char *label);
+
+/* Release pin */
+void stmp3xxx_release_pin(unsigned id, const char *label);
+
+void stmp3xxx_set_pin_type(unsigned id, enum pin_fun fun);
+
+/*
+ * Each bank is associated with a number of registers to control
+ * pin function, drive strength, voltage and pull-up reigster. The
+ * number of registers of a given type depends on the number of bits
+ * describin particular pin.
+ */
+#define HW_MUXSEL_NUM		2	/* registers per bank */
+#define HW_MUXSEL_PIN_LEN	2	/* bits per pin */
+#define HW_MUXSEL_PIN_NUM	16	/* pins per register */
+#define HW_MUXSEL_PINFUN_MASK	0x3	/* pin function mask */
+#define HW_MUXSEL_PINFUN_NUM	4	/* four options for a pin */
+
+#define HW_DRIVE_NUM		4	/* registers per bank */
+#define HW_DRIVE_PIN_LEN	4	/* bits per pin */
+#define HW_DRIVE_PIN_NUM	8	/* pins per register */
+#define HW_DRIVE_PINDRV_MASK	0x3	/* pin strength mask - 2 bits */
+#define HW_DRIVE_PINDRV_NUM	5	/* five possible strength values */
+#define HW_DRIVE_PINV_MASK	0x4	/* pin voltage mask - 1 bit */
+
+
+struct stmp3xxx_pinmux_bank {
+	struct gpio_chip chip;
+
+	/* Pins allocation map */
+	unsigned long pin_map;
+
+	/* Pin owner names */
+	const char *pin_labels[32];
+
+	/* Bank registers */
+	void __iomem *hw_muxsel[HW_MUXSEL_NUM];
+	void __iomem *hw_drive[HW_DRIVE_NUM];
+	void __iomem *hw_pull;
+
+	void __iomem *pin2irq,
+		*irqlevel,
+		*irqpolarity,
+		*irqen,
+		*irqstat;
+
+	/* HW MUXSEL register function bit values */
+	u8 functions[HW_MUXSEL_PINFUN_NUM];
+
+	/*
+	 * HW DRIVE register strength bit values:
+	 * 0xff - requested strength is not supported for this bank
+	 */
+	u8 strengths[HW_DRIVE_PINDRV_NUM];
+
+	/* GPIO things */
+	void __iomem *hw_gpio_in,
+		     *hw_gpio_out,
+		     *hw_gpio_doe;
+	int irq, virq;
+};
+
+int __init stmp3xxx_pinmux_init(int virtual_irq_start);
+
+#endif /* __PINMUX_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/pins.h b/arch/arm/plat-stmp3xxx/include/mach/pins.h
new file mode 100644
index 0000000..c573318
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/pins.h
@@ -0,0 +1,30 @@
+/*
+ * Freescale STMP37XX/STMP378X Pin multiplexing interface definitions
+ *
+ * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __ASM_PLAT_PINS_H
+#define __ASM_PLAT_PINS_H
+
+#define STMP3XXX_PINID(bank, pin)	(bank * 32 + pin)
+#define STMP3XXX_PINID_TO_BANK(pinid)	(pinid / 32)
+#define STMP3XXX_PINID_TO_PINNUM(pinid)	(pinid % 32)
+
+/*
+ * Special invalid pin identificator to show a pin doesn't exist
+ */
+#define PINID_NO_PIN	STMP3XXX_PINID(0xFF, 0xFF)
+
+#endif /* __ASM_PLAT_PINS_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/platform.h b/arch/arm/plat-stmp3xxx/include/mach/platform.h
new file mode 100644
index 0000000..7007dda
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/platform.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __ASM_PLAT_PLATFORM_H
+#define __ASM_PLAT_PLATFORM_H
+
+#ifndef __ASSEMBLER__
+#include <linux/io.h>
+#endif
+#include <asm/sizes.h>
+
+/* Virtual address where registers are mapped */
+#define STMP3XXX_REGS_PHBASE	0x80000000
+#ifdef __ASSEMBLER__
+#define STMP3XXX_REGS_BASE	0xF0000000
+#else
+#define STMP3XXX_REGS_BASE	(void __iomem *)0xF0000000
+#endif
+#define STMP3XXX_REGS_SIZE	SZ_1M
+
+/* Virtual address where OCRAM is mapped */
+#define STMP3XXX_OCRAM_PHBASE	0x00000000
+#ifdef __ASSEMBLER__
+#define STMP3XXX_OCRAM_BASE	0xf1000000
+#else
+#define STMP3XXX_OCRAM_BASE	(void __iomem *)0xf1000000
+#endif
+#define STMP3XXX_OCRAM_SIZE	(32 * SZ_1K)
+
+#ifdef CONFIG_ARCH_STMP37XX
+#define IRQ_PRIORITY_REG_RD	HW_ICOLL_PRIORITYn_RD
+#define IRQ_PRIORITY_REG_WR	HW_ICOLL_PRIORITYn_WR
+#endif
+
+#ifdef CONFIG_ARCH_STMP378X
+#define IRQ_PRIORITY_REG_RD	HW_ICOLL_INTERRUPTn_RD
+#define IRQ_PRIORITY_REG_WR	HW_ICOLL_INTERRUPTn_WR
+#endif
+
+#define HW_STMP3XXX_SET		0x04
+#define HW_STMP3XXX_CLR		0x08
+#define HW_STMP3XXX_TOG		0x0c
+
+#ifndef __ASSEMBLER__
+static inline void stmp3xxx_clearl(u32 v, void __iomem *r)
+{
+	__raw_writel(v, r + HW_STMP3XXX_CLR);
+}
+
+static inline void stmp3xxx_setl(u32 v, void __iomem *r)
+{
+	__raw_writel(v, r + HW_STMP3XXX_SET);
+}
+#endif
+
+#define BF(value, field) (((value) << BP_##field) & BM_##field)
+
+#endif /* __ASM_ARCH_PLATFORM_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h b/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h
new file mode 100644
index 0000000..2e300fe
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h
@@ -0,0 +1,54 @@
+/*
+ * Freescale STMP37XX/STMP378X core structure and function declarations
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __ASM_PLAT_STMP3XXX_H
+#define __ASM_PLAT_STMP3XXX_H
+
+#include <linux/irq.h>
+
+extern struct sys_timer stmp3xxx_timer;
+
+void stmp3xxx_init_irq(struct irq_chip *chip);
+void stmp3xxx_init(void);
+int stmp3xxx_reset_block(void __iomem *hwreg, int just_enable);
+extern struct platform_device stmp3xxx_dbguart,
+			      stmp3xxx_appuart,
+			      stmp3xxx_watchdog,
+			      stmp3xxx_touchscreen,
+			      stmp3xxx_keyboard,
+			      stmp3xxx_gpmi,
+			      stmp3xxx_mmc,
+			      stmp3xxx_udc,
+			      stmp3xxx_ehci,
+			      stmp3xxx_rtc,
+			      stmp3xxx_spi1,
+			      stmp3xxx_spi2,
+			      stmp3xxx_backlight,
+			      stmp3xxx_rotdec,
+			      stmp3xxx_dcp,
+			      stmp3xxx_dcp_bootstream,
+			      stmp3xxx_persistent,
+			      stmp3xxx_framebuffer,
+			      stmp3xxx_battery;
+int stmp3xxx_ssp1_device_register(void);
+int stmp3xxx_ssp2_device_register(void);
+
+struct pin_group;
+void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label);
+int stmp3xxx_request_pin_group(struct pin_group *pin_group, const char *label);
+
+#endif /* __ASM_PLAT_STMP3XXX_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/system.h b/arch/arm/plat-stmp3xxx/include/mach/system.h
new file mode 100644
index 0000000..28a9888
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/system.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2005 Sigmatel Inc
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+#include <asm/proc-fns.h>
+#include <mach/platform.h>
+#include <mach/regs-clkctrl.h>
+#include <mach/regs-power.h>
+
+static inline void arch_idle(void)
+{
+	/*
+	 * This should do all the clock switching
+	 * and wait for interrupt tricks
+	 */
+
+	cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+	/* Set BATTCHRG to default value */
+	__raw_writel(0x00010000, REGS_POWER_BASE + HW_POWER_CHARGE);
+
+	/* Set MINPWR to default value   */
+	__raw_writel(0, REGS_POWER_BASE + HW_POWER_MINPWR);
+
+	/* Reset digital side of chip (but not power or RTC) */
+	__raw_writel(BM_CLKCTRL_RESET_DIG,
+			REGS_CLKCTRL_BASE + HW_CLKCTRL_RESET);
+
+	/* Should not return */
+}
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/timex.h b/arch/arm/plat-stmp3xxx/include/mach/timex.h
new file mode 100644
index 0000000..3373985
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/timex.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 1999 ARM Limited
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+
+/*
+ * System time clock is sourced from the 32k clock
+ */
+#define CLOCK_TICK_RATE		(32768)
diff --git a/arch/arm/plat-stmp3xxx/include/mach/uncompress.h b/arch/arm/plat-stmp3xxx/include/mach/uncompress.h
new file mode 100644
index 0000000..f79f5ee
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/uncompress.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef __ASM_PLAT_UNCOMPRESS_H
+#define __ASM_PLAT_UNCOMPRESS_H
+
+/*
+ * Register includes are for when the MMU enabled; we need to define our
+ * own stuff here for pre-MMU use
+ */
+#define UARTDBG_BASE		0x80070000
+#define UART(c)			(((volatile unsigned *)UARTDBG_BASE)[c])
+
+/*
+ * This does not append a newline
+ */
+static void putc(char c)
+{
+	/* Wait for TX fifo empty */
+	while ((UART(6) & (1<<7)) == 0)
+		continue;
+
+	/* Write byte */
+	UART(0) = c;
+
+	/* Wait for last bit to exit the UART */
+	while (UART(6) & (1<<3))
+		continue;
+}
+
+static void flush(void)
+{
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+
+#define arch_decomp_wdog()
+
+#endif /* __ASM_PLAT_UNCOMPRESS_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h b/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h
new file mode 100644
index 0000000..541b880
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define VMALLOC_END       (0xF0000000)
diff --git a/arch/arm/plat-stmp3xxx/irq.c b/arch/arm/plat-stmp3xxx/irq.c
new file mode 100644
index 0000000..20de4e0
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/irq.c
@@ -0,0 +1,51 @@
+/*
+ * Freescale STMP37XX/STMP378X common interrupt handling code
+ *
+ * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/sysdev.h>
+
+#include <mach/stmp3xxx.h>
+#include <mach/platform.h>
+#include <mach/regs-icoll.h>
+
+void __init stmp3xxx_init_irq(struct irq_chip *chip)
+{
+	unsigned int i, lv;
+
+	/* Reset the interrupt controller */
+	stmp3xxx_reset_block(REGS_ICOLL_BASE + HW_ICOLL_CTRL, true);
+
+	/* Disable all interrupts initially */
+	for (i = 0; i < NR_REAL_IRQS; i++) {
+		chip->mask(i);
+		set_irq_chip(i, chip);
+		set_irq_handler(i, handle_level_irq);
+		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+	}
+
+	/* Ensure vector is cleared */
+	for (lv = 0; lv < 4; lv++)
+		__raw_writel(1 << lv, REGS_ICOLL_BASE + HW_ICOLL_LEVELACK);
+	__raw_writel(0, REGS_ICOLL_BASE + HW_ICOLL_VECTOR);
+
+	/* Barrier */
+	(void)__raw_readl(REGS_ICOLL_BASE + HW_ICOLL_STAT);
+}
+
diff --git a/arch/arm/plat-stmp3xxx/pinmux.c b/arch/arm/plat-stmp3xxx/pinmux.c
new file mode 100644
index 0000000..d412003
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/pinmux.c
@@ -0,0 +1,552 @@
+/*
+ * Freescale STMP378X/STMP378X Pin Multiplexing
+ *
+ * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define DEBUG
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sysdev.h>
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <linux/sysdev.h>
+#include <linux/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include <mach/regs-pinctrl.h>
+#include <mach/pins.h>
+#include <mach/pinmux.h>
+
+#define NR_BANKS ARRAY_SIZE(pinmux_banks)
+static struct stmp3xxx_pinmux_bank pinmux_banks[] = {
+	[0] = {
+		.hw_muxsel = {
+			REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL0,
+			REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL1,
+		},
+		.hw_drive = {
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE0,
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE1,
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE2,
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE3,
+		},
+		.hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL0,
+		.functions = { 0x0, 0x1, 0x2, 0x3 },
+		.strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
+
+		.hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN0,
+		.hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT0,
+		.hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE0,
+		.irq = IRQ_GPIO0,
+
+		.pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ0,
+		.irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT0,
+		.irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL0,
+		.irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL0,
+		.irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN0,
+	},
+	[1] = {
+		.hw_muxsel = {
+			REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL2,
+			REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL3,
+		},
+		.hw_drive = {
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE4,
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE5,
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE6,
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE7,
+		},
+		.hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL1,
+		.functions = { 0x0, 0x1, 0x2, 0x3 },
+		.strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
+
+		.hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN1,
+		.hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT1,
+		.hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE1,
+		.irq = IRQ_GPIO1,
+
+		.pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ1,
+		.irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT1,
+		.irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL1,
+		.irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL1,
+		.irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN1,
+	},
+	[2] = {
+	       .hw_muxsel = {
+			REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL4,
+			REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL5,
+		},
+		.hw_drive = {
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE8,
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE9,
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE10,
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE11,
+		},
+		.hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL2,
+		.functions = { 0x0, 0x1, 0x2, 0x3 },
+		.strengths = { 0x0, 0x1, 0x2, 0x1, 0x2 },
+
+		.hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN2,
+		.hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT2,
+		.hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE2,
+		.irq = IRQ_GPIO2,
+
+		.pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ2,
+		.irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT2,
+		.irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL2,
+		.irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL2,
+		.irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN2,
+	},
+	[3] = {
+	       .hw_muxsel = {
+		       REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL6,
+		       REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL7,
+	       },
+	       .hw_drive = {
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE12,
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE13,
+			REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE14,
+			NULL,
+	       },
+	       .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL3,
+	       .functions = {0x0, 0x1, 0x2, 0x3},
+	       .strengths = {0x0, 0x1, 0x2, 0x3, 0xff},
+	},
+};
+
+static inline struct stmp3xxx_pinmux_bank *
+stmp3xxx_pinmux_bank(unsigned id, unsigned *bank, unsigned *pin)
+{
+	unsigned b, p;
+
+	b = STMP3XXX_PINID_TO_BANK(id);
+	p = STMP3XXX_PINID_TO_PINNUM(id);
+	BUG_ON(b >= NR_BANKS);
+	if (bank)
+		*bank = b;
+	if (pin)
+		*pin = p;
+	return &pinmux_banks[b];
+}
+
+/* Check if requested pin is owned by caller */
+static int stmp3xxx_check_pin(unsigned id, const char *label)
+{
+	unsigned pin;
+	struct stmp3xxx_pinmux_bank *pm = stmp3xxx_pinmux_bank(id, NULL, &pin);
+
+	if (!test_bit(pin, &pm->pin_map)) {
+		printk(KERN_WARNING
+		       "%s: Accessing free pin %x, caller %s\n",
+		       __func__, id, label);
+
+		return -EINVAL;
+	}
+
+	if (label && pm->pin_labels[pin] &&
+	    strcmp(label, pm->pin_labels[pin])) {
+		printk(KERN_WARNING
+		       "%s: Wrong pin owner %x, caller %s owner %s\n",
+		       __func__, id, label, pm->pin_labels[pin]);
+
+		return -EINVAL;
+	}
+	return 0;
+}
+
+void stmp3xxx_pin_strength(unsigned id, enum pin_strength strength,
+		const char *label)
+{
+	struct stmp3xxx_pinmux_bank *pbank;
+	void __iomem *hwdrive;
+	u32 shift, val;
+	u32 bank, pin;
+
+	pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
+	pr_debug("%s: label %s bank %d pin %d strength %d\n", __func__, label,
+		 bank, pin, strength);
+
+	hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
+	shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
+	val = pbank->strengths[strength];
+	if (val == 0xff) {
+		printk(KERN_WARNING
+		       "%s: strength is not supported for bank %d, caller %s",
+		       __func__, bank, label);
+		return;
+	}
+
+	if (stmp3xxx_check_pin(id, label))
+		return;
+
+	pr_debug("%s: writing 0x%x to 0x%p register\n", __func__,
+			val << shift, hwdrive);
+	stmp3xxx_clearl(HW_DRIVE_PINDRV_MASK << shift, hwdrive);
+	stmp3xxx_setl(val << shift, hwdrive);
+}
+
+void stmp3xxx_pin_voltage(unsigned id, enum pin_voltage voltage,
+			  const char *label)
+{
+	struct stmp3xxx_pinmux_bank *pbank;
+	void __iomem *hwdrive;
+	u32 shift;
+	u32 bank, pin;
+
+	pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
+	pr_debug("%s: label %s bank %d pin %d voltage %d\n", __func__, label,
+		 bank, pin, voltage);
+
+	hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
+	shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
+
+	if (stmp3xxx_check_pin(id, label))
+		return;
+
+	pr_debug("%s: changing 0x%x bit in 0x%p register\n",
+			__func__, HW_DRIVE_PINV_MASK << shift, hwdrive);
+	if (voltage == PIN_1_8V)
+		stmp3xxx_clearl(HW_DRIVE_PINV_MASK << shift, hwdrive);
+	else
+		stmp3xxx_setl(HW_DRIVE_PINV_MASK << shift, hwdrive);
+}
+
+void stmp3xxx_pin_pullup(unsigned id, int enable, const char *label)
+{
+	struct stmp3xxx_pinmux_bank *pbank;
+	void __iomem *hwpull;
+	u32 bank, pin;
+
+	pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
+	pr_debug("%s: label %s bank %d pin %d enable %d\n", __func__, label,
+		 bank, pin, enable);
+
+	hwpull = pbank->hw_pull;
+
+	if (stmp3xxx_check_pin(id, label))
+		return;
+
+	pr_debug("%s: changing 0x%x bit in 0x%p register\n",
+			__func__, 1 << pin, hwpull);
+	if (enable)
+		stmp3xxx_setl(1 << pin, hwpull);
+	else
+		stmp3xxx_clearl(1 << pin, hwpull);
+}
+
+int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, const char *label)
+{
+	struct stmp3xxx_pinmux_bank *pbank;
+	u32 bank, pin;
+	int ret = 0;
+
+	pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
+	pr_debug("%s: label %s bank %d pin %d fun %d\n", __func__, label,
+		 bank, pin, fun);
+
+	if (test_bit(pin, &pbank->pin_map)) {
+		printk(KERN_WARNING
+		       "%s: CONFLICT DETECTED pin %d:%d caller %s owner %s\n",
+		       __func__, bank, pin, label, pbank->pin_labels[pin]);
+		return -EBUSY;
+	}
+
+	set_bit(pin, &pbank->pin_map);
+	pbank->pin_labels[pin] = label;
+
+	stmp3xxx_set_pin_type(id, fun);
+
+	return ret;
+}
+
+void stmp3xxx_set_pin_type(unsigned id, enum pin_fun fun)
+{
+	struct stmp3xxx_pinmux_bank *pbank;
+	void __iomem *hwmux;
+	u32 shift, val;
+	u32 bank, pin;
+
+	pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
+
+	hwmux = pbank->hw_muxsel[pin / HW_MUXSEL_PIN_NUM];
+	shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
+
+	val = pbank->functions[fun];
+	shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
+	pr_debug("%s: writing 0x%x to 0x%p register\n",
+			__func__, val << shift, hwmux);
+	stmp3xxx_clearl(HW_MUXSEL_PINFUN_MASK << shift, hwmux);
+	stmp3xxx_setl(val << shift, hwmux);
+}
+
+void stmp3xxx_release_pin(unsigned id, const char *label)
+{
+	struct stmp3xxx_pinmux_bank *pbank;
+	u32 bank, pin;
+
+	pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
+	pr_debug("%s: label %s bank %d pin %d\n", __func__, label, bank, pin);
+
+	if (stmp3xxx_check_pin(id, label))
+		return;
+
+	clear_bit(pin, &pbank->pin_map);
+	pbank->pin_labels[pin] = NULL;
+}
+
+int stmp3xxx_request_pin_group(struct pin_group *pin_group, const char *label)
+{
+	struct pin_desc *pin;
+	int p;
+	int err = 0;
+
+	/* Allocate and configure pins */
+	for (p = 0; p < pin_group->nr_pins; p++) {
+		pr_debug("%s: #%d\n", __func__, p);
+		pin = &pin_group->pins[p];
+
+		err = stmp3xxx_request_pin(pin->id, pin->fun, label);
+		if (err)
+			goto out_err;
+
+		stmp3xxx_pin_strength(pin->id, pin->strength, label);
+		stmp3xxx_pin_voltage(pin->id, pin->voltage, label);
+		stmp3xxx_pin_pullup(pin->id, pin->pullup, label);
+	}
+
+	return 0;
+
+out_err:
+	/* Release allocated pins in case of error */
+	while (--p >= 0) {
+		pr_debug("%s: releasing #%d\n", __func__, p);
+		stmp3xxx_release_pin(pin_group->pins[p].id, label);
+	}
+	return err;
+}
+EXPORT_SYMBOL(stmp3xxx_request_pin_group);
+
+void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label)
+{
+	struct pin_desc *pin;
+	int p;
+
+	for (p = 0; p < pin_group->nr_pins; p++) {
+		pin = &pin_group->pins[p];
+		stmp3xxx_release_pin(pin->id, label);
+	}
+}
+EXPORT_SYMBOL(stmp3xxx_release_pin_group);
+
+static int stmp3xxx_irq_to_gpio(int irq,
+	struct stmp3xxx_pinmux_bank **bank, unsigned *gpio)
+{
+	struct stmp3xxx_pinmux_bank *pm;
+
+	for (pm = pinmux_banks; pm < pinmux_banks + NR_BANKS; pm++)
+		if (pm->virq <= irq && irq < pm->virq + 32) {
+			*bank = pm;
+			*gpio = irq - pm->virq;
+			return 0;
+		}
+	return -ENOENT;
+}
+
+static int stmp3xxx_set_irqtype(unsigned irq, unsigned type)
+{
+	struct stmp3xxx_pinmux_bank *pm;
+	unsigned gpio;
+	int l, p;
+
+	stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		l = 0; p = 1; break;
+	case IRQ_TYPE_EDGE_FALLING:
+		l = 0; p = 0; break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		l = 1; p = 1; break;
+	case IRQ_TYPE_LEVEL_LOW:
+		l = 1; p = 0; break;
+	default:
+		pr_debug("%s: Incorrect GPIO interrupt type 0x%x\n",
+				__func__, type);
+		return -ENXIO;
+	}
+
+	if (l)
+		stmp3xxx_setl(1 << gpio, pm->irqlevel);
+	else
+		stmp3xxx_clearl(1 << gpio, pm->irqlevel);
+	if (p)
+		stmp3xxx_setl(1 << gpio, pm->irqpolarity);
+	else
+		stmp3xxx_clearl(1 << gpio, pm->irqpolarity);
+	return 0;
+}
+
+static void stmp3xxx_pin_ack_irq(unsigned irq)
+{
+	u32 stat;
+	struct stmp3xxx_pinmux_bank *pm;
+	unsigned gpio;
+
+	stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
+	stat = __raw_readl(pm->irqstat) & (1 << gpio);
+	stmp3xxx_clearl(stat, pm->irqstat);
+}
+
+static void stmp3xxx_pin_mask_irq(unsigned irq)
+{
+	struct stmp3xxx_pinmux_bank *pm;
+	unsigned gpio;
+
+	stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
+	stmp3xxx_clearl(1 << gpio, pm->irqen);
+	stmp3xxx_clearl(1 << gpio, pm->pin2irq);
+}
+
+static void stmp3xxx_pin_unmask_irq(unsigned irq)
+{
+	struct stmp3xxx_pinmux_bank *pm;
+	unsigned gpio;
+
+	stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
+	stmp3xxx_setl(1 << gpio, pm->irqen);
+	stmp3xxx_setl(1 << gpio, pm->pin2irq);
+}
+
+static inline
+struct stmp3xxx_pinmux_bank *to_pinmux_bank(struct gpio_chip *chip)
+{
+	return container_of(chip, struct stmp3xxx_pinmux_bank, chip);
+}
+
+static int stmp3xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
+	return pm->virq + offset;
+}
+
+static int stmp3xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
+	unsigned v;
+
+	v = __raw_readl(pm->hw_gpio_in) & (1 << offset);
+	return v ? 1 : 0;
+}
+
+static void stmp3xxx_gpio_set(struct gpio_chip *chip, unsigned offset, int v)
+{
+	struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
+
+	if (v)
+		stmp3xxx_setl(1 << offset, pm->hw_gpio_out);
+	else
+		stmp3xxx_clearl(1 << offset, pm->hw_gpio_out);
+}
+
+static int stmp3xxx_gpio_output(struct gpio_chip *chip, unsigned offset, int v)
+{
+	struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
+
+	stmp3xxx_setl(1 << offset, pm->hw_gpio_doe);
+	stmp3xxx_gpio_set(chip, offset, v);
+	return 0;
+}
+
+static int stmp3xxx_gpio_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
+
+	stmp3xxx_clearl(1 << offset, pm->hw_gpio_doe);
+	return 0;
+}
+
+static int stmp3xxx_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	return stmp3xxx_request_pin(chip->base + offset, PIN_GPIO, "gpio");
+}
+
+static void stmp3xxx_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	stmp3xxx_release_pin(chip->base + offset, "gpio");
+}
+
+static void stmp3xxx_gpio_irq(u32 irq, struct irq_desc *desc)
+{
+	struct stmp3xxx_pinmux_bank *pm = get_irq_data(irq);
+	int gpio_irq = pm->virq;
+	u32 stat = __raw_readl(pm->irqstat);
+
+	while (stat) {
+		if (stat & 1)
+			irq_desc[gpio_irq].handle_irq(gpio_irq,
+				&irq_desc[gpio_irq]);
+		gpio_irq++;
+		stat >>= 1;
+	}
+}
+
+static struct irq_chip gpio_irq_chip = {
+	.ack	= stmp3xxx_pin_ack_irq,
+	.mask	= stmp3xxx_pin_mask_irq,
+	.unmask	= stmp3xxx_pin_unmask_irq,
+	.set_type = stmp3xxx_set_irqtype,
+};
+
+int __init stmp3xxx_pinmux_init(int virtual_irq_start)
+{
+	int b, r = 0;
+	struct stmp3xxx_pinmux_bank *pm;
+	int virq;
+
+	for (b = 0; b < 3; b++) {
+		/* only banks 0,1,2 are allowed to GPIO */
+		pm = pinmux_banks + b;
+		pm->chip.base = 32 * b;
+		pm->chip.ngpio = 32;
+		pm->chip.owner = THIS_MODULE;
+		pm->chip.can_sleep = 1;
+		pm->chip.exported = 1;
+		pm->chip.to_irq = stmp3xxx_gpio_to_irq;
+		pm->chip.direction_input = stmp3xxx_gpio_input;
+		pm->chip.direction_output = stmp3xxx_gpio_output;
+		pm->chip.get = stmp3xxx_gpio_get;
+		pm->chip.set = stmp3xxx_gpio_set;
+		pm->chip.request = stmp3xxx_gpio_request;
+		pm->chip.free = stmp3xxx_gpio_free;
+		pm->virq = virtual_irq_start + b * 32;
+
+		for (virq = pm->virq; virq < pm->virq; virq++) {
+			gpio_irq_chip.mask(virq);
+			set_irq_chip(virq, &gpio_irq_chip);
+			set_irq_handler(virq, handle_level_irq);
+			set_irq_flags(virq, IRQF_VALID);
+		}
+		r = gpiochip_add(&pm->chip);
+		if (r < 0)
+			break;
+		set_irq_chained_handler(pm->irq, stmp3xxx_gpio_irq);
+		set_irq_data(pm->irq, pm);
+	}
+	return r;
+}
+
+MODULE_AUTHOR("Vladislav Buzov");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-stmp3xxx/timer.c b/arch/arm/plat-stmp3xxx/timer.c
new file mode 100644
index 0000000..063c7bc
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/timer.c
@@ -0,0 +1,189 @@
+/*
+ * System timer for Freescale STMP37XX/STMP378X
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, 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/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <asm/mach/time.h>
+#include <mach/stmp3xxx.h>
+#include <mach/platform.h>
+#include <mach/regs-timrot.h>
+
+static irqreturn_t
+stmp3xxx_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *c = dev_id;
+
+	/* timer 0 */
+	if (__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0) &
+			BM_TIMROT_TIMCTRLn_IRQ) {
+		stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ,
+				REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
+		c->event_handler(c);
+	}
+
+	/* timer 1 */
+	else if (__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1)
+			& BM_TIMROT_TIMCTRLn_IRQ) {
+		stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ,
+				REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
+		stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ_EN,
+				REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
+		__raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static cycle_t stmp3xxx_clock_read(struct clocksource *cs)
+{
+	return ~((__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1)
+				& 0xFFFF0000) >> 16);
+}
+
+static int
+stmp3xxx_timrot_set_next_event(unsigned long delta,
+		struct clock_event_device *dev)
+{
+	/* reload the timer */
+	__raw_writel(delta, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
+	return 0;
+}
+
+static void
+stmp3xxx_timrot_set_mode(enum clock_event_mode mode,
+		struct clock_event_device *dev)
+{
+}
+
+static struct clock_event_device ckevt_timrot = {
+	.name		= "timrot",
+	.features	= CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 32,
+	.set_next_event	= stmp3xxx_timrot_set_next_event,
+	.set_mode	= stmp3xxx_timrot_set_mode,
+};
+
+static struct clocksource cksrc_stmp3xxx = {
+	.name           = "cksrc_stmp3xxx",
+	.rating         = 250,
+	.read           = stmp3xxx_clock_read,
+	.mask           = CLOCKSOURCE_MASK(16),
+	.shift          = 10,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static struct irqaction stmp3xxx_timer_irq = {
+	.name		= "stmp3xxx_timer",
+	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.handler	= stmp3xxx_timer_interrupt,
+	.dev_id		= &ckevt_timrot,
+};
+
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+static void __init stmp3xxx_init_timer(void)
+{
+	cksrc_stmp3xxx.mult = clocksource_hz2mult(CLOCK_TICK_RATE,
+				cksrc_stmp3xxx.shift);
+	ckevt_timrot.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
+				ckevt_timrot.shift);
+	ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot);
+	ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot);
+	ckevt_timrot.cpumask = cpumask_of(0);
+
+	stmp3xxx_reset_block(REGS_TIMROT_BASE, false);
+
+	/* clear two timers */
+	__raw_writel(0, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
+	__raw_writel(0, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
+
+	/* configure them */
+	__raw_writel(
+		(8 << BP_TIMROT_TIMCTRLn_SELECT) |  /* 32 kHz */
+		BM_TIMROT_TIMCTRLn_RELOAD |
+		BM_TIMROT_TIMCTRLn_UPDATE |
+		BM_TIMROT_TIMCTRLn_IRQ_EN,
+			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
+	__raw_writel(
+		(8 << BP_TIMROT_TIMCTRLn_SELECT) |  /* 32 kHz */
+		BM_TIMROT_TIMCTRLn_RELOAD |
+		BM_TIMROT_TIMCTRLn_UPDATE |
+		BM_TIMROT_TIMCTRLn_IRQ_EN,
+			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
+
+	__raw_writel(CLOCK_TICK_RATE / HZ - 1,
+			REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
+	__raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
+
+	setup_irq(IRQ_TIMER0, &stmp3xxx_timer_irq);
+
+	clocksource_register(&cksrc_stmp3xxx);
+	clockevents_register_device(&ckevt_timrot);
+}
+
+#ifdef CONFIG_PM
+
+void stmp3xxx_suspend_timer(void)
+{
+	stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ_EN | BM_TIMROT_TIMCTRLn_IRQ,
+			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
+	stmp3xxx_setl(BM_TIMROT_ROTCTRL_CLKGATE,
+			REGS_TIMROT_BASE + HW_TIMROT_ROTCTRL);
+}
+
+void stmp3xxx_resume_timer(void)
+{
+	stmp3xxx_clearl(BM_TIMROT_ROTCTRL_SFTRST | BM_TIMROT_ROTCTRL_CLKGATE,
+			REGS_TIMROT_BASE + HW_TIMROT_ROTCTRL);
+	__raw_writel(
+		8 << BP_TIMROT_TIMCTRLn_SELECT |  /* 32 kHz */
+		BM_TIMROT_TIMCTRLn_RELOAD |
+		BM_TIMROT_TIMCTRLn_UPDATE |
+		BM_TIMROT_TIMCTRLn_IRQ_EN,
+			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
+	__raw_writel(
+		8 << BP_TIMROT_TIMCTRLn_SELECT |  /* 32 kHz */
+		BM_TIMROT_TIMCTRLn_RELOAD |
+		BM_TIMROT_TIMCTRLn_UPDATE |
+		BM_TIMROT_TIMCTRLn_IRQ_EN,
+			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
+	__raw_writel(CLOCK_TICK_RATE / HZ - 1,
+			REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
+	__raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
+}
+
+#else
+
+#define stmp3xxx_suspend_timer	NULL
+#define	stmp3xxx_resume_timer	NULL
+
+#endif	/* CONFIG_PM */
+
+struct sys_timer stmp3xxx_timer = {
+	.init		= stmp3xxx_init_timer,
+	.suspend	= stmp3xxx_suspend_timer,
+	.resume		= stmp3xxx_resume_timer,
+};
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index 83c4e38..1aeae38 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -100,6 +100,7 @@
 	beq	no_old_VFP_process
 	VFPFSTMIA r4, r5		@ save the working registers
 	VFPFMRX	r5, FPSCR		@ current status
+#ifndef CONFIG_CPU_FEROCEON
 	tst	r1, #FPEXC_EX		@ is there additional state to save?
 	beq	1f
 	VFPFMRX	r6, FPINST		@ FPINST (only if FPEXC.EX is set)
@@ -107,6 +108,7 @@
 	beq	1f
 	VFPFMRX	r8, FPINST2		@ FPINST2 if needed (and present)
 1:
+#endif
 	stmia	r4, {r1, r5, r6, r8}	@ save FPEXC, FPSCR, FPINST, FPINST2
 					@ and point r4 at the word at the
 					@ start of the register dump
@@ -119,6 +121,7 @@
 	VFPFLDMIA r10, r5		@ reload the working registers while
 					@ FPEXC is in a safe state
 	ldmia	r10, {r1, r5, r6, r8}	@ load FPEXC, FPSCR, FPINST, FPINST2
+#ifndef CONFIG_CPU_FEROCEON
 	tst	r1, #FPEXC_EX		@ is there additional state to restore?
 	beq	1f
 	VFPFMXR	FPINST, r6		@ restore FPINST (only if FPEXC.EX is set)
@@ -126,6 +129,7 @@
 	beq	1f
 	VFPFMXR	FPINST2, r8		@ FPINST2 if needed (and present)
 1:
+#endif
 	VFPFMXR	FPSCR, r5		@ restore status
 
 check_for_exception:
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 01599c4..2d7423a 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -253,12 +253,14 @@
 	}
 
 	if (fpexc & FPEXC_EX) {
+#ifndef CONFIG_CPU_FEROCEON
 		/*
 		 * Asynchronous exception. The instruction is read from FPINST
 		 * and the interrupted instruction has to be restarted.
 		 */
 		trigger = fmrx(FPINST);
 		regs->ARM_pc -= 4;
+#endif
 	} else if (!(fpexc & FPEXC_DEX)) {
 		/*
 		 * Illegal combination of bits. It can be caused by an
diff --git a/arch/avr32/boards/atngw100/Kconfig b/arch/avr32/boards/atngw100/Kconfig
index b3f9947..be27a02 100644
--- a/arch/avr32/boards/atngw100/Kconfig
+++ b/arch/avr32/boards/atngw100/Kconfig
@@ -2,8 +2,15 @@
 
 if BOARD_ATNGW100
 
+choice
+	prompt "Select an NGW100 add-on board to support"
+	default BOARD_ATNGW100_ADDON_NONE
+
+config BOARD_ATNGW100_ADDON_NONE
+	bool "None"
+
 config BOARD_ATNGW100_EVKLCD10X
-	bool "Add support for EVKLCD10X addon board"
+	bool "EVKLCD10X addon board"
 	help
 	  This enables support for the EVKLCD100 (QVGA) or EVKLCD101 (VGA)
 	  addon board for the NGW100. By enabling this the LCD controller and
@@ -14,7 +21,19 @@
 	  The MCI pins can be reenabled by editing the "add device function" but
 	  this may break the setup for other displays that use these pins.
 
-	  Choose 'Y' here if you have a EVKLCD100/101 connected to the NGW100.
+config BOARD_ATNGW100_MRMT
+	bool "Mediama RMT1/2 add-on board"
+	help
+	  This enables support for the Mediama RMT1 or RMT2 board.
+	  RMT provides LCD support, AC97 codec and other
+	  optional peripherals to the Atmel NGW100.
+
+	  This choice disables the detect pin and the write-protect pin for the
+	  MCI platform device, since it conflicts with the LCD platform device.
+	  The MCI pins can be reenabled by editing the "add device function" but
+	  this may break the setup for other displays that use these pins.
+
+endchoice
 
 choice
 	prompt "LCD panel resolution on EVKLCD10X"
@@ -32,4 +51,8 @@
 
 endchoice
 
+if BOARD_ATNGW100_MRMT
+source	"arch/avr32/boards/atngw100/Kconfig_mrmt"
+endif
+
 endif	# BOARD_ATNGW100
diff --git a/arch/avr32/boards/atngw100/Kconfig_mrmt b/arch/avr32/boards/atngw100/Kconfig_mrmt
new file mode 100644
index 0000000..9a199a2
--- /dev/null
+++ b/arch/avr32/boards/atngw100/Kconfig_mrmt
@@ -0,0 +1,80 @@
+# RMT for NGW100 customization
+
+choice
+	prompt "RMT Version"
+	help
+	  Select the RMTx board version.
+
+config BOARD_MRMT_REV1
+	bool "RMT1"
+config BOARD_MRMT_REV2
+	bool "RMT2"
+
+endchoice
+
+config BOARD_MRMT_AC97
+	bool "Enable AC97 CODEC"
+	help
+	  Enable the UCB1400 AC97 CODEC driver.
+
+choice
+	prompt "Touchscreen Driver"
+	default BOARD_MRMT_ADS7846_TS
+
+config BOARD_MRMT_UCB1400_TS
+	bool "Use UCB1400 Touchscreen"
+
+config BOARD_MRMT_ADS7846_TS
+	bool "Use ADS7846 Touchscreen"
+
+endchoice
+
+choice
+	prompt "RMTx LCD Selection"
+	default BOARD_MRMT_LCD_DISABLE
+
+config BOARD_MRMT_LCD_DISABLE
+	bool "LCD Disabled"
+
+config BOARD_MRMT_LCD_LQ043T3DX0X
+	bool "Sharp LQ043T3DX0x or compatible"
+	help
+	  If using RMT2, be sure to load the resistor pack selectors accordingly
+
+if BOARD_MRMT_REV2
+config BOARD_MRMT_LCD_KWH043GM08
+	bool "Formike KWH043GM08 or compatible"
+	help
+	  Be sure to load the RMT2 resistor pack selectors accordingly
+endif
+
+endchoice
+
+if !BOARD_MRMT_LCD_DISABLE
+config BOARD_MRMT_BL_PWM
+	bool "Use PWM control for LCD Backlight"
+	help
+		Use PWM driver for controlling LCD Backlight.
+		Otherwise, LCD Backlight is always on.
+endif
+
+config BOARD_MRMT_RTC_I2C
+	bool "Use External RTC on I2C Bus"
+	help
+		RMT1 has an optional RTC device on the I2C bus.
+		It is a SII S35390A.  Be sure to select the
+		matching RTC driver.
+
+choice
+	prompt "Wireless Module on ttyS2"
+	default BOARD_MRMT_WIRELESS_ZB
+
+config BOARD_MRMT_WIRELESS_ZB
+	bool "Use ZigBee/802.15.4 Module"
+
+config BOARD_MRMT_WIRELESS_BT
+	bool "Use Bluetooth (HCI) Module"
+
+config BOARD_MRMT_WIRELESS_NONE
+	bool "Not Installed"
+endchoice
diff --git a/arch/avr32/boards/atngw100/Makefile b/arch/avr32/boards/atngw100/Makefile
index 6376f53..f4ebe42 100644
--- a/arch/avr32/boards/atngw100/Makefile
+++ b/arch/avr32/boards/atngw100/Makefile
@@ -1,2 +1,3 @@
 obj-y					+= setup.o flash.o
 obj-$(CONFIG_BOARD_ATNGW100_EVKLCD10X)	+= evklcd10x.o
+obj-$(CONFIG_BOARD_ATNGW100_MRMT)	+= mrmt.o
diff --git a/arch/avr32/boards/atngw100/mrmt.c b/arch/avr32/boards/atngw100/mrmt.c
new file mode 100644
index 0000000..bf78e51
--- /dev/null
+++ b/arch/avr32/boards/atngw100/mrmt.c
@@ -0,0 +1,373 @@
+/*
+ * Board-specific setup code for Remote Media Terminal 1 (RMT1)
+ * add-on board for the ATNGW100 Network Gateway
+ *
+ * Copyright (C) 2008 Mediama Technologies
+ * Based on ATNGW100 Network Gateway (Copyright (C) Atmel)
+ *
+ * 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/gpio.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/linkage.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/fb.h>
+#include <linux/leds.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/atmel_serial.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+
+#include <video/atmel_lcdc.h>
+#include <sound/atmel-ac97c.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+
+#include <mach/at32ap700x.h>
+#include <mach/board.h>
+#include <mach/init.h>
+#include <mach/portmux.h>
+
+/* Define board-specifoic GPIO assignments */
+#define PIN_LCD_BL	GPIO_PIN_PA(28)
+#define PWM_CH_BL	0	/* Must match with GPIO pin definition */
+#define PIN_LCD_DISP	GPIO_PIN_PA(31)
+#define	PIN_AC97_RST_N	GPIO_PIN_PA(30)
+#define PB_EXTINT_BASE	25
+#define TS_IRQ		0
+#define PIN_TS_EXTINT	GPIO_PIN_PB(PB_EXTINT_BASE+TS_IRQ)
+#define PIN_PB_LEFT	GPIO_PIN_PB(11)
+#define PIN_PB_RIGHT	GPIO_PIN_PB(12)
+#define PIN_PWR_SW_N	GPIO_PIN_PB(14)
+#define PIN_PWR_ON	GPIO_PIN_PB(13)
+#define PIN_ZB_RST_N	GPIO_PIN_PA(21)
+#define PIN_BT_RST	GPIO_PIN_PA(22)
+#define PIN_LED_SYS	GPIO_PIN_PA(16)
+#define PIN_LED_A	GPIO_PIN_PA(19)
+#define PIN_LED_B	GPIO_PIN_PE(19)
+
+#ifdef CONFIG_BOARD_MRMT_LCD_LQ043T3DX0X
+/* Sharp LQ043T3DX0x (or compatible) panel */
+static struct fb_videomode __initdata lcd_fb_modes[] = {
+	{
+		.name		= "480x272 @ 59.94Hz",
+		.refresh	= 59.94,
+		.xres		= 480,		.yres		= 272,
+		.pixclock	= KHZ2PICOS(9000),
+
+		.left_margin	= 2,		.right_margin	= 2,
+		.upper_margin	= 3,		.lower_margin	= 9,
+		.hsync_len	= 41,		.vsync_len	= 1,
+
+		.sync		= 0,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+};
+
+static struct fb_monspecs __initdata lcd_fb_default_monspecs = {
+	.manufacturer		= "SHA",
+	.monitor		= "LQ043T3DX02",
+	.modedb			= lcd_fb_modes,
+	.modedb_len		= ARRAY_SIZE(lcd_fb_modes),
+	.hfmin			= 14915,
+	.hfmax			= 17638,
+	.vfmin			= 53,
+	.vfmax			= 61,
+	.dclkmax		= 9260000,
+};
+
+static struct atmel_lcdfb_info __initdata rmt_lcdc_data = {
+	.default_bpp		= 24,
+	.default_dmacon		= ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
+	.default_lcdcon2	= (ATMEL_LCDC_DISTYPE_TFT
+				   | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE
+				   | ATMEL_LCDC_INVCLK_NORMAL
+				   | ATMEL_LCDC_MEMOR_BIG),
+	.lcd_wiring_mode	= ATMEL_LCDC_WIRING_RGB,
+	.default_monspecs	= &lcd_fb_default_monspecs,
+	.guard_time		= 2,
+};
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_LCD_KWH043GM08
+/* Sharp KWH043GM08-Fxx (or compatible) panel */
+static struct fb_videomode __initdata lcd_fb_modes[] = {
+	{
+		.name		= "480x272 @ 59.94Hz",
+		.refresh	= 59.94,
+		.xres		= 480,		.yres		= 272,
+		.pixclock	= KHZ2PICOS(9000),
+
+		.left_margin	= 2,		.right_margin	= 2,
+		.upper_margin	= 3,		.lower_margin	= 9,
+		.hsync_len	= 41,		.vsync_len	= 1,
+
+		.sync		= 0,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+};
+
+static struct fb_monspecs __initdata lcd_fb_default_monspecs = {
+	.manufacturer		= "FOR",
+	.monitor		= "KWH043GM08",
+	.modedb			= lcd_fb_modes,
+	.modedb_len		= ARRAY_SIZE(lcd_fb_modes),
+	.hfmin			= 14915,
+	.hfmax			= 17638,
+	.vfmin			= 53,
+	.vfmax			= 61,
+	.dclkmax		= 9260000,
+};
+
+static struct atmel_lcdfb_info __initdata rmt_lcdc_data = {
+	.default_bpp		= 24,
+	.default_dmacon		= ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
+	.default_lcdcon2	= (ATMEL_LCDC_DISTYPE_TFT
+				   | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE
+				   | ATMEL_LCDC_INVCLK_INVERTED
+				   | ATMEL_LCDC_MEMOR_BIG),
+	.lcd_wiring_mode	= ATMEL_LCDC_WIRING_RGB,
+	.default_monspecs	= &lcd_fb_default_monspecs,
+	.guard_time		= 2,
+};
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_AC97
+static struct ac97c_platform_data __initdata ac97c0_data = {
+	.reset_pin		= PIN_AC97_RST_N,
+};
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_UCB1400_TS
+/* NOTE: IRQ assignment relies on kernel module parameter */
+static struct platform_device rmt_ts_device = {
+	.name	= "ucb1400_ts",
+	.id	= -1,
+	}
+};
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_BL_PWM
+/* PWM LEDs: LCD Backlight, etc */
+static struct gpio_led rmt_pwm_led[] = {
+	/* here the "gpio" is actually a PWM channel */
+	{ .name = "backlight",	.gpio = PWM_CH_BL, },
+};
+
+static struct gpio_led_platform_data rmt_pwm_led_data = {
+	.num_leds	= ARRAY_SIZE(rmt_pwm_led),
+	.leds		= rmt_pwm_led,
+};
+
+static struct platform_device rmt_pwm_led_dev = {
+	.name		= "leds-atmel-pwm",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &rmt_pwm_led_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_ADS7846_TS
+static int ads7846_pendown_state(void)
+{
+	return !gpio_get_value( PIN_TS_EXTINT );	/* PENIRQ.*/
+}
+
+static struct ads7846_platform_data ads_info = {
+	.model				= 7846,
+	.keep_vref_on			= 0,	/* Use external VREF pin */
+	.vref_delay_usecs		= 0,
+	.vref_mv			= 3300,	/* VREF = 3.3V */
+	.settle_delay_usecs		= 800,
+	.penirq_recheck_delay_usecs	= 800,
+	.x_plate_ohms			= 750,
+	.y_plate_ohms			= 300,
+	.pressure_max			= 4096,
+	.debounce_max			= 1,
+	.debounce_rep			= 0,
+	.debounce_tol			= (~0),
+	.get_pendown_state		= ads7846_pendown_state,
+	.filter				= NULL,
+	.filter_init			= NULL,
+};
+
+static struct spi_board_info spi01_board_info[] __initdata = {
+	{
+		.modalias	= "ads7846",
+		.max_speed_hz	= 31250*26,
+		.bus_num	= 0,
+		.chip_select	= 1,
+		.platform_data	= &ads_info,
+		.irq		= AT32_EXTINT(TS_IRQ),
+	},
+};
+#endif
+
+/* GPIO Keys: left, right, power, etc */
+static const struct gpio_keys_button rmt_gpio_keys_buttons[] = {
+	[0] = {
+		.type		= EV_KEY,
+		.code		= KEY_POWER,
+		.gpio		= PIN_PWR_SW_N,
+		.active_low	= 1,
+		.desc		= "power button",
+	},
+	[1] = {
+		.type		= EV_KEY,
+		.code		= KEY_LEFT,
+		.gpio		= PIN_PB_LEFT,
+		.active_low	= 1,
+		.desc		= "left button",
+	},
+	[2] = {
+		.type		= EV_KEY,
+		.code		= KEY_RIGHT,
+		.gpio		= PIN_PB_RIGHT,
+		.active_low	= 1,
+		.desc		= "right button",
+	},
+};
+
+static const struct gpio_keys_platform_data rmt_gpio_keys_data = {
+	.nbuttons =	ARRAY_SIZE(rmt_gpio_keys_buttons),
+	.buttons =	(void *) rmt_gpio_keys_buttons,
+};
+
+static struct platform_device rmt_gpio_keys = {
+	.name =		"gpio-keys",
+	.id =		-1,
+	.dev = {
+		.platform_data = (void *) &rmt_gpio_keys_data,
+	}
+};
+
+#ifdef CONFIG_BOARD_MRMT_RTC_I2C
+static struct i2c_board_info __initdata mrmt1_i2c_rtc = {
+	I2C_BOARD_INFO("s35390a", 0x30),
+	.irq		= 0,
+};
+#endif
+
+static void mrmt_power_off(void)
+{
+	/* PWR_ON=0 will force power off */
+	gpio_set_value( PIN_PWR_ON, 0 );
+}
+
+static int __init mrmt1_init(void)
+{
+	gpio_set_value( PIN_PWR_ON, 1 );	/* Ensure PWR_ON is enabled */
+
+	pm_power_off = mrmt_power_off;
+
+	/* Setup USARTS (other than console) */
+	at32_map_usart(2, 1, 0);	/* USART 2: /dev/ttyS1, RMT1:DB9M */
+	at32_map_usart(3, 2, ATMEL_USART_RTS | ATMEL_USART_CTS);
+			/* USART 3: /dev/ttyS2, RMT1:Wireless, w/ RTS/CTS */
+	at32_add_device_usart(1);
+	at32_add_device_usart(2);
+
+	/* Select GPIO Key pins */
+	at32_select_gpio( PIN_PWR_SW_N, AT32_GPIOF_DEGLITCH);
+	at32_select_gpio( PIN_PB_LEFT, AT32_GPIOF_DEGLITCH);
+	at32_select_gpio( PIN_PB_RIGHT, AT32_GPIOF_DEGLITCH);
+	platform_device_register(&rmt_gpio_keys);
+
+#ifdef CONFIG_BOARD_MRMT_RTC_I2C
+	i2c_register_board_info(0, &mrmt1_i2c_rtc, 1);
+#endif
+
+#ifndef CONFIG_BOARD_MRMT_LCD_DISABLE
+	/* User "alternate" LCDC inferface on Port E & D */
+	/* NB: exclude LCDC_CC pin, as NGW100 reserves it for other use */
+	at32_add_device_lcdc(0, &rmt_lcdc_data,
+		fbmem_start, fbmem_size,
+		(ATMEL_LCDC_ALT_24BIT | ATMEL_LCDC_PE_DVAL ) );
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_AC97
+	at32_add_device_ac97c(0, &ac97c0_data, AC97C_BOTH);
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_ADS7846_TS
+	/* Select the Touchscreen interrupt pin mode */
+	at32_select_periph( GPIO_PIOB_BASE, 1 << (PB_EXTINT_BASE+TS_IRQ),
+			GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
+	set_irq_type( AT32_EXTINT(TS_IRQ), IRQ_TYPE_EDGE_FALLING );
+	spi_register_board_info(spi01_board_info,ARRAY_SIZE(spi01_board_info));
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_UCB1400_TS
+	/* Select the Touchscreen interrupt pin mode */
+	at32_select_periph( GPIO_PIOB_BASE, 1 << (PB_EXTINT_BASE+TS_IRQ),
+			GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
+	platform_device_register(&rmt_ts_device);
+#endif
+
+	at32_select_gpio( PIN_LCD_DISP, AT32_GPIOF_OUTPUT );
+	gpio_request( PIN_LCD_DISP, "LCD_DISP" );
+	gpio_direction_output( PIN_LCD_DISP, 0 );	/* LCD DISP */
+#ifdef CONFIG_BOARD_MRMT_LCD_DISABLE
+	/* Keep Backlight and DISP off */
+	at32_select_gpio( PIN_LCD_BL, AT32_GPIOF_OUTPUT );
+	gpio_request( PIN_LCD_BL, "LCD_BL" );
+	gpio_direction_output( PIN_LCD_BL, 0 );		/* Backlight */
+#else
+	gpio_set_value( PIN_LCD_DISP, 1 );	/* DISP asserted first */
+#ifdef CONFIG_BOARD_MRMT_BL_PWM
+	/* Use PWM for Backlight controls */
+	at32_add_device_pwm(1 << PWM_CH_BL);
+	platform_device_register(&rmt_pwm_led_dev);
+#else
+	/* Backlight always on */
+	udelay( 1 );
+	at32_select_gpio( PIN_LCD_BL, AT32_GPIOF_OUTPUT );
+	gpio_request( PIN_LCD_BL, "LCD_BL" );
+	gpio_direction_output( PIN_LCD_BL, 1 );
+#endif
+#endif
+
+	/* Make sure BT and Zigbee modules in reset */
+	at32_select_gpio( PIN_BT_RST, AT32_GPIOF_OUTPUT );
+	gpio_request( PIN_BT_RST, "BT_RST" );
+	gpio_direction_output( PIN_BT_RST, 1 );
+	/* BT Module in Reset */
+
+	at32_select_gpio( PIN_ZB_RST_N, AT32_GPIOF_OUTPUT );
+	gpio_request( PIN_ZB_RST_N, "ZB_RST_N" );
+	gpio_direction_output( PIN_ZB_RST_N, 0 );
+	/* XBee Module in Reset */
+
+#ifdef CONFIG_BOARD_MRMT_WIRELESS_ZB
+	udelay( 1000 );
+	/* Unreset the XBee Module */
+	gpio_set_value( PIN_ZB_RST_N, 1 );
+#endif
+#ifdef CONFIG_BOARD_MRMT_WIRELESS_BT
+	udelay( 1000 );
+	/* Unreset the BT Module */
+	gpio_set_value( PIN_BT_RST, 0 );
+#endif
+
+	return 0;
+}
+arch_initcall(mrmt1_init);
+
+static int __init mrmt1_early_init(void)
+{
+	/* To maintain power-on signal in case boot loader did not already */
+	at32_select_gpio( PIN_PWR_ON, AT32_GPIOF_OUTPUT );
+	gpio_request( PIN_PWR_ON, "PIN_PWR_ON" );
+	gpio_direction_output( PIN_PWR_ON, 1 );
+
+	return 0;
+}
+core_initcall(mrmt1_early_init);
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index 5b022aa..bc299fb 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -56,8 +56,13 @@
 static struct mci_platform_data __initdata mci0_data = {
 	.slot[0] = {
 		.bus_width	= 4,
+#if defined(CONFIG_BOARD_ATNGW100_EVKLCD10X) || defined(CONFIG_BOARD_ATNGW100_MRMT1)
+		.detect_pin     = GPIO_PIN_NONE,
+		.wp_pin         = GPIO_PIN_NONE,
+#else
 		.detect_pin	= GPIO_PIN_PC(25),
 		.wp_pin		= GPIO_PIN_PE(0),
+#endif
 	},
 };
 
diff --git a/arch/avr32/boards/merisc/setup.c b/arch/avr32/boards/merisc/setup.c
index 20b300c..623b077 100644
--- a/arch/avr32/boards/merisc/setup.c
+++ b/arch/avr32/boards/merisc/setup.c
@@ -94,9 +94,10 @@
 
 static struct mci_platform_data __initdata mci0_data = {
 	.slot[0] = {
-		.bus_width	= 4,
-		.detect_pin	= GPIO_PIN_PE(19),
-		.wp_pin		= GPIO_PIN_PE(20),
+		.bus_width		= 4,
+		.detect_pin		= GPIO_PIN_PE(19),
+		.wp_pin			= GPIO_PIN_PE(20),
+		.detect_is_active_high	= true,
 	},
 };
 
diff --git a/arch/avr32/boards/mimc200/setup.c b/arch/avr32/boards/mimc200/setup.c
index c1b2175..523d8e1 100644
--- a/arch/avr32/boards/mimc200/setup.c
+++ b/arch/avr32/boards/mimc200/setup.c
@@ -43,16 +43,16 @@
 /* Initialized by bootloader-specific startup code. */
 struct tag *bootloader_tags __initdata;
 
-static struct fb_videomode __initdata tx14d14_modes[] = {
+static struct fb_videomode __initdata pt0434827_modes[] = {
 	{
-		.name		= "640x480 @ 60",
-		.refresh	= 60,
-		.xres		= 640,		.yres		= 480,
-		.pixclock	= KHZ2PICOS(11666),
+		.name		= "480x272 @ 72",
+		.refresh	= 72,
+		.xres		= 480,		.yres		= 272,
+		.pixclock	= KHZ2PICOS(10000),
 
-		.left_margin	= 80,		.right_margin	= 1,
-		.upper_margin	= 13,		.lower_margin	= 2,
-		.hsync_len	= 64,		.vsync_len	= 1,
+		.left_margin	= 1,		.right_margin	= 1,
+		.upper_margin	= 12,		.lower_margin	= 1,
+		.hsync_len	= 42,		.vsync_len	= 1,
 
 		.sync		= 0,
 		.vmode		= FB_VMODE_NONINTERLACED,
@@ -60,14 +60,14 @@
 };
 
 static struct fb_monspecs __initdata mimc200_default_monspecs = {
-	.manufacturer		= "HIT",
-	.monitor		= "TX14D14VM1BAB",
-	.modedb			= tx14d14_modes,
-	.modedb_len		= ARRAY_SIZE(tx14d14_modes),
+	.manufacturer		= "PT",
+	.monitor		= "PT0434827-A401",
+	.modedb			= pt0434827_modes,
+	.modedb_len		= ARRAY_SIZE(pt0434827_modes),
 	.hfmin			= 14820,
 	.hfmax			= 22230,
 	.vfmin			= 60,
-	.vfmax			= 73.3,
+	.vfmax			= 85,
 	.dclkmax		= 25200000,
 };
 
@@ -228,7 +228,8 @@
 	i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info));
 
 	at32_add_device_lcdc(0, &mimc200_lcdc_data,
-			     fbmem_start, fbmem_size, 1);
+			     fbmem_start, fbmem_size,
+			     ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_CONTROL | ATMEL_LCDC_ALT_24B_DATA);
 
 	return 0;
 }
diff --git a/arch/avr32/configs/atngw100_mrmt_defconfig b/arch/avr32/configs/atngw100_mrmt_defconfig
new file mode 100644
index 0000000..17b0307
--- /dev/null
+++ b/arch/avr32/configs/atngw100_mrmt_defconfig
@@ -0,0 +1,1363 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc1
+# Wed Jun  3 00:24:53 2009
+#
+CONFIG_AVR32=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_SLUB_DEBUG is not set
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_CLK=y
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=1
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# System Type and features
+#
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_SUBARCH_AVR32B=y
+CONFIG_MMU=y
+CONFIG_PERFORMANCE_COUNTERS=y
+CONFIG_PLATFORM_AT32AP=y
+CONFIG_CPU_AT32AP700X=y
+CONFIG_CPU_AT32AP7000=y
+# CONFIG_BOARD_ATSTK1000 is not set
+CONFIG_BOARD_ATNGW100=y
+# CONFIG_BOARD_HAMMERHEAD is not set
+# CONFIG_BOARD_FAVR_32 is not set
+# CONFIG_BOARD_MERISC is not set
+# CONFIG_BOARD_MIMC200 is not set
+# CONFIG_BOARD_ATNGW100_ADDON_NONE is not set
+# CONFIG_BOARD_ATNGW100_EVKLCD10X is not set
+CONFIG_BOARD_ATNGW100_MRMT=y
+CONFIG_BOARD_MRMT_REV1=y
+# CONFIG_BOARD_MRMT_REV2 is not set
+CONFIG_BOARD_MRMT_AC97=y
+# CONFIG_BOARD_MRMT_UCB1400_TS is not set
+CONFIG_BOARD_MRMT_ADS7846_TS=y
+# CONFIG_BOARD_MRMT_LCD_DISABLE is not set
+CONFIG_BOARD_MRMT_LCD_LQ043T3DX0X=y
+# CONFIG_BOARD_MRMT_LCD_KWH043GM08 is not set
+CONFIG_BOARD_MRMT_BL_PWM=y
+CONFIG_BOARD_MRMT_RTC_I2C=y
+CONFIG_BOARD_MRMT_WIRELESS_ZB=y
+# CONFIG_BOARD_MRMT_WIRELESS_BT is not set
+# CONFIG_BOARD_MRMT_WIRELESS_NONE is not set
+CONFIG_LOADER_U_BOOT=y
+
+#
+# Atmel AVR32 AP options
+#
+# CONFIG_AP700X_32_BIT_SMC is not set
+CONFIG_AP700X_16_BIT_SMC=y
+# CONFIG_AP700X_8_BIT_SMC is not set
+CONFIG_LOAD_ADDRESS=0x10000000
+CONFIG_ENTRY_ADDRESS=0x90000000
+CONFIG_PHYS_OFFSET=0x10000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_QUICKLIST=y
+# CONFIG_HAVE_ARCH_BOOTMEM is not set
+# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
+# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# CONFIG_ARCH_SPARSEMEM_ENABLE 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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_OWNERSHIP_TRACE is not set
+# CONFIG_NMI_DEBUGGING is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_CMDLINE=""
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_SUSPEND is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_AT32AP=y
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# 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=y
+CONFIG_INET_TCP_DIAG=y
+# 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_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+# CONFIG_BT_SCO is not set
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+# CONFIG_BT_BNEP is not set
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIBTSDIO is not set
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+# CONFIG_BT_HCIUART_LL is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_DATAFLASH=y
+# CONFIG_MTD_DATAFLASH_WRITE_VERIFY is not set
+# CONFIG_MTD_DATAFLASH_OTP is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+CONFIG_ATMEL_PWM=y
+# CONFIG_ATMEL_TCLIB is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ATMEL_SSC is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# 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_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+CONFIG_COMPAT_NET_DEV_OPS=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+CONFIG_MACB=y
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=m
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_WM97XX is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_ATMEL_PDC=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_GPIO=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_ATMEL=y
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+
+#
+# SPI Protocol Masters
+#
+CONFIG_SPI_SPIDEV=y
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT32AP700X_WDT=y
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_ATMEL=y
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_ATMEL_LCDC is not set
+# CONFIG_BACKLIGHT_ATMEL_PWM is not set
+CONFIG_BACKLIGHT_GENERIC=y
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_LOGO is not set
+CONFIG_SOUND=m
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_AC97_POWER_SAVE is not set
+
+#
+# Atmel devices (AVR32 and AT91)
+#
+# CONFIG_SND_ATMEL_ABDAC is not set
+CONFIG_SND_ATMEL_AC97C=m
+# CONFIG_SND_SPI is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_HID_PID is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_APPLE is not set
+CONFIG_USB_SUPPORT=y
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG is not set
+CONFIG_USB_GADGET_DEBUG_FILES=y
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+CONFIG_USB_GADGET_ATMEL_USBA=y
+CONFIG_USB_ATMEL_USBA=m
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_ATMELMCI=y
+# CONFIG_MMC_ATMELMCI_DMA is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_ATMEL_PWM=y
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_BD2802 is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=m
+CONFIG_RTC_CLASS=m
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+CONFIG_RTC_DRV_S35390A=m
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_AT32AP700X=m
+CONFIG_DMADEVICES=y
+
+#
+# DMA Devices
+#
+CONFIG_DW_DMAC=y
+CONFIG_DMA_ENGINE=y
+
+#
+# DMA Clients
+#
+# CONFIG_NET_DMA is not set
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_DMATEST is not set
+# CONFIG_AUXDISPLAY is not set
+CONFIG_UIO=y
+# CONFIG_UIO_PDRV is not set
+# CONFIG_UIO_PDRV_GENIRQ is not set
+# CONFIG_UIO_SMX is not set
+# CONFIG_UIO_SERCOS3 is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=850
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=y
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL 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=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_SAMPLES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/avr32/include/asm/atomic.h b/arch/avr32/include/asm/atomic.h
index 3188151..b131c27 100644
--- a/arch/avr32/include/asm/atomic.h
+++ b/arch/avr32/include/asm/atomic.h
@@ -196,6 +196,6 @@
 #define smp_mb__before_atomic_inc()	barrier()
 #define smp_mb__after_atomic_inc()	barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 
 #endif /*  __ASM_AVR32_ATOMIC_H */
diff --git a/arch/avr32/include/asm/bitsperlong.h b/arch/avr32/include/asm/bitsperlong.h
new file mode 100644
index 0000000..6dc0bb0
--- /dev/null
+++ b/arch/avr32/include/asm/bitsperlong.h
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
diff --git a/arch/avr32/include/asm/hw_irq.h b/arch/avr32/include/asm/hw_irq.h
index 218b0a6..a36f9fc 100644
--- a/arch/avr32/include/asm/hw_irq.h
+++ b/arch/avr32/include/asm/hw_irq.h
@@ -1,7 +1,7 @@
 #ifndef __ASM_AVR32_HW_IRQ_H
 #define __ASM_AVR32_HW_IRQ_H
 
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
+static inline void hw_resend_irq(struct irq_chip *h, unsigned int i)
 {
 	/* Nothing to do */
 }
diff --git a/arch/avr32/include/asm/mman.h b/arch/avr32/include/asm/mman.h
index 648f91e..9a92b15 100644
--- a/arch/avr32/include/asm/mman.h
+++ b/arch/avr32/include/asm/mman.h
@@ -1,7 +1,7 @@
 #ifndef __ASM_AVR32_MMAN_H__
 #define __ASM_AVR32_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
diff --git a/arch/avr32/include/asm/signal.h b/arch/avr32/include/asm/signal.h
index caffefe..8790dfc 100644
--- a/arch/avr32/include/asm/signal.h
+++ b/arch/avr32/include/asm/signal.h
@@ -112,7 +112,7 @@
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/arch/avr32/include/asm/termios.h b/arch/avr32/include/asm/termios.h
index 0152aba..dd7e9da 100644
--- a/arch/avr32/include/asm/termios.h
+++ b/arch/avr32/include/asm/termios.h
@@ -55,7 +55,7 @@
 */
 #define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
 
-#include <asm-generic/termios.h>
+#include <asm-generic/termios-base.h>
 
 #endif	/* __KERNEL__ */
 
diff --git a/arch/avr32/kernel/module.c b/arch/avr32/kernel/module.c
index 1167fe9c..98f94d0 100644
--- a/arch/avr32/kernel/module.c
+++ b/arch/avr32/kernel/module.c
@@ -32,8 +32,6 @@
 	mod->arch.syminfo = NULL;
 
 	vfree(module_region);
-	/* FIXME: if module_region == mod->init_region, trim exception
-	 * table entries. */
 }
 
 static inline int check_rela(Elf32_Rela *rela, struct module *module,
diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
index d547c8d..6e3d491 100644
--- a/arch/avr32/kernel/traps.c
+++ b/arch/avr32/kernel/traps.c
@@ -75,8 +75,17 @@
 {
 	siginfo_t info;
 
-	if (!user_mode(regs))
+	if (!user_mode(regs)) {
+		const struct exception_table_entry *fixup;
+
+		/* Are we prepared to handle this kernel fault? */
+		fixup = search_exception_tables(regs->pc);
+		if (fixup) {
+			regs->pc = fixup->fixup;
+			return;
+		}
 		die("Unhandled exception in kernel mode", regs, signr);
+	}
 
 	memset(&info, 0, sizeof(info));
 	info.si_signo = signr;
diff --git a/arch/avr32/mach-at32ap/include/mach/board.h b/arch/avr32/mach-at32ap/include/mach/board.h
index 0b81642..ddedb47 100644
--- a/arch/avr32/mach-at32ap/include/mach/board.h
+++ b/arch/avr32/mach-at32ap/include/mach/board.h
@@ -29,7 +29,7 @@
 /* Flags for selecting USART extra pins */
 #define	ATMEL_USART_RTS		0x01
 #define	ATMEL_USART_CTS		0x02
-#define	ATMEL_USART_CLK		0x03
+#define	ATMEL_USART_CLK		0x04
 
 struct atmel_uart_data {
 	short		use_dma_tx;	/* use transmit DMA? */
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index bc9ce89..a60cfe7 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -223,6 +223,7 @@
 
 config SMP
 	depends on BF561
+	select GENERIC_TIME
 	bool "Symmetric multi-processing support"
 	---help---
 	  This enables support for systems with more than one CPU,
@@ -241,12 +242,6 @@
 	depends on SMP
 	default y
 
-config TICK_SOURCE_SYSTMR0
-	bool
-	select BFIN_GPTIMERS
-	depends on SMP
-	default y
-
 config BF_REV_MIN
 	int
 	default 0 if (BF51x || BF52x || (BF54x && !BF54xM))
@@ -263,8 +258,8 @@
 
 choice
 	prompt "Silicon Rev"
-	default BF_REV_0_1 if (BF51x || BF52x || (BF54x && !BF54xM))
-	default BF_REV_0_2 if (BF534 || BF536 || BF537)
+	default BF_REV_0_0 if (BF51x || BF52x)
+	default BF_REV_0_2 if (BF534 || BF536 || BF537 || (BF54x && !BF54xM))
 	default BF_REV_0_3 if (BF531 || BF532 || BF533 || BF54xM || BF561)
 
 config BF_REV_0_0
@@ -607,7 +602,6 @@
 
 config GENERIC_TIME
 	bool "Generic time"
-	depends on !SMP
 	default y
 
 config GENERIC_CLOCKEVENTS
@@ -615,12 +609,26 @@
 	depends on GENERIC_TIME
 	default y
 
+choice
+	prompt "Kernel Tick Source"
+	depends on GENERIC_CLOCKEVENTS
+	default TICKSOURCE_CORETMR
+
+config TICKSOURCE_GPTMR0
+	bool "Gptimer0 (SCLK domain)"
+	select BFIN_GPTIMERS
+	depends on !IPIPE
+
+config TICKSOURCE_CORETMR
+	bool "Core timer (CCLK domain)"
+
+endchoice
+
 config CYCLES_CLOCKSOURCE
-	bool "Use 'CYCLES' as a clocksource (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
+	bool "Use 'CYCLES' as a clocksource"
 	depends on GENERIC_CLOCKEVENTS
 	depends on !BFIN_SCRATCH_REG_CYCLES
-	default n
+	depends on !SMP
 	help
 	  If you say Y here, you will enable support for using the 'cycles'
 	  registers as a clock source.  Doing so means you will be unable to
@@ -628,6 +636,11 @@
 	  still be able to read it (such as for performance monitoring), but
 	  writing the registers will most likely crash the kernel.
 
+config GPTMR0_CLOCKSOURCE
+	bool "Use GPTimer0 as a clocksource (higher rating)"
+	depends on GENERIC_CLOCKEVENTS
+	depends on !TICKSOURCE_GPTMR0
+
 source kernel/time/Kconfig
 
 comment "Misc"
@@ -808,7 +821,7 @@
 config EXCEPTION_L1_SCRATCH
 	bool "Locate exception stack in L1 Scratch Memory"
 	default n
-	depends on !APP_STACK_L1 && !SYSCALL_TAB_L1
+	depends on !APP_STACK_L1
 	help
 	  Whenever an exception occurs, use the L1 Scratch memory for
 	  stack storage.  You cannot place the stacks of FLAT binaries
@@ -901,7 +914,7 @@
 	bool "Enable Instruction Cache Locking"
 
 choice
-	prompt "Policy"
+	prompt "External memory cache policy"
 	depends on BFIN_DCACHE
 	default BFIN_WB if !SMP
 	default BFIN_WT if SMP
@@ -942,12 +955,22 @@
 
 endchoice
 
-config BFIN_L2_CACHEABLE
-	bool "Cache L2 SRAM"
-	depends on (BFIN_DCACHE || BFIN_ICACHE) && (BF54x || (BF561 && !SMP))
-	default n
-	help
-	  Select to make L2 SRAM cacheable in L1 data and instruction cache.
+choice
+	prompt "L2 SRAM cache policy"
+	depends on (BF54x || BF561)
+	default BFIN_L2_WT
+config BFIN_L2_WB
+	bool "Write back"
+	depends on !SMP
+
+config BFIN_L2_WT
+	bool "Write through"
+	depends on !SMP
+
+config BFIN_L2_NOT_CACHED
+	bool "Not cached"
+
+endchoice
 
 config MPU
 	bool "Enable the memory protection unit (EXPERIMENTAL)"
@@ -1011,21 +1034,34 @@
 
 menu "EBIU_AMBCTL Control"
 config BANK_0
-	hex "Bank 0"
+	hex "Bank 0 (AMBCTL0.L)"
 	default 0x7BB0
+	help
+	  These are the low 16 bits of the EBIU_AMBCTL0 MMR which are
+	  used to control the Asynchronous Memory Bank 0 settings.
 
 config BANK_1
-	hex "Bank 1"
+	hex "Bank 1 (AMBCTL0.H)"
 	default 0x7BB0
 	default 0x5558 if BF54x
+	help
+	  These are the high 16 bits of the EBIU_AMBCTL0 MMR which are
+	  used to control the Asynchronous Memory Bank 1 settings.
 
 config BANK_2
-	hex "Bank 2"
+	hex "Bank 2 (AMBCTL1.L)"
 	default 0x7BB0
+	help
+	  These are the low 16 bits of the EBIU_AMBCTL1 MMR which are
+	  used to control the Asynchronous Memory Bank 2 settings.
 
 config BANK_3
-	hex "Bank 3"
+	hex "Bank 3 (AMBCTL1.H)"
 	default 0x99B3
+	help
+	  These are the high 16 bits of the EBIU_AMBCTL1 MMR which are
+	  used to control the Asynchronous Memory Bank 3 settings.
+
 endmenu
 
 config EBIU_MBSCTLVAL
diff --git a/arch/blackfin/Kconfig.debug b/arch/blackfin/Kconfig.debug
index 79e7e63..1fc4981 100644
--- a/arch/blackfin/Kconfig.debug
+++ b/arch/blackfin/Kconfig.debug
@@ -54,6 +54,19 @@
 	  hardware error interrupts and need to know where they are coming
 	  from.
 
+config EXACT_HWERR
+	bool "Try to make Hardware errors exact"
+	depends on DEBUG_HWERR
+	help
+	  By default, the Blackfin hardware errors are not exact - the error
+          be reported multiple cycles after the error happens. This delay
+	  can cause the wrong application, or even the kernel to receive a
+	  signal to be killed. If you are getting HW errors in your system,
+	  try turning this on to ensure they are at least comming from the
+	  proper thread.
+
+	  On production systems, it is safe (and a small optimization) to say N.
+
 config DEBUG_DOUBLEFAULT
 	bool "Debug Double Faults"
 	default n
diff --git a/arch/blackfin/configs/BF518F-EZBRD_defconfig b/arch/blackfin/configs/BF518F-EZBRD_defconfig
index c121d6e..baec133 100644
--- a/arch/blackfin/configs/BF518F-EZBRD_defconfig
+++ b/arch/blackfin/configs/BF518F-EZBRD_defconfig
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 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 is not set
@@ -53,16 +55,15 @@
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -259,7 +259,10 @@
 # CONFIG_SCHED_HRTICK is not set
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 # CONFIG_NO_HZ is not set
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
@@ -404,7 +407,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -688,14 +691,14 @@
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPI_ADC is not set
 # CONFIG_BFIN_SPORT is not set
 # CONFIG_BFIN_TIMER_LATENCY is not set
-# CONFIG_TWI_LCD is not set
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 CONFIG_SIMPLE_GPIO=m
 CONFIG_VT=y
 CONFIG_CONSOLE_TRANSLATIONS=y
@@ -802,7 +805,30 @@
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -831,6 +857,7 @@
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_REGULATOR is not set
@@ -962,7 +989,8 @@
 #
 # File systems
 #
-# CONFIG_EXT2_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT3_FS is not set
 # CONFIG_EXT4_FS is not set
 # CONFIG_REISERFS_FS is not set
@@ -988,8 +1016,11 @@
 #
 # DOS/FAT/NT Filesystems
 #
+CONFIG_FAT_FS=m
 # CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -1012,8 +1043,8 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_YAFFS_FS is not set
 # CONFIG_JFFS2_FS is not set
+# CONFIG_YAFFS_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1048,9 +1079,9 @@
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-CONFIG_NLS=y
+CONFIG_NLS=m
 CONFIG_NLS_DEFAULT="iso8859-1"
-CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
 # CONFIG_NLS_CODEPAGE_850 is not set
@@ -1065,7 +1096,7 @@
 # CONFIG_NLS_CODEPAGE_865 is not set
 # CONFIG_NLS_CODEPAGE_866 is not set
 # CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
+CONFIG_NLS_CODEPAGE_936=m
 # CONFIG_NLS_CODEPAGE_950 is not set
 # CONFIG_NLS_CODEPAGE_932 is not set
 # CONFIG_NLS_CODEPAGE_949 is not set
@@ -1074,7 +1105,7 @@
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 # CONFIG_NLS_ASCII is not set
-CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
@@ -1087,7 +1118,7 @@
 # CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+CONFIG_NLS_UTF8=m
 # CONFIG_DLM is not set
 
 #
@@ -1102,7 +1133,7 @@
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1111,8 +1142,6 @@
 # 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
@@ -1132,7 +1161,6 @@
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 
 #
 # Tracers
@@ -1148,16 +1176,20 @@
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1269,7 +1301,6 @@
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/BF526-EZBRD_defconfig b/arch/blackfin/configs/BF526-EZBRD_defconfig
index 3e562b2..c06262e 100644
--- a/arch/blackfin/configs/BF526-EZBRD_defconfig
+++ b/arch/blackfin/configs/BF526-EZBRD_defconfig
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 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 is not set
@@ -53,16 +55,15 @@
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -144,8 +144,8 @@
 # CONFIG_BF561 is not set
 CONFIG_BF_REV_MIN=0
 CONFIG_BF_REV_MAX=2
-# CONFIG_BF_REV_0_0 is not set
-CONFIG_BF_REV_0_1=y
+CONFIG_BF_REV_0_0=y
+# CONFIG_BF_REV_0_1 is not set
 # CONFIG_BF_REV_0_2 is not set
 # CONFIG_BF_REV_0_3 is not set
 # CONFIG_BF_REV_0_4 is not set
@@ -264,7 +264,10 @@
 # CONFIG_SCHED_HRTICK is not set
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 # CONFIG_NO_HZ is not set
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
@@ -409,7 +412,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -491,7 +494,7 @@
 #
 # User Modules And Translation Layers
 #
-CONFIG_MTD_CHAR=m
+CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLKDEVS=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
@@ -504,9 +507,9 @@
 #
 # RAM/ROM/Flash chip drivers
 #
-# CONFIG_MTD_CFI is not set
-CONFIG_MTD_JEDECPROBE=m
-CONFIG_MTD_GEN_PROBE=m
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
 # CONFIG_MTD_CFI_ADV_OPTIONS is not set
 CONFIG_MTD_MAP_BANK_WIDTH_1=y
 CONFIG_MTD_MAP_BANK_WIDTH_2=y
@@ -518,9 +521,10 @@
 CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I4 is not set
 # CONFIG_MTD_CFI_I8 is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 CONFIG_MTD_RAM=y
 CONFIG_MTD_ROM=m
 # CONFIG_MTD_ABSENT is not set
@@ -529,7 +533,8 @@
 # Mapping drivers for chip access
 #
 CONFIG_MTD_COMPLEX_MAPPINGS=y
-# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
 # CONFIG_MTD_GPIO_ADDR is not set
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
@@ -597,9 +602,42 @@
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_DMA is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
 CONFIG_NETDEVICES=y
@@ -644,9 +682,8 @@
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -715,14 +752,14 @@
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPI_ADC is not set
 # CONFIG_BFIN_SPORT is not set
 # CONFIG_BFIN_TIMER_LATENCY is not set
-# CONFIG_TWI_LCD is not set
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 CONFIG_SIMPLE_GPIO=m
 CONFIG_VT=y
 CONFIG_CONSOLE_TRANSLATIONS=y
@@ -832,11 +869,35 @@
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD5252 is not set
 # CONFIG_SENSORS_AD7414 is not set
 # CONFIG_SENSORS_AD7418 is not set
 # CONFIG_SENSORS_ADCXX is not set
@@ -920,6 +981,7 @@
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_REGULATOR is not set
@@ -1008,8 +1070,8 @@
 #
 # Miscellaneous USB options
 #
-# CONFIG_USB_DEVICEFS is not set
-CONFIG_USB_DEVICE_CLASS=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_OTG is not set
 # CONFIG_USB_OTG_WHITELIST is not set
@@ -1037,10 +1099,10 @@
 CONFIG_USB_MUSB_HOST=y
 # CONFIG_USB_MUSB_PERIPHERAL is not set
 # CONFIG_USB_MUSB_OTG is not set
-# CONFIG_USB_GADGET_MUSB_HDRC is not set
 CONFIG_USB_MUSB_HDRC_HCD=y
-CONFIG_MUSB_PIO_ONLY=y
-CONFIG_MUSB_DMA_POLL=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
 # CONFIG_USB_MUSB_DEBUG is not set
 
 #
@@ -1058,7 +1120,7 @@
 #
 # see USB_STORAGE Help for more information
 #
-CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
@@ -1107,33 +1169,10 @@
 # CONFIG_USB_LD is not set
 # CONFIG_USB_TRANCEVIBRATOR is not set
 # CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
 # CONFIG_USB_ISIGHTFW is not set
 # CONFIG_USB_VST is not set
 # CONFIG_USB_GADGET is not set
-# CONFIG_USB_GADGET_AT91 is not set
-# CONFIG_USB_GADGET_ATMEL_USBA is not set
-# CONFIG_USB_GADGET_FSL_USB2 is not set
-# CONFIG_USB_GADGET_LH7A40X is not set
-# CONFIG_USB_GADGET_OMAP is not set
-# CONFIG_USB_GADGET_PXA25X is not set
-# CONFIG_USB_GADGET_PXA27X is not set
-# CONFIG_USB_GADGET_S3C2410 is not set
-# CONFIG_USB_GADGET_M66592 is not set
-# CONFIG_USB_GADGET_AMD5536UDC is not set
-# CONFIG_USB_GADGET_FSL_QE is not set
-# CONFIG_USB_GADGET_NET2272 is not set
-# CONFIG_USB_GADGET_NET2280 is not set
-# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
-# CONFIG_USB_ZERO is not set
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_ETH is not set
-# CONFIG_USB_GADGETFS is not set
-# CONFIG_USB_FILE_STORAGE is not set
-# CONFIG_USB_G_SERIAL is not set
-# CONFIG_USB_MIDI_GADGET is not set
-# CONFIG_USB_G_PRINTER is not set
-# CONFIG_USB_CDC_COMPOSITE is not set
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
@@ -1206,7 +1245,8 @@
 #
 # File systems
 #
-# CONFIG_EXT2_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT3_FS is not set
 # CONFIG_EXT4_FS is not set
 # CONFIG_REISERFS_FS is not set
@@ -1226,14 +1266,19 @@
 #
 # CD-ROM/DVD Filesystems
 #
-# CONFIG_ISO9660_FS is not set
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
 # CONFIG_UDF_FS is not set
 
 #
 # DOS/FAT/NT Filesystems
 #
+CONFIG_FAT_FS=m
 # CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -1256,16 +1301,6 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1277,6 +1312,16 @@
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1313,7 +1358,7 @@
 CONFIG_MSDOS_PARTITION=y
 CONFIG_NLS=m
 CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
 # CONFIG_NLS_CODEPAGE_850 is not set
@@ -1328,7 +1373,7 @@
 # CONFIG_NLS_CODEPAGE_865 is not set
 # CONFIG_NLS_CODEPAGE_866 is not set
 # CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
+CONFIG_NLS_CODEPAGE_936=m
 # CONFIG_NLS_CODEPAGE_950 is not set
 # CONFIG_NLS_CODEPAGE_932 is not set
 # CONFIG_NLS_CODEPAGE_949 is not set
@@ -1337,7 +1382,7 @@
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 # CONFIG_NLS_ASCII is not set
-# CONFIG_NLS_ISO8859_1 is not set
+CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
@@ -1350,7 +1395,7 @@
 # CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+CONFIG_NLS_UTF8=m
 # CONFIG_DLM is not set
 
 #
@@ -1365,7 +1410,7 @@
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1374,8 +1419,6 @@
 # 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
@@ -1395,7 +1438,6 @@
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 
 #
 # Tracers
@@ -1411,16 +1453,20 @@
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1534,7 +1580,6 @@
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/BF527-EZKIT_defconfig b/arch/blackfin/configs/BF527-EZKIT_defconfig
index 911b5db..e9175c6 100644
--- a/arch/blackfin/configs/BF527-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF527-EZKIT_defconfig
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 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 is not set
@@ -53,16 +55,15 @@
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -145,8 +145,8 @@
 CONFIG_BF_REV_MIN=0
 CONFIG_BF_REV_MAX=2
 # CONFIG_BF_REV_0_0 is not set
-CONFIG_BF_REV_0_1=y
-# CONFIG_BF_REV_0_2 is not set
+# CONFIG_BF_REV_0_1 is not set
+CONFIG_BF_REV_0_2=y
 # CONFIG_BF_REV_0_3 is not set
 # CONFIG_BF_REV_0_4 is not set
 # CONFIG_BF_REV_0_5 is not set
@@ -264,7 +264,10 @@
 # CONFIG_SCHED_HRTICK is not set
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 # CONFIG_NO_HZ is not set
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
@@ -318,7 +321,7 @@
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_VIRT_TO_BUS=y
-CONFIG_BFIN_GPTIMERS=m
+CONFIG_BFIN_GPTIMERS=y
 # CONFIG_DMA_UNCACHED_4M is not set
 # CONFIG_DMA_UNCACHED_2M is not set
 CONFIG_DMA_UNCACHED_1M=y
@@ -409,7 +412,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -639,9 +642,42 @@
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_DMA is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
 CONFIG_NETDEVICES=y
@@ -687,9 +723,8 @@
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -758,14 +793,14 @@
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-CONFIG_BF5xx_PPI=m
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=m
 # CONFIG_BFIN_TIMER_LATENCY is not set
-# CONFIG_TWI_LCD is not set
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 CONFIG_SIMPLE_GPIO=m
 CONFIG_VT=y
 CONFIG_CONSOLE_TRANSLATIONS=y
@@ -875,7 +910,30 @@
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -909,6 +967,7 @@
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_REGULATOR is not set
@@ -1091,8 +1150,8 @@
 #
 # Miscellaneous USB options
 #
-# CONFIG_USB_DEVICEFS is not set
-CONFIG_USB_DEVICE_CLASS=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_OTG is not set
 # CONFIG_USB_OTG_WHITELIST is not set
@@ -1120,10 +1179,10 @@
 CONFIG_USB_MUSB_HOST=y
 # CONFIG_USB_MUSB_PERIPHERAL is not set
 # CONFIG_USB_MUSB_OTG is not set
-# CONFIG_USB_GADGET_MUSB_HDRC is not set
 CONFIG_USB_MUSB_HDRC_HCD=y
-CONFIG_MUSB_PIO_ONLY=y
-CONFIG_MUSB_DMA_POLL=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
 # CONFIG_USB_MUSB_DEBUG is not set
 
 #
@@ -1141,7 +1200,7 @@
 #
 # see USB_STORAGE Help for more information
 #
-CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
@@ -1190,33 +1249,10 @@
 # CONFIG_USB_LD is not set
 # CONFIG_USB_TRANCEVIBRATOR is not set
 # CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
 # CONFIG_USB_ISIGHTFW is not set
 # CONFIG_USB_VST is not set
 # CONFIG_USB_GADGET is not set
-# CONFIG_USB_GADGET_AT91 is not set
-# CONFIG_USB_GADGET_ATMEL_USBA is not set
-# CONFIG_USB_GADGET_FSL_USB2 is not set
-# CONFIG_USB_GADGET_LH7A40X is not set
-# CONFIG_USB_GADGET_OMAP is not set
-# CONFIG_USB_GADGET_PXA25X is not set
-# CONFIG_USB_GADGET_PXA27X is not set
-# CONFIG_USB_GADGET_S3C2410 is not set
-# CONFIG_USB_GADGET_M66592 is not set
-# CONFIG_USB_GADGET_AMD5536UDC is not set
-# CONFIG_USB_GADGET_FSL_QE is not set
-# CONFIG_USB_GADGET_NET2272 is not set
-# CONFIG_USB_GADGET_NET2280 is not set
-# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
-# CONFIG_USB_ZERO is not set
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_ETH is not set
-# CONFIG_USB_GADGETFS is not set
-# CONFIG_USB_FILE_STORAGE is not set
-# CONFIG_USB_G_SERIAL is not set
-# CONFIG_USB_MIDI_GADGET is not set
-# CONFIG_USB_G_PRINTER is not set
-# CONFIG_USB_CDC_COMPOSITE is not set
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
@@ -1289,7 +1325,8 @@
 #
 # File systems
 #
-# CONFIG_EXT2_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT3_FS is not set
 # CONFIG_EXT4_FS is not set
 # CONFIG_REISERFS_FS is not set
@@ -1309,14 +1346,20 @@
 #
 # CD-ROM/DVD Filesystems
 #
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
 
 #
 # DOS/FAT/NT Filesystems
 #
+CONFIG_FAT_FS=m
 # CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -1339,16 +1382,6 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1360,6 +1393,16 @@
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1396,7 +1439,7 @@
 CONFIG_MSDOS_PARTITION=y
 CONFIG_NLS=m
 CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
 # CONFIG_NLS_CODEPAGE_850 is not set
@@ -1411,7 +1454,7 @@
 # CONFIG_NLS_CODEPAGE_865 is not set
 # CONFIG_NLS_CODEPAGE_866 is not set
 # CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
+CONFIG_NLS_CODEPAGE_936=m
 # CONFIG_NLS_CODEPAGE_950 is not set
 # CONFIG_NLS_CODEPAGE_932 is not set
 # CONFIG_NLS_CODEPAGE_949 is not set
@@ -1420,7 +1463,7 @@
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 # CONFIG_NLS_ASCII is not set
-# CONFIG_NLS_ISO8859_1 is not set
+CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
@@ -1433,7 +1476,7 @@
 # CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+CONFIG_NLS_UTF8=m
 # CONFIG_DLM is not set
 
 #
@@ -1448,7 +1491,7 @@
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1457,8 +1500,6 @@
 # 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
@@ -1478,7 +1519,6 @@
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
 
 #
 # Tracers
@@ -1494,16 +1534,20 @@
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1611,13 +1655,12 @@
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
-# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC_ITU_T=m
 CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/BF533-EZKIT_defconfig b/arch/blackfin/configs/BF533-EZKIT_defconfig
index 4c41e03..5aa63ba 100644
--- a/arch/blackfin/configs/BF533-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF533-EZKIT_defconfig
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 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 is not set
@@ -53,16 +55,15 @@
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -225,7 +225,10 @@
 CONFIG_SCHED_HRTICK=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
 CONFIG_HIGH_RES_TIMERS=y
@@ -382,7 +385,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -613,9 +616,8 @@
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -667,13 +669,13 @@
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=y
 # CONFIG_BFIN_TIMER_LATENCY is not set
-CONFIG_BFIN_DMA_INTERFACE=m
 CONFIG_SIMPLE_GPIO=m
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
@@ -729,7 +731,30 @@
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -904,16 +929,6 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -925,6 +940,16 @@
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1013,7 +1038,7 @@
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1022,8 +1047,6 @@
 # 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
@@ -1043,7 +1066,6 @@
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
 
 #
 # Tracers
@@ -1059,16 +1081,20 @@
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1181,7 +1207,6 @@
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/BF533-STAMP_defconfig b/arch/blackfin/configs/BF533-STAMP_defconfig
index 9c482cd..fed2532 100644
--- a/arch/blackfin/configs/BF533-STAMP_defconfig
+++ b/arch/blackfin/configs/BF533-STAMP_defconfig
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 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 is not set
@@ -53,16 +55,15 @@
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -225,7 +225,10 @@
 CONFIG_SCHED_HRTICK=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
 CONFIG_HIGH_RES_TIMERS=y
@@ -382,7 +385,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -618,9 +621,8 @@
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -674,14 +676,14 @@
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-CONFIG_BF5xx_PPI=m
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=m
 # CONFIG_BFIN_TIMER_LATENCY is not set
-# CONFIG_TWI_LCD is not set
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 CONFIG_SIMPLE_GPIO=m
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
@@ -781,7 +783,30 @@
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -1068,16 +1093,6 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1089,6 +1104,16 @@
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1177,7 +1202,7 @@
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1186,8 +1211,6 @@
 # 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
@@ -1207,7 +1230,6 @@
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
 
 #
 # Tracers
@@ -1223,16 +1245,20 @@
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1345,7 +1371,6 @@
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/BF537-STAMP_defconfig b/arch/blackfin/configs/BF537-STAMP_defconfig
index 591f6ed..f9ac20d 100644
--- a/arch/blackfin/configs/BF537-STAMP_defconfig
+++ b/arch/blackfin/configs/BF537-STAMP_defconfig
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 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 is not set
@@ -53,16 +55,15 @@
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -232,7 +232,10 @@
 CONFIG_SCHED_HRTICK=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
 CONFIG_HIGH_RES_TIMERS=y
@@ -390,7 +393,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -548,9 +551,7 @@
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 CONFIG_MTD_PHYSMAP=m
-CONFIG_MTD_PHYSMAP_START=0x20000000
-CONFIG_MTD_PHYSMAP_LEN=0x0
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
 
@@ -649,9 +650,8 @@
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -708,14 +708,14 @@
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-CONFIG_BF5xx_PPI=m
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=m
 # CONFIG_BFIN_TIMER_LATENCY is not set
-# CONFIG_TWI_LCD is not set
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 CONFIG_SIMPLE_GPIO=m
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
@@ -823,7 +823,30 @@
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -1123,16 +1146,6 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1144,6 +1157,16 @@
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1232,7 +1255,7 @@
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1241,8 +1264,6 @@
 # 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
@@ -1262,7 +1283,6 @@
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
 
 #
 # Tracers
@@ -1278,16 +1298,20 @@
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1400,7 +1424,6 @@
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/BF538-EZKIT_defconfig b/arch/blackfin/configs/BF538-EZKIT_defconfig
index 1a8e8c3..ee98e22 100644
--- a/arch/blackfin/configs/BF538-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF538-EZKIT_defconfig
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 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 is not set
@@ -53,16 +55,15 @@
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -243,7 +243,10 @@
 CONFIG_SCHED_HRTICK=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
 CONFIG_HIGH_RES_TIMERS=y
@@ -389,7 +392,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -546,9 +549,7 @@
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 CONFIG_MTD_PHYSMAP=m
-CONFIG_MTD_PHYSMAP_START=0x20000000
-CONFIG_MTD_PHYSMAP_LEN=0x0
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
 
@@ -691,11 +692,11 @@
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 CONFIG_INPUT_TOUCHSCREEN=y
-# CONFIG_TOUCHSCREEN_ADS7846 is not set
 # CONFIG_TOUCHSCREEN_AD7877 is not set
 # CONFIG_TOUCHSCREEN_AD7879_I2C is not set
 CONFIG_TOUCHSCREEN_AD7879_SPI=y
 CONFIG_TOUCHSCREEN_AD7879=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
@@ -720,14 +721,14 @@
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-CONFIG_BF5xx_PPI=m
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=m
 # CONFIG_BFIN_TIMER_LATENCY is not set
-# CONFIG_TWI_LCD is not set
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 CONFIG_SIMPLE_GPIO=m
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
@@ -833,7 +834,30 @@
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -1056,16 +1080,6 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1077,6 +1091,16 @@
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1165,7 +1189,7 @@
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1174,8 +1198,6 @@
 # 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
@@ -1195,7 +1217,6 @@
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 
 #
 # Tracers
@@ -1211,16 +1232,20 @@
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1333,7 +1358,6 @@
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/BF548-EZKIT_defconfig b/arch/blackfin/configs/BF548-EZKIT_defconfig
index 2cd1c2b..deeabef 100644
--- a/arch/blackfin/configs/BF548-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF548-EZKIT_defconfig
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 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 is not set
@@ -53,16 +55,15 @@
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -196,6 +196,7 @@
 # BF548 Specific Configuration
 #
 # CONFIG_DEB_DMA_URGENT is not set
+# CONFIG_BF548_ATAPI_ALTERNATIVE_PORT is not set
 
 #
 # Interrupt Priority Assignment
@@ -298,7 +299,10 @@
 # CONFIG_SCHED_HRTICK is not set
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 # CONFIG_NO_HZ is not set
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
@@ -367,7 +371,9 @@
 # CONFIG_BFIN_ICACHE_LOCK is not set
 CONFIG_BFIN_WB=y
 # CONFIG_BFIN_WT is not set
-# CONFIG_BFIN_L2_CACHEABLE is not set
+# CONFIG_BFIN_L2_WB is not set
+CONFIG_BFIN_L2_WT=y
+# CONFIG_BFIN_L2_NOT_CACHED is not set
 # CONFIG_MPU is not set
 
 #
@@ -447,7 +453,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -616,9 +622,7 @@
 #
 CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PHYSMAP_START=0x20000000
-CONFIG_MTD_PHYSMAP_LEN=0
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
 # CONFIG_MTD_GPIO_ADDR is not set
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
@@ -696,7 +700,7 @@
 CONFIG_BLK_DEV_SD=y
 # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR=m
 # CONFIG_BLK_DEV_SR_VENDOR is not set
 # CONFIG_CHR_DEV_SG is not set
 # CONFIG_CHR_DEV_SCH is not set
@@ -718,9 +722,7 @@
 # CONFIG_SCSI_ISCSI_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
 # CONFIG_SCSI_SRP_ATTRS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_LOWLEVEL is not set
 # CONFIG_SCSI_DH is not set
 CONFIG_ATA=y
 # CONFIG_ATA_NONSTANDARD is not set
@@ -752,9 +754,8 @@
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -821,11 +822,11 @@
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 CONFIG_INPUT_TOUCHSCREEN=y
-# CONFIG_TOUCHSCREEN_ADS7846 is not set
 CONFIG_TOUCHSCREEN_AD7877=m
 # CONFIG_TOUCHSCREEN_AD7879_I2C is not set
 # CONFIG_TOUCHSCREEN_AD7879_SPI is not set
 # CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
@@ -858,14 +859,14 @@
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-CONFIG_BF5xx_PPI=m
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=m
 # CONFIG_BFIN_TIMER_LATENCY is not set
-# CONFIG_TWI_LCD is not set
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 CONFIG_SIMPLE_GPIO=m
 CONFIG_VT=y
 CONFIG_CONSOLE_TRANSLATIONS=y
@@ -977,7 +978,30 @@
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -1011,6 +1035,7 @@
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_REGULATOR is not set
@@ -1193,8 +1218,8 @@
 #
 # Miscellaneous USB options
 #
-# CONFIG_USB_DEVICEFS is not set
-CONFIG_USB_DEVICE_CLASS=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_OTG is not set
 # CONFIG_USB_OTG_WHITELIST is not set
@@ -1222,10 +1247,10 @@
 CONFIG_USB_MUSB_HOST=y
 # CONFIG_USB_MUSB_PERIPHERAL is not set
 # CONFIG_USB_MUSB_OTG is not set
-# CONFIG_USB_GADGET_MUSB_HDRC is not set
 CONFIG_USB_MUSB_HDRC_HCD=y
-CONFIG_MUSB_PIO_ONLY=y
-CONFIG_MUSB_DMA_POLL=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
 # CONFIG_USB_MUSB_DEBUG is not set
 
 #
@@ -1243,7 +1268,7 @@
 #
 # see USB_STORAGE Help for more information
 #
-CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
@@ -1292,33 +1317,10 @@
 # CONFIG_USB_LD is not set
 # CONFIG_USB_TRANCEVIBRATOR is not set
 # CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
 # CONFIG_USB_ISIGHTFW is not set
 # CONFIG_USB_VST is not set
 # CONFIG_USB_GADGET is not set
-# CONFIG_USB_GADGET_AT91 is not set
-# CONFIG_USB_GADGET_ATMEL_USBA is not set
-# CONFIG_USB_GADGET_FSL_USB2 is not set
-# CONFIG_USB_GADGET_LH7A40X is not set
-# CONFIG_USB_GADGET_OMAP is not set
-# CONFIG_USB_GADGET_PXA25X is not set
-# CONFIG_USB_GADGET_PXA27X is not set
-# CONFIG_USB_GADGET_S3C2410 is not set
-# CONFIG_USB_GADGET_M66592 is not set
-# CONFIG_USB_GADGET_AMD5536UDC is not set
-# CONFIG_USB_GADGET_FSL_QE is not set
-# CONFIG_USB_GADGET_NET2272 is not set
-# CONFIG_USB_GADGET_NET2280 is not set
-# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
-# CONFIG_USB_ZERO is not set
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_ETH is not set
-# CONFIG_USB_GADGETFS is not set
-# CONFIG_USB_FILE_STORAGE is not set
-# CONFIG_USB_G_SERIAL is not set
-# CONFIG_USB_MIDI_GADGET is not set
-# CONFIG_USB_G_PRINTER is not set
-# CONFIG_USB_CDC_COMPOSITE is not set
 CONFIG_MMC=y
 # CONFIG_MMC_DEBUG is not set
 # CONFIG_MMC_UNSAFE_RESUME is not set
@@ -1414,13 +1416,8 @@
 CONFIG_EXT2_FS_XATTR=y
 # CONFIG_EXT2_FS_POSIX_ACL is not set
 # CONFIG_EXT2_FS_SECURITY is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT3_FS is not set
 # CONFIG_EXT4_FS is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
@@ -1476,16 +1473,6 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1497,6 +1484,16 @@
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1539,63 +1536,47 @@
 #
 # Partition Types
 #
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
+# CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_KARMA_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-# CONFIG_SYSV68_PARTITION is not set
 CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=m
-CONFIG_NLS_CODEPAGE_737=m
-CONFIG_NLS_CODEPAGE_775=m
-CONFIG_NLS_CODEPAGE_850=m
-CONFIG_NLS_CODEPAGE_852=m
-CONFIG_NLS_CODEPAGE_855=m
-CONFIG_NLS_CODEPAGE_857=m
-CONFIG_NLS_CODEPAGE_860=m
-CONFIG_NLS_CODEPAGE_861=m
-CONFIG_NLS_CODEPAGE_862=m
-CONFIG_NLS_CODEPAGE_863=m
-CONFIG_NLS_CODEPAGE_864=m
-CONFIG_NLS_CODEPAGE_865=m
-CONFIG_NLS_CODEPAGE_866=m
-CONFIG_NLS_CODEPAGE_869=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
 CONFIG_NLS_CODEPAGE_936=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=m
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 CONFIG_NLS_ISO8859_1=m
-CONFIG_NLS_ISO8859_2=m
-CONFIG_NLS_ISO8859_3=m
-CONFIG_NLS_ISO8859_4=m
-CONFIG_NLS_ISO8859_5=m
-CONFIG_NLS_ISO8859_6=m
-CONFIG_NLS_ISO8859_7=m
-CONFIG_NLS_ISO8859_9=m
-CONFIG_NLS_ISO8859_13=m
-CONFIG_NLS_ISO8859_14=m
-CONFIG_NLS_ISO8859_15=m
-CONFIG_NLS_KOI8_R=m
-CONFIG_NLS_KOI8_U=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
 CONFIG_NLS_UTF8=m
 # CONFIG_DLM is not set
 
@@ -1611,7 +1592,7 @@
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1620,8 +1601,6 @@
 # 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
@@ -1641,7 +1620,6 @@
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
 
 #
 # Tracers
@@ -1657,16 +1635,20 @@
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1780,7 +1762,6 @@
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/BF561-EZKIT_defconfig b/arch/blackfin/configs/BF561-EZKIT_defconfig
index 4a6ea8e..dcfbe2e 100644
--- a/arch/blackfin/configs/BF561-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF561-EZKIT_defconfig
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 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 is not set
@@ -53,16 +55,15 @@
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -148,9 +148,9 @@
 # CONFIG_BF_REV_0_0 is not set
 # CONFIG_BF_REV_0_1 is not set
 # CONFIG_BF_REV_0_2 is not set
-CONFIG_BF_REV_0_3=y
+# CONFIG_BF_REV_0_3 is not set
 # CONFIG_BF_REV_0_4 is not set
-# CONFIG_BF_REV_0_5 is not set
+CONFIG_BF_REV_0_5=y
 # CONFIG_BF_REV_0_6 is not set
 # CONFIG_BF_REV_ANY is not set
 # CONFIG_BF_REV_NONE is not set
@@ -179,7 +179,6 @@
 # Core B Support
 #
 CONFIG_BF561_COREB=y
-CONFIG_BF561_COREB_RESET=y
 
 #
 # Interrupt Priority Assignment
@@ -264,7 +263,10 @@
 CONFIG_SCHED_HRTICK=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
 CONFIG_HIGH_RES_TIMERS=y
@@ -334,7 +336,9 @@
 # CONFIG_BFIN_ICACHE_LOCK is not set
 CONFIG_BFIN_WB=y
 # CONFIG_BFIN_WT is not set
-# CONFIG_BFIN_L2_CACHEABLE is not set
+# CONFIG_BFIN_L2_WB is not set
+CONFIG_BFIN_L2_WT=y
+# CONFIG_BFIN_L2_NOT_CACHED is not set
 # CONFIG_MPU is not set
 
 #
@@ -415,7 +419,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -570,9 +574,7 @@
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 CONFIG_MTD_PHYSMAP=m
-CONFIG_MTD_PHYSMAP_START=0x20000000
-CONFIG_MTD_PHYSMAP_LEN=0x0
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
 
@@ -649,9 +651,8 @@
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -703,13 +704,13 @@
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPI_ADC is not set
 # CONFIG_BFIN_SPORT is not set
 # CONFIG_BFIN_TIMER_LATENCY is not set
-CONFIG_BFIN_DMA_INTERFACE=m
 CONFIG_SIMPLE_GPIO=m
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
@@ -765,7 +766,30 @@
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -897,16 +921,6 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -918,6 +932,16 @@
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1006,7 +1030,7 @@
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1015,8 +1039,6 @@
 # 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
@@ -1036,7 +1058,6 @@
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
 
 #
 # Tracers
@@ -1052,16 +1073,20 @@
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1174,7 +1199,6 @@
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/BlackStamp_defconfig b/arch/blackfin/configs/BlackStamp_defconfig
index ef1a2c8..174c578 100644
--- a/arch/blackfin/configs/BlackStamp_defconfig
+++ b/arch/blackfin/configs/BlackStamp_defconfig
@@ -46,7 +46,7 @@
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -381,7 +381,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
diff --git a/arch/blackfin/configs/CM-BF527_defconfig b/arch/blackfin/configs/CM-BF527_defconfig
index e2fc588..e17875e 100644
--- a/arch/blackfin/configs/CM-BF527_defconfig
+++ b/arch/blackfin/configs/CM-BF527_defconfig
@@ -46,7 +46,7 @@
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 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 is not set
@@ -411,7 +411,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -783,7 +783,30 @@
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
diff --git a/arch/blackfin/configs/CM-BF533_defconfig b/arch/blackfin/configs/CM-BF533_defconfig
index 65a8bbb..fafd95e 100644
--- a/arch/blackfin/configs/CM-BF533_defconfig
+++ b/arch/blackfin/configs/CM-BF533_defconfig
@@ -49,7 +49,7 @@
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 # CONFIG_UID16 is not set
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_HOTPLUG is not set
@@ -347,7 +347,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -547,9 +547,9 @@
 CONFIG_SMC91X=y
 # CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
-CONFIG_NETDEV_1000=y
+# CONFIG_NETDEV_1000 is not set
 # CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -641,6 +641,10 @@
 # CONFIG_TCG_TPM is not set
 # CONFIG_I2C is not set
 
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+
 #
 # SPI support
 #
diff --git a/arch/blackfin/configs/CM-BF537E_defconfig b/arch/blackfin/configs/CM-BF537E_defconfig
index 9b7e9d78..e73aa5a 100644
--- a/arch/blackfin/configs/CM-BF537E_defconfig
+++ b/arch/blackfin/configs/CM-BF537E_defconfig
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22.16
+# Linux kernel version: 2.6.28.10
+# Wed Jun  3 06:27:41 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -8,48 +9,44 @@
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BLACKFIN=y
 CONFIG_ZONE_DMA=y
-CONFIG_SEMAPHORE_SLEEPERS=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
 # CONFIG_AUDIT is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
 # CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 # CONFIG_UID16 is not set
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_HOTPLUG is not set
@@ -58,37 +55,36 @@
 # CONFIG_ELF_CORE is not set
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3
-# CONFIG_NP2 is not set
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
-CONFIG_RT_MUTEXES=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 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
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
 
 #
 # IO Schedulers
@@ -102,9 +98,11 @@
 # CONFIG_DEFAULT_CFQ is not set
 CONFIG_DEFAULT_NOOP=y
 CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_CLASSIC_RCU=y
 CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
+# CONFIG_FREEZER is not set
 
 #
 # Blackfin Processor Options
@@ -113,6 +111,10 @@
 #
 # Processor and Board Settings
 #
+# CONFIG_BF512 is not set
+# CONFIG_BF514 is not set
+# CONFIG_BF516 is not set
+# CONFIG_BF518 is not set
 # CONFIG_BF522 is not set
 # CONFIG_BF523 is not set
 # CONFIG_BF524 is not set
@@ -125,22 +127,31 @@
 # CONFIG_BF534 is not set
 # CONFIG_BF536 is not set
 CONFIG_BF537=y
+# CONFIG_BF538 is not set
+# CONFIG_BF539 is not set
 # CONFIG_BF542 is not set
+# CONFIG_BF542M is not set
 # CONFIG_BF544 is not set
+# CONFIG_BF544M is not set
 # CONFIG_BF547 is not set
+# CONFIG_BF547M is not set
 # CONFIG_BF548 is not set
+# CONFIG_BF548M is not set
 # CONFIG_BF549 is not set
+# CONFIG_BF549M is not set
 # CONFIG_BF561 is not set
+CONFIG_BF_REV_MIN=2
+CONFIG_BF_REV_MAX=3
 # CONFIG_BF_REV_0_0 is not set
 # CONFIG_BF_REV_0_1 is not set
 CONFIG_BF_REV_0_2=y
 # CONFIG_BF_REV_0_3 is not set
 # CONFIG_BF_REV_0_4 is not set
 # CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_0_6 is not set
 # CONFIG_BF_REV_ANY is not set
 # CONFIG_BF_REV_NONE is not set
 CONFIG_BF53x=y
-CONFIG_BFIN_SINGLE_CORE=y
 CONFIG_MEM_MT48LC16M16A2TG_75=y
 CONFIG_IRQ_PLL_WAKEUP=7
 CONFIG_IRQ_RTC=8
@@ -150,7 +161,6 @@
 CONFIG_IRQ_SPORT1_RX=9
 CONFIG_IRQ_SPORT1_TX=9
 CONFIG_IRQ_TWI=10
-CONFIG_IRQ_SPI=10
 CONFIG_IRQ_UART0_RX=10
 CONFIG_IRQ_UART0_TX=10
 CONFIG_IRQ_UART1_RX=10
@@ -169,11 +179,12 @@
 CONFIG_IRQ_MEM_DMA0=13
 CONFIG_IRQ_MEM_DMA1=13
 CONFIG_IRQ_WATCH=13
+CONFIG_IRQ_SPI=10
 # CONFIG_BFIN537_STAMP is not set
 CONFIG_BFIN537_BLUETECHNIX_CM=y
+# CONFIG_BFIN537_BLUETECHNIX_TCM is not set
 # CONFIG_PNAV10 is not set
 # CONFIG_CAMSIG_MINOTAUR is not set
-# CONFIG_GENERIC_BF537_BOARD is not set
 
 #
 # BF537 Specific Configuration
@@ -196,6 +207,7 @@
 # Board customizations
 #
 # CONFIG_CMDLINE_BOOL is not set
+CONFIG_BOOT_LOAD=0x1000
 
 #
 # Clock/PLL Setup
@@ -215,13 +227,20 @@
 # CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
+# CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 
 #
-# Memory Setup
+# Misc
 #
-CONFIG_MAX_MEM_SIZE=32
-CONFIG_MEM_ADD_WIDTH=9
-CONFIG_BOOT_LOAD=0x1000
 CONFIG_BFIN_SCRATCH_REG_RETN=y
 # CONFIG_BFIN_SCRATCH_REG_RETE is not set
 # CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
@@ -248,6 +267,12 @@
 CONFIG_CACHELINE_ALIGNED_L1=y
 CONFIG_SYSCALL_TAB_L1=y
 CONFIG_CPLB_SWITCH_TAB_L1=y
+CONFIG_APP_STACK_L1=y
+
+#
+# Speed Optimizations
+#
+CONFIG_BFIN_INS_LOWOVERHEAD=y
 CONFIG_RAMKERNEL=y
 # CONFIG_ROMKERNEL is not set
 CONFIG_SELECT_MEMORY_MODEL=y
@@ -256,12 +281,14 @@
 # CONFIG_SPARSEMEM_MANUAL is not set
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
-CONFIG_LARGE_ALLOCS=y
+CONFIG_VIRT_TO_BUS=y
 # CONFIG_BFIN_GPTIMERS is not set
+# CONFIG_DMA_UNCACHED_4M is not set
 # CONFIG_DMA_UNCACHED_2M is not set
 CONFIG_DMA_UNCACHED_1M=y
 # CONFIG_DMA_UNCACHED_NONE is not set
@@ -275,7 +302,6 @@
 # CONFIG_BFIN_ICACHE_LOCK is not set
 CONFIG_BFIN_WB=y
 # CONFIG_BFIN_WT is not set
-CONFIG_L1_MAX_PIECE=16
 # CONFIG_MPU is not set
 
 #
@@ -304,36 +330,28 @@
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
 #
-# CONFIG_PCI is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 
 #
-# PCCARD (PCMCIA/CardBus) support
-#
-
-#
 # Executable file formats
 #
 CONFIG_BINFMT_ELF_FDPIC=y
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
 CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_HAVE_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
 
 #
 # Power management options
 #
 # CONFIG_PM is not set
-# CONFIG_PM_WAKEUP_BY_GPIO is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
 
 #
 # CPU Frequency scaling
 #
 # CONFIG_CPU_FREQ is not set
-
-#
-# Networking
-#
 CONFIG_NET=y
 
 #
@@ -346,6 +364,7 @@
 # CONFIG_XFRM_USER is not set
 # CONFIG_XFRM_SUB_POLICY is not set
 # CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -358,7 +377,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -367,6 +386,7 @@
 CONFIG_INET_XFRM_MODE_TRANSPORT=y
 CONFIG_INET_XFRM_MODE_TUNNEL=y
 CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
@@ -374,8 +394,6 @@
 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_NETLABEL is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
@@ -384,6 +402,7 @@
 # CONFIG_TIPC is not set
 # CONFIG_ATM 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
@@ -393,10 +412,6 @@
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
 # CONFIG_NET_SCHED is not set
 
 #
@@ -404,18 +419,14 @@
 #
 # CONFIG_NET_PKTGEN is not set
 # CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-
-#
-# Wireless
-#
-# CONFIG_CFG80211 is not set
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -427,10 +438,6 @@
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
@@ -438,6 +445,7 @@
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
 
 #
 # User Modules And Translation Layers
@@ -450,12 +458,15 @@
 # CONFIG_INFTL is not set
 # CONFIG_RFD_FTL is not set
 # CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
 
 #
 # RAM/ROM/Flash chip drivers
 #
-# CONFIG_MTD_CFI is not set
+CONFIG_MTD_CFI=y
 # CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
 CONFIG_MTD_MAP_BANK_WIDTH_1=y
 CONFIG_MTD_MAP_BANK_WIDTH_2=y
 CONFIG_MTD_MAP_BANK_WIDTH_4=y
@@ -466,6 +477,10 @@
 CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I4 is not set
 # CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 CONFIG_MTD_RAM=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
@@ -473,7 +488,8 @@
 #
 # Mapping drivers for chip access
 #
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_GPIO_ADDR=y
 CONFIG_MTD_UCLINUX=y
 # CONFIG_MTD_PLATRAM is not set
 
@@ -498,33 +514,23 @@
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_BLK_DEV_XIP is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
 #
@@ -532,22 +538,17 @@
 #
 # CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
 # CONFIG_SCSI_NETLINK is not set
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 # CONFIG_MD is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
+# CONFIG_VETH is not set
 CONFIG_PHYLIB=y
 
 #
@@ -561,46 +562,44 @@
 # CONFIG_VITESSE_PHY is not set
 # CONFIG_SMSC_PHY is not set
 # CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
 # CONFIG_FIXED_PHY is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
+# CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
-# CONFIG_SMC91X is not set
 CONFIG_BFIN_MAC=y
 CONFIG_BFIN_MAC_USE_L1=y
 CONFIG_BFIN_TX_DESC_NUM=10
 CONFIG_BFIN_RX_DESC_NUM=20
 # CONFIG_BFIN_MAC_RMII is not set
+# CONFIG_SMC91X is not set
 # CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
 #
 # CONFIG_WLAN_PRE80211 is not set
 # CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -618,15 +617,17 @@
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PFLAGS is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=y
 # CONFIG_BFIN_TIMER_LATENCY is not set
+# CONFIG_SIMPLE_GPIO is not set
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
+# CONFIG_BFIN_JTAG_COMM is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -655,138 +656,119 @@
 # CAN, the car bus and industrial fieldbus
 #
 # CONFIG_CAN4LINUX is not set
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
-# CONFIG_GEN_RTC is not set
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
 # CONFIG_I2C is not set
-
-#
-# SPI support
-#
 # CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
 
 #
-# Dallas's 1-wire bus
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
 #
 # CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
 # CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_VT1211 is not set
 # CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
 
 #
 # Multifunction device drivers
 #
+# CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_REGULATOR is not set
 
 #
 # Multimedia devices
 #
+
+#
+# Multimedia core support
+#
 # CONFIG_VIDEO_DEV is not set
 # CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
 # CONFIG_DAB is not set
 
 #
 # Graphics support
 #
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Display device support
 #
 # CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_FB is not set
-
-#
-# Sound
-#
 # CONFIG_SOUND is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 # CONFIG_USB_ARCH_HAS_EHCI is not set
 # CONFIG_USB is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
 
 #
 # Enable Host or Gadget support to see Inventra options
 #
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# USB Gadget Support
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
 #
 # CONFIG_USB_GADGET is not set
 # CONFIG_MMC is not set
-
-#
-# LED devices
-#
+# CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
+# CONFIG_ACCESSIBILITY is not set
 # CONFIG_RTC_CLASS is not set
-
-#
-# DMA Engine support
-#
-# CONFIG_DMA_ENGINE is not set
-
-#
-# DMA Clients
-#
-
-#
-# DMA Devices
-#
-
-#
-# PBX support
-#
-# CONFIG_PBX is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
 
 #
 # File systems
@@ -796,20 +778,18 @@
 # CONFIG_EXT2_FS_POSIX_ACL is not set
 # CONFIG_EXT2_FS_SECURITY is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_EXT4DEV_FS is not set
+# CONFIG_EXT4_FS is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
 # 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_DNOTIFY is not set
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
-# CONFIG_DNOTIFY is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
@@ -835,7 +815,6 @@
 CONFIG_SYSFS=y
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
 # CONFIG_CONFIGFS_FS is not set
 
 #
@@ -848,60 +827,53 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_YAFFS_FS is not set
 # CONFIG_JFFS2_FS is not set
+# CONFIG_YAFFS_FS is not set
 # CONFIG_CRAMFS 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_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-# CONFIG_NFS_FS is not set
-# CONFIG_NFSD is not set
-# CONFIG_SMB_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
-# CONFIG_9P_FS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
 # CONFIG_NLS is not set
-
-#
-# Distributed Lock Manager
-#
 # CONFIG_DLM is not set
 
 #
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
 # CONFIG_DEBUG_KERNEL is not set
 # CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+
+#
+# Tracers
+#
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
+# CONFIG_DEBUG_DOUBLEFAULT is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
@@ -919,13 +891,95 @@
 #
 # CONFIG_KEYS is not set
 CONFIG_SECURITY=y
+# CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_NETWORK is not set
-CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+CONFIG_CRYPTO=y
 
 #
-# Cryptographic options
+# Crypto core or helper
 #
-# CONFIG_CRYPTO is not set
+# CONFIG_CRYPTO_FIPS is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_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
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES 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_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
 
 #
 # Library routines
@@ -933,11 +987,12 @@
 CONFIG_BITREVERSE=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/CM-BF537U_defconfig b/arch/blackfin/configs/CM-BF537U_defconfig
index 569523c..8021130 100644
--- a/arch/blackfin/configs/CM-BF537U_defconfig
+++ b/arch/blackfin/configs/CM-BF537U_defconfig
@@ -49,7 +49,7 @@
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 # CONFIG_UID16 is not set
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_HOTPLUG is not set
@@ -355,7 +355,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -556,9 +556,9 @@
 # CONFIG_BFIN_MAC is not set
 # CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
-CONFIG_NETDEV_1000=y
+# CONFIG_NETDEV_1000 is not set
 # CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -652,6 +652,10 @@
 # CONFIG_TCG_TPM is not set
 # CONFIG_I2C is not set
 
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+
 #
 # SPI support
 #
diff --git a/arch/blackfin/configs/CM-BF548_defconfig b/arch/blackfin/configs/CM-BF548_defconfig
index 035b635..dd815f0 100644
--- a/arch/blackfin/configs/CM-BF548_defconfig
+++ b/arch/blackfin/configs/CM-BF548_defconfig
@@ -49,7 +49,7 @@
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_HOTPLUG=y
@@ -125,9 +125,9 @@
 CONFIG_BF548=y
 # CONFIG_BF549 is not set
 # CONFIG_BF561 is not set
-CONFIG_BF_REV_0_0=y
+# CONFIG_BF_REV_0_0 is not set
 # CONFIG_BF_REV_0_1 is not set
-# CONFIG_BF_REV_0_2 is not set
+CONFIG_BF_REV_0_2=y
 # CONFIG_BF_REV_0_3 is not set
 # CONFIG_BF_REV_0_4 is not set
 # CONFIG_BF_REV_0_5 is not set
@@ -422,7 +422,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -811,6 +811,10 @@
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+
 #
 # SPI support
 #
diff --git a/arch/blackfin/configs/CM-BF561_defconfig b/arch/blackfin/configs/CM-BF561_defconfig
index 7015e42..16c198b 100644
--- a/arch/blackfin/configs/CM-BF561_defconfig
+++ b/arch/blackfin/configs/CM-BF561_defconfig
@@ -49,7 +49,7 @@
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 # CONFIG_UID16 is not set
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_HOTPLUG is not set
@@ -389,7 +389,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -569,9 +569,9 @@
 # CONFIG_IBM_NEW_EMAC_TAH is not set
 # CONFIG_IBM_NEW_EMAC_EMAC4 is not set
 # CONFIG_B44 is not set
-CONFIG_NETDEV_1000=y
+# CONFIG_NETDEV_1000 is not set
 # CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -646,6 +646,10 @@
 # CONFIG_TCG_TPM is not set
 # CONFIG_I2C is not set
 
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+
 #
 # SPI support
 #
diff --git a/arch/blackfin/configs/H8606_defconfig b/arch/blackfin/configs/H8606_defconfig
index dfc8e1d..6b4c1a9 100644
--- a/arch/blackfin/configs/H8606_defconfig
+++ b/arch/blackfin/configs/H8606_defconfig
@@ -48,7 +48,7 @@
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_HOTPLUG=y
@@ -347,7 +347,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -594,8 +594,8 @@
 # CONFIG_SMC91X is not set
 # CONFIG_SMSC911X is not set
 CONFIG_DM9000=y
-CONFIG_NETDEV_1000=y
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 # CONFIG_AX88180 is not set
 
 #
diff --git a/arch/blackfin/configs/IP0X_defconfig b/arch/blackfin/configs/IP0X_defconfig
index 95a5f91..1ec9ae2 100644
--- a/arch/blackfin/configs/IP0X_defconfig
+++ b/arch/blackfin/configs/IP0X_defconfig
@@ -49,7 +49,7 @@
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_HOTPLUG is not set
@@ -355,7 +355,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -672,9 +672,9 @@
 # CONFIG_SMC91X is not set
 # CONFIG_SMSC911X is not set
 CONFIG_DM9000=y
-CONFIG_NETDEV_1000=y
+# CONFIG_NETDEV_1000 is not set
 # CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
diff --git a/arch/blackfin/configs/PNAV-10_defconfig b/arch/blackfin/configs/PNAV-10_defconfig
index 78e2408..09701f9 100644
--- a/arch/blackfin/configs/PNAV-10_defconfig
+++ b/arch/blackfin/configs/PNAV-10_defconfig
@@ -1,6 +1,6 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -40,26 +40,26 @@
 # CONFIG_NAMESPACES is not set
 # CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
 CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -68,7 +68,6 @@
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -229,7 +228,10 @@
 # CONFIG_SCHED_HRTICK is not set
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 # CONFIG_NO_HZ is not set
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
@@ -374,7 +376,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -598,9 +600,8 @@
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -640,11 +641,11 @@
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 CONFIG_INPUT_TOUCHSCREEN=y
-# CONFIG_TOUCHSCREEN_ADS7846 is not set
 CONFIG_TOUCHSCREEN_AD7877=y
 # CONFIG_TOUCHSCREEN_AD7879_I2C is not set
 # CONFIG_TOUCHSCREEN_AD7879_SPI is not set
 # CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
@@ -676,14 +677,14 @@
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=y
 # CONFIG_BFIN_TIMER_LATENCY is not set
-CONFIG_TWI_LCD=m
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 # CONFIG_SIMPLE_GPIO is not set
 # CONFIG_VT is not set
 CONFIG_DEVKMEM=y
@@ -796,6 +797,7 @@
 # CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD5252 is not set
 # CONFIG_SENSORS_AD7414 is not set
 # CONFIG_SENSORS_AD7418 is not set
 # CONFIG_SENSORS_ADCXX is not set
@@ -867,6 +869,7 @@
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_REGULATOR is not set
@@ -1111,6 +1114,7 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
 CONFIG_YAFFS_FS=y
 CONFIG_YAFFS_YAFFS1=y
 # CONFIG_YAFFS_9BYTE_TAGS is not set
@@ -1121,7 +1125,6 @@
 # CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
 # CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
 CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
-# CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1213,7 +1216,6 @@
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_MEMORY_INIT is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
 
 #
 # Tracers
@@ -1343,7 +1345,6 @@
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/SRV1_defconfig b/arch/blackfin/configs/SRV1_defconfig
index 2bc0779..ec84a53 100644
--- a/arch/blackfin/configs/SRV1_defconfig
+++ b/arch/blackfin/configs/SRV1_defconfig
@@ -52,7 +52,7 @@
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -373,7 +373,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
diff --git a/arch/blackfin/configs/TCM-BF537_defconfig b/arch/blackfin/configs/TCM-BF537_defconfig
index e65b3a4..6e27962 100644
--- a/arch/blackfin/configs/TCM-BF537_defconfig
+++ b/arch/blackfin/configs/TCM-BF537_defconfig
@@ -42,7 +42,7 @@
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 # CONFIG_UID16 is not set
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_HOTPLUG is not set
@@ -537,7 +537,30 @@
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
diff --git a/arch/blackfin/include/asm/atomic.h b/arch/blackfin/include/asm/atomic.h
index 94b2a9b..7bbf44e 100644
--- a/arch/blackfin/include/asm/atomic.h
+++ b/arch/blackfin/include/asm/atomic.h
@@ -208,6 +208,6 @@
 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
 #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 
 #endif				/* __ARCH_BLACKFIN_ATOMIC __ */
diff --git a/arch/blackfin/include/asm/bitsperlong.h b/arch/blackfin/include/asm/bitsperlong.h
new file mode 100644
index 0000000..6dc0bb0
--- /dev/null
+++ b/arch/blackfin/include/asm/bitsperlong.h
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
diff --git a/arch/blackfin/include/asm/cacheflush.h b/arch/blackfin/include/asm/cacheflush.h
index 1b040f5..94697f0 100644
--- a/arch/blackfin/include/asm/cacheflush.h
+++ b/arch/blackfin/include/asm/cacheflush.h
@@ -30,7 +30,8 @@
 #ifndef _BLACKFIN_CACHEFLUSH_H
 #define _BLACKFIN_CACHEFLUSH_H
 
-extern void blackfin_icache_dcache_flush_range(unsigned long start_address, unsigned long end_address);
+#include <asm/blackfin.h>	/* for SSYNC() */
+
 extern void blackfin_icache_flush_range(unsigned long start_address, unsigned long end_address);
 extern void blackfin_dcache_flush_range(unsigned long start_address, unsigned long end_address);
 extern void blackfin_dcache_invalidate_range(unsigned long start_address, unsigned long end_address);
@@ -54,32 +55,28 @@
 
 static inline void flush_icache_range(unsigned start, unsigned end)
 {
-#if defined(CONFIG_BFIN_DCACHE) && defined(CONFIG_BFIN_ICACHE)
+#if defined(CONFIG_BFIN_WB)
+	blackfin_dcache_flush_range(start, end);
+#endif
 
-# if defined(CONFIG_BFIN_WT)
-	blackfin_icache_flush_range((start), (end));
+	/* Make sure all write buffers in the data side of the core
+	 * are flushed before trying to invalidate the icache.  This
+	 * needs to be after the data flush and before the icache
+	 * flush so that the SSYNC does the right thing in preventing
+	 * the instruction prefetcher from hitting things in cached
+	 * memory at the wrong time -- it runs much further ahead than
+	 * the pipeline.
+	 */
+	SSYNC();
+#if defined(CONFIG_BFIN_ICACHE)
+	blackfin_icache_flush_range(start, end);
 	flush_icache_range_others(start, end);
-# else
-	blackfin_icache_dcache_flush_range((start), (end));
-# endif
-
-#else
-
-# if defined(CONFIG_BFIN_ICACHE)
-	blackfin_icache_flush_range((start), (end));
-	flush_icache_range_others(start, end);
-# endif
-# if defined(CONFIG_BFIN_DCACHE)
-	blackfin_dcache_flush_range((start), (end));
-# endif
-
 #endif
 }
 
 #define copy_to_user_page(vma, page, vaddr, dst, src, len)		\
 do { memcpy(dst, src, len);						\
      flush_icache_range((unsigned) (dst), (unsigned) (dst) + (len));	\
-     flush_icache_range_others((unsigned long) (dst), (unsigned long) (dst) + (len));\
 } while (0)
 
 #define copy_from_user_page(vma, page, vaddr, dst, src, len)	memcpy(dst, src, len)
@@ -111,6 +108,11 @@
 		addr >= _ramend && addr < physical_mem_end)
 		return 1;
 
+#ifndef CONFIG_BFIN_L2_NOT_CACHED
+	if (addr >= L2_START && addr < L2_START + L2_LENGTH)
+		return 1;
+#endif
+
 	return 0;
 }
 
diff --git a/arch/blackfin/include/asm/cplb.h b/arch/blackfin/include/asm/cplb.h
index ad566ff..a75a6a9 100644
--- a/arch/blackfin/include/asm/cplb.h
+++ b/arch/blackfin/include/asm/cplb.h
@@ -53,29 +53,32 @@
 #define SDRAM_DGENERIC   (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW  | CPLB_COMMON)
 #endif
 
-#define L1_DMEMORY       (CPLB_LOCK | CPLB_COMMON)
-
-#ifdef CONFIG_SMP
-#define L2_ATTR           (INITIAL_T | I_CPLB | D_CPLB)
-#define L2_IMEMORY         (CPLB_COMMON | CPLB_LOCK)
-#define L2_DMEMORY         (CPLB_COMMON | CPLB_LOCK)
-
-#else
-#ifdef CONFIG_BFIN_L2_CACHEABLE
-#define L2_IMEMORY        (SDRAM_IGENERIC)
-#define L2_DMEMORY        (SDRAM_DGENERIC)
-#else
-#define L2_IMEMORY        (CPLB_COMMON)
-#define L2_DMEMORY        (CPLB_COMMON)
-#endif /* CONFIG_BFIN_L2_CACHEABLE */
-
-#define L2_ATTR           (INITIAL_T | SWITCH_T | I_CPLB | D_CPLB)
-#endif /* CONFIG_SMP */
-
 #define SDRAM_DNON_CHBL  (CPLB_COMMON)
 #define SDRAM_EBIU       (CPLB_COMMON)
 #define SDRAM_OOPS       (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY)
 
+#define L1_DMEMORY       (CPLB_LOCK | CPLB_COMMON)
+
+#ifdef CONFIG_SMP
+#define L2_ATTR          (INITIAL_T | I_CPLB | D_CPLB)
+#define L2_IMEMORY       (CPLB_COMMON)
+#define L2_DMEMORY       (CPLB_LOCK | CPLB_COMMON)
+
+#else
+#define L2_ATTR          (INITIAL_T | SWITCH_T | I_CPLB | D_CPLB)
+#define L2_IMEMORY       (SDRAM_IGENERIC)
+
+# if defined(CONFIG_BFIN_L2_WB)
+# define L2_DMEMORY      (CPLB_L1_CHBL | CPLB_COMMON)
+# elif defined(CONFIG_BFIN_L2_WT)
+# define L2_DMEMORY      (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW  | CPLB_COMMON)
+# elif defined(CONFIG_BFIN_L2_NOT_CACHED)
+# define L2_DMEMORY      (CPLB_COMMON)
+# else
+# define L2_DMEMORY      (0)
+# endif
+#endif /* CONFIG_SMP */
+
 #define SIZE_1K 0x00000400      /* 1K */
 #define SIZE_4K 0x00001000      /* 4K */
 #define SIZE_1M 0x00100000      /* 1M */
diff --git a/arch/blackfin/include/asm/dma.h b/arch/blackfin/include/asm/dma.h
index e4f7b80..c9a5962 100644
--- a/arch/blackfin/include/asm/dma.h
+++ b/arch/blackfin/include/asm/dma.h
@@ -206,10 +206,16 @@
 
 static inline void set_dma_sg(unsigned int channel, struct dmasg *sg, int ndsize)
 {
+	/* Make sure the internal data buffers in the core are drained
+	 * so that the DMA descriptors are completely written when the
+	 * DMA engine goes to fetch them below.
+	 */
+	SSYNC();
+
+	dma_ch[channel].regs->next_desc_ptr = sg;
 	dma_ch[channel].regs->cfg =
 		(dma_ch[channel].regs->cfg & ~(0xf << 8)) |
 		((ndsize & 0xf) << 8);
-	dma_ch[channel].regs->next_desc_ptr = sg;
 }
 
 static inline int dma_channel_active(unsigned int channel)
@@ -253,5 +259,7 @@
 void *dma_memcpy(void *dest, const void *src, size_t count);
 void *safe_dma_memcpy(void *dest, const void *src, size_t count);
 void blackfin_dma_early_init(void);
+void early_dma_memcpy(void *dest, const void *src, size_t count);
+void early_dma_memcpy_done(void);
 
 #endif
diff --git a/arch/blackfin/include/asm/elf.h b/arch/blackfin/include/asm/elf.h
index cdbfcfc..230e160 100644
--- a/arch/blackfin/include/asm/elf.h
+++ b/arch/blackfin/include/asm/elf.h
@@ -55,50 +55,50 @@
 #define ELF_FDPIC_CORE_EFLAGS	EF_BFIN_FDPIC
 #define ELF_EXEC_PAGESIZE	4096
 
-#define	R_unused0	0	/* relocation type 0 is not defined */
-#define R_pcrel5m2	1	/*LSETUP part a */
-#define R_unused1	2	/* relocation type 2 is not defined */
-#define R_pcrel10	3	/* type 3, if cc jump <target>  */
-#define R_pcrel12_jump	4	/* type 4, jump <target> */
-#define R_rimm16	5	/* type 0x5, rN = <target> */
-#define R_luimm16	6	/* # 0x6, preg.l=<target> Load imm 16 to lower half */
-#define R_huimm16  	7	/* # 0x7, preg.h=<target> Load imm 16 to upper half */
-#define R_pcrel12_jump_s 8	/* # 0x8 jump.s <target> */
-#define R_pcrel24_jump_x 9	/* # 0x9 jump.x <target> */
-#define R_pcrel24       10	/* # 0xa call <target> , not expandable */
-#define R_unusedb       11	/* # 0xb not generated */
-#define R_unusedc       12	/* # 0xc  not used */
-#define R_pcrel24_jump_l 13	/*0xd jump.l <target> */
-#define R_pcrel24_call_x 14	/* 0xE, call.x <target> if <target> is above 24 bit limit call through P1 */
-#define R_var_eq_symb    15	/* 0xf, linker should treat it same as 0x12 */
-#define R_byte_data      16	/* 0x10, .byte var = symbol */
-#define R_byte2_data     17	/* 0x11, .byte2 var = symbol */
-#define R_byte4_data     18	/* 0x12, .byte4 var = symbol and .var var=symbol */
-#define R_pcrel11        19	/* 0x13, lsetup part b */
-#define R_unused14      20	/* 0x14, undefined */
-#define R_unused15       21	/* not generated by VDSP 3.5 */
+#define R_BFIN_UNUSED0         0   /* relocation type 0 is not defined */
+#define R_BFIN_PCREL5M2        1   /* LSETUP part a */
+#define R_BFIN_UNUSED1         2   /* relocation type 2 is not defined */
+#define R_BFIN_PCREL10         3   /* type 3, if cc jump <target> */
+#define R_BFIN_PCREL12_JUMP    4   /* type 4, jump <target> */
+#define R_BFIN_RIMM16          5   /* type 0x5, rN = <target> */
+#define R_BFIN_LUIMM16         6   /* # 0x6, preg.l=<target> Load imm 16 to lower half */
+#define R_BFIN_HUIMM16         7   /* # 0x7, preg.h=<target> Load imm 16 to upper half */
+#define R_BFIN_PCREL12_JUMP_S  8   /* # 0x8 jump.s <target> */
+#define R_BFIN_PCREL24_JUMP_X  9   /* # 0x9 jump.x <target> */
+#define R_BFIN_PCREL24         10  /* # 0xa call <target> , not expandable */
+#define R_BFIN_UNUSEDB         11  /* # 0xb not generated */
+#define R_BFIN_UNUSEDC         12  /* # 0xc  not used */
+#define R_BFIN_PCREL24_JUMP_L  13  /* 0xd jump.l <target> */
+#define R_BFIN_PCREL24_CALL_X  14  /* 0xE, call.x <target> if <target> is above 24 bit limit call through P1 */
+#define R_BFIN_VAR_EQ_SYMB     15  /* 0xf, linker should treat it same as 0x12 */
+#define R_BFIN_BYTE_DATA       16  /* 0x10, .byte var = symbol */
+#define R_BFIN_BYTE2_DATA      17  /* 0x11, .byte2 var = symbol */
+#define R_BFIN_BYTE4_DATA      18  /* 0x12, .byte4 var = symbol and .var var=symbol */
+#define R_BFIN_PCREL11         19  /* 0x13, lsetup part b */
+#define R_BFIN_UNUSED14        20  /* 0x14, undefined */
+#define R_BFIN_UNUSED15        21  /* not generated by VDSP 3.5 */
 
 /* arithmetic relocations */
-#define R_push		 0xE0
-#define R_const		 0xE1
-#define R_add		 0xE2
-#define R_sub		 0xE3
-#define R_mult		 0xE4
-#define R_div		 0xE5
-#define R_mod		 0xE6
-#define R_lshift	 0xE7
-#define R_rshift	 0xE8
-#define R_and		 0xE9
-#define R_or		 0xEA
-#define R_xor		 0xEB
-#define R_land		 0xEC
-#define R_lor		 0xED
-#define R_len		 0xEE
-#define R_neg		 0xEF
-#define R_comp		 0xF0
-#define R_page		 0xF1
-#define R_hwpage	 0xF2
-#define R_addr		 0xF3
+#define R_BFIN_PUSH            0xE0
+#define R_BFIN_CONST           0xE1
+#define R_BFIN_ADD             0xE2
+#define R_BFIN_SUB             0xE3
+#define R_BFIN_MULT            0xE4
+#define R_BFIN_DIV             0xE5
+#define R_BFIN_MOD             0xE6
+#define R_BFIN_LSHIFT          0xE7
+#define R_BFIN_RSHIFT          0xE8
+#define R_BFIN_AND             0xE9
+#define R_BFIN_OR              0xEA
+#define R_BFIN_XOR             0xEB
+#define R_BFIN_LAND            0xEC
+#define R_BFIN_LOR             0xED
+#define R_BFIN_LEN             0xEE
+#define R_BFIN_NEG             0xEF
+#define R_BFIN_COMP            0xF0
+#define R_BFIN_PAGE            0xF1
+#define R_BFIN_HWPAGE          0xF2
+#define R_BFIN_ADDR            0xF3
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
    use of this is to invoke "./ld.so someprog" to test out a new version of
diff --git a/arch/blackfin/include/asm/entry.h b/arch/blackfin/include/asm/entry.h
index b30a296..ec58efc 100644
--- a/arch/blackfin/include/asm/entry.h
+++ b/arch/blackfin/include/asm/entry.h
@@ -35,21 +35,39 @@
 #else
 # define LOAD_IPIPE_IPEND
 #endif
+
+#ifndef CONFIG_EXACT_HWERR
+/* As a debugging aid - we save IPEND when DEBUG_KERNEL is on,
+ * otherwise it is a waste of cycles.
+ */
+# ifndef CONFIG_DEBUG_KERNEL
 #define INTERRUPT_ENTRY(N)						\
     [--sp] = SYSCFG;							\
-									\
     [--sp] = P0;	/*orig_p0*/					\
     [--sp] = R0;	/*orig_r0*/					\
     [--sp] = (R7:0,P5:0);						\
     R0 = (N);								\
     LOAD_IPIPE_IPEND							\
     jump __common_int_entry;
+# else /* CONFIG_DEBUG_KERNEL */
+#define INTERRUPT_ENTRY(N)						\
+    [--sp] = SYSCFG;							\
+    [--sp] = P0;	/*orig_p0*/					\
+    [--sp] = R0;	/*orig_r0*/					\
+    [--sp] = (R7:0,P5:0);						\
+    p0.l = lo(IPEND);							\
+    p0.h = hi(IPEND);							\
+    r1 = [p0];								\
+    R0 = (N);								\
+    LOAD_IPIPE_IPEND							\
+    jump __common_int_entry;
+# endif /* CONFIG_DEBUG_KERNEL */
 
 /* For timer interrupts, we need to save IPEND, since the user_mode
-	   macro accesses it to determine where to account time.  */
+ *macro accesses it to determine where to account time.
+ */
 #define TIMER_INTERRUPT_ENTRY(N)					\
     [--sp] = SYSCFG;							\
-									\
     [--sp] = P0;	/*orig_p0*/					\
     [--sp] = R0;	/*orig_r0*/					\
     [--sp] = (R7:0,P5:0);						\
@@ -58,6 +76,74 @@
     r1 = [p0];								\
     R0 = (N);								\
     jump __common_int_entry;
+#else /* CONFIG_EXACT_HWERR is defined */
+
+/* if we want hardware error to be exact, we need to do a SSYNC (which forces
+ * read/writes to complete to the memory controllers), and check to see that
+ * caused a pending HW error condition. If so, we assume it was caused by user
+ * space, by setting the same interrupt that we are in (so it goes off again)
+ * and context restore, and a RTI (without servicing anything). This should
+ * cause the pending HWERR to fire, and when that is done, this interrupt will
+ * be re-serviced properly.
+ * As you can see by the code - we actually need to do two SSYNCS - one to
+ * make sure the read/writes complete, and another to make sure the hardware
+ * error is recognized by the core.
+ */
+#define INTERRUPT_ENTRY(N)						\
+    SSYNC;								\
+    SSYNC;								\
+    [--sp] = SYSCFG;							\
+    [--sp] = P0;	/*orig_p0*/					\
+    [--sp] = R0;	/*orig_r0*/					\
+    [--sp] = (R7:0,P5:0);						\
+    R1 = ASTAT;								\
+    P0.L = LO(ILAT);							\
+    P0.H = HI(ILAT);							\
+    R0 = [P0];								\
+    CC = BITTST(R0, EVT_IVHW_P);					\
+    IF CC JUMP 1f;							\
+    ASTAT = R1;								\
+    p0.l = lo(IPEND);							\
+    p0.h = hi(IPEND);							\
+    r1 = [p0];								\
+    R0 = (N);								\
+    LOAD_IPIPE_IPEND							\
+    jump __common_int_entry;						\
+1:  ASTAT = R1;								\
+    RAISE N;								\
+    (R7:0, P5:0) = [SP++];						\
+    SP += 0x8;								\
+    SYSCFG = [SP++];							\
+    CSYNC;								\
+    RTI;
+
+#define TIMER_INTERRUPT_ENTRY(N)					\
+    SSYNC;								\
+    SSYNC;								\
+    [--sp] = SYSCFG;							\
+    [--sp] = P0;	/*orig_p0*/					\
+    [--sp] = R0;	/*orig_r0*/					\
+    [--sp] = (R7:0,P5:0);						\
+    R1 = ASTAT;								\
+    P0.L = LO(ILAT);							\
+    P0.H = HI(ILAT);							\
+    R0 = [P0];								\
+    CC = BITTST(R0, EVT_IVHW_P);					\
+    IF CC JUMP 1f;							\
+    ASTAT = R1;								\
+    p0.l = lo(IPEND);							\
+    p0.h = hi(IPEND);							\
+    r1 = [p0];								\
+    R0 = (N);								\
+    jump __common_int_entry;						\
+1:  ASTAT = R1;								\
+    RAISE N;								\
+    (R7:0, P5:0) = [SP++];						\
+    SP += 0x8;								\
+    SYSCFG = [SP++];							\
+    CSYNC;								\
+    RTI;
+#endif	/* CONFIG_EXACT_HWERR */
 
 /* This one pushes RETI without using CLI.  Interrupts are enabled.  */
 #define SAVE_CONTEXT_SYSCALL	save_context_syscall
diff --git a/arch/blackfin/include/asm/gptimers.h b/arch/blackfin/include/asm/gptimers.h
index b0f847a..89f08de 100644
--- a/arch/blackfin/include/asm/gptimers.h
+++ b/arch/blackfin/include/asm/gptimers.h
@@ -30,6 +30,7 @@
 # else
 #  define MAX_BLACKFIN_GPTIMERS 11
 #  define TIMER8_GROUP_REG      TIMER_ENABLE1
+#  define TIMER_GROUP2          1
 # endif
 # define TIMER0_GROUP_REG       TIMER_ENABLE0
 #endif
@@ -40,10 +41,12 @@
 # define MAX_BLACKFIN_GPTIMERS 12
 # define TIMER0_GROUP_REG      TMRS8_ENABLE
 # define TIMER8_GROUP_REG      TMRS4_ENABLE
+# define TIMER_GROUP2          1
 #endif
 /*
  * All others: 3 timers:
  */
+#define TIMER_GROUP1           0
 #if !defined(MAX_BLACKFIN_GPTIMERS)
 # define MAX_BLACKFIN_GPTIMERS 3
 # define TIMER0_GROUP_REG      TIMER_ENABLE
@@ -109,8 +112,8 @@
 #define TIMER_ERR_PROG_PER  0x8000
 #define TIMER_ERR_PROG_PW   0xC000
 #define TIMER_EMU_RUN       0x0200
-#define	TIMER_TOGGLE_HI     0x0100
-#define	TIMER_CLK_SEL       0x0080
+#define TIMER_TOGGLE_HI     0x0100
+#define TIMER_CLK_SEL       0x0080
 #define TIMER_OUT_DIS       0x0040
 #define TIMER_TIN_SEL       0x0020
 #define TIMER_IRQ_ENA       0x0010
@@ -169,23 +172,25 @@
 
 /* The actual gptimer API */
 
-void     set_gptimer_pwidth    (int timer_id, uint32_t width);
-uint32_t get_gptimer_pwidth    (int timer_id);
-void     set_gptimer_period    (int timer_id, uint32_t period);
-uint32_t get_gptimer_period    (int timer_id);
-uint32_t get_gptimer_count     (int timer_id);
-uint16_t get_gptimer_intr      (int timer_id);
-void     clear_gptimer_intr    (int timer_id);
-uint16_t get_gptimer_over      (int timer_id);
-void     clear_gptimer_over    (int timer_id);
-void     set_gptimer_config    (int timer_id, uint16_t config);
-uint16_t get_gptimer_config    (int timer_id);
-void     set_gptimer_pulse_hi  (int timer_id);
+void     set_gptimer_pwidth(int timer_id, uint32_t width);
+uint32_t get_gptimer_pwidth(int timer_id);
+void     set_gptimer_period(int timer_id, uint32_t period);
+uint32_t get_gptimer_period(int timer_id);
+uint32_t get_gptimer_count(int timer_id);
+int      get_gptimer_intr(int timer_id);
+void     clear_gptimer_intr(int timer_id);
+int      get_gptimer_over(int timer_id);
+void     clear_gptimer_over(int timer_id);
+void     set_gptimer_config(int timer_id, uint16_t config);
+uint16_t get_gptimer_config(int timer_id);
+int      get_gptimer_run(int timer_id);
+void     set_gptimer_pulse_hi(int timer_id);
 void     clear_gptimer_pulse_hi(int timer_id);
-void     enable_gptimers       (uint16_t mask);
-void     disable_gptimers      (uint16_t mask);
-uint16_t get_enabled_gptimers  (void);
-uint32_t get_gptimer_status    (int group);
-void     set_gptimer_status    (int group, uint32_t value);
+void     enable_gptimers(uint16_t mask);
+void     disable_gptimers(uint16_t mask);
+void     disable_gptimers_sync(uint16_t mask);
+uint16_t get_enabled_gptimers(void);
+uint32_t get_gptimer_status(int group);
+void     set_gptimer_status(int group, uint32_t value);
 
 #endif
diff --git a/arch/blackfin/include/asm/io.h b/arch/blackfin/include/asm/io.h
index 63b2d8c..3022b5c 100644
--- a/arch/blackfin/include/asm/io.h
+++ b/arch/blackfin/include/asm/io.h
@@ -80,19 +80,22 @@
 #define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
 #define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
 
-#define inb(addr)    readb(addr)
-#define inw(addr)    readw(addr)
-#define inl(addr)    readl(addr)
-#define outb(x,addr) ((void) writeb(x,addr))
-#define outw(x,addr) ((void) writew(x,addr))
-#define outl(x,addr) ((void) writel(x,addr))
+/* Convert "I/O port addresses" to actual addresses.  i.e. ugly casts. */
+#define __io(port) ((void *)(unsigned long)(port))
 
-#define inb_p(addr)    inb(addr)
-#define inw_p(addr)    inw(addr)
-#define inl_p(addr)    inl(addr)
-#define outb_p(x,addr) outb(x,addr)
-#define outw_p(x,addr) outw(x,addr)
-#define outl_p(x,addr) outl(x,addr)
+#define inb(port)    readb(__io(port))
+#define inw(port)    readw(__io(port))
+#define inl(port)    readl(__io(port))
+#define outb(x,port) writeb(x,__io(port))
+#define outw(x,port) writew(x,__io(port))
+#define outl(x,port) writel(x,__io(port))
+
+#define inb_p(port)    inb(__io(port))
+#define inw_p(port)    inw(__io(port))
+#define inl_p(port)    inl(__io(port))
+#define outb_p(x,port) outb(x,__io(port))
+#define outw_p(x,port) outw(x,__io(port))
+#define outl_p(x,port) outl(x,__io(port))
 
 #define ioread8_rep(a,d,c)	readsb(a,d,c)
 #define ioread16_rep(a,d,c)	readsw(a,d,c)
diff --git a/arch/blackfin/include/asm/ipipe.h b/arch/blackfin/include/asm/ipipe.h
index 343b563..51d0bf5 100644
--- a/arch/blackfin/include/asm/ipipe.h
+++ b/arch/blackfin/include/asm/ipipe.h
@@ -35,10 +35,10 @@
 #include <asm/atomic.h>
 #include <asm/traps.h>
 
-#define IPIPE_ARCH_STRING     "1.9-00"
+#define IPIPE_ARCH_STRING     "1.9-01"
 #define IPIPE_MAJOR_NUMBER    1
 #define IPIPE_MINOR_NUMBER    9
-#define IPIPE_PATCH_NUMBER    0
+#define IPIPE_PATCH_NUMBER    1
 
 #ifdef CONFIG_SMP
 #error "I-pipe/blackfin: SMP not implemented"
diff --git a/arch/blackfin/include/asm/page.h b/arch/blackfin/include/asm/page.h
index 344f6a8..3ea2016 100644
--- a/arch/blackfin/include/asm/page.h
+++ b/arch/blackfin/include/asm/page.h
@@ -81,7 +81,7 @@
 #define	virt_addr_valid(kaddr)	(((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
 				((void *)(kaddr) < (void *)memory_end))
 
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif				/* __ASSEMBLY__ */
 
diff --git a/arch/blackfin/include/asm/pda.h b/arch/blackfin/include/asm/pda.h
index a671427..b42555c 100644
--- a/arch/blackfin/include/asm/pda.h
+++ b/arch/blackfin/include/asm/pda.h
@@ -64,8 +64,6 @@
 
 extern struct blackfin_pda cpu_pda[];
 
-void reserve_pda(void);
-
 #endif	/* __ASSEMBLY__ */
 
 #endif /* _ASM_BLACKFIN_PDA_H */
diff --git a/arch/blackfin/include/asm/processor.h b/arch/blackfin/include/asm/processor.h
index 0eece23..3040415 100644
--- a/arch/blackfin/include/asm/processor.h
+++ b/arch/blackfin/include/asm/processor.h
@@ -131,8 +131,8 @@
 /* Get the Silicon Revision of the chip */
 static inline uint32_t __pure bfin_revid(void)
 {
-	/* stored in the upper 4 bits */
-	uint32_t revid = bfin_read_CHIPID() >> 28;
+	/* Always use CHIPID, to work around ANOMALY_05000234 */
+	uint32_t revid = (bfin_read_CHIPID() & CHIPID_VERSION) >> 28;
 
 #ifdef CONFIG_BF52x
 	/* ANOMALY_05000357
diff --git a/arch/blackfin/include/asm/signal.h b/arch/blackfin/include/asm/signal.h
index 87951d2..2eea907 100644
--- a/arch/blackfin/include/asm/signal.h
+++ b/arch/blackfin/include/asm/signal.h
@@ -104,7 +104,7 @@
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/arch/blackfin/include/asm/time.h b/arch/blackfin/include/asm/time.h
index ddc43ce..589e937 100644
--- a/arch/blackfin/include/asm/time.h
+++ b/arch/blackfin/include/asm/time.h
@@ -37,4 +37,5 @@
 extern unsigned int __bfin_cycles_mod;
 #endif
 
+extern void __init setup_core_timer(void);
 #endif
diff --git a/arch/blackfin/include/asm/uaccess.h b/arch/blackfin/include/asm/uaccess.h
index 3248033..8894e9f 100644
--- a/arch/blackfin/include/asm/uaccess.h
+++ b/arch/blackfin/include/asm/uaccess.h
@@ -59,12 +59,8 @@
 #ifndef CONFIG_ACCESS_CHECK
 static inline int _access_ok(unsigned long addr, unsigned long size) { return 1; }
 #else
-#ifdef CONFIG_ACCESS_OK_L1
-extern int _access_ok(unsigned long addr, unsigned long size)__attribute__((l1_text));
-#else
 extern int _access_ok(unsigned long addr, unsigned long size);
 #endif
-#endif
 
 /*
  * The exception table consists of pairs of addresses: the first is the
@@ -83,9 +79,6 @@
 	unsigned long insn, fixup;
 };
 
-/* Returns 0 if exception not found and fixup otherwise.  */
-extern unsigned long search_exception_table(unsigned long);
-
 /*
  * These are the main single-value transfer routines.  They automatically
  * use the right size if we just have the right pointer type.
@@ -233,16 +226,29 @@
 }
 
 /*
- * Return the size of a string (including the ending 0)
+ * Get the size of a string in user space.
+ *   src: The string to measure
+ *     n: The maximum valid length
  *
- * Return 0 on exception, a value greater than N if too long
+ * Get the size of a NUL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ * On exception, returns 0.
+ * If the string is too long, returns a value greater than n.
  */
-static inline long strnlen_user(const char *src, long n)
+static inline long __must_check strnlen_user(const char *src, long n)
 {
-	return (strlen(src) + 1);
+	if (!access_ok(VERIFY_READ, src, 1))
+		return 0;
+	return strnlen(src, n) + 1;
 }
 
-#define strlen_user(str) strnlen_user(str, 32767)
+static inline long __must_check strlen_user(const char *src)
+{
+	if (!access_ok(VERIFY_READ, src, 1))
+		return 0;
+	return strlen(src) + 1;
+}
 
 /*
  * Zero Userspace
@@ -251,6 +257,8 @@
 static inline unsigned long __must_check
 __clear_user(void *to, unsigned long n)
 {
+	if (!access_ok(VERIFY_WRITE, to, n))
+		return n;
 	memset(to, 0, n);
 	return 0;
 }
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
index 8531693..763ed84 100644
--- a/arch/blackfin/kernel/bfin_dma_5xx.c
+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
@@ -20,6 +20,11 @@
 #include <asm/dma.h>
 #include <asm/uaccess.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);
 
@@ -232,6 +237,87 @@
 void __init blackfin_dma_early_init(void)
 {
 	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;
+
+	/* 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);
+
+	/* 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();
+
+	src_ch = 0;
+	/* Find an avalible memDMA channel */
+	while (1) {
+		if (!src_ch || src_ch == (struct dma_register *)MDMA_S1_NEXT_DESC_PTR) {
+			dst_ch = (struct dma_register *)MDMA_D0_NEXT_DESC_PTR;
+			src_ch = (struct dma_register *)MDMA_S0_NEXT_DESC_PTR;
+		} else {
+			dst_ch = (struct dma_register *)MDMA_D1_NEXT_DESC_PTR;
+			src_ch = (struct dma_register *)MDMA_S1_NEXT_DESC_PTR;
+		}
+
+		if (!bfin_read16(&src_ch->cfg)) {
+			break;
+		} else {
+			if (bfin_read16(&src_ch->irq_status) & DMA_DONE)
+				bfin_write16(&src_ch->cfg, 0);
+		}
+
+	}
+
+	/* 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)
+{
+	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();
 }
 
 /**
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
index a0678da..beffa00 100644
--- a/arch/blackfin/kernel/bfin_gpio.c
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -313,15 +313,6 @@
 # define portmux_setup(...)  do { } while (0)
 #endif
 
-static int __init bfin_gpio_init(void)
-{
-	printk(KERN_INFO "Blackfin GPIO Controller\n");
-
-	return 0;
-}
-arch_initcall(bfin_gpio_init);
-
-
 #ifndef CONFIG_BF54x
 /***********************************************************
 *
@@ -1021,15 +1012,6 @@
 
 	local_irq_save_hw(flags);
 
-	if (unlikely(reserved_gpio_irq_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
-		if (system_state == SYSTEM_BOOTING)
-			dump_stack();
-		printk(KERN_ERR
-		       "bfin-gpio: GPIO %d is already reserved as gpio-irq !\n",
-		       gpio);
-		local_irq_restore_hw(flags);
-		return -EBUSY;
-	}
 	if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
 		if (system_state == SYSTEM_BOOTING)
 			dump_stack();
diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c
index 01f917d..53e893f 100644
--- a/arch/blackfin/kernel/bfin_ksyms.c
+++ b/arch/blackfin/kernel/bfin_ksyms.c
@@ -16,7 +16,6 @@
 
 /* All the Blackfin cache functions: mach-common/cache.S */
 EXPORT_SYMBOL(blackfin_dcache_invalidate_range);
-EXPORT_SYMBOL(blackfin_icache_dcache_flush_range);
 EXPORT_SYMBOL(blackfin_icache_flush_range);
 EXPORT_SYMBOL(blackfin_dcache_flush_range);
 EXPORT_SYMBOL(blackfin_dflush_page);
diff --git a/arch/blackfin/kernel/cplb-mpu/cacheinit.c b/arch/blackfin/kernel/cplb-mpu/cacheinit.c
index c6ff947..d5a86c3 100644
--- a/arch/blackfin/kernel/cplb-mpu/cacheinit.c
+++ b/arch/blackfin/kernel/cplb-mpu/cacheinit.c
@@ -55,7 +55,14 @@
 	}
 
 	ctrl = bfin_read_DMEM_CONTROL();
-	ctrl |= DMEM_CNTR;
+
+	/*
+	 *  Anomaly notes:
+	 *  05000287 - We implement workaround #2 - Change the DMEM_CONTROL
+	 *  register, so that the port preferences for DAG0 and DAG1 are set
+	 *  to port B
+	 */
+	ctrl |= DMEM_CNTR | PORT_PREF0 | (ANOMALY_05000287 ? PORT_PREF1 : 0);
 	bfin_write_DMEM_CONTROL(ctrl);
 	SSYNC();
 }
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
index 3e329a6..c006a44 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbinit.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
@@ -64,7 +64,7 @@
 	dcplb_tbl[cpu][i_d++].data = SDRAM_OOPS | PAGE_SIZE_1KB;
 
 	icplb_tbl[cpu][i_i].addr = 0;
-	icplb_tbl[cpu][i_i++].data = i_cache | CPLB_USER_RD | PAGE_SIZE_1KB;
+	icplb_tbl[cpu][i_i++].data = CPLB_VALID | i_cache | CPLB_USER_RD | PAGE_SIZE_1KB;
 
 	/* Cover kernel memory with 4M pages.  */
 	addr = 0;
diff --git a/arch/blackfin/kernel/cplb-nompu/cacheinit.c b/arch/blackfin/kernel/cplb-nompu/cacheinit.c
index c6ff947..d5a86c3 100644
--- a/arch/blackfin/kernel/cplb-nompu/cacheinit.c
+++ b/arch/blackfin/kernel/cplb-nompu/cacheinit.c
@@ -55,7 +55,14 @@
 	}
 
 	ctrl = bfin_read_DMEM_CONTROL();
-	ctrl |= DMEM_CNTR;
+
+	/*
+	 *  Anomaly notes:
+	 *  05000287 - We implement workaround #2 - Change the DMEM_CONTROL
+	 *  register, so that the port preferences for DAG0 and DAG1 are set
+	 *  to port B
+	 */
+	ctrl |= DMEM_CNTR | PORT_PREF0 | (ANOMALY_05000287 ? PORT_PREF1 : 0);
 	bfin_write_DMEM_CONTROL(ctrl);
 	SSYNC();
 }
diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c
index c8ad051..3302719 100644
--- a/arch/blackfin/kernel/early_printk.c
+++ b/arch/blackfin/kernel/early_printk.c
@@ -178,25 +178,15 @@
 
 asmlinkage void __init init_early_exception_vectors(void)
 {
+	u32 evt;
 	SSYNC();
 
 	/* cannot program in software:
 	 * evt0 - emulation (jtag)
 	 * evt1 - reset
 	 */
-	bfin_write_EVT2(early_trap);
-	bfin_write_EVT3(early_trap);
-	bfin_write_EVT5(early_trap);
-	bfin_write_EVT6(early_trap);
-	bfin_write_EVT7(early_trap);
-	bfin_write_EVT8(early_trap);
-	bfin_write_EVT9(early_trap);
-	bfin_write_EVT10(early_trap);
-	bfin_write_EVT11(early_trap);
-	bfin_write_EVT12(early_trap);
-	bfin_write_EVT13(early_trap);
-	bfin_write_EVT14(early_trap);
-	bfin_write_EVT15(early_trap);
+	for (evt = EVT2; evt <= EVT15; evt += 4)
+		bfin_write32(evt, early_trap);
 	CSYNC();
 
 	/* Set all the return from interrupt, exception, NMI to a known place
diff --git a/arch/blackfin/kernel/gptimers.c b/arch/blackfin/kernel/gptimers.c
index 3a3e961..7281a91 100644
--- a/arch/blackfin/kernel/gptimers.c
+++ b/arch/blackfin/kernel/gptimers.c
@@ -189,10 +189,10 @@
 }
 EXPORT_SYMBOL(set_gptimer_status);
 
-uint16_t get_gptimer_intr(int timer_id)
+int get_gptimer_intr(int timer_id)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
-	return (group_regs[BFIN_TIMER_OCTET(timer_id)]->status & timil_mask[timer_id]) ? 1 : 0;
+	return !!(group_regs[BFIN_TIMER_OCTET(timer_id)]->status & timil_mask[timer_id]);
 }
 EXPORT_SYMBOL(get_gptimer_intr);
 
@@ -203,10 +203,10 @@
 }
 EXPORT_SYMBOL(clear_gptimer_intr);
 
-uint16_t get_gptimer_over(int timer_id)
+int get_gptimer_over(int timer_id)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
-	return (group_regs[BFIN_TIMER_OCTET(timer_id)]->status & tovf_mask[timer_id]) ? 1 : 0;
+	return !!(group_regs[BFIN_TIMER_OCTET(timer_id)]->status & tovf_mask[timer_id]);
 }
 EXPORT_SYMBOL(get_gptimer_over);
 
@@ -217,6 +217,13 @@
 }
 EXPORT_SYMBOL(clear_gptimer_over);
 
+int get_gptimer_run(int timer_id)
+{
+	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
+	return !!(group_regs[BFIN_TIMER_OCTET(timer_id)]->status & trun_mask[timer_id]);
+}
+EXPORT_SYMBOL(get_gptimer_run);
+
 void set_gptimer_config(int timer_id, uint16_t config)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
@@ -244,7 +251,7 @@
 }
 EXPORT_SYMBOL(enable_gptimers);
 
-void disable_gptimers(uint16_t mask)
+static void _disable_gptimers(uint16_t mask)
 {
 	int i;
 	uint16_t m = mask;
@@ -253,6 +260,12 @@
 		group_regs[i]->disable = m & 0xFF;
 		m >>= 8;
 	}
+}
+
+void disable_gptimers(uint16_t mask)
+{
+	int i;
+	_disable_gptimers(mask);
 	for (i = 0; i < MAX_BLACKFIN_GPTIMERS; ++i)
 		if (mask & (1 << i))
 			group_regs[BFIN_TIMER_OCTET(i)]->status |= trun_mask[i];
@@ -260,6 +273,13 @@
 }
 EXPORT_SYMBOL(disable_gptimers);
 
+void disable_gptimers_sync(uint16_t mask)
+{
+	_disable_gptimers(mask);
+	SSYNC();
+}
+EXPORT_SYMBOL(disable_gptimers_sync);
+
 void set_gptimer_pulse_hi(int timer_id)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
diff --git a/arch/blackfin/kernel/ipipe.c b/arch/blackfin/kernel/ipipe.c
index a5de8d4..5fc4248 100644
--- a/arch/blackfin/kernel/ipipe.c
+++ b/arch/blackfin/kernel/ipipe.c
@@ -167,7 +167,7 @@
 void __ipipe_enable_irqdesc(struct ipipe_domain *ipd, unsigned irq)
 {
 	struct irq_desc *desc = irq_to_desc(irq);
-	int prio = desc->ic_prio;
+	int prio = __ipipe_get_irq_priority(irq);
 
 	desc->depth = 0;
 	if (ipd != &ipipe_root &&
@@ -178,8 +178,7 @@
 
 void __ipipe_disable_irqdesc(struct ipipe_domain *ipd, unsigned irq)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
-	int prio = desc->ic_prio;
+	int prio = __ipipe_get_irq_priority(irq);
 
 	if (ipd != &ipipe_root &&
 	    atomic_dec_and_test(&__ipipe_irq_lvdepth[prio]))
@@ -310,12 +309,16 @@
 
 asmlinkage void __ipipe_sync_root(void)
 {
+	void (*irq_tail_hook)(void) = (void (*)(void))__ipipe_irq_tail_hook;
 	unsigned long flags;
 
 	BUG_ON(irqs_disabled());
 
 	local_irq_save_hw(flags);
 
+	if (irq_tail_hook)
+		irq_tail_hook();
+
 	clear_thread_flag(TIF_IRQ_SYNC);
 
 	if (ipipe_root_cpudom_var(irqpend_himask) != 0)
diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c
index 401bd32..6e31e93 100644
--- a/arch/blackfin/kernel/irqchip.c
+++ b/arch/blackfin/kernel/irqchip.c
@@ -59,12 +59,14 @@
 	.unmask = dummy_mask_unmask_irq,
 };
 
+static int bad_stats;
 static struct irq_desc bad_irq_desc = {
 	.status = IRQ_DISABLED,
 	.chip = &bad_chip,
 	.handle_irq = handle_bad_irq,
 	.depth = 1,
 	.lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),
+	.kstat_irqs = &bad_stats,
 #ifdef CONFIG_SMP
 	.affinity = CPU_MASK_ALL
 #endif
diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c
index b163f6d..da28f79 100644
--- a/arch/blackfin/kernel/kgdb.c
+++ b/arch/blackfin/kernel/kgdb.c
@@ -466,7 +466,7 @@
 	int cpu = raw_smp_processor_id();
 
 	if (size < 0)
-		return EFAULT;
+		return -EFAULT;
 	if (addr >= 0x1000 && (addr + size) <= physical_mem_end)
 		return 0;
 	if (addr >= SYSMMR_BASE)
@@ -498,7 +498,7 @@
 	if (IN_MEM(addr, size, L2_START, L2_LENGTH))
 		return 0;
 
-	return EFAULT;
+	return -EFAULT;
 }
 
 /*
@@ -508,14 +508,15 @@
 int kgdb_mem2hex(char *mem, char *buf, int count)
 {
 	char *tmp;
-	int err = 0;
+	int err;
 	unsigned char *pch;
 	unsigned short mmr16;
 	unsigned long mmr32;
 	int cpu = raw_smp_processor_id();
 
-	if (validate_memory_access_address((unsigned long)mem, count))
-		return EFAULT;
+	err = validate_memory_access_address((unsigned long)mem, count);
+	if (err)
+		return err;
 
 	/*
 	 * We use the upper half of buf as an intermediate buffer for the
@@ -533,7 +534,7 @@
 				*tmp++ = *pch++;
 				tmp -= 2;
 			} else
-				err = EFAULT;
+				err = -EFAULT;
 			break;
 		case 4:
 			if ((unsigned int)mem % 4 == 0) {
@@ -545,10 +546,10 @@
 				*tmp++ = *pch++;
 				tmp -= 4;
 			} else
-				err = EFAULT;
+				err = -EFAULT;
 			break;
 		default:
-			err = EFAULT;
+			err = -EFAULT;
 		}
 	} else if ((cpu == 0 && IN_MEM(mem, count, L1_CODE_START, L1_CODE_LENGTH))
 #ifdef CONFIG_SMP
@@ -557,7 +558,7 @@
 		) {
 		/* access L1 instruction SRAM*/
 		if (dma_memcpy(tmp, mem, count) == NULL)
-			err = EFAULT;
+			err = -EFAULT;
 	} else
 		err = probe_kernel_read(tmp, mem, count);
 
@@ -585,24 +586,24 @@
 	char *tmp_new;
 	unsigned short *mmr16;
 	unsigned long *mmr32;
-	int err = 0;
-	int size = 0;
+	int err;
+	int size;
 	int cpu = raw_smp_processor_id();
 
 	tmp_old = tmp_new = buf;
 
-	while (count-- > 0) {
+	for (size = 0; size < count; ++size) {
 		if (*tmp_old == 0x7d)
 			*tmp_new = *(++tmp_old) ^ 0x20;
 		else
 			*tmp_new = *tmp_old;
 		tmp_new++;
 		tmp_old++;
-		size++;
 	}
 
-	if (validate_memory_access_address((unsigned long)mem, size))
-		return EFAULT;
+	err = validate_memory_access_address((unsigned long)mem, size);
+	if (err)
+		return err;
 
 	if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/
 		switch (size) {
@@ -611,17 +612,17 @@
 				mmr16 = (unsigned short *)buf;
 				*(unsigned short *)mem = *mmr16;
 			} else
-				return EFAULT;
+				err = -EFAULT;
 			break;
 		case 4:
 			if ((unsigned int)mem % 4 == 0) {
 				mmr32 = (unsigned long *)buf;
 				*(unsigned long *)mem = *mmr32;
 			} else
-				return EFAULT;
+				err = -EFAULT;
 			break;
 		default:
-			return EFAULT;
+			err = -EFAULT;
 		}
 	} else if ((cpu == 0 && IN_MEM(mem, count, L1_CODE_START, L1_CODE_LENGTH))
 #ifdef CONFIG_SMP
@@ -630,7 +631,7 @@
 		) {
 		/* access L1 instruction SRAM */
 		if (dma_memcpy(mem, buf, size) == NULL)
-			err = EFAULT;
+			err = -EFAULT;
 	} else
 		err = probe_kernel_write(mem, buf, size);
 
@@ -648,10 +649,12 @@
 	char *tmp_hex;
 	unsigned short *mmr16;
 	unsigned long *mmr32;
+	int err;
 	int cpu = raw_smp_processor_id();
 
-	if (validate_memory_access_address((unsigned long)mem, count))
-		return EFAULT;
+	err = validate_memory_access_address((unsigned long)mem, count);
+	if (err)
+		return err;
 
 	/*
 	 * We use the upper half of buf as an intermediate buffer for the
@@ -673,17 +676,17 @@
 				mmr16 = (unsigned short *)tmp_raw;
 				*(unsigned short *)mem = *mmr16;
 			} else
-				return EFAULT;
+				err = -EFAULT;
 			break;
 		case 4:
 			if ((unsigned int)mem % 4 == 0) {
 				mmr32 = (unsigned long *)tmp_raw;
 				*(unsigned long *)mem = *mmr32;
 			} else
-				return EFAULT;
+				err = -EFAULT;
 			break;
 		default:
-			return EFAULT;
+			err = -EFAULT;
 		}
 	} else if ((cpu == 0 && IN_MEM(mem, count, L1_CODE_START, L1_CODE_LENGTH))
 #ifdef CONFIG_SMP
@@ -692,10 +695,11 @@
 		) {
 		/* access L1 instruction SRAM */
 		if (dma_memcpy(mem, tmp_raw, count) == NULL)
-			return EFAULT;
+			err = -EFAULT;
 	} else
-		return probe_kernel_write(mem, tmp_raw, count);
-	return 0;
+		err = probe_kernel_write(mem, tmp_raw, count);
+
+	return err;
 }
 
 int kgdb_validate_break_address(unsigned long addr)
@@ -715,7 +719,7 @@
 	if (IN_MEM(addr, BREAK_INSTR_SIZE, L2_START, L2_LENGTH))
 		return 0;
 
-	return EFAULT;
+	return -EFAULT;
 }
 
 int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
diff --git a/arch/blackfin/kernel/module.c b/arch/blackfin/kernel/module.c
index 1bd7f2d..d5aee36 100644
--- a/arch/blackfin/kernel/module.c
+++ b/arch/blackfin/kernel/module.c
@@ -201,8 +201,8 @@
 /*            Arithmetic relocations are handled.                        */
 /*            We do not expect LSETUP to be split and hence is not       */
 /*            handled.                                                   */
-/*            R_byte and R_byte2 are also not handled as the gas         */
-/*            does not generate it.                                      */
+/*            R_BFIN_BYTE and R_BFIN_BYTE2 are also not handled as the   */
+/*            gas does not generate it.                                  */
 /*************************************************************************/
 int
 apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
@@ -243,8 +243,8 @@
 #endif
 		switch (ELF32_R_TYPE(rel[i].r_info)) {
 
-		case R_pcrel24:
-		case R_pcrel24_jump_l:
+		case R_BFIN_PCREL24:
+		case R_BFIN_PCREL24_JUMP_L:
 			/* Add the value, subtract its postition */
 			location16 =
 			    (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].
@@ -266,18 +266,18 @@
 			    (*location16 & 0xff00) | (value >> 16 & 0x00ff);
 			*(location16 + 1) = value & 0xffff;
 			break;
-		case R_pcrel12_jump:
-		case R_pcrel12_jump_s:
+		case R_BFIN_PCREL12_JUMP:
+		case R_BFIN_PCREL12_JUMP_S:
 			value -= (uint32_t) location32;
 			value >>= 1;
 			*location16 = (value & 0xfff);
 			break;
-		case R_pcrel10:
+		case R_BFIN_PCREL10:
 			value -= (uint32_t) location32;
 			value >>= 1;
 			*location16 = (value & 0x3ff);
 			break;
-		case R_luimm16:
+		case R_BFIN_LUIMM16:
 			pr_debug("before %x after %x\n", *location16,
 				       (value & 0xffff));
 			tmp = (value & 0xffff);
@@ -286,7 +286,7 @@
 			} else
 				*location16 = tmp;
 			break;
-		case R_huimm16:
+		case R_BFIN_HUIMM16:
 			pr_debug("before %x after %x\n", *location16,
 				       ((value >> 16) & 0xffff));
 			tmp = ((value >> 16) & 0xffff);
@@ -295,10 +295,10 @@
 			} else
 				*location16 = tmp;
 			break;
-		case R_rimm16:
+		case R_BFIN_RIMM16:
 			*location16 = (value & 0xffff);
 			break;
-		case R_byte4_data:
+		case R_BFIN_BYTE4_DATA:
 			pr_debug("before %x after %x\n", *location32, value);
 			*location32 = value;
 			break;
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index e040e03..30d0843 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -322,6 +322,9 @@
 }
 
 #if defined(CONFIG_ACCESS_CHECK)
+#ifdef CONFIG_ACCESS_OK_L1
+__attribute__((l1_text))
+#endif
 /* Return 1 if access to memory range is OK, 0 otherwise */
 int _access_ok(unsigned long addr, unsigned long size)
 {
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
index a58687b..80447f9 100644
--- a/arch/blackfin/kernel/setup.c
+++ b/arch/blackfin/kernel/setup.c
@@ -18,9 +18,12 @@
 #include <linux/tty.h>
 #include <linux/pfn.h>
 
+#ifdef CONFIG_MTD_UCLINUX
+#include <linux/mtd/map.h>
 #include <linux/ext2_fs.h>
 #include <linux/cramfs_fs.h>
 #include <linux/romfs_fs.h>
+#endif
 
 #include <asm/cplb.h>
 #include <asm/cacheflush.h>
@@ -45,6 +48,7 @@
 EXPORT_SYMBOL(reserved_mem_dcache_on);
 
 #ifdef CONFIG_MTD_UCLINUX
+extern struct map_info uclinux_ram_map;
 unsigned long memory_mtd_end, memory_mtd_start, mtd_size;
 unsigned long _ebss;
 EXPORT_SYMBOL(memory_mtd_end);
@@ -150,40 +154,45 @@
 	unsigned long l1_data_b_length;
 	unsigned long l2_length;
 
-	blackfin_dma_early_init();
-
-	l1_code_length = _etext_l1 - _stext_l1;
-	if (l1_code_length > L1_CODE_LENGTH)
-		panic("L1 Instruction SRAM Overflow\n");
-	/* cannot complain as printk is not available as yet.
-	 * But we can continue booting and complain later!
+	/*
+	 * due to the ALIGN(4) in the arch/blackfin/kernel/vmlinux.lds.S
+	 * we know that everything about l1 text/data is nice and aligned,
+	 * so copy by 4 byte chunks, and don't worry about overlapping
+	 * src/dest.
+	 *
+	 * We can't use the dma_memcpy functions, since they can call
+	 * scheduler functions which might be in L1 :( and core writes
+	 * into L1 instruction cause bad access errors, so we are stuck,
+	 * we are required to use DMA, but can't use the common dma
+	 * functions. We can't use memcpy either - since that might be
+	 * going to be in the relocated L1
 	 */
 
-	/* Copy _stext_l1 to _etext_l1 to L1 instruction SRAM */
-	dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length);
+	blackfin_dma_early_init();
 
+	/* if necessary, copy _stext_l1 to _etext_l1 to L1 instruction SRAM */
+	l1_code_length = _etext_l1 - _stext_l1;
+	if (l1_code_length)
+		early_dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length);
+
+	/* if necessary, copy _sdata_l1 to _sbss_l1 to L1 data bank A SRAM */
 	l1_data_a_length = _sbss_l1 - _sdata_l1;
-	if (l1_data_a_length > L1_DATA_A_LENGTH)
-		panic("L1 Data SRAM Bank A Overflow\n");
+	if (l1_data_a_length)
+		early_dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length);
 
-	/* Copy _sdata_l1 to _sbss_l1 to L1 data bank A SRAM */
-	dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length);
-
+	/* if necessary, copy _sdata_b_l1 to _sbss_b_l1 to L1 data bank B SRAM */
 	l1_data_b_length = _sbss_b_l1 - _sdata_b_l1;
-	if (l1_data_b_length > L1_DATA_B_LENGTH)
-		panic("L1 Data SRAM Bank B Overflow\n");
-
-	/* Copy _sdata_b_l1 to _sbss_b_l1 to L1 data bank B SRAM */
-	dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length +
+	if (l1_data_b_length)
+		early_dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length +
 			l1_data_a_length, l1_data_b_length);
 
+	early_dma_memcpy_done();
+
+	/* if necessary, copy _stext_l2 to _edata_l2 to L2 SRAM */
 	if (L2_LENGTH != 0) {
 		l2_length = _sbss_l2 - _stext_l2;
-		if (l2_length > L2_LENGTH)
-			panic("L2 SRAM Overflow\n");
-
-		/* Copy _stext_l2 to _edata_l2 to L2 SRAM */
-		dma_memcpy(_stext_l2, _l2_lma_start, l2_length);
+		if (l2_length)
+			memcpy(_stext_l2, _l2_lma_start, l2_length);
 	}
 }
 
@@ -472,7 +481,7 @@
 
 	if (DMA_UNCACHED_REGION > (_ramend - _ramstart)) {
 		console_init();
-		panic("DMA region exceeds memory limit: %lu.\n",
+		panic("DMA region exceeds memory limit: %lu.",
 			_ramend - _ramstart);
 	}
 	memory_end = _ramend - DMA_UNCACHED_REGION;
@@ -526,14 +535,13 @@
 
 	if (mtd_size == 0) {
 		console_init();
-		panic("Don't boot kernel without rootfs attached.\n");
+		panic("Don't boot kernel without rootfs attached.");
 	}
 
 	/* Relocate MTD image to the top of memory after the uncached memory area */
-	dma_memcpy((char *)memory_end, _end, mtd_size);
-
-	memory_mtd_start = memory_end;
-	_ebss = memory_mtd_start;	/* define _ebss for compatible */
+	uclinux_ram_map.phys = memory_mtd_start = memory_end;
+	uclinux_ram_map.size = mtd_size;
+	dma_memcpy((void *)uclinux_ram_map.phys, _end, uclinux_ram_map.size);
 #endif				/* CONFIG_MTD_UCLINUX */
 
 #if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263)
@@ -796,10 +804,8 @@
 	cclk = get_cclk();
 	sclk = get_sclk();
 
-#if !defined(CONFIG_BFIN_KERNEL_CLOCK)
-	if (ANOMALY_05000273 && cclk == sclk)
-		panic("ANOMALY 05000273, SCLK can not be same as CCLK");
-#endif
+	if ((ANOMALY_05000273 || ANOMALY_05000274) && (cclk >> 1) < sclk)
+		panic("ANOMALY 05000273 or 05000274: CCLK must be >= 2*SCLK");
 
 #ifdef BF561_FAMILY
 	if (ANOMALY_05000266) {
@@ -881,7 +887,7 @@
 				printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
 				       bfin_compiled_revid(), bfin_revid());
 				if (bfin_compiled_revid() > bfin_revid())
-					panic("Error: you are missing anomaly workarounds for this rev\n");
+					panic("Error: you are missing anomaly workarounds for this rev");
 			}
 		}
 		if (bfin_revid() < CONFIG_BF_REV_MIN || bfin_revid() > CONFIG_BF_REV_MAX)
@@ -891,16 +897,13 @@
 
 	/* We can't run on BF548-0.1 due to ANOMALY 05000448 */
 	if (bfin_cpuid() == 0x27de && bfin_revid() == 1)
-		panic("You can't run on this processor due to 05000448\n");
+		panic("You can't run on this processor due to 05000448");
 
 	printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n");
 
 	printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu MHz System Clock\n",
 	       cclk / 1000000, sclk / 1000000);
 
-	if (ANOMALY_05000273 && (cclk >> 1) <= sclk)
-		printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n");
-
 	setup_bootmem_allocator();
 
 	paging_init();
diff --git a/arch/blackfin/kernel/sys_bfin.c b/arch/blackfin/kernel/sys_bfin.c
index fce49d7..a8f1329 100644
--- a/arch/blackfin/kernel/sys_bfin.c
+++ b/arch/blackfin/kernel/sys_bfin.c
@@ -78,11 +78,6 @@
 	return do_mmap2(addr, len, prot, flags, fd, pgoff);
 }
 
-asmlinkage int sys_getpagesize(void)
-{
-	return PAGE_SIZE;
-}
-
 asmlinkage void *sys_sram_alloc(size_t size, unsigned long flags)
 {
 	return sram_alloc_with_lsl(size, flags);
diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c
index 2764612..0791eba 100644
--- a/arch/blackfin/kernel/time-ts.c
+++ b/arch/blackfin/kernel/time-ts.c
@@ -20,8 +20,9 @@
 
 #include <asm/blackfin.h>
 #include <asm/time.h>
+#include <asm/gptimers.h>
 
-#ifdef CONFIG_CYCLES_CLOCKSOURCE
+#if defined(CONFIG_CYCLES_CLOCKSOURCE)
 
 /* Accelerators for sched_clock()
  * convert from cycles(64bits) => nanoseconds (64bits)
@@ -58,15 +59,15 @@
 	return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
 }
 
-static cycle_t read_cycles(struct clocksource *cs)
+static cycle_t bfin_read_cycles(struct clocksource *cs)
 {
 	return __bfin_cycles_off + (get_cycles() << __bfin_cycles_mod);
 }
 
-static struct clocksource clocksource_bfin = {
-	.name		= "bfin_cycles",
+static struct clocksource bfin_cs_cycles = {
+	.name		= "bfin_cs_cycles",
 	.rating		= 350,
-	.read		= read_cycles,
+	.read		= bfin_read_cycles,
 	.mask		= CLOCKSOURCE_MASK(64),
 	.shift		= 22,
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
@@ -74,53 +75,198 @@
 
 unsigned long long sched_clock(void)
 {
-	return cycles_2_ns(read_cycles(&clocksource_bfin));
+	return cycles_2_ns(bfin_read_cycles(&bfin_cs_cycles));
 }
 
-static int __init bfin_clocksource_init(void)
+static int __init bfin_cs_cycles_init(void)
 {
 	set_cyc2ns_scale(get_cclk() / 1000);
 
-	clocksource_bfin.mult = clocksource_hz2mult(get_cclk(), clocksource_bfin.shift);
+	bfin_cs_cycles.mult = \
+		clocksource_hz2mult(get_cclk(), bfin_cs_cycles.shift);
 
-	if (clocksource_register(&clocksource_bfin))
+	if (clocksource_register(&bfin_cs_cycles))
 		panic("failed to register clocksource");
 
 	return 0;
 }
-
 #else
-# define bfin_clocksource_init()
+# define bfin_cs_cycles_init()
 #endif
 
+#ifdef CONFIG_GPTMR0_CLOCKSOURCE
+
+void __init setup_gptimer0(void)
+{
+	disable_gptimers(TIMER0bit);
+
+	set_gptimer_config(TIMER0_id, \
+		TIMER_OUT_DIS | TIMER_PERIOD_CNT | TIMER_MODE_PWM);
+	set_gptimer_period(TIMER0_id, -1);
+	set_gptimer_pwidth(TIMER0_id, -2);
+	SSYNC();
+	enable_gptimers(TIMER0bit);
+}
+
+static cycle_t bfin_read_gptimer0(void)
+{
+	return bfin_read_TIMER0_COUNTER();
+}
+
+static struct clocksource bfin_cs_gptimer0 = {
+	.name		= "bfin_cs_gptimer0",
+	.rating		= 400,
+	.read		= bfin_read_gptimer0,
+	.mask		= CLOCKSOURCE_MASK(32),
+	.shift		= 22,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init bfin_cs_gptimer0_init(void)
+{
+	setup_gptimer0();
+
+	bfin_cs_gptimer0.mult = \
+		clocksource_hz2mult(get_sclk(), bfin_cs_gptimer0.shift);
+
+	if (clocksource_register(&bfin_cs_gptimer0))
+		panic("failed to register clocksource");
+
+	return 0;
+}
+#else
+# define bfin_cs_gptimer0_init()
+#endif
+
+#ifdef CONFIG_CORE_TIMER_IRQ_L1
+__attribute__((l1_text))
+#endif
+irqreturn_t timer_interrupt(int irq, void *dev_id);
+
+static int bfin_timer_set_next_event(unsigned long, \
+		struct clock_event_device *);
+
+static void bfin_timer_set_mode(enum clock_event_mode, \
+		struct clock_event_device *);
+
+static struct clock_event_device clockevent_bfin = {
+#if defined(CONFIG_TICKSOURCE_GPTMR0)
+	.name		= "bfin_gptimer0",
+	.rating		= 300,
+	.irq		= IRQ_TIMER0,
+#else
+	.name		= "bfin_core_timer",
+	.rating		= 350,
+	.irq		= IRQ_CORETMR,
+#endif
+	.shift		= 32,
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.set_next_event = bfin_timer_set_next_event,
+	.set_mode	= bfin_timer_set_mode,
+};
+
+static struct irqaction bfin_timer_irq = {
+#if defined(CONFIG_TICKSOURCE_GPTMR0)
+	.name		= "Blackfin GPTimer0",
+#else
+	.name		= "Blackfin CoreTimer",
+#endif
+	.flags		= IRQF_DISABLED | IRQF_TIMER | \
+			  IRQF_IRQPOLL | IRQF_PERCPU,
+	.handler	= timer_interrupt,
+	.dev_id		= &clockevent_bfin,
+};
+
+#if defined(CONFIG_TICKSOURCE_GPTMR0)
 static int bfin_timer_set_next_event(unsigned long cycles,
                                      struct clock_event_device *evt)
 {
-	bfin_write_TCOUNT(cycles);
-	CSYNC();
+	disable_gptimers(TIMER0bit);
+
+	/* it starts counting three SCLK cycles after the TIMENx bit is set */
+	set_gptimer_pwidth(TIMER0_id, cycles - 3);
+	enable_gptimers(TIMER0bit);
 	return 0;
 }
 
 static void bfin_timer_set_mode(enum clock_event_mode mode,
-                                struct clock_event_device *evt)
+				struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC: {
+		set_gptimer_config(TIMER0_id, \
+			TIMER_OUT_DIS | TIMER_IRQ_ENA | \
+			TIMER_PERIOD_CNT | TIMER_MODE_PWM);
+		set_gptimer_period(TIMER0_id, get_sclk() / HZ);
+		set_gptimer_pwidth(TIMER0_id, get_sclk() / HZ - 1);
+		enable_gptimers(TIMER0bit);
+		break;
+	}
+	case CLOCK_EVT_MODE_ONESHOT:
+		disable_gptimers(TIMER0bit);
+		set_gptimer_config(TIMER0_id, \
+			TIMER_OUT_DIS | TIMER_IRQ_ENA | TIMER_MODE_PWM);
+		set_gptimer_period(TIMER0_id, 0);
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		disable_gptimers(TIMER0bit);
+		break;
+	case CLOCK_EVT_MODE_RESUME:
+		break;
+	}
+}
+
+static void bfin_timer_ack(void)
+{
+	set_gptimer_status(TIMER_GROUP1, TIMER_STATUS_TIMIL0);
+}
+
+static void __init bfin_timer_init(void)
+{
+	disable_gptimers(TIMER0bit);
+}
+
+static unsigned long  __init bfin_clockevent_check(void)
+{
+	setup_irq(IRQ_TIMER0, &bfin_timer_irq);
+	return get_sclk();
+}
+
+#else /* CONFIG_TICKSOURCE_CORETMR */
+
+static int bfin_timer_set_next_event(unsigned long cycles,
+				struct clock_event_device *evt)
+{
+	bfin_write_TCNTL(TMPWR);
+	CSYNC();
+	bfin_write_TCOUNT(cycles);
+	CSYNC();
+	bfin_write_TCNTL(TMPWR | TMREN);
+	return 0;
+}
+
+static void bfin_timer_set_mode(enum clock_event_mode mode,
+				struct clock_event_device *evt)
 {
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC: {
 		unsigned long tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1);
 		bfin_write_TCNTL(TMPWR);
-		bfin_write_TSCALE(TIME_SCALE - 1);
 		CSYNC();
+		bfin_write_TSCALE(TIME_SCALE - 1);
 		bfin_write_TPERIOD(tcount);
 		bfin_write_TCOUNT(tcount);
-		bfin_write_TCNTL(TMPWR | TMREN | TAUTORLD);
 		CSYNC();
+		bfin_write_TCNTL(TMPWR | TMREN | TAUTORLD);
 		break;
 	}
 	case CLOCK_EVT_MODE_ONESHOT:
-		bfin_write_TSCALE(TIME_SCALE - 1);
-		bfin_write_TCOUNT(0);
-		bfin_write_TCNTL(TMPWR | TMREN);
+		bfin_write_TCNTL(TMPWR);
 		CSYNC();
+		bfin_write_TSCALE(TIME_SCALE - 1);
+		bfin_write_TPERIOD(0);
+		bfin_write_TCOUNT(0);
 		break;
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
@@ -132,6 +278,10 @@
 	}
 }
 
+static void bfin_timer_ack(void)
+{
+}
+
 static void __init bfin_timer_init(void)
 {
 	/* power up the timer, but don't enable it just yet */
@@ -145,38 +295,32 @@
 	bfin_write_TPERIOD(0);
 	bfin_write_TCOUNT(0);
 
-	/* now enable the timer */
 	CSYNC();
 }
 
+static unsigned long  __init bfin_clockevent_check(void)
+{
+	setup_irq(IRQ_CORETMR, &bfin_timer_irq);
+	return get_cclk() / TIME_SCALE;
+}
+
+void __init setup_core_timer(void)
+{
+	bfin_timer_init();
+	bfin_timer_set_mode(CLOCK_EVT_MODE_PERIODIC, NULL);
+}
+#endif /* CONFIG_TICKSOURCE_GPTMR0 */
+
 /*
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-#ifdef CONFIG_CORE_TIMER_IRQ_L1
-__attribute__((l1_text))
-#endif
-irqreturn_t timer_interrupt(int irq, void *dev_id);
-
-static struct clock_event_device clockevent_bfin = {
-	.name		= "bfin_core_timer",
-	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-	.shift		= 32,
-	.set_next_event = bfin_timer_set_next_event,
-	.set_mode	= bfin_timer_set_mode,
-};
-
-static struct irqaction bfin_timer_irq = {
-	.name		= "Blackfin Core Timer",
-	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-	.handler	= timer_interrupt,
-	.dev_id		= &clockevent_bfin,
-};
-
 irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
 	struct clock_event_device *evt = dev_id;
+	smp_mb();
 	evt->event_handler(evt);
+	bfin_timer_ack();
 	return IRQ_HANDLED;
 }
 
@@ -184,9 +328,8 @@
 {
 	unsigned long timer_clk;
 
-	timer_clk = get_cclk() / TIME_SCALE;
+	timer_clk = bfin_clockevent_check();
 
-	setup_irq(IRQ_CORETMR, &bfin_timer_irq);
 	bfin_timer_init();
 
 	clockevent_bfin.mult = div_sc(timer_clk, NSEC_PER_SEC, clockevent_bfin.shift);
@@ -218,6 +361,7 @@
 	xtime.tv_nsec = 0;
 	set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec);
 
-	bfin_clocksource_init();
+	bfin_cs_cycles_init();
+	bfin_cs_gptimer0_init();
 	bfin_clockevent_init();
 }
diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
index 1bbacfb..adb54aa 100644
--- a/arch/blackfin/kernel/time.c
+++ b/arch/blackfin/kernel/time.c
@@ -24,14 +24,10 @@
 
 static struct irqaction bfin_timer_irq = {
 	.name = "Blackfin Timer Tick",
-#ifdef CONFIG_IRQ_PER_CPU
-	.flags = IRQF_DISABLED | IRQF_PERCPU,
-#else
 	.flags = IRQF_DISABLED
-#endif
 };
 
-#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
+#if defined(CONFIG_IPIPE)
 void __init setup_system_timer0(void)
 {
 	/* Power down the core timer, just to play safe. */
@@ -74,7 +70,7 @@
 static void __init
 time_sched_init(irqreturn_t(*timer_routine) (int, void *))
 {
-#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
+#if defined(CONFIG_IPIPE)
 	setup_system_timer0();
 	bfin_timer_irq.handler = timer_routine;
 	setup_irq(IRQ_TIMER0, &bfin_timer_irq);
@@ -94,7 +90,7 @@
 	unsigned long offset;
 	unsigned long clocks_per_jiffy;
 
-#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
+#if defined(CONFIG_IPIPE)
 	clocks_per_jiffy = bfin_read_TIMER0_PERIOD();
 	offset = bfin_read_TIMER0_COUNTER() / \
 		(((clocks_per_jiffy + 1) * HZ) / USEC_PER_SEC);
@@ -133,36 +129,25 @@
 	static long last_rtc_update;
 
 	write_seqlock(&xtime_lock);
-#if defined(CONFIG_TICK_SOURCE_SYSTMR0) && !defined(CONFIG_IPIPE)
-	/*
-	 * TIMIL0 is latched in __ipipe_grab_irq() when the I-Pipe is
-	 * enabled.
-	 */
-	if (get_gptimer_status(0) & TIMER_STATUS_TIMIL0) {
-#endif
-		do_timer(1);
+	do_timer(1);
 
-		/*
-		 * If we have an externally synchronized Linux clock, then update
-		 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-		 * called as close as possible to 500 ms before the new second starts.
-		 */
-		if (ntp_synced() &&
-		    xtime.tv_sec > last_rtc_update + 660 &&
-		    (xtime.tv_nsec / NSEC_PER_USEC) >=
-		    500000 - ((unsigned)TICK_SIZE) / 2
-		    && (xtime.tv_nsec / NSEC_PER_USEC) <=
-		    500000 + ((unsigned)TICK_SIZE) / 2) {
-			if (set_rtc_mmss(xtime.tv_sec) == 0)
-				last_rtc_update = xtime.tv_sec;
-			else
-				/* Do it again in 60s. */
-				last_rtc_update = xtime.tv_sec - 600;
-		}
-#if defined(CONFIG_TICK_SOURCE_SYSTMR0) && !defined(CONFIG_IPIPE)
-		set_gptimer_status(0, TIMER_STATUS_TIMIL0);
+	/*
+	 * If we have an externally synchronized Linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 */
+	if (ntp_synced() &&
+	    xtime.tv_sec > last_rtc_update + 660 &&
+	    (xtime.tv_nsec / NSEC_PER_USEC) >=
+	    500000 - ((unsigned)TICK_SIZE) / 2
+	    && (xtime.tv_nsec / NSEC_PER_USEC) <=
+	    500000 + ((unsigned)TICK_SIZE) / 2) {
+		if (set_rtc_mmss(xtime.tv_sec) == 0)
+			last_rtc_update = xtime.tv_sec;
+		else
+			/* Do it again in 60s. */
+			last_rtc_update = xtime.tv_sec - 600;
 	}
-#endif
 	write_sequnlock(&xtime_lock);
 
 #ifdef CONFIG_IPIPE
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index ffe7fb5..aa76dfb 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -68,6 +68,13 @@
 	({ if (0) printk(fmt, ##arg); 0; })
 #endif
 
+#if defined(CONFIG_DEBUG_MMRS) || defined(CONFIG_DEBUG_MMRS_MODULE)
+u32 last_seqstat;
+#ifdef CONFIG_DEBUG_MMRS_MODULE
+EXPORT_SYMBOL(last_seqstat);
+#endif
+#endif
+
 /* Initiate the event table handler */
 void __init trap_init(void)
 {
@@ -79,7 +86,6 @@
 static void decode_address(char *buf, unsigned long address)
 {
 #ifdef CONFIG_DEBUG_VERBOSE
-	struct vm_list_struct *vml;
 	struct task_struct *p;
 	struct mm_struct *mm;
 	unsigned long flags, offset;
@@ -196,6 +202,11 @@
 
 asmlinkage void double_fault_c(struct pt_regs *fp)
 {
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
+	int j;
+	trace_buffer_save(j);
+#endif
+
 	console_verbose();
 	oops_in_progress = 1;
 #ifdef CONFIG_DEBUG_VERBOSE
@@ -220,9 +231,10 @@
 		dump_bfin_process(fp);
 		dump_bfin_mem(fp);
 		show_regs(fp);
+		dump_bfin_trace_buffer();
 	}
 #endif
-	panic("Double Fault - unrecoverable event\n");
+	panic("Double Fault - unrecoverable event");
 
 }
 
@@ -239,6 +251,9 @@
 	unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
 
 	trace_buffer_save(j);
+#if defined(CONFIG_DEBUG_MMRS) || defined(CONFIG_DEBUG_MMRS_MODULE)
+	last_seqstat = (u32)fp->seqstat;
+#endif
 
 	/* Important - be very careful dereferncing pointers - will lead to
 	 * double faults if the stack has become corrupt
@@ -588,6 +603,9 @@
 		force_sig_info(sig, &info, current);
 	}
 
+	if (ANOMALY_05000461 && trapnr == VEC_HWERR && !access_ok(VERIFY_READ, fp->pc, 8))
+		fp->pc = SAFE_USER_INSTRUCTION;
+
 	trace_buffer_restore(j);
 	return;
 }
@@ -832,6 +850,11 @@
 	decode_address(buf, (unsigned int)stack);
 	printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf);
 
+	if (!access_ok(VERIFY_READ, stack, (unsigned int)endstack - (unsigned int)stack)) {
+		printk(KERN_NOTICE "Invalid stack pointer\n");
+		return;
+	}
+
 	/* First thing is to look for a frame pointer */
 	for (addr = (unsigned int *)((unsigned int)stack & ~0xF); addr < endstack; addr++) {
 		if (*addr & 0x1)
@@ -1066,6 +1089,29 @@
 	unsigned int cpu = smp_processor_id();
 	unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic();
 
+	verbose_printk(KERN_NOTICE "\n");
+	if (CPUID != bfin_cpuid())
+		verbose_printk(KERN_NOTICE "Compiled for cpu family 0x%04x (Rev %d), "
+			"but running on:0x%04x (Rev %d)\n",
+			CPUID, bfin_compiled_revid(), bfin_cpuid(), bfin_revid());
+
+	verbose_printk(KERN_NOTICE "ADSP-%s-0.%d",
+		CPU, bfin_compiled_revid());
+
+	if (bfin_compiled_revid() !=  bfin_revid())
+		verbose_printk("(Detected 0.%d)", bfin_revid());
+
+	verbose_printk(" %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n",
+		get_cclk()/1000000, get_sclk()/1000000,
+#ifdef CONFIG_MPU
+		"mpu on"
+#else
+		"mpu off"
+#endif
+		);
+
+	verbose_printk(KERN_NOTICE "%s", linux_banner);
+
 	verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
 	verbose_printk(KERN_NOTICE " SEQSTAT: %08lx  IPEND: %04lx  SYSCFG: %04lx\n",
 		(long)fp->seqstat, fp->ipend, fp->syscfg);
@@ -1246,5 +1292,5 @@
 	dump_bfin_mem(fp);
 	show_regs(fp);
 	dump_stack();
-	panic("Unrecoverable event\n");
+	panic("Unrecoverable event");
 }
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S
index 27952ae..8b67167 100644
--- a/arch/blackfin/kernel/vmlinux.lds.S
+++ b/arch/blackfin/kernel/vmlinux.lds.S
@@ -50,7 +50,9 @@
 		_text = .;
 		__stext = .;
 		TEXT_TEXT
+#ifndef CONFIG_SCHEDULE_L1
 		SCHED_TEXT
+#endif
 		LOCK_TEXT
 		KPROBES_TEXT
 		*(.text.*)
@@ -180,6 +182,9 @@
 		. = ALIGN(4);
 		__stext_l1 = .;
 		*(.l1.text)
+#ifdef CONFIG_SCHEDULE_L1
+		SCHED_TEXT
+#endif
 		. = ALIGN(4);
 		__etext_l1 = .;
 	}
diff --git a/arch/blackfin/mach-bf518/Kconfig b/arch/blackfin/mach-bf518/Kconfig
index f397ede..4c76fef 100644
--- a/arch/blackfin/mach-bf518/Kconfig
+++ b/arch/blackfin/mach-bf518/Kconfig
@@ -156,6 +156,7 @@
 	default 11
 config IRQ_TIMER0
 	int "IRQ_TIMER0"
+	default 7 if TICKSOURCE_GPTMR0
 	default 8
 config IRQ_TIMER1
 	int "IRQ_TIMER1"
diff --git a/arch/blackfin/mach-bf518/boards/ezbrd.c b/arch/blackfin/mach-bf518/boards/ezbrd.c
index 41f2eac..62bba09 100644
--- a/arch/blackfin/mach-bf518/boards/ezbrd.c
+++ b/arch/blackfin/mach-bf518/boards/ezbrd.c
@@ -82,7 +82,11 @@
 
 static struct resource ezbrd_flash_resource = {
 	.start = 0x20000000,
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	.end   = 0x202fffff,
+#else
 	.end   = 0x203fffff,
+#endif
 	.flags = IORESOURCE_MEM,
 };
 
@@ -162,8 +166,8 @@
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+	|| defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
 	.enable_dma = 1,         /* use dma transfer with this chip*/
@@ -249,8 +253,8 @@
 	},
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+	|| defined(CONFIG_BFIN_SPI_ADC_MODULE)
 	{
 		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
 		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
@@ -514,7 +518,7 @@
 #endif
 
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
-#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
 	{
 		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
 	},
@@ -678,6 +682,11 @@
 				ARRAY_SIZE(bfin_i2c_board_info));
 	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
 	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+	/* setup BF518-EZBRD GPIO pin PG11 to AMS2, PG15 to AMS3. */
+	peripheral_request(P_AMS2, "ParaFlash");
+#if !defined(CONFIG_SPI_BFIN) && !defined(CONFIG_SPI_BFIN_MODULE)
+	peripheral_request(P_AMS3, "ParaFlash");
+#endif
 	return 0;
 }
 
diff --git a/arch/blackfin/mach-bf518/include/mach/anomaly.h b/arch/blackfin/mach-bf518/include/mach/anomaly.h
index c847bb1..b69bd9a 100644
--- a/arch/blackfin/mach-bf518/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf518/include/mach/anomaly.h
@@ -6,14 +6,19 @@
  * Licensed under the GPL-2 or later.
  */
 
-/* This file shoule be up to date with:
+/* This file should be up to date with:
  *  - Revision B, 02/03/2009; ADSP-BF512/BF514/BF516/BF518 Blackfin Processor Anomaly List
  */
 
+/* We plan on not supporting 0.0 silicon, but 0.1 isn't out yet - sorry */
+#if __SILICON_REVISION__ < 0
+# error will not work on BF518 silicon version
+#endif
+
 #ifndef _MACH_ANOMALY_H_
 #define _MACH_ANOMALY_H_
 
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
+/* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */
 #define ANOMALY_05000074 (1)
 /* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */
 #define ANOMALY_05000122 (1)
@@ -47,7 +52,7 @@
 #define ANOMALY_05000435 (1)
 /* PORTx_DRIVE and PORTx_HYSTERESIS Registers Read Back Incorrect Values */
 #define ANOMALY_05000438 (1)
-/* Preboot Cannot be Used to Program the PLL_DIV Register */
+/* Preboot Cannot be Used to Alter the PLL_DIV Register */
 #define ANOMALY_05000439 (1)
 /* bfrom_SysControl() Cannot be Used to Write the PLL_DIV Register */
 #define ANOMALY_05000440 (1)
@@ -61,32 +66,56 @@
 #define ANOMALY_05000453 (1)
 /* PPI_FS3 is Driven One Half Cycle Later Than PPI Data */
 #define ANOMALY_05000455 (1)
+/* False Hardware Error when RETI points to invalid memory */
+#define ANOMALY_05000461 (1)
 
 /* Anomalies that don't exist on this proc */
+#define ANOMALY_05000099 (0)
+#define ANOMALY_05000119 (0)
+#define ANOMALY_05000120 (0)
 #define ANOMALY_05000125 (0)
+#define ANOMALY_05000149 (0)
 #define ANOMALY_05000158 (0)
+#define ANOMALY_05000171 (0)
+#define ANOMALY_05000179 (0)
 #define ANOMALY_05000183 (0)
 #define ANOMALY_05000198 (0)
+#define ANOMALY_05000215 (0)
+#define ANOMALY_05000220 (0)
+#define ANOMALY_05000227 (0)
 #define ANOMALY_05000230 (0)
+#define ANOMALY_05000231 (0)
+#define ANOMALY_05000233 (0)
+#define ANOMALY_05000242 (0)
 #define ANOMALY_05000244 (0)
+#define ANOMALY_05000248 (0)
+#define ANOMALY_05000250 (0)
 #define ANOMALY_05000261 (0)
 #define ANOMALY_05000263 (0)
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000273 (0)
+#define ANOMALY_05000274 (0)
 #define ANOMALY_05000278 (0)
 #define ANOMALY_05000285 (0)
+#define ANOMALY_05000287 (0)
+#define ANOMALY_05000301 (0)
 #define ANOMALY_05000305 (0)
 #define ANOMALY_05000307 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000312 (0)
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000353 (0)
+#define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (0)
+#define ANOMALY_05000389 (0)
+#define ANOMALY_05000400 (0)
 #define ANOMALY_05000412 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
+#define ANOMALY_05000456 (0)
+#define ANOMALY_05000450 (0)
 
 #endif
diff --git a/arch/blackfin/mach-bf518/include/mach/portmux.h b/arch/blackfin/mach-bf518/include/mach/portmux.h
index f618b48..a0fc77f 100644
--- a/arch/blackfin/mach-bf518/include/mach/portmux.h
+++ b/arch/blackfin/mach-bf518/include/mach/portmux.h
@@ -185,6 +185,10 @@
 #define P_PTP_PPS		(P_DEFINED | P_IDENT(GPIO_PG12) | P_FUNCT(2))
 #define P_PTP_CLKOUT		(P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(2))
 
-#define P_HWAIT		(P_DEFINED | P_IDENT(GPIO_PG000000000) | P_FUNCT(1))
+/* AMS */
+#define P_AMS2			(P_DEFINED | P_IDENT(GPIO_PG11) | P_FUNCT(1))
+#define P_AMS3			(P_DEFINED | P_IDENT(GPIO_PG15) | P_FUNCT(2))
+
+#define P_HWAIT			(P_DEFINED | P_IDENT(GPIO_PG000000000) | P_FUNCT(1))
 
 #endif				/* _MACH_PORTMUX_H_ */
diff --git a/arch/blackfin/mach-bf527/Kconfig b/arch/blackfin/mach-bf527/Kconfig
index 8438ec6..848ac6f 100644
--- a/arch/blackfin/mach-bf527/Kconfig
+++ b/arch/blackfin/mach-bf527/Kconfig
@@ -170,6 +170,7 @@
 	default 11
 config IRQ_TIMER0
 	int "IRQ_TIMER0"
+	default 7 if TICKSOURCE_GPTMR0
 	default 8
 config IRQ_TIMER1
 	int "IRQ_TIMER1"
diff --git a/arch/blackfin/mach-bf527/boards/cm_bf527.c b/arch/blackfin/mach-bf527/boards/cm_bf527.c
index 48e69ee..6d6f9ef 100644
--- a/arch/blackfin/mach-bf527/boards/cm_bf527.c
+++ b/arch/blackfin/mach-bf527/boards/cm_bf527.c
@@ -463,8 +463,8 @@
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+	|| defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
 	.enable_dma = 1,         /* use dma transfer with this chip*/
@@ -554,8 +554,8 @@
 	},
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+	|| defined(CONFIG_BFIN_SPI_ADC_MODULE)
 	{
 		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
 		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
@@ -789,7 +789,7 @@
 #endif
 
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
-#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
 	{
 		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
 		.type = "pcf8574_lcd",
diff --git a/arch/blackfin/mach-bf527/boards/ezbrd.c b/arch/blackfin/mach-bf527/boards/ezbrd.c
index 7fe480e..1435c5d 100644
--- a/arch/blackfin/mach-bf527/boards/ezbrd.c
+++ b/arch/blackfin/mach-bf527/boards/ezbrd.c
@@ -247,8 +247,8 @@
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+	|| defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
 	.enable_dma = 1,         /* use dma transfer with this chip*/
@@ -354,8 +354,8 @@
 	},
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+	|| defined(CONFIG_BFIN_SPI_ADC_MODULE)
 	{
 		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
 		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
@@ -586,7 +586,7 @@
 #endif
 
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
-#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
 	{
 		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
 	},
diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
index d086411..147edd1 100644
--- a/arch/blackfin/mach-bf527/boards/ezkit.c
+++ b/arch/blackfin/mach-bf527/boards/ezkit.c
@@ -485,8 +485,8 @@
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+	|| defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
 	.enable_dma = 1,         /* use dma transfer with this chip*/
@@ -509,6 +509,13 @@
 };
 #endif
 
+#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
+static struct bfin5xx_spi_chip  mmc_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+#endif
+
 #if defined(CONFIG_PBX)
 static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
 	.ctl_reg	= 0x4, /* send zero */
@@ -593,8 +600,8 @@
 	},
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+	|| defined(CONFIG_BFIN_SPI_ADC_MODULE)
 	{
 		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
 		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
@@ -624,6 +631,17 @@
 		.controller_data = &ad9960_spi_chip_info,
 	},
 #endif
+#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
+	{
+		.modalias = "mmc_spi",
+		.max_speed_hz = 20000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 3,
+		.controller_data = &mmc_spi_chip_info,
+		.mode = SPI_MODE_0,
+	},
+#endif
+
 #if defined(CONFIG_PBX)
 	{
 		.modalias = "fxs-spi",
@@ -836,7 +854,7 @@
 #endif
 
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
-#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
 	{
 		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
 	},
diff --git a/arch/blackfin/mach-bf527/include/mach/anomaly.h b/arch/blackfin/mach-bf527/include/mach/anomaly.h
index df6808d..c84ddea 100644
--- a/arch/blackfin/mach-bf527/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf527/include/mach/anomaly.h
@@ -6,14 +6,19 @@
  * Licensed under the GPL-2 or later.
  */
 
-/* This file shoule be up to date with:
- *  - Revision B, 08/12/2008; ADSP-BF526 Blackfin Processor Anomaly List
- *  - Revision E, 08/18/2008; ADSP-BF527 Blackfin Processor Anomaly List
+/* This file should be up to date with:
+ *  - Revision C, 03/13/2009; ADSP-BF526 Blackfin Processor Anomaly List
+ *  - Revision F, 03/03/2009; ADSP-BF527 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define _MACH_ANOMALY_H_
 
+/* We do not support old silicon - sorry */
+#if __SILICON_REVISION__ < 0
+# error will not work on BF526/BF527 silicon version
+#endif
+
 #if defined(__ADSPBF522__) || defined(__ADSPBF524__) || defined(__ADSPBF526__)
 # define ANOMALY_BF526 1
 #else
@@ -25,158 +30,203 @@
 # define ANOMALY_BF527 0
 #endif
 
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
+#define _ANOMALY_BF526(rev526) (ANOMALY_BF526 && __SILICON_REVISION__ rev526)
+#define _ANOMALY_BF527(rev527) (ANOMALY_BF527 && __SILICON_REVISION__ rev527)
+#define _ANOMALY_BF526_BF527(rev526, rev527) (_ANOMALY_BF526(rev526) || _ANOMALY_BF527(rev527))
+
+/* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */
 #define ANOMALY_05000074 (1)
 /* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
 #define ANOMALY_05000119 (1)	/* note: brokenness is noted in documentation, not anomaly sheet */
 /* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */
 #define ANOMALY_05000122 (1)
-/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */
+/* False Hardware Error from an Access in the Shadow of a Conditional Branch */
 #define ANOMALY_05000245 (1)
+/* Incorrect Timer Pulse Width in Single-Shot PWM_OUT Mode with External Clock */
+#define ANOMALY_05000254 (1)
 /* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */
 #define ANOMALY_05000265 (1)
 /* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
 #define ANOMALY_05000310 (1)
 /* PPI Is Level-Sensitive on First Transfer In Single Frame Sync Modes */
-#define ANOMALY_05000313 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000313 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Incorrect Access of OTP_STATUS During otp_write() Function */
-#define ANOMALY_05000328 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000328 (_ANOMALY_BF527(< 2))
+/* Host DMA Boot Modes Are Not Functional */
+#define ANOMALY_05000330 (__SILICON_REVISION__ < 2)
 /* Disallowed Configuration Prevents Subsequent Allowed Configuration on Host DMA Port */
-#define ANOMALY_05000337 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000337 (_ANOMALY_BF527(< 2))
 /* Ethernet MAC MDIO Reads Do Not Meet IEEE Specification */
-#define ANOMALY_05000341 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000341 (_ANOMALY_BF527(< 2))
 /* TWI May Not Operate Correctly Under Certain Signal Termination Conditions */
-#define ANOMALY_05000342 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000342 (_ANOMALY_BF527(< 2))
 /* USB Calibration Value Is Not Initialized */
-#define ANOMALY_05000346 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000346 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* USB Calibration Value to use */
 #define ANOMALY_05000346_value 0xE510
 /* Preboot Routine Incorrectly Alters Reset Value of USB Register */
-#define ANOMALY_05000347 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000347 (_ANOMALY_BF527(< 2))
 /* Security Features Are Not Functional */
-#define ANOMALY_05000348 (ANOMALY_BF527 && __SILICON_REVISION__ < 1)
+#define ANOMALY_05000348 (_ANOMALY_BF527(< 1))
 /* bfrom_SysControl() Firmware Function Performs Improper System Reset */
-#define ANOMALY_05000353 (ANOMALY_BF526)
+#define ANOMALY_05000353 (_ANOMALY_BF526(< 1))
 /* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */
-#define ANOMALY_05000355 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000355 (_ANOMALY_BF527(< 2))
 /* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
-#define ANOMALY_05000357 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000357 (_ANOMALY_BF527(< 2))
 /* Incorrect Revision Number in DSPID Register */
-#define ANOMALY_05000364 (ANOMALY_BF527 && __SILICON_REVISION__ == 1)
+#define ANOMALY_05000364 (_ANOMALY_BF527(== 1))
 /* PPI Underflow Error Goes Undetected in ITU-R 656 Mode */
 #define ANOMALY_05000366 (1)
 /* Incorrect Default CSEL Value in PLL_DIV */
-#define ANOMALY_05000368 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000368 (_ANOMALY_BF527(< 2))
 /* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
-#define ANOMALY_05000371 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000371 (_ANOMALY_BF527(< 2))
 /* Authentication Fails To Initiate */
-#define ANOMALY_05000376 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000376 (_ANOMALY_BF527(< 2))
 /* Data Read From L3 Memory by USB DMA May be Corrupted */
-#define ANOMALY_05000380 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000380 (_ANOMALY_BF527(< 2))
 /* 8-Bit NAND Flash Boot Mode Not Functional */
-#define ANOMALY_05000382 (__SILICON_REVISION__ < 2)
-/* Host Must Not Read Back During Host DMA Boot */
-#define ANOMALY_05000384 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000382 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Boot from OTP Memory Not Functional */
-#define ANOMALY_05000385 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000385 (_ANOMALY_BF527(< 2))
 /* bfrom_SysControl() Firmware Routine Not Functional */
-#define ANOMALY_05000386 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000386 (_ANOMALY_BF527(< 2))
 /* Programmable Preboot Settings Not Functional */
-#define ANOMALY_05000387 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000387 (_ANOMALY_BF527(< 2))
 /* CRC32 Checksum Support Not Functional */
-#define ANOMALY_05000388 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000388 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Reset Vector Must Not Be in SDRAM Memory Space */
-#define ANOMALY_05000389 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000389 (_ANOMALY_BF527(< 2))
 /* pTempCurrent Not Present in ADI_BOOT_DATA Structure */
-#define ANOMALY_05000392 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000392 (_ANOMALY_BF527(< 2))
 /* Deprecated Value of dTempByteCount in ADI_BOOT_DATA Structure */
-#define ANOMALY_05000393 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000393 (_ANOMALY_BF527(< 2))
 /* Log Buffer Not Functional */
-#define ANOMALY_05000394 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000394 (_ANOMALY_BF527(< 2))
 /* Hook Routine Not Functional */
-#define ANOMALY_05000395 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000395 (_ANOMALY_BF527(< 2))
 /* Header Indirect Bit Not Functional */
-#define ANOMALY_05000396 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000396 (_ANOMALY_BF527(< 2))
 /* BK_ONES, BK_ZEROS, and BK_DATECODE Constants Not Functional */
-#define ANOMALY_05000397 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000397 (_ANOMALY_BF527(< 2))
 /* SWRESET, DFRESET and WDRESET Bits in the SYSCR Register Not Functional */
-#define ANOMALY_05000398 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000398 (_ANOMALY_BF527(< 2))
 /* BCODE_NOBOOT in BCODE Field of SYSCR Register Not Functional */
-#define ANOMALY_05000399 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000399 (_ANOMALY_BF527(< 2))
 /* PPI Data Signals D0 and D8 do not Tristate After Disabling PPI */
-#define ANOMALY_05000401 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000401 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Level-Sensitive External GPIO Wakeups May Cause Indefinite Stall */
-#define ANOMALY_05000403 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000403 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Lockbox SESR Disallows Certain User Interrupts */
-#define ANOMALY_05000404 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000404 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Lockbox SESR Firmware Does Not Save/Restore Full Context */
 #define ANOMALY_05000405 (1)
 /* Lockbox SESR Firmware Arguments Are Not Retained After First Initialization */
-#define ANOMALY_05000407 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000407 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Lockbox Firmware Memory Cleanup Routine Does not Clear Registers */
 #define ANOMALY_05000408 (1)
 /* Lockbox firmware leaves MDMA0 channel enabled */
-#define ANOMALY_05000409 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000409 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Incorrect Default Internal Voltage Regulator Setting */
-#define ANOMALY_05000410 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000410 (_ANOMALY_BF527(< 2))
 /* bfrom_SysControl() Firmware Function Cannot be Used to Enter Power Saving Modes */
-#define ANOMALY_05000411 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000411 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* OTP_CHECK_FOR_PREV_WRITE Bit is Not Functional in bfrom_OtpWrite() API */
-#define ANOMALY_05000414 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000414 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* DEB2_URGENT Bit Not Functional */
-#define ANOMALY_05000415 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000415 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Speculative Fetches Can Cause Undesired External FIFO Operations */
 #define ANOMALY_05000416 (1)
 /* SPORT0 Ignores External TSCLK0 on PG14 When TMR6 is an Output */
-#define ANOMALY_05000417 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
-/* tSFSPE and tHFSPE Do Not Meet Data Sheet Specifications */
-#define ANOMALY_05000418 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000417 (_ANOMALY_BF527(< 2))
+/* PPI Timing Requirements tSFSPE and tHFSPE Do Not Meet Data Sheet Specifications */
+#define ANOMALY_05000418 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* USB PLL_STABLE Bit May Not Accurately Reflect the USB PLL's Status */
-#define ANOMALY_05000420 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000420 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* TWI Fall Time (Tof) May Violate the Minimum I2C Specification */
 #define ANOMALY_05000421 (1)
 /* TWI Input Capacitance (Ci) May Violate the Maximum I2C Specification */
-#define ANOMALY_05000422 (ANOMALY_BF527 && __SILICON_REVISION__ > 1)
+#define ANOMALY_05000422 (_ANOMALY_BF526_BF527(> 0, > 1))
 /* Certain Ethernet Frames With Errors are Misclassified in RMII Mode */
-#define ANOMALY_05000423 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000423 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Internal Voltage Regulator Not Trimmed */
-#define ANOMALY_05000424 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000424 (_ANOMALY_BF527(< 2))
 /* Multichannel SPORT Channel Misalignment Under Specific Configuration */
-#define ANOMALY_05000425 (__SILICON_REVISION__ < 2)
-/* Speculative Fetches of Indirect-Pointer Instructions Can Cause Spurious Hardware Errors */
+#define ANOMALY_05000425 (_ANOMALY_BF526_BF527(< 1, < 2))
+/* Speculative Fetches of Indirect-Pointer Instructions Can Cause False Hardware Errors */
 #define ANOMALY_05000426 (1)
 /* WB_EDGE Bit in NFC_IRQSTAT Incorrectly Reflects Buffer Status Instead of IRQ Status */
-#define ANOMALY_05000429 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000429 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Software System Reset Corrupts PLL_LOCKCNT Register */
-#define ANOMALY_05000430 (ANOMALY_BF527 && __SILICON_REVISION__ > 1)
+#define ANOMALY_05000430 (_ANOMALY_BF527(> 1))
+/* Incorrect Use of Stack in Lockbox Firmware During Authentication */
+#define ANOMALY_05000431 (1)
 /* bfrom_SysControl() Does Not Clear SIC_IWR1 Before Executing PLL Programming Sequence */
-#define ANOMALY_05000432 (ANOMALY_BF526)
+#define ANOMALY_05000432 (_ANOMALY_BF526(< 1))
 /* Certain SIC Registers are not Reset After Soft or Core Double Fault Reset */
-#define ANOMALY_05000435 ((ANOMALY_BF526 && __SILICON_REVISION__ < 1) || ANOMALY_BF527)
+#define ANOMALY_05000435 (_ANOMALY_BF526_BF527(< 1, >= 0))
+/* Preboot Cannot be Used to Alter the PLL_DIV Register */
+#define ANOMALY_05000439 (_ANOMALY_BF526_BF527(< 1, >= 0))
+/* bfrom_SysControl() Cannot be Used to Write the PLL_DIV Register */
+#define ANOMALY_05000440 (_ANOMALY_BF526_BF527(< 1, >= 0))
+/* OTP Write Accesses Not Supported */
+#define ANOMALY_05000442 (_ANOMALY_BF527(< 1))
 /* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */
 #define ANOMALY_05000443 (1)
+/* The WURESET Bit in the SYSCR Register is not Functional */
+#define ANOMALY_05000445 (1)
+/* BCODE_QUICKBOOT, BCODE_ALLBOOT, and BCODE_FULLBOOT Settings in SYSCR Register Not Functional */
+#define ANOMALY_05000451 (1)
+/* Incorrect Default Hysteresis Setting for RESET, NMI, and BMODE Signals */
+#define ANOMALY_05000452 (_ANOMALY_BF526_BF527(< 1, >= 0))
+/* USB Receive Interrupt Is Not Generated in DMA Mode 1 */
+#define ANOMALY_05000456 (1)
+/* Host DMA Port Responds to Certain Bus Activity Without HOST_CE Assertion */
+#define ANOMALY_05000457 (1)
+/* False Hardware Error when RETI points to invalid memory */
+#define ANOMALY_05000461 (1)
 
 /* Anomalies that don't exist on this proc */
+#define ANOMALY_05000099 (0)
+#define ANOMALY_05000120 (0)
 #define ANOMALY_05000125 (0)
+#define ANOMALY_05000149 (0)
 #define ANOMALY_05000158 (0)
+#define ANOMALY_05000171 (0)
+#define ANOMALY_05000179 (0)
 #define ANOMALY_05000183 (0)
 #define ANOMALY_05000198 (0)
+#define ANOMALY_05000215 (0)
+#define ANOMALY_05000220 (0)
+#define ANOMALY_05000227 (0)
 #define ANOMALY_05000230 (0)
+#define ANOMALY_05000231 (0)
+#define ANOMALY_05000233 (0)
+#define ANOMALY_05000242 (0)
 #define ANOMALY_05000244 (0)
+#define ANOMALY_05000248 (0)
+#define ANOMALY_05000250 (0)
 #define ANOMALY_05000261 (0)
 #define ANOMALY_05000263 (0)
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000273 (0)
+#define ANOMALY_05000274 (0)
 #define ANOMALY_05000278 (0)
 #define ANOMALY_05000285 (0)
+#define ANOMALY_05000287 (0)
+#define ANOMALY_05000301 (0)
 #define ANOMALY_05000305 (0)
 #define ANOMALY_05000307 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000312 (0)
 #define ANOMALY_05000323 (0)
+#define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
+#define ANOMALY_05000400 (0)
 #define ANOMALY_05000412 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
+#define ANOMALY_05000450 (0)
 
 #endif
diff --git a/arch/blackfin/mach-bf533/Kconfig b/arch/blackfin/mach-bf533/Kconfig
index 14427de..4c57244 100644
--- a/arch/blackfin/mach-bf533/Kconfig
+++ b/arch/blackfin/mach-bf533/Kconfig
@@ -59,6 +59,7 @@
 	default 10
 config TIMER0
 	int "TIMER0"
+	default 7 if TICKSOURCE_GPTMR0
 	default 8
 config TIMER1
 	int "TIMER1"
diff --git a/arch/blackfin/mach-bf533/boards/H8606.c b/arch/blackfin/mach-bf533/boards/H8606.c
index 0c66bf4..895f213 100644
--- a/arch/blackfin/mach-bf533/boards/H8606.c
+++ b/arch/blackfin/mach-bf533/boards/H8606.c
@@ -173,7 +173,7 @@
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
 	.ctl_reg = 0x1000,
@@ -216,7 +216,7 @@
 	},
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 	{
 		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
 		.max_speed_hz = 4,     /* actual baudrate is SCLK/(2xspeed_hz) */
diff --git a/arch/blackfin/mach-bf533/boards/cm_bf533.c b/arch/blackfin/mach-bf533/boards/cm_bf533.c
index e897487..a727e53 100644
--- a/arch/blackfin/mach-bf533/boards/cm_bf533.c
+++ b/arch/blackfin/mach-bf533/boards/cm_bf533.c
@@ -82,7 +82,7 @@
 #endif
 
 /* SPI ADC chip */
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
 	.enable_dma = 1,         /* use dma transfer with this chip*/
 	.bits_per_word = 16,
@@ -117,7 +117,7 @@
 	},
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 	{
 		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
 		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c
index 08cd096..842f1c9 100644
--- a/arch/blackfin/mach-bf533/boards/ezkit.c
+++ b/arch/blackfin/mach-bf533/boards/ezkit.c
@@ -118,7 +118,7 @@
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
 	.enable_dma = 1,         /* use dma transfer with this chip*/
@@ -154,7 +154,7 @@
 	},
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 	{
 		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
 		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c
index db96f33..e19c565 100644
--- a/arch/blackfin/mach-bf533/boards/stamp.c
+++ b/arch/blackfin/mach-bf533/boards/stamp.c
@@ -192,7 +192,7 @@
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
 	.enable_dma = 1,         /* use dma transfer with this chip*/
@@ -237,7 +237,7 @@
 	},
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 	{
 		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
 		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
@@ -448,7 +448,7 @@
 		.irq = 39,
 	},
 #endif
-#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
 	{
 		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
 	},
diff --git a/arch/blackfin/mach-bf533/include/mach/anomaly.h b/arch/blackfin/mach-bf533/include/mach/anomaly.h
index 1cf893e..31145b5 100644
--- a/arch/blackfin/mach-bf533/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf533/include/mach/anomaly.h
@@ -6,7 +6,7 @@
  * Licensed under the GPL-2 or later.
  */
 
-/* This file shoule be up to date with:
+/* This file should be up to date with:
  *  - Revision E, 09/18/2008; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
  */
 
@@ -34,12 +34,12 @@
 # define ANOMALY_BF533 0
 #endif
 
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot 2 Not Supported */
+/* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */
 #define ANOMALY_05000074 (1)
 /* UART Line Status Register (UART_LSR) Bits Are Not Updated at the Same Time */
 #define ANOMALY_05000099 (__SILICON_REVISION__ < 5)
 /* Watchpoint Status Register (WPSTAT) Bits Are Set on Every Corresponding Match */
-#define ANOMALY_05000105 (1)
+#define ANOMALY_05000105 (__SILICON_REVISION__ > 2)
 /* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
 #define ANOMALY_05000119 (1)
 /* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */
@@ -48,7 +48,7 @@
 #define ANOMALY_05000158 (__SILICON_REVISION__ < 5)
 /* PPI Data Lengths Between 8 and 16 Do Not Zero Out Upper Bits */
 #define ANOMALY_05000166 (1)
-/* Turning Serial Ports on with External Frame Syncs */
+/* Turning SPORTs on while External Frame Sync Is Active May Corrupt Data */
 #define ANOMALY_05000167 (1)
 /* PPI_COUNT Cannot Be Programmed to 0 in General Purpose TX or RX Modes */
 #define ANOMALY_05000179 (__SILICON_REVISION__ < 5)
@@ -67,9 +67,9 @@
 /* Current DMA Address Shows Wrong Value During Carry Fix */
 #define ANOMALY_05000199 (__SILICON_REVISION__ < 4)
 /* SPORT TFS and DT Are Incorrectly Driven During Inactive Channels in Certain Conditions */
-#define ANOMALY_05000200 (__SILICON_REVISION__ < 5)
+#define ANOMALY_05000200 (__SILICON_REVISION__ == 3 || __SILICON_REVISION__ == 4)
 /* Receive Frame Sync Not Ignored During Active Frames in SPORT Multi-Channel Mode */
-#define ANOMALY_05000201 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000201 (__SILICON_REVISION__ == 3)
 /* Possible Infinite Stall with Specific Dual-DAG Situation */
 #define ANOMALY_05000202 (__SILICON_REVISION__ < 5)
 /* Specific Sequence That Can Cause DMA Error or DMA Stopping */
@@ -104,7 +104,7 @@
 #define ANOMALY_05000242 (__SILICON_REVISION__ < 5)
 /* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */
 #define ANOMALY_05000244 (__SILICON_REVISION__ < 5)
-/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */
+/* False Hardware Error from an Access in the Shadow of a Conditional Branch */
 #define ANOMALY_05000245 (1)
 /* Data CPLBs Should Prevent Spurious Hardware Errors */
 #define ANOMALY_05000246 (__SILICON_REVISION__ < 5)
@@ -137,7 +137,7 @@
 /* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Decrease */
 #define ANOMALY_05000270 (__SILICON_REVISION__ < 5)
 /* Spontaneous Reset of Internal Voltage Regulator */
-#define ANOMALY_05000271 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000271 (__SILICON_REVISION__ == 3)
 /* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */
 #define ANOMALY_05000272 (1)
 /* Writes to Synchronous SDRAM Memory May Be Lost */
@@ -165,14 +165,14 @@
 /* New Feature: Additional PPI Frame Sync Sampling Options (Not Available On Older Silicon) */
 #define ANOMALY_05000306 (__SILICON_REVISION__ < 5)
 /* SCKELOW Bit Does Not Maintain State Through Hibernate */
-#define ANOMALY_05000307 (1)
+#define ANOMALY_05000307 (1)	/* note: brokenness is noted in documentation, not anomaly sheet */
 /* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
 #define ANOMALY_05000310 (1)
 /* Erroneous Flag (GPIO) Pin Operations under Specific Sequences */
 #define ANOMALY_05000311 (__SILICON_REVISION__ < 6)
 /* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
 #define ANOMALY_05000312 (__SILICON_REVISION__ < 6)
-/* PPI Is Level-Sensitive on First Transfer */
+/* PPI Is Level-Sensitive on First Transfer In Single Frame Sync Modes */
 #define ANOMALY_05000313 (__SILICON_REVISION__ < 6)
 /* Killed System MMR Write Completes Erroneously On Next System MMR Access */
 #define ANOMALY_05000315 (__SILICON_REVISION__ < 6)
@@ -200,17 +200,63 @@
 #define ANOMALY_05000426 (1)
 /* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */
 #define ANOMALY_05000443 (1)
+/* False Hardware Error when RETI points to invalid memory */
+#define ANOMALY_05000461 (1)
 
 /* These anomalies have been "phased" out of analog.com anomaly sheets and are
  * here to show running on older silicon just isn't feasible.
  */
 
+/* Internal voltage regulator can't be modified via register writes */
+#define ANOMALY_05000066 (__SILICON_REVISION__ < 2)
 /* Watchpoints (Hardware Breakpoints) are not supported */
 #define ANOMALY_05000067 (__SILICON_REVISION__ < 3)
+/* SDRAM PSSE bit cannot be set again after SDRAM Powerup */
+#define ANOMALY_05000070 (__SILICON_REVISION__ < 2)
+/* Writing FIO_DIR can corrupt a programmable flag's data */
+#define ANOMALY_05000079 (__SILICON_REVISION__ < 2)
+/* Timer Auto-Baud Mode requires the UART clock to be enabled */
+#define ANOMALY_05000086 (__SILICON_REVISION__ < 2)
+/* Internal Clocking Modes on SPORT0 not supported */
+#define ANOMALY_05000088 (__SILICON_REVISION__ < 2)
+/* Internal voltage regulator does not wake up from an RTC wakeup */
+#define ANOMALY_05000092 (__SILICON_REVISION__ < 2)
+/* The IFLUSH instruction must be preceded by a CSYNC instruction */
+#define ANOMALY_05000093 (__SILICON_REVISION__ < 2)
+/* Vectoring to an instruction that is presently being filled into the instruction cache may cause erroneous behavior */
+#define ANOMALY_05000095 (__SILICON_REVISION__ < 2)
+/* PREFETCH, FLUSH, and FLUSHINV must be followed by a CSYNC */
+#define ANOMALY_05000096 (__SILICON_REVISION__ < 2)
+/* Performance Monitor 0 and 1 are swapped when monitoring memory events */
+#define ANOMALY_05000097 (__SILICON_REVISION__ < 2)
+/* 32-bit SPORT DMA will be word reversed */
+#define ANOMALY_05000098 (__SILICON_REVISION__ < 2)
+/* Incorrect status in the UART_IIR register */
+#define ANOMALY_05000100 (__SILICON_REVISION__ < 2)
+/* Reading X_MODIFY or Y_MODIFY while DMA channel is active */
+#define ANOMALY_05000101 (__SILICON_REVISION__ < 2)
+/* Descriptor-based MemDMA may lock up with 32-bit transfers or if transfers span 64KB buffers */
+#define ANOMALY_05000102 (__SILICON_REVISION__ < 2)
+/* Incorrect value written to the cycle counters */
+#define ANOMALY_05000103 (__SILICON_REVISION__ < 2)
+/* Stores to L1 Data memory incorrect when a specific sequence is followed */
+#define ANOMALY_05000104 (__SILICON_REVISION__ < 2)
+/* Programmable Flag (PF3) functionality not supported in all PPI modes */
+#define ANOMALY_05000106 (__SILICON_REVISION__ < 2)
+/* Data store can be lost when targeting a cache line fill */
+#define ANOMALY_05000107 (__SILICON_REVISION__ < 2)
 /* Reserved bits in SYSCFG register not set at power on */
 #define ANOMALY_05000109 (__SILICON_REVISION__ < 3)
+/* Infinite Core Stall */
+#define ANOMALY_05000114 (__SILICON_REVISION__ < 2)
+/* PPI_FSx may glitch when generated by the on chip Timers */
+#define ANOMALY_05000115 (__SILICON_REVISION__ < 2)
 /* Trace Buffers may record discontinuities into emulation mode and/or exception, NMI, reset handlers */
 #define ANOMALY_05000116 (__SILICON_REVISION__ < 3)
+/* DTEST registers allow access to Data Cache when DTEST_COMMAND< 14 >= 0 */
+#define ANOMALY_05000117 (__SILICON_REVISION__ < 2)
+/* Booting from an 8-bit or 24-bit Addressable SPI device is not supported */
+#define ANOMALY_05000118 (__SILICON_REVISION__ < 2)
 /* DTEST_COMMAND initiated memory access may be incorrect if data cache or DMA is active */
 #define ANOMALY_05000123 (__SILICON_REVISION__ < 3)
 /* DMA Lock-up at CCLK to SCLK ratios of 4:1, 2:1, or 1:1 */
@@ -222,7 +268,9 @@
 /* DMEM_CONTROL is not set on Reset */
 #define ANOMALY_05000137 (__SILICON_REVISION__ < 3)
 /* SPI boot will not complete if there is a zero fill block in the loader file */
-#define ANOMALY_05000138 (__SILICON_REVISION__ < 3)
+#define ANOMALY_05000138 (__SILICON_REVISION__ == 2)
+/* Timerx_Config must be set for using the PPI in GP output mode with internal Frame Syncs */
+#define ANOMALY_05000139 (__SILICON_REVISION__ < 2)
 /* Allowing the SPORT RX FIFO to fill will cause an overflow */
 #define ANOMALY_05000140 (__SILICON_REVISION__ < 3)
 /* An Infinite Stall occurs with a particular sequence of consecutive dual dag events */
@@ -237,17 +285,17 @@
 #define ANOMALY_05000145 (__SILICON_REVISION__ < 3)
 /* MDMA may lose the first few words of a descriptor chain */
 #define ANOMALY_05000146 (__SILICON_REVISION__ < 3)
-/* The source MDMA descriptor may stop with a DMA Error */
+/* Source MDMA descriptor may stop with a DMA Error near beginning of descriptor fetch */
 #define ANOMALY_05000147 (__SILICON_REVISION__ < 3)
 /* When booting from a 16-bit asynchronous memory device, the upper 8-bits of each word must be 0x00 */
 #define ANOMALY_05000148 (__SILICON_REVISION__ < 3)
 /* Frame Delay in SPORT Multichannel Mode */
 #define ANOMALY_05000153 (__SILICON_REVISION__ < 3)
-/* SPORT TFS signal is active in Multi-channel mode outside of valid channels */
+/* SPORT TFS signal stays active in multichannel mode outside of valid channels */
 #define ANOMALY_05000154 (__SILICON_REVISION__ < 3)
 /* Timer1 can not be used for PWMOUT mode when a certain PPI mode is in use */
 #define ANOMALY_05000155 (__SILICON_REVISION__ < 3)
-/* A killed 32-bit System MMR write will lead to the next system MMR access thinking it should be 32-bit. */
+/* Killed 32-bit MMR write leads to next system MMR access thinking it should be 32-bit */
 #define ANOMALY_05000157 (__SILICON_REVISION__ < 3)
 /* SPORT transmit data is not gated by external frame sync in certain conditions */
 #define ANOMALY_05000163 (__SILICON_REVISION__ < 3)
@@ -275,15 +323,27 @@
 #define ANOMALY_05000206 (__SILICON_REVISION__ < 3)
 
 /* Anomalies that don't exist on this proc */
+#define ANOMALY_05000120 (0)
+#define ANOMALY_05000149 (0)
+#define ANOMALY_05000171 (0)
+#define ANOMALY_05000220 (0)
+#define ANOMALY_05000248 (0)
 #define ANOMALY_05000266 (0)
+#define ANOMALY_05000274 (0)
+#define ANOMALY_05000287 (0)
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000353 (1)
+#define ANOMALY_05000362 (1)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (1)
+#define ANOMALY_05000389 (0)
 #define ANOMALY_05000412 (0)
+#define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
+#define ANOMALY_05000456 (0)
+#define ANOMALY_05000450 (0)
 
 #endif
diff --git a/arch/blackfin/mach-bf537/Kconfig b/arch/blackfin/mach-bf537/Kconfig
index bbc08fd..d81224f 100644
--- a/arch/blackfin/mach-bf537/Kconfig
+++ b/arch/blackfin/mach-bf537/Kconfig
@@ -66,6 +66,7 @@
 	default 11
 config IRQ_TIMER0
 	int "IRQ_TIMER0"
+	default 7 if TICKSOURCE_GPTMR0
 	default 8
 config IRQ_TIMER1
 	int "IRQ_TIMER1"
diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537.c b/arch/blackfin/mach-bf537/boards/cm_bf537.c
index 41c75b9..4fee196 100644
--- a/arch/blackfin/mach-bf537/boards/cm_bf537.c
+++ b/arch/blackfin/mach-bf537/boards/cm_bf537.c
@@ -86,7 +86,7 @@
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
 	.enable_dma = 1,         /* use dma transfer with this chip*/
@@ -129,7 +129,7 @@
 	},
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 	{
 		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
 		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c
index 4e1de1e..26707ce 100644
--- a/arch/blackfin/mach-bf537/boards/pnav10.c
+++ b/arch/blackfin/mach-bf537/boards/pnav10.c
@@ -265,8 +265,8 @@
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+	|| defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
 	.enable_dma = 1,         /* use dma transfer with this chip*/
@@ -333,8 +333,8 @@
 	},
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+	|| defined(CONFIG_BFIN_SPI_ADC_MODULE)
 	{
 		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
 		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 0572926..dfb5036 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -508,8 +508,8 @@
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+	|| defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
 	.enable_dma = 1,         /* use dma transfer with this chip*/
@@ -607,6 +607,43 @@
 };
 #endif
 
+#if defined(CONFIG_INPUT_ADXL34X) || defined(CONFIG_INPUT_ADXL34X_MODULE)
+#include <linux/input.h>
+#include <linux/spi/adxl34x.h>
+static const struct adxl34x_platform_data adxl34x_info = {
+	.x_axis_offset = 0,
+	.y_axis_offset = 0,
+	.z_axis_offset = 0,
+	.tap_threshold = 0x31,
+	.tap_duration = 0x10,
+	.tap_latency = 0x60,
+	.tap_window = 0xF0,
+	.tap_axis_control = ADXL_TAP_X_EN | ADXL_TAP_Y_EN | ADXL_TAP_Z_EN,
+	.act_axis_control = 0xFF,
+	.activity_threshold = 5,
+	.inactivity_threshold = 3,
+	.inactivity_time = 4,
+	.free_fall_threshold = 0x7,
+	.free_fall_time = 0x20,
+	.data_rate = 0x8,
+	.data_range = ADXL_FULL_RES,
+
+	.ev_type = EV_ABS,
+	.ev_code_x = ABS_X,		/* EV_REL */
+	.ev_code_y = ABS_Y,		/* EV_REL */
+	.ev_code_z = ABS_Z,		/* EV_REL */
+
+	.ev_code_tap_x = BTN_TOUCH,		/* EV_KEY */
+	.ev_code_tap_y = BTN_TOUCH,		/* EV_KEY */
+	.ev_code_tap_z = BTN_TOUCH,		/* EV_KEY */
+
+/*	.ev_code_ff = KEY_F,*/		/* EV_KEY */
+/*	.ev_code_act_inactivity = KEY_A,*/	/* EV_KEY */
+	.power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
+	.fifo_mode = ADXL_FIFO_STREAM,
+};
+#endif
+
 #if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
 static struct bfin5xx_spi_chip spi_ad7879_chip_info = {
 	.enable_dma = 0,
@@ -695,8 +732,8 @@
 		.mode = SPI_MODE_3,
 	},
 #endif
-#if defined(CONFIG_SPI_ADC_BF533) \
-	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+	|| defined(CONFIG_BFIN_SPI_ADC_MODULE)
 	{
 		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
 		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
@@ -1280,7 +1317,7 @@
 		.irq = IRQ_PF5,
 	},
 #endif
-#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
 	{
 		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
 	},
@@ -1312,6 +1349,13 @@
 		.platform_data = (void *)&adp5520_pdev_data,
 	},
 #endif
+#if defined(CONFIG_INPUT_ADXL34X_I2C) || defined(CONFIG_INPUT_ADXL34X_I2C_MODULE)
+	{
+		I2C_BOARD_INFO("adxl34x", 0x53),
+		.irq = IRQ_PG3,
+		.platform_data = (void *)&adxl34x_info,
+	},
+#endif
 };
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
@@ -1358,16 +1402,18 @@
 static struct pata_platform_info bfin_pata_platform_data = {
 	.ioport_shift = 0,
 };
-
+/* CompactFlash Storage Card Memory Mapped Adressing
+ * /REG = A11 = 1
+ */
 static struct resource bfin_pata_resources[] = {
 	{
-		.start = 0x20211820,
-		.end = 0x2021183F,
+		.start = 0x20211800,
+		.end = 0x20211807,
 		.flags = IORESOURCE_MEM,
 	},
 	{
-		.start = 0x2021181C,
-		.end = 0x2021181F,
+		.start = 0x2021180E,	/* Device Ctl */
+		.end = 0x2021180E,
 		.flags = IORESOURCE_MEM,
 	},
 };
@@ -1527,7 +1573,8 @@
 	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
 	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
 
-#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
+#if (defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)) \
+	 && defined(PATA_INT)
 	irq_desc[PATA_INT].status |= IRQ_NOAUTOEN;
 #endif
 
diff --git a/arch/blackfin/mach-bf537/boards/tcm_bf537.c b/arch/blackfin/mach-bf537/boards/tcm_bf537.c
index 53ad10f..2805745 100644
--- a/arch/blackfin/mach-bf537/boards/tcm_bf537.c
+++ b/arch/blackfin/mach-bf537/boards/tcm_bf537.c
@@ -86,7 +86,7 @@
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
 	.enable_dma = 1,         /* use dma transfer with this chip*/
@@ -129,7 +129,7 @@
 	},
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 	{
 		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
 		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
diff --git a/arch/blackfin/mach-bf537/include/mach/anomaly.h b/arch/blackfin/mach-bf537/include/mach/anomaly.h
index 1bfd80c..fc96634 100644
--- a/arch/blackfin/mach-bf537/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf537/include/mach/anomaly.h
@@ -6,7 +6,7 @@
  * Licensed under the GPL-2 or later.
  */
 
-/* This file shoule be up to date with:
+/* This file should be up to date with:
  *  - Revision D, 09/18/2008; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List
  */
 
@@ -36,77 +36,75 @@
 
 /* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */
 #define ANOMALY_05000074 (1)
-/* DMA_RUN bit is not valid after a Peripheral Receive Channel DMA stops */
+/* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
 #define ANOMALY_05000119 (1)
-/* Rx.H cannot be used to access 16-bit System MMR registers */
+/* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */
 #define ANOMALY_05000122 (1)
 /* Killed 32-bit MMR write leads to next system MMR access thinking it should be 32-bit */
 #define ANOMALY_05000157 (__SILICON_REVISION__ < 2)
-/* Turning SPORTs on while External Frame Sync Is Active May Corrupt Data */
-#define ANOMALY_05000167 (1)
-/* PPI_DELAY not functional in PPI modes with 0 frame syncs */
+/* PPI_DELAY Not Functional in PPI Modes with 0 Frame Syncs */
 #define ANOMALY_05000180 (1)
 /* Instruction Cache Is Not Functional */
 #define ANOMALY_05000237 (__SILICON_REVISION__ < 2)
-/* If i-cache is on, CSYNC/SSYNC/IDLE around Change of Control causes failures */
+/* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */
 #define ANOMALY_05000244 (__SILICON_REVISION__ < 3)
-/* Spurious Hardware Error from an access in the shadow of a conditional branch */
+/* False Hardware Error from an Access in the Shadow of a Conditional Branch */
 #define ANOMALY_05000245 (1)
 /* CLKIN Buffer Output Enable Reset Behavior Is Changed */
 #define ANOMALY_05000247 (1)
-/* Incorrect Bit-Shift of Data Word in Multichannel (TDM) mode in certain conditions */
+/* Incorrect Bit Shift of Data Word in Multichannel (TDM) Mode in Certain Conditions */
 #define ANOMALY_05000250 (__SILICON_REVISION__ < 3)
 /* EMAC Tx DMA error after an early frame abort */
 #define ANOMALY_05000252 (__SILICON_REVISION__ < 3)
-/* Maximum external clock speed for Timers */
+/* Maximum External Clock Speed for Timers */
 #define ANOMALY_05000253 (__SILICON_REVISION__ < 3)
-/* Incorrect Timer Pulse Width in Single-Shot PWM_OUT mode with external clock */
+/* Incorrect Timer Pulse Width in Single-Shot PWM_OUT Mode with External Clock */
 #define ANOMALY_05000254 (__SILICON_REVISION__ > 2)
-/* Entering Hibernate Mode with RTC Seconds event interrupt not functional */
+/* Entering Hibernate State with RTC Seconds Interrupt Not Functional */
 #define ANOMALY_05000255 (__SILICON_REVISION__ < 3)
 /* EMAC MDIO input latched on wrong MDC edge */
 #define ANOMALY_05000256 (__SILICON_REVISION__ < 3)
-/* Interrupt/Exception during short hardware loop may cause bad instruction fetches */
+/* Interrupt/Exception During Short Hardware Loop May Cause Bad Instruction Fetches */
 #define ANOMALY_05000257 (__SILICON_REVISION__ < 3)
-/* Instruction Cache is corrupted when bits 9 and 12 of the ICPLB Data registers differ */
+/* Instruction Cache Is Corrupted When Bits 9 and 12 of the ICPLB Data Registers Differ */
 #define ANOMALY_05000258 (((ANOMALY_BF536 || ANOMALY_BF537) && __SILICON_REVISION__ == 1) || __SILICON_REVISION__ == 2)
-/* ICPLB_STATUS MMR register may be corrupted */
+/* ICPLB_STATUS MMR Register May Be Corrupted */
 #define ANOMALY_05000260 (__SILICON_REVISION__ == 2)
-/* DCPLB_FAULT_ADDR MMR register may be corrupted */
+/* DCPLB_FAULT_ADDR MMR Register May Be Corrupted */
 #define ANOMALY_05000261 (__SILICON_REVISION__ < 3)
-/* Stores to data cache may be lost */
+/* Stores To Data Cache May Be Lost */
 #define ANOMALY_05000262 (__SILICON_REVISION__ < 3)
-/* Hardware loop corrupted when taking an ICPLB exception */
+/* Hardware Loop Corrupted When Taking an ICPLB Exception */
 #define ANOMALY_05000263 (__SILICON_REVISION__ == 2)
-/* CSYNC/SSYNC/IDLE causes infinite stall in second to last instruction in hardware loop */
+/* CSYNC/SSYNC/IDLE Causes Infinite Stall in Penultimate Instruction in Hardware Loop */
 #define ANOMALY_05000264 (__SILICON_REVISION__ < 3)
-/* Sensitivity to noise with slow input edge rates on external SPORT TX and RX clocks */
+/* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */
 #define ANOMALY_05000265 (1)
 /* Memory DMA error when peripheral DMA is running with non-zero DEB_TRAFFIC_PERIOD */
 #define ANOMALY_05000268 (__SILICON_REVISION__ < 3)
-/* High I/O activity causes output voltage of internal voltage regulator (VDDint) to decrease */
+/* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Decrease */
 #define ANOMALY_05000270 (__SILICON_REVISION__ < 3)
-/* Certain data cache write through modes fail for VDDint <=0.9V */
+/* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */
 #define ANOMALY_05000272 (1)
-/* Writes to Synchronous SDRAM memory may be lost */
+/* Writes to Synchronous SDRAM Memory May Be Lost */
 #define ANOMALY_05000273 (__SILICON_REVISION__ < 3)
-/* Writes to an I/O data register one SCLK cycle after an edge is detected may clear interrupt */
+/* Writes to an I/O Data Register One SCLK Cycle after an Edge Is Detected May Clear Interrupt */
 #define ANOMALY_05000277 (__SILICON_REVISION__ < 3)
-/* Disabling Peripherals with DMA running may cause DMA system instability */
+/* Disabling Peripherals with DMA Running May Cause DMA System Instability */
 #define ANOMALY_05000278 (((ANOMALY_BF536 || ANOMALY_BF537) && __SILICON_REVISION__ < 3) || (ANOMALY_BF534 && __SILICON_REVISION__ < 2))
 /* SPI Master boot mode does not work well with Atmel Data flash devices */
 #define ANOMALY_05000280 (1)
-/* False Hardware Error Exception when ISR context is not restored */
+/* False Hardware Error Exception When ISR Context Is Not Restored */
 #define ANOMALY_05000281 (__SILICON_REVISION__ < 3)
-/* Memory DMA corruption with 32-bit data and traffic control */
+/* Memory DMA Corruption with 32-Bit Data and Traffic Control */
 #define ANOMALY_05000282 (__SILICON_REVISION__ < 3)
 /* System MMR Write Is Stalled Indefinitely When Killed in a Particular Stage */
 #define ANOMALY_05000283 (__SILICON_REVISION__ < 3)
 /* New Feature: EMAC TX DMA Word Alignment (Not Available On Older Silicon) */
 #define ANOMALY_05000285 (__SILICON_REVISION__ < 3)
-/* SPORTs may receive bad data if FIFOs fill up */
+/* SPORTs May Receive Bad Data If FIFOs Fill Up */
 #define ANOMALY_05000288 (__SILICON_REVISION__ < 3)
-/* Memory to memory DMA source/destination descriptors must be in same memory space */
+/* Memory-To-Memory DMA Source/Destination Descriptors Must Be in Same Memory Space */
 #define ANOMALY_05000301 (1)
 /* SSYNCs After Writes To CAN/DMA MMR Registers Are Not Always Handled Correctly */
 #define ANOMALY_05000304 (__SILICON_REVISION__ < 3)
@@ -116,11 +114,11 @@
 #define ANOMALY_05000307 (__SILICON_REVISION__ < 3)
 /* Writing UART_THR while UART clock is disabled sends erroneous start bit */
 #define ANOMALY_05000309 (__SILICON_REVISION__ < 3)
-/* False hardware errors caused by fetches at the boundary of reserved memory */
+/* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
 #define ANOMALY_05000310 (1)
-/* Errors when SSYNC, CSYNC, or loads to LT, LB and LC registers are interrupted */
+/* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
 #define ANOMALY_05000312 (1)
-/* PPI is level sensitive on first transfer */
+/* PPI Is Level-Sensitive on First Transfer In Single Frame Sync Modes */
 #define ANOMALY_05000313 (1)
 /* Killed System MMR Write Completes Erroneously On Next System MMR Access */
 #define ANOMALY_05000315 (__SILICON_REVISION__ < 3)
@@ -156,24 +154,46 @@
 #define ANOMALY_05000426 (1)
 /* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */
 #define ANOMALY_05000443 (1)
+/* False Hardware Error when RETI points to invalid memory */
+#define ANOMALY_05000461 (1)
 
 /* Anomalies that don't exist on this proc */
+#define ANOMALY_05000099 (0)
+#define ANOMALY_05000120 (0)
 #define ANOMALY_05000125 (0)
+#define ANOMALY_05000149 (0)
 #define ANOMALY_05000158 (0)
+#define ANOMALY_05000171 (0)
+#define ANOMALY_05000179 (0)
 #define ANOMALY_05000183 (0)
 #define ANOMALY_05000198 (0)
+#define ANOMALY_05000215 (0)
+#define ANOMALY_05000220 (0)
+#define ANOMALY_05000227 (0)
 #define ANOMALY_05000230 (0)
+#define ANOMALY_05000231 (0)
+#define ANOMALY_05000233 (0)
+#define ANOMALY_05000242 (0)
+#define ANOMALY_05000248 (0)
 #define ANOMALY_05000266 (0)
+#define ANOMALY_05000274 (0)
+#define ANOMALY_05000287 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000353 (1)
+#define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (1)
+#define ANOMALY_05000389 (0)
+#define ANOMALY_05000400 (0)
 #define ANOMALY_05000412 (0)
+#define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
+#define ANOMALY_05000456 (0)
+#define ANOMALY_05000450 (0)
 
 #endif
diff --git a/arch/blackfin/mach-bf538/Kconfig b/arch/blackfin/mach-bf538/Kconfig
index f068c35..2d280f5 100644
--- a/arch/blackfin/mach-bf538/Kconfig
+++ b/arch/blackfin/mach-bf538/Kconfig
@@ -57,6 +57,7 @@
 	default 10
 config IRQ_TIMER0
 	int "IRQ_TIMER0"
+	default 7 if TICKSOURCE_GPTMR0
 	default 8
 config IRQ_TIMER1
 	int "IRQ_TIMER1"
diff --git a/arch/blackfin/mach-bf538/include/mach/anomaly.h b/arch/blackfin/mach-bf538/include/mach/anomaly.h
index 3a56998..175ca9e 100644
--- a/arch/blackfin/mach-bf538/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf538/include/mach/anomaly.h
@@ -6,7 +6,7 @@
  * Licensed under the GPL-2 or later.
  */
 
-/* This file shoule be up to date with:
+/* This file should be up to date with:
  *  - Revision G, 09/18/2008; ADSP-BF538/BF538F Blackfin Processor Anomaly List
  *  - Revision L, 09/18/2008; ADSP-BF539/BF539F Blackfin Processor Anomaly List
  */
@@ -14,17 +14,29 @@
 #ifndef _MACH_ANOMALY_H_
 #define _MACH_ANOMALY_H_
 
+/* We do not support old silicon - sorry */
 #if __SILICON_REVISION__ < 4
-# error will not work on BF538 silicon version 0.0, 0.1, 0.2, or 0.3
+# error will not work on BF538/BF539 silicon version 0.0, 0.1, 0.2, or 0.3
 #endif
 
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
+#if defined(__ADSPBF538__)
+# define ANOMALY_BF538 1
+#else
+# define ANOMALY_BF538 0
+#endif
+#if defined(__ADSPBF539__)
+# define ANOMALY_BF539 1
+#else
+# define ANOMALY_BF539 0
+#endif
+
+/* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */
 #define ANOMALY_05000074 (1)
 /* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
 #define ANOMALY_05000119 (1)
 /* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */
 #define ANOMALY_05000122 (1)
-/* PPI Data Lengths between 8 and 16 Do Not Zero Out Upper Bits */
+/* PPI Data Lengths Between 8 and 16 Do Not Zero Out Upper Bits */
 #define ANOMALY_05000166 (1)
 /* PPI_COUNT Cannot Be Programmed to 0 in General Purpose TX or RX Modes */
 #define ANOMALY_05000179 (1)
@@ -40,13 +52,13 @@
 #define ANOMALY_05000229 (1)
 /* PPI_FS3 Is Not Driven in 2 or 3 Internal Frame Sync Transmit Modes */
 #define ANOMALY_05000233 (1)
-/* If i-cache is on, CSYNC/SSYNC/IDLE around Change of Control causes failures */
+/* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */
 #define ANOMALY_05000244 (__SILICON_REVISION__ < 3)
-/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */
+/* False Hardware Error from an Access in the Shadow of a Conditional Branch */
 #define ANOMALY_05000245 (1)
 /* Maximum External Clock Speed for Timers */
 #define ANOMALY_05000253 (1)
-/* DCPLB_FAULT_ADDR MMR register may be corrupted */
+/* DCPLB_FAULT_ADDR MMR Register May Be Corrupted */
 #define ANOMALY_05000261 (__SILICON_REVISION__ < 3)
 /* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Decrease */
 #define ANOMALY_05000270 (__SILICON_REVISION__ < 4)
@@ -58,11 +70,11 @@
 #define ANOMALY_05000277 (__SILICON_REVISION__ < 4)
 /* Disabling Peripherals with DMA Running May Cause DMA System Instability */
 #define ANOMALY_05000278 (__SILICON_REVISION__ < 4)
-/* False Hardware Error Exception when ISR Context Is Not Restored */
+/* False Hardware Error Exception When ISR Context Is Not Restored */
 #define ANOMALY_05000281 (__SILICON_REVISION__ < 4)
 /* Memory DMA Corruption with 32-Bit Data and Traffic Control */
 #define ANOMALY_05000282 (__SILICON_REVISION__ < 4)
-/* System MMR Write Is Stalled Indefinitely when Killed in a Particular Stage */
+/* System MMR Write Is Stalled Indefinitely When Killed in a Particular Stage */
 #define ANOMALY_05000283 (__SILICON_REVISION__ < 4)
 /* SPORTs May Receive Bad Data If FIFOs Fill Up */
 #define ANOMALY_05000288 (__SILICON_REVISION__ < 4)
@@ -80,14 +92,14 @@
 #define ANOMALY_05000307 (__SILICON_REVISION__ < 4)
 /* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
 #define ANOMALY_05000310 (1)
-/* Errors when SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
+/* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
 #define ANOMALY_05000312 (__SILICON_REVISION__ < 5)
-/* PPI Is Level-Sensitive on First Transfer */
+/* PPI Is Level-Sensitive on First Transfer In Single Frame Sync Modes */
 #define ANOMALY_05000313 (__SILICON_REVISION__ < 4)
-/* Killed System MMR Write Completes Erroneously on Next System MMR Access */
+/* Killed System MMR Write Completes Erroneously On Next System MMR Access */
 #define ANOMALY_05000315 (__SILICON_REVISION__ < 4)
 /* PFx Glitch on Write to FIO_FLAG_D or FIO_FLAG_T */
-#define ANOMALY_05000318 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000318 (ANOMALY_BF539 && __SILICON_REVISION__ < 4)
 /* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */
 #define ANOMALY_05000355 (__SILICON_REVISION__ < 5)
 /* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
@@ -114,23 +126,45 @@
 #define ANOMALY_05000436 (__SILICON_REVISION__ > 3)
 /* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */
 #define ANOMALY_05000443 (1)
+/* False Hardware Error when RETI points to invalid memory */
+#define ANOMALY_05000461 (1)
 
 /* Anomalies that don't exist on this proc */
+#define ANOMALY_05000099 (0)
+#define ANOMALY_05000120 (0)
+#define ANOMALY_05000149 (0)
 #define ANOMALY_05000158 (0)
+#define ANOMALY_05000171 (0)
 #define ANOMALY_05000198 (0)
+#define ANOMALY_05000215 (0)
+#define ANOMALY_05000220 (0)
+#define ANOMALY_05000227 (0)
 #define ANOMALY_05000230 (0)
+#define ANOMALY_05000231 (0)
+#define ANOMALY_05000242 (0)
+#define ANOMALY_05000248 (0)
+#define ANOMALY_05000250 (0)
+#define ANOMALY_05000254 (0)
 #define ANOMALY_05000263 (0)
+#define ANOMALY_05000274 (0)
+#define ANOMALY_05000287 (0)
 #define ANOMALY_05000305 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000353 (1)
+#define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (1)
+#define ANOMALY_05000389 (0)
+#define ANOMALY_05000400 (0)
 #define ANOMALY_05000412 (0)
+#define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
+#define ANOMALY_05000456 (0)
+#define ANOMALY_05000450 (0)
 
 #endif
diff --git a/arch/blackfin/mach-bf538/include/mach/blackfin.h b/arch/blackfin/mach-bf538/include/mach/blackfin.h
index ea25371a9..6f62835 100644
--- a/arch/blackfin/mach-bf538/include/mach/blackfin.h
+++ b/arch/blackfin/mach-bf538/include/mach/blackfin.h
@@ -68,25 +68,6 @@
 #define OFFSET_SCR              0x1C	/* SCR Scratch Register                 */
 #define OFFSET_GCTL             0x24	/* Global Control Register              */
 
-
-#define bfin_write_MDMA_D0_IRQ_STATUS	bfin_write_MDMA0_D0_IRQ_STATUS
-#define bfin_write_MDMA_D0_START_ADDR   bfin_write_MDMA0_D0_START_ADDR
-#define bfin_write_MDMA_S0_START_ADDR   bfin_write_MDMA0_S0_START_ADDR
-#define bfin_write_MDMA_D0_X_COUNT      bfin_write_MDMA0_D0_X_COUNT
-#define bfin_write_MDMA_S0_X_COUNT      bfin_write_MDMA0_S0_X_COUNT
-#define bfin_write_MDMA_D0_Y_COUNT      bfin_write_MDMA0_D0_Y_COUNT
-#define bfin_write_MDMA_S0_Y_COUNT      bfin_write_MDMA0_S0_Y_COUNT
-#define bfin_write_MDMA_D0_X_MODIFY     bfin_write_MDMA0_D0_X_MODIFY
-#define bfin_write_MDMA_S0_X_MODIFY     bfin_write_MDMA0_S0_X_MODIFY
-#define bfin_write_MDMA_D0_Y_MODIFY     bfin_write_MDMA0_D0_Y_MODIFY
-#define bfin_write_MDMA_S0_Y_MODIFY     bfin_write_MDMA0_S0_Y_MODIFY
-#define bfin_write_MDMA_S0_CONFIG       bfin_write_MDMA0_S0_CONFIG
-#define bfin_write_MDMA_D0_CONFIG       bfin_write_MDMA0_D0_CONFIG
-#define bfin_read_MDMA_S0_CONFIG        bfin_read_MDMA0_S0_CONFIG
-#define bfin_read_MDMA_D0_IRQ_STATUS    bfin_read_MDMA0_D0_IRQ_STATUS
-#define bfin_write_MDMA_S0_IRQ_STATUS   bfin_write_MDMA0_S0_IRQ_STATUS
-
-
 /* DPMC*/
 #define bfin_read_STOPCK_OFF() bfin_read_STOPCK()
 #define bfin_write_STOPCK_OFF(val) bfin_write_STOPCK(val)
diff --git a/arch/blackfin/mach-bf538/include/mach/cdefBF538.h b/arch/blackfin/mach-bf538/include/mach/cdefBF538.h
index 241725b..99ca3f4 100644
--- a/arch/blackfin/mach-bf538/include/mach/cdefBF538.h
+++ b/arch/blackfin/mach-bf538/include/mach/cdefBF538.h
@@ -67,14 +67,14 @@
 #define bfin_write_SIC_ISR0(val)       bfin_write32(SIC_ISR0, val)
 #define bfin_read_SIC_ISR1()           bfin_read32(SIC_ISR1)
 #define bfin_write_SIC_ISR1(val)       bfin_write32(SIC_ISR1, val)
-#define bfin_read_SIC_ISR(x)	       bfin_read32(SIC_ISR0 + x * (SIC_ISR1 - SIC_ISR0))
+#define bfin_read_SIC_ISR(x)           bfin_read32(SIC_ISR0 + x * (SIC_ISR1 - SIC_ISR0))
 #define bfin_write_SIC_ISR(x, val)     bfin_write32(SIC_ISR0 + x * (SIC_ISR1 - SIC_ISR0), val)
 #define bfin_read_SIC_IWR0()           bfin_read32(SIC_IWR0)
 #define bfin_write_SIC_IWR0(val)       bfin_write32(SIC_IWR0, val)
 #define bfin_read_SIC_IWR1()           bfin_read32(SIC_IWR1)
 #define bfin_write_SIC_IWR1(val)       bfin_write32(SIC_IWR1, val)
-#define bfin_read_SIC_IWR(x)	       bfin_read32(SIC_IWR0 + x * (SIC_IWR1 - SIC_IWR0))
-#define bfin_write_SIC_IWR(x, val)     bfin_write32((SIC_IWR0 + x * (SIC_IWR1 - SIC_IWR0), val)
+#define bfin_read_SIC_IWR(x)           bfin_read32(SIC_IWR0 + x * (SIC_IWR1 - SIC_IWR0))
+#define bfin_write_SIC_IWR(x, val)     bfin_write32(SIC_IWR0 + x * (SIC_IWR1 - SIC_IWR0), val)
 #define bfin_read_SIC_IAR0()           bfin_read32(SIC_IAR0)
 #define bfin_write_SIC_IAR0(val)       bfin_write32(SIC_IAR0, val)
 #define bfin_read_SIC_IAR1()           bfin_read32(SIC_IAR1)
@@ -1247,6 +1247,65 @@
 #define bfin_write_MDMA1_S1_CURR_X_COUNT(val) bfin_write16(MDMA1_S1_CURR_X_COUNT, val)
 #define bfin_read_MDMA1_S1_CURR_Y_COUNT() bfin_read16(MDMA1_S1_CURR_Y_COUNT)
 #define bfin_write_MDMA1_S1_CURR_Y_COUNT(val) bfin_write16(MDMA1_S1_CURR_Y_COUNT, val)
+
+#define bfin_read_MDMA_S0_CONFIG()  bfin_read_MDMA0_S0_CONFIG()
+#define bfin_write_MDMA_S0_CONFIG(val) bfin_write_MDMA0_S0_CONFIG(val)
+#define bfin_read_MDMA_S0_IRQ_STATUS()  bfin_read_MDMA0_S0_IRQ_STATUS()
+#define bfin_write_MDMA_S0_IRQ_STATUS(val) bfin_write_MDMA0_S0_IRQ_STATUS(val)
+#define bfin_read_MDMA_S0_X_MODIFY()  bfin_read_MDMA0_S0_X_MODIFY()
+#define bfin_write_MDMA_S0_X_MODIFY(val) bfin_write_MDMA0_S0_X_MODIFY(val)
+#define bfin_read_MDMA_S0_Y_MODIFY()  bfin_read_MDMA0_S0_Y_MODIFY()
+#define bfin_write_MDMA_S0_Y_MODIFY(val) bfin_write_MDMA0_S0_Y_MODIFY(val)
+#define bfin_read_MDMA_S0_X_COUNT()  bfin_read_MDMA0_S0_X_COUNT()
+#define bfin_write_MDMA_S0_X_COUNT(val) bfin_write_MDMA0_S0_X_COUNT(val)
+#define bfin_read_MDMA_S0_Y_COUNT()  bfin_read_MDMA0_S0_Y_COUNT()
+#define bfin_write_MDMA_S0_Y_COUNT(val) bfin_write_MDMA0_S0_Y_COUNT(val)
+#define bfin_read_MDMA_S0_START_ADDR()  bfin_read_MDMA0_S0_START_ADDR()
+#define bfin_write_MDMA_S0_START_ADDR(val) bfin_write_MDMA0_S0_START_ADDR(val)
+#define bfin_read_MDMA_D0_CONFIG()  bfin_read_MDMA0_D0_CONFIG()
+#define bfin_write_MDMA_D0_CONFIG(val) bfin_write_MDMA0_D0_CONFIG(val)
+#define bfin_read_MDMA_D0_IRQ_STATUS()  bfin_read_MDMA0_D0_IRQ_STATUS()
+#define bfin_write_MDMA_D0_IRQ_STATUS(val) bfin_write_MDMA0_D0_IRQ_STATUS(val)
+#define bfin_read_MDMA_D0_X_MODIFY()  bfin_read_MDMA0_D0_X_MODIFY()
+#define bfin_write_MDMA_D0_X_MODIFY(val) bfin_write_MDMA0_D0_X_MODIFY(val)
+#define bfin_read_MDMA_D0_Y_MODIFY()  bfin_read_MDMA0_D0_Y_MODIFY()
+#define bfin_write_MDMA_D0_Y_MODIFY(val) bfin_write_MDMA0_D0_Y_MODIFY(val)
+#define bfin_read_MDMA_D0_X_COUNT()  bfin_read_MDMA0_D0_X_COUNT()
+#define bfin_write_MDMA_D0_X_COUNT(val) bfin_write_MDMA0_D0_X_COUNT(val)
+#define bfin_read_MDMA_D0_Y_COUNT()  bfin_read_MDMA0_D0_Y_COUNT()
+#define bfin_write_MDMA_D0_Y_COUNT(val) bfin_write_MDMA0_D0_Y_COUNT(val)
+#define bfin_read_MDMA_D0_START_ADDR()  bfin_read_MDMA0_D0_START_ADDR()
+#define bfin_write_MDMA_D0_START_ADDR(val) bfin_write_MDMA0_D0_START_ADDR(val)
+
+#define bfin_read_MDMA_S1_CONFIG()  bfin_read_MDMA0_S1_CONFIG()
+#define bfin_write_MDMA_S1_CONFIG(val) bfin_write_MDMA0_S1_CONFIG(val)
+#define bfin_read_MDMA_S1_IRQ_STATUS()  bfin_read_MDMA0_S1_IRQ_STATUS()
+#define bfin_write_MDMA_S1_IRQ_STATUS(val) bfin_write_MDMA0_S1_IRQ_STATUS(val)
+#define bfin_read_MDMA_S1_X_MODIFY()  bfin_read_MDMA0_S1_X_MODIFY()
+#define bfin_write_MDMA_S1_X_MODIFY(val) bfin_write_MDMA0_S1_X_MODIFY(val)
+#define bfin_read_MDMA_S1_Y_MODIFY()  bfin_read_MDMA0_S1_Y_MODIFY()
+#define bfin_write_MDMA_S1_Y_MODIFY(val) bfin_write_MDMA0_S1_Y_MODIFY(val)
+#define bfin_read_MDMA_S1_X_COUNT()  bfin_read_MDMA0_S1_X_COUNT()
+#define bfin_write_MDMA_S1_X_COUNT(val) bfin_write_MDMA0_S1_X_COUNT(val)
+#define bfin_read_MDMA_S1_Y_COUNT()  bfin_read_MDMA0_S1_Y_COUNT()
+#define bfin_write_MDMA_S1_Y_COUNT(val) bfin_write_MDMA0_S1_Y_COUNT(val)
+#define bfin_read_MDMA_S1_START_ADDR()  bfin_read_MDMA0_S1_START_ADDR()
+#define bfin_write_MDMA_S1_START_ADDR(val) bfin_write_MDMA0_S1_START_ADDR(val)
+#define bfin_read_MDMA_D1_CONFIG()  bfin_read_MDMA0_D1_CONFIG()
+#define bfin_write_MDMA_D1_CONFIG(val) bfin_write_MDMA0_D1_CONFIG(val)
+#define bfin_read_MDMA_D1_IRQ_STATUS()  bfin_read_MDMA0_D1_IRQ_STATUS()
+#define bfin_write_MDMA_D1_IRQ_STATUS(val) bfin_write_MDMA0_D1_IRQ_STATUS(val)
+#define bfin_read_MDMA_D1_X_MODIFY()  bfin_read_MDMA0_D1_X_MODIFY()
+#define bfin_write_MDMA_D1_X_MODIFY(val) bfin_write_MDMA0_D1_X_MODIFY(val)
+#define bfin_read_MDMA_D1_Y_MODIFY()  bfin_read_MDMA0_D1_Y_MODIFY()
+#define bfin_write_MDMA_D1_Y_MODIFY(val) bfin_write_MDMA0_D1_Y_MODIFY(val)
+#define bfin_read_MDMA_D1_X_COUNT()  bfin_read_MDMA0_D1_X_COUNT()
+#define bfin_write_MDMA_D1_X_COUNT(val) bfin_write_MDMA0_D1_X_COUNT(val)
+#define bfin_read_MDMA_D1_Y_COUNT()  bfin_read_MDMA0_D1_Y_COUNT()
+#define bfin_write_MDMA_D1_Y_COUNT(val) bfin_write_MDMA0_D1_Y_COUNT(val)
+#define bfin_read_MDMA_D1_START_ADDR()  bfin_read_MDMA0_D1_START_ADDR()
+#define bfin_write_MDMA_D1_START_ADDR(val) bfin_write_MDMA0_D1_START_ADDR(val)
+
 #define bfin_read_PPI_CONTROL()        bfin_read16(PPI_CONTROL)
 #define bfin_write_PPI_CONTROL(val)    bfin_write16(PPI_CONTROL, val)
 #define bfin_read_PPI_STATUS()         bfin_read16(PPI_STATUS)
diff --git a/arch/blackfin/mach-bf538/include/mach/defBF539.h b/arch/blackfin/mach-bf538/include/mach/defBF539.h
index 6adbfcc..bdc330c 100644
--- a/arch/blackfin/mach-bf538/include/mach/defBF539.h
+++ b/arch/blackfin/mach-bf538/include/mach/defBF539.h
@@ -412,6 +412,62 @@
 #define	MDMA0_S1_CURR_X_COUNT	0xFFC00EF0	/* MemDMA0 Stream 1 Source Current X Count Register */
 #define	MDMA0_S1_CURR_Y_COUNT	0xFFC00EF8	/* MemDMA0 Stream 1 Source Current Y Count Register */
 
+#define MDMA_D0_NEXT_DESC_PTR MDMA0_D0_NEXT_DESC_PTR
+#define MDMA_D0_START_ADDR MDMA0_D0_START_ADDR
+#define MDMA_D0_CONFIG MDMA0_D0_CONFIG
+#define MDMA_D0_X_COUNT MDMA0_D0_X_COUNT
+#define MDMA_D0_X_MODIFY MDMA0_D0_X_MODIFY
+#define MDMA_D0_Y_COUNT MDMA0_D0_Y_COUNT
+#define MDMA_D0_Y_MODIFY MDMA0_D0_Y_MODIFY
+#define MDMA_D0_CURR_DESC_PTR MDMA0_D0_CURR_DESC_PTR
+#define MDMA_D0_CURR_ADDR MDMA0_D0_CURR_ADDR
+#define MDMA_D0_IRQ_STATUS MDMA0_D0_IRQ_STATUS
+#define MDMA_D0_PERIPHERAL_MAP MDMA0_D0_PERIPHERAL_MAP
+#define MDMA_D0_CURR_X_COUNT MDMA0_D0_CURR_X_COUNT
+#define MDMA_D0_CURR_Y_COUNT MDMA0_D0_CURR_Y_COUNT
+
+#define MDMA_S0_NEXT_DESC_PTR MDMA0_S0_NEXT_DESC_PTR
+#define MDMA_S0_START_ADDR MDMA0_S0_START_ADDR
+#define MDMA_S0_CONFIG MDMA0_S0_CONFIG
+#define MDMA_S0_X_COUNT MDMA0_S0_X_COUNT
+#define MDMA_S0_X_MODIFY MDMA0_S0_X_MODIFY
+#define MDMA_S0_Y_COUNT MDMA0_S0_Y_COUNT
+#define MDMA_S0_Y_MODIFY MDMA0_S0_Y_MODIFY
+#define MDMA_S0_CURR_DESC_PTR MDMA0_S0_CURR_DESC_PTR
+#define MDMA_S0_CURR_ADDR MDMA0_S0_CURR_ADDR
+#define MDMA_S0_IRQ_STATUS MDMA0_S0_IRQ_STATUS
+#define MDMA_S0_PERIPHERAL_MAP MDMA0_S0_PERIPHERAL_MAP
+#define MDMA_S0_CURR_X_COUNT MDMA0_S0_CURR_X_COUNT
+#define MDMA_S0_CURR_Y_COUNT MDMA0_S0_CURR_Y_COUNT
+
+#define MDMA_D1_NEXT_DESC_PTR MDMA0_D1_NEXT_DESC_PTR
+#define MDMA_D1_START_ADDR MDMA0_D1_START_ADDR
+#define MDMA_D1_CONFIG MDMA0_D1_CONFIG
+#define MDMA_D1_X_COUNT MDMA0_D1_X_COUNT
+#define MDMA_D1_X_MODIFY MDMA0_D1_X_MODIFY
+#define MDMA_D1_Y_COUNT MDMA0_D1_Y_COUNT
+#define MDMA_D1_Y_MODIFY MDMA0_D1_Y_MODIFY
+#define MDMA_D1_CURR_DESC_PTR MDMA0_D1_CURR_DESC_PTR
+#define MDMA_D1_CURR_ADDR MDMA0_D1_CURR_ADDR
+#define MDMA_D1_IRQ_STATUS MDMA0_D1_IRQ_STATUS
+#define MDMA_D1_PERIPHERAL_MAP MDMA0_D1_PERIPHERAL_MAP
+#define MDMA_D1_CURR_X_COUNT MDMA0_D1_CURR_X_COUNT
+#define MDMA_D1_CURR_Y_COUNT MDMA0_D1_CURR_Y_COUNT
+
+#define MDMA_S1_NEXT_DESC_PTR MDMA0_S1_NEXT_DESC_PTR
+#define MDMA_S1_START_ADDR MDMA0_S1_START_ADDR
+#define MDMA_S1_CONFIG MDMA0_S1_CONFIG
+#define MDMA_S1_X_COUNT MDMA0_S1_X_COUNT
+#define MDMA_S1_X_MODIFY MDMA0_S1_X_MODIFY
+#define MDMA_S1_Y_COUNT MDMA0_S1_Y_COUNT
+#define MDMA_S1_Y_MODIFY MDMA0_S1_Y_MODIFY
+#define MDMA_S1_CURR_DESC_PTR MDMA0_S1_CURR_DESC_PTR
+#define MDMA_S1_CURR_ADDR MDMA0_S1_CURR_ADDR
+#define MDMA_S1_IRQ_STATUS MDMA0_S1_IRQ_STATUS
+#define MDMA_S1_PERIPHERAL_MAP MDMA0_S1_PERIPHERAL_MAP
+#define MDMA_S1_CURR_X_COUNT MDMA0_S1_CURR_X_COUNT
+#define MDMA_S1_CURR_Y_COUNT MDMA0_S1_CURR_Y_COUNT
+
 
 /* Parallel Peripheral Interface (PPI) (0xFFC01000 - 0xFFC010FF) */
 #define	PPI_CONTROL			0xFFC01000	/* PPI Control Register */
diff --git a/arch/blackfin/mach-bf548/Kconfig b/arch/blackfin/mach-bf548/Kconfig
index dcf6571..a09623d 100644
--- a/arch/blackfin/mach-bf548/Kconfig
+++ b/arch/blackfin/mach-bf548/Kconfig
@@ -11,6 +11,13 @@
 	help
 	  Treat any DEB1, DEB2 and DEB3 request as Urgent
 
+config BF548_ATAPI_ALTERNATIVE_PORT
+	bool "BF548 ATAPI alternative port via GPIO"
+	help
+	  BF548 ATAPI data and address PINs can be routed through
+	  async address or GPIO port F and G. Select y to route it
+	  to GPIO.
+
 comment "Interrupt Priority Assignment"
 menu "Priority"
 
@@ -250,6 +257,7 @@
 	default 11
 config IRQ_TIMER0
 	int "IRQ_TIMER0"
+	default 7 if TICKSOURCE_GPTMR0
 	default 8
 config IRQ_TIMER1
 	int "IRQ_TIMER1"
diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
index 096e661..add5a17 100644
--- a/arch/blackfin/mach-bf548/boards/ezkit.c
+++ b/arch/blackfin/mach-bf548/boards/ezkit.c
@@ -208,6 +208,43 @@
 };
 #endif
 
+#if defined(CONFIG_INPUT_ADXL34X) || defined(CONFIG_INPUT_ADXL34X_MODULE)
+#include <linux/input.h>
+#include <linux/spi/adxl34x.h>
+static const struct adxl34x_platform_data adxl34x_info = {
+	.x_axis_offset = 0,
+	.y_axis_offset = 0,
+	.z_axis_offset = 0,
+	.tap_threshold = 0x31,
+	.tap_duration = 0x10,
+	.tap_latency = 0x60,
+	.tap_window = 0xF0,
+	.tap_axis_control = ADXL_TAP_X_EN | ADXL_TAP_Y_EN | ADXL_TAP_Z_EN,
+	.act_axis_control = 0xFF,
+	.activity_threshold = 5,
+	.inactivity_threshold = 3,
+	.inactivity_time = 4,
+	.free_fall_threshold = 0x7,
+	.free_fall_time = 0x20,
+	.data_rate = 0x8,
+	.data_range = ADXL_FULL_RES,
+
+	.ev_type = EV_ABS,
+	.ev_code_x = ABS_X,		/* EV_REL */
+	.ev_code_y = ABS_Y,		/* EV_REL */
+	.ev_code_z = ABS_Z,		/* EV_REL */
+
+	.ev_code_tap_x = BTN_TOUCH,		/* EV_KEY */
+	.ev_code_tap_y = BTN_TOUCH,		/* EV_KEY */
+	.ev_code_tap_z = BTN_TOUCH,		/* EV_KEY */
+
+/*	.ev_code_ff = KEY_F,*/		/* EV_KEY */
+/*	.ev_code_act_inactivity = KEY_A,*/	/* EV_KEY */
+	.power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
+	.fifo_mode = ADXL_FIFO_STREAM,
+};
+#endif
+
 #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
 static struct platform_device rtc_device = {
 	.name = "rtc-bfin",
@@ -628,6 +665,14 @@
 };
 #endif
 
+#if defined(CONFIG_INPUT_ADXL34X_SPI) || defined(CONFIG_INPUT_ADXL34X_SPI_MODULE)
+static struct bfin5xx_spi_chip spi_adxl34x_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+	.cs_change_per_word = 0,
+};
+#endif
+
 static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #if defined(CONFIG_MTD_M25P80) \
 	|| defined(CONFIG_MTD_M25P80_MODULE)
@@ -653,15 +698,15 @@
 	},
 #endif
 #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
-{
-	.modalias		= "ad7877",
-	.platform_data		= &bfin_ad7877_ts_info,
-	.irq			= IRQ_PB4,	/* old boards (<=Rev 1.3) use IRQ_PJ11 */
-	.max_speed_hz		= 12500000,     /* max spi clock (SCK) speed in HZ */
-	.bus_num		= 0,
-	.chip_select  		= 2,
-	.controller_data = &spi_ad7877_chip_info,
-},
+	{
+		.modalias		= "ad7877",
+		.platform_data		= &bfin_ad7877_ts_info,
+		.irq			= IRQ_PB4,	/* old boards (<=Rev 1.3) use IRQ_PJ11 */
+		.max_speed_hz		= 12500000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num		= 0,
+		.chip_select  		= 2,
+		.controller_data = &spi_ad7877_chip_info,
+	},
 #endif
 #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
 	{
@@ -672,8 +717,19 @@
 		.controller_data = &spidev_chip_info,
 	},
 #endif
+#if defined(CONFIG_INPUT_ADXL34X_SPI) || defined(CONFIG_INPUT_ADXL34X_SPI_MODULE)
+	{
+		.modalias		= "adxl34x",
+		.platform_data		= &adxl34x_info,
+		.irq			= IRQ_PC5,
+		.max_speed_hz		= 5000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num		= 1,
+		.chip_select  		= 2,
+		.controller_data = &spi_adxl34x_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
 };
-
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 /* SPI (0) */
 static struct resource bfin_spi0_resource[] = {
@@ -786,7 +842,7 @@
 
 #if !defined(CONFIG_BF542)	/* The BF542 only has 1 TWI */
 static struct i2c_board_info __initdata bfin_i2c_board_info1[] = {
-#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
 	{
 		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
 	},
@@ -797,6 +853,13 @@
 		.irq = 212,
 	},
 #endif
+#if defined(CONFIG_INPUT_ADXL34X_I2C) || defined(CONFIG_INPUT_ADXL34X_I2C_MODULE)
+	{
+		I2C_BOARD_INFO("adxl34x", 0x53),
+		.irq = IRQ_PC5,
+		.platform_data = (void *)&adxl34x_info,
+	},
+#endif
 };
 #endif
 
diff --git a/arch/blackfin/mach-bf548/include/mach/anomaly.h b/arch/blackfin/mach-bf548/include/mach/anomaly.h
index 882e40c..c510ae6 100644
--- a/arch/blackfin/mach-bf548/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf548/include/mach/anomaly.h
@@ -6,26 +6,31 @@
  * Licensed under the GPL-2 or later.
  */
 
-/* This file shoule be up to date with:
+/* This file should be up to date with:
  *  - Revision H, 01/16/2009; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define _MACH_ANOMALY_H_
 
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
+/* We do not support 0.0 or 0.1 silicon - sorry */
+#if __SILICON_REVISION__ < 2
+# error will not work on BF548 silicon version 0.0, or 0.1
+#endif
+
+/* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */
 #define ANOMALY_05000074 (1)
 /* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
 #define ANOMALY_05000119 (1)
 /* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */
 #define ANOMALY_05000122 (1)
-/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */
+/* False Hardware Error from an Access in the Shadow of a Conditional Branch */
 #define ANOMALY_05000245 (1)
 /* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */
 #define ANOMALY_05000265 (1)
 /* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */
 #define ANOMALY_05000272 (1)
-/* False Hardware Error Exception when ISR context is not restored */
+/* False Hardware Error Exception When ISR Context Is Not Restored */
 #define ANOMALY_05000281 (__SILICON_REVISION__ < 1)
 /* SSYNCs After Writes To CAN/DMA MMR Registers Are Not Always Handled Correctly */
 #define ANOMALY_05000304 (__SILICON_REVISION__ < 1)
@@ -59,7 +64,7 @@
 #define ANOMALY_05000340 (__SILICON_REVISION__ < 1)
 /* Boot Host Wait (HWAIT) and Boot Host Wait Alternate (HWAITA) Signals Are Swapped */
 #define ANOMALY_05000344 (__SILICON_REVISION__ < 1)
-/* USB Calibration Value Is Not Intialized */
+/* USB Calibration Value Is Not Initialized */
 #define ANOMALY_05000346 (__SILICON_REVISION__ < 1)
 /* USB Calibration Value to use */
 #define ANOMALY_05000346_value 0x5411
@@ -147,11 +152,11 @@
 #define ANOMALY_05000416 (1)
 /* Multichannel SPORT Channel Misalignment Under Specific Configuration */
 #define ANOMALY_05000425 (1)
-/* Speculative Fetches of Indirect-Pointer Instructions Can Cause Spurious Hardware Errors */
+/* Speculative Fetches of Indirect-Pointer Instructions Can Cause False Hardware Errors */
 #define ANOMALY_05000426 (1)
 /* CORE_EPPI_PRIO bit and SYS_EPPI_PRIO bit in the HMDMA1_CONTROL register are not functional */
 #define ANOMALY_05000427 (__SILICON_REVISION__ < 2)
-/* WB_EDGE Bit in NFC_IRQSTAT Incorrectly Behaves as a Buffer Status Bit Instead of an IRQ Status Bit */
+/* WB_EDGE Bit in NFC_IRQSTAT Incorrectly Reflects Buffer Status Instead of IRQ Status */
 #define ANOMALY_05000429 (__SILICON_REVISION__ < 2)
 /* Software System Reset Corrupts PLL_LOCKCNT Register */
 #define ANOMALY_05000430 (__SILICON_REVISION__ >= 2)
@@ -170,26 +175,49 @@
 /* Reduced Timing Margins on DDR Output Setup and Hold (tDS and tDH) */
 #define ANOMALY_05000449 (__SILICON_REVISION__ == 1)
 /* USB DMA Mode 1 Short Packet Data Corruption */
-#define ANOMALY_05000450 (1
+#define ANOMALY_05000450 (1)
+/* USB Receive Interrupt Is Not Generated in DMA Mode 1 */
+#define ANOMALY_05000456 (__SILICON_REVISION__ < 3)
+/* False Hardware Error when RETI points to invalid memory */
+#define ANOMALY_05000461 (1)
 
 /* Anomalies that don't exist on this proc */
+#define ANOMALY_05000099 (0)
+#define ANOMALY_05000120 (0)
 #define ANOMALY_05000125 (0)
+#define ANOMALY_05000149 (0)
 #define ANOMALY_05000158 (0)
+#define ANOMALY_05000171 (0)
+#define ANOMALY_05000179 (0)
 #define ANOMALY_05000183 (0)
 #define ANOMALY_05000198 (0)
+#define ANOMALY_05000215 (0)
+#define ANOMALY_05000220 (0)
+#define ANOMALY_05000227 (0)
 #define ANOMALY_05000230 (0)
+#define ANOMALY_05000231 (0)
+#define ANOMALY_05000233 (0)
+#define ANOMALY_05000242 (0)
 #define ANOMALY_05000244 (0)
+#define ANOMALY_05000248 (0)
+#define ANOMALY_05000250 (0)
+#define ANOMALY_05000254 (0)
 #define ANOMALY_05000261 (0)
 #define ANOMALY_05000263 (0)
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000273 (0)
+#define ANOMALY_05000274 (0)
 #define ANOMALY_05000278 (0)
+#define ANOMALY_05000287 (0)
+#define ANOMALY_05000301 (0)
 #define ANOMALY_05000305 (0)
 #define ANOMALY_05000307 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000323 (0)
+#define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
 #define ANOMALY_05000380 (0)
+#define ANOMALY_05000400 (0)
 #define ANOMALY_05000412 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
diff --git a/arch/blackfin/mach-bf548/include/mach/portmux.h b/arch/blackfin/mach-bf548/include/mach/portmux.h
index ffb1d0a..ce372ba 100644
--- a/arch/blackfin/mach-bf548/include/mach/portmux.h
+++ b/arch/blackfin/mach-bf548/include/mach/portmux.h
@@ -167,22 +167,42 @@
 #define P_PPI0_D13	(P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(0))
 #define P_PPI0_D14	(P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(0))
 #define P_PPI0_D15	(P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(0))
-#define P_ATAPI_D0A	(P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(1))
-#define P_ATAPI_D1A	(P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(1))
-#define P_ATAPI_D2A	(P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(1))
-#define P_ATAPI_D3A	(P_DEFINED | P_IDENT(GPIO_PF3) | P_FUNCT(1))
-#define P_ATAPI_D4A	(P_DEFINED | P_IDENT(GPIO_PF4) | P_FUNCT(1))
-#define P_ATAPI_D5A	(P_DEFINED | P_IDENT(GPIO_PF5) | P_FUNCT(1))
-#define P_ATAPI_D6A	(P_DEFINED | P_IDENT(GPIO_PF6) | P_FUNCT(1))
-#define P_ATAPI_D7A	(P_DEFINED | P_IDENT(GPIO_PF7) | P_FUNCT(1))
-#define P_ATAPI_D8A	(P_DEFINED | P_IDENT(GPIO_PF8) | P_FUNCT(1))
-#define P_ATAPI_D9A	(P_DEFINED | P_IDENT(GPIO_PF9) | P_FUNCT(1))
-#define P_ATAPI_D10A	(P_DEFINED | P_IDENT(GPIO_PF10) | P_FUNCT(1))
-#define P_ATAPI_D11A	(P_DEFINED | P_IDENT(GPIO_PF11) | P_FUNCT(1))
-#define P_ATAPI_D12A	(P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(1))
-#define P_ATAPI_D13A	(P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(1))
-#define P_ATAPI_D14A	(P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(1))
-#define P_ATAPI_D15A	(P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(1))
+
+#ifdef CONFIG_BF548_ATAPI_ALTERNATIVE_PORT
+# define P_ATAPI_D0A	(P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(1))
+# define P_ATAPI_D1A	(P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(1))
+# define P_ATAPI_D2A	(P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(1))
+# define P_ATAPI_D3A	(P_DEFINED | P_IDENT(GPIO_PF3) | P_FUNCT(1))
+# define P_ATAPI_D4A	(P_DEFINED | P_IDENT(GPIO_PF4) | P_FUNCT(1))
+# define P_ATAPI_D5A	(P_DEFINED | P_IDENT(GPIO_PF5) | P_FUNCT(1))
+# define P_ATAPI_D6A	(P_DEFINED | P_IDENT(GPIO_PF6) | P_FUNCT(1))
+# define P_ATAPI_D7A	(P_DEFINED | P_IDENT(GPIO_PF7) | P_FUNCT(1))
+# define P_ATAPI_D8A	(P_DEFINED | P_IDENT(GPIO_PF8) | P_FUNCT(1))
+# define P_ATAPI_D9A	(P_DEFINED | P_IDENT(GPIO_PF9) | P_FUNCT(1))
+# define P_ATAPI_D10A	(P_DEFINED | P_IDENT(GPIO_PF10) | P_FUNCT(1))
+# define P_ATAPI_D11A	(P_DEFINED | P_IDENT(GPIO_PF11) | P_FUNCT(1))
+# define P_ATAPI_D12A	(P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(1))
+# define P_ATAPI_D13A	(P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(1))
+# define P_ATAPI_D14A	(P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(1))
+# define P_ATAPI_D15A	(P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(1))
+#else
+# define P_ATAPI_D0A	(P_DONTCARE)
+# define P_ATAPI_D1A	(P_DONTCARE)
+# define P_ATAPI_D2A	(P_DONTCARE)
+# define P_ATAPI_D3A	(P_DONTCARE)
+# define P_ATAPI_D4A	(P_DONTCARE)
+# define P_ATAPI_D5A	(P_DONTCARE)
+# define P_ATAPI_D6A	(P_DONTCARE)
+# define P_ATAPI_D7A	(P_DONTCARE)
+# define P_ATAPI_D8A	(P_DONTCARE)
+# define P_ATAPI_D9A	(P_DONTCARE)
+# define P_ATAPI_D10A	(P_DONTCARE)
+# define P_ATAPI_D11A	(P_DONTCARE)
+# define P_ATAPI_D12A	(P_DONTCARE)
+# define P_ATAPI_D13A	(P_DONTCARE)
+# define P_ATAPI_D14A	(P_DONTCARE)
+# define P_ATAPI_D15A	(P_DONTCARE)
+#endif
 
 #define P_PPI0_CLK	(P_DEFINED | P_IDENT(GPIO_PG0) | P_FUNCT(0))
 #define P_PPI0_FS1	(P_DEFINED | P_IDENT(GPIO_PG1) | P_FUNCT(0))
@@ -200,9 +220,15 @@
 #define P_CAN0_RX	(P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(0))
 #define P_CAN1_TX	(P_DEFINED | P_IDENT(GPIO_PG14) | P_FUNCT(0))
 #define P_CAN1_RX	(P_DEFINED | P_IDENT(GPIO_PG15) | P_FUNCT(0))
-#define P_ATAPI_A0A	(P_DEFINED | P_IDENT(GPIO_PG2) | P_FUNCT(1))
-#define P_ATAPI_A1A	(P_DEFINED | P_IDENT(GPIO_PG3) | P_FUNCT(1))
-#define P_ATAPI_A2A	(P_DEFINED | P_IDENT(GPIO_PG4) | P_FUNCT(1))
+#ifdef CONFIG_BF548_ATAPI_ALTERNATIVE_PORT
+# define P_ATAPI_A0A	(P_DEFINED | P_IDENT(GPIO_PG2) | P_FUNCT(1))
+# define P_ATAPI_A1A	(P_DEFINED | P_IDENT(GPIO_PG3) | P_FUNCT(1))
+# define P_ATAPI_A2A	(P_DEFINED | P_IDENT(GPIO_PG4) | P_FUNCT(1))
+#else
+# define P_ATAPI_A0A	(P_DONTCARE)
+# define P_ATAPI_A1A	(P_DONTCARE)
+# define P_ATAPI_A2A	(P_DONTCARE)
+#endif
 #define P_HOST_CE	(P_DEFINED | P_IDENT(GPIO_PG5) | P_FUNCT(1))
 #define P_HOST_RD	(P_DEFINED | P_IDENT(GPIO_PG6) | P_FUNCT(1))
 #define P_HOST_WR	(P_DEFINED | P_IDENT(GPIO_PG7) | P_FUNCT(1))
diff --git a/arch/blackfin/mach-bf561/Kconfig b/arch/blackfin/mach-bf561/Kconfig
index 638ec38..cb97436 100644
--- a/arch/blackfin/mach-bf561/Kconfig
+++ b/arch/blackfin/mach-bf561/Kconfig
@@ -9,22 +9,9 @@
 comment "Core B Support"
 
 config BF561_COREB
-	bool "Enable Core B support"
+	bool "Enable Core B loader"
 	default y
 
-config BF561_COREB_RESET
-	bool "Enable Core B reset support"
-	default n
-	help
-	  This requires code in the application that is loaded
-	  into Core B. In order to reset, the application needs
-	  to install an interrupt handler for Supplemental
-	  Interrupt 0, that sets RETI to 0xff600000 and writes
-	  bit 11 of SICB_SYSCR when bit 5 of SICA_SYSCR is 0.
-	  This causes Core B to stall when Supplemental Interrupt
-	  0 is set, and will reset PC to 0xff600000 when
-	  COREB_SRAM_INIT is cleared.
-
 endif
 
 comment "Interrupt Priority Assignment"
@@ -138,6 +125,7 @@
 	default 9
 config IRQ_TIMER0
 	int "TIMER 0  Interrupt"
+	default 7 if TICKSOURCE_GPTMR0
 	default 8
 config IRQ_TIMER1
 	int "TIMER 1  Interrupt"
diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c
index f623c6b..0dd9685 100644
--- a/arch/blackfin/mach-bf561/boards/cm_bf561.c
+++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c
@@ -83,7 +83,7 @@
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
 	.enable_dma = 1,         /* use dma transfer with this chip*/
@@ -126,7 +126,7 @@
 	},
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 	{
 		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
 		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
diff --git a/arch/blackfin/mach-bf561/coreb.c b/arch/blackfin/mach-bf561/coreb.c
index 8598098..93635a7 100644
--- a/arch/blackfin/mach-bf561/coreb.c
+++ b/arch/blackfin/mach-bf561/coreb.c
@@ -1,406 +1,74 @@
-/*
- * File:         arch/blackfin/mach-bf561/coreb.c
- * Based on:
- * Author:
+/* Load firmware into Core B on a BF561
  *
- * Created:
- * Description:  Handle CoreB on a BF561
- *
- * Modified:
- *               Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * Copyright 2004-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
  */
 
-#include <linux/mm.h>
-#include <linux/miscdevice.h>
+/* The Core B reset func requires code in the application that is loaded into
+ * Core B.  In order to reset, the application needs to install an interrupt
+ * handler for Supplemental Interrupt 0, that sets RETI to 0xff600000 and
+ * writes bit 11 of SICB_SYSCR when bit 5 of SICA_SYSCR is 0.  This causes Core
+ * B to stall when Supplemental Interrupt 0 is set, and will reset PC to
+ * 0xff600000 when COREB_SRAM_INIT is cleared.
+ */
+
 #include <linux/device.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/uaccess.h>
 #include <linux/fs.h>
-#include <asm/dma.h>
-#include <asm/cacheflush.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
 
-#define MODULE_VER		"v0.1"
-
-static spinlock_t coreb_lock;
-static wait_queue_head_t coreb_dma_wait;
-
-#define COREB_IS_OPEN		0x00000001
-#define COREB_IS_RUNNING	0x00000010
-
-#define CMD_COREB_INDEX		1
 #define CMD_COREB_START		2
 #define CMD_COREB_STOP		3
 #define CMD_COREB_RESET		4
 
-#define COREB_MINOR		229
-
-static unsigned long coreb_status = 0;
-static unsigned long coreb_base = 0xff600000;
-static unsigned long coreb_size = 0x4000;
-int coreb_dma_done;
-
-static loff_t coreb_lseek(struct file *file, loff_t offset, int origin);
-static ssize_t coreb_read(struct file *file, char *buf, size_t count,
-			  loff_t * ppos);
-static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
-			   loff_t * ppos);
-static int coreb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-		       unsigned long arg);
-static int coreb_open(struct inode *inode, struct file *file);
-static int coreb_release(struct inode *inode, struct file *file);
-
-static irqreturn_t coreb_dma_interrupt(int irq, void *dev_id)
+static int
+coreb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	clear_dma_irqstat(CH_MEM_STREAM2_DEST);
-	coreb_dma_done = 1;
-	wake_up_interruptible(&coreb_dma_wait);
-	return IRQ_HANDLED;
-}
+	int ret = 0;
 
-static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
-			   loff_t * ppos)
-{
-	unsigned long p = *ppos;
-	ssize_t wrote = 0;
-
-	if (p + count > coreb_size)
-		return -EFAULT;
-
-	while (count > 0) {
-		int len = count;
-
-		if (len > PAGE_SIZE)
-			len = PAGE_SIZE;
-
-		coreb_dma_done = 0;
-
-		flush_dcache_range((unsigned long)buf, (unsigned long)(buf+len));
-		/* Source Channel */
-		set_dma_start_addr(CH_MEM_STREAM2_SRC, (unsigned long)buf);
-		set_dma_x_count(CH_MEM_STREAM2_SRC, len);
-		set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
-		set_dma_config(CH_MEM_STREAM2_SRC, 0);
-		/* Destination Channel */
-		set_dma_start_addr(CH_MEM_STREAM2_DEST, coreb_base + p);
-		set_dma_x_count(CH_MEM_STREAM2_DEST, len);
-		set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char));
-		set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN);
-
-		enable_dma(CH_MEM_STREAM2_SRC);
-		enable_dma(CH_MEM_STREAM2_DEST);
-
-		wait_event_interruptible(coreb_dma_wait, coreb_dma_done);
-
-		disable_dma(CH_MEM_STREAM2_SRC);
-		disable_dma(CH_MEM_STREAM2_DEST);
-
-		count -= len;
-		wrote += len;
-		buf += len;
-		p += len;
-	}
-	*ppos = p;
-	return wrote;
-}
-
-static ssize_t coreb_read(struct file *file, char *buf, size_t count,
-			  loff_t * ppos)
-{
-	unsigned long p = *ppos;
-	ssize_t read = 0;
-
-	if ((p + count) > coreb_size)
-		return -EFAULT;
-
-	while (count > 0) {
-		int len = count;
-
-		if (len > PAGE_SIZE)
-			len = PAGE_SIZE;
-
-		coreb_dma_done = 0;
-
-		invalidate_dcache_range((unsigned long)buf, (unsigned long)(buf+len));
-		/* Source Channel */
-		set_dma_start_addr(CH_MEM_STREAM2_SRC, coreb_base + p);
-		set_dma_x_count(CH_MEM_STREAM2_SRC, len);
-		set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
-		set_dma_config(CH_MEM_STREAM2_SRC, 0);
-		/* Destination Channel */
-		set_dma_start_addr(CH_MEM_STREAM2_DEST, (unsigned long)buf);
-		set_dma_x_count(CH_MEM_STREAM2_DEST, len);
-		set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char));
-		set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN);
-
-		enable_dma(CH_MEM_STREAM2_SRC);
-		enable_dma(CH_MEM_STREAM2_DEST);
-
-		wait_event_interruptible(coreb_dma_wait, coreb_dma_done);
-
-		disable_dma(CH_MEM_STREAM2_SRC);
-		disable_dma(CH_MEM_STREAM2_DEST);
-
-		count -= len;
-		read += len;
-		buf += len;
-		p += len;
-	}
-
-	return read;
-}
-
-static loff_t coreb_lseek(struct file *file, loff_t offset, int origin)
-{
-	loff_t ret;
-
-	mutex_lock(&file->f_dentry->d_inode->i_mutex);
-
-	switch (origin) {
-	case 0 /* SEEK_SET */ :
-		if (offset < coreb_size) {
-			file->f_pos = offset;
-			ret = file->f_pos;
-		} else
-			ret = -EINVAL;
+	switch (cmd) {
+	case CMD_COREB_START:
+		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020);
 		break;
-	case 1 /* SEEK_CUR */ :
-		if ((offset + file->f_pos) < coreb_size) {
-			file->f_pos += offset;
-			ret = file->f_pos;
-		} else
-			ret = -EINVAL;
+	case CMD_COREB_STOP:
+		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020);
+		bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
+		break;
+	case CMD_COREB_RESET:
+		bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
+		break;
 	default:
 		ret = -EINVAL;
+		break;
 	}
-	mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+
+	CSYNC();
+
 	return ret;
 }
 
-/* No BKL needed here */
-static int coreb_open(struct inode *inode, struct file *file)
-{
-	spin_lock_irq(&coreb_lock);
-
-	if (coreb_status & COREB_IS_OPEN)
-		goto out_busy;
-
-	coreb_status |= COREB_IS_OPEN;
-
-	spin_unlock_irq(&coreb_lock);
-	return 0;
-
- out_busy:
-	spin_unlock_irq(&coreb_lock);
-	return -EBUSY;
-}
-
-static int coreb_release(struct inode *inode, struct file *file)
-{
-	spin_lock_irq(&coreb_lock);
-	coreb_status &= ~COREB_IS_OPEN;
-	spin_unlock_irq(&coreb_lock);
-	return 0;
-}
-
-static int coreb_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg)
-{
-	int retval = 0;
-	int coreb_index = 0;
-
-	switch (cmd) {
-	case CMD_COREB_INDEX:
-		if (copy_from_user(&coreb_index, (int *)arg, sizeof(int))) {
-			retval = -EFAULT;
-			break;
-		}
-
-		spin_lock_irq(&coreb_lock);
-		switch (coreb_index) {
-		case 0:
-			coreb_base = 0xff600000;
-			coreb_size = 0x4000;
-			break;
-		case 1:
-			coreb_base = 0xff610000;
-			coreb_size = 0x4000;
-			break;
-		case 2:
-			coreb_base = 0xff500000;
-			coreb_size = 0x8000;
-			break;
-		case 3:
-			coreb_base = 0xff400000;
-			coreb_size = 0x8000;
-			break;
-		default:
-			retval = -EINVAL;
-			break;
-		}
-		spin_unlock_irq(&coreb_lock);
-
-		mutex_lock(&file->f_dentry->d_inode->i_mutex);
-		file->f_pos = 0;
-		mutex_unlock(&file->f_dentry->d_inode->i_mutex);
-		break;
-	case CMD_COREB_START:
-		spin_lock_irq(&coreb_lock);
-		if (coreb_status & COREB_IS_RUNNING) {
-			retval = -EBUSY;
-			break;
-		}
-		printk(KERN_INFO "Starting Core B\n");
-		coreb_status |= COREB_IS_RUNNING;
-		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020);
-		SSYNC();
-		spin_unlock_irq(&coreb_lock);
-		break;
-#if defined(CONFIG_BF561_COREB_RESET)
-	case CMD_COREB_STOP:
-		spin_lock_irq(&coreb_lock);
-		printk(KERN_INFO "Stopping Core B\n");
-		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020);
-		bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
-		coreb_status &= ~COREB_IS_RUNNING;
-		spin_unlock_irq(&coreb_lock);
-		break;
-	case CMD_COREB_RESET:
-		printk(KERN_INFO "Resetting Core B\n");
-		bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
-		break;
-#endif
-	}
-
-	return retval;
-}
-
 static struct file_operations coreb_fops = {
-	.owner = THIS_MODULE,
-	.llseek = coreb_lseek,
-	.read = coreb_read,
-	.write = coreb_write,
-	.ioctl = coreb_ioctl,
-	.open = coreb_open,
-	.release = coreb_release
+	.owner   = THIS_MODULE,
+	.ioctl   = coreb_ioctl,
 };
 
 static struct miscdevice coreb_dev = {
-	COREB_MINOR,
-	"coreb",
-	&coreb_fops
+	.minor = MISC_DYNAMIC_MINOR,
+	.name  = "coreb",
+	.fops  = &coreb_fops,
 };
 
-static ssize_t coreb_show_status(struct device *dev, struct device_attribute *attr, char *buf)
+static int __init bf561_coreb_init(void)
 {
-	return sprintf(buf,
-		       "Base Address:\t0x%08lx\n"
-		       "Core B is %s\n"
-		       "SICA_SYSCR:\t%04x\n"
-		       "SICB_SYSCR:\t%04x\n"
-		       "\n"
-		       "IRQ Status:\tCore A\t\tCore B\n"
-		       "ISR0:\t\t%08x\t\t%08x\n"
-		       "ISR1:\t\t%08x\t\t%08x\n"
-		       "IMASK0:\t\t%08x\t\t%08x\n"
-		       "IMASK1:\t\t%08x\t\t%08x\n",
-		       coreb_base,
-		       coreb_status & COREB_IS_RUNNING ? "running" : "stalled",
-		       bfin_read_SICA_SYSCR(), bfin_read_SICB_SYSCR(),
-		       bfin_read_SICA_ISR0(), bfin_read_SICB_ISR0(),
-		       bfin_read_SICA_ISR1(), bfin_read_SICB_ISR0(),
-		       bfin_read_SICA_IMASK0(), bfin_read_SICB_IMASK0(),
-		       bfin_read_SICA_IMASK1(), bfin_read_SICB_IMASK1());
+	return misc_register(&coreb_dev);
 }
-
-static DEVICE_ATTR(coreb_status, S_IRUGO, coreb_show_status, NULL);
-
-int __init bf561_coreb_init(void)
-{
-	init_waitqueue_head(&coreb_dma_wait);
-
-	spin_lock_init(&coreb_lock);
-	/* Request the core memory regions for Core B */
-	if (request_mem_region(0xff600000, 0x4000,
-			       "Core B - Instruction SRAM") == NULL)
-		goto exit;
-
-	if (request_mem_region(0xFF610000, 0x4000,
-			       "Core B - Instruction SRAM") == NULL)
-		goto release_instruction_a_sram;
-
-	if (request_mem_region(0xFF500000, 0x8000,
-			       "Core B - Data Bank B SRAM") == NULL)
-		goto release_instruction_b_sram;
-
-	if (request_mem_region(0xff400000, 0x8000,
-			       "Core B - Data Bank A SRAM") == NULL)
-		goto release_data_b_sram;
-
-	if (request_dma(CH_MEM_STREAM2_DEST, "Core B - DMA Destination") < 0)
-		goto release_data_a_sram;
-
-	if (request_dma(CH_MEM_STREAM2_SRC, "Core B - DMA Source") < 0)
-		goto release_dma_dest;
-
-	set_dma_callback(CH_MEM_STREAM2_DEST, coreb_dma_interrupt, NULL);
-
-	misc_register(&coreb_dev);
-
-	if (device_create_file(coreb_dev.this_device, &dev_attr_coreb_status))
-		goto release_dma_src;
-
-	printk(KERN_INFO "BF561 Core B driver %s initialized.\n", MODULE_VER);
-	return 0;
-
- release_dma_src:
-	free_dma(CH_MEM_STREAM2_SRC);
- release_dma_dest:
-	free_dma(CH_MEM_STREAM2_DEST);
- release_data_a_sram:
-	release_mem_region(0xff400000, 0x8000);
- release_data_b_sram:
-	release_mem_region(0xff500000, 0x8000);
- release_instruction_b_sram:
-	release_mem_region(0xff610000, 0x4000);
- release_instruction_a_sram:
-	release_mem_region(0xff600000, 0x4000);
- exit:
-	return -ENOMEM;
-}
-
-void __exit bf561_coreb_exit(void)
-{
-	device_remove_file(coreb_dev.this_device, &dev_attr_coreb_status);
-	misc_deregister(&coreb_dev);
-
-	release_mem_region(0xff610000, 0x4000);
-	release_mem_region(0xff600000, 0x4000);
-	release_mem_region(0xff500000, 0x8000);
-	release_mem_region(0xff400000, 0x8000);
-
-	free_dma(CH_MEM_STREAM2_DEST);
-	free_dma(CH_MEM_STREAM2_SRC);
-}
-
 module_init(bf561_coreb_init);
+
+static void __exit bf561_coreb_exit(void)
+{
+	misc_deregister(&coreb_dev);
+}
 module_exit(bf561_coreb_exit);
 
 MODULE_AUTHOR("Bas Vermeulen <bvermeul@blackstar.xs4all.nl>");
diff --git a/arch/blackfin/mach-bf561/include/mach/anomaly.h b/arch/blackfin/mach-bf561/include/mach/anomaly.h
index d0b0b35..dccd396 100644
--- a/arch/blackfin/mach-bf561/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf561/include/mach/anomaly.h
@@ -6,7 +6,7 @@
  * Licensed under the GPL-2 or later.
  */
 
-/* This file shoule be up to date with:
+/* This file should be up to date with:
  *  - Revision Q, 11/07/2008; ADSP-BF561 Blackfin Processor Anomaly List
  */
 
@@ -18,11 +18,11 @@
 # error will not work on BF561 silicon version 0.0, 0.1, 0.2, or 0.4
 #endif
 
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot 2 Not Supported */
+/* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */
 #define ANOMALY_05000074 (1)
 /* UART Line Status Register (UART_LSR) Bits Are Not Updated at the Same Time */
 #define ANOMALY_05000099 (__SILICON_REVISION__ < 5)
-/* Trace Buffers may contain errors in emulation mode and/or exception, NMI, reset handlers */
+/* Trace Buffers may record discontinuities into emulation mode and/or exception, NMI, reset handlers */
 #define ANOMALY_05000116 (__SILICON_REVISION__ < 3)
 /* Testset instructions restricted to 32-bit aligned memory locations */
 #define ANOMALY_05000120 (1)
@@ -40,7 +40,7 @@
 #define ANOMALY_05000136 (__SILICON_REVISION__ < 3)
 /* Allowing the SPORT RX FIFO to fill will cause an overflow */
 #define ANOMALY_05000140 (__SILICON_REVISION__ < 3)
-/* Infinite Stall may occur with a particular sequence of consecutive dual dag events */
+/* An Infinite Stall occurs with a particular sequence of consecutive dual dag events */
 #define ANOMALY_05000141 (__SILICON_REVISION__ < 3)
 /* Interrupts may be lost when a programmable input flag is configured to be edge sensitive */
 #define ANOMALY_05000142 (__SILICON_REVISION__ < 3)
@@ -80,7 +80,7 @@
 #define ANOMALY_05000163 (__SILICON_REVISION__ < 3)
 /* PPI Data Lengths Between 8 and 16 Do Not Zero Out Upper Bits */
 #define ANOMALY_05000166 (1)
-/* Turning Serial Ports on with External Frame Syncs */
+/* Turning SPORTs on while External Frame Sync Is Active May Corrupt Data */
 #define ANOMALY_05000167 (1)
 /* SDRAM auto-refresh and subsequent Power Ups */
 #define ANOMALY_05000168 (__SILICON_REVISION__ < 5)
@@ -164,7 +164,7 @@
 #define ANOMALY_05000242 (__SILICON_REVISION__ < 5)
 /* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */
 #define ANOMALY_05000244 (__SILICON_REVISION__ < 5)
-/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */
+/* False Hardware Error from an Access in the Shadow of a Conditional Branch */
 #define ANOMALY_05000245 (__SILICON_REVISION__ < 5)
 /* TESTSET operation forces stall on the other core */
 #define ANOMALY_05000248 (__SILICON_REVISION__ < 5)
@@ -208,7 +208,7 @@
 #define ANOMALY_05000275 (__SILICON_REVISION__ > 2)
 /* Timing Requirements Change for External Frame Sync PPI Modes with Non-Zero PPI_DELAY */
 #define ANOMALY_05000276 (__SILICON_REVISION__ < 5)
-/* Writes to an I/O data register one SCLK cycle after an edge is detected may clear interrupt */
+/* Writes to an I/O Data Register One SCLK Cycle after an Edge Is Detected May Clear Interrupt */
 #define ANOMALY_05000277 (__SILICON_REVISION__ < 3)
 /* Disabling Peripherals with DMA Running May Cause DMA System Instability */
 #define ANOMALY_05000278 (__SILICON_REVISION__ < 5)
@@ -232,7 +232,7 @@
 #define ANOMALY_05000310 (1)
 /* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
 #define ANOMALY_05000312 (1)
-/* PPI Is Level-Sensitive on First Transfer */
+/* PPI Is Level-Sensitive on First Transfer In Single Frame Sync Modes */
 #define ANOMALY_05000313 (1)
 /* Killed System MMR Write Completes Erroneously On Next System MMR Access */
 #define ANOMALY_05000315 (1)
@@ -276,18 +276,27 @@
 #define ANOMALY_05000428 (__SILICON_REVISION__ > 3)
 /* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */
 #define ANOMALY_05000443 (1)
+/* False Hardware Error when RETI points to invalid memory */
+#define ANOMALY_05000461 (1)
 
 /* Anomalies that don't exist on this proc */
+#define ANOMALY_05000119 (0)
 #define ANOMALY_05000158 (0)
 #define ANOMALY_05000183 (0)
+#define ANOMALY_05000233 (0)
 #define ANOMALY_05000273 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000353 (1)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (1)
+#define ANOMALY_05000389 (0)
+#define ANOMALY_05000400 (0)
+#define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
+#define ANOMALY_05000456 (0)
+#define ANOMALY_05000450 (0)
 
 #endif
diff --git a/arch/blackfin/mach-bf561/include/mach/cdefBF561.h b/arch/blackfin/mach-bf561/include/mach/cdefBF561.h
index 95d609f..9d9858c 100644
--- a/arch/blackfin/mach-bf561/include/mach/cdefBF561.h
+++ b/arch/blackfin/mach-bf561/include/mach/cdefBF561.h
@@ -1526,6 +1526,35 @@
 #define bfin_read_MDMA_D0_START_ADDR()  bfin_read_MDMA1_D0_START_ADDR()
 #define bfin_write_MDMA_D0_START_ADDR(val) bfin_write_MDMA1_D0_START_ADDR(val)
 
+#define bfin_read_MDMA_S1_CONFIG()  bfin_read_MDMA1_S1_CONFIG()
+#define bfin_write_MDMA_S1_CONFIG(val) bfin_write_MDMA1_S1_CONFIG(val)
+#define bfin_read_MDMA_S1_IRQ_STATUS()  bfin_read_MDMA1_S1_IRQ_STATUS()
+#define bfin_write_MDMA_S1_IRQ_STATUS(val) bfin_write_MDMA1_S1_IRQ_STATUS(val)
+#define bfin_read_MDMA_S1_X_MODIFY()  bfin_read_MDMA1_S1_X_MODIFY()
+#define bfin_write_MDMA_S1_X_MODIFY(val) bfin_write_MDMA1_S1_X_MODIFY(val)
+#define bfin_read_MDMA_S1_Y_MODIFY()  bfin_read_MDMA1_S1_Y_MODIFY()
+#define bfin_write_MDMA_S1_Y_MODIFY(val) bfin_write_MDMA1_S1_Y_MODIFY(val)
+#define bfin_read_MDMA_S1_X_COUNT()  bfin_read_MDMA1_S1_X_COUNT()
+#define bfin_write_MDMA_S1_X_COUNT(val) bfin_write_MDMA1_S1_X_COUNT(val)
+#define bfin_read_MDMA_S1_Y_COUNT()  bfin_read_MDMA1_S1_Y_COUNT()
+#define bfin_write_MDMA_S1_Y_COUNT(val) bfin_write_MDMA1_S1_Y_COUNT(val)
+#define bfin_read_MDMA_S1_START_ADDR()  bfin_read_MDMA1_S1_START_ADDR()
+#define bfin_write_MDMA_S1_START_ADDR(val) bfin_write_MDMA1_S1_START_ADDR(val)
+#define bfin_read_MDMA_D1_CONFIG()  bfin_read_MDMA1_D1_CONFIG()
+#define bfin_write_MDMA_D1_CONFIG(val) bfin_write_MDMA1_D1_CONFIG(val)
+#define bfin_read_MDMA_D1_IRQ_STATUS()  bfin_read_MDMA1_D1_IRQ_STATUS()
+#define bfin_write_MDMA_D1_IRQ_STATUS(val) bfin_write_MDMA1_D1_IRQ_STATUS(val)
+#define bfin_read_MDMA_D1_X_MODIFY()  bfin_read_MDMA1_D1_X_MODIFY()
+#define bfin_write_MDMA_D1_X_MODIFY(val) bfin_write_MDMA1_D1_X_MODIFY(val)
+#define bfin_read_MDMA_D1_Y_MODIFY()  bfin_read_MDMA1_D1_Y_MODIFY()
+#define bfin_write_MDMA_D1_Y_MODIFY(val) bfin_write_MDMA1_D1_Y_MODIFY(val)
+#define bfin_read_MDMA_D1_X_COUNT()  bfin_read_MDMA1_D1_X_COUNT()
+#define bfin_write_MDMA_D1_X_COUNT(val) bfin_write_MDMA1_D1_X_COUNT(val)
+#define bfin_read_MDMA_D1_Y_COUNT()  bfin_read_MDMA1_D1_Y_COUNT()
+#define bfin_write_MDMA_D1_Y_COUNT(val) bfin_write_MDMA1_D1_Y_COUNT(val)
+#define bfin_read_MDMA_D1_START_ADDR()  bfin_read_MDMA1_D1_START_ADDR()
+#define bfin_write_MDMA_D1_START_ADDR(val) bfin_write_MDMA1_D1_START_ADDR(val)
+
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
diff --git a/arch/blackfin/mach-bf561/include/mach/defBF561.h b/arch/blackfin/mach-bf561/include/mach/defBF561.h
index cf92229..5fc0f05 100644
--- a/arch/blackfin/mach-bf561/include/mach/defBF561.h
+++ b/arch/blackfin/mach-bf561/include/mach/defBF561.h
@@ -796,6 +796,62 @@
 #define MDMA2_S1_IRQ_STATUS 0xFFC00FE8	/*MemDMA2 Stream 1 Source Interrupt/Status Register */
 #define MDMA2_S1_PERIPHERAL_MAP 0xFFC00FEC	/*MemDMA2 Stream 1 Source Peripheral Map register */
 
+#define MDMA_D0_NEXT_DESC_PTR MDMA1_D0_NEXT_DESC_PTR
+#define MDMA_D0_START_ADDR MDMA1_D0_START_ADDR
+#define MDMA_D0_CONFIG MDMA1_D0_CONFIG
+#define MDMA_D0_X_COUNT MDMA1_D0_X_COUNT
+#define MDMA_D0_X_MODIFY MDMA1_D0_X_MODIFY
+#define MDMA_D0_Y_COUNT MDMA1_D0_Y_COUNT
+#define MDMA_D0_Y_MODIFY MDMA1_D0_Y_MODIFY
+#define MDMA_D0_CURR_DESC_PTR MDMA1_D0_CURR_DESC_PTR
+#define MDMA_D0_CURR_ADDR MDMA1_D0_CURR_ADDR
+#define MDMA_D0_IRQ_STATUS MDMA1_D0_IRQ_STATUS
+#define MDMA_D0_PERIPHERAL_MAP MDMA1_D0_PERIPHERAL_MAP
+#define MDMA_D0_CURR_X_COUNT MDMA1_D0_CURR_X_COUNT
+#define MDMA_D0_CURR_Y_COUNT MDMA1_D0_CURR_Y_COUNT
+
+#define MDMA_S0_NEXT_DESC_PTR MDMA1_S0_NEXT_DESC_PTR
+#define MDMA_S0_START_ADDR MDMA1_S0_START_ADDR
+#define MDMA_S0_CONFIG MDMA1_S0_CONFIG
+#define MDMA_S0_X_COUNT MDMA1_S0_X_COUNT
+#define MDMA_S0_X_MODIFY MDMA1_S0_X_MODIFY
+#define MDMA_S0_Y_COUNT MDMA1_S0_Y_COUNT
+#define MDMA_S0_Y_MODIFY MDMA1_S0_Y_MODIFY
+#define MDMA_S0_CURR_DESC_PTR MDMA1_S0_CURR_DESC_PTR
+#define MDMA_S0_CURR_ADDR MDMA1_S0_CURR_ADDR
+#define MDMA_S0_IRQ_STATUS MDMA1_S0_IRQ_STATUS
+#define MDMA_S0_PERIPHERAL_MAP MDMA1_S0_PERIPHERAL_MAP
+#define MDMA_S0_CURR_X_COUNT MDMA1_S0_CURR_X_COUNT
+#define MDMA_S0_CURR_Y_COUNT MDMA1_S0_CURR_Y_COUNT
+
+#define MDMA_D1_NEXT_DESC_PTR MDMA1_D1_NEXT_DESC_PTR
+#define MDMA_D1_START_ADDR MDMA1_D1_START_ADDR
+#define MDMA_D1_CONFIG MDMA1_D1_CONFIG
+#define MDMA_D1_X_COUNT MDMA1_D1_X_COUNT
+#define MDMA_D1_X_MODIFY MDMA1_D1_X_MODIFY
+#define MDMA_D1_Y_COUNT MDMA1_D1_Y_COUNT
+#define MDMA_D1_Y_MODIFY MDMA1_D1_Y_MODIFY
+#define MDMA_D1_CURR_DESC_PTR MDMA1_D1_CURR_DESC_PTR
+#define MDMA_D1_CURR_ADDR MDMA1_D1_CURR_ADDR
+#define MDMA_D1_IRQ_STATUS MDMA1_D1_IRQ_STATUS
+#define MDMA_D1_PERIPHERAL_MAP MDMA1_D1_PERIPHERAL_MAP
+#define MDMA_D1_CURR_X_COUNT MDMA1_D1_CURR_X_COUNT
+#define MDMA_D1_CURR_Y_COUNT MDMA1_D1_CURR_Y_COUNT
+
+#define MDMA_S1_NEXT_DESC_PTR MDMA1_S1_NEXT_DESC_PTR
+#define MDMA_S1_START_ADDR MDMA1_S1_START_ADDR
+#define MDMA_S1_CONFIG MDMA1_S1_CONFIG
+#define MDMA_S1_X_COUNT MDMA1_S1_X_COUNT
+#define MDMA_S1_X_MODIFY MDMA1_S1_X_MODIFY
+#define MDMA_S1_Y_COUNT MDMA1_S1_Y_COUNT
+#define MDMA_S1_Y_MODIFY MDMA1_S1_Y_MODIFY
+#define MDMA_S1_CURR_DESC_PTR MDMA1_S1_CURR_DESC_PTR
+#define MDMA_S1_CURR_ADDR MDMA1_S1_CURR_ADDR
+#define MDMA_S1_IRQ_STATUS MDMA1_S1_IRQ_STATUS
+#define MDMA_S1_PERIPHERAL_MAP MDMA1_S1_PERIPHERAL_MAP
+#define MDMA_S1_CURR_X_COUNT MDMA1_S1_CURR_X_COUNT
+#define MDMA_S1_CURR_Y_COUNT MDMA1_S1_CURR_Y_COUNT
+
 /* Internal Memory DMA Registers (0xFFC0_1800 - 0xFFC0_19FF) */
 #define IMDMA_D0_CONFIG 0xFFC01808	/*IMDMA Stream 0 Destination Configuration */
 #define IMDMA_D0_NEXT_DESC_PTR 0xFFC01800	/*IMDMA Stream 0 Destination Next Descriptor Ptr Reg */
diff --git a/arch/blackfin/mach-bf561/smp.c b/arch/blackfin/mach-bf561/smp.c
index 9b27e69..8c10701 100644
--- a/arch/blackfin/mach-bf561/smp.c
+++ b/arch/blackfin/mach-bf561/smp.c
@@ -133,9 +133,9 @@
 	int ret;
 
 	ret = request_irq(IRQ_SUPPLE_0, handler, IRQF_DISABLED,
-			  "SMP interrupt", handler);
+			  "Supplemental Interrupt0", handler);
 	if (ret)
-		panic("Cannot request supplemental interrupt 0 for IPI service\n");
+		panic("Cannot request supplemental interrupt 0 for IPI service");
 }
 
 void platform_send_ipi(cpumask_t callmap)
diff --git a/arch/blackfin/mach-common/arch_checks.c b/arch/blackfin/mach-common/arch_checks.c
index 80d39b2..da93d92 100644
--- a/arch/blackfin/mach-common/arch_checks.c
+++ b/arch/blackfin/mach-common/arch_checks.c
@@ -71,3 +71,10 @@
 #if ANOMALY_05000448
 # error You are using a part with anomaly 05000448, this issue causes random memory read/write failures - that means random crashes.
 #endif
+
+/* if 220 exists, can not set External Memory WB and L2 not_cached, either External Memory not_cached and L2 WB */
+#if ANOMALY_05000220 && \
+	((defined(CONFIG_BFIN_WB) && defined(CONFIG_BFIN_L2_NOT_CACHED)) || \
+	 (!defined(CONFIG_BFIN_DCACHE) && defined(CONFIG_BFIN_L2_WB)))
+# error You are exposing Anomaly 220 in this config, either config L2 as Write Through, or make External Memory WB.
+#endif
diff --git a/arch/blackfin/mach-common/cache.S b/arch/blackfin/mach-common/cache.S
index aa0648c..d9666fe 100644
--- a/arch/blackfin/mach-common/cache.S
+++ b/arch/blackfin/mach-common/cache.S
@@ -15,6 +15,13 @@
 
 .text
 
+/* 05000443 - IFLUSH cannot be last instruction in hardware loop */
+#if ANOMALY_05000443
+# define BROK_FLUSH_INST "IFLUSH"
+#else
+# define BROK_FLUSH_INST "no anomaly! yeah!"
+#endif
+
 /* Since all L1 caches work the same way, we use the same method for flushing
  * them.  Only the actual flush instruction differs.  We write this in asm as
  * GCC can be hard to coax into writing nice hardware loops.
@@ -23,7 +30,7 @@
  * R0 = start address
  * R1 = end address
  */
-.macro do_flush flushins:req optflushins optnopins label
+.macro do_flush flushins:req label
 
 	R2 = -L1_CACHE_BYTES;
 
@@ -44,22 +51,15 @@
 \label :
 .endif
 	P0 = R0;
+
 	LSETUP (1f, 2f) LC1 = P1;
 1:
-.ifnb \optflushins
-	\optflushins [P0];
-.endif
-#if ANOMALY_05000443
-.ifb \optnopins
-2:
-.endif
+.ifeqs "\flushins", BROK_FLUSH_INST
 	\flushins [P0++];
-.ifnb \optnopins
-2:	\optnopins;
-.endif
-#else
+2:	nop;
+.else
 2:	\flushins [P0++];
-#endif
+.endif
 
 	RTS;
 .endm
@@ -77,25 +77,9 @@
  */
 	P0 = R0;
 	IFLUSH[P0];
-	do_flush IFLUSH, , nop
+	do_flush IFLUSH
 ENDPROC(_blackfin_icache_flush_range)
 
-/* Flush all cache lines assocoiated with this area of memory. */
-ENTRY(_blackfin_icache_dcache_flush_range)
-/*
- * Walkaround to avoid loading wrong instruction after invalidating icache
- * and following sequence is met.
- *
- * 1) One instruction address is cached in the instruction cache.
- * 2) This instruction in SDRAM is changed.
- * 3) IFLASH[P0] is executed only once in blackfin_icache_flush_range().
- * 4) This instruction is executed again, but the old one is loaded.
- */
-	P0 = R0;
-	IFLUSH[P0];
-	do_flush FLUSH, IFLUSH
-ENDPROC(_blackfin_icache_dcache_flush_range)
-
 /* Throw away all D-cached data in specified region without any obligation to
  * write them back.  Since the Blackfin ISA does not have an "invalidate"
  * instruction, we use flush/invalidate.  Perhaps as a speed optimization we
@@ -107,7 +91,7 @@
 
 /* Flush all data cache lines assocoiated with this memory area */
 ENTRY(_blackfin_dcache_flush_range)
-	do_flush FLUSH, , , .Ldfr
+	do_flush FLUSH, .Ldfr
 ENDPROC(_blackfin_dcache_flush_range)
 
 /* Our headers convert the page structure to an address, so just need to flush
diff --git a/arch/blackfin/mach-common/clocks-init.c b/arch/blackfin/mach-common/clocks-init.c
index 3539365..ef6870e 100644
--- a/arch/blackfin/mach-common/clocks-init.c
+++ b/arch/blackfin/mach-common/clocks-init.c
@@ -72,6 +72,7 @@
 #endif
 	bfin_write_PLL_LOCKCNT(0x300);
 	do_sync();
+	/* We always write PLL_CTL thus avoiding Anomaly 05000242 */
 	bfin_write16(PLL_CTL, PLL_CTL_VAL);
 	__asm__ __volatile__("IDLE;");
 	bfin_write_PLL_DIV(CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
diff --git a/arch/blackfin/mach-common/cpufreq.c b/arch/blackfin/mach-common/cpufreq.c
index 72e1660..70e3411 100644
--- a/arch/blackfin/mach-common/cpufreq.c
+++ b/arch/blackfin/mach-common/cpufreq.c
@@ -140,7 +140,8 @@
 	cclk = get_cclk() / 1000;
 	sclk = get_sclk() / 1000;
 
-#if ANOMALY_05000273 || (!defined(CONFIG_BF54x) && defined(CONFIG_BFIN_DCACHE))
+#if ANOMALY_05000273 || ANOMALY_05000274 || \
+	(!defined(CONFIG_BF54x) && defined(CONFIG_BFIN_DCACHE))
 	min_cclk = sclk * 2;
 #else
 	min_cclk = sclk;
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index a063a43..da0558a 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -36,7 +36,6 @@
 #include <linux/init.h>
 #include <linux/linkage.h>
 #include <linux/unistd.h>
-#include <linux/threads.h>
 #include <asm/blackfin.h>
 #include <asm/errno.h>
 #include <asm/fixed_code.h>
@@ -201,7 +200,18 @@
 	cc = r7 == 0;
 	if !cc jump 1f;
 #endif
-
+#ifdef CONFIG_EXACT_HWERR
+	/* Read the ILAT, and to check to see if the process we are
+	 * single stepping caused a previous hardware error
+	 * If so, do not single step, (which lowers to IRQ5, and makes
+	 * us miss the error).
+	 */
+	p5.l = lo(ILAT);
+	p5.h = hi(ILAT);
+	r7 = [p5];
+	cc = bittst(r7, EVT_IVHW_P);
+	if cc jump 1f;
+#endif
 	/* Single stepping only a single instruction, so clear the trace
 	 * bit here.  */
 	r7 = syscfg;
@@ -263,15 +273,6 @@
 	r6 = 0x25;
 	CC = R7 == R6;
 	if CC JUMP _double_fault;
-
-	/* Did we cause a HW error? */
-	p5.l = lo(ILAT);
-	p5.h = hi(ILAT);
-	r6 = [p5];
-	r7 = 0x20;		/* Did I just cause anther HW error? */
-	r6 = r7 & r6;
-	CC = R7 == R6;
-	if CC JUMP _double_fault;
 #endif
 
 	(R7:6,P5:4) = [sp++];
@@ -473,6 +474,16 @@
 	[--sp] = ASTAT;
 	[--sp] = (R7:6,P5:4);
 
+#ifdef CONFIG_EXACT_HWERR
+	/* Make sure all pending read/writes complete. This will ensure any
+	 * accesses which could cause hardware errors completes, and signal
+	 * the the hardware before we do something silly, like crash the
+	 * kernel. We don't need to work around anomaly 05000312, since
+	 * we are already atomic
+	 */
+	ssync;
+#endif
+
 #if ANOMALY_05000283 || ANOMALY_05000315
 	cc = r7 == r7;
 	p5.h = HI(CHIPID);
@@ -855,7 +866,7 @@
 	p1.h = _schedule_and_signal;
 	[p0] = p1;
 	csync;
-	raise 15;		/* raise evt14 to do signal or reschedule */
+	raise 15;		/* raise evt15 to do signal or reschedule */
 4:
 	r0 = syscfg;
 	bitclr(r0, 0);
@@ -916,7 +927,7 @@
 	p1.h = _schedule_and_signal_from_int;
 	[p0] = p1;
 	csync;
-#if ANOMALY_05000281
+#if ANOMALY_05000281 || ANOMALY_05000461
 	r0.l = lo(SAFE_USER_INSTRUCTION);
 	r0.h = hi(SAFE_USER_INSTRUCTION);
 	reti = r0;
@@ -930,18 +941,27 @@
 ENDPROC(_return_from_int)
 
 ENTRY(_lower_to_irq14)
-#if ANOMALY_05000281
+#if ANOMALY_05000281 || ANOMALY_05000461
 	r0.l = lo(SAFE_USER_INSTRUCTION);
 	r0.h = hi(SAFE_USER_INSTRUCTION);
 	reti = r0;
 #endif
-	r0 = 0x401f;
+
+#ifdef CONFIG_DEBUG_HWERR
+	/* enable irq14 & hwerr interrupt, until we transition to _evt14_softirq */
+	r0 = (EVT_IVG14 | EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
+#else
+	/* Only enable irq14 interrupt, until we transition to _evt14_softirq */
+	r0 = (EVT_IVG14 | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
+#endif
 	sti r0;
 	raise 14;
 	rti;
+ENDPROC(_lower_to_irq14)
+
 ENTRY(_evt14_softirq)
 #ifdef CONFIG_DEBUG_HWERR
-	r0 = 0x3f;
+	r0 = (EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
 	sti r0;
 #else
 	cli r0;
@@ -949,8 +969,9 @@
 	[--sp] = RETI;
 	SP += 4;
 	rts;
+ENDPROC(_evt14_softirq)
 
-_schedule_and_signal_from_int:
+ENTRY(_schedule_and_signal_from_int)
 	/* To end up here, vector 15 was changed - so we have to change it
 	 * back.
 	 */
@@ -983,8 +1004,9 @@
 	call _finish_atomic_sections;
 	sp += 12;
 	jump.s .Lresume_userspace;
+ENDPROC(_schedule_and_signal_from_int)
 
-_schedule_and_signal:
+ENTRY(_schedule_and_signal)
 	SAVE_CONTEXT_SYSCALL
 	/* To end up here, vector 15 was changed - so we have to change it
 	 * back.
@@ -1002,7 +1024,7 @@
 1:
 	RESTORE_CONTEXT
 	rti;
-ENDPROC(_lower_to_irq14)
+ENDPROC(_schedule_and_signal)
 
 /* We handle this 100% in exception space - to reduce overhead
  * Only potiential problem is if the software buffer gets swapped out of the
@@ -1588,19 +1610,3 @@
 	.long _sys_ni_syscall
 	.endr
 END(_sys_call_table)
-
-#ifdef CONFIG_EXCEPTION_L1_SCRATCH
-/* .section .l1.bss.scratch */
-.set _exception_stack_top, L1_SCRATCH_START + L1_SCRATCH_LENGTH
-#else
-#ifdef CONFIG_SYSCALL_TAB_L1
-.section .l1.bss
-#else
-.bss
-#endif
-ENTRY(_exception_stack)
-	.rept 1024 * NR_CPUS
-	.long 0
-	.endr
-_exception_stack_top:
-#endif
diff --git a/arch/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S
index 698d4c0..f826f6b 100644
--- a/arch/blackfin/mach-common/head.S
+++ b/arch/blackfin/mach-common/head.S
@@ -30,8 +30,6 @@
 	rts;
 ENDPROC(__init_clear_bss)
 
-#define INITIAL_STACK	(L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12)
-
 ENTRY(__start)
 	/* R0: argument of command line string, passed from uboot, save it */
 	R7 = R0;
@@ -126,30 +124,30 @@
 	 * below
 	 */
 	GET_PDA(p0, r0);
-	r7 = [p0 + PDA_RETX];
+	r6 = [p0 + PDA_RETX];
 	p1.l = _init_saved_retx;
 	p1.h = _init_saved_retx;
-	[p1] = r7;
+	[p1] = r6;
 
-	r7 = [p0 + PDA_DCPLB];
+	r6 = [p0 + PDA_DCPLB];
 	p1.l = _init_saved_dcplb_fault_addr;
 	p1.h = _init_saved_dcplb_fault_addr;
-	[p1] = r7;
+	[p1] = r6;
 
-	r7 = [p0 + PDA_ICPLB];
+	r6 = [p0 + PDA_ICPLB];
 	p1.l = _init_saved_icplb_fault_addr;
 	p1.h = _init_saved_icplb_fault_addr;
-	[p1] = r7;
+	[p1] = r6;
 
-	r7 = [p0 + PDA_SEQSTAT];
+	r6 = [p0 + PDA_SEQSTAT];
 	p1.l = _init_saved_seqstat;
 	p1.h = _init_saved_seqstat;
-	[p1] = r7;
+	[p1] = r6;
 #endif
 
 	/* Initialize stack pointer */
-	sp.l = lo(INITIAL_STACK);
-	sp.h = hi(INITIAL_STACK);
+	sp.l = _init_thread_union;
+	sp.h = _init_thread_union;
 	fp = sp;
 	usp = sp;
 
@@ -189,7 +187,15 @@
 	/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
 	call _bfin_relocate_l1_mem;
 #ifdef CONFIG_BFIN_KERNEL_CLOCK
+	/* Only use on-chip scratch space for stack when absolutely required
+	 * to avoid Anomaly 05000227 ... we know the init_clocks() func only
+	 * uses L1 text and stack space and no other memory region.
+	 */
+# define KERNEL_CLOCK_STACK (L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12)
+	sp.l = lo(KERNEL_CLOCK_STACK);
+	sp.h = hi(KERNEL_CLOCK_STACK);
 	call _init_clocks;
+	sp = usp;	/* usp hasnt been touched, so restore from there */
 #endif
 
 	/* This section keeps the processor in supervisor mode
@@ -243,9 +249,7 @@
 	call _cmdline_init;
 
 	/* Load the current thread pointer and stack */
-	sp.l = _init_thread_union;
-	sp.h = _init_thread_union;
-	p1 = THREAD_SIZE (z);
+	p1 = THREAD_SIZE + 4 (z);	/* +4 is for reti loading */
 	sp = sp + p1;
 	usp = sp;
 	fp = sp;
diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S
index 0069c2d..9c46680 100644
--- a/arch/blackfin/mach-common/interrupt.S
+++ b/arch/blackfin/mach-common/interrupt.S
@@ -145,6 +145,14 @@
 
 /* interrupt routine for ivhw - 5 */
 ENTRY(_evt_ivhw)
+	/* In case a single action kicks off multiple memory transactions, (like
+	 * a cache line fetch, - this can cause multiple hardware errors, let's
+	 * catch them all. First - make sure all the actions are complete, and
+	 * the core sees the hardware errors.
+	 */
+	SSYNC;
+	SSYNC;
+
 	SAVE_ALL_SYS
 #ifdef CONFIG_FRAME_POINTER
 	fp = 0;
@@ -159,6 +167,25 @@
 1:
 #endif
 
+	/* Handle all stacked hardware errors
+	 * To make sure we don't hang forever, only do it 10 times
+	 */
+	R0 = 0;
+	R2 = 10;
+1:
+	P0.L = LO(ILAT);
+	P0.H = HI(ILAT);
+	R1 = [P0];
+	CC = BITTST(R1, EVT_IVHW_P);
+	IF ! CC JUMP 2f;
+	/* OK a hardware error is pending - clear it */
+	R1 = EVT_IVHW_P;
+	[P0] = R1;
+	R0 += 1;
+	CC = R1 == R2;
+	if CC JUMP 2f;
+	JUMP 1b;
+2:
 	# We are going to dump something out, so make sure we print IPEND properly
 	p2.l = lo(IPEND);
 	p2.h = hi(IPEND);
diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c
index a7d7b2d..351afd0 100644
--- a/arch/blackfin/mach-common/ints-priority.c
+++ b/arch/blackfin/mach-common/ints-priority.c
@@ -1052,7 +1052,7 @@
 			set_irq_chained_handler(irq, bfin_demux_error_irq);
 			break;
 #endif
-#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
+#if defined(CONFIG_TICKSOURCE_GPTMR0)
 		case IRQ_TIMER0:
 			set_irq_handler(irq, handle_percpu_irq);
 			break;
@@ -1116,6 +1116,9 @@
 	    IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
 	    IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
 
+	/* This implicitly covers ANOMALY_05000171
+	 * Boot-ROM code modifies SICA_IWRx wakeup registers
+	 */
 #ifdef SIC_IWR0
 	bfin_write_SIC_IWR0(IWR_DISABLE_ALL);
 # ifdef SIC_IWR1
@@ -1136,13 +1139,6 @@
 	bfin_write_SIC_IWR(IWR_DISABLE_ALL);
 #endif
 
-#ifdef CONFIG_IPIPE
-	for (irq = 0; irq < NR_IRQS; irq++) {
-		struct irq_desc *desc = irq_to_desc(irq);
-		desc->ic_prio = __ipipe_get_irq_priority(irq);
-	}
-#endif /* CONFIG_IPIPE */
-
 	return 0;
 }
 
@@ -1156,23 +1152,22 @@
 	} else {
 		struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
 		struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) \
-	|| defined(BF538_FAMILY) || defined(CONFIG_BF51x)
+#if defined(SIC_ISR0) || defined(SICA_ISR0)
 		unsigned long sic_status[3];
 
 		if (smp_processor_id()) {
-#ifdef CONFIG_SMP
+# ifdef SICB_ISR0
 			/* This will be optimized out in UP mode. */
 			sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
 			sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
-#endif
+# endif
 		} else {
 			sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
 			sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
 		}
-#ifdef CONFIG_BF54x
+# ifdef SIC_ISR2
 		sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
-#endif
+# endif
 		for (;; ivg++) {
 			if (ivg >= ivg_stop) {
 				atomic_inc(&num_spurious);
@@ -1236,20 +1231,16 @@
 
 	if (likely(vec == EVT_IVTMR_P)) {
 		irq = IRQ_CORETMR;
-		goto core_tick;
-	}
 
-	SSYNC();
-
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
-	{
+	} else {
+#if defined(SIC_ISR0) || defined(SICA_ISR0)
 		unsigned long sic_status[3];
 
 		sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
 		sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
-#ifdef CONFIG_BF54x
+# ifdef SIC_ISR2
 		sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
-#endif
+# endif
 		for (;; ivg++) {
 			if (ivg >= ivg_stop) {
 				atomic_inc(&num_spurious);
@@ -1258,9 +1249,7 @@
 			if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
 				break;
 		}
-	}
 #else
-	{
 		unsigned long sic_status;
 
 		sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
@@ -1272,15 +1261,13 @@
 			} else if (sic_status & ivg->isrflag)
 				break;
 		}
-	}
 #endif
 
-	irq = ivg->irqno;
+		irq = ivg->irqno;
+	}
 
 	if (irq == IRQ_SYSTMR) {
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-core_tick:
-#else
+#ifndef CONFIG_GENERIC_CLOCKEVENTS
 		bfin_write_TIMER_STATUS(1); /* Latch TIMIL0 */
 #endif
 		/* This is basically what we need from the register frame. */
@@ -1292,9 +1279,6 @@
 			__raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10;
 	}
 
-#ifndef CONFIG_GENERIC_CLOCKEVENTS
-core_tick:
-#endif
 	if (this_domain == ipipe_root_domain) {
 		s = __test_and_set_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
 		barrier();
@@ -1312,7 +1296,7 @@
 		}
 	}
 
-       return 0;
+	return 0;
 }
 
 #endif /* CONFIG_IPIPE */
diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c
index 93eab61..3b8ebae 100644
--- a/arch/blackfin/mach-common/smp.c
+++ b/arch/blackfin/mach-common/smp.c
@@ -43,8 +43,13 @@
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/cpu.h>
+#include <asm/time.h>
 #include <linux/err.h>
 
+/*
+ * Anomaly notes:
+ * 05000120 - we always define corelock as 32-bit integer in L2
+ */
 struct corelock_slot corelock __attribute__ ((__section__(".l2.bss")));
 
 void __cpuinitdata *init_retx_coreb, *init_saved_retx_coreb,
@@ -352,7 +357,7 @@
 
 static void __cpuinit setup_secondary(unsigned int cpu)
 {
-#if !(defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE))
+#if !defined(CONFIG_TICKSOURCE_GPTMR0)
 	struct irq_desc *timer_desc;
 #endif
 	unsigned long ilat;
@@ -364,16 +369,13 @@
 	bfin_write_ILAT(ilat);
 	CSYNC();
 
-	/* Reserve the PDA space for the secondary CPU. */
-	reserve_pda();
-
 	/* Enable interrupt levels IVG7-15. IARs have been already
 	 * programmed by the boot CPU.  */
 	bfin_irq_flags |= IMASK_IVG15 |
 	    IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
 	    IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
 
-#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
+#if defined(CONFIG_TICKSOURCE_GPTMR0)
 	/* Power down the core timer, just to play safe. */
 	bfin_write_TCNTL(0);
 
diff --git a/arch/blackfin/mm/blackfin_sram.h b/arch/blackfin/mm/blackfin_sram.h
index 8cb0945..bc00628 100644
--- a/arch/blackfin/mm/blackfin_sram.h
+++ b/arch/blackfin/mm/blackfin_sram.h
@@ -30,7 +30,6 @@
 #ifndef __BLACKFIN_SRAM_H__
 #define __BLACKFIN_SRAM_H__
 
-extern void bfin_sram_init(void);
 extern void *l1sram_alloc(size_t);
 
 #endif
diff --git a/arch/blackfin/mm/init.c b/arch/blackfin/mm/init.c
index 9c3629b..014a55a 100644
--- a/arch/blackfin/mm/init.c
+++ b/arch/blackfin/mm/init.c
@@ -52,9 +52,14 @@
 
 static unsigned long empty_bad_page;
 
-unsigned long empty_zero_page;
+static unsigned long empty_zero_page;
 
-extern unsigned long exception_stack[NR_CPUS][1024];
+#ifndef CONFIG_EXCEPTION_L1_SCRATCH
+#if defined CONFIG_SYSCALL_TAB_L1
+__attribute__((l1_data))
+#endif
+static unsigned long exception_stack[NR_CPUS][1024];
+#endif
 
 struct blackfin_pda cpu_pda[NR_CPUS];
 EXPORT_SYMBOL(cpu_pda);
@@ -117,19 +122,18 @@
 	cpu_pda[0].next = &cpu_pda[1];
 	cpu_pda[1].next = &cpu_pda[0];
 
+#ifdef CONFIG_EXCEPTION_L1_SCRATCH
+	cpu_pda[cpu].ex_stack = (unsigned long *)(L1_SCRATCH_START + \
+					L1_SCRATCH_LENGTH);
+#else
 	cpu_pda[cpu].ex_stack = exception_stack[cpu + 1];
+#endif
 
 #ifdef CONFIG_SMP
 	cpu_pda[cpu].imask = 0x1f;
 #endif
 }
 
-void __cpuinit reserve_pda(void)
-{
-	printk(KERN_INFO "PDA for CPU%u reserved at %p\n", smp_processor_id(),
-					&cpu_pda[smp_processor_id()]);
-}
-
 void __init mem_init(void)
 {
 	unsigned int codek = 0, datak = 0, initk = 0;
@@ -171,19 +175,6 @@
 		initk, codek, datak, DMA_UNCACHED_REGION >> 10, (reservedpages << (PAGE_SHIFT-10)));
 }
 
-static int __init sram_init(void)
-{
-	/* Initialize the blackfin L1 Memory. */
-	bfin_sram_init();
-
-	/* Reserve the PDA space for the boot CPU right after we
-	 * initialized the scratch memory allocator.
-	 */
-	reserve_pda();
-	return 0;
-}
-pure_initcall(sram_init);
-
 static void __init free_init_pages(const char *what, unsigned long begin, unsigned long end)
 {
 	unsigned long addr;
diff --git a/arch/blackfin/mm/isram-driver.c b/arch/blackfin/mm/isram-driver.c
index 22913e7..c080e70 100644
--- a/arch/blackfin/mm/isram-driver.c
+++ b/arch/blackfin/mm/isram-driver.c
@@ -125,7 +125,7 @@
 {
 	if ((addr >= (void *)L1_CODE_START) &&
 	    (addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))) {
-		if ((addr + n) >= (void *)(L1_CODE_START + L1_CODE_LENGTH)) {
+		if ((addr + n) > (void *)(L1_CODE_START + L1_CODE_LENGTH)) {
 			show_stack(NULL, NULL);
 			printk(KERN_ERR "isram_memcpy: copy involving %p length "
 					"(%zu) too long\n", addr, n);
diff --git a/arch/blackfin/mm/sram-alloc.c b/arch/blackfin/mm/sram-alloc.c
index 530d139..0bc3c4e 100644
--- a/arch/blackfin/mm/sram-alloc.c
+++ b/arch/blackfin/mm/sram-alloc.c
@@ -83,6 +83,14 @@
 static void __init l1sram_init(void)
 {
 	unsigned int cpu;
+	unsigned long reserve;
+
+#ifdef CONFIG_SMP
+	reserve = 0;
+#else
+	reserve = sizeof(struct l1_scratch_task_info);
+#endif
+
 	for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
 		per_cpu(free_l1_ssram_head, cpu).next =
 			kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
@@ -91,8 +99,8 @@
 			return;
 		}
 
-		per_cpu(free_l1_ssram_head, cpu).next->paddr = (void *)get_l1_scratch_start_cpu(cpu);
-		per_cpu(free_l1_ssram_head, cpu).next->size = L1_SCRATCH_LENGTH;
+		per_cpu(free_l1_ssram_head, cpu).next->paddr = (void *)get_l1_scratch_start_cpu(cpu) + reserve;
+		per_cpu(free_l1_ssram_head, cpu).next->size = L1_SCRATCH_LENGTH - reserve;
 		per_cpu(free_l1_ssram_head, cpu).next->pid = 0;
 		per_cpu(free_l1_ssram_head, cpu).next->next = NULL;
 
@@ -223,7 +231,7 @@
 	spin_lock_init(&l2_sram_lock);
 }
 
-void __init bfin_sram_init(void)
+static int __init bfin_sram_init(void)
 {
 	sram_piece_cache = kmem_cache_create("sram_piece_cache",
 				sizeof(struct sram_piece),
@@ -233,7 +241,10 @@
 	l1_data_sram_init();
 	l1_inst_sram_init();
 	l2_sram_init();
+
+	return 0;
 }
+pure_initcall(bfin_sram_init);
 
 /* SRAM allocate function */
 static void *_sram_alloc(size_t size, struct sram_piece *pfree_head,
@@ -732,6 +743,10 @@
 }
 EXPORT_SYMBOL(sram_free_with_lsl);
 
+/* Allocate memory and keep in L1 SRAM List (lsl) so that the resources are
+ * tracked.  These are designed for userspace so that when a process exits,
+ * we can safely reap their resources.
+ */
 void *sram_alloc_with_lsl(size_t size, unsigned long flags)
 {
 	void *addr = NULL;
diff --git a/arch/cris/include/asm/atomic.h b/arch/cris/include/asm/atomic.h
index 5718dd8..a6aca81 100644
--- a/arch/cris/include/asm/atomic.h
+++ b/arch/cris/include/asm/atomic.h
@@ -158,5 +158,5 @@
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc()     barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif
diff --git a/arch/cris/include/asm/bitsperlong.h b/arch/cris/include/asm/bitsperlong.h
new file mode 100644
index 0000000..6dc0bb0
--- /dev/null
+++ b/arch/cris/include/asm/bitsperlong.h
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
diff --git a/arch/cris/include/asm/mman.h b/arch/cris/include/asm/mman.h
index 1c35e1b..b7f0afb 100644
--- a/arch/cris/include/asm/mman.h
+++ b/arch/cris/include/asm/mman.h
@@ -3,7 +3,7 @@
 
 /* verbatim copy of asm-i386/ version */
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
diff --git a/arch/cris/include/asm/page.h b/arch/cris/include/asm/page.h
index f3fdbd0..be45ee3 100644
--- a/arch/cris/include/asm/page.h
+++ b/arch/cris/include/asm/page.h
@@ -68,7 +68,7 @@
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _CRIS_PAGE_H */
 
diff --git a/arch/cris/include/asm/signal.h b/arch/cris/include/asm/signal.h
index 349ae68..ea6af9a 100644
--- a/arch/cris/include/asm/signal.h
+++ b/arch/cris/include/asm/signal.h
@@ -106,7 +106,7 @@
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/arch/cris/kernel/module.c b/arch/cris/kernel/module.c
index a187833..abc13e3 100644
--- a/arch/cris/kernel/module.c
+++ b/arch/cris/kernel/module.c
@@ -48,8 +48,6 @@
 void module_free(struct module *mod, void *module_region)
 {
 	FREE_MODULE(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-	   table entries. */
 }
 
 /* We don't need anything special. */
diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h
index 296c35c..0409d98 100644
--- a/arch/frv/include/asm/atomic.h
+++ b/arch/frv/include/asm/atomic.h
@@ -194,5 +194,5 @@
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* _ASM_ATOMIC_H */
diff --git a/arch/frv/include/asm/bitsperlong.h b/arch/frv/include/asm/bitsperlong.h
new file mode 100644
index 0000000..6dc0bb0
--- /dev/null
+++ b/arch/frv/include/asm/bitsperlong.h
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
diff --git a/arch/frv/include/asm/mman.h b/arch/frv/include/asm/mman.h
index b4371e9..58c1d11 100644
--- a/arch/frv/include/asm/mman.h
+++ b/arch/frv/include/asm/mman.h
@@ -1,7 +1,7 @@
 #ifndef __ASM_MMAN_H__
 #define __ASM_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
diff --git a/arch/frv/include/asm/page.h b/arch/frv/include/asm/page.h
index bd9c220..25c6a50 100644
--- a/arch/frv/include/asm/page.h
+++ b/arch/frv/include/asm/page.h
@@ -73,6 +73,6 @@
 #endif /* __ASSEMBLY__ */
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _ASM_PAGE_H */
diff --git a/arch/frv/include/asm/pci.h b/arch/frv/include/asm/pci.h
index cc685e6..492b5c4 100644
--- a/arch/frv/include/asm/pci.h
+++ b/arch/frv/include/asm/pci.h
@@ -10,8 +10,8 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#ifndef ASM_PCI_H
-#define	ASM_PCI_H
+#ifndef _ASM_FRV_PCI_H
+#define _ASM_FRV_PCI_H
 
 #include <linux/mm.h>
 #include <asm/scatterlist.h>
@@ -43,12 +43,6 @@
 /* Return the index of the PCI controller for device PDEV. */
 #define pci_controller_num(PDEV)	(0)
 
-/* The PCI address space does equal the physical memory
- * address space.  The networking and block device layers use
- * this boolean for bounce buffer decisions.
- */
-#define PCI_DMA_BUS_IS_PHYS	(1)
-
 /* pci_unmap_{page,single} is a nop so... */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
@@ -111,5 +105,4 @@
 				    sg_dma_address(&sg[i])+sg_dma_len(&sg[i]));
 }
 
-
-#endif
+#endif /* _ASM_FRV_PCI_H */
diff --git a/arch/frv/include/asm/signal.h b/arch/frv/include/asm/signal.h
index 2079197..f071e81 100644
--- a/arch/frv/include/asm/signal.h
+++ b/arch/frv/include/asm/signal.h
@@ -3,107 +3,15 @@
 
 #include <linux/types.h>
 
-/* Avoid too many header ordering problems.  */
-struct siginfo;
-
-#ifdef __KERNEL__
-/* Most things should be clean enough to redefine this at will, if care
-   is taken to make libc match.  */
-
-#define _NSIG		64
-#define _NSIG_BPW	32
-#define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
-
-typedef unsigned long old_sigset_t;		/* at least 32 bits */
-
-typedef struct {
-	unsigned long sig[_NSIG_WORDS];
-} sigset_t;
-
-#else
+#ifndef __KERNEL__
 /* Here we must cater to libcs that poke about in kernel headers.  */
 
 #define NSIG		32
 typedef unsigned long sigset_t;
 
-#endif /* __KERNEL__ */
+#endif /* !__KERNEL__ */
 
-#define SIGHUP		 1
-#define SIGINT		 2
-#define SIGQUIT		 3
-#define SIGILL		 4
-#define SIGTRAP		 5
-#define SIGABRT		 6
-#define SIGIOT		 6
-#define SIGBUS		 7
-#define SIGFPE		 8
-#define SIGKILL		 9
-#define SIGUSR1		10
-#define SIGSEGV		11
-#define SIGUSR2		12
-#define SIGPIPE		13
-#define SIGALRM		14
-#define SIGTERM		15
-#define SIGSTKFLT	16
-#define SIGCHLD		17
-#define SIGCONT		18
-#define SIGSTOP		19
-#define SIGTSTP		20
-#define SIGTTIN		21
-#define SIGTTOU		22
-#define SIGURG		23
-#define SIGXCPU		24
-#define SIGXFSZ		25
-#define SIGVTALRM	26
-#define SIGPROF		27
-#define SIGWINCH	28
-#define SIGIO		29
-#define SIGPOLL		SIGIO
-/*
-#define SIGLOST		29
-*/
-#define SIGPWR		30
-#define SIGSYS		31
-#define	SIGUNUSED	31
-
-/* These should not be considered constants from userland.  */
-#define SIGRTMIN	32
-#define SIGRTMAX	(_NSIG-1)
-
-/*
- * SA_FLAGS values:
- *
- * SA_ONSTACK indicates that a registered stack_t will be used.
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
- * SA_RESETHAND clears the handler when the signal is delivered.
- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
- * SA_NODEFER prevents the current signal from being masked in the handler.
- *
- * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
- * Unix names RESETHAND and NODEFER respectively.
- */
-#define SA_NOCLDSTOP	0x00000001
-#define SA_NOCLDWAIT	0x00000002 /* not supported yet */
-#define SA_SIGINFO	0x00000004
-#define SA_ONSTACK	0x08000000
-#define SA_RESTART	0x10000000
-#define SA_NODEFER	0x40000000
-#define SA_RESETHAND	0x80000000
-
-#define SA_NOMASK	SA_NODEFER
-#define SA_ONESHOT	SA_RESETHAND
-
-#define SA_RESTORER	0x04000000
-
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK	1
-#define SS_DISABLE	2
-
-#define MINSIGSTKSZ	2048
-#define SIGSTKSZ	8192
+#define SA_RESTORER	0x04000000 /* to get struct sigaction correct */
 
 #include <asm-generic/signal.h>
 
@@ -115,16 +23,6 @@
 	__sigrestore_t sa_restorer;
 };
 
-struct sigaction {
-	__sighandler_t sa_handler;
-	unsigned long sa_flags;
-	__sigrestore_t sa_restorer;
-	sigset_t sa_mask;		/* mask last for extensibility */
-};
-
-struct k_sigaction {
-	struct sigaction sa;
-};
 #else
 /* Here we must cater to libcs that poke about in kernel headers.  */
 
@@ -143,19 +41,4 @@
 
 #endif /* __KERNEL__ */
 
-typedef struct sigaltstack {
-	void __user *ss_sp;
-	int ss_flags;
-	size_t ss_size;
-} stack_t;
-
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-
-#ifdef __KERNEL__
-
-#include <asm/sigcontext.h>
-#undef __HAVE_ARCH_SIG_BITOPS
-
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_SIGNAL_H */
diff --git a/arch/frv/include/asm/termios.h b/arch/frv/include/asm/termios.h
index a62fb58..b4868aa 100644
--- a/arch/frv/include/asm/termios.h
+++ b/arch/frv/include/asm/termios.h
@@ -52,7 +52,7 @@
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
 #ifdef __KERNEL__
-#include <asm-generic/termios.h>
+#include <asm-generic/termios-base.h>
 #endif
 
 #endif /* _ASM_TERMIOS_H */
diff --git a/arch/frv/kernel/module.c b/arch/frv/kernel/module.c
index 850d168..711763c 100644
--- a/arch/frv/kernel/module.c
+++ b/arch/frv/kernel/module.c
@@ -35,8 +35,6 @@
 void module_free(struct module *mod, void *module_region)
 {
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
diff --git a/arch/h8300/include/asm/atomic.h b/arch/h8300/include/asm/atomic.h
index 833186c..33c8c0f 100644
--- a/arch/h8300/include/asm/atomic.h
+++ b/arch/h8300/include/asm/atomic.h
@@ -141,5 +141,5 @@
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc() barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* __ARCH_H8300_ATOMIC __ */
diff --git a/arch/h8300/include/asm/bitsperlong.h b/arch/h8300/include/asm/bitsperlong.h
new file mode 100644
index 0000000..6dc0bb0
--- /dev/null
+++ b/arch/h8300/include/asm/bitsperlong.h
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
diff --git a/arch/h8300/include/asm/mman.h b/arch/h8300/include/asm/mman.h
index b9f104f..cf35f0a 100644
--- a/arch/h8300/include/asm/mman.h
+++ b/arch/h8300/include/asm/mman.h
@@ -1,7 +1,7 @@
 #ifndef __H8300_MMAN_H__
 #define __H8300_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
diff --git a/arch/h8300/include/asm/page.h b/arch/h8300/include/asm/page.h
index 0b6acf0..837381a 100644
--- a/arch/h8300/include/asm/page.h
+++ b/arch/h8300/include/asm/page.h
@@ -73,6 +73,6 @@
 #endif /* __ASSEMBLY__ */
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _H8300_PAGE_H */
diff --git a/arch/h8300/include/asm/signal.h b/arch/h8300/include/asm/signal.h
index 7bc1504..fd8b66e 100644
--- a/arch/h8300/include/asm/signal.h
+++ b/arch/h8300/include/asm/signal.h
@@ -105,7 +105,7 @@
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/arch/h8300/kernel/module.c b/arch/h8300/kernel/module.c
index cfc9127..0865e29 100644
--- a/arch/h8300/kernel/module.c
+++ b/arch/h8300/kernel/module.c
@@ -23,8 +23,6 @@
 void module_free(struct module *mod, void *module_region)
 {
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h
index d37292b..88405cb 100644
--- a/arch/ia64/include/asm/atomic.h
+++ b/arch/ia64/include/asm/atomic.h
@@ -216,5 +216,5 @@
 #define smp_mb__before_atomic_inc()	barrier()
 #define smp_mb__after_atomic_inc()	barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* _ASM_IA64_ATOMIC_H */
diff --git a/arch/ia64/include/asm/bitsperlong.h b/arch/ia64/include/asm/bitsperlong.h
new file mode 100644
index 0000000..ec4db3c
--- /dev/null
+++ b/arch/ia64/include/asm/bitsperlong.h
@@ -0,0 +1,8 @@
+#ifndef __ASM_IA64_BITSPERLONG_H
+#define __ASM_IA64_BITSPERLONG_H
+
+#define __BITS_PER_LONG 64
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_IA64_BITSPERLONG_H */
diff --git a/arch/ia64/include/asm/mman.h b/arch/ia64/include/asm/mman.h
index c73b878..48cf8b9 100644
--- a/arch/ia64/include/asm/mman.h
+++ b/arch/ia64/include/asm/mman.h
@@ -8,7 +8,7 @@
  *	David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
  */
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN	0x00100		/* stack-like segment */
 #define MAP_GROWSUP	0x00200		/* register stack-like segment */
diff --git a/arch/ia64/include/asm/signal.h b/arch/ia64/include/asm/signal.h
index 4f5ca56..b166248 100644
--- a/arch/ia64/include/asm/signal.h
+++ b/arch/ia64/include/asm/signal.h
@@ -114,7 +114,7 @@
 
 #endif /* __KERNEL__ */
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 # ifndef __ASSEMBLY__
 
diff --git a/arch/ia64/include/asm/suspend.h b/arch/ia64/include/asm/suspend.h
deleted file mode 100644
index b05bbb6..0000000
--- a/arch/ia64/include/asm/suspend.h
+++ /dev/null
@@ -1 +0,0 @@
-/* dummy (must be non-empty to prevent prejudicial removal...) */
diff --git a/arch/ia64/include/asm/types.h b/arch/ia64/include/asm/types.h
index e36b371..fbf1ed3 100644
--- a/arch/ia64/include/asm/types.h
+++ b/arch/ia64/include/asm/types.h
@@ -19,10 +19,6 @@
 # define __IA64_UL(x)		(x)
 # define __IA64_UL_CONST(x)	x
 
-# ifdef __KERNEL__
-#  define BITS_PER_LONG 64
-# endif
-
 #else
 # define __IA64_UL(x)		((unsigned long)(x))
 # define __IA64_UL_CONST(x)	x##UL
@@ -34,10 +30,7 @@
  */
 # ifdef __KERNEL__
 
-#define BITS_PER_LONG 64
-
 /* DMA addresses are 64-bits wide, in general.  */
-
 typedef u64 dma_addr_t;
 
 # endif /* __KERNEL__ */
diff --git a/arch/ia64/mm/extable.c b/arch/ia64/mm/extable.c
index 71c50dd..e95d5ad 100644
--- a/arch/ia64/mm/extable.c
+++ b/arch/ia64/mm/extable.c
@@ -53,6 +53,32 @@
 	     cmp_ex, swap_ex);
 }
 
+static inline unsigned long ex_to_addr(const struct exception_table_entry *x)
+{
+	return (unsigned long)&x->insn + x->insn;
+}
+
+#ifdef CONFIG_MODULES
+/*
+ * Any entry referring to the module init will be at the beginning or
+ * the end.
+ */
+void trim_init_extable(struct module *m)
+{
+	/*trim the beginning*/
+	while (m->num_exentries &&
+	       within_module_init(ex_to_addr(&m->extable[0]), m)) {
+		m->extable++;
+		m->num_exentries--;
+	}
+	/*trim the end*/
+	while (m->num_exentries &&
+	       within_module_init(ex_to_addr(&m->extable[m->num_exentries-1]),
+				  m))
+		m->num_exentries--;
+}
+#endif /* CONFIG_MODULES */
+
 const struct exception_table_entry *
 search_extable (const struct exception_table_entry *first,
 		const struct exception_table_entry *last,
diff --git a/arch/m32r/include/asm/atomic.h b/arch/m32r/include/asm/atomic.h
index 2eed30f..63f0cf0 100644
--- a/arch/m32r/include/asm/atomic.h
+++ b/arch/m32r/include/asm/atomic.h
@@ -314,5 +314,5 @@
 #define smp_mb__before_atomic_inc()	barrier()
 #define smp_mb__after_atomic_inc()	barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif	/* _ASM_M32R_ATOMIC_H */
diff --git a/arch/m32r/include/asm/bitsperlong.h b/arch/m32r/include/asm/bitsperlong.h
new file mode 100644
index 0000000..6dc0bb0
--- /dev/null
+++ b/arch/m32r/include/asm/bitsperlong.h
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
diff --git a/arch/m32r/include/asm/mman.h b/arch/m32r/include/asm/mman.h
index 516a897..04a5f40 100644
--- a/arch/m32r/include/asm/mman.h
+++ b/arch/m32r/include/asm/mman.h
@@ -1,7 +1,7 @@
 #ifndef __M32R_MMAN_H__
 #define __M32R_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
diff --git a/arch/m32r/include/asm/page.h b/arch/m32r/include/asm/page.h
index c933308..11777f7 100644
--- a/arch/m32r/include/asm/page.h
+++ b/arch/m32r/include/asm/page.h
@@ -82,6 +82,6 @@
 #define devmem_is_allowed(x) 1
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _ASM_M32R_PAGE_H */
diff --git a/arch/m32r/include/asm/pci.h b/arch/m32r/include/asm/pci.h
index fe785d1..07d3834 100644
--- a/arch/m32r/include/asm/pci.h
+++ b/arch/m32r/include/asm/pci.h
@@ -3,6 +3,4 @@
 
 #include <asm-generic/pci.h>
 
-#define PCI_DMA_BUS_IS_PHYS	(1)
-
 #endif /* _ASM_M32R_PCI_H */
diff --git a/arch/m32r/include/asm/signal.h b/arch/m32r/include/asm/signal.h
index 1a60706..9c1acb2 100644
--- a/arch/m32r/include/asm/signal.h
+++ b/arch/m32r/include/asm/signal.h
@@ -107,7 +107,7 @@
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/arch/m32r/kernel/module.c b/arch/m32r/kernel/module.c
index 8d42057..cb5f37d 100644
--- a/arch/m32r/kernel/module.c
+++ b/arch/m32r/kernel/module.c
@@ -44,8 +44,6 @@
 void module_free(struct module *mod, void *module_region)
 {
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
diff --git a/arch/m68k/include/asm/atomic_mm.h b/arch/m68k/include/asm/atomic_mm.h
index eb0ab9d..88b7af2 100644
--- a/arch/m68k/include/asm/atomic_mm.h
+++ b/arch/m68k/include/asm/atomic_mm.h
@@ -192,5 +192,5 @@
 #define smp_mb__before_atomic_inc()	barrier()
 #define smp_mb__after_atomic_inc()	barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* __ARCH_M68K_ATOMIC __ */
diff --git a/arch/m68k/include/asm/atomic_no.h b/arch/m68k/include/asm/atomic_no.h
index 6bb6748..5674cb9 100644
--- a/arch/m68k/include/asm/atomic_no.h
+++ b/arch/m68k/include/asm/atomic_no.h
@@ -151,5 +151,5 @@
 #define atomic_dec_return(v) atomic_sub_return(1,(v))
 #define atomic_inc_return(v) atomic_add_return(1,(v))
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* __ARCH_M68KNOMMU_ATOMIC __ */
diff --git a/arch/m68k/include/asm/bitsperlong.h b/arch/m68k/include/asm/bitsperlong.h
new file mode 100644
index 0000000..6dc0bb0
--- /dev/null
+++ b/arch/m68k/include/asm/bitsperlong.h
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
diff --git a/arch/m68k/include/asm/mman.h b/arch/m68k/include/asm/mman.h
index 1626d37..9f5c4c4 100644
--- a/arch/m68k/include/asm/mman.h
+++ b/arch/m68k/include/asm/mman.h
@@ -1,7 +1,7 @@
 #ifndef __M68K_MMAN_H__
 #define __M68K_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
diff --git a/arch/m68k/include/asm/page_mm.h b/arch/m68k/include/asm/page_mm.h
index a34b8ba..d009f3e 100644
--- a/arch/m68k/include/asm/page_mm.h
+++ b/arch/m68k/include/asm/page_mm.h
@@ -223,6 +223,6 @@
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _M68K_PAGE_H */
diff --git a/arch/m68k/include/asm/page_no.h b/arch/m68k/include/asm/page_no.h
index 3a1ede4..9aa3f90 100644
--- a/arch/m68k/include/asm/page_no.h
+++ b/arch/m68k/include/asm/page_no.h
@@ -72,6 +72,6 @@
 
 #endif /* __ASSEMBLY__ */
 
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _M68KNOMMU_PAGE_H */
diff --git a/arch/m68k/include/asm/signal.h b/arch/m68k/include/asm/signal.h
index 08788fd..5bc09c7 100644
--- a/arch/m68k/include/asm/signal.h
+++ b/arch/m68k/include/asm/signal.h
@@ -103,7 +103,7 @@
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/arch/m68k/include/asm/suspend.h b/arch/m68k/include/asm/suspend.h
deleted file mode 100644
index 57b3ddb..0000000
--- a/arch/m68k/include/asm/suspend.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_SUSPEND_H
-#define _M68K_SUSPEND_H
-
-/* Dummy include. */
-
-#endif  /* _M68K_SUSPEND_H */
diff --git a/arch/m68k/kernel/module.c b/arch/m68k/kernel/module.c
index 774862b..cd6bcb1 100644
--- a/arch/m68k/kernel/module.c
+++ b/arch/m68k/kernel/module.c
@@ -31,8 +31,6 @@
 void module_free(struct module *mod, void *module_region)
 {
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
diff --git a/arch/m68knommu/kernel/module.c b/arch/m68knommu/kernel/module.c
index 3b1a2ff..d11ffae 100644
--- a/arch/m68knommu/kernel/module.c
+++ b/arch/m68knommu/kernel/module.c
@@ -23,8 +23,6 @@
 void module_free(struct module *mod, void *module_region)
 {
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 8cc312b..b50b845 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -6,6 +6,7 @@
 config MICROBLAZE
 	def_bool y
 	select HAVE_LMB
+	select ARCH_WANT_OPTIONAL_GPIOLIB
 
 config SWAP
 	def_bool n
@@ -49,13 +50,14 @@
 config GENERIC_HARDIRQS_NO__DO_IRQ
 	def_bool y
 
+config GENERIC_GPIO
+	def_bool y
+
 config PCI
-	depends on !MMU
 	def_bool n
 
 config NO_DMA
-	depends on !MMU
-	def_bool n
+	def_bool y
 
 source "init/Kconfig"
 
@@ -72,7 +74,8 @@
 source "kernel/Kconfig.hz"
 
 config MMU
-	def_bool n
+	bool "MMU support"
+	default n
 
 config NO_MMU
 	bool
@@ -105,9 +108,6 @@
 config OF
 	def_bool y
 
-config OF_DEVICE
-	def_bool y
-
 config PROC_DEVICETREE
 	bool "Support for device tree in /proc"
 	depends on PROC_FS
@@ -118,6 +118,113 @@
 
 endmenu
 
+menu "Advanced setup"
+
+config ADVANCED_OPTIONS
+	bool "Prompt for advanced kernel configuration options"
+	depends on MMU
+	help
+	  This option will enable prompting for a variety of advanced kernel
+	  configuration options.  These options can cause the kernel to not
+	  work if they are set incorrectly, but can be used to optimize certain
+	  aspects of kernel memory management.
+
+	  Unless you know what you are doing, say N here.
+
+comment "Default settings for advanced configuration options are used"
+	depends on !ADVANCED_OPTIONS
+
+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
+	depends on MMU
+	default "0xfe000000"
+
+config LOWMEM_SIZE_BOOL
+	bool "Set maximum low memory"
+	depends on ADVANCED_OPTIONS
+	help
+	  This option allows you to set the maximum amount of memory which
+	  will be used as "low memory", that is, memory which the kernel can
+	  access directly, without having to set up a kernel virtual mapping.
+	  This can be useful in optimizing the layout of kernel virtual
+	  memory.
+
+	  Say N here unless you know what you are doing.
+
+config LOWMEM_SIZE
+	hex "Maximum low memory size (in bytes)" if LOWMEM_SIZE_BOOL
+	depends on MMU
+	default "0x30000000"
+
+config KERNEL_START_BOOL
+	bool "Set custom kernel base address"
+	depends on ADVANCED_OPTIONS
+	help
+	  This option allows you to set the kernel virtual address at which
+	  the kernel will map low memory (the kernel image will be linked at
+	  this address).  This can be useful in optimizing the virtual memory
+	  layout of the system.
+
+	  Say N here unless you know what you are doing.
+
+config KERNEL_START
+	hex "Virtual address of kernel base" if KERNEL_START_BOOL
+	default "0xc0000000" if MMU
+	default KERNEL_BASE_ADDR if !MMU
+
+config TASK_SIZE_BOOL
+	bool "Set custom user task size"
+	depends on ADVANCED_OPTIONS
+	help
+	  This option allows you to set the amount of virtual address space
+	  allocated to user tasks.  This can be useful in optimizing the
+	  virtual memory layout of the system.
+
+	  Say N here unless you know what you are doing.
+
+config TASK_SIZE
+	hex "Size of user task space" if TASK_SIZE_BOOL
+	depends on MMU
+	default "0x80000000"
+
+config CONSISTENT_START_BOOL
+	bool "Set custom consistent memory pool address"
+	depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
+	help
+	  This option allows you to set the base virtual address
+	  of the the consistent memory pool.  This pool of virtual
+	  memory is used to make consistent memory allocations.
+
+config CONSISTENT_START
+	hex "Base virtual address of consistent memory pool" if CONSISTENT_START_BOOL
+	depends on MMU
+	default "0xff100000" if NOT_COHERENT_CACHE
+
+config CONSISTENT_SIZE_BOOL
+	bool "Set custom consistent memory pool size"
+	depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
+	help
+	  This option allows you to set the size of the the
+	  consistent memory pool.  This pool of virtual memory
+	  is used to make consistent memory allocations.
+
+config CONSISTENT_SIZE
+	hex "Size of consistent memory pool" if CONSISTENT_SIZE_BOOL
+	depends on MMU
+	default "0x00200000" if NOT_COHERENT_CACHE
+
+endmenu
+
 source "mm/Kconfig"
 
 menu "Exectuable file formats"
diff --git a/arch/microblaze/Makefile b/arch/microblaze/Makefile
index aaadfa7..d0bcf80 100644
--- a/arch/microblaze/Makefile
+++ b/arch/microblaze/Makefile
@@ -1,4 +1,8 @@
+ifeq ($(CONFIG_MMU),y)
+UTS_SYSNAME = -DUTS_SYSNAME=\"Linux\"
+else
 UTS_SYSNAME = -DUTS_SYSNAME=\"uClinux\"
+endif
 
 # What CPU vesion are we building for, and crack it open
 # as major.minor.rev
@@ -36,6 +40,8 @@
 # r31 holds current when in kernel mode
 CFLAGS_KERNEL += -ffixed-r31 $(CPUFLAGS-1) $(CPUFLAGS-2)
 
+LDFLAGS		:=
+LDFLAGS_vmlinux	:=
 LDFLAGS_BLOB := --format binary --oformat elf32-microblaze
 
 LIBGCC := $(shell $(CC) $(CFLAGS_KERNEL) -print-libgcc-file-name)
diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile
index 844edf4..c2bb043 100644
--- a/arch/microblaze/boot/Makefile
+++ b/arch/microblaze/boot/Makefile
@@ -7,6 +7,8 @@
 OBJCOPYFLAGS_linux.bin  := -O binary
 
 $(obj)/linux.bin: vmlinux FORCE
+	[ -n $(CONFIG_INITRAMFS_SOURCE) ] && [ ! -e $(CONFIG_INITRAMFS_SOURCE) ] && \
+	touch $(CONFIG_INITRAMFS_SOURCE) || echo "No CPIO image"
 	$(call if_changed,objcopy)
 	@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
diff --git a/arch/microblaze/configs/mmu_defconfig b/arch/microblaze/configs/mmu_defconfig
new file mode 100644
index 0000000..bd0b85e
--- /dev/null
+++ b/arch/microblaze/configs/mmu_defconfig
@@ -0,0 +1,798 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc6
+# Fri May 22 10:02:33 2009
+#
+CONFIG_MICROBLAZE=y
+# CONFIG_SWAP is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_GENERIC_TIME_VSYSCALL is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="rootfs.cpio"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+CONFIG_INITRAMFS_COMPRESSION_NONE=y
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
+# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+# CONFIG_SHMEM is not set
+CONFIG_AIO=y
+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_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_BASE_SMALL=1
+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_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# Platform options
+#
+CONFIG_PLATFORM_GENERIC=y
+CONFIG_OPT_LIB_FUNCTION=y
+CONFIG_OPT_LIB_ASM=y
+CONFIG_ALLOW_EDIT_AUTO=y
+
+#
+# Automatic platform settings from Kconfig.auto
+#
+
+#
+# Definitions for MICROBLAZE0
+#
+CONFIG_KERNEL_BASE_ADDR=0x90000000
+CONFIG_XILINX_MICROBLAZE0_FAMILY="virtex5"
+CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR=1
+CONFIG_XILINX_MICROBLAZE0_USE_PCMP_INSTR=1
+CONFIG_XILINX_MICROBLAZE0_USE_BARREL=1
+CONFIG_XILINX_MICROBLAZE0_USE_DIV=1
+CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL=2
+CONFIG_XILINX_MICROBLAZE0_USE_FPU=2
+CONFIG_XILINX_MICROBLAZE0_HW_VER="7.10.d"
+
+#
+# Processor type and features
+#
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_MMU=y
+
+#
+# Boot options
+#
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyUL0,115200"
+CONFIG_CMDLINE_FORCE=y
+CONFIG_OF=y
+CONFIG_PROC_DEVICETREE=y
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+
+#
+# Exectuable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_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_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# 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_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+CONFIG_OF_DEVICE=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_XILINX_SYSACE is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# 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_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+CONFIG_COMPAT_NET_DEV_OPS=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_UARTLITE=y
+CONFIG_SERIAL_UARTLITE_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_XILINX_HWICAP is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_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_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=y
+CONFIG_CIFS_STATS=y
+CONFIG_CIFS_STATS2=y
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL 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=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+CONFIG_DEBUG_SLAB=y
+# CONFIG_DEBUG_SLAB_LEAK is not set
+CONFIG_DEBUG_SPINLOCK=y
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_PAGE_POISONING is not set
+# CONFIG_SAMPLES is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_HEART_BEAT=y
+CONFIG_DEBUG_BOOTMEM=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_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
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES 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_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
diff --git a/arch/microblaze/include/asm/Kbuild b/arch/microblaze/include/asm/Kbuild
index 31820df..db5294c 100644
--- a/arch/microblaze/include/asm/Kbuild
+++ b/arch/microblaze/include/asm/Kbuild
@@ -1,26 +1,3 @@
 include include/asm-generic/Kbuild.asm
 
-header-y += auxvec.h
-header-y += errno.h
-header-y += fcntl.h
-header-y += ioctl.h
-header-y += ioctls.h
-header-y += ipcbuf.h
-header-y += linkage.h
-header-y += msgbuf.h
-header-y += poll.h
-header-y += resource.h
-header-y += sembuf.h
-header-y += shmbuf.h
-header-y += sigcontext.h
-header-y += siginfo.h
-header-y += socket.h
-header-y += sockios.h
-header-y += statfs.h
-header-y += stat.h
-header-y += termbits.h
-header-y += ucontext.h
-
-unifdef-y += cputable.h
-unifdef-y += elf.h
-unifdef-y += termios.h
+header-y  += elf.h
diff --git a/arch/microblaze/include/asm/atomic.h b/arch/microblaze/include/asm/atomic.h
index a448d94..0de612a 100644
--- a/arch/microblaze/include/asm/atomic.h
+++ b/arch/microblaze/include/asm/atomic.h
@@ -118,6 +118,6 @@
 #define smp_mb__before_atomic_inc()	barrier()
 #define smp_mb__after_atomic_inc()	barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 
 #endif /* _ASM_MICROBLAZE_ATOMIC_H */
diff --git a/arch/microblaze/include/asm/bitsperlong.h b/arch/microblaze/include/asm/bitsperlong.h
new file mode 100644
index 0000000..6dc0bb0
--- /dev/null
+++ b/arch/microblaze/include/asm/bitsperlong.h
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
diff --git a/arch/microblaze/include/asm/cacheflush.h b/arch/microblaze/include/asm/cacheflush.h
index 3300b78..f989d6a 100644
--- a/arch/microblaze/include/asm/cacheflush.h
+++ b/arch/microblaze/include/asm/cacheflush.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2007 PetaLogix
+ * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
  * based on v850 version which was
  * Copyright (C) 2001,02,03 NEC Electronics Corporation
@@ -43,6 +44,23 @@
 #define flush_icache_range(start, len)	__invalidate_icache_range(start, len)
 #define flush_icache_page(vma, pg)		do { } while (0)
 
+#ifndef CONFIG_MMU
+# define flush_icache_user_range(start, len)	do { } while (0)
+#else
+# define flush_icache_user_range(vma, pg, adr, len) __invalidate_icache_all()
+
+# define flush_page_to_ram(page)		do { } while (0)
+
+# define flush_icache()			__invalidate_icache_all()
+# define flush_cache_sigtramp(vaddr) \
+			__invalidate_icache_range(vaddr, vaddr + 8)
+
+# define flush_dcache_mmap_lock(mapping)	do { } while (0)
+# define flush_dcache_mmap_unlock(mapping)	do { } while (0)
+
+# define flush_cache_dup_mm(mm)			do { } while (0)
+#endif
+
 #define flush_cache_vmap(start, end)		do { } while (0)
 #define flush_cache_vunmap(start, end)		do { } while (0)
 
diff --git a/arch/microblaze/include/asm/checksum.h b/arch/microblaze/include/asm/checksum.h
index 92b3076..97ea46b 100644
--- a/arch/microblaze/include/asm/checksum.h
+++ b/arch/microblaze/include/asm/checksum.h
@@ -51,7 +51,8 @@
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
  */
-extern __wsum csum_partial_copy(const char *src, char *dst, int len, int sum);
+extern __wsum csum_partial_copy(const void *src, void *dst, int len,
+								__wsum sum);
 
 /*
  * the same as csum_partial_copy, but copies from user space.
@@ -59,8 +60,8 @@
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
  */
-extern __wsum csum_partial_copy_from_user(const char *src, char *dst,
-					int len, int sum, int *csum_err);
+extern __wsum csum_partial_copy_from_user(const void __user *src, void *dst,
+					int len, __wsum sum, int *csum_err);
 
 #define csum_partial_copy_nocheck(src, dst, len, sum)	\
 	csum_partial_copy((src), (dst), (len), (sum))
@@ -75,11 +76,12 @@
 /*
  *	Fold a partial checksum
  */
-static inline __sum16 csum_fold(unsigned int sum)
+static inline __sum16 csum_fold(__wsum csum)
 {
+	u32 sum = (__force u32)csum;
 	sum = (sum & 0xffff) + (sum >> 16);
 	sum = (sum & 0xffff) + (sum >> 16);
-	return ~sum;
+	return (__force __sum16)~sum;
 }
 
 static inline __sum16
@@ -93,6 +95,6 @@
  * this routine is used for miscellaneous IP-like checksums, mainly
  * in icmp.c
  */
-extern __sum16 ip_compute_csum(const unsigned char *buff, int len);
+extern __sum16 ip_compute_csum(const void *buff, int len);
 
 #endif /* _ASM_MICROBLAZE_CHECKSUM_H */
diff --git a/arch/microblaze/include/asm/current.h b/arch/microblaze/include/asm/current.h
index 8375ea9..29303ed 100644
--- a/arch/microblaze/include/asm/current.h
+++ b/arch/microblaze/include/asm/current.h
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -9,6 +11,12 @@
 #ifndef _ASM_MICROBLAZE_CURRENT_H
 #define _ASM_MICROBLAZE_CURRENT_H
 
+/*
+ * Register used to hold the current task pointer while in the kernel.
+ * Any `call clobbered' register without a special meaning should be OK,
+ * but check asm/microblaze/kernel/entry.S to be sure.
+ */
+#define CURRENT_TASK	r31
 # ifndef __ASSEMBLY__
 /*
  * Dedicate r31 to keeping the current task pointer
diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h
index 1733625..d00e400 100644
--- a/arch/microblaze/include/asm/dma-mapping.h
+++ b/arch/microblaze/include/asm/dma-mapping.h
@@ -1,129 +1 @@
-/*
- * 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_DMA_MAPPING_H
-#define _ASM_MICROBLAZE_DMA_MAPPING_H
-
-#include <asm/cacheflush.h>
-#include <linux/io.h>
-#include <linux/bug.h>
-
-struct scatterlist;
-
-#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)
-
-/* FIXME */
-static inline int
-dma_supported(struct device *dev, u64 mask)
-{
-	return 1;
-}
-
-static inline dma_addr_t
-dma_map_page(struct device *dev, struct page *page,
-	unsigned long offset, size_t size,
-	enum dma_data_direction direction)
-{
-	BUG();
-	return 0;
-}
-
-static inline void
-dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-	enum dma_data_direction direction)
-{
-	BUG();
-}
-
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-	enum dma_data_direction direction)
-{
-	BUG();
-	return 0;
-}
-
-static inline void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-	enum dma_data_direction direction)
-{
-	BUG();
-}
-
-static inline void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-			enum dma_data_direction direction)
-{
-	BUG();
-}
-
-static inline void
-dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-		size_t size, enum dma_data_direction direction)
-{
-	BUG();
-}
-
-static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-		enum dma_data_direction direction)
-{
-	BUG();
-}
-
-static inline void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-		enum dma_data_direction direction)
-{
-	BUG();
-}
-
-static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-	return 0;
-}
-
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-				dma_addr_t *dma_handle, int flag)
-{
-	return NULL; /* consistent_alloc(flag, size, dma_handle); */
-}
-
-static inline void dma_free_coherent(struct device *dev, size_t size,
-			void *vaddr, dma_addr_t dma_handle)
-{
-	BUG();
-}
-
-static inline dma_addr_t
-dma_map_single(struct device *dev, void *ptr, size_t size,
-	enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-
-	return virt_to_bus(ptr);
-}
-
-static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
-				    size_t size,
-				    enum dma_data_direction direction)
-{
-	switch (direction) {
-	case DMA_FROM_DEVICE:
-		flush_dcache_range((unsigned)dma_addr,
-			(unsigned)dma_addr + size);
-			/* Fall through */
-	case DMA_TO_DEVICE:
-		break;
-	default:
-		BUG();
-	}
-}
-
-#endif /* _ASM_MICROBLAZE_DMA_MAPPING_H */
+#include <asm-generic/dma-mapping-broken.h>
diff --git a/arch/microblaze/include/asm/dma.h b/arch/microblaze/include/asm/dma.h
index 0967fa0..08c073b 100644
--- a/arch/microblaze/include/asm/dma.h
+++ b/arch/microblaze/include/asm/dma.h
@@ -9,8 +9,13 @@
 #ifndef _ASM_MICROBLAZE_DMA_H
 #define _ASM_MICROBLAZE_DMA_H
 
+#ifndef CONFIG_MMU
 /* we don't have dma address limit. define it as zero to be
  * unlimited. */
 #define MAX_DMA_ADDRESS		(0)
+#else
+/* Virtual address corresponding to last available physical memory address.  */
+#define MAX_DMA_ADDRESS (CONFIG_KERNEL_START + memory_size - 1)
+#endif
 
 #endif /* _ASM_MICROBLAZE_DMA_H */
diff --git a/arch/microblaze/include/asm/elf.h b/arch/microblaze/include/asm/elf.h
index 81337f2..f92fc0d 100644
--- a/arch/microblaze/include/asm/elf.h
+++ b/arch/microblaze/include/asm/elf.h
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -27,4 +29,95 @@
  */
 #define ELF_CLASS	ELFCLASS32
 
+#ifndef __uClinux__
+
+/*
+ * ELF register definitions..
+ */
+
+#include <asm/ptrace.h>
+#include <asm/byteorder.h>
+
+#ifndef ELF_GREG_T
+#define ELF_GREG_T
+typedef unsigned long elf_greg_t;
+#endif
+
+#ifndef ELF_NGREG
+#define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t))
+#endif
+
+#ifndef ELF_GREGSET_T
+#define ELF_GREGSET_T
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+#endif
+
+#ifndef ELF_FPREGSET_T
+#define ELF_FPREGSET_T
+
+/* TBD */
+#define ELF_NFPREG	33	/* includes fsr */
+typedef unsigned long elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+/* typedef struct user_fpu_struct elf_fpregset_t; */
+#endif
+
+/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
+ * use of this is to invoke "./ld.so someprog" to test out a new version of
+ * the loader.  We need to make sure that it is out of the way of the program
+ * that it will "exec", and that there is sufficient room for the brk.
+ */
+
+#define ELF_ET_DYN_BASE         (0x08000000)
+
+#ifdef __LITTLE_ENDIAN__
+#define ELF_DATA	ELFDATA2LSB
+#else
+#define ELF_DATA	ELFDATA2MSB
+#endif
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE	4096
+
+
+#define ELF_CORE_COPY_REGS(_dest, _regs)			\
+	memcpy((char *) &_dest, (char *) _regs,		\
+	sizeof(struct pt_regs));
+
+/* This yields a mask that user programs can use to figure out what
+ * instruction set this CPU supports.  This could be done in user space,
+ * but it's not easy, and we've already done it here.
+ */
+#define ELF_HWCAP	(0)
+
+/* This yields a string that ld.so will use to load implementation
+ * specific libraries for optimization.  This is more specific in
+ * intent than poking at uname or /proc/cpuinfo.
+
+ * For the moment, we have only optimizations for the Intel generations,
+ * but that could change...
+ */
+#define ELF_PLATFORM  (NULL)
+
+/* Added _f parameter. Is this definition correct: TBD */
+#define ELF_PLAT_INIT(_r, _f)				\
+do {							\
+	_r->r1 =  _r->r1 =  _r->r2 =  _r->r3 =		\
+	_r->r4 =  _r->r5 =  _r->r6 =  _r->r7 =		\
+	_r->r8 =  _r->r9 =  _r->r10 = _r->r11 =		\
+	_r->r12 = _r->r13 = _r->r14 = _r->r15 =		\
+	_r->r16 = _r->r17 = _r->r18 = _r->r19 =		\
+	_r->r20 = _r->r21 = _r->r22 = _r->r23 =		\
+	_r->r24 = _r->r25 = _r->r26 = _r->r27 =		\
+	_r->r28 = _r->r29 = _r->r30 = _r->r31 =		\
+	0;						\
+} while (0)
+
+#ifdef __KERNEL__
+#define SET_PERSONALITY(ex) set_personality(PER_LINUX_32BIT)
+#endif
+
+#endif /* __uClinux__ */
+
 #endif /* _ASM_MICROBLAZE_ELF_H */
diff --git a/arch/microblaze/include/asm/entry.h b/arch/microblaze/include/asm/entry.h
index e4c3aef..61abbd2 100644
--- a/arch/microblaze/include/asm/entry.h
+++ b/arch/microblaze/include/asm/entry.h
@@ -1,8 +1,8 @@
 /*
  * Definitions used by low-level trap handlers
  *
- * Copyright (C) 2008 Michal Simek
- * Copyright (C) 2007 - 2008 PetaLogix
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
  *
  * This file is subject to the terms and conditions of the GNU General
@@ -31,7 +31,40 @@
 DECLARE_PER_CPU(unsigned int, CURRENT_SAVE); /* Saved current pointer */
 # endif /* __ASSEMBLY__ */
 
+#ifndef CONFIG_MMU
+
 /* noMMU hasn't any space for args */
 # define STATE_SAVE_ARG_SPACE	(0)
 
+#else /* CONFIG_MMU */
+
+/* If true, system calls save and restore all registers (except result
+ * registers, of course).  If false, then `call clobbered' registers
+ * will not be preserved, on the theory that system calls are basically
+ * function calls anyway, and the caller should be able to deal with it.
+ * This is a security risk, of course, as `internal' values may leak out
+ * after a system call, but that certainly doesn't matter very much for
+ * a processor with no MMU protection!  For a protected-mode kernel, it
+ * would be faster to just zero those registers before returning.
+ *
+ * I can not rely on the glibc implementation. If you turn it off make
+ * sure that r11/r12 is saved in user-space. --KAA
+ *
+ * These are special variables using by the kernel trap/interrupt code
+ * to save registers in, at a time when there are no spare registers we
+ * can use to do so, and we can't depend on the value of the stack
+ * pointer.  This means that they must be within a signed 16-bit
+ * displacement of 0x00000000.
+ */
+
+/* A `state save frame' is a struct pt_regs preceded by some extra space
+ * suitable for a function call stack frame. */
+
+/* Amount of room on the stack reserved for arguments and to satisfy the
+ * C calling conventions, in addition to the space used by the struct
+ * pt_regs that actually holds saved values. */
+#define STATE_SAVE_ARG_SPACE	(6*4) /* Up to six arguments */
+
+#endif /* CONFIG_MMU */
+
 #endif /* _ASM_MICROBLAZE_ENTRY_H */
diff --git a/arch/microblaze/include/asm/exceptions.h b/arch/microblaze/include/asm/exceptions.h
index 24ca540..90731df 100644
--- a/arch/microblaze/include/asm/exceptions.h
+++ b/arch/microblaze/include/asm/exceptions.h
@@ -1,8 +1,8 @@
 /*
  * Preliminary support for HW exception handing for Microblaze
  *
- * Copyright (C) 2008 Michal Simek
- * Copyright (C) 2008 PetaLogix
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2005 John Williams <jwilliams@itee.uq.edu.au>
  *
  * This file is subject to the terms and conditions of the GNU General
@@ -64,21 +64,13 @@
 void die(const char *str, struct pt_regs *fp, long err);
 void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr);
 
-#if defined(CONFIG_XMON)
-extern void xmon(struct pt_regs *regs);
-extern int xmon_bpt(struct pt_regs *regs);
-extern int xmon_sstep(struct pt_regs *regs);
-extern int xmon_iabr_match(struct pt_regs *regs);
-extern int xmon_dabr_match(struct pt_regs *regs);
-extern void (*xmon_fault_handler)(struct pt_regs *regs);
+#ifdef CONFIG_MMU
+void __bug(const char *file, int line, void *data);
+int bad_trap(int trap_num, struct pt_regs *regs);
+int debug_trap(struct pt_regs *regs);
+#endif /* CONFIG_MMU */
 
-void (*debugger)(struct pt_regs *regs) = xmon;
-int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt;
-int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep;
-int (*debugger_iabr_match)(struct pt_regs *regs) = xmon_iabr_match;
-int (*debugger_dabr_match)(struct pt_regs *regs) = xmon_dabr_match;
-void (*debugger_fault_handler)(struct pt_regs *regs);
-#elif defined(CONFIG_KGDB)
+#if defined(CONFIG_KGDB)
 void (*debugger)(struct pt_regs *regs);
 int (*debugger_bpt)(struct pt_regs *regs);
 int (*debugger_sstep)(struct pt_regs *regs);
diff --git a/arch/microblaze/include/asm/flat.h b/arch/microblaze/include/asm/flat.h
index acf0da5..6847c15 100644
--- a/arch/microblaze/include/asm/flat.h
+++ b/arch/microblaze/include/asm/flat.h
@@ -13,7 +13,6 @@
 
 #include <asm/unaligned.h>
 
-#define	flat_stack_align(sp) /* nothing needed */
 #define	flat_argvp_envp_on_stack()	0
 #define	flat_old_ram_flag(flags)	(flags)
 #define	flat_reloc_valid(reloc, size)	((reloc) <= (size))
diff --git a/arch/microblaze/include/asm/gpio.h b/arch/microblaze/include/asm/gpio.h
index ea04632..2345ac3 100644
--- a/arch/microblaze/include/asm/gpio.h
+++ b/arch/microblaze/include/asm/gpio.h
@@ -11,8 +11,8 @@
  * (at your option) any later version.
  */
 
-#ifndef __ASM_POWERPC_GPIO_H
-#define __ASM_POWERPC_GPIO_H
+#ifndef _ASM_MICROBLAZE_GPIO_H
+#define _ASM_MICROBLAZE_GPIO_H
 
 #include <linux/errno.h>
 #include <asm-generic/gpio.h>
@@ -53,4 +53,4 @@
 
 #endif /* CONFIG_GPIOLIB */
 
-#endif /* __ASM_POWERPC_GPIO_H */
+#endif /* _ASM_MICROBLAZE_GPIO_H */
diff --git a/arch/microblaze/include/asm/io.h b/arch/microblaze/include/asm/io.h
index 8b5853e..5c17342 100644
--- a/arch/microblaze/include/asm/io.h
+++ b/arch/microblaze/include/asm/io.h
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -12,6 +14,9 @@
 #include <asm/byteorder.h>
 #include <asm/page.h>
 #include <linux/types.h>
+#include <asm/byteorder.h>
+#include <linux/mm.h>          /* Get struct page {...} */
+
 
 #define IO_SPACE_LIMIT (0xFFFFFFFF)
 
@@ -112,6 +117,30 @@
 #define memcpy_fromio(a, b, c)	memcpy((a), (void *)(b), (c))
 #define memcpy_toio(a, b, c)	memcpy((void *)(a), (b), (c))
 
+#ifdef CONFIG_MMU
+
+#define mm_ptov(addr)		((void *)__phys_to_virt(addr))
+#define mm_vtop(addr)		((unsigned long)__virt_to_phys(addr))
+#define phys_to_virt(addr)	((void *)__phys_to_virt(addr))
+#define virt_to_phys(addr)	((unsigned long)__virt_to_phys(addr))
+#define virt_to_bus(addr)	((unsigned long)__virt_to_phys(addr))
+
+#define __page_address(page) \
+		(PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT))
+#define page_to_phys(page)	virt_to_phys((void *)__page_address(page))
+#define page_to_bus(page)	(page_to_phys(page))
+#define bus_to_virt(addr)	(phys_to_virt(addr))
+
+extern void iounmap(void *addr);
+/*extern void *__ioremap(phys_addr_t address, unsigned long size,
+		unsigned long flags);*/
+extern void __iomem *ioremap(phys_addr_t address, unsigned long size);
+#define ioremap_writethrough(addr, size) ioremap((addr), (size))
+#define ioremap_nocache(addr, size)      ioremap((addr), (size))
+#define ioremap_fullcache(addr, size)    ioremap((addr), (size))
+
+#else /* CONFIG_MMU */
+
 /**
  *	virt_to_phys - map virtual addresses to physical
  *	@address: address to remap
@@ -160,6 +189,8 @@
 #define iounmap(addr)		((void)0)
 #define ioremap_nocache(physaddr, size)	ioremap(physaddr, size)
 
+#endif /* CONFIG_MMU */
+
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
  * access
diff --git a/arch/microblaze/include/asm/mmu.h b/arch/microblaze/include/asm/mmu.h
index 0e0431d..66cad6a 100644
--- a/arch/microblaze/include/asm/mmu.h
+++ b/arch/microblaze/include/asm/mmu.h
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -9,11 +11,109 @@
 #ifndef _ASM_MICROBLAZE_MMU_H
 #define _ASM_MICROBLAZE_MMU_H
 
-#ifndef __ASSEMBLY__
+# ifndef CONFIG_MMU
+#  ifndef __ASSEMBLY__
 typedef struct {
 	struct vm_list_struct	*vmlist;
 	unsigned long		end_brk;
 } mm_context_t;
-#endif /* __ASSEMBLY__ */
+#  endif /* __ASSEMBLY__ */
+# else /* CONFIG_MMU */
+#  ifdef __KERNEL__
+#   ifndef __ASSEMBLY__
 
+/* Default "unsigned long" context */
+typedef unsigned long mm_context_t;
+
+/* Hardware Page Table Entry */
+typedef struct _PTE {
+	unsigned long    v:1;	/* Entry is valid */
+	unsigned long vsid:24;	/* Virtual segment identifier */
+	unsigned long    h:1;	/* Hash algorithm indicator */
+	unsigned long  api:6;	/* Abbreviated page index */
+	unsigned long  rpn:20;	/* Real (physical) page number */
+	unsigned long     :3;	/* Unused */
+	unsigned long    r:1;	/* Referenced */
+	unsigned long    c:1;	/* Changed */
+	unsigned long    w:1;	/* Write-thru cache mode */
+	unsigned long    i:1;	/* Cache inhibited */
+	unsigned long    m:1;	/* Memory coherence */
+	unsigned long    g:1;	/* Guarded */
+	unsigned long     :1;	/* Unused */
+	unsigned long   pp:2;	/* Page protection */
+} PTE;
+
+/* Values for PP (assumes Ks=0, Kp=1) */
+#  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 */
+
+/* Segment Register */
+typedef struct _SEGREG {
+	unsigned long    t:1;	/* Normal or I/O  type */
+	unsigned long   ks:1;	/* Supervisor 'key' (normally 0) */
+	unsigned long   kp:1;	/* User 'key' (normally 1) */
+	unsigned long    n:1;	/* No-execute */
+	unsigned long     :4;	/* Unused */
+	unsigned long vsid:24;	/* Virtual Segment Identifier */
+} SEGREG;
+
+extern void _tlbie(unsigned long va);	/* invalidate a TLB entry */
+extern void _tlbia(void);		/* invalidate all TLB entries */
+#   endif /* __ASSEMBLY__ */
+
+/*
+ * The MicroBlaze processor has a TLB architecture identical to PPC-40x. The
+ * instruction and data sides share a unified, 64-entry, semi-associative
+ * TLB which is maintained totally under software control. In addition, the
+ * instruction side has a hardware-managed, 2,4, or 8-entry, fully-associative
+ * TLB which serves as a first level to the shared TLB. These two TLBs are
+ * known as the UTLB and ITLB, respectively.
+ */
+
+#  define MICROBLAZE_TLB_SIZE 64
+
+/*
+ * TLB entries are defined by a "high" tag portion and a "low" data
+ * portion. The data portion is 32-bits.
+ *
+ * TLB entries are managed entirely under software control by reading,
+ * writing, and searching using the MTS and MFS instructions.
+ */
+
+#  define TLB_LO		1
+#  define TLB_HI		0
+#  define TLB_DATA		TLB_LO
+#  define TLB_TAG		TLB_HI
+
+/* Tag portion */
+#  define TLB_EPN_MASK		0xFFFFFC00 /* Effective Page Number */
+#  define TLB_PAGESZ_MASK	0x00000380
+#  define TLB_PAGESZ(x)		(((x) & 0x7) << 7)
+#  define PAGESZ_1K		0
+#  define PAGESZ_4K		1
+#  define PAGESZ_16K		2
+#  define PAGESZ_64K		3
+#  define PAGESZ_256K		4
+#  define PAGESZ_1M		5
+#  define PAGESZ_4M		6
+#  define PAGESZ_16M		7
+#  define TLB_VALID		0x00000040 /* Entry is valid */
+
+/* Data portion */
+#  define TLB_RPN_MASK		0xFFFFFC00 /* Real Page Number */
+#  define TLB_PERM_MASK		0x00000300
+#  define TLB_EX		0x00000200 /* Instruction execution allowed */
+#  define TLB_WR		0x00000100 /* Writes permitted */
+#  define TLB_ZSEL_MASK		0x000000F0
+#  define TLB_ZSEL(x)		(((x) & 0xF) << 4)
+#  define TLB_ATTR_MASK		0x0000000F
+#  define TLB_W			0x00000008 /* Caching is write-through */
+#  define TLB_I			0x00000004 /* Caching is inhibited */
+#  define TLB_M			0x00000002 /* Memory is coherent */
+#  define TLB_G			0x00000001 /* Memory is guarded from prefetch */
+
+#  endif /* __KERNEL__ */
+# endif /* CONFIG_MMU */
 #endif /* _ASM_MICROBLAZE_MMU_H */
diff --git a/arch/microblaze/include/asm/mmu_context.h b/arch/microblaze/include/asm/mmu_context.h
index 150ca01..385fed1 100644
--- a/arch/microblaze/include/asm/mmu_context.h
+++ b/arch/microblaze/include/asm/mmu_context.h
@@ -1,21 +1,5 @@
-/*
- * 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_MMU_CONTEXT_H
-#define _ASM_MICROBLAZE_MMU_CONTEXT_H
-
-# define init_new_context(tsk, mm)		({ 0; })
-
-# define enter_lazy_tlb(mm, tsk)		do {} while (0)
-# define change_mm_context(old, ctx, _pml4)	do {} while (0)
-# define destroy_context(mm)			do {} while (0)
-# define deactivate_mm(tsk, mm)			do {} while (0)
-# define switch_mm(prev, next, tsk)		do {} while (0)
-# define activate_mm(prev, next)		do {} while (0)
-
-#endif /* _ASM_MICROBLAZE_MMU_CONTEXT_H */
+#ifdef CONFIG_MMU
+# include "mmu_context_mm.h"
+#else
+# include "mmu_context_no.h"
+#endif
diff --git a/arch/microblaze/include/asm/mmu_context_mm.h b/arch/microblaze/include/asm/mmu_context_mm.h
new file mode 100644
index 0000000..3e5c254
--- /dev/null
+++ b/arch/microblaze/include/asm/mmu_context_mm.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
+ * 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_MMU_CONTEXT_H
+#define _ASM_MICROBLAZE_MMU_CONTEXT_H
+
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/mmu.h>
+#include <asm-generic/mm_hooks.h>
+
+# ifdef __KERNEL__
+/*
+ * This function defines the mapping from contexts to VSIDs (virtual
+ * segment IDs).  We use a skew on both the context and the high 4 bits
+ * of the 32-bit virtual address (the "effective segment ID") in order
+ * to spread out the entries in the MMU hash table.
+ */
+# define CTX_TO_VSID(ctx, va)	(((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \
+				 & 0xffffff)
+
+/*
+   MicroBlaze has 256 contexts, so we can just rotate through these
+   as a way of "switching" contexts.  If the TID of the TLB is zero,
+   the PID/TID comparison is disabled, so we can use a TID of zero
+   to represent all kernel pages as shared among all contexts.
+ */
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+# define NO_CONTEXT	256
+# define LAST_CONTEXT	255
+# define FIRST_CONTEXT	1
+
+/*
+ * Set the current MMU context.
+ * This is done byloading up the segment registers for the user part of the
+ * address space.
+ *
+ * Since the PGD is immediately available, it is much faster to simply
+ * pass this along as a second parameter, which is required for 8xx and
+ * can be used for debugging on all processors (if you happen to have
+ * an Abatron).
+ */
+extern void set_context(mm_context_t context, pgd_t *pgd);
+
+/*
+ * Bitmap of contexts in use.
+ * The size of this bitmap is LAST_CONTEXT + 1 bits.
+ */
+extern unsigned long context_map[];
+
+/*
+ * This caches the next context number that we expect to be free.
+ * Its use is an optimization only, we can't rely on this context
+ * number to be free, but it usually will be.
+ */
+extern mm_context_t next_mmu_context;
+
+/*
+ * Since we don't have sufficient contexts to give one to every task
+ * that could be in the system, we need to be able to steal contexts.
+ * These variables support that.
+ */
+extern atomic_t nr_free_contexts;
+extern struct mm_struct *context_mm[LAST_CONTEXT+1];
+extern void steal_context(void);
+
+/*
+ * Get a new mmu context for the address space described by `mm'.
+ */
+static inline void get_mmu_context(struct mm_struct *mm)
+{
+	mm_context_t ctx;
+
+	if (mm->context != NO_CONTEXT)
+		return;
+	while (atomic_dec_if_positive(&nr_free_contexts) < 0)
+		steal_context();
+	ctx = next_mmu_context;
+	while (test_and_set_bit(ctx, context_map)) {
+		ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx);
+		if (ctx > LAST_CONTEXT)
+			ctx = 0;
+	}
+	next_mmu_context = (ctx + 1) & LAST_CONTEXT;
+	mm->context = ctx;
+	context_mm[ctx] = mm;
+}
+
+/*
+ * Set up the context for a new address space.
+ */
+# define init_new_context(tsk, mm)	(((mm)->context = NO_CONTEXT), 0)
+
+/*
+ * We're finished using the context for an address space.
+ */
+static inline void destroy_context(struct mm_struct *mm)
+{
+	if (mm->context != NO_CONTEXT) {
+		clear_bit(mm->context, context_map);
+		mm->context = NO_CONTEXT;
+		atomic_inc(&nr_free_contexts);
+	}
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+			     struct task_struct *tsk)
+{
+	tsk->thread.pgdir = next->pgd;
+	get_mmu_context(next);
+	set_context(next->context, next->pgd);
+}
+
+/*
+ * After we have set current->mm to a new value, this activates
+ * the context for the new mm so we see the new mappings.
+ */
+static inline void activate_mm(struct mm_struct *active_mm,
+			struct mm_struct *mm)
+{
+	current->thread.pgdir = mm->pgd;
+	get_mmu_context(mm);
+	set_context(mm->context, mm->pgd);
+}
+
+extern void mmu_context_init(void);
+
+# endif /* __KERNEL__ */
+#endif /* _ASM_MICROBLAZE_MMU_CONTEXT_H */
diff --git a/arch/microblaze/include/asm/mmu_context_no.h b/arch/microblaze/include/asm/mmu_context_no.h
new file mode 100644
index 0000000..ba55671
--- /dev/null
+++ b/arch/microblaze/include/asm/mmu_context_no.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
+ * 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_MMU_CONTEXT_H
+#define _ASM_MICROBLAZE_MMU_CONTEXT_H
+
+# define init_new_context(tsk, mm)		({ 0; })
+
+# define enter_lazy_tlb(mm, tsk)		do {} while (0)
+# define change_mm_context(old, ctx, _pml4)	do {} while (0)
+# define destroy_context(mm)			do {} while (0)
+# define deactivate_mm(tsk, mm)			do {} while (0)
+# define switch_mm(prev, next, tsk)		do {} while (0)
+# define activate_mm(prev, next)		do {} while (0)
+
+#endif /* _ASM_MICROBLAZE_MMU_CONTEXT_H */
diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h
index 7238dcf..72aceae 100644
--- a/arch/microblaze/include/asm/page.h
+++ b/arch/microblaze/include/asm/page.h
@@ -1,6 +1,8 @@
 /*
- * Copyright (C) 2008 Michal Simek
- * Copyright (C) 2008 PetaLogix
+ * VM ops
+ *
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  * Changes for MMU support:
  *    Copyright (C) 2007 Xilinx, Inc.  All rights reserved.
@@ -15,14 +17,15 @@
 
 #include <linux/pfn.h>
 #include <asm/setup.h>
+#include <linux/const.h>
+
+#ifdef __KERNEL__
 
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	(12)
-#define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#define PAGE_SIZE	(_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 
-#ifdef __KERNEL__
-
 #ifndef __ASSEMBLY__
 
 #define PAGE_UP(addr)	(((addr)+((PAGE_SIZE)-1))&(~((PAGE_SIZE)-1)))
@@ -35,6 +38,7 @@
 /* align addr on a size boundary - adjust address up if needed */
 #define _ALIGN(addr, size)	_ALIGN_UP(addr, size)
 
+#ifndef CONFIG_MMU
 /*
  * PAGE_OFFSET -- the first address of the first page of memory. When not
  * using MMU this corresponds to the first free page in physical memory (aligned
@@ -43,15 +47,44 @@
 extern unsigned int __page_offset;
 #define PAGE_OFFSET __page_offset
 
-#define copy_page(to, from)			memcpy((to), (from), PAGE_SIZE)
-#define get_user_page(vaddr)			__get_free_page(GFP_KERNEL)
-#define free_user_page(page, addr)		free_page(addr)
+#else /* CONFIG_MMU */
 
-#define clear_page(pgaddr)			memset((pgaddr), 0, PAGE_SIZE)
+/*
+ * PAGE_OFFSET -- the first address of the first page of memory. With MMU
+ * it is set to the kernel start address (aligned on a page boundary).
+ *
+ * CONFIG_KERNEL_START is defined in arch/microblaze/config.in and used
+ * in arch/microblaze/Makefile.
+ */
+#define PAGE_OFFSET	CONFIG_KERNEL_START
 
+/*
+ * MAP_NR -- given an address, calculate the index of the page struct which
+ * points to the address's page.
+ */
+#define MAP_NR(addr) (((unsigned long)(addr) - PAGE_OFFSET) >> PAGE_SHIFT)
 
-#define clear_user_page(pgaddr, vaddr, page)	memset((pgaddr), 0, PAGE_SIZE)
-#define copy_user_page(vto, vfrom, vaddr, topg) \
+/*
+ * The basic type of a PTE - 32 bit physical addressing.
+ */
+typedef unsigned long pte_basic_t;
+#define PTE_SHIFT	(PAGE_SHIFT - 2)	/* 1024 ptes per page */
+#define PTE_FMT		"%.8lx"
+
+#endif /* CONFIG_MMU */
+
+#  ifndef CONFIG_MMU
+#  define copy_page(to, from)			memcpy((to), (from), PAGE_SIZE)
+#  define get_user_page(vaddr)			__get_free_page(GFP_KERNEL)
+#  define free_user_page(page, addr)		free_page(addr)
+#  else /* CONFIG_MMU */
+extern void copy_page(void *to, void *from);
+#  endif /* CONFIG_MMU */
+
+# define clear_page(pgaddr)			memset((pgaddr), 0, PAGE_SIZE)
+
+# define clear_user_page(pgaddr, vaddr, page)	memset((pgaddr), 0, PAGE_SIZE)
+# define copy_user_page(vto, vfrom, vaddr, topg) \
 			memcpy((vto), (vfrom), PAGE_SIZE)
 
 /*
@@ -60,21 +93,32 @@
 typedef struct page *pgtable_t;
 typedef struct { unsigned long	pte; }		pte_t;
 typedef struct { unsigned long	pgprot; }	pgprot_t;
+/* FIXME this can depend on linux kernel version */
+#   ifdef CONFIG_MMU
+typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pgd; } pgd_t;
+#   else /* CONFIG_MMU */
 typedef struct { unsigned long	ste[64]; }	pmd_t;
 typedef struct { pmd_t		pue[1]; }	pud_t;
 typedef struct { pud_t		pge[1]; }	pgd_t;
+#   endif /* CONFIG_MMU */
 
+# define pte_val(x)	((x).pte)
+# define pgprot_val(x)	((x).pgprot)
 
-#define pte_val(x)	((x).pte)
-#define pgprot_val(x)	((x).pgprot)
-#define pmd_val(x)	((x).ste[0])
-#define pud_val(x)	((x).pue[0])
-#define pgd_val(x)	((x).pge[0])
+#   ifdef CONFIG_MMU
+#   define pmd_val(x)      ((x).pmd)
+#   define pgd_val(x)      ((x).pgd)
+#   else  /* CONFIG_MMU */
+#   define pmd_val(x)	((x).ste[0])
+#   define pud_val(x)	((x).pue[0])
+#   define pgd_val(x)	((x).pge[0])
+#   endif  /* CONFIG_MMU */
 
-#define __pte(x)	((pte_t) { (x) })
-#define __pmd(x)	((pmd_t) { (x) })
-#define __pgd(x)	((pgd_t) { (x) })
-#define __pgprot(x)	((pgprot_t) { (x) })
+# define __pte(x)	((pte_t) { (x) })
+# define __pmd(x)	((pmd_t) { (x) })
+# define __pgd(x)	((pgd_t) { (x) })
+# define __pgprot(x)	((pgprot_t) { (x) })
 
 /**
  * Conversions for virtual address, physical address, pfn, and struct
@@ -94,47 +138,83 @@
 extern unsigned long min_low_pfn;
 extern unsigned long max_pfn;
 
-#define __pa(vaddr)		((unsigned long) (vaddr))
-#define __va(paddr)		((void *) (paddr))
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+extern unsigned long memory_size;
 
-#define phys_to_pfn(phys)	(PFN_DOWN(phys))
-#define pfn_to_phys(pfn)	(PFN_PHYS(pfn))
+extern int page_is_ram(unsigned long pfn);
 
-#define virt_to_pfn(vaddr)	(phys_to_pfn((__pa(vaddr))))
-#define pfn_to_virt(pfn)	__va(pfn_to_phys((pfn)))
+# define phys_to_pfn(phys)	(PFN_DOWN(phys))
+# define pfn_to_phys(pfn)	(PFN_PHYS(pfn))
 
-#define virt_to_page(vaddr)	(pfn_to_page(virt_to_pfn(vaddr)))
-#define page_to_virt(page)	(pfn_to_virt(page_to_pfn(page)))
+# define virt_to_pfn(vaddr)	(phys_to_pfn((__pa(vaddr))))
+# define pfn_to_virt(pfn)	__va(pfn_to_phys((pfn)))
 
-#define page_to_phys(page)	(pfn_to_phys(page_to_pfn(page)))
-#define page_to_bus(page)	(page_to_phys(page))
-#define phys_to_page(paddr)	(pfn_to_page(phys_to_pfn(paddr)))
+#  ifdef CONFIG_MMU
+#  define virt_to_page(kaddr) 	(mem_map +  MAP_NR(kaddr))
+#  else /* CONFIG_MMU */
+#  define virt_to_page(vaddr)	(pfn_to_page(virt_to_pfn(vaddr)))
+#  define page_to_virt(page)	(pfn_to_virt(page_to_pfn(page)))
+#  define page_to_phys(page)	(pfn_to_phys(page_to_pfn(page)))
+#  define page_to_bus(page)	(page_to_phys(page))
+#  define phys_to_page(paddr)	(pfn_to_page(phys_to_pfn(paddr)))
+#  endif /* CONFIG_MMU */
 
-extern unsigned int memory_start;
-extern unsigned int memory_end;
-extern unsigned int memory_size;
+#  ifndef CONFIG_MMU
+#  define pfn_valid(pfn)	((pfn) >= min_low_pfn && (pfn) <= max_mapnr)
+#  define ARCH_PFN_OFFSET	(PAGE_OFFSET >> PAGE_SHIFT)
+#  else /* CONFIG_MMU */
+#  define ARCH_PFN_OFFSET	(memory_start >> PAGE_SHIFT)
+#  define pfn_valid(pfn)	((pfn) < (max_mapnr + ARCH_PFN_OFFSET))
+#  define VALID_PAGE(page) 	((page - mem_map) < max_mapnr)
+#  endif /* CONFIG_MMU */
 
-#define pfn_valid(pfn)		((pfn) >= min_low_pfn && (pfn) < max_mapnr)
+# endif /* __ASSEMBLY__ */
 
-#define ARCH_PFN_OFFSET		(PAGE_OFFSET >> PAGE_SHIFT)
+#define	virt_addr_valid(vaddr)	(pfn_valid(virt_to_pfn(vaddr)))
 
-#else
-#define tophys(rd, rs)	(addik rd, rs, 0)
-#define tovirt(rd, rs)	(addik rd, rs, 0)
-#endif /* __ASSEMBLY__ */
 
-#define virt_addr_valid(vaddr)	(pfn_valid(virt_to_pfn(vaddr)))
+#  ifndef CONFIG_MMU
+#  define __pa(vaddr)	((unsigned long) (vaddr))
+#  define __va(paddr)	((void *) (paddr))
+#  else /* CONFIG_MMU */
+#  define __pa(x)	__virt_to_phys((unsigned long)(x))
+#  define __va(x)	((void *)__phys_to_virt((unsigned long)(x)))
+#  endif /* CONFIG_MMU */
 
-/* Convert between virtual and physical address for MMU.  */
-/* Handle MicroBlaze processor with virtual memory.  */
+
+/* Convert between virtual and physical address for MMU. */
+/* Handle MicroBlaze processor with virtual memory. */
+#ifndef CONFIG_MMU
 #define __virt_to_phys(addr)	addr
 #define __phys_to_virt(addr)	addr
+#define tophys(rd, rs)	addik rd, rs, 0
+#define tovirt(rd, rs)	addik rd, rs, 0
+#else
+#define __virt_to_phys(addr) \
+	((addr) + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START)
+#define __phys_to_virt(addr) \
+	((addr) + CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR)
+#define tophys(rd, rs) \
+	addik rd, rs, (CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START)
+#define tovirt(rd, rs) \
+	addik rd, rs, (CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR)
+#endif /* CONFIG_MMU */
 
 #define TOPHYS(addr)  __virt_to_phys(addr)
 
+#ifdef CONFIG_MMU
+#ifdef CONFIG_CONTIGUOUS_PAGE_ALLOC
+#define WANT_PAGE_VIRTUAL 1 /* page alloc 2 relies on this */
+#endif
+
+#define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
+				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#endif /* CONFIG_MMU */
+
 #endif /* __KERNEL__ */
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _ASM_MICROBLAZE_PAGE_H */
diff --git a/arch/microblaze/include/asm/pgalloc.h b/arch/microblaze/include/asm/pgalloc.h
index 2a4b354..59a757e 100644
--- a/arch/microblaze/include/asm/pgalloc.h
+++ b/arch/microblaze/include/asm/pgalloc.h
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -9,6 +11,195 @@
 #ifndef _ASM_MICROBLAZE_PGALLOC_H
 #define _ASM_MICROBLAZE_PGALLOC_H
 
+#ifdef CONFIG_MMU
+
+#include <linux/kernel.h>	/* For min/max macros */
+#include <linux/highmem.h>
+#include <asm/setup.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+
+#define PGDIR_ORDER	0
+
+/*
+ * This is handled very differently on MicroBlaze since out page tables
+ * are all 0's and I want to be able to use these zero'd pages elsewhere
+ * as well - it gives us quite a speedup.
+ * -- Cort
+ */
+extern struct pgtable_cache_struct {
+	unsigned long *pgd_cache;
+	unsigned long *pte_cache;
+	unsigned long pgtable_cache_sz;
+} quicklists;
+
+#define pgd_quicklist		(quicklists.pgd_cache)
+#define pmd_quicklist		((unsigned long *)0)
+#define pte_quicklist		(quicklists.pte_cache)
+#define pgtable_cache_size	(quicklists.pgtable_cache_sz)
+
+extern unsigned long *zero_cache; /* head linked list of pre-zero'd pages */
+extern atomic_t zero_sz; /* # currently pre-zero'd pages */
+extern atomic_t zeropage_hits; /* # zero'd pages request that we've done */
+extern atomic_t zeropage_calls; /* # zero'd pages request that've been made */
+extern atomic_t zerototal; /* # pages zero'd over time */
+
+#define zero_quicklist		(zero_cache)
+#define zero_cache_sz	 	(zero_sz)
+#define zero_cache_calls	(zeropage_calls)
+#define zero_cache_hits		(zeropage_hits)
+#define zero_cache_total	(zerototal)
+
+/*
+ * return a pre-zero'd page from the list,
+ * return NULL if none available -- Cort
+ */
+extern unsigned long get_zero_page_fast(void);
+
+extern void __bad_pte(pmd_t *pmd);
+
+extern inline pgd_t *get_pgd_slow(void)
+{
+	pgd_t *ret;
+
+	ret = (pgd_t *)__get_free_pages(GFP_KERNEL, PGDIR_ORDER);
+	if (ret != NULL)
+		clear_page(ret);
+	return ret;
+}
+
+extern inline pgd_t *get_pgd_fast(void)
+{
+	unsigned long *ret;
+
+	ret = pgd_quicklist;
+	if (ret != NULL) {
+		pgd_quicklist = (unsigned long *)(*ret);
+		ret[0] = 0;
+		pgtable_cache_size--;
+	} else
+		ret = (unsigned long *)get_pgd_slow();
+	return (pgd_t *)ret;
+}
+
+extern inline void free_pgd_fast(pgd_t *pgd)
+{
+	*(unsigned long **)pgd = pgd_quicklist;
+	pgd_quicklist = (unsigned long *) pgd;
+	pgtable_cache_size++;
+}
+
+extern inline void free_pgd_slow(pgd_t *pgd)
+{
+	free_page((unsigned long)pgd);
+}
+
+#define pgd_free(mm, pgd)        free_pgd_fast(pgd)
+#define pgd_alloc(mm)		get_pgd_fast()
+
+#define pmd_pgtable(pmd)	pmd_page(pmd)
+
+/*
+ * We don't have any real pmd's, and this code never triggers because
+ * the pgd will always be present..
+ */
+#define pmd_alloc_one_fast(mm, address)	({ BUG(); ((pmd_t *)1); })
+#define pmd_alloc_one(mm, address)	({ BUG(); ((pmd_t *)2); })
+/* FIXME two definition - look below */
+#define pmd_free(mm, x)			do { } while (0)
+#define pgd_populate(mm, pmd, pte)	BUG()
+
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
+		unsigned long address)
+{
+	pte_t *pte;
+	extern int mem_init_done;
+	extern void *early_get_page(void);
+	if (mem_init_done) {
+		pte = (pte_t *)__get_free_page(GFP_KERNEL |
+					__GFP_REPEAT | __GFP_ZERO);
+	} else {
+		pte = (pte_t *)early_get_page();
+		if (pte)
+			clear_page(pte);
+	}
+	return pte;
+}
+
+static inline struct page *pte_alloc_one(struct mm_struct *mm,
+		unsigned long address)
+{
+	struct page *ptepage;
+
+#ifdef CONFIG_HIGHPTE
+	int flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_REPEAT;
+#else
+	int flags = GFP_KERNEL | __GFP_REPEAT;
+#endif
+
+	ptepage = alloc_pages(flags, 0);
+	if (ptepage)
+		clear_highpage(ptepage);
+	return ptepage;
+}
+
+static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm,
+		unsigned long address)
+{
+	unsigned long *ret;
+
+	ret = pte_quicklist;
+	if (ret != NULL) {
+		pte_quicklist = (unsigned long *)(*ret);
+		ret[0] = 0;
+		pgtable_cache_size--;
+	}
+	return (pte_t *)ret;
+}
+
+extern inline void pte_free_fast(pte_t *pte)
+{
+	*(unsigned long **)pte = pte_quicklist;
+	pte_quicklist = (unsigned long *) pte;
+	pgtable_cache_size++;
+}
+
+extern inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
+{
+	free_page((unsigned long)pte);
+}
+
+extern inline void pte_free_slow(struct page *ptepage)
+{
+	__free_page(ptepage);
+}
+
+extern inline void pte_free(struct mm_struct *mm, struct page *ptepage)
+{
+	__free_page(ptepage);
+}
+
+#define __pte_free_tlb(tlb, pte)	pte_free((tlb)->mm, (pte))
+
+#define pmd_populate(mm, pmd, pte)	(pmd_val(*(pmd)) = page_address(pte))
+
+#define pmd_populate_kernel(mm, pmd, pte) \
+		(pmd_val(*(pmd)) = (unsigned long) (pte))
+
+/*
+ * We don't have any real pmd's, and this code never triggers because
+ * the pgd will always be present..
+ */
+#define pmd_alloc_one(mm, address)	({ BUG(); ((pmd_t *)2); })
+/*#define pmd_free(mm, x)			do { } while (0)*/
+#define __pmd_free_tlb(tlb, x)		do { } while (0)
+#define pgd_populate(mm, pmd, pte)	BUG()
+
+extern int do_check_pgt_cache(int, int);
+
+#endif /* CONFIG_MMU */
+
 #define check_pgt_cache()	do {} while (0)
 
 #endif /* _ASM_MICROBLAZE_PGALLOC_H */
diff --git a/arch/microblaze/include/asm/pgtable.h b/arch/microblaze/include/asm/pgtable.h
index 4df31e4..4c57a58 100644
--- a/arch/microblaze/include/asm/pgtable.h
+++ b/arch/microblaze/include/asm/pgtable.h
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -14,6 +16,8 @@
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 
+#ifndef CONFIG_MMU
+
 #define pgd_present(pgd)	(1) /* pages are always present on non MMU */
 #define pgd_none(pgd)		(0)
 #define pgd_bad(pgd)		(0)
@@ -27,6 +31,8 @@
 #define PAGE_READONLY		__pgprot(0) /* these mean nothing to non MMU */
 #define PAGE_KERNEL		__pgprot(0) /* these mean nothing to non MMU */
 
+#define pgprot_noncached(x)	(x)
+
 #define __swp_type(x)		(0)
 #define __swp_offset(x)		(0)
 #define __swp_entry(typ, off)	((swp_entry_t) { ((typ) | ((off) << 7)) })
@@ -45,6 +51,538 @@
 
 #define arch_enter_lazy_cpu_mode()	do {} while (0)
 
+#else /* CONFIG_MMU */
+
+#include <asm-generic/4level-fixup.h>
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#include <linux/sched.h>
+#include <linux/threads.h>
+#include <asm/processor.h>		/* For TASK_SIZE */
+#include <asm/mmu.h>
+#include <asm/page.h>
+
+#define FIRST_USER_ADDRESS	0
+
+extern unsigned long va_to_phys(unsigned long address);
+extern pte_t *va_to_pte(unsigned long address);
+extern unsigned long ioremap_bot, ioremap_base;
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+
+static inline int pte_special(pte_t pte)	{ return 0; }
+
+static inline pte_t pte_mkspecial(pte_t pte)	{ return pte; }
+
+/* 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_END	ioremap_bot
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * The MicroBlaze MMU is identical to the PPC-40x MMU, and uses a hash
+ * table containing PTEs, together with a set of 16 segment registers, to
+ * define the virtual to physical address mapping.
+ *
+ * We use the hash table as an extended TLB, i.e. a cache of currently
+ * active mappings.  We maintain a two-level page table tree, much
+ * like that used by the i386, for the sake of the Linux memory
+ * management code.  Low-level assembler code in hashtable.S
+ * (procedure hash_page) is responsible for extracting ptes from the
+ * tree and putting them into the hash table when necessary, and
+ * updating the accessed and modified bits in the page table tree.
+ */
+
+/*
+ * The MicroBlaze processor has a TLB architecture identical to PPC-40x. The
+ * instruction and data sides share a unified, 64-entry, semi-associative
+ * TLB which is maintained totally under software control. In addition, the
+ * instruction side has a hardware-managed, 2,4, or 8-entry, fully-associative
+ * TLB which serves as a first level to the shared TLB. These two TLBs are
+ * known as the UTLB and ITLB, respectively (see "mmu.h" for definitions).
+ */
+
+/*
+ * The normal case is that PTEs are 32-bits and we have a 1-page
+ * 1024-entry pgdir pointing to 1-page 1024-entry PTE pages.  -- paulus
+ *
+ */
+
+/* PMD_SHIFT determines the size of the area mapped by the PTE pages */
+#define PMD_SHIFT	(PAGE_SHIFT + PTE_SHIFT)
+#define PMD_SIZE	(1UL << PMD_SHIFT)
+#define PMD_MASK	(~(PMD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a top-level page table entry can map */
+#define PGDIR_SHIFT	PMD_SHIFT
+#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+
+/*
+ * entries per page directory level: our page-table tree is two-level, so
+ * we don't really have any PMD directory.
+ */
+#define PTRS_PER_PTE	(1 << PTE_SHIFT)
+#define PTRS_PER_PMD	1
+#define PTRS_PER_PGD	(1 << (32 - PGDIR_SHIFT))
+
+#define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
+#define FIRST_USER_PGD_NR	0
+
+#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
+#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
+
+#define pte_ERROR(e) \
+	printk(KERN_ERR "%s:%d: bad pte "PTE_FMT".\n", \
+		__FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+	printk(KERN_ERR "%s:%d: bad pmd %08lx.\n", \
+		__FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+	printk(KERN_ERR "%s:%d: bad pgd %08lx.\n", \
+		__FILE__, __LINE__, pgd_val(e))
+
+/*
+ * Bits in a linux-style PTE.  These match the bits in the
+ * (hardware-defined) PTE as closely as possible.
+ */
+
+/* There are several potential gotchas here.  The hardware TLBLO
+ * field looks like this:
+ *
+ * 0  1  2  3  4  ... 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ * RPN.....................  0  0 EX WR ZSEL.......  W  I  M  G
+ *
+ * Where possible we make the Linux PTE bits match up with this
+ *
+ * - bits 20 and 21 must be cleared, because we use 4k pages (4xx can
+ * support down to 1k pages), this is done in the TLBMiss exception
+ * handler.
+ * - We use only zones 0 (for kernel pages) and 1 (for user pages)
+ * of the 16 available.  Bit 24-26 of the TLB are cleared in the TLB
+ * miss handler.  Bit 27 is PAGE_USER, thus selecting the correct
+ * zone.
+ * - PRESENT *must* be in the bottom two bits because swap cache
+ * entries use the top 30 bits.  Because 4xx doesn't support SMP
+ * anyway, M is irrelevant so we borrow it for PAGE_PRESENT.  Bit 30
+ * is cleared in the TLB miss handler before the TLB entry is loaded.
+ * - All other bits of the PTE are loaded into TLBLO without
+ *  * modification, leaving us only the bits 20, 21, 24, 25, 26, 30 for
+ * software PTE bits.  We actually use use bits 21, 24, 25, and
+ * 30 respectively for the software bits: ACCESSED, DIRTY, RW, and
+ * PRESENT.
+ */
+
+/* Definitions for MicroBlaze. */
+#define	_PAGE_GUARDED	0x001	/* G: page is guarded from prefetch */
+#define _PAGE_PRESENT	0x002	/* software: PTE contains a translation */
+#define	_PAGE_NO_CACHE	0x004	/* I: caching is inhibited */
+#define	_PAGE_WRITETHRU	0x008	/* W: caching is write-through */
+#define	_PAGE_USER	0x010	/* matches one of the zone permission bits */
+#define	_PAGE_RW	0x040	/* software: Writes permitted */
+#define	_PAGE_DIRTY	0x080	/* software: dirty page */
+#define _PAGE_HWWRITE	0x100	/* hardware: Dirty & RW, set in exception */
+#define _PAGE_HWEXEC	0x200	/* hardware: EX permission */
+#define _PAGE_ACCESSED	0x400	/* software: R: page referenced */
+#define _PMD_PRESENT	PAGE_MASK
+
+/*
+ * Some bits are unused...
+ */
+#ifndef _PAGE_HASHPTE
+#define _PAGE_HASHPTE	0
+#endif
+#ifndef _PTE_NONE_MASK
+#define _PTE_NONE_MASK	0
+#endif
+#ifndef _PAGE_SHARED
+#define _PAGE_SHARED	0
+#endif
+#ifndef _PAGE_HWWRITE
+#define _PAGE_HWWRITE	0
+#endif
+#ifndef _PAGE_HWEXEC
+#define _PAGE_HWEXEC	0
+#endif
+#ifndef _PAGE_EXEC
+#define _PAGE_EXEC	0
+#endif
+
+#define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+/*
+ * Note: the _PAGE_COHERENT bit automatically gets set in the hardware
+ * PTE if CONFIG_SMP is defined (hash_page does this); there is no need
+ * to have it in the Linux PTE, and in fact the bit could be reused for
+ * another purpose.  -- paulus.
+ */
+#define _PAGE_BASE	(_PAGE_PRESENT | _PAGE_ACCESSED)
+#define _PAGE_WRENABLE	(_PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE)
+
+#define _PAGE_KERNEL \
+	(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED | _PAGE_HWEXEC)
+
+#define _PAGE_IO	(_PAGE_KERNEL | _PAGE_NO_CACHE | _PAGE_GUARDED)
+
+#define PAGE_NONE	__pgprot(_PAGE_BASE)
+#define PAGE_READONLY	__pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_READONLY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
+#define PAGE_SHARED_X \
+		__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC)
+#define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_COPY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+
+#define PAGE_KERNEL	__pgprot(_PAGE_KERNEL)
+#define PAGE_KERNEL_RO	__pgprot(_PAGE_BASE | _PAGE_SHARED)
+#define PAGE_KERNEL_CI	__pgprot(_PAGE_IO)
+
+/*
+ * We consider execute permission the same as read.
+ * Also, write permissions imply read permissions.
+ */
+#define __P000	PAGE_NONE
+#define __P001	PAGE_READONLY_X
+#define __P010	PAGE_COPY
+#define __P011	PAGE_COPY_X
+#define __P100	PAGE_READONLY
+#define __P101	PAGE_READONLY_X
+#define __P110	PAGE_COPY
+#define __P111	PAGE_COPY_X
+
+#define __S000	PAGE_NONE
+#define __S001	PAGE_READONLY_X
+#define __S010	PAGE_SHARED
+#define __S011	PAGE_SHARED_X
+#define __S100	PAGE_READONLY
+#define __S101	PAGE_READONLY_X
+#define __S110	PAGE_SHARED
+#define __S111	PAGE_SHARED_X
+
+#ifndef __ASSEMBLY__
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[1024];
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+#endif /* __ASSEMBLY__ */
+
+#define pte_none(pte)		((pte_val(pte) & ~_PTE_NONE_MASK) == 0)
+#define pte_present(pte)	(pte_val(pte) & _PAGE_PRESENT)
+#define pte_clear(mm, addr, ptep) \
+	do { set_pte_at((mm), (addr), (ptep), __pte(0)); } while (0)
+
+#define pmd_none(pmd)		(!pmd_val(pmd))
+#define	pmd_bad(pmd)		((pmd_val(pmd) & _PMD_PRESENT) == 0)
+#define	pmd_present(pmd)	((pmd_val(pmd) & _PMD_PRESENT) != 0)
+#define	pmd_clear(pmdp)		do { pmd_val(*(pmdp)) = 0; } while (0)
+
+#define pte_page(x)		(mem_map + (unsigned long) \
+				((pte_val(x) - memory_start) >> PAGE_SHIFT))
+#define PFN_SHIFT_OFFSET	(PAGE_SHIFT)
+
+#define pte_pfn(x)		(pte_val(x) >> PFN_SHIFT_OFFSET)
+
+#define pfn_pte(pfn, prot) \
+	__pte(((pte_basic_t)(pfn) << PFN_SHIFT_OFFSET) | pgprot_val(prot))
+
+#ifndef __ASSEMBLY__
+/*
+ * The "pgd_xxx()" functions here are trivial for a folded two-level
+ * setup: the pgd is never bad, and a pmd always exists (as it's folded
+ * into the pgd entry)
+ */
+static inline int pgd_none(pgd_t pgd)		{ return 0; }
+static inline int pgd_bad(pgd_t pgd)		{ return 0; }
+static inline int pgd_present(pgd_t pgd)	{ return 1; }
+#define pgd_clear(xp)				do { } while (0)
+#define pgd_page(pgd) \
+	((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+static inline int pte_read(pte_t pte)  { return pte_val(pte) & _PAGE_USER; }
+static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
+static inline int pte_exec(pte_t pte)  { return pte_val(pte) & _PAGE_EXEC; }
+static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
+/* FIXME */
+static inline int pte_file(pte_t pte)		{ return 0; }
+
+static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
+static inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
+
+static inline pte_t pte_rdprotect(pte_t pte) \
+		{ pte_val(pte) &= ~_PAGE_USER; return pte; }
+static inline pte_t pte_wrprotect(pte_t pte) \
+	{ pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; }
+static inline pte_t pte_exprotect(pte_t pte) \
+	{ pte_val(pte) &= ~_PAGE_EXEC; return pte; }
+static inline pte_t pte_mkclean(pte_t pte) \
+	{ pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; }
+static inline pte_t pte_mkold(pte_t pte) \
+	{ pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+
+static inline pte_t pte_mkread(pte_t pte) \
+	{ pte_val(pte) |= _PAGE_USER; return pte; }
+static inline pte_t pte_mkexec(pte_t pte) \
+	{ pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; }
+static inline pte_t pte_mkwrite(pte_t pte) \
+	{ pte_val(pte) |= _PAGE_RW; return pte; }
+static inline pte_t pte_mkdirty(pte_t pte) \
+	{ pte_val(pte) |= _PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkyoung(pte_t pte) \
+	{ pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+
+static inline pte_t mk_pte_phys(phys_addr_t physpage, pgprot_t pgprot)
+{
+	pte_t pte;
+	pte_val(pte) = physpage | pgprot_val(pgprot);
+	return pte;
+}
+
+#define mk_pte(page, pgprot) \
+({									   \
+	pte_t pte;							   \
+	pte_val(pte) = (((page - mem_map) << PAGE_SHIFT) + memory_start) |  \
+			pgprot_val(pgprot);				   \
+	pte;								   \
+})
+
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+	pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
+	return pte;
+}
+
+/*
+ * Atomic PTE updates.
+ *
+ * pte_update clears and sets bit atomically, and returns
+ * the old pte value.
+ * The ((unsigned long)(p+1) - 4) hack is to get to the least-significant
+ * 32 bits of the PTE regardless of whether PTEs are 32 or 64 bits.
+ */
+static inline unsigned long pte_update(pte_t *p, unsigned long clr,
+				unsigned long set)
+{
+	unsigned long old, tmp, msr;
+
+	__asm__ __volatile__("\
+	msrclr	%2, 0x2\n\
+	nop\n\
+	lw	%0, %4, r0\n\
+	andn	%1, %0, %5\n\
+	or	%1, %1, %6\n\
+	sw	%1, %4, r0\n\
+	mts     rmsr, %2\n\
+	nop"
+	: "=&r" (old), "=&r" (tmp), "=&r" (msr), "=m" (*p)
+	: "r" ((unsigned long)(p+1) - 4), "r" (clr), "r" (set), "m" (*p)
+	: "cc");
+
+	return old;
+}
+
+/*
+ * set_pte stores a linux PTE into the linux page table.
+ */
+static inline void set_pte(struct mm_struct *mm, unsigned long addr,
+		pte_t *ptep, pte_t pte)
+{
+	*ptep = pte;
+}
+
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+		pte_t *ptep, pte_t pte)
+{
+	*ptep = pte;
+}
+
+static inline int ptep_test_and_clear_young(struct mm_struct *mm,
+		unsigned long addr, pte_t *ptep)
+{
+	return (pte_update(ptep, _PAGE_ACCESSED, 0) & _PAGE_ACCESSED) != 0;
+}
+
+static inline int ptep_test_and_clear_dirty(struct mm_struct *mm,
+		unsigned long addr, pte_t *ptep)
+{
+	return (pte_update(ptep, \
+		(_PAGE_DIRTY | _PAGE_HWWRITE), 0) & _PAGE_DIRTY) != 0;
+}
+
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
+		unsigned long addr, pte_t *ptep)
+{
+	return __pte(pte_update(ptep, ~_PAGE_HASHPTE, 0));
+}
+
+/*static inline void ptep_set_wrprotect(struct mm_struct *mm,
+		unsigned long addr, pte_t *ptep)
+{
+	pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), 0);
+}*/
+
+static inline void ptep_mkdirty(struct mm_struct *mm,
+		unsigned long addr, pte_t *ptep)
+{
+	pte_update(ptep, 0, _PAGE_DIRTY);
+}
+
+/*#define pte_same(A,B)	(((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0)*/
+
+/* Convert pmd entry to page */
+/* our pmd entry is an effective address of pte table*/
+/* returns effective address of the pmd entry*/
+#define pmd_page_kernel(pmd)	((unsigned long) (pmd_val(pmd) & PAGE_MASK))
+
+/* returns struct *page of the pmd entry*/
+#define pmd_page(pmd)	(pfn_to_page(__pa(pmd_val(pmd)) >> PAGE_SHIFT))
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+/* to find an entry in a page-table-directory */
+#define pgd_index(address)	 ((address) >> PGDIR_SHIFT)
+#define pgd_offset(mm, address)	 ((mm)->pgd + pgd_index(address))
+
+/* Find an entry in the second-level page table.. */
+static inline pmd_t *pmd_offset(pgd_t *dir, unsigned long address)
+{
+	return (pmd_t *) dir;
+}
+
+/* Find an entry in the third-level page table.. */
+#define pte_index(address)		\
+	(((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset_kernel(dir, addr)	\
+	((pte_t *) pmd_page_kernel(*(dir)) + pte_index(addr))
+#define pte_offset_map(dir, addr)		\
+	((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE0) + pte_index(addr))
+#define pte_offset_map_nested(dir, addr)	\
+	((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE1) + pte_index(addr))
+
+#define pte_unmap(pte)		kunmap_atomic(pte, KM_PTE0)
+#define pte_unmap_nested(pte)	kunmap_atomic(pte, KM_PTE1)
+
+/* Encode and decode a nonlinear file mapping entry */
+#define PTE_FILE_MAX_BITS	29
+#define pte_to_pgoff(pte)	(pte_val(pte) >> 3)
+#define pgoff_to_pte(off)	((pte_t) { ((off) << 3) })
+
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
+/*
+ * When flushing the tlb entry for a page, we also need to flush the hash
+ * table entry.  flush_hash_page is assembler (for speed) in hashtable.S.
+ */
+extern int flush_hash_page(unsigned context, unsigned long va, pte_t *ptep);
+
+/* Add an HPTE to the hash table */
+extern void add_hash_page(unsigned context, unsigned long va, pte_t *ptep);
+
+/*
+ * Encode and decode a swap entry.
+ * Note that the bits we use in a PTE for representing a swap entry
+ * must not include the _PAGE_PRESENT bit, or the _PAGE_HASHPTE bit
+ * (if used).  -- paulus
+ */
+#define __swp_type(entry)		((entry).val & 0x3f)
+#define __swp_offset(entry)	((entry).val >> 6)
+#define __swp_entry(type, offset) \
+		((swp_entry_t) { (type) | ((offset) << 6) })
+#define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) >> 2 })
+#define __swp_entry_to_pte(x)	((pte_t) { (x).val << 2 })
+
+
+/* CONFIG_APUS */
+/* For virtual address to physical address conversion */
+extern void cache_clear(__u32 addr, int length);
+extern void cache_push(__u32 addr, int length);
+extern int mm_end_of_chunk(unsigned long addr, int len);
+extern unsigned long iopa(unsigned long addr);
+/* extern unsigned long mm_ptov(unsigned long addr) \
+	__attribute__ ((const)); TBD */
+
+/* Values for nocacheflag and cmode */
+/* These are not used by the APUS kernel_map, but prevents
+ * compilation errors.
+ */
+#define	IOMAP_FULL_CACHING	0
+#define	IOMAP_NOCACHE_SER	1
+#define	IOMAP_NOCACHE_NONSER	2
+#define	IOMAP_NO_COPYBACK	3
+
+/*
+ * Map some physical address range into the kernel address space.
+ */
+extern unsigned long kernel_map(unsigned long paddr, unsigned long size,
+				int nocacheflag, unsigned long *memavailp);
+
+/*
+ * Set cache mode of (kernel space) address range.
+ */
+extern void kernel_set_cachemode(unsigned long address, unsigned long size,
+				unsigned int cmode);
+
+/* 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
+ */
+#define pgtable_cache_init()	do { } while (0)
+
+void do_page_fault(struct pt_regs *regs, unsigned long address,
+		   unsigned long error_code);
+
+void __init io_block_mapping(unsigned long virt, phys_addr_t phys,
+			     unsigned int size, int flags);
+
+void __init adjust_total_lowmem(void);
+void mapin_ram(void);
+int map_page(unsigned long va, phys_addr_t pa, int flags);
+
+extern int mem_init_done;
+extern unsigned long ioremap_base;
+extern unsigned long ioremap_bot;
+
+asmlinkage void __init mmu_init(void);
+
+void __init *early_get_page(void);
+
+void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle);
+void consistent_free(void *vaddr);
+void consistent_sync(void *vaddr, size_t size, int direction);
+void consistent_sync_page(struct page *page, unsigned long offset,
+	size_t size, int direction);
+#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+
+#endif /* CONFIG_MMU */
+
 #ifndef __ASSEMBLY__
 #include <asm-generic/pgtable.h>
 
diff --git a/arch/microblaze/include/asm/posix_types.h b/arch/microblaze/include/asm/posix_types.h
index b4df41c..8c758b2 100644
--- a/arch/microblaze/include/asm/posix_types.h
+++ b/arch/microblaze/include/asm/posix_types.h
@@ -16,7 +16,7 @@
  */
 
 typedef unsigned long	__kernel_ino_t;
-typedef unsigned int	__kernel_mode_t;
+typedef unsigned short	__kernel_mode_t;
 typedef unsigned int	__kernel_nlink_t;
 typedef long		__kernel_off_t;
 typedef int		__kernel_pid_t;
diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h
index 9329029..563c6b9 100644
--- a/arch/microblaze/include/asm/processor.h
+++ b/arch/microblaze/include/asm/processor.h
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2008 Michal Simek
- * Copyright (C) 2008 PetaLogix
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -26,14 +26,15 @@
 # define cpu_sleep()		do {} while (0)
 # define prepare_to_copy(tsk)	do {} while (0)
 
-# endif /* __ASSEMBLY__ */
-
 #define task_pt_regs(tsk) \
 		(((struct pt_regs *)(THREAD_SIZE + task_stack_page(tsk))) - 1)
 
 /* Do necessary setup to start up a newly executed thread. */
 void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp);
 
+# endif /* __ASSEMBLY__ */
+
+# ifndef CONFIG_MMU
 /*
  * User space process size: memory size
  *
@@ -85,4 +86,90 @@
 # define KSTK_EIP(tsk)	(0)
 # define KSTK_ESP(tsk)	(0)
 
+# else /* CONFIG_MMU */
+
+/*
+ * This is used to define STACK_TOP, and with MMU it must be below
+ * kernel base to select the correct PGD when handling MMU exceptions.
+ */
+# define TASK_SIZE	(CONFIG_KERNEL_START)
+
+/*
+ * This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+# define TASK_UNMAPPED_BASE	(TASK_SIZE / 8 * 3)
+
+# define THREAD_KSP	0
+
+#  ifndef __ASSEMBLY__
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#  define current_text_addr()	({ __label__ _l; _l: &&_l; })
+
+/* If you change this, you must change the associated assembly-languages
+ * constants defined below, THREAD_*.
+ */
+struct thread_struct {
+	/* kernel stack pointer (must be first field in structure) */
+	unsigned long	ksp;
+	unsigned long	ksp_limit;	/* if ksp <= ksp_limit stack overflow */
+	void		*pgdir;		/* root of page-table tree */
+	struct pt_regs	*regs;		/* Pointer to saved register state */
+};
+
+#  define INIT_THREAD { \
+	.ksp   = sizeof init_stack + (unsigned long)init_stack, \
+	.pgdir = swapper_pg_dir, \
+}
+
+/* Do necessary setup to start up a newly executed thread.  */
+void start_thread(struct pt_regs *regs,
+		unsigned long pc, unsigned long usp);
+
+/* Free all resources held by a thread. */
+extern inline void release_thread(struct task_struct *dead_task)
+{
+}
+
+extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+
+/* Free current thread data structures etc.  */
+static inline void exit_thread(void)
+{
+}
+
+/* Return saved (kernel) PC of a blocked thread.  */
+#  define thread_saved_pc(tsk)	\
+	((tsk)->thread.regs ? (tsk)->thread.regs->r15 : 0)
+
+unsigned long get_wchan(struct task_struct *p);
+
+/* The size allocated for kernel stacks. This _must_ be a power of two! */
+# define KERNEL_STACK_SIZE	0x2000
+
+/* Return some info about the user process TASK.  */
+#  define task_tos(task)	((unsigned long)(task) + KERNEL_STACK_SIZE)
+#  define task_regs(task) ((struct pt_regs *)task_tos(task) - 1)
+
+#  define task_pt_regs_plus_args(tsk) \
+	(((void *)task_pt_regs(tsk)) - STATE_SAVE_ARG_SPACE)
+
+#  define task_sp(task)	(task_regs(task)->r1)
+#  define task_pc(task)	(task_regs(task)->pc)
+/* Grotty old names for some.  */
+#  define KSTK_EIP(task)	(task_pc(task))
+#  define KSTK_ESP(task)	(task_sp(task))
+
+/* FIXME */
+#  define deactivate_mm(tsk, mm)	do { } while (0)
+
+#  define STACK_TOP	TASK_SIZE
+#  define STACK_TOP_MAX	STACK_TOP
+
+#  endif /* __ASSEMBLY__ */
+# endif /* CONFIG_MMU */
 #endif /* _ASM_MICROBLAZE_PROCESSOR_H */
diff --git a/arch/microblaze/include/asm/ptrace.h b/arch/microblaze/include/asm/ptrace.h
index 55015bc..a917dc5 100644
--- a/arch/microblaze/include/asm/ptrace.h
+++ b/arch/microblaze/include/asm/ptrace.h
@@ -10,7 +10,6 @@
 #define _ASM_MICROBLAZE_PTRACE_H
 
 #ifndef __ASSEMBLY__
-#include <linux/types.h>
 
 typedef unsigned long microblaze_reg_t;
 
diff --git a/arch/microblaze/include/asm/registers.h b/arch/microblaze/include/asm/registers.h
index 834142d..68c3afb 100644
--- a/arch/microblaze/include/asm/registers.h
+++ b/arch/microblaze/include/asm/registers.h
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2008 Michal Simek
- * Copyright (C) 2008 PetaLogix
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -30,4 +30,21 @@
 #define FSR_UF		(1<<1) /* Underflow */
 #define FSR_DO		(1<<0) /* Denormalized operand error */
 
+# ifdef CONFIG_MMU
+/* Machine State Register (MSR) Fields */
+# define MSR_UM		(1<<11) /* User Mode */
+# define MSR_UMS	(1<<12) /* User Mode Save */
+# define MSR_VM		(1<<13) /* Virtual Mode */
+# define MSR_VMS	(1<<14) /* Virtual Mode Save */
+
+# define MSR_KERNEL	(MSR_EE | MSR_VM)
+/* # define MSR_USER	(MSR_KERNEL | MSR_UM | MSR_IE) */
+# define MSR_KERNEL_VMS	(MSR_EE | MSR_VMS)
+/* # define MSR_USER_VMS	(MSR_KERNEL_VMS | MSR_UMS | MSR_IE) */
+
+/* Exception State Register (ESR) Fields */
+# define	  ESR_DIZ	(1<<11) /* Zone Protection */
+# define	  ESR_S		(1<<10) /* Store instruction */
+
+# endif /* CONFIG_MMU */
 #endif /* _ASM_MICROBLAZE_REGISTERS_H */
diff --git a/arch/microblaze/include/asm/sections.h b/arch/microblaze/include/asm/sections.h
index 8434a43..4487e15 100644
--- a/arch/microblaze/include/asm/sections.h
+++ b/arch/microblaze/include/asm/sections.h
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -14,6 +16,7 @@
 # ifndef __ASSEMBLY__
 extern char _ssbss[], _esbss[];
 extern unsigned long __ivt_start[], __ivt_end[];
+extern char _etext[], _stext[];
 
 #  ifdef CONFIG_MTD_UCLINUX
 extern char *_ebss;
diff --git a/arch/microblaze/include/asm/segment.h b/arch/microblaze/include/asm/segment.h
index 7f5dcc5..0e7102c 100644
--- a/arch/microblaze/include/asm/segment.h
+++ b/arch/microblaze/include/asm/segment.h
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2008 Michal Simek
- * Copyright (C) 2008 PetaLogix
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -11,7 +11,7 @@
 #ifndef _ASM_MICROBLAZE_SEGMENT_H
 #define _ASM_MICROBLAZE_SEGMENT_H
 
-#ifndef __ASSEMBLY__
+# ifndef __ASSEMBLY__
 
 typedef struct {
 	unsigned long seg;
@@ -29,15 +29,21 @@
  *
  * For non-MMU arch like Microblaze, KERNEL_DS and USER_DS is equal.
  */
-#  define KERNEL_DS	((mm_segment_t){0})
+# define MAKE_MM_SEG(s)       ((mm_segment_t) { (s) })
+
+#  ifndef CONFIG_MMU
+#  define KERNEL_DS	MAKE_MM_SEG(0)
 #  define USER_DS	KERNEL_DS
+#  else
+#  define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFF)
+#  define USER_DS	MAKE_MM_SEG(TASK_SIZE - 1)
+#  endif
 
 # define get_ds()	(KERNEL_DS)
 # define get_fs()	(current_thread_info()->addr_limit)
-# define set_fs(x) \
-		do { current_thread_info()->addr_limit = (x); } while (0)
+# define set_fs(val)	(current_thread_info()->addr_limit = (val))
 
-# define segment_eq(a, b)		((a).seg == (b).seg)
+# define segment_eq(a, b)	((a).seg == (b).seg)
 
 # endif /* __ASSEMBLY__ */
 #endif /* _ASM_MICROBLAZE_SEGMENT_H */
diff --git a/arch/microblaze/include/asm/setup.h b/arch/microblaze/include/asm/setup.h
index 9b98e8e..27f8daf 100644
--- a/arch/microblaze/include/asm/setup.h
+++ b/arch/microblaze/include/asm/setup.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2007-2008 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -18,7 +19,6 @@
 extern unsigned int boot_cpuid; /* move to smp.h */
 
 extern char cmd_line[COMMAND_LINE_SIZE];
-#  endif/* __KERNEL__ */
 
 void early_printk(const char *fmt, ...);
 
@@ -30,6 +30,11 @@
 
 unsigned long long sched_clock(void);
 
+#   ifdef CONFIG_MMU
+extern void mmu_reset(void);
+extern void early_console_reg_tlb_alloc(unsigned int addr);
+#   endif /* CONFIG_MMU */
+
 void time_init(void);
 void init_IRQ(void);
 void machine_early_init(const char *cmdline, unsigned int ram,
@@ -40,5 +45,6 @@
 void machine_halt(void);
 void machine_power_off(void);
 
+#  endif/* __KERNEL__ */
 # endif /* __ASSEMBLY__ */
 #endif /* _ASM_MICROBLAZE_SETUP_H */
diff --git a/arch/microblaze/include/asm/signal.h b/arch/microblaze/include/asm/signal.h
index 9676fad..46bc226 100644
--- a/arch/microblaze/include/asm/signal.h
+++ b/arch/microblaze/include/asm/signal.h
@@ -90,7 +90,7 @@
 
 # ifndef __ASSEMBLY__
 # include <linux/types.h>
-# include <asm-generic/signal.h>
+# include <asm-generic/signal-defs.h>
 
 /* Avoid too many header ordering problems. */
 struct siginfo;
diff --git a/arch/microblaze/include/asm/stat.h b/arch/microblaze/include/asm/stat.h
index 5f18b8a..a15f775 100644
--- a/arch/microblaze/include/asm/stat.h
+++ b/arch/microblaze/include/asm/stat.h
@@ -16,58 +16,53 @@
 
 #include <linux/posix_types.h>
 
+#define STAT_HAVE_NSEC 1
+
 struct stat {
-	unsigned int	st_dev;
+	unsigned long	st_dev;
 	unsigned long	st_ino;
 	unsigned int	st_mode;
 	unsigned int	st_nlink;
 	unsigned int	st_uid;
 	unsigned int	st_gid;
-	unsigned int	st_rdev;
-	unsigned long	st_size;
-	unsigned long	st_blksize;
-	unsigned long	st_blocks;
-	unsigned long	st_atime;
-	unsigned long	__unused1; /* unsigned long  st_atime_nsec */
-	unsigned long	st_mtime;
-	unsigned long	__unused2; /* unsigned long  st_mtime_nsec */
-	unsigned long	st_ctime;
-	unsigned long	__unused3; /* unsigned long  st_ctime_nsec */
+	unsigned long	st_rdev;
+	unsigned long	__pad1;
+	long		st_size;
+	int		st_blksize;
+	int		__pad2;
+	long		st_blocks;
+	int		st_atime;
+	unsigned int	st_atime_nsec;
+	int		st_mtime;
+	unsigned int	st_mtime_nsec;
+	int		st_ctime;
+	unsigned int	st_ctime_nsec;
 	unsigned long	__unused4;
 	unsigned long	__unused5;
 };
 
 struct stat64 {
-	unsigned long long	st_dev;
-	unsigned long	__unused1;
-
-	unsigned long long	st_ino;
-
-	unsigned int	st_mode;
-	unsigned int	st_nlink;
-
-	unsigned int	st_uid;
-	unsigned int	st_gid;
-
-	unsigned long long	st_rdev;
-	unsigned long	__unused3;
-
-	long long	st_size;
-	unsigned long	st_blksize;
-
-	unsigned long	st_blocks; /* No. of 512-byte blocks allocated */
-	unsigned long	__unused4; /* future possible st_blocks high bits */
-
-	unsigned long	st_atime;
-	unsigned long	st_atime_nsec;
-
-	unsigned long	st_mtime;
-	unsigned long	st_mtime_nsec;
-
-	unsigned long	st_ctime;
-	unsigned long	st_ctime_nsec;
-
-	unsigned long	__unused8;
+	unsigned long long	st_dev;		/* Device.  */
+	unsigned long long	st_ino;		/* File serial number.  */
+	unsigned int		st_mode;	/* File mode.  */
+	unsigned int		st_nlink;	/* Link count.  */
+	unsigned int		st_uid;		/* User ID of the file's owner.  */
+	unsigned int		st_gid;		/* Group ID of the file's group. */
+	unsigned long long	st_rdev;	/* Device number, if device.  */
+	unsigned long long	__pad1;
+	long long		st_size;	/* Size of file, in bytes.  */
+	int			st_blksize;	/* Optimal block size for I/O.  */
+	int			__pad2;
+	long long		st_blocks;	/* Number 512-byte blocks allocated. */
+	int			st_atime;	/* Time of last access.  */
+	unsigned int		st_atime_nsec;
+	int			st_mtime;	/* Time of last modification.  */
+	unsigned int		st_mtime_nsec;
+	int			st_ctime;	/* Time of last status change.  */
+	unsigned int		st_ctime_nsec;
+	unsigned int		__unused4;
+	unsigned int		__unused5;
 };
 
 #endif /* _ASM_MICROBLAZE_STAT_H */
+
diff --git a/arch/microblaze/include/asm/string.h b/arch/microblaze/include/asm/string.h
index f7728c9..aec2f59 100644
--- a/arch/microblaze/include/asm/string.h
+++ b/arch/microblaze/include/asm/string.h
@@ -9,7 +9,7 @@
 #ifndef _ASM_MICROBLAZE_STRING_H
 #define _ASM_MICROBLAZE_STRING_H
 
-#ifndef __KERNEL__
+#ifdef __KERNEL__
 
 #define __HAVE_ARCH_MEMSET
 #define __HAVE_ARCH_MEMCPY
diff --git a/arch/microblaze/include/asm/syscalls.h b/arch/microblaze/include/asm/syscalls.h
index 9cb4ff0..ddea9eb 100644
--- a/arch/microblaze/include/asm/syscalls.h
+++ b/arch/microblaze/include/asm/syscalls.h
@@ -34,6 +34,9 @@
 asmlinkage int sys_sigaction(int sig, const struct old_sigaction *act,
 		struct old_sigaction *oact);
 
+asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act,
+		struct sigaction __user *oact, size_t sigsetsize);
+
 asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
 		struct pt_regs *regs);
 
diff --git a/arch/microblaze/include/asm/termios.h b/arch/microblaze/include/asm/termios.h
index 102d772..47a46d1 100644
--- a/arch/microblaze/include/asm/termios.h
+++ b/arch/microblaze/include/asm/termios.h
@@ -81,7 +81,7 @@
 
 #ifdef __KERNEL__
 
-#include <asm-generic/termios.h>
+#include <asm-generic/termios-base.h>
 
 #endif	/* __KERNEL__ */
 
diff --git a/arch/microblaze/include/asm/thread_info.h b/arch/microblaze/include/asm/thread_info.h
index 4c3943e..7fac444 100644
--- a/arch/microblaze/include/asm/thread_info.h
+++ b/arch/microblaze/include/asm/thread_info.h
@@ -122,6 +122,8 @@
 #define TIF_SINGLESTEP		4
 #define TIF_IRET		5 /* return with iret */
 #define TIF_MEMDIE		6
+#define TIF_SYSCALL_AUDIT	9       /* syscall auditing active */
+#define TIF_SECCOMP		10      /* secure computing */
 #define TIF_FREEZE		14	/* Freezing for suspend */
 
 /* FIXME change in entry.S */
@@ -138,10 +140,17 @@
 #define _TIF_IRET		(1<<TIF_IRET)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_FREEZE		(1<<TIF_FREEZE)
+#define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
+#define _TIF_SECCOMP		(1 << TIF_SECCOMP)
 #define _TIF_KERNEL_TRACE	(1 << TIF_KERNEL_TRACE)
 
+/* work to do in syscall trace */
+#define _TIF_WORK_SYSCALL_MASK  (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
+				 _TIF_SYSCALL_AUDIT | _TIF_SECCOMP)
+
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK		0x0000FFFE
+
 /* work to do on any return to u-space */
 #define _TIF_ALLWORK_MASK	0x0000FFFF
 
@@ -154,6 +163,17 @@
  */
 /* FPU was used by this task this quantum (SMP) */
 #define TS_USEDFPU		0x0001
+#define TS_RESTORE_SIGMASK	0x0002
+
+#ifndef __ASSEMBLY__
+#define HAVE_SET_RESTORE_SIGMASK 1
+static inline void set_restore_sigmask(void)
+{
+	struct thread_info *ti = current_thread_info();
+	ti->status |= TS_RESTORE_SIGMASK;
+	set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags);
+}
+#endif
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_MICROBLAZE_THREAD_INFO_H */
diff --git a/arch/microblaze/include/asm/tlb.h b/arch/microblaze/include/asm/tlb.h
index d1dfe37..c472d28 100644
--- a/arch/microblaze/include/asm/tlb.h
+++ b/arch/microblaze/include/asm/tlb.h
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -13,4 +15,10 @@
 
 #include <asm-generic/tlb.h>
 
+#ifdef CONFIG_MMU
+#define tlb_start_vma(tlb, vma)		do { } while (0)
+#define tlb_end_vma(tlb, vma)		do { } while (0)
+#define __tlb_remove_tlb_entry(tlb, pte, address) do { } while (0)
+#endif
+
 #endif /* _ASM_MICROBLAZE_TLB_H */
diff --git a/arch/microblaze/include/asm/tlbflush.h b/arch/microblaze/include/asm/tlbflush.h
index d7fe762..eb31a0e 100644
--- a/arch/microblaze/include/asm/tlbflush.h
+++ b/arch/microblaze/include/asm/tlbflush.h
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -9,6 +11,50 @@
 #ifndef _ASM_MICROBLAZE_TLBFLUSH_H
 #define _ASM_MICROBLAZE_TLBFLUSH_H
 
+#ifdef CONFIG_MMU
+
+#include <linux/sched.h>
+#include <linux/threads.h>
+#include <asm/processor.h>	/* For TASK_SIZE */
+#include <asm/mmu.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+
+extern void _tlbie(unsigned long address);
+extern void _tlbia(void);
+
+#define __tlbia()	_tlbia()
+
+static inline void local_flush_tlb_all(void)
+	{ __tlbia(); }
+static inline void local_flush_tlb_mm(struct mm_struct *mm)
+	{ __tlbia(); }
+static inline void local_flush_tlb_page(struct vm_area_struct *vma,
+				unsigned long vmaddr)
+	{ _tlbie(vmaddr); }
+static inline void local_flush_tlb_range(struct vm_area_struct *vma,
+		unsigned long start, unsigned long end)
+	{ __tlbia(); }
+
+#define flush_tlb_kernel_range(start, end)	do { } while (0)
+
+#define update_mmu_cache(vma, addr, pte)	do { } while (0)
+
+#define flush_tlb_all local_flush_tlb_all
+#define flush_tlb_mm local_flush_tlb_mm
+#define flush_tlb_page local_flush_tlb_page
+#define flush_tlb_range local_flush_tlb_range
+
+/*
+ * This is called in munmap when we have freed up some page-table
+ * pages.  We don't need to do anything here, there's nothing special
+ * about our page-table pages.  -- paulus
+ */
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+	unsigned long start, unsigned long end) { }
+
+#else /* CONFIG_MMU */
+
 #define flush_tlb()				BUG()
 #define flush_tlb_all()				BUG()
 #define flush_tlb_mm(mm)			BUG()
@@ -17,4 +63,6 @@
 #define flush_tlb_pgtables(mm, start, end)	BUG()
 #define flush_tlb_kernel_range(start, end)	BUG()
 
+#endif /* CONFIG_MMU */
+
 #endif /* _ASM_MICROBLAZE_TLBFLUSH_H */
diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h
index 5a3ffc3..65adad6 100644
--- a/arch/microblaze/include/asm/uaccess.h
+++ b/arch/microblaze/include/asm/uaccess.h
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -26,6 +28,10 @@
 #define VERIFY_READ	0
 #define VERIFY_WRITE	1
 
+#define __clear_user(addr, n)	(memset((void *)(addr), 0, (n)), 0)
+
+#ifndef CONFIG_MMU
+
 extern int ___range_ok(unsigned long addr, unsigned long size);
 
 #define __range_ok(addr, size) \
@@ -34,68 +40,68 @@
 #define access_ok(type, addr, size) (__range_ok((addr), (size)) == 0)
 #define __access_ok(add, size) (__range_ok((addr), (size)) == 0)
 
-extern inline int bad_user_access_length(void)
-{
-	return 0;
-}
+/* Undefined function to trigger linker error */
+extern int bad_user_access_length(void);
+
 /* FIXME this is function for optimalization -> memcpy */
-#define __get_user(var, ptr)					\
-	({							\
-		int __gu_err = 0;				\
-		switch (sizeof(*(ptr))) {			\
-		case 1:						\
-		case 2:						\
-		case 4:						\
-			(var) = *(ptr);				\
-			break;					\
-		case 8:						\
-			memcpy((void *) &(var), (ptr), 8);	\
-			break;					\
-		default:					\
-			(var) = 0;				\
-			__gu_err = __get_user_bad();		\
-			break;					\
-		}						\
-		__gu_err;					\
-	})
+#define __get_user(var, ptr)				\
+({							\
+	int __gu_err = 0;				\
+	switch (sizeof(*(ptr))) {			\
+	case 1:						\
+	case 2:						\
+	case 4:						\
+		(var) = *(ptr);				\
+		break;					\
+	case 8:						\
+		memcpy((void *) &(var), (ptr), 8);	\
+		break;					\
+	default:					\
+		(var) = 0;				\
+		__gu_err = __get_user_bad();		\
+		break;					\
+	}						\
+	__gu_err;					\
+})
 
 #define __get_user_bad()	(bad_user_access_length(), (-EFAULT))
 
+/* FIXME is not there defined __pu_val */
 #define __put_user(var, ptr)					\
-	({							\
-		int __pu_err = 0;				\
-		switch (sizeof(*(ptr))) {			\
-		case 1:						\
-		case 2:						\
-		case 4:						\
-			*(ptr) = (var);				\
-			break;					\
-		case 8: {					\
-			typeof(*(ptr)) __pu_val = var;		\
-			memcpy(ptr, &__pu_val, sizeof(__pu_val));\
-			}					\
-			break;					\
-		default:					\
-			__pu_err = __put_user_bad();		\
-			break;					\
-		}							\
-		__pu_err;						\
-	})
+({								\
+	int __pu_err = 0;					\
+	switch (sizeof(*(ptr))) {				\
+	case 1:							\
+	case 2:							\
+	case 4:							\
+		*(ptr) = (var);					\
+		break;						\
+	case 8: {						\
+		typeof(*(ptr)) __pu_val = (var);		\
+		memcpy(ptr, &__pu_val, sizeof(__pu_val));	\
+		}						\
+		break;						\
+	default:						\
+		__pu_err = __put_user_bad();			\
+		break;						\
+	}							\
+	__pu_err;						\
+})
 
 #define __put_user_bad()	(bad_user_access_length(), (-EFAULT))
 
-#define put_user(x, ptr)	__put_user(x, ptr)
-#define get_user(x, ptr)	__get_user(x, ptr)
+#define put_user(x, ptr)	__put_user((x), (ptr))
+#define get_user(x, ptr)	__get_user((x), (ptr))
 
-#define copy_to_user(to, from, n)		(memcpy(to, from, n), 0)
-#define copy_from_user(to, from, n)		(memcpy(to, from, n), 0)
+#define copy_to_user(to, from, n)	(memcpy((to), (from), (n)), 0)
+#define copy_from_user(to, from, n)	(memcpy((to), (from), (n)), 0)
 
-#define __copy_to_user(to, from, n)		(copy_to_user(to, from, n))
-#define __copy_from_user(to, from, n)		(copy_from_user(to, from, n))
-#define __copy_to_user_inatomic(to, from, n)	(__copy_to_user(to, from, n))
-#define __copy_from_user_inatomic(to, from, n)	(__copy_from_user(to, from, n))
-
-#define __clear_user(addr, n)	(memset((void *)addr, 0, n), 0)
+#define __copy_to_user(to, from, n)	(copy_to_user((to), (from), (n)))
+#define __copy_from_user(to, from, n)	(copy_from_user((to), (from), (n)))
+#define __copy_to_user_inatomic(to, from, n) \
+			(__copy_to_user((to), (from), (n)))
+#define __copy_from_user_inatomic(to, from, n) \
+			(__copy_from_user((to), (from), (n)))
 
 static inline unsigned long clear_user(void *addr, unsigned long size)
 {
@@ -104,13 +110,200 @@
 	return size;
 }
 
-/* Returns 0 if exception not found and fixup otherwise. */
+/* Returns 0 if exception not found and fixup otherwise.  */
 extern unsigned long search_exception_table(unsigned long);
 
+extern long strncpy_from_user(char *dst, const char *src, long count);
+extern long strnlen_user(const char *src, long count);
 
-extern long strncpy_from_user(char *dst, const char __user *src, long count);
-extern long strnlen_user(const char __user *src, long count);
-extern long __strncpy_from_user(char *dst, const char __user *src, long count);
+#else /* CONFIG_MMU */
+
+/*
+ * Address is valid if:
+ *  - "addr", "addr + size" and "size" are all below the limit
+ */
+#define access_ok(type, addr, size) \
+	(get_fs().seg > (((unsigned long)(addr)) | \
+		(size) | ((unsigned long)(addr) + (size))))
+
+/* || printk("access_ok failed for %s at 0x%08lx (size %d), seg 0x%08x\n",
+ type?"WRITE":"READ",addr,size,get_fs().seg)) */
+
+/*
+ * All the __XXX versions macros/functions below do not perform
+ * access checking. It is assumed that the necessary checks have been
+ * already performed before the finction (macro) is called.
+ */
+
+#define get_user(x, ptr)						\
+({									\
+	access_ok(VERIFY_READ, (ptr), sizeof(*(ptr)))			\
+		? __get_user((x), (ptr)) : -EFAULT;			\
+})
+
+#define put_user(x, ptr)						\
+({									\
+	access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr)))			\
+		? __put_user((x), (ptr)) : -EFAULT;			\
+})
+
+#define __get_user(x, ptr)						\
+({									\
+	unsigned long __gu_val;						\
+	/*unsigned long __gu_ptr = (unsigned long)(ptr);*/		\
+	long __gu_err;							\
+	switch (sizeof(*(ptr))) {					\
+	case 1:								\
+		__get_user_asm("lbu", (ptr), __gu_val, __gu_err);	\
+		break;							\
+	case 2:								\
+		__get_user_asm("lhu", (ptr), __gu_val, __gu_err);	\
+		break;							\
+	case 4:								\
+		__get_user_asm("lw", (ptr), __gu_val, __gu_err);	\
+		break;							\
+	default:							\
+		__gu_val = 0; __gu_err = -EINVAL;			\
+	}								\
+	x = (__typeof__(*(ptr))) __gu_val;				\
+	__gu_err;							\
+})
+
+#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err)		\
+({									\
+	__asm__ __volatile__ (						\
+			"1:"	insn	" %1, %2, r0;			\
+				addk	%0, r0, r0;			\
+			2:						\
+			.section .fixup,\"ax\";				\
+			3:	brid	2b;				\
+				addik	%0, r0, %3;			\
+			.previous;					\
+			.section __ex_table,\"a\";			\
+			.word	1b,3b;					\
+			.previous;"					\
+		: "=r"(__gu_err), "=r"(__gu_val)			\
+		: "r"(__gu_ptr), "i"(-EFAULT)				\
+	);								\
+})
+
+#define __put_user(x, ptr)						\
+({									\
+	__typeof__(*(ptr)) __gu_val = x;				\
+	long __gu_err = 0;						\
+	switch (sizeof(__gu_val)) {					\
+	case 1:								\
+		__put_user_asm("sb", (ptr), __gu_val, __gu_err);	\
+		break;							\
+	case 2: 							\
+		__put_user_asm("sh", (ptr), __gu_val, __gu_err);	\
+		break;							\
+	case 4:								\
+		__put_user_asm("sw", (ptr), __gu_val, __gu_err);	\
+		break;							\
+	case 8:								\
+		__put_user_asm_8((ptr), __gu_val, __gu_err);		\
+		break;							\
+	default:							\
+		__gu_err = -EINVAL;					\
+	}								\
+	__gu_err;							\
+})
+
+#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err)	\
+({							\
+__asm__ __volatile__ ("	lwi	%0, %1, 0;		\
+		1:	swi	%0, %2, 0;		\
+			lwi	%0, %1, 4;		\
+		2:	swi	%0, %2, 4;		\
+			addk	%0,r0,r0;		\
+		3:					\
+		.section .fixup,\"ax\";			\
+		4:	brid	3b;			\
+			addik	%0, r0, %3;		\
+		.previous;				\
+		.section __ex_table,\"a\";		\
+		.word	1b,4b,2b,4b;			\
+		.previous;"				\
+	: "=&r"(__gu_err)				\
+	: "r"(&__gu_val),				\
+	"r"(__gu_ptr), "i"(-EFAULT)			\
+	);						\
+})
+
+#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err)	\
+({								\
+	__asm__ __volatile__ (					\
+			"1:"	insn	" %1, %2, r0;		\
+				addk	%0, r0, r0;		\
+			2:					\
+			.section .fixup,\"ax\";			\
+			3:	brid	2b;			\
+				addik	%0, r0, %3;		\
+			.previous;				\
+			.section __ex_table,\"a\";		\
+			.word	1b,3b;				\
+			.previous;"				\
+		: "=r"(__gu_err)				\
+		: "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT)	\
+	);							\
+})
+
+/*
+ * Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail.
+ */
+static inline int clear_user(char *to, int size)
+{
+	if (size && access_ok(VERIFY_WRITE, to, size)) {
+		__asm__ __volatile__ ("				\
+				1:				\
+					sb	r0, %2, r0;	\
+					addik	%0, %0, -1;	\
+					bneid	%0, 1b;		\
+					addik	%2, %2, 1;	\
+				2:				\
+				.section __ex_table,\"a\";	\
+				.word	1b,2b;			\
+				.section .text;"		\
+			: "=r"(size)				\
+			: "0"(size), "r"(to)
+		);
+	}
+	return size;
+}
+
+extern unsigned long __copy_tofrom_user(void __user *to,
+		const void __user *from, unsigned long size);
+
+#define copy_to_user(to, from, n)					\
+	(access_ok(VERIFY_WRITE, (to), (n)) ?				\
+		__copy_tofrom_user((void __user *)(to),			\
+			(__force const void __user *)(from), (n))	\
+		: -EFAULT)
+
+#define __copy_to_user(to, from, n)	copy_to_user((to), (from), (n))
+#define __copy_to_user_inatomic(to, from, n)	copy_to_user((to), (from), (n))
+
+#define copy_from_user(to, from, n)					\
+	(access_ok(VERIFY_READ, (from), (n)) ?				\
+		__copy_tofrom_user((__force void __user *)(to),		\
+			(void __user *)(from), (n))			\
+		: -EFAULT)
+
+#define __copy_from_user(to, from, n)	copy_from_user((to), (from), (n))
+#define __copy_from_user_inatomic(to, from, n) \
+		copy_from_user((to), (from), (n))
+
+extern int __strncpy_user(char *to, const char __user *from, int len);
+extern int __strnlen_user(const char __user *sstr, int len);
+
+#define strncpy_from_user(to, from, len)	\
+		(access_ok(VERIFY_READ, from, 1) ?	\
+			__strncpy_user(to, from, len) : -EFAULT)
+#define strnlen_user(str, len)	\
+		(access_ok(VERIFY_READ, str, 1) ? __strnlen_user(str, len) : 0)
+
+#endif /* CONFIG_MMU */
 
 /*
  * The exception table consists of pairs of addresses: the first is the
diff --git a/arch/microblaze/include/asm/unaligned.h b/arch/microblaze/include/asm/unaligned.h
index 9d66b64..3658d91 100644
--- a/arch/microblaze/include/asm/unaligned.h
+++ b/arch/microblaze/include/asm/unaligned.h
@@ -12,7 +12,8 @@
 
 # ifdef __KERNEL__
 
-# include <linux/unaligned/access_ok.h>
+# include <linux/unaligned/be_struct.h>
+# include <linux/unaligned/le_byteshift.h>
 # include <linux/unaligned/generic.h>
 
 # define get_unaligned	__get_unaligned_be
diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile
index da94bec..f4a5e19 100644
--- a/arch/microblaze/kernel/Makefile
+++ b/arch/microblaze/kernel/Makefile
@@ -15,5 +15,6 @@
 obj-$(CONFIG_SELFMOD)		+= selfmod.o
 obj-$(CONFIG_HEART_BEAT)	+= heartbeat.o
 obj-$(CONFIG_MODULES)		+= microblaze_ksyms.o module.o
+obj-$(CONFIG_MMU)		+= misc.o
 
 obj-y	+= entry$(MMUEXT).o
diff --git a/arch/microblaze/kernel/asm-offsets.c b/arch/microblaze/kernel/asm-offsets.c
index aabd9e9..7bc7b68 100644
--- a/arch/microblaze/kernel/asm-offsets.c
+++ b/arch/microblaze/kernel/asm-offsets.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
@@ -68,16 +69,26 @@
 
 	/* struct task_struct */
 	DEFINE(TS_THREAD_INFO, offsetof(struct task_struct, stack));
+#ifdef CONFIG_MMU
+	DEFINE(TASK_STATE, offsetof(struct task_struct, state));
+	DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
+	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
+	DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
+	DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+	DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
+	DEFINE(TASK_PID, offsetof(struct task_struct, pid));
+	DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
+	DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
+	BLANK();
+
+	DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
+	BLANK();
+#endif
 
 	/* struct thread_info */
 	DEFINE(TI_TASK, offsetof(struct thread_info, task));
-	DEFINE(TI_EXEC_DOMAIN, offsetof(struct thread_info, exec_domain));
 	DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
-	DEFINE(TI_STATUS, offsetof(struct thread_info, status));
-	DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
-	DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count));
 	DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
-	DEFINE(TI_RESTART_BLOCK, offsetof(struct thread_info, restart_block));
 	DEFINE(TI_CPU_CONTEXT, offsetof(struct thread_info, cpu_context));
 	BLANK();
 
diff --git a/arch/microblaze/kernel/early_printk.c b/arch/microblaze/kernel/early_printk.c
index 4b0f0fd..7de8492 100644
--- a/arch/microblaze/kernel/early_printk.c
+++ b/arch/microblaze/kernel/early_printk.c
@@ -87,6 +87,9 @@
 	base_addr = early_uartlite_console();
 	if (base_addr) {
 		early_console_initialized = 1;
+#ifdef CONFIG_MMU
+		early_console_reg_tlb_alloc(base_addr);
+#endif
 		early_printk("early_printk_console is enabled at 0x%08x\n",
 							base_addr);
 
diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S
index f24b126..1fce6b8 100644
--- a/arch/microblaze/kernel/entry-nommu.S
+++ b/arch/microblaze/kernel/entry-nommu.S
@@ -10,7 +10,7 @@
 
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
 #include <asm/entry.h>
 #include <asm/asm-offsets.h>
 #include <asm/registers.h>
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S
new file mode 100644
index 0000000..91a0e7b
--- /dev/null
+++ b/arch/microblaze/kernel/entry.S
@@ -0,0 +1,1116 @@
+/*
+ * Low-level system-call handling, trap handlers and context-switching
+ *
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
+ * Copyright (C) 2003		John Williams <jwilliams@itee.uq.edu.au>
+ * Copyright (C) 2001,2002	NEC Corporation
+ * Copyright (C) 2001,2002	Miles Bader <miles@gnu.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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ * Heavily modified by John Williams for Microblaze
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+
+#include <asm/entry.h>
+#include <asm/current.h>
+#include <asm/processor.h>
+#include <asm/exceptions.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+
+#include <asm/page.h>
+#include <asm/unistd.h>
+
+#include <linux/errno.h>
+#include <asm/signal.h>
+
+/* The size of a state save frame. */
+#define STATE_SAVE_SIZE		(PT_SIZE + STATE_SAVE_ARG_SPACE)
+
+/* The offset of the struct pt_regs in a `state save frame' on the stack. */
+#define PTO	STATE_SAVE_ARG_SPACE /* 24 the space for args */
+
+#define C_ENTRY(name)	.globl name; .align 4; name
+
+/*
+ * Various ways of setting and clearing BIP in flags reg.
+ * This is mucky, but necessary using microblaze version that
+ * allows msr ops to write to BIP
+ */
+#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
+	.macro	clear_bip
+	msrclr	r11, MSR_BIP
+	nop
+	.endm
+
+	.macro	set_bip
+	msrset	r11, MSR_BIP
+	nop
+	.endm
+
+	.macro	clear_eip
+	msrclr	r11, MSR_EIP
+	nop
+	.endm
+
+	.macro	set_ee
+	msrset	r11, MSR_EE
+	nop
+	.endm
+
+	.macro	disable_irq
+	msrclr	r11, MSR_IE
+	nop
+	.endm
+
+	.macro	enable_irq
+	msrset	r11, MSR_IE
+	nop
+	.endm
+
+	.macro	set_ums
+	msrset	r11, MSR_UMS
+	nop
+	msrclr	r11, MSR_VMS
+	nop
+	.endm
+
+	.macro	set_vms
+	msrclr	r11, MSR_UMS
+	nop
+	msrset	r11, MSR_VMS
+	nop
+	.endm
+
+	.macro	clear_vms_ums
+	msrclr	r11, MSR_VMS
+	nop
+	msrclr	r11, MSR_UMS
+	nop
+	.endm
+#else
+	.macro	clear_bip
+	mfs	r11, rmsr
+	nop
+	andi	r11, r11, ~MSR_BIP
+	mts	rmsr, r11
+	nop
+	.endm
+
+	.macro	set_bip
+	mfs	r11, rmsr
+	nop
+	ori	r11, r11, MSR_BIP
+	mts	rmsr, r11
+	nop
+	.endm
+
+	.macro	clear_eip
+	mfs	r11, rmsr
+	nop
+	andi	r11, r11, ~MSR_EIP
+	mts	rmsr, r11
+	nop
+	.endm
+
+	.macro	set_ee
+	mfs	r11, rmsr
+	nop
+	ori	r11, r11, MSR_EE
+	mts	rmsr, r11
+	nop
+	.endm
+
+	.macro	disable_irq
+	mfs	r11, rmsr
+	nop
+	andi	r11, r11, ~MSR_IE
+	mts	rmsr, r11
+	nop
+	.endm
+
+	.macro	enable_irq
+	mfs	r11, rmsr
+	nop
+	ori	r11, r11, MSR_IE
+	mts	rmsr, r11
+	nop
+	.endm
+
+	.macro set_ums
+	mfs	r11, rmsr
+	nop
+	ori	r11, r11, MSR_VMS
+	andni	r11, r11, MSR_UMS
+	mts	rmsr, r11
+	nop
+	.endm
+
+	.macro	set_vms
+	mfs	r11, rmsr
+	nop
+	ori	r11, r11, MSR_VMS
+	andni	r11, r11, MSR_UMS
+	mts	rmsr, r11
+	nop
+	.endm
+
+	.macro	clear_vms_ums
+	mfs	r11, rmsr
+	nop
+	andni	r11, r11, (MSR_VMS|MSR_UMS)
+	mts	rmsr,r11
+	nop
+	.endm
+#endif
+
+/* Define how to call high-level functions. With MMU, virtual mode must be
+ * enabled when calling the high-level function. Clobbers R11.
+ * VM_ON, VM_OFF, DO_JUMP_BIPCLR, DO_CALL
+ */
+
+/* turn on virtual protected mode save */
+#define VM_ON		\
+	set_ums;		\
+	rted	r0, 2f;	\
+2: nop;
+
+/* turn off virtual protected mode save and user mode save*/
+#define VM_OFF			\
+	clear_vms_ums;			\
+	rted	r0, TOPHYS(1f);	\
+1: nop;
+
+#define SAVE_REGS \
+	swi	r2, r1, PTO+PT_R2;	/* Save SDA */			\
+	swi	r5, r1, PTO+PT_R5;					\
+	swi	r6, r1, PTO+PT_R6;					\
+	swi	r7, r1, PTO+PT_R7;					\
+	swi	r8, r1, PTO+PT_R8;					\
+	swi	r9, r1, PTO+PT_R9;					\
+	swi	r10, r1, PTO+PT_R10;					\
+	swi	r11, r1, PTO+PT_R11;	/* save clobbered regs after rval */\
+	swi	r12, r1, PTO+PT_R12;					\
+	swi	r13, r1, PTO+PT_R13;	/* Save SDA2 */			\
+	swi	r14, r1, PTO+PT_PC;	/* PC, before IRQ/trap */	\
+	swi	r15, r1, PTO+PT_R15;	/* Save LP */			\
+	swi	r18, r1, PTO+PT_R18;	/* Save asm scratch reg */	\
+	swi	r19, r1, PTO+PT_R19;					\
+	swi	r20, r1, PTO+PT_R20;					\
+	swi	r21, r1, PTO+PT_R21;					\
+	swi	r22, r1, PTO+PT_R22;					\
+	swi	r23, r1, PTO+PT_R23;					\
+	swi	r24, r1, PTO+PT_R24;					\
+	swi	r25, r1, PTO+PT_R25;					\
+	swi	r26, r1, PTO+PT_R26;					\
+	swi	r27, r1, PTO+PT_R27;					\
+	swi	r28, r1, PTO+PT_R28;					\
+	swi	r29, r1, PTO+PT_R29;					\
+	swi	r30, r1, PTO+PT_R30;					\
+	swi	r31, r1, PTO+PT_R31;	/* Save current task reg */	\
+	mfs	r11, rmsr;		/* save MSR */			\
+	nop;								\
+	swi	r11, r1, PTO+PT_MSR;
+
+#define RESTORE_REGS \
+	lwi	r11, r1, PTO+PT_MSR;					\
+	mts	rmsr , r11;						\
+	nop;								\
+	lwi	r2, r1, PTO+PT_R2;	/* restore SDA */		\
+	lwi	r5, r1, PTO+PT_R5;					\
+	lwi	r6, r1, PTO+PT_R6;					\
+	lwi	r7, r1, PTO+PT_R7;					\
+	lwi	r8, r1, PTO+PT_R8;					\
+	lwi	r9, r1, PTO+PT_R9;					\
+	lwi	r10, r1, PTO+PT_R10;					\
+	lwi	r11, r1, PTO+PT_R11;	/* restore clobbered regs after rval */\
+	lwi	r12, r1, PTO+PT_R12;					\
+	lwi	r13, r1, PTO+PT_R13;	/* restore SDA2 */		\
+	lwi	r14, r1, PTO+PT_PC;	/* RESTORE_LINK PC, before IRQ/trap */\
+	lwi	r15, r1, PTO+PT_R15;	/* restore LP */		\
+	lwi	r18, r1, PTO+PT_R18;	/* restore asm scratch reg */	\
+	lwi	r19, r1, PTO+PT_R19;					\
+	lwi	r20, r1, PTO+PT_R20;					\
+	lwi	r21, r1, PTO+PT_R21;					\
+	lwi	r22, r1, PTO+PT_R22;					\
+	lwi	r23, r1, PTO+PT_R23;					\
+	lwi	r24, r1, PTO+PT_R24;					\
+	lwi	r25, r1, PTO+PT_R25;					\
+	lwi	r26, r1, PTO+PT_R26;					\
+	lwi	r27, r1, PTO+PT_R27;					\
+	lwi	r28, r1, PTO+PT_R28;					\
+	lwi	r29, r1, PTO+PT_R29;					\
+	lwi	r30, r1, PTO+PT_R30;					\
+	lwi	r31, r1, PTO+PT_R31;	/* Restore cur task reg */
+
+.text
+
+/*
+ * User trap.
+ *
+ * System calls are handled here.
+ *
+ * Syscall protocol:
+ * Syscall number in r12, args in r5-r10
+ * Return value in r3
+ *
+ * Trap entered via brki instruction, so BIP bit is set, and interrupts
+ * are masked. This is nice, means we don't have to CLI before state save
+ */
+C_ENTRY(_user_exception):
+	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
+	addi	r14, r14, 4	/* return address is 4 byte after call */
+	swi	r11, r0, TOPHYS(r0_ram + PTO + PT_R11);	/* Save r11 */
+
+	lwi	r11, r0, TOPHYS(PER_CPU(KM));/* See if already in kernel mode.*/
+	beqi	r11, 1f;		/* Jump ahead if coming from user */
+/* Kernel-mode state save. */
+	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
+	tophys(r1,r11);
+	swi	r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */
+	lwi	r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
+
+	addik	r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */
+	SAVE_REGS
+
+	addi	r11, r0, 1; 		/* Was in kernel-mode. */
+	swi	r11, r1, PTO+PT_MODE; /* pt_regs -> kernel mode */
+	brid	2f;
+	nop;				/* Fill delay slot */
+
+/* User-mode state save.  */
+1:
+	lwi	r11, r0, TOPHYS(r0_ram + PTO + PT_R11);	/* restore r11 */
+	lwi	r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
+	tophys(r1,r1);
+	lwi	r1, r1, TS_THREAD_INFO;	/* get stack from task_struct */
+/* calculate kernel stack pointer from task struct 8k */
+	addik	r1, r1, THREAD_SIZE;
+	tophys(r1,r1);
+
+	addik	r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */
+	SAVE_REGS
+
+	swi	r0, r1, PTO+PT_MODE;			/* Was in user-mode. */
+	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
+	swi	r11, r1, PTO+PT_R1;		/* Store user SP.  */
+	addi	r11, r0, 1;
+	swi	r11, r0, TOPHYS(PER_CPU(KM));	/* Now we're in kernel-mode.  */
+2:	lwi	r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE));	/* get saved current */
+	/* Save away the syscall number.  */
+	swi	r12, r1, PTO+PT_R0;
+	tovirt(r1,r1)
+
+	la	r15, r0, ret_from_trap-8
+/* where the trap should return need -8 to adjust for rtsd r15, 8*/
+/* Jump to the appropriate function for the system call number in r12
+ * (r12 is not preserved), or return an error if r12 is not valid. The LP
+ * register should point to the location where
+ * the called function should return.  [note that MAKE_SYS_CALL uses label 1] */
+	/* See if the system call number is valid.  */
+	addi	r11, r12, -__NR_syscalls;
+	bgei	r11,1f;
+	/* Figure out which function to use for this system call.  */
+	/* Note Microblaze barrel shift is optional, so don't rely on it */
+	add	r12, r12, r12;			/* convert num -> ptr */
+	add	r12, r12, r12;
+
+	/* Trac syscalls and stored them to r0_ram */
+	lwi	r3, r12, 0x400 + TOPHYS(r0_ram)
+	addi	r3, r3, 1
+	swi	r3, r12, 0x400 + TOPHYS(r0_ram)
+
+	lwi	r12, r12, TOPHYS(sys_call_table); /* Function ptr */
+	/* Make the system call.  to r12*/
+	set_vms;
+	rtid	r12, 0;
+	nop;
+	/* The syscall number is invalid, return an error.  */
+1:	VM_ON;	/* RETURN() expects virtual mode*/
+	addi	r3, r0, -ENOSYS;
+	rtsd	r15,8;		/* looks like a normal subroutine return */
+	or 	r0, r0, r0
+
+
+/* Entry point used to return from a syscall/trap.  */
+/* We re-enable BIP bit before state restore */
+C_ENTRY(ret_from_trap):
+	set_bip;			/*  Ints masked for state restore*/
+	lwi	r11, r1, PTO+PT_MODE;
+/* See if returning to kernel mode, if so, skip resched &c.  */
+	bnei	r11, 2f;
+
+	/* We're returning to user mode, so check for various conditions that
+	 * trigger rescheduling. */
+	/* Get current task ptr into r11 */
+	add	r11, r0, CURRENT_TASK;	/* Get current task ptr into r11 */
+	lwi	r11, r11, TS_THREAD_INFO;	/* get thread info */
+	lwi	r11, r11, TI_FLAGS;		/* get flags in thread info */
+	andi	r11, r11, _TIF_NEED_RESCHED;
+	beqi	r11, 5f;
+
+	swi	r3, r1, PTO + PT_R3; /* store syscall result */
+	swi	r4, r1, PTO + PT_R4;
+	bralid	r15, schedule;	/* Call scheduler */
+	nop;				/* delay slot */
+	lwi	r3, r1, PTO + PT_R3; /* restore syscall result */
+	lwi	r4, r1, PTO + PT_R4;
+
+	/* Maybe handle a signal */
+5:	add	r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+	lwi	r11, r11, TS_THREAD_INFO;	/* get thread info */
+	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
+	andi	r11, r11, _TIF_SIGPENDING;
+	beqi	r11, 1f;		/* Signals to handle, handle them */
+
+	swi	r3, r1, PTO + PT_R3; /* store syscall result */
+	swi	r4, r1, PTO + PT_R4;
+	la	r5, r1, PTO;		/* Arg 1: struct pt_regs *regs */
+	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */
+	addi	r7, r0, 1;		/* Arg 3: int in_syscall */
+	bralid	r15, do_signal;	/* Handle any signals */
+	nop;
+	lwi	r3, r1, PTO + PT_R3; /* restore syscall result */
+	lwi	r4, r1, PTO + PT_R4;
+
+/* Finally, return to user state.  */
+1:	swi	r0, r0, PER_CPU(KM);	/* Now officially in user state. */
+	add	r11, r0, CURRENT_TASK;	/* Get current task ptr into r11 */
+	swi	r11, r0, PER_CPU(CURRENT_SAVE); /* save current */
+	VM_OFF;
+	tophys(r1,r1);
+	RESTORE_REGS;
+	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */
+	lwi	r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */
+	bri	6f;
+
+/* Return to kernel state.  */
+2:	VM_OFF;
+	tophys(r1,r1);
+	RESTORE_REGS;
+	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */
+	tovirt(r1,r1);
+6:
+TRAP_return:		/* Make global symbol for debugging */
+	rtbd	r14, 0;	/* Instructions to return from an IRQ */
+	nop;
+
+
+/* These syscalls need access to the struct pt_regs on the stack, so we
+   implement them in assembly (they're basically all wrappers anyway).  */
+
+C_ENTRY(sys_fork_wrapper):
+	addi	r5, r0, SIGCHLD			/* Arg 0: flags */
+	lwi	r6, r1, PTO+PT_R1	/* Arg 1: child SP (use parent's) */
+	la	r7, r1, PTO			/* Arg 2: parent context */
+	add	r8. r0, r0			/* Arg 3: (unused) */
+	add	r9, r0, r0;			/* Arg 4: (unused) */
+	add	r10, r0, r0;			/* Arg 5: (unused) */
+	brid	do_fork		/* Do real work (tail-call) */
+	nop;
+
+/* This the initial entry point for a new child thread, with an appropriate
+   stack in place that makes it look the the child is in the middle of an
+   syscall.  This function is actually `returned to' from switch_thread
+   (copy_thread makes ret_from_fork the return address in each new thread's
+   saved context).  */
+C_ENTRY(ret_from_fork):
+	bralid	r15, schedule_tail; /* ...which is schedule_tail's arg */
+	add	r3, r5, r0;	/* switch_thread returns the prev task */
+				/* ( in the delay slot ) */
+	add	r3, r0, r0;	/* Child's fork call should return 0. */
+	brid	ret_from_trap;	/* Do normal trap return */
+	nop;
+
+C_ENTRY(sys_vfork_wrapper):
+	la	r5, r1, PTO
+	brid	sys_vfork	/* Do real work (tail-call) */
+	nop
+
+C_ENTRY(sys_clone_wrapper):
+	bnei	r6, 1f;			/* See if child SP arg (arg 1) is 0. */
+	lwi	r6, r1, PTO+PT_R1;	/* If so, use paret's stack ptr */
+1:	la	r7, r1, PTO;			/* Arg 2: parent context */
+	add	r8, r0, r0;			/* Arg 3: (unused) */
+	add	r9, r0, r0;			/* Arg 4: (unused) */
+	add	r10, r0, r0;			/* Arg 5: (unused) */
+	brid	do_fork		/* Do real work (tail-call) */
+	nop;
+
+C_ENTRY(sys_execve_wrapper):
+	la	r8, r1, PTO;		/* add user context as 4th arg */
+	brid	sys_execve;	/* Do real work (tail-call).*/
+	nop;
+
+C_ENTRY(sys_sigsuspend_wrapper):
+	swi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+	swi	r4, r1, PTO+PT_R4;
+	la	r6, r1, PTO;		/* add user context as 2nd arg */
+	bralid	r15, sys_sigsuspend; /* Do real work.*/
+	nop;
+	lwi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+	lwi	r4, r1, PTO+PT_R4;
+	bri ret_from_trap /* fall through will not work here due to align */
+	nop;
+
+C_ENTRY(sys_rt_sigsuspend_wrapper):
+	swi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+	swi	r4, r1, PTO+PT_R4;
+	la	r7, r1, PTO;		/* add user context as 3rd arg */
+	brlid	r15, sys_rt_sigsuspend;	/* Do real work.*/
+	nop;
+	lwi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+	lwi	r4, r1, PTO+PT_R4;
+	bri ret_from_trap /* fall through will not work here due to align */
+	nop;
+
+
+C_ENTRY(sys_sigreturn_wrapper):
+	swi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+	swi	r4, r1, PTO+PT_R4;
+	la	r5, r1, PTO;		/* add user context as 1st arg */
+	brlid	r15, sys_sigreturn;	/* Do real work.*/
+	nop;
+	lwi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+	lwi	r4, r1, PTO+PT_R4;
+	bri ret_from_trap /* fall through will not work here due to align */
+	nop;
+
+C_ENTRY(sys_rt_sigreturn_wrapper):
+	swi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+	swi	r4, r1, PTO+PT_R4;
+	la	r5, r1, PTO;		/* add user context as 1st arg */
+	brlid	r15, sys_rt_sigreturn	/* Do real work */
+	nop;
+	lwi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+	lwi	r4, r1, PTO+PT_R4;
+	bri ret_from_trap /* fall through will not work here due to align */
+	nop;
+
+/*
+ * HW EXCEPTION rutine start
+ */
+
+#define SAVE_STATE	\
+	swi	r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */	\
+	set_bip;	/*equalize initial state for all possible entries*/\
+	clear_eip;							\
+	enable_irq;							\
+	set_ee;								\
+	/* See if already in kernel mode.*/				\
+	lwi	r11, r0, TOPHYS(PER_CPU(KM));				\
+	beqi	r11, 1f;		/* Jump ahead if coming from user */\
+	/* Kernel-mode state save.  */					\
+	/* Reload kernel stack-ptr. */					\
+	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));			\
+	tophys(r1,r11);							\
+	swi	r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */	\
+	lwi	r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */\
+	addik	r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */\
+	/* store return registers separately because			\
+	 * this macros is use for others exceptions */			\
+	swi	r3, r1, PTO + PT_R3;					\
+	swi	r4, r1, PTO + PT_R4;					\
+	SAVE_REGS							\
+	/* PC, before IRQ/trap - this is one instruction above */	\
+	swi	r17, r1, PTO+PT_PC;					\
+									\
+	addi	r11, r0, 1; 		/* Was in kernel-mode.  */	\
+	swi	r11, r1, PTO+PT_MODE; 	 				\
+	brid	2f;							\
+	nop;				/* Fill delay slot */		\
+1:	/* User-mode state save.  */					\
+	lwi	r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */\
+	lwi	r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\
+	tophys(r1,r1);							\
+	lwi	r1, r1, TS_THREAD_INFO;	/* get the thread info */	\
+	addik	r1, r1, THREAD_SIZE;	/* calculate kernel stack pointer */\
+	tophys(r1,r1);							\
+									\
+	addik	r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */\
+	/* store return registers separately because this macros	\
+	 * is use for others exceptions */				\
+	swi	r3, r1, PTO + PT_R3; 					\
+	swi	r4, r1, PTO + PT_R4;					\
+	SAVE_REGS							\
+	/* PC, before IRQ/trap - this is one instruction above FIXME*/	\
+	swi	r17, r1, PTO+PT_PC;					\
+									\
+	swi	r0, r1, PTO+PT_MODE; /* Was in user-mode.  */		\
+	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));			\
+	swi	r11, r1, PTO+PT_R1; /* Store user SP.  */		\
+	addi	r11, r0, 1;						\
+	swi	r11, r0, TOPHYS(PER_CPU(KM)); /* Now we're in kernel-mode.*/\
+2:	lwi	r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\
+	/* Save away the syscall number.  */				\
+	swi	r0, r1, PTO+PT_R0;					\
+	tovirt(r1,r1)
+
+C_ENTRY(full_exception_trap):
+	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
+	/* adjust exception address for privileged instruction
+	 * for finding where is it */
+	addik	r17, r17, -4
+	SAVE_STATE /* Save registers */
+	/* FIXME this can be store directly in PT_ESR reg.
+	 * I tested it but there is a fault */
+	/* where the trap should return need -8 to adjust for rtsd r15, 8 */
+	la	r15, r0, ret_from_exc - 8
+	la	r5, r1, PTO		 /* parameter struct pt_regs * regs */
+	mfs	r6, resr
+	nop
+	mfs	r7, rfsr;		/* save FSR */
+	nop
+	la	r12, r0, full_exception
+	set_vms;
+	rtbd	r12, 0;
+	nop;
+
+/*
+ * Unaligned data trap.
+ *
+ * Unaligned data trap last on 4k page is handled here.
+ *
+ * Trap entered via exception, so EE bit is set, and interrupts
+ * are masked.  This is nice, means we don't have to CLI before state save
+ *
+ * The assembler routine is in "arch/microblaze/kernel/hw_exception_handler.S"
+ */
+C_ENTRY(unaligned_data_trap):
+	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
+	SAVE_STATE		/* Save registers.*/
+	/* where the trap should return need -8 to adjust for rtsd r15, 8 */
+	la	r15, r0, ret_from_exc-8
+	mfs	r3, resr		/* ESR */
+	nop
+	mfs	r4, rear		/* EAR */
+	nop
+	la	r7, r1, PTO		/* parameter struct pt_regs * regs */
+	la	r12, r0, _unaligned_data_exception
+	set_vms;
+	rtbd	r12, 0;	/* interrupts enabled */
+	nop;
+
+/*
+ * Page fault traps.
+ *
+ * If the real exception handler (from hw_exception_handler.S) didn't find
+ * the mapping for the process, then we're thrown here to handle such situation.
+ *
+ * Trap entered via exceptions, so EE bit is set, and interrupts
+ * are masked.  This is nice, means we don't have to CLI before state save
+ *
+ * Build a standard exception frame for TLB Access errors.  All TLB exceptions
+ * will bail out to this point if they can't resolve the lightweight TLB fault.
+ *
+ * The C function called is in "arch/microblaze/mm/fault.c", declared as:
+ * void do_page_fault(struct pt_regs *regs,
+ *				unsigned long address,
+ *				unsigned long error_code)
+ */
+/* data and intruction trap - which is choose is resolved int fault.c */
+C_ENTRY(page_fault_data_trap):
+	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
+	SAVE_STATE		/* Save registers.*/
+	/* where the trap should return need -8 to adjust for rtsd r15, 8 */
+	la	r15, r0, ret_from_exc-8
+	la	r5, r1, PTO		/* parameter struct pt_regs * regs */
+	mfs	r6, rear		/* parameter unsigned long address */
+	nop
+	mfs	r7, resr		/* parameter unsigned long error_code */
+	nop
+	la	r12, r0, do_page_fault
+	set_vms;
+	rtbd	r12, 0;	/* interrupts enabled */
+	nop;
+
+C_ENTRY(page_fault_instr_trap):
+	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
+	SAVE_STATE		/* Save registers.*/
+	/* where the trap should return need -8 to adjust for rtsd r15, 8 */
+	la	r15, r0, ret_from_exc-8
+	la	r5, r1, PTO		/* parameter struct pt_regs * regs */
+	mfs	r6, rear		/* parameter unsigned long address */
+	nop
+	ori	r7, r0, 0		/* parameter unsigned long error_code */
+	la	r12, r0, do_page_fault
+	set_vms;
+	rtbd	r12, 0;	/* interrupts enabled */
+	nop;
+
+/* Entry point used to return from an exception.  */
+C_ENTRY(ret_from_exc):
+	set_bip;			/*  Ints masked for state restore*/
+	lwi	r11, r1, PTO+PT_MODE;
+	bnei	r11, 2f;		/* See if returning to kernel mode, */
+					/* ... if so, skip resched &c.  */
+
+	/* We're returning to user mode, so check for various conditions that
+	   trigger rescheduling. */
+	/* Get current task ptr into r11 */
+	add	r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+	lwi	r11, r11, TS_THREAD_INFO;	/* get thread info */
+	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
+	andi	r11, r11, _TIF_NEED_RESCHED;
+	beqi	r11, 5f;
+
+/* Call the scheduler before returning from a syscall/trap. */
+	bralid	r15, schedule;	/* Call scheduler */
+	nop;				/* delay slot */
+
+	/* Maybe handle a signal */
+5:	add	r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+	lwi	r11, r11, TS_THREAD_INFO;	/* get thread info */
+	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
+	andi	r11, r11, _TIF_SIGPENDING;
+	beqi	r11, 1f;		/* Signals to handle, handle them */
+
+	/*
+	 * Handle a signal return; Pending signals should be in r18.
+	 *
+	 * Not all registers are saved by the normal trap/interrupt entry
+	 * points (for instance, call-saved registers (because the normal
+	 * C-compiler calling sequence in the kernel makes sure they're
+	 * preserved), and call-clobbered registers in the case of
+	 * traps), but signal handlers may want to examine or change the
+	 * complete register state.  Here we save anything not saved by
+	 * the normal entry sequence, so that it may be safely restored
+	 * (in a possibly modified form) after do_signal returns.
+	 * store return registers separately because this macros is use
+	 * for others exceptions */
+	swi	r3, r1, PTO + PT_R3;
+	swi	r4, r1, PTO + PT_R4;
+	la	r5, r1, PTO;		/* Arg 1: struct pt_regs *regs */
+	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */
+	addi	r7, r0, 0;		/* Arg 3: int in_syscall */
+	bralid	r15, do_signal;	/* Handle any signals */
+	nop;
+	lwi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+	lwi	r4, r1, PTO+PT_R4;
+
+/* Finally, return to user state.  */
+1:	swi	r0, r0, PER_CPU(KM);	/* Now officially in user state. */
+	add	r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+	swi	r11, r0, PER_CPU(CURRENT_SAVE); /* save current */
+	VM_OFF;
+	tophys(r1,r1);
+
+	lwi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+	lwi	r4, r1, PTO+PT_R4;
+	RESTORE_REGS;
+	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */
+
+	lwi	r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */
+	bri	6f;
+/* Return to kernel state.  */
+2:	VM_OFF;
+	tophys(r1,r1);
+	lwi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+	lwi	r4, r1, PTO+PT_R4;
+	RESTORE_REGS;
+	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */
+
+	tovirt(r1,r1);
+6:
+EXC_return:		/* Make global symbol for debugging */
+	rtbd	r14, 0;	/* Instructions to return from an IRQ */
+	nop;
+
+/*
+ * HW EXCEPTION rutine end
+ */
+
+/*
+ * Hardware maskable interrupts.
+ *
+ * The stack-pointer (r1) should have already been saved to the memory
+ * location PER_CPU(ENTRY_SP).
+ */
+C_ENTRY(_interrupt):
+/* MS: we are in physical address */
+/* Save registers, switch to proper stack, convert SP to virtual.*/
+	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
+	swi	r11, r0, TOPHYS(PER_CPU(R11_SAVE));
+	/* MS: See if already in kernel mode. */
+	lwi	r11, r0, TOPHYS(PER_CPU(KM));
+	beqi	r11, 1f; /* MS: Jump ahead if coming from user */
+
+/* Kernel-mode state save. */
+	or	r11, r1, r0
+	tophys(r1,r11); /* MS: I have in r1 physical address where stack is */
+/* MS: Save original SP - position PT_R1 to next stack frame 4 *1 - 152*/
+	swi	r11, r1, (PT_R1 - PT_SIZE);
+/* MS: restore r11 because of saving in SAVE_REGS */
+	lwi	r11, r0, TOPHYS(PER_CPU(R11_SAVE));
+	/* save registers */
+/* MS: Make room on the stack -> activation record */
+	addik	r1, r1, -STATE_SAVE_SIZE;
+/* MS: store return registers separately because
+ * this macros is use for others exceptions */
+	swi	r3, r1, PTO + PT_R3;
+	swi	r4, r1, PTO + PT_R4;
+	SAVE_REGS
+	/* MS: store mode */
+	addi	r11, r0, 1; /* MS: Was in kernel-mode. */
+	swi	r11, r1, PTO + PT_MODE; /* MS: and save it */
+	brid	2f;
+	nop; /* MS: Fill delay slot */
+
+1:
+/* User-mode state save. */
+/* MS: restore r11 -> FIXME move before SAVE_REG */
+	lwi	r11, r0, TOPHYS(PER_CPU(R11_SAVE));
+ /* MS: get the saved current */
+	lwi	r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
+	tophys(r1,r1);
+	lwi	r1, r1, TS_THREAD_INFO;
+	addik	r1, r1, THREAD_SIZE;
+	tophys(r1,r1);
+	/* save registers */
+	addik	r1, r1, -STATE_SAVE_SIZE;
+	swi	r3, r1, PTO+PT_R3;
+	swi	r4, r1, PTO+PT_R4;
+	SAVE_REGS
+	/* calculate mode */
+	swi	r0, r1, PTO + PT_MODE;
+	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
+	swi	r11, r1, PTO+PT_R1;
+	/* setup kernel mode to KM */
+	addi	r11, r0, 1;
+	swi	r11, r0, TOPHYS(PER_CPU(KM));
+
+2:
+	lwi	r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
+	swi	r0, r1, PTO + PT_R0;
+	tovirt(r1,r1)
+	la	r5, r1, PTO;
+	set_vms;
+	la	r11, r0, do_IRQ;
+	la	r15, r0, irq_call;
+irq_call:rtbd	r11, 0;
+	nop;
+
+/* MS: we are in virtual mode */
+ret_from_irq:
+	lwi	r11, r1, PTO + PT_MODE;
+	bnei	r11, 2f;
+
+	add	r11, r0, CURRENT_TASK;
+	lwi	r11, r11, TS_THREAD_INFO;
+	lwi	r11, r11, TI_FLAGS; /* MS: get flags from thread info */
+	andi	r11, r11, _TIF_NEED_RESCHED;
+	beqi	r11, 5f
+	bralid	r15, schedule;
+	nop; /* delay slot */
+
+    /* Maybe handle a signal */
+5:	add	r11, r0, CURRENT_TASK;
+	lwi	r11, r11, TS_THREAD_INFO; /* MS: get thread info */
+	lwi	r11, r11, TI_FLAGS; /* get flags in thread info */
+	andi	r11, r11, _TIF_SIGPENDING;
+	beqid	r11, no_intr_resched
+/* Handle a signal return; Pending signals should be in r18. */
+	addi	r7, r0, 0; /* Arg 3: int in_syscall */
+	la	r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
+	bralid	r15, do_signal;	/* Handle any signals */
+	add	r6, r0, r0; /* Arg 2: sigset_t *oldset */
+
+/* Finally, return to user state. */
+no_intr_resched:
+    /* Disable interrupts, we are now committed to the state restore */
+	disable_irq
+	swi	r0, r0, PER_CPU(KM); /* MS: Now officially in user state. */
+	add	r11, r0, CURRENT_TASK;
+	swi	r11, r0, PER_CPU(CURRENT_SAVE);
+	VM_OFF;
+	tophys(r1,r1);
+	lwi	r3, r1, PTO + PT_R3; /* MS: restore saved r3, r4 registers */
+	lwi	r4, r1, PTO + PT_R4;
+	RESTORE_REGS
+	addik	r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */
+	lwi	r1, r1, PT_R1 - PT_SIZE;
+	bri	6f;
+/* MS: Return to kernel state. */
+2:	VM_OFF /* MS: turn off MMU */
+	tophys(r1,r1)
+	lwi	r3, r1, PTO + PT_R3; /* MS: restore saved r3, r4 registers */
+	lwi	r4, r1, PTO + PT_R4;
+	RESTORE_REGS
+	addik	r1, r1, STATE_SAVE_SIZE	/* MS: Clean up stack space. */
+	tovirt(r1,r1);
+6:
+IRQ_return: /* MS: Make global symbol for debugging */
+	rtid	r14, 0
+	nop
+
+/*
+ * `Debug' trap
+ *  We enter dbtrap in "BIP" (breakpoint) mode.
+ *  So we exit the breakpoint mode with an 'rtbd' and proceed with the
+ *  original dbtrap.
+ *  however, wait to save state first
+ */
+C_ENTRY(_debug_exception):
+	/* BIP bit is set on entry, no interrupts can occur */
+	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
+
+	swi	r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */
+	set_bip;	/*equalize initial state for all possible entries*/
+	clear_eip;
+	enable_irq;
+	lwi	r11, r0, TOPHYS(PER_CPU(KM));/* See if already in kernel mode.*/
+	beqi	r11, 1f;		/* Jump ahead if coming from user */
+	/* Kernel-mode state save.  */
+	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
+	tophys(r1,r11);
+	swi	r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */
+	lwi	r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
+
+	addik	r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */
+	swi	r3, r1, PTO + PT_R3;
+	swi	r4, r1, PTO + PT_R4;
+	SAVE_REGS;
+
+	addi	r11, r0, 1; 		/* Was in kernel-mode.  */
+	swi	r11, r1, PTO + PT_MODE;
+	brid	2f;
+	nop;				/* Fill delay slot */
+1:      /* User-mode state save.  */
+	lwi	r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
+	lwi	r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
+	tophys(r1,r1);
+	lwi	r1, r1, TS_THREAD_INFO;	/* get the thread info */
+	addik	r1, r1, THREAD_SIZE;	/* calculate kernel stack pointer */
+	tophys(r1,r1);
+
+	addik	r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */
+	swi	r3, r1, PTO + PT_R3;
+	swi	r4, r1, PTO + PT_R4;
+	SAVE_REGS;
+
+	swi	r0, r1, PTO+PT_MODE; /* Was in user-mode.  */
+	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
+	swi	r11, r1, PTO+PT_R1; /* Store user SP.  */
+	addi	r11, r0, 1;
+	swi	r11, r0, TOPHYS(PER_CPU(KM));	/* Now we're in kernel-mode.  */
+2:	lwi	r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
+	/* Save away the syscall number.  */
+	swi	r0, r1, PTO+PT_R0;
+	tovirt(r1,r1)
+
+	addi	r5, r0, SIGTRAP		     /* send the trap signal */
+	add	r6, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+	addk	r7, r0, r0		     /* 3rd param zero */
+
+	set_vms;
+	la	r11, r0, send_sig;
+	la	r15, r0, dbtrap_call;
+dbtrap_call:	rtbd	r11, 0;
+	nop;
+
+	set_bip;			/*  Ints masked for state restore*/
+	lwi	r11, r1, PTO+PT_MODE;
+	bnei	r11, 2f;
+
+	/* Get current task ptr into r11 */
+	add	r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+	lwi	r11, r11, TS_THREAD_INFO;	/* get thread info */
+	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
+	andi	r11, r11, _TIF_NEED_RESCHED;
+	beqi	r11, 5f;
+
+/* Call the scheduler before returning from a syscall/trap. */
+
+	bralid	r15, schedule;	/* Call scheduler */
+	nop;				/* delay slot */
+	/* XXX Is PT_DTRACE handling needed here? */
+	/* XXX m68knommu also checks TASK_STATE & TASK_COUNTER here.  */
+
+	/* Maybe handle a signal */
+5:	add	r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+	lwi	r11, r11, TS_THREAD_INFO;	/* get thread info */
+	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
+	andi	r11, r11, _TIF_SIGPENDING;
+	beqi	r11, 1f;		/* Signals to handle, handle them */
+
+/* Handle a signal return; Pending signals should be in r18.  */
+	/* Not all registers are saved by the normal trap/interrupt entry
+	   points (for instance, call-saved registers (because the normal
+	   C-compiler calling sequence in the kernel makes sure they're
+	   preserved), and call-clobbered registers in the case of
+	   traps), but signal handlers may want to examine or change the
+	   complete register state.  Here we save anything not saved by
+	   the normal entry sequence, so that it may be safely restored
+	   (in a possibly modified form) after do_signal returns.  */
+
+	la	r5, r1, PTO;		/* Arg 1: struct pt_regs *regs */
+	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */
+	addi  r7, r0, 0;	/* Arg 3: int in_syscall */
+	bralid	r15, do_signal;	/* Handle any signals */
+	nop;
+
+
+/* Finally, return to user state.  */
+1:	swi	r0, r0, PER_CPU(KM);	/* Now officially in user state. */
+	add	r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+	swi	r11, r0, PER_CPU(CURRENT_SAVE); /* save current */
+	VM_OFF;
+	tophys(r1,r1);
+
+	lwi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+	lwi	r4, r1, PTO+PT_R4;
+	RESTORE_REGS
+	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */
+
+
+	lwi	r1, r1, PT_R1 - PT_SIZE;
+					/* Restore user stack pointer. */
+	bri	6f;
+
+/* Return to kernel state.  */
+2:	VM_OFF;
+	tophys(r1,r1);
+	lwi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+	lwi	r4, r1, PTO+PT_R4;
+	RESTORE_REGS
+	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */
+
+	tovirt(r1,r1);
+6:
+DBTRAP_return:		/* Make global symbol for debugging */
+	rtbd	r14, 0;	/* Instructions to return from an IRQ */
+	nop;
+
+
+
+ENTRY(_switch_to)
+	/* prepare return value */
+	addk	r3, r0, r31
+
+	/* save registers in cpu_context */
+	/* use r11 and r12, volatile registers, as temp register */
+	/* give start of cpu_context for previous process */
+	addik	r11, r5, TI_CPU_CONTEXT
+	swi	r1, r11, CC_R1
+	swi	r2, r11, CC_R2
+	/* skip volatile registers.
+	 * they are saved on stack when we jumped to _switch_to() */
+	/* dedicated registers */
+	swi	r13, r11, CC_R13
+	swi	r14, r11, CC_R14
+	swi	r15, r11, CC_R15
+	swi	r16, r11, CC_R16
+	swi	r17, r11, CC_R17
+	swi	r18, r11, CC_R18
+	/* save non-volatile registers */
+	swi	r19, r11, CC_R19
+	swi	r20, r11, CC_R20
+	swi	r21, r11, CC_R21
+	swi	r22, r11, CC_R22
+	swi	r23, r11, CC_R23
+	swi	r24, r11, CC_R24
+	swi	r25, r11, CC_R25
+	swi	r26, r11, CC_R26
+	swi	r27, r11, CC_R27
+	swi	r28, r11, CC_R28
+	swi	r29, r11, CC_R29
+	swi	r30, r11, CC_R30
+	/* special purpose registers */
+	mfs	r12, rmsr
+	nop
+	swi	r12, r11, CC_MSR
+	mfs	r12, rear
+	nop
+	swi	r12, r11, CC_EAR
+	mfs	r12, resr
+	nop
+	swi	r12, r11, CC_ESR
+	mfs	r12, rfsr
+	nop
+	swi	r12, r11, CC_FSR
+
+	/* update r31, the current */
+	lwi	r31, r6, TI_TASK/* give me pointer to task which will be next */
+	/* stored it to current_save too */
+	swi	r31, r0, PER_CPU(CURRENT_SAVE)
+
+	/* get new process' cpu context and restore */
+	/* give me start where start context of next task */
+	addik	r11, r6, TI_CPU_CONTEXT
+
+	/* non-volatile registers */
+	lwi	r30, r11, CC_R30
+	lwi	r29, r11, CC_R29
+	lwi	r28, r11, CC_R28
+	lwi	r27, r11, CC_R27
+	lwi	r26, r11, CC_R26
+	lwi	r25, r11, CC_R25
+	lwi	r24, r11, CC_R24
+	lwi	r23, r11, CC_R23
+	lwi	r22, r11, CC_R22
+	lwi	r21, r11, CC_R21
+	lwi	r20, r11, CC_R20
+	lwi	r19, r11, CC_R19
+	/* dedicated registers */
+	lwi	r18, r11, CC_R18
+	lwi	r17, r11, CC_R17
+	lwi	r16, r11, CC_R16
+	lwi	r15, r11, CC_R15
+	lwi	r14, r11, CC_R14
+	lwi	r13, r11, CC_R13
+	/* skip volatile registers */
+	lwi	r2, r11, CC_R2
+	lwi	r1, r11, CC_R1
+
+	/* special purpose registers */
+	lwi	r12, r11, CC_FSR
+	mts	rfsr, r12
+	nop
+	lwi	r12, r11, CC_MSR
+	mts	rmsr, r12
+	nop
+
+	rtsd	r15, 8
+	nop
+
+ENTRY(_reset)
+	brai	0x70; /* Jump back to FS-boot */
+
+ENTRY(_break)
+	mfs	r5, rmsr
+	nop
+	swi	r5, r0, 0x250 + TOPHYS(r0_ram)
+	mfs	r5, resr
+	nop
+	swi	r5, r0, 0x254 + TOPHYS(r0_ram)
+	bri	0
+
+	/* These are compiled and loaded into high memory, then
+	 * copied into place in mach_early_setup */
+	.section	.init.ivt, "ax"
+	.org	0x0
+	/* this is very important - here is the reset vector */
+	/* in current MMU branch you don't care what is here - it is
+	 * used from bootloader site - but this is correct for FS-BOOT */
+	brai	0x70
+	nop
+	brai	TOPHYS(_user_exception); /* syscall handler */
+	brai	TOPHYS(_interrupt);	/* Interrupt handler */
+	brai	TOPHYS(_break);		/* nmi trap handler */
+	brai	TOPHYS(_hw_exception_handler);	/* HW exception handler */
+
+	.org	0x60
+	brai	TOPHYS(_debug_exception);	/* debug trap handler*/
+
+.section .rodata,"a"
+#include "syscall_table.S"
+
+syscall_table_size=(.-sys_call_table)
+
diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c
index 4a8a406..0cb64a3 100644
--- a/arch/microblaze/kernel/exceptions.c
+++ b/arch/microblaze/kernel/exceptions.c
@@ -21,9 +21,9 @@
 
 #include <asm/exceptions.h>
 #include <asm/entry.h>		/* For KM CPU var */
-#include <asm/uaccess.h>
-#include <asm/errno.h>
-#include <asm/ptrace.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
 #include <asm/current.h>
 
 #define MICROBLAZE_ILL_OPCODE_EXCEPTION	0x02
@@ -31,7 +31,7 @@
 #define MICROBLAZE_DBUS_EXCEPTION	0x04
 #define MICROBLAZE_DIV_ZERO_EXCEPTION	0x05
 #define MICROBLAZE_FPU_EXCEPTION	0x06
-#define MICROBLAZE_PRIVILEG_EXCEPTION	0x07
+#define MICROBLAZE_PRIVILEGED_EXCEPTION	0x07
 
 static DEFINE_SPINLOCK(die_lock);
 
@@ -66,6 +66,11 @@
 asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
 							int fsr, int addr)
 {
+#ifdef CONFIG_MMU
+	int code;
+	addr = regs->pc;
+#endif
+
 #if 0
 	printk(KERN_WARNING "Exception %02x in %s mode, FSR=%08x PC=%08x ESR=%08x\n",
 			type, user_mode(regs) ? "user" : "kernel", fsr,
@@ -74,7 +79,13 @@
 
 	switch (type & 0x1F) {
 	case MICROBLAZE_ILL_OPCODE_EXCEPTION:
-		_exception(SIGILL, regs, ILL_ILLOPC, addr);
+		if (user_mode(regs)) {
+			printk(KERN_WARNING "Illegal opcode exception in user mode.\n");
+			_exception(SIGILL, regs, ILL_ILLOPC, addr);
+			return;
+		}
+		printk(KERN_WARNING "Illegal opcode exception in kernel mode.\n");
+		die("opcode exception", regs, SIGBUS);
 		break;
 	case MICROBLAZE_IBUS_EXCEPTION:
 		if (user_mode(regs)) {
@@ -95,11 +106,16 @@
 		die("bus exception", regs, SIGBUS);
 		break;
 	case MICROBLAZE_DIV_ZERO_EXCEPTION:
-		printk(KERN_WARNING "Divide by zero exception\n");
-		_exception(SIGILL, regs, ILL_ILLOPC, addr);
+		if (user_mode(regs)) {
+			printk(KERN_WARNING "Divide by zero exception in user mode\n");
+			_exception(SIGILL, regs, ILL_ILLOPC, addr);
+			return;
+		}
+		printk(KERN_WARNING "Divide by zero exception in kernel mode.\n");
+		die("Divide by exception", regs, SIGBUS);
 		break;
-
 	case MICROBLAZE_FPU_EXCEPTION:
+		printk(KERN_WARNING "FPU exception\n");
 		/* IEEE FP exception */
 		/* I removed fsr variable and use code var for storing fsr */
 		if (fsr & FSR_IO)
@@ -115,7 +131,20 @@
 		_exception(SIGFPE, regs, fsr, addr);
 		break;
 
+#ifdef CONFIG_MMU
+	case MICROBLAZE_PRIVILEGED_EXCEPTION:
+		printk(KERN_WARNING "Privileged exception\n");
+		/* "brk r0,r0" - used as debug breakpoint */
+		if (get_user(code, (unsigned long *)regs->pc) == 0
+			&& code == 0x980c0000) {
+			_exception(SIGTRAP, regs, TRAP_BRKPT, addr);
+		} else {
+			_exception(SIGILL, regs, ILL_PRVOPC, addr);
+		}
+		break;
+#endif
 	default:
+	/* FIXME what to do in unexpected exception */
 		printk(KERN_WARNING "Unexpected exception %02x "
 			"PC=%08x in %s mode\n", type, (unsigned int) addr,
 			kernel_mode(regs) ? "kernel" : "user");
diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S
index 319dc35..e568d6e 100644
--- a/arch/microblaze/kernel/head.S
+++ b/arch/microblaze/kernel/head.S
@@ -3,6 +3,26 @@
  * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
+ * MMU code derived from arch/ppc/kernel/head_4xx.S:
+ *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
+ *      Initial PowerPC version.
+ *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
+ *      Rewritten for PReP
+ *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
+ *      Low-level exception handers, MMU support, and rewrite.
+ *    Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
+ *      PowerPC 8xx modifications.
+ *    Copyright (c) 1998-1999 TiVo, Inc.
+ *      PowerPC 403GCX modifications.
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *      PowerPC 403GCX/405GP modifications.
+ *    Copyright 2000 MontaVista Software Inc.
+ *	PPC405 modifications
+ *      PowerPC 403GCX/405GP modifications.
+ * 	Author: MontaVista Software, Inc.
+ *         	frank_rowand@mvista.com or source@mvista.com
+ * 	   	debbie_chu@mvista.com
+ *
  * This file is subject to the terms and conditions of the GNU General Public
  * License. See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -12,6 +32,22 @@
 #include <asm/thread_info.h>
 #include <asm/page.h>
 
+#ifdef CONFIG_MMU
+#include <asm/setup.h> /* COMMAND_LINE_SIZE */
+#include <asm/mmu.h>
+#include <asm/processor.h>
+
+.data
+.global empty_zero_page
+.align 12
+empty_zero_page:
+	.space	4096
+.global swapper_pg_dir
+swapper_pg_dir:
+	.space	4096
+
+#endif /* CONFIG_MMU */
+
 	.text
 ENTRY(_start)
 	mfs	r1, rmsr
@@ -32,6 +68,123 @@
 	addik	r3, r3, -4 /* descrement loop */
 no_fdt_arg:
 
+#ifdef CONFIG_MMU
+
+#ifndef CONFIG_CMDLINE_BOOL
+/*
+ * handling command line
+ * copy command line to __init_end. There is space for storing command line.
+ */
+	or	r6, r0, r0		/* incremment */
+	ori	r4, r0, __init_end	/* load address of command line */
+	tophys(r4,r4)			/* convert to phys address */
+	ori	r3, r0, COMMAND_LINE_SIZE - 1 /* number of loops */
+_copy_command_line:
+	lbu	r7, r5, r6 /* r7=r5+r6 - r5 contain pointer to command line */
+	sb	r7, r4, r6		/* addr[r4+r6]= r7*/
+	addik	r6, r6, 1		/* increment counting */
+	bgtid	r3, _copy_command_line	/* loop for all entries       */
+	addik	r3, r3, -1		/* descrement loop */
+	addik	r5, r4, 0		/* add new space for command line */
+	tovirt(r5,r5)
+#endif /* CONFIG_CMDLINE_BOOL */
+
+#ifdef NOT_COMPILE
+/* save bram context */
+	or	r6, r0, r0				/* incremment */
+	ori	r4, r0, TOPHYS(_bram_load_start)	/* save bram context */
+	ori	r3, r0, (LMB_SIZE - 4)
+_copy_bram:
+	lw	r7, r0, r6		/* r7 = r0 + r6 */
+	sw	r7, r4, r6		/* addr[r4 + r6] = r7*/
+	addik	r6, r6, 4		/* increment counting */
+	bgtid	r3, _copy_bram		/* loop for all entries */
+	addik	r3, r3, -4		/* descrement loop */
+#endif
+	/* We have to turn on the MMU right away. */
+
+	/*
+	 * Set up the initial MMU state so we can do the first level of
+	 * kernel initialization.  This maps the first 16 MBytes of memory 1:1
+	 * virtual to physical.
+	 */
+	nop
+	addik	r3, r0, 63		/* Invalidate all TLB entries */
+_invalidate:
+	mts	rtlbx, r3
+	mts	rtlbhi, r0			/* flush: ensure V is clear   */
+	bgtid	r3, _invalidate		/* loop for all entries       */
+	addik	r3, r3, -1
+	/* sync */
+
+	/*
+	 * We should still be executing code at physical address area
+	 * RAM_BASEADDR at this point. However, kernel code is at
+	 * a virtual address. So, set up a TLB mapping to cover this once
+	 * translation is enabled.
+	 */
+
+	addik	r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */
+	tophys(r4,r3)			/* Load the kernel physical address */
+
+	mts	rpid,r0			/* Load the kernel PID */
+	nop
+	bri	4
+
+	/*
+	 * Configure and load two entries into TLB slots 0 and 1.
+	 * In case we are pinning TLBs, these are reserved in by the
+	 * other TLB functions.  If not reserving, then it doesn't
+	 * matter where they are loaded.
+	 */
+	andi	r4,r4,0xfffffc00	/* Mask off the real page number */
+	ori	r4,r4,(TLB_WR | TLB_EX)	/* Set the write and execute bits */
+
+	andi	r3,r3,0xfffffc00	/* Mask off the effective page number */
+	ori	r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M))
+
+	mts     rtlbx,r0		/* 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
+
+	ori	r6,r0,1			/* TLB slot 1 */
+	mts     rtlbx,r6
+
+	mts	rtlblo,r4		/* Load the data portion of the entry */
+	mts	rtlbhi,r3		/* Load the tag portion of the entry */
+
+	/*
+	 * 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 */
+	mts     rtlbx,r6
+
+	ori	r4,r0,(TLB_WR | TLB_EX)
+	ori	r3,r0,(TLB_VALID | TLB_PAGESZ(PAGESZ_4K))
+
+	mts	rtlblo,r4		/* Load the data portion of the entry */
+	mts	rtlbhi,r3		/* Load the tag portion of the entry */
+
+	/*
+	 * We now have the lower 16 Meg of RAM mapped into TLB entries, and the
+	 * caches ready to work.
+	 */
+turn_on_mmu:
+	ori	r15,r0,start_here
+	ori	r4,r0,MSR_KERNEL_VMS
+	mts	rmsr,r4
+	nop
+	rted	r15,0			/* enables MMU */
+	nop
+
+start_here:
+#endif /* CONFIG_MMU */
+
 	/* Initialize small data anchors */
 	la	r13, r0, _KERNEL_SDA_BASE_
 	la	r2, r0, _KERNEL_SDA2_BASE_
@@ -51,6 +204,43 @@
 	brald	r15, r8
 	nop
 
+#ifndef CONFIG_MMU
 	la	r15, r0, machine_halt
 	braid	start_kernel
 	nop
+#else
+	/*
+	 * Initialize the MMU.
+	 */
+	bralid	r15, mmu_init
+	nop
+
+	/* Go back to running unmapped so we can load up new values
+	 * and change to using our exception vectors.
+	 * On the MicroBlaze, all we invalidate the used TLB entries to clear
+	 * the old 16M byte TLB mappings.
+	 */
+	ori	r15,r0,TOPHYS(kernel_load_context)
+	ori	r4,r0,MSR_KERNEL
+	mts	rmsr,r4
+	nop
+	bri	4
+	rted	r15,0
+	nop
+
+	/* 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
+	mts     rtlbx,r5
+	nop
+	mts	rtlbhi,r0
+	nop
+	addi	r15, r0, machine_halt
+	ori	r17, r0, start_kernel
+	ori	r4, r0, MSR_KERNEL_VMS
+	mts	rmsr, r4
+	nop
+	rted	r17, 0		/* enable MMU and jump to start_kernel */
+	nop
+#endif /* CONFIG_MMU */
diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S
index cf9486d..9d591cd 100644
--- a/arch/microblaze/kernel/hw_exception_handler.S
+++ b/arch/microblaze/kernel/hw_exception_handler.S
@@ -53,6 +53,12 @@
  *   - Illegal instruction opcode
  *   - Divide-by-zero
  *
+ *   - Privileged instruction exception (MMU)
+ *   - Data storage exception (MMU)
+ *   - Instruction storage exception (MMU)
+ *   - Data TLB miss exception (MMU)
+ *   - Instruction TLB miss exception (MMU)
+ *
  * Note we disable interrupts during exception handling, otherwise we will
  * possibly get multiple re-entrancy if interrupt handles themselves cause
  * exceptions. JW
@@ -71,9 +77,24 @@
 #include <asm/asm-offsets.h>
 
 /* Helpful Macros */
+#ifndef CONFIG_MMU
 #define EX_HANDLER_STACK_SIZ	(4*19)
+#endif
 #define NUM_TO_REG(num)		r ## num
 
+#ifdef CONFIG_MMU
+/* FIXME you can't change first load of MSR because there is
+ * hardcoded jump bri 4 */
+	#define RESTORE_STATE			\
+		lwi	r3, r1, PT_R3;		\
+		lwi	r4, r1, PT_R4;		\
+		lwi	r5, r1, PT_R5;		\
+		lwi	r6, r1, PT_R6;		\
+		lwi	r11, r1, PT_R11;	\
+		lwi	r31, r1, PT_R31;	\
+		lwi	r1, r0, TOPHYS(r0_ram + 0);
+#endif /* CONFIG_MMU */
+
 #define LWREG_NOP			\
 	bri	ex_handler_unhandled;	\
 	nop;
@@ -106,6 +127,54 @@
 	or	r3, r0, NUM_TO_REG (regnum);		\
 	bri	ex_sw_tail;
 
+#ifdef CONFIG_MMU
+	#define R3_TO_LWREG_VM_V(regnum)		\
+		brid	ex_lw_end_vm;			\
+		swi	r3, r7, 4 * regnum;
+
+	#define R3_TO_LWREG_VM(regnum)			\
+		brid	ex_lw_end_vm;			\
+		or	NUM_TO_REG (regnum), r0, r3;
+
+	#define SWREG_TO_R3_VM_V(regnum)		\
+		brid	ex_sw_tail_vm;			\
+		lwi	r3, r7, 4 * regnum;
+
+	#define SWREG_TO_R3_VM(regnum)			\
+		brid	ex_sw_tail_vm;			\
+		or	r3, r0, NUM_TO_REG (regnum);
+
+	/* Shift right instruction depending on available configuration */
+	#if CONFIG_XILINX_MICROBLAZE0_USE_BARREL > 0
+	#define BSRLI(rD, rA, imm)	\
+		bsrli rD, rA, imm
+	#elif CONFIG_XILINX_MICROBLAZE0_USE_DIV > 0
+	#define BSRLI(rD, rA, imm)	\
+		ori rD, r0, (1 << imm);	\
+		idivu rD, rD, rA
+	#else
+	#define BSRLI(rD, rA, imm) BSRLI ## imm (rD, rA)
+	/* Only the used shift constants defined here - add more if needed */
+	#define BSRLI2(rD, rA)				\
+		srl rD, rA;		/* << 1 */	\
+		srl rD, rD;		/* << 2 */
+	#define BSRLI10(rD, rA)				\
+		srl rD, rA;		/* << 1 */	\
+		srl rD, rD;		/* << 2 */	\
+		srl rD, rD;		/* << 3 */	\
+		srl rD, rD;		/* << 4 */	\
+		srl rD, rD;		/* << 5 */	\
+		srl rD, rD;		/* << 6 */	\
+		srl rD, rD;		/* << 7 */	\
+		srl rD, rD;		/* << 8 */	\
+		srl rD, rD;		/* << 9 */	\
+		srl rD, rD		/* << 10 */
+	#define BSRLI20(rD, rA)		\
+		BSRLI10(rD, rA);	\
+		BSRLI10(rD, rD)
+	#endif
+#endif /* CONFIG_MMU */
+
 .extern other_exception_handler /* Defined in exception.c */
 
 /*
@@ -163,34 +232,119 @@
 
 /* wrappers to restore state before coming to entry.S */
 
+#ifdef CONFIG_MMU
+.section .rodata
+.align 4
+_MB_HW_ExceptionVectorTable:
+/*  0 - Undefined */
+	.long	TOPHYS(ex_handler_unhandled)
+/*  1 - Unaligned data access exception */
+	.long	TOPHYS(handle_unaligned_ex)
+/*  2 - Illegal op-code exception */
+	.long	TOPHYS(full_exception_trapw)
+/*  3 - Instruction bus error exception */
+	.long	TOPHYS(full_exception_trapw)
+/*  4 - Data bus error exception */
+	.long	TOPHYS(full_exception_trapw)
+/*  5 - Divide by zero exception */
+	.long	TOPHYS(full_exception_trapw)
+/*  6 - Floating point unit exception */
+	.long	TOPHYS(full_exception_trapw)
+/*  7 - Privileged instruction exception */
+	.long	TOPHYS(full_exception_trapw)
+/*  8 - 15 - Undefined */
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+/* 16 - Data storage exception */
+	.long	TOPHYS(handle_data_storage_exception)
+/* 17 - Instruction storage exception */
+	.long	TOPHYS(handle_instruction_storage_exception)
+/* 18 - Data TLB miss exception */
+	.long	TOPHYS(handle_data_tlb_miss_exception)
+/* 19 - Instruction TLB miss exception */
+	.long	TOPHYS(handle_instruction_tlb_miss_exception)
+/* 20 - 31 - Undefined */
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+	.long	TOPHYS(ex_handler_unhandled)
+#endif
+
 .global _hw_exception_handler
 .section .text
 .align 4
 .ent _hw_exception_handler
 _hw_exception_handler:
+#ifndef CONFIG_MMU
 	addik	r1, r1, -(EX_HANDLER_STACK_SIZ); /* Create stack frame */
+#else
+	swi	r1, r0, TOPHYS(r0_ram + 0); /* GET_SP */
+	/* Save date to kernel memory. Here is the problem
+	 * when you came from user space */
+	ori	r1, r0, TOPHYS(r0_ram + 28);
+#endif
 	swi	r3, r1, PT_R3
 	swi	r4, r1, PT_R4
 	swi	r5, r1, PT_R5
 	swi	r6, r1, PT_R6
 
-	mfs	r5, rmsr;
-	nop
-	swi	r5, r1, 0;
-	mfs	r4, rbtr	/* Save BTR before jumping to handler */
-	nop
+#ifdef CONFIG_MMU
+	swi	r11, r1, PT_R11
+	swi	r31, r1, PT_R31
+	lwi	r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)) /* get saved current */
+#endif
+
 	mfs	r3, resr
 	nop
+	mfs	r4, rear;
+	nop
 
+#ifndef CONFIG_MMU
 	andi	r5, r3, 0x1000;		/* Check ESR[DS] */
 	beqi	r5, not_in_delay_slot;	/* Branch if ESR[DS] not set */
 	mfs	r17, rbtr;	/* ESR[DS] set - return address in BTR */
 	nop
 not_in_delay_slot:
 	swi	r17, r1, PT_R17
+#endif
 
 	andi	r5, r3, 0x1F;		/* Extract ESR[EXC] */
 
+#ifdef CONFIG_MMU
+	/* Calculate exception vector offset = r5 << 2 */
+	addk	r6, r5, r5; /* << 1 */
+	addk	r6, r6, r6; /* << 2 */
+
+/* counting which exception happen */
+	lwi	r5, r0, 0x200 + TOPHYS(r0_ram)
+	addi	r5, r5, 1
+	swi	r5, r0, 0x200 + TOPHYS(r0_ram)
+	lwi	r5, r6, 0x200 + TOPHYS(r0_ram)
+	addi	r5, r5, 1
+	swi	r5, r6, 0x200 + TOPHYS(r0_ram)
+/* end */
+	/* Load the HW Exception vector */
+	lwi	r6, r6, TOPHYS(_MB_HW_ExceptionVectorTable)
+	bra	r6
+
+full_exception_trapw:
+	RESTORE_STATE
+	bri	full_exception_trap
+#else
 	/* Exceptions enabled here. This will allow nested exceptions */
 	mfs	r6, rmsr;
 	nop
@@ -254,6 +408,7 @@
 	lwi	r18, r1, PT_R18
 
 	bri	ex_handler_done; /* Complete exception handling */
+#endif
 
 /* 0x01 - Unaligned data access exception
  * This occurs when a word access is not aligned on a word boundary,
@@ -265,11 +420,28 @@
 handle_unaligned_ex:
 	/* Working registers already saved: R3, R4, R5, R6
 	 *  R3 = ESR
-	 *  R4 = BTR
+	 *  R4 = EAR
 	 */
-	mfs	r4, rear;
+#ifdef CONFIG_MMU
+	andi	r6, r3, 0x1000			/* Check ESR[DS] */
+	beqi	r6, _no_delayslot		/* Branch if ESR[DS] not set */
+	mfs	r17, rbtr;	/* ESR[DS] set - return address in BTR */
 	nop
+_no_delayslot:
+#endif
 
+#ifdef CONFIG_MMU
+	/* Check if unaligned address is last on a 4k page */
+		andi	r5, r4, 0xffc
+		xori	r5, r5, 0xffc
+		bnei	r5, _unaligned_ex2
+	_unaligned_ex1:
+		RESTORE_STATE;
+/* Another page must be accessed or physical address not in page table */
+		bri	unaligned_data_trap
+
+	_unaligned_ex2:
+#endif
 	andi	r6, r3, 0x3E0; /* Mask and extract the register operand */
 	srl	r6, r6; /* r6 >> 5 */
 	srl	r6, r6;
@@ -278,6 +450,45 @@
 	srl	r6, r6;
 	/* Store the register operand in a temporary location */
 	sbi	r6, r0, TOPHYS(ex_reg_op);
+#ifdef CONFIG_MMU
+	/* Get physical address */
+	/* If we are faulting a kernel address, we have to use the
+	 * kernel page tables.
+	 */
+	ori	r5, r0, CONFIG_KERNEL_START
+	cmpu	r5, r4, r5
+	bgti	r5, _unaligned_ex3
+	ori	r5, r0, swapper_pg_dir
+	bri	_unaligned_ex4
+
+	/* Get the PGD for the current thread. */
+_unaligned_ex3: /* user thread */
+	addi	r5 ,CURRENT_TASK, TOPHYS(0); /* get current task address */
+	lwi	r5, r5, TASK_THREAD + PGDIR
+_unaligned_ex4:
+	tophys(r5,r5)
+	BSRLI(r6,r4,20)			/* Create L1 (pgdir/pmd) address */
+	andi	r6, r6, 0xffc
+/* Assume pgdir aligned on 4K boundary, no need for "andi r5,r5,0xfffff003" */
+	or	r5, r5, r6
+	lwi	r6, r5, 0		/* Get L1 entry */
+	andi	r5, r6, 0xfffff000	/* Extract L2 (pte) base address. */
+	beqi	r5, _unaligned_ex1	/* Bail if no table */
+
+	tophys(r5,r5)
+	BSRLI(r6,r4,10)			/* Compute PTE address */
+	andi	r6, r6, 0xffc
+	andi	r5, r5, 0xfffff003
+	or	r5, r5, r6
+	lwi	r5, r5, 0		/* Get Linux PTE */
+
+	andi	r6, r5, _PAGE_PRESENT
+	beqi	r6, _unaligned_ex1	/* Bail if no page */
+
+	andi	r5, r5, 0xfffff000	/* Extract RPN */
+	andi	r4, r4, 0x00000fff	/* Extract offset */
+	or	r4, r4, r5		/* Create physical address */
+#endif /* CONFIG_MMU */
 
 	andi	r6, r3, 0x400; /* Extract ESR[S] */
 	bnei	r6, ex_sw;
@@ -355,6 +566,7 @@
 ex_sw_end: /* Exception handling of store word, ends. */
 
 ex_handler_done:
+#ifndef CONFIG_MMU
 	lwi	r5, r1, 0 /* RMSR */
 	mts	rmsr, r5
 	nop
@@ -366,13 +578,455 @@
 
 	rted	r17, 0
 	addik	r1, r1, (EX_HANDLER_STACK_SIZ); /* Restore stack frame */
+#else
+	RESTORE_STATE;
+	rted	r17, 0
+	nop
+#endif
 
+#ifdef CONFIG_MMU
+	/* Exception vector entry code. This code runs with address translation
+	 * turned off (i.e. using physical addresses). */
+
+	/* Exception vectors. */
+
+	/* 0x10 - Data Storage Exception
+	 * This happens for just a few reasons. U0 set (but we don't do that),
+	 * or zone protection fault (user violation, write to protected page).
+	 * If this is just an update of modified status, we do that quickly
+	 * and exit. Otherwise, we call heavyweight functions to do the work.
+	 */
+	handle_data_storage_exception:
+		/* Working registers already saved: R3, R4, R5, R6
+		 * R3 = ESR
+		 */
+		mfs	r11, rpid
+		nop
+		bri	4
+		mfs	r3, rear		/* Get faulting address */
+		nop
+		/* If we are faulting a kernel address, we have to use the
+		 * kernel page tables.
+		 */
+		ori	r4, r0, CONFIG_KERNEL_START
+		cmpu	r4, r3, r4
+		bgti	r4, ex3
+		/* First, check if it was a zone fault (which means a user
+		 * tried to access a kernel or read-protected page - always
+		 * a SEGV). All other faults here must be stores, so no
+		 * need to check ESR_S as well. */
+		mfs	r4, resr
+		nop
+		andi	r4, r4, 0x800		/* ESR_Z - zone protection */
+		bnei	r4, ex2
+
+		ori	r4, r0, swapper_pg_dir
+		mts	rpid, r0		/* TLB will have 0 TID */
+		nop
+		bri	ex4
+
+		/* Get the PGD for the current thread. */
+	ex3:
+		/* First, check if it was a zone fault (which means a user
+		 * tried to access a kernel or read-protected page - always
+		 * a SEGV). All other faults here must be stores, so no
+		 * need to check ESR_S as well. */
+		mfs	r4, resr
+		nop
+		andi	r4, r4, 0x800		/* ESR_Z */
+		bnei	r4, ex2
+		/* get current task address */
+		addi	r4 ,CURRENT_TASK, TOPHYS(0);
+		lwi	r4, r4, TASK_THREAD+PGDIR
+	ex4:
+		tophys(r4,r4)
+		BSRLI(r5,r3,20)		/* Create L1 (pgdir/pmd) address */
+		andi	r5, r5, 0xffc
+/* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
+		or	r4, r4, r5
+		lwi	r4, r4, 0		/* Get L1 entry */
+		andi	r5, r4, 0xfffff000 /* Extract L2 (pte) base address */
+		beqi	r5, ex2			/* Bail if no table */
+
+		tophys(r5,r5)
+		BSRLI(r6,r3,10)			/* Compute PTE address */
+		andi	r6, r6, 0xffc
+		andi	r5, r5, 0xfffff003
+		or	r5, r5, r6
+		lwi	r4, r5, 0		/* Get Linux PTE */
+
+		andi	r6, r4, _PAGE_RW	/* Is it writeable? */
+		beqi	r6, ex2			/* Bail if not */
+
+		/* Update 'changed' */
+		ori	r4, r4, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
+		swi	r4, r5, 0		/* Update Linux page table */
+
+		/* Most of the Linux PTE is ready to load into the TLB LO.
+		 * We set ZSEL, where only the LS-bit determines user access.
+		 * We set execute, because we don't have the granularity to
+		 * properly set this at the page level (Linux problem).
+		 * If shared is set, we cause a zero PID->TID load.
+		 * Many of these bits are software only. Bits we don't set
+		 * here we (properly should) assume have the appropriate value.
+		 */
+		andni	r4, r4, 0x0ce2		/* Make sure 20, 21 are zero */
+		ori	r4, r4, _PAGE_HWEXEC	/* make it executable */
+
+		/* find the TLB index that caused the fault. It has to be here*/
+		mts	rtlbsx, r3
+		nop
+		mfs	r5, rtlbx		/* DEBUG: TBD */
+		nop
+		mts	rtlblo, r4		/* Load TLB LO */
+		nop
+						/* Will sync shadow TLBs */
+
+		/* Done...restore registers and get out of here. */
+		mts	rpid, r11
+		nop
+		bri 4
+
+		RESTORE_STATE;
+		rted	r17, 0
+		nop
+	ex2:
+		/* The bailout. Restore registers to pre-exception conditions
+		 * and call the heavyweights to help us out. */
+		mts	rpid, r11
+		nop
+		bri 4
+		RESTORE_STATE;
+		bri	page_fault_data_trap
+
+
+	/* 0x11 - Instruction Storage Exception
+	 * This is caused by a fetch from non-execute or guarded pages. */
+	handle_instruction_storage_exception:
+		/* Working registers already saved: R3, R4, R5, R6
+		 * R3 = ESR
+		 */
+
+		mfs	r3, rear		/* Get faulting address */
+		nop
+		RESTORE_STATE;
+		bri	page_fault_instr_trap
+
+	/* 0x12 - Data TLB Miss Exception
+	 * As the name implies, translation is not in the MMU, so search the
+	 * page tables and fix it. The only purpose of this function is to
+	 * load TLB entries from the page table if they exist.
+	 */
+	handle_data_tlb_miss_exception:
+		/* Working registers already saved: R3, R4, R5, R6
+		 * R3 = ESR
+		 */
+		mfs	r11, rpid
+		nop
+		bri	4
+		mfs	r3, rear		/* Get faulting address */
+		nop
+
+		/* If we are faulting a kernel address, we have to use the
+		 * kernel page tables. */
+		ori	r4, r0, CONFIG_KERNEL_START
+		cmpu	r4, r3, r4
+		bgti	r4, ex5
+		ori	r4, r0, swapper_pg_dir
+		mts	rpid, r0		/* TLB will have 0 TID */
+		nop
+		bri	ex6
+
+		/* Get the PGD for the current thread. */
+	ex5:
+		/* get current task address */
+		addi	r4 ,CURRENT_TASK, TOPHYS(0);
+		lwi	r4, r4, TASK_THREAD+PGDIR
+	ex6:
+		tophys(r4,r4)
+		BSRLI(r5,r3,20)		/* Create L1 (pgdir/pmd) address */
+		andi	r5, r5, 0xffc
+/* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
+		or	r4, r4, r5
+		lwi	r4, r4, 0		/* Get L1 entry */
+		andi	r5, r4, 0xfffff000 /* Extract L2 (pte) base address */
+		beqi	r5, ex7			/* Bail if no table */
+
+		tophys(r5,r5)
+		BSRLI(r6,r3,10)			/* Compute PTE address */
+		andi	r6, r6, 0xffc
+		andi	r5, r5, 0xfffff003
+		or	r5, r5, r6
+		lwi	r4, r5, 0		/* Get Linux PTE */
+
+		andi	r6, r4, _PAGE_PRESENT
+		beqi	r6, ex7
+
+		ori	r4, r4, _PAGE_ACCESSED
+		swi	r4, r5, 0
+
+		/* Most of the Linux PTE is ready to load into the TLB LO.
+		 * We set ZSEL, where only the LS-bit determines user access.
+		 * We set execute, because we don't have the granularity to
+		 * properly set this at the page level (Linux problem).
+		 * If shared is set, we cause a zero PID->TID load.
+		 * Many of these bits are software only. Bits we don't set
+		 * here we (properly should) assume have the appropriate value.
+		 */
+		andni	r4, r4, 0x0ce2		/* Make sure 20, 21 are zero */
+
+		bri	finish_tlb_load
+	ex7:
+		/* The bailout. Restore registers to pre-exception conditions
+		 * and call the heavyweights to help us out.
+		 */
+		mts	rpid, r11
+		nop
+		bri	4
+		RESTORE_STATE;
+		bri	page_fault_data_trap
+
+	/* 0x13 - Instruction TLB Miss Exception
+	 * Nearly the same as above, except we get our information from
+	 * different registers and bailout to a different point.
+	 */
+	handle_instruction_tlb_miss_exception:
+		/* Working registers already saved: R3, R4, R5, R6
+		 *  R3 = ESR
+		 */
+		mfs	r11, rpid
+		nop
+		bri	4
+		mfs	r3, rear		/* Get faulting address */
+		nop
+
+		/* If we are faulting a kernel address, we have to use the
+		 * kernel page tables.
+		 */
+		ori	r4, r0, CONFIG_KERNEL_START
+		cmpu	r4, r3, r4
+		bgti	r4, ex8
+		ori	r4, r0, swapper_pg_dir
+		mts	rpid, r0		/* TLB will have 0 TID */
+		nop
+		bri	ex9
+
+		/* Get the PGD for the current thread. */
+	ex8:
+		/* get current task address */
+		addi	r4 ,CURRENT_TASK, TOPHYS(0);
+		lwi	r4, r4, TASK_THREAD+PGDIR
+	ex9:
+		tophys(r4,r4)
+		BSRLI(r5,r3,20)		/* Create L1 (pgdir/pmd) address */
+		andi	r5, r5, 0xffc
+/* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
+		or	r4, r4, r5
+		lwi	r4, r4, 0		/* Get L1 entry */
+		andi	r5, r4, 0xfffff000 /* Extract L2 (pte) base address */
+		beqi	r5, ex10		/* Bail if no table */
+
+		tophys(r5,r5)
+		BSRLI(r6,r3,10)			/* Compute PTE address */
+		andi	r6, r6, 0xffc
+		andi	r5, r5, 0xfffff003
+		or	r5, r5, r6
+		lwi	r4, r5, 0		/* Get Linux PTE */
+
+		andi	r6, r4, _PAGE_PRESENT
+		beqi	r6, ex7
+
+		ori	r4, r4, _PAGE_ACCESSED
+		swi	r4, r5, 0
+
+		/* Most of the Linux PTE is ready to load into the TLB LO.
+		 * We set ZSEL, where only the LS-bit determines user access.
+		 * We set execute, because we don't have the granularity to
+		 * properly set this at the page level (Linux problem).
+		 * If shared is set, we cause a zero PID->TID load.
+		 * Many of these bits are software only. Bits we don't set
+		 * here we (properly should) assume have the appropriate value.
+		 */
+		andni	r4, r4, 0x0ce2		/* Make sure 20, 21 are zero */
+
+		bri	finish_tlb_load
+	ex10:
+		/* The bailout. Restore registers to pre-exception conditions
+		 * and call the heavyweights to help us out.
+		 */
+		mts	rpid, r11
+		nop
+		bri 4
+		RESTORE_STATE;
+		bri	page_fault_instr_trap
+
+/* Both the instruction and data TLB miss get to this point to load the TLB.
+ *	r3 - EA of fault
+ *	r4 - TLB LO (info from Linux PTE)
+ *	r5, r6 - available to use
+ *	PID - loaded with proper value when we get here
+ *	Upon exit, we reload everything and RFI.
+ * A common place to load the TLB.
+ */
+	tlb_index:
+		.long	1 /* MS: storing last used tlb index */
+	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)
+		ori	r6, r0, 1
+		cmp	r31, r5, r6
+		blti	r31, sem
+		addik	r5, r6, 1
+	sem:
+		/* MS: save back current TLB index */
+		swi	r5, r0, TOPHYS(tlb_index)
+
+		ori	r4, r4, _PAGE_HWEXEC	/* make it executable */
+		mts	rtlbx, r5		/* MS: save current TLB */
+		nop
+		mts	rtlblo,	r4		/* MS: save to TLB LO */
+		nop
+
+		/* Create EPN. This is the faulting address plus a static
+		 * set of bits. These are size, valid, E, U0, and ensure
+		 * bits 20 and 21 are zero.
+		 */
+		andi	r3, r3, 0xfffff000
+		ori	r3, r3, 0x0c0
+		mts	rtlbhi,	r3		/* Load TLB HI */
+		nop
+
+		/* Done...restore registers and get out of here. */
+	ex12:
+		mts	rpid, r11
+		nop
+		bri 4
+		RESTORE_STATE;
+		rted	r17, 0
+		nop
+
+	/* extern void giveup_fpu(struct task_struct *prev)
+	 *
+	 * The MicroBlaze processor may have an FPU, so this should not just
+	 * return: TBD.
+	 */
+	.globl giveup_fpu;
+	.align 4;
+	giveup_fpu:
+		bralid	r15,0			/* TBD */
+		nop
+
+	/* At present, this routine just hangs. - extern void abort(void) */
+	.globl abort;
+	.align 4;
+	abort:
+		br	r0
+
+	.globl set_context;
+	.align 4;
+	set_context:
+		mts	rpid, r5	/* Shadow TLBs are automatically */
+		nop
+		bri	4		/* flushed by changing PID */
+		rtsd	r15,8
+		nop
+
+#endif
 .end _hw_exception_handler
 
+#ifdef CONFIG_MMU
+/* Unaligned data access exception last on a 4k page for MMU.
+ * When this is called, we are in virtual mode with exceptions enabled
+ * and registers 1-13,15,17,18 saved.
+ *
+ * R3 = ESR
+ * R4 = EAR
+ * R7 = pointer to saved registers (struct pt_regs *regs)
+ *
+ * This handler perform the access, and returns via ret_from_exc.
+ */
+.global _unaligned_data_exception
+.ent _unaligned_data_exception
+_unaligned_data_exception:
+	andi	r8, r3, 0x3E0;	/* Mask and extract the register operand */
+	BSRLI(r8,r8,2);		/* r8 >> 2 = register operand * 8 */
+	andi	r6, r3, 0x400;	/* Extract ESR[S] */
+	bneid	r6, ex_sw_vm;
+	andi	r6, r3, 0x800;	/* Extract ESR[W] - delay slot */
+ex_lw_vm:
+	beqid	r6, ex_lhw_vm;
+	lbui	r5, r4, 0;	/* Exception address in r4 - delay slot */
+/* Load a word, byte-by-byte from destination address and save it in tmp space*/
+	la	r6, r0, ex_tmp_data_loc_0;
+	sbi	r5, r6, 0;
+	lbui	r5, r4, 1;
+	sbi	r5, r6, 1;
+	lbui	r5, r4, 2;
+	sbi	r5, r6, 2;
+	lbui	r5, r4, 3;
+	sbi	r5, r6, 3;
+	brid	ex_lw_tail_vm;
+/* Get the destination register value into r3 - delay slot */
+	lwi	r3, r6, 0;
+ex_lhw_vm:
+	/* Load a half-word, byte-by-byte from destination address and
+	 * save it in tmp space */
+	la	r6, r0, ex_tmp_data_loc_0;
+	sbi	r5, r6, 0;
+	lbui	r5, r4, 1;
+	sbi	r5, r6, 1;
+	lhui	r3, r6, 0;	/* Get the destination register value into r3 */
+ex_lw_tail_vm:
+	/* Form load_word jump table offset (lw_table_vm + (8 * regnum)) */
+	addik	r5, r8, lw_table_vm;
+	bra	r5;
+ex_lw_end_vm:			/* Exception handling of load word, ends */
+	brai	ret_from_exc;
+ex_sw_vm:
+/* Form store_word jump table offset (sw_table_vm + (8 * regnum)) */
+	addik	r5, r8, sw_table_vm;
+	bra	r5;
+ex_sw_tail_vm:
+	la	r5, r0, ex_tmp_data_loc_0;
+	beqid	r6, ex_shw_vm;
+	swi	r3, r5, 0;	/* Get the word - delay slot */
+	/* Store the word, byte-by-byte into destination address */
+	lbui	r3, r5, 0;
+	sbi	r3, r4, 0;
+	lbui	r3, r5, 1;
+	sbi	r3, r4, 1;
+	lbui	r3, r5, 2;
+	sbi	r3, r4, 2;
+	lbui	r3, r5, 3;
+	brid	ret_from_exc;
+	sbi	r3, r4, 3;	/* Delay slot */
+ex_shw_vm:
+	/* Store the lower half-word, byte-by-byte into destination address */
+	lbui	r3, r5, 2;
+	sbi	r3, r4, 0;
+	lbui	r3, r5, 3;
+	brid	ret_from_exc;
+	sbi	r3, r4, 1;	/* Delay slot */
+ex_sw_end_vm:			/* Exception handling of store word, ends. */
+.end _unaligned_data_exception
+#endif /* CONFIG_MMU */
+
 ex_handler_unhandled:
 /* FIXME add handle function for unhandled exception - dump register */
 	bri 0
 
+/*
+ * hw_exception_handler Jump Table
+ * - Contains code snippets for each register that caused the unalign exception
+ * - Hence exception handler is NOT self-modifying
+ * - Separate table for load exceptions and store exceptions.
+ * - Each table is of size: (8 * 32) = 256 bytes
+ */
+
 .section .text
 .align 4
 lw_table:
@@ -407,7 +1061,11 @@
 lw_r28:		R3_TO_LWREG	(28);
 lw_r29:		R3_TO_LWREG	(29);
 lw_r30:		R3_TO_LWREG	(30);
+#ifdef CONFIG_MMU
+lw_r31: 	R3_TO_LWREG_V	(31);
+#else
 lw_r31:		R3_TO_LWREG	(31);
+#endif
 
 sw_table:
 sw_r0:		SWREG_TO_R3	(0);
@@ -441,7 +1099,81 @@
 sw_r28:		SWREG_TO_R3	(28);
 sw_r29:		SWREG_TO_R3	(29);
 sw_r30:		SWREG_TO_R3	(30);
+#ifdef CONFIG_MMU
+sw_r31:		SWREG_TO_R3_V	(31);
+#else
 sw_r31:		SWREG_TO_R3	(31);
+#endif
+
+#ifdef CONFIG_MMU
+lw_table_vm:
+lw_r0_vm:	R3_TO_LWREG_VM		(0);
+lw_r1_vm:	R3_TO_LWREG_VM_V	(1);
+lw_r2_vm:	R3_TO_LWREG_VM_V	(2);
+lw_r3_vm:	R3_TO_LWREG_VM_V	(3);
+lw_r4_vm:	R3_TO_LWREG_VM_V	(4);
+lw_r5_vm:	R3_TO_LWREG_VM_V	(5);
+lw_r6_vm:	R3_TO_LWREG_VM_V	(6);
+lw_r7_vm:	R3_TO_LWREG_VM_V	(7);
+lw_r8_vm:	R3_TO_LWREG_VM_V	(8);
+lw_r9_vm:	R3_TO_LWREG_VM_V	(9);
+lw_r10_vm:	R3_TO_LWREG_VM_V	(10);
+lw_r11_vm:	R3_TO_LWREG_VM_V	(11);
+lw_r12_vm:	R3_TO_LWREG_VM_V	(12);
+lw_r13_vm:	R3_TO_LWREG_VM_V	(13);
+lw_r14_vm:	R3_TO_LWREG_VM		(14);
+lw_r15_vm:	R3_TO_LWREG_VM_V	(15);
+lw_r16_vm:	R3_TO_LWREG_VM		(16);
+lw_r17_vm:	R3_TO_LWREG_VM_V	(17);
+lw_r18_vm:	R3_TO_LWREG_VM_V	(18);
+lw_r19_vm:	R3_TO_LWREG_VM		(19);
+lw_r20_vm:	R3_TO_LWREG_VM		(20);
+lw_r21_vm:	R3_TO_LWREG_VM		(21);
+lw_r22_vm:	R3_TO_LWREG_VM		(22);
+lw_r23_vm:	R3_TO_LWREG_VM		(23);
+lw_r24_vm:	R3_TO_LWREG_VM		(24);
+lw_r25_vm:	R3_TO_LWREG_VM		(25);
+lw_r26_vm:	R3_TO_LWREG_VM		(26);
+lw_r27_vm:	R3_TO_LWREG_VM		(27);
+lw_r28_vm:	R3_TO_LWREG_VM		(28);
+lw_r29_vm:	R3_TO_LWREG_VM		(29);
+lw_r30_vm:	R3_TO_LWREG_VM		(30);
+lw_r31_vm:	R3_TO_LWREG_VM_V	(31);
+
+sw_table_vm:
+sw_r0_vm:	SWREG_TO_R3_VM		(0);
+sw_r1_vm:	SWREG_TO_R3_VM_V	(1);
+sw_r2_vm:	SWREG_TO_R3_VM_V	(2);
+sw_r3_vm:	SWREG_TO_R3_VM_V	(3);
+sw_r4_vm:	SWREG_TO_R3_VM_V	(4);
+sw_r5_vm:	SWREG_TO_R3_VM_V	(5);
+sw_r6_vm:	SWREG_TO_R3_VM_V	(6);
+sw_r7_vm:	SWREG_TO_R3_VM_V	(7);
+sw_r8_vm:	SWREG_TO_R3_VM_V	(8);
+sw_r9_vm:	SWREG_TO_R3_VM_V	(9);
+sw_r10_vm:	SWREG_TO_R3_VM_V	(10);
+sw_r11_vm:	SWREG_TO_R3_VM_V	(11);
+sw_r12_vm:	SWREG_TO_R3_VM_V	(12);
+sw_r13_vm:	SWREG_TO_R3_VM_V	(13);
+sw_r14_vm:	SWREG_TO_R3_VM		(14);
+sw_r15_vm:	SWREG_TO_R3_VM_V	(15);
+sw_r16_vm:	SWREG_TO_R3_VM		(16);
+sw_r17_vm:	SWREG_TO_R3_VM_V	(17);
+sw_r18_vm:	SWREG_TO_R3_VM_V	(18);
+sw_r19_vm:	SWREG_TO_R3_VM		(19);
+sw_r20_vm:	SWREG_TO_R3_VM		(20);
+sw_r21_vm:	SWREG_TO_R3_VM		(21);
+sw_r22_vm:	SWREG_TO_R3_VM		(22);
+sw_r23_vm:	SWREG_TO_R3_VM		(23);
+sw_r24_vm:	SWREG_TO_R3_VM		(24);
+sw_r25_vm:	SWREG_TO_R3_VM		(25);
+sw_r26_vm:	SWREG_TO_R3_VM		(26);
+sw_r27_vm:	SWREG_TO_R3_VM		(27);
+sw_r28_vm:	SWREG_TO_R3_VM		(28);
+sw_r29_vm:	SWREG_TO_R3_VM		(29);
+sw_r30_vm:	SWREG_TO_R3_VM		(30);
+sw_r31_vm:	SWREG_TO_R3_VM_V	(31);
+#endif /* CONFIG_MMU */
 
 /* Temporary data structures used in the handler */
 .section .data
diff --git a/arch/microblaze/kernel/microblaze_ksyms.c b/arch/microblaze/kernel/microblaze_ksyms.c
index 5f71790..59ff20e 100644
--- a/arch/microblaze/kernel/microblaze_ksyms.c
+++ b/arch/microblaze/kernel/microblaze_ksyms.c
@@ -45,3 +45,5 @@
 EXPORT_SYMBOL(__udivsi3);
 extern void __umodsi3(void);
 EXPORT_SYMBOL(__umodsi3);
+extern char *_ebss;
+EXPORT_SYMBOL_GPL(_ebss);
diff --git a/arch/microblaze/kernel/misc.S b/arch/microblaze/kernel/misc.S
new file mode 100644
index 0000000..df16c62
--- /dev/null
+++ b/arch/microblaze/kernel/misc.S
@@ -0,0 +1,120 @@
+/*
+ * Miscellaneous low-level MMU functions.
+ *
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
+ * Copyright (C) 2007 Xilinx, Inc.  All rights reserved.
+ *
+ * Derived from arch/ppc/kernel/misc.S
+ *
+ * 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/linkage.h>
+#include <linux/sys.h>
+#include <asm/unistd.h>
+#include <linux/errno.h>
+#include <asm/mmu.h>
+#include <asm/page.h>
+
+	.text
+/*
+ * Flush MMU TLB
+ *
+ * We avoid flushing the pinned 0, 1 and possibly 2 entries.
+ */
+.globl _tlbia;
+.align 4;
+_tlbia:
+	addik	r12, r0, 63 /* flush all entries (63 - 3) */
+	/* isync */
+_tlbia_1:
+	mts	rtlbx, r12
+	nop
+	mts	rtlbhi, r0 /* flush: ensure V is clear */
+	nop
+	addik	r11, r12, -2
+	bneid	r11, _tlbia_1 /* loop for all entries */
+	addik	r12, r12, -1
+	/* sync */
+	rtsd	r15, 8
+	nop
+
+/*
+ * Flush MMU TLB for a particular address (in r5)
+ */
+.globl _tlbie;
+.align 4;
+_tlbie:
+	mts	rtlbsx, r5 /* look up the address in TLB */
+	nop
+	mfs	r12, rtlbx /* Retrieve index */
+	nop
+	blti	r12, _tlbie_1 /* Check if found */
+	mts	rtlbhi, r0 /* flush: ensure V is clear */
+	nop
+_tlbie_1:
+	rtsd	r15, 8
+	nop
+
+/*
+ * Allocate TLB entry for early console
+ */
+.globl early_console_reg_tlb_alloc;
+.align 4;
+early_console_reg_tlb_alloc:
+	/*
+	 * 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, 63
+	mts	rtlbx, r4 /* TLB slot 2 */
+
+	or	r4,r5,r0
+	andi	r4,r4,0xfffff000
+	ori	r4,r4,(TLB_WR|TLB_I|TLB_M|TLB_G)
+
+	andi	r5,r5,0xfffff000
+	ori	r5,r5,(TLB_VALID | TLB_PAGESZ(PAGESZ_4K))
+
+	mts	rtlblo,r4 /* Load the data portion of the entry */
+	nop
+	mts	rtlbhi,r5 /* Load the tag portion of the entry */
+	nop
+	rtsd	r15, 8
+	nop
+
+/*
+ * Copy a whole page (4096 bytes).
+ */
+#define COPY_16_BYTES		\
+	lwi	r7, r6, 0;	\
+	lwi	r8, r6, 4;	\
+	lwi	r9, r6, 8;	\
+	lwi	r10, r6, 12;	\
+	swi	r7, r5, 0;	\
+	swi	r8, r5, 4;	\
+	swi	r9, r5, 8;	\
+	swi	r10, r5, 12
+
+
+/* FIXME DCACHE_LINE_BYTES (CONFIG_XILINX_MICROBLAZE0_DCACHE_LINE_LEN * 4)*/
+#define DCACHE_LINE_BYTES (4 * 4)
+
+.globl copy_page;
+.align 4;
+copy_page:
+	ori	r11, r0, (PAGE_SIZE/DCACHE_LINE_BYTES) - 1
+_copy_page_loop:
+	COPY_16_BYTES
+#if DCACHE_LINE_BYTES >= 32
+	COPY_16_BYTES
+#endif
+	addik	r6, r6, DCACHE_LINE_BYTES
+	addik	r5, r5, DCACHE_LINE_BYTES
+	bneid	r11, _copy_page_loop
+	addik	r11, r11, -1
+	rtsd	r15, 8
+	nop
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index 07d4fa3..00b12c6 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -126,9 +126,54 @@
 	else
 		childregs->r1 = ((unsigned long) ti) + THREAD_SIZE;
 
+#ifndef CONFIG_MMU
 	memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
 	ti->cpu_context.r1 = (unsigned long)childregs;
 	ti->cpu_context.msr = (unsigned long)childregs->msr;
+#else
+
+	/* if creating a kernel thread then update the current reg (we don't
+	 * want to use the parent's value when restoring by POP_STATE) */
+	if (kernel_mode(regs))
+		/* save new current on stack to use POP_STATE */
+		childregs->CURRENT_TASK = (unsigned long)p;
+	/* if returning to user then use the parent's value of this register */
+
+	/* if we're creating a new kernel thread then just zeroing all
+	 * the registers. That's OK for a brand new thread.*/
+	/* Pls. note that some of them will be restored in POP_STATE */
+	if (kernel_mode(regs))
+		memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
+	/* if this thread is created for fork/vfork/clone, then we want to
+	 * restore all the parent's context */
+	/* in addition to the registers which will be restored by POP_STATE */
+	else {
+		ti->cpu_context = *(struct cpu_context *)regs;
+		childregs->msr |= MSR_UMS;
+	}
+
+	/* FIXME STATE_SAVE_PT_OFFSET; */
+	ti->cpu_context.r1  = (unsigned long)childregs - STATE_SAVE_ARG_SPACE;
+	/* we should consider the fact that childregs is a copy of the parent
+	 * regs which were saved immediately after entering the kernel state
+	 * before enabling VM. This MSR will be restored in switch_to and
+	 * RETURN() and we want to have the right machine state there
+	 * specifically this state must have INTs disabled before and enabled
+	 * after performing rtbd
+	 * compose the right MSR for RETURN(). It will work for switch_to also
+	 * excepting for VM and UMS
+	 * don't touch UMS , CARRY and cache bits
+	 * right now MSR is a copy of parent one */
+	childregs->msr |= MSR_BIP;
+	childregs->msr &= ~MSR_EIP;
+	childregs->msr |= MSR_IE;
+	childregs->msr &= ~MSR_VM;
+	childregs->msr |= MSR_VMS;
+	childregs->msr |= MSR_EE; /* exceptions will be enabled*/
+
+	ti->cpu_context.msr = (childregs->msr|MSR_VM);
+	ti->cpu_context.msr &= ~MSR_UMS; /* switch_to to kernel mode */
+#endif
 	ti->cpu_context.r15 = (unsigned long)ret_from_fork - 8;
 
 	if (clone_flags & CLONE_SETTLS)
@@ -137,6 +182,7 @@
 	return 0;
 }
 
+#ifndef CONFIG_MMU
 /*
  * Return saved PC of a blocked thread.
  */
@@ -151,6 +197,7 @@
 	else
 		return ctx->r14;
 }
+#endif
 
 static void kernel_thread_helper(int (*fn)(void *), void *arg)
 {
@@ -173,6 +220,7 @@
 	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
 			&regs, 0, NULL, NULL);
 }
+EXPORT_SYMBOL_GPL(kernel_thread);
 
 unsigned long get_wchan(struct task_struct *p)
 {
@@ -188,3 +236,14 @@
 	regs->r1 = usp;
 	regs->pt_mode = 0;
 }
+
+#ifdef CONFIG_MMU
+#include <linux/elfcore.h>
+/*
+ * Set up a thread for executing a new program
+ */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
+{
+	return 0; /* MicroBlaze has no separate FPU registers */
+}
+#endif /* CONFIG_MMU */
diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c
index 34c4871..c005cc6 100644
--- a/arch/microblaze/kernel/prom.c
+++ b/arch/microblaze/kernel/prom.c
@@ -509,12 +509,13 @@
 
 	prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
 	if (prop) {
-		initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
+		initrd_start = (unsigned long)
+					__va((u32)of_read_ulong(prop, l/4));
 
 		prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
 		if (prop) {
 			initrd_end = (unsigned long)
-					__va(of_read_ulong(prop, l/4));
+					__va((u32)of_read_ulong(prop, 1/4));
 			initrd_below_start_ok = 1;
 		} else {
 			initrd_start = 0;
@@ -563,7 +564,9 @@
 		strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE));
 
 #ifdef CONFIG_CMDLINE
+#ifndef CONFIG_CMDLINE_FORCE
 	if (p == NULL || l == 0 || (l == 1 && (*p) == 0))
+#endif
 		strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
 #endif /* CONFIG_CMDLINE */
 
diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c
index eb6b417..8709bea 100644
--- a/arch/microblaze/kernel/setup.c
+++ b/arch/microblaze/kernel/setup.c
@@ -42,10 +42,6 @@
 
 void __init setup_arch(char **cmdline_p)
 {
-#ifdef CONFIG_CMDLINE_FORCE
-	strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-	strlcpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-#endif
 	*cmdline_p = cmd_line;
 
 	console_verbose();
@@ -102,14 +98,34 @@
 {
 	unsigned long *src, *dst = (unsigned long *)0x0;
 
+	/* If CONFIG_MTD_UCLINUX is defined, assume ROMFS is at the
+	 * end of kernel. There are two position which we want to check.
+	 * The first is __init_end and the second __bss_start.
+	 */
+#ifdef CONFIG_MTD_UCLINUX
+	int romfs_size;
+	unsigned int romfs_base;
+	char *old_klimit = klimit;
+
+	romfs_base = (ram ? ram : (unsigned int)&__init_end);
+	romfs_size = PAGE_ALIGN(get_romfs_len((unsigned *)romfs_base));
+	if (!romfs_size) {
+		romfs_base = (unsigned int)&__bss_start;
+		romfs_size = PAGE_ALIGN(get_romfs_len((unsigned *)romfs_base));
+	}
+
+	/* Move ROMFS out of BSS before clearing it */
+	if (romfs_size > 0) {
+		memmove(&_ebss, (int *)romfs_base, romfs_size);
+		klimit += romfs_size;
+	}
+#endif
+
 /* clearing bss section */
 	memset(__bss_start, 0, __bss_stop-__bss_start);
 	memset(_ssbss, 0, _esbss-_ssbss);
 
-	/*
-	 * Copy command line passed from bootloader, or use default
-	 * if none provided, or forced
-	 */
+	/* Copy command line passed from bootloader */
 #ifndef CONFIG_CMDLINE_BOOL
 	if (cmdline && cmdline[0] != '\0')
 		strlcpy(cmd_line, cmdline, COMMAND_LINE_SIZE);
@@ -126,27 +142,15 @@
 	printk(KERN_NOTICE "Found FDT at 0x%08x\n", fdt);
 
 #ifdef CONFIG_MTD_UCLINUX
-	{
-		int size;
-		unsigned int romfs_base;
-		romfs_base = (ram ? ram : (unsigned int)&__init_end);
-		/* if CONFIG_MTD_UCLINUX_EBSS is defined, assume ROMFS is at the
-		 * end of kernel, which is ROMFS_LOCATION defined above. */
-		size = PAGE_ALIGN(get_romfs_len((unsigned *)romfs_base));
-		early_printk("Found romfs @ 0x%08x (0x%08x)\n",
-				romfs_base, size);
-		early_printk("#### klimit %p ####\n", klimit);
-		BUG_ON(size < 0); /* What else can we do? */
+	early_printk("Found romfs @ 0x%08x (0x%08x)\n",
+			romfs_base, romfs_size);
+	early_printk("#### klimit %p ####\n", old_klimit);
+	BUG_ON(romfs_size < 0); /* What else can we do? */
 
-		/* Use memmove to handle likely case of memory overlap */
-		early_printk("Moving 0x%08x bytes from 0x%08x to 0x%08x\n",
-			size, romfs_base, (unsigned)&_ebss);
-		memmove(&_ebss, (int *)romfs_base, size);
+	early_printk("Moved 0x%08x bytes from 0x%08x to 0x%08x\n",
+			romfs_size, romfs_base, (unsigned)&_ebss);
 
-		/* update klimit */
-		klimit += PAGE_ALIGN(size);
-		early_printk("New klimit: 0x%08x\n", (unsigned)klimit);
-	}
+	early_printk("New klimit: 0x%08x\n", (unsigned)klimit);
 #endif
 
 	for (src = __ivt_start; src < __ivt_end; src++, dst++)
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c
index 40d3693..4c0e652 100644
--- a/arch/microblaze/kernel/signal.c
+++ b/arch/microblaze/kernel/signal.c
@@ -152,8 +152,8 @@
 	unsigned long tramp[2];	/* signal trampoline */
 };
 
-static int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *rval_p)
+static int restore_sigcontext(struct pt_regs *regs,
+				struct sigcontext __user *sc, int *rval_p)
 {
 	unsigned int err = 0;
 
@@ -211,11 +211,10 @@
 
 asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
 {
-	struct rt_sigframe *frame =
-			(struct rt_sigframe *)(regs->r1 + STATE_SAVE_ARG_SPACE);
+	struct rt_sigframe __user *frame =
+		(struct rt_sigframe __user *)(regs->r1 + STATE_SAVE_ARG_SPACE);
 
 	sigset_t set;
-	stack_t st;
 	int rval;
 
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -233,11 +232,10 @@
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval))
 		goto badframe;
 
-	if (__copy_from_user((void *)&st, &frame->uc.uc_stack, sizeof(st)))
-		goto badframe;
 	/* It is more difficult to avoid calling this function than to
 	 call it and ignore errors. */
-	do_sigaltstack(&st, NULL, regs->r1);
+	if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->r1))
+		goto badframe;
 
 	return rval;
 
@@ -251,7 +249,7 @@
  */
 
 static int
-setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
 		unsigned long mask)
 {
 	int err = 0;
@@ -278,7 +276,7 @@
 /*
  * Determine which stack to use..
  */
-static inline void *
+static inline void __user *
 get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
 {
 	/* Default to using normal stack */
@@ -287,87 +285,13 @@
 	if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
 		sp = current->sas_ss_sp + current->sas_ss_size;
 
-	return (void *)((sp - frame_size) & -8UL);
-}
-
-static void setup_frame(int sig, struct k_sigaction *ka,
-			sigset_t *set, struct pt_regs *regs)
-{
-	struct sigframe *frame;
-	int err = 0;
-	int signal;
-
-	frame = get_sigframe(ka, regs, sizeof(*frame));
-
-	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto give_sigsegv;
-
-	signal = current_thread_info()->exec_domain
-		&& current_thread_info()->exec_domain->signal_invmap
-		&& sig < 32
-		? current_thread_info()->exec_domain->signal_invmap[sig]
-		: sig;
-
-	err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
-
-	if (_NSIG_WORDS > 1) {
-		err |= __copy_to_user(frame->extramask, &set->sig[1],
-					sizeof(frame->extramask));
-	}
-
-	/* Set up to return from userspace. If provided, use a stub
-	 already in userspace. */
-	/* minus 8 is offset to cater for "rtsd r15,8" offset */
-	if (ka->sa.sa_flags & SA_RESTORER) {
-		regs->r15 = ((unsigned long)ka->sa.sa_restorer)-8;
-	} else {
-		/* Note, these encodings are _big endian_! */
-
-		/* addi r12, r0, __NR_sigreturn */
-		err |= __put_user(0x31800000 | __NR_sigreturn ,
-				frame->tramp + 0);
-		/* brki r14, 0x8 */
-		err |= __put_user(0xb9cc0008, frame->tramp + 1);
-
-		/* Return from sighandler will jump to the tramp.
-		 Negative 8 offset because return is rtsd r15, 8 */
-		regs->r15 = ((unsigned long)frame->tramp)-8;
-
-		__invalidate_cache_sigtramp((unsigned long)frame->tramp);
-	}
-
-	if (err)
-		goto give_sigsegv;
-
-	/* Set up registers for signal handler */
-	regs->r1 = (unsigned long) frame - STATE_SAVE_ARG_SPACE;
-
-	/* Signal handler args: */
-	regs->r5 = signal; /* Arg 0: signum */
-	regs->r6 = (unsigned long) &frame->sc; /* arg 1: sigcontext */
-
-	/* Offset of 4 to handle microblaze rtid r14, 0 */
-	regs->pc = (unsigned long)ka->sa.sa_handler;
-
-	set_fs(USER_DS);
-
-#ifdef DEBUG_SIG
-	printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n",
-		current->comm, current->pid, frame, regs->pc);
-#endif
-
-	return;
-
-give_sigsegv:
-	if (sig == SIGSEGV)
-		ka->sa.sa_handler = SIG_DFL;
-	force_sig(SIGSEGV, current);
+	return (void __user *)((sp - frame_size) & -8UL);
 }
 
 static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 			sigset_t *set, struct pt_regs *regs)
 {
-	struct rt_sigframe *frame;
+	struct rt_sigframe __user *frame;
 	int err = 0;
 	int signal;
 
@@ -382,7 +306,8 @@
 		? current_thread_info()->exec_domain->signal_invmap[sig]
 		: sig;
 
-	err |= copy_siginfo_to_user(&frame->info, info);
+	if (info)
+		err |= copy_siginfo_to_user(&frame->info, info);
 
 	/* Create the ucontext. */
 	err |= __put_user(0, &frame->uc.uc_flags);
@@ -463,7 +388,15 @@
 	case -ERESTARTNOINTR:
 do_restart:
 		/* offset of 4 bytes to re-execute trap (brki) instruction */
+#ifndef CONFIG_MMU
 		regs->pc -= 4;
+#else
+		/* offset of 8 bytes required = 4 for rtbd
+		   offset, plus 4 for size of
+			"brki r14,8"
+		   instruction. */
+		regs->pc -= 8;
+#endif
 		break;
 	}
 }
@@ -480,7 +413,7 @@
 	if (ka->sa.sa_flags & SA_SIGINFO)
 		setup_rt_frame(sig, ka, info, oldset, regs);
 	else
-		setup_frame(sig, ka, oldset, regs);
+		setup_rt_frame(sig, ka, NULL, oldset, regs);
 
 	if (ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S
index 3bb42ec..376d178 100644
--- a/arch/microblaze/kernel/syscall_table.S
+++ b/arch/microblaze/kernel/syscall_table.S
@@ -2,7 +2,11 @@
 	.long sys_restart_syscall	/* 0 - old "setup()" system call,
 					 * used for restarting */
 	.long sys_exit
-	.long sys_ni_syscall		/* was fork */
+#ifdef CONFIG_MMU
+	.long sys_fork_wrapper
+#else
+	.long sys_ni_syscall
+#endif
 	.long sys_read
 	.long sys_write
 	.long sys_open			/* 5 */
diff --git a/arch/microblaze/kernel/traps.c b/arch/microblaze/kernel/traps.c
index 293ef48..eaaaf80 100644
--- a/arch/microblaze/kernel/traps.c
+++ b/arch/microblaze/kernel/traps.c
@@ -22,14 +22,6 @@
 	__enable_hw_exceptions();
 }
 
-void __bad_xchg(volatile void *ptr, int size)
-{
-	printk(KERN_INFO "xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
-		__builtin_return_address(0), ptr, size);
-	BUG();
-}
-EXPORT_SYMBOL(__bad_xchg);
-
 static int kstack_depth_to_print = 24;
 
 static int __init kstack_setup(char *s)
@@ -105,3 +97,37 @@
 	show_stack(NULL, NULL);
 }
 EXPORT_SYMBOL(dump_stack);
+
+#ifdef CONFIG_MMU
+void __bug(const char *file, int line, void *data)
+{
+	if (data)
+		printk(KERN_CRIT "kernel BUG at %s:%d (data = %p)!\n",
+			file, line, data);
+	else
+		printk(KERN_CRIT "kernel BUG at %s:%d!\n", file, line);
+
+	machine_halt();
+}
+
+int bad_trap(int trap_num, struct pt_regs *regs)
+{
+	printk(KERN_CRIT
+		"unimplemented trap %d called at 0x%08lx, pid %d!\n",
+		trap_num, regs->pc, current->pid);
+	return -ENOSYS;
+}
+
+int debug_trap(struct pt_regs *regs)
+{
+	int i;
+	printk(KERN_CRIT "debug trap\n");
+	for (i = 0; i < 32; i++) {
+		/* printk("r%i:%08X\t",i,regs->gpr[i]); */
+		if ((i % 4) == 3)
+			printk(KERN_CRIT "\n");
+	}
+	printk(KERN_CRIT "pc:%08lX\tmsr:%08lX\n", regs->pc, regs->msr);
+	return -ENOSYS;
+}
+#endif
diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S
index 840385e..8ae807a 100644
--- a/arch/microblaze/kernel/vmlinux.lds.S
+++ b/arch/microblaze/kernel/vmlinux.lds.S
@@ -17,8 +17,7 @@
 jiffies = jiffies_64 + 4;
 
 SECTIONS {
-	. = CONFIG_KERNEL_BASE_ADDR;
-
+	. = CONFIG_KERNEL_START;
 	.text : {
 		_text = . ;
 		_stext = . ;
@@ -132,6 +131,8 @@
 		__con_initcall_end = .;
 	}
 
+	SECURITY_INIT
+
 	__init_end_before_initramfs = .;
 
 	.init.ramfs ALIGN(4096) : {
diff --git a/arch/microblaze/lib/Makefile b/arch/microblaze/lib/Makefile
index d27126b..71c8cb6 100644
--- a/arch/microblaze/lib/Makefile
+++ b/arch/microblaze/lib/Makefile
@@ -10,4 +10,5 @@
 lib-y += memcpy.o memmove.o
 endif
 
-lib-y +=  uaccess.o
+lib-$(CONFIG_NO_MMU) += uaccess.o
+lib-$(CONFIG_MMU) += uaccess_old.o
diff --git a/arch/microblaze/lib/checksum.c b/arch/microblaze/lib/checksum.c
index 8093400..f08e745 100644
--- a/arch/microblaze/lib/checksum.c
+++ b/arch/microblaze/lib/checksum.c
@@ -32,9 +32,10 @@
 /* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access
  kills, so most of the assembly has to go. */
 
-#include <net/checksum.h>
-#include <asm/checksum.h>
 #include <linux/module.h>
+#include <net/checksum.h>
+
+#include <asm/byteorder.h>
 
 static inline unsigned short from32to16(unsigned long x)
 {
@@ -102,6 +103,7 @@
 {
 	return (__force __sum16)~do_csum(iph, ihl*4);
 }
+EXPORT_SYMBOL(ip_fast_csum);
 
 /*
  * computes the checksum of a memory block at buff, length len,
@@ -115,15 +117,16 @@
  *
  * it's best to have buff aligned on a 32-bit boundary
  */
-__wsum csum_partial(const void *buff, int len, __wsum sum)
+__wsum csum_partial(const void *buff, int len, __wsum wsum)
 {
+	unsigned int sum = (__force unsigned int)wsum;
 	unsigned int result = do_csum(buff, len);
 
 	/* add in old sum, and carry.. */
 	result += sum;
 	if (sum > result)
 		result += 1;
-	return result;
+	return (__force __wsum)result;
 }
 EXPORT_SYMBOL(csum_partial);
 
@@ -131,9 +134,9 @@
  * this routine is used for miscellaneous IP-like checksums, mainly
  * in icmp.c
  */
-__sum16 ip_compute_csum(const unsigned char *buff, int len)
+__sum16 ip_compute_csum(const void *buff, int len)
 {
-	return ~do_csum(buff, len);
+	return (__force __sum16)~do_csum(buff, len);
 }
 EXPORT_SYMBOL(ip_compute_csum);
 
@@ -141,12 +144,18 @@
  * copy from fs while checksumming, otherwise like csum_partial
  */
 __wsum
-csum_partial_copy_from_user(const char __user *src, char *dst, int len,
-						int sum, int *csum_err)
+csum_partial_copy_from_user(const void __user *src, void *dst, int len,
+						__wsum sum, int *csum_err)
 {
-	if (csum_err)
+	int missing;
+
+	missing = __copy_from_user(dst, src, len);
+	if (missing) {
+		memset(dst + len - missing, 0, missing);
+		*csum_err = -EFAULT;
+	} else
 		*csum_err = 0;
-	memcpy(dst, src, len);
+
 	return csum_partial(dst, len, sum);
 }
 EXPORT_SYMBOL(csum_partial_copy_from_user);
@@ -155,7 +164,7 @@
  * copy from ds while checksumming, otherwise like csum_partial
  */
 __wsum
-csum_partial_copy(const char *src, char *dst, int len, int sum)
+csum_partial_copy(const void *src, void *dst, int len, __wsum sum)
 {
 	memcpy(dst, src, len);
 	return csum_partial(dst, len, sum);
diff --git a/arch/microblaze/lib/memcpy.c b/arch/microblaze/lib/memcpy.c
index 5880119..6a907c5 100644
--- a/arch/microblaze/lib/memcpy.c
+++ b/arch/microblaze/lib/memcpy.c
@@ -154,8 +154,3 @@
 }
 EXPORT_SYMBOL(memcpy);
 #endif /* __HAVE_ARCH_MEMCPY */
-
-void *cacheable_memcpy(void *d, const void *s, __kernel_size_t c)
-{
-	return memcpy(d, s, c);
-}
diff --git a/arch/microblaze/lib/uaccess_old.S b/arch/microblaze/lib/uaccess_old.S
new file mode 100644
index 0000000..67f991c
--- /dev/null
+++ b/arch/microblaze/lib/uaccess_old.S
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2009 PetaLogix
+ * Copyright (C) 2007 LynuxWorks, 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.
+ */
+
+#include <linux/errno.h>
+#include <linux/linkage.h>
+
+/*
+ * int __strncpy_user(char *to, char *from, int len);
+ *
+ * Returns:
+ *  -EFAULT  for an exception
+ *  len      if we hit the buffer limit
+ *  bytes copied
+ */
+
+	.text
+.globl __strncpy_user;
+.align 4;
+__strncpy_user:
+
+	/*
+	 * r5 - to
+	 * r6 - from
+	 * r7 - len
+	 * r3 - temp count
+	 * r4 - temp val
+	 */
+	addik	r3,r7,0		/* temp_count = len */
+	beqi	r3,3f
+1:
+	lbu	r4,r6,r0
+	sb	r4,r5,r0
+
+	addik	r3,r3,-1
+	beqi	r3,2f		/* break on len */
+
+	addik	r5,r5,1
+	bneid	r4,1b
+	addik	r6,r6,1		/* delay slot */
+	addik	r3,r3,1		/* undo "temp_count--" */
+2:
+	rsubk	r3,r3,r7	/* temp_count = len - temp_count */
+3:
+	rtsd	r15,8
+	nop
+
+
+	.section	.fixup, "ax"
+	.align	2
+4:
+	brid	3b
+	addik	r3,r0, -EFAULT
+
+	.section	__ex_table, "a"
+	.word	1b,4b
+
+/*
+ * int __strnlen_user(char __user *str, int maxlen);
+ *
+ * Returns:
+ *  0 on error
+ *  maxlen + 1  if no NUL byte found within maxlen bytes
+ *  size of the string (including NUL byte)
+ */
+
+	.text
+.globl __strnlen_user;
+.align 4;
+__strnlen_user:
+	addik	r3,r6,0
+	beqi	r3,3f
+1:
+	lbu	r4,r5,r0
+	beqid	r4,2f		/* break on NUL */
+	addik	r3,r3,-1	/* delay slot */
+
+	bneid	r3,1b
+	addik	r5,r5,1		/* delay slot */
+
+	addik	r3,r3,-1	/* for break on len */
+2:
+	rsubk	r3,r3,r6
+3:
+	rtsd	r15,8
+	nop
+
+
+	.section	.fixup,"ax"
+4:
+	brid	3b
+	addk	r3,r0,r0
+
+	.section	__ex_table,"a"
+	.word	1b,4b
+
+/*
+ * int __copy_tofrom_user(char *to, char *from, int len)
+ * Return:
+ *   0 on success
+ *   number of not copied bytes on error
+ */
+	.text
+.globl __copy_tofrom_user;
+.align 4;
+__copy_tofrom_user:
+	/*
+	 * r5 - to
+	 * r6 - from
+	 * r7, r3 - count
+	 * r4 - tempval
+	 */
+	addik	r3,r7,0
+	beqi	r3,3f
+1:
+	lbu	r4,r6,r0
+	addik	r6,r6,1
+2:
+	sb	r4,r5,r0
+	addik	r3,r3,-1
+	bneid	r3,1b
+	addik	r5,r5,1		/* delay slot */
+3:
+	rtsd	r15,8
+	nop
+
+
+	.section	__ex_table,"a"
+	.word	1b,3b,2b,3b
diff --git a/arch/microblaze/mm/Makefile b/arch/microblaze/mm/Makefile
index bf9e447..6c8a924 100644
--- a/arch/microblaze/mm/Makefile
+++ b/arch/microblaze/mm/Makefile
@@ -3,3 +3,5 @@
 #
 
 obj-y := init.o
+
+obj-$(CONFIG_MMU) += pgtable.o mmu_context.o fault.o
diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c
new file mode 100644
index 0000000..5e67cd1
--- /dev/null
+++ b/arch/microblaze/mm/fault.c
@@ -0,0 +1,304 @@
+/*
+ *  arch/microblaze/mm/fault.c
+ *
+ *    Copyright (C) 2007 Xilinx, Inc.  All rights reserved.
+ *
+ *  Derived from "arch/ppc/mm/fault.c"
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/i386/mm/fault.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  Modified by Cort Dougan and Paul Mackerras.
+ *
+ * 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/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+
+#include <asm/page.h>
+#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>
+
+#if defined(CONFIG_KGDB)
+int debugger_kernel_faults = 1;
+#endif
+
+static unsigned long pte_misses;	/* updated by do_page_fault() */
+static unsigned long pte_errors;	/* updated by do_page_fault() */
+
+/*
+ * Check whether the instruction at regs->pc is a store using
+ * an update addressing form which will update r1.
+ */
+static int store_updates_sp(struct pt_regs *regs)
+{
+	unsigned int inst;
+
+	if (get_user(inst, (unsigned int *)regs->pc))
+		return 0;
+	/* check for 1 in the rD field */
+	if (((inst >> 21) & 0x1f) != 1)
+		return 0;
+	/* check for store opcodes */
+	if ((inst & 0xd0000000) == 0xd0000000)
+		return 1;
+	return 0;
+}
+
+
+/*
+ * bad_page_fault is called when we have a bad access from the kernel.
+ * It is called from do_page_fault above and from some of the procedures
+ * in traps.c.
+ */
+static void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
+{
+	const struct exception_table_entry *fixup;
+/* MS: no context */
+	/* Are we prepared to handle this fault?  */
+	fixup = search_exception_tables(regs->pc);
+	if (fixup) {
+		regs->pc = fixup->fixup;
+		return;
+	}
+
+	/* kernel has accessed a bad area */
+#if defined(CONFIG_KGDB)
+	if (debugger_kernel_faults)
+		debugger(regs);
+#endif
+	die("kernel access of bad area", regs, sig);
+}
+
+/*
+ * The error_code parameter is ESR for a data fault,
+ * 0 for an instruction fault.
+ */
+void do_page_fault(struct pt_regs *regs, unsigned long address,
+		   unsigned long error_code)
+{
+	struct vm_area_struct *vma;
+	struct mm_struct *mm = current->mm;
+	siginfo_t info;
+	int code = SEGV_MAPERR;
+	int is_write = error_code & ESR_S;
+	int fault;
+
+	regs->ear = address;
+	regs->esr = error_code;
+
+	/* On a kernel SLB miss we can only check for a valid exception entry */
+	if (kernel_mode(regs) && (address >= TASK_SIZE)) {
+		printk(KERN_WARNING "kernel task_size exceed");
+		_exception(SIGSEGV, regs, code, address);
+	}
+
+	/* for instr TLB miss and instr storage exception ESR_S is undefined */
+	if ((error_code & 0x13) == 0x13 || (error_code & 0x11) == 0x11)
+		is_write = 0;
+
+#if defined(CONFIG_KGDB)
+	if (debugger_fault_handler && regs->trap == 0x300) {
+		debugger_fault_handler(regs);
+		return;
+	}
+#endif /* CONFIG_KGDB */
+
+	if (in_atomic() || mm == NULL) {
+		/* FIXME */
+		if (kernel_mode(regs)) {
+			printk(KERN_EMERG
+				"Page fault in kernel mode - Oooou!!! pid %d\n",
+				current->pid);
+			_exception(SIGSEGV, regs, code, address);
+			return;
+		}
+		/* in_atomic() in user mode is really bad,
+		   as is current->mm == NULL. */
+		printk(KERN_EMERG "Page fault in user mode with "
+		       "in_atomic(), mm = %p\n", mm);
+		printk(KERN_EMERG "r15 = %lx  MSR = %lx\n",
+		       regs->r15, regs->msr);
+		die("Weird page fault", regs, SIGSEGV);
+	}
+
+	/* When running in the kernel we expect faults to occur only to
+	 * addresses in user space.  All other faults represent errors in the
+	 * kernel and should generate an OOPS.  Unfortunately, in the case of an
+	 * erroneous fault occurring in a code path which already holds mmap_sem
+	 * we will deadlock attempting to validate the fault against the
+	 * address space.  Luckily the kernel only validly references user
+	 * space from well defined areas of code, which are listed in the
+	 * exceptions table.
+	 *
+	 * As the vast majority of faults will be valid we will only perform
+	 * the source reference check when there is a possibility of a deadlock.
+	 * Attempt to lock the address space, if we cannot we then validate the
+	 * source.  If this is invalid we can skip the address space check,
+	 * thus avoiding the deadlock.
+	 */
+	if (!down_read_trylock(&mm->mmap_sem)) {
+		if (kernel_mode(regs) && !search_exception_tables(regs->pc))
+			goto bad_area_nosemaphore;
+
+		down_read(&mm->mmap_sem);
+	}
+
+	vma = find_vma(mm, address);
+	if (!vma)
+		goto bad_area;
+
+	if (vma->vm_start <= address)
+		goto good_area;
+
+	if (!(vma->vm_flags & VM_GROWSDOWN))
+		goto bad_area;
+
+	if (!is_write)
+		goto bad_area;
+
+	/*
+	 * N.B. The ABI allows programs to access up to
+	 * a few hundred bytes below the stack pointer (TBD).
+	 * The kernel signal delivery code writes up to about 1.5kB
+	 * below the stack pointer (r1) before decrementing it.
+	 * The exec code can write slightly over 640kB to the stack
+	 * before setting the user r1.  Thus we allow the stack to
+	 * expand to 1MB without further checks.
+	 */
+	if (address + 0x100000 < vma->vm_end) {
+
+		/* get user regs even if this fault is in kernel mode */
+		struct pt_regs *uregs = current->thread.regs;
+		if (uregs == NULL)
+			goto bad_area;
+
+		/*
+		 * A user-mode access to an address a long way below
+		 * the stack pointer is only valid if the instruction
+		 * is one which would update the stack pointer to the
+		 * address accessed if the instruction completed,
+		 * i.e. either stwu rs,n(r1) or stwux rs,r1,rb
+		 * (or the byte, halfword, float or double forms).
+		 *
+		 * If we don't check this then any write to the area
+		 * between the last mapped region and the stack will
+		 * expand the stack rather than segfaulting.
+		 */
+		if (address + 2048 < uregs->r1
+			&& (kernel_mode(regs) || !store_updates_sp(regs)))
+				goto bad_area;
+	}
+	if (expand_stack(vma, address))
+		goto bad_area;
+
+good_area:
+	code = SEGV_ACCERR;
+
+	/* a write */
+	if (is_write) {
+		if (!(vma->vm_flags & VM_WRITE))
+			goto bad_area;
+	/* a read */
+	} else {
+		/* protection fault */
+		if (error_code & 0x08000000)
+			goto bad_area;
+		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+			goto bad_area;
+	}
+
+	/*
+	 * If for any reason at all we couldn't handle the fault,
+	 * make sure we exit gracefully rather than endlessly redo
+	 * the fault.
+	 */
+survive:
+	fault = handle_mm_fault(mm, vma, address, is_write);
+	if (unlikely(fault & VM_FAULT_ERROR)) {
+		if (fault & VM_FAULT_OOM)
+			goto out_of_memory;
+		else if (fault & VM_FAULT_SIGBUS)
+			goto do_sigbus;
+		BUG();
+	}
+	if (fault & VM_FAULT_MAJOR)
+		current->maj_flt++;
+	else
+		current->min_flt++;
+	up_read(&mm->mmap_sem);
+	/*
+	 * keep track of tlb+htab misses that are good addrs but
+	 * just need pte's created via handle_mm_fault()
+	 * -- Cort
+	 */
+	pte_misses++;
+	return;
+
+bad_area:
+	up_read(&mm->mmap_sem);
+
+bad_area_nosemaphore:
+	pte_errors++;
+
+	/* User mode accesses cause a SIGSEGV */
+	if (user_mode(regs)) {
+		_exception(SIGSEGV, regs, code, address);
+/*		info.si_signo = SIGSEGV;
+		info.si_errno = 0;
+		info.si_code = code;
+		info.si_addr = (void *) address;
+		force_sig_info(SIGSEGV, &info, current);*/
+		return;
+	}
+
+	bad_page_fault(regs, address, SIGSEGV);
+	return;
+
+/*
+ * 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:
+	if (current->pid == 1) {
+		yield();
+		down_read(&mm->mmap_sem);
+		goto survive;
+	}
+	up_read(&mm->mmap_sem);
+	printk(KERN_WARNING "VM: killing process %s\n", current->comm);
+	if (user_mode(regs))
+		do_exit(SIGKILL);
+	bad_page_fault(regs, address, SIGKILL);
+	return;
+
+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;
+	}
+	bad_page_fault(regs, address, SIGBUS);
+}
diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c
index b0c8213..b5a701c 100644
--- a/arch/microblaze/mm/init.c
+++ b/arch/microblaze/mm/init.c
@@ -23,8 +23,16 @@
 #include <asm/sections.h>
 #include <asm/tlb.h>
 
+#ifndef CONFIG_MMU
 unsigned int __page_offset;
-/* EXPORT_SYMBOL(__page_offset); */
+EXPORT_SYMBOL(__page_offset);
+
+#else
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+int mem_init_done;
+static int init_bootmem_done;
+#endif /* CONFIG_MMU */
 
 char *klimit = _end;
 
@@ -32,28 +40,26 @@
  * Initialize the bootmem system and give it all the memory we
  * have available.
  */
-unsigned int memory_start;
-unsigned int memory_end; /* due to mm/nommu.c */
-unsigned int memory_size;
+unsigned long memory_start;
+unsigned long memory_end; /* due to mm/nommu.c */
+unsigned long memory_size;
 
 /*
  * paging_init() sets up the page tables - in fact we've already done this.
  */
 static void __init paging_init(void)
 {
-	int i;
 	unsigned long zones_size[MAX_NR_ZONES];
 
+	/* 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;
 
-	/* every other zones are empty */
-	for (i = 1; i < MAX_NR_ZONES; i++)
-		zones_size[i] = 0;
-
 	free_area_init(zones_size);
 }
 
@@ -61,6 +67,7 @@
 {
 	int i;
 	unsigned long map_size;
+#ifndef CONFIG_MMU
 	u32 kernel_align_start, kernel_align_size;
 
 	/* Find main memory where is the kernel */
@@ -93,6 +100,7 @@
 		__func__, kernel_align_start, kernel_align_start
 			+ kernel_align_size, kernel_align_size);
 
+#endif
 	/*
 	 * Kernel:
 	 * start: base phys address of kernel - page align
@@ -121,9 +129,13 @@
 	 * for 4GB of memory, using 4kB pages), plus 1 page
 	 * (in case the address isn't page-aligned).
 	 */
+#ifndef CONFIG_MMU
 	map_size = init_bootmem_node(NODE_DATA(0), PFN_UP(TOPHYS((u32)_end)),
 					min_low_pfn, max_low_pfn);
-
+#else
+	map_size = init_bootmem_node(&contig_page_data,
+		PFN_UP(TOPHYS((u32)_end)), min_low_pfn, max_low_pfn);
+#endif
 	lmb_reserve(PFN_UP(TOPHYS((u32)_end)) << PAGE_SHIFT, map_size);
 
 	/* free bootmem is whole main memory */
@@ -137,6 +149,9 @@
 		reserve_bootmem(lmb.reserved.region[i].base,
 			lmb_size_bytes(&lmb.reserved, i) - 1, BOOTMEM_DEFAULT);
 	}
+#ifdef CONFIG_MMU
+	init_bootmem_done = 1;
+#endif
 	paging_init();
 }
 
@@ -191,11 +206,145 @@
 	printk(KERN_INFO "Memory: %luk/%luk available\n",
 	       (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
 	       num_physpages << (PAGE_SHIFT-10));
+#ifdef CONFIG_MMU
+	mem_init_done = 1;
+#endif
 }
 
+#ifndef CONFIG_MMU
 /* Check against bounds of physical memory */
 int ___range_ok(unsigned long addr, unsigned long size)
 {
 	return ((addr < memory_start) ||
 		((addr + size) > memory_end));
 }
+EXPORT_SYMBOL(___range_ok);
+
+#else
+int page_is_ram(unsigned long pfn)
+{
+	return pfn < max_low_pfn;
+}
+
+/*
+ * Check for command-line options that affect what MMU_init will do.
+ */
+static void mm_cmdline_setup(void)
+{
+	unsigned long maxmem = 0;
+	char *p = cmd_line;
+
+	/* Look for mem= option on command line */
+	p = strstr(cmd_line, "mem=");
+	if (p) {
+		p += 4;
+		maxmem = memparse(p, &p);
+		if (maxmem && memory_size > maxmem) {
+			memory_size = maxmem;
+			memory_end = memory_start + memory_size;
+			lmb.memory.region[0].size = memory_size;
+		}
+	}
+}
+
+/*
+ * MMU_init_hw does the chip-specific initialization of the MMU hardware.
+ */
+static void __init mmu_init_hw(void)
+{
+	/*
+	 * The Zone Protection Register (ZPR) defines how protection will
+	 * be applied to every page which is a member of a given zone. At
+	 * present, we utilize only two of the zones.
+	 * The zone index bits (of ZSEL) in the PTE are used for software
+	 * indicators, except the LSB.  For user access, zone 1 is used,
+	 * for kernel access, zone 0 is used.  We set all but zone 1
+	 * to zero, allowing only kernel access as indicated in the PTE.
+	 * For zone 1, we set a 01 binary (a value of 10 will not work)
+	 * to allow user access as indicated in the PTE.  This also allows
+	 * kernel access as indicated in the PTE.
+	 */
+	__asm__ __volatile__ ("ori r11, r0, 0x10000000;" \
+			"mts rzpr, r11;"
+			: : : "r11");
+}
+
+/*
+ * MMU_init sets up the basic memory mappings for the kernel,
+ * including both RAM and possibly some I/O regions,
+ * and sets up the page tables and the MMU hardware ready to go.
+ */
+
+/* called from head.S */
+asmlinkage void __init mmu_init(void)
+{
+	unsigned int kstart, ksize;
+
+	if (!lmb.reserved.cnt) {
+		printk(KERN_EMERG "Error memory count\n");
+		machine_restart(NULL);
+	}
+
+	if ((u32) lmb.memory.region[0].size < 0x1000000) {
+		printk(KERN_EMERG "Memory must be greater than 16MB\n");
+		machine_restart(NULL);
+	}
+	/* Find main memory where the kernel is */
+	memory_start = (u32) lmb.memory.region[0].base;
+	memory_end = (u32) lmb.memory.region[0].base +
+				(u32) lmb.memory.region[0].size;
+	memory_size = memory_end - memory_start;
+
+	mm_cmdline_setup(); /* FIXME parse args from command line - not used */
+
+	/*
+	 * Map out the kernel text/data/bss from the available physical
+	 * memory.
+	 */
+	kstart = __pa(CONFIG_KERNEL_START); /* kernel start */
+	/* kernel size */
+	ksize = PAGE_ALIGN(((u32)_end - (u32)CONFIG_KERNEL_START));
+	lmb_reserve(kstart, ksize);
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+	/* Remove the init RAM disk from the available memory. */
+/*	if (initrd_start) {
+		mem_pieces_remove(&phys_avail, __pa(initrd_start),
+				  initrd_end - initrd_start, 1);
+	}*/
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	/* Initialize the MMU hardware */
+	mmu_init_hw();
+
+	/* Map in all of RAM starting at CONFIG_KERNEL_START */
+	mapin_ram();
+
+#ifdef HIGHMEM_START_BOOL
+	ioremap_base = HIGHMEM_START;
+#else
+	ioremap_base = 0xfe000000UL;	/* for now, could be 0xfffff000 */
+#endif /* CONFIG_HIGHMEM */
+	ioremap_bot = ioremap_base;
+
+	/* Initialize the context management stuff */
+	mmu_context_init();
+}
+
+/* This is only called until mem_init is done. */
+void __init *early_get_page(void)
+{
+	void *p;
+	if (init_bootmem_done) {
+		p = alloc_bootmem_pages(PAGE_SIZE);
+	} else {
+		/*
+		 * Mem start + 32MB -> here is limit
+		 * because of mem mapping from head.S
+		 */
+		p = __va(lmb_alloc_base(PAGE_SIZE, PAGE_SIZE,
+					memory_start + 0x2000000));
+	}
+	return p;
+}
+#endif /* CONFIG_MMU */
diff --git a/arch/microblaze/mm/mmu_context.c b/arch/microblaze/mm/mmu_context.c
new file mode 100644
index 0000000..26ff82f
--- /dev/null
+++ b/arch/microblaze/mm/mmu_context.c
@@ -0,0 +1,70 @@
+/*
+ * This file contains the routines for handling the MMU.
+ *
+ *    Copyright (C) 2007 Xilinx, Inc.  All rights reserved.
+ *
+ *  Derived from arch/ppc/mm/4xx_mmu.c:
+ *  -- paulus
+ *
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the 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/mm.h>
+#include <linux/init.h>
+
+#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
+
+mm_context_t next_mmu_context;
+unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
+atomic_t nr_free_contexts;
+struct mm_struct *context_mm[LAST_CONTEXT+1];
+
+/*
+ * Initialize the context management stuff.
+ */
+void __init mmu_context_init(void)
+{
+	/*
+	 * The use of context zero is reserved for the kernel.
+	 * This code assumes FIRST_CONTEXT < 32.
+	 */
+	context_map[0] = (1 << FIRST_CONTEXT) - 1;
+	next_mmu_context = FIRST_CONTEXT;
+	atomic_set(&nr_free_contexts, LAST_CONTEXT - FIRST_CONTEXT + 1);
+}
+
+/*
+ * Steal a context from a task that has one at the moment.
+ *
+ * This isn't an LRU system, it just frees up each context in
+ * turn (sort-of pseudo-random replacement :).  This would be the
+ * place to implement an LRU scheme if anyone were motivated to do it.
+ */
+void steal_context(void)
+{
+	struct mm_struct *mm;
+
+	/* free up context `next_mmu_context' */
+	/* if we shouldn't free context 0, don't... */
+	if (next_mmu_context < FIRST_CONTEXT)
+		next_mmu_context = FIRST_CONTEXT;
+	mm = context_mm[next_mmu_context];
+	flush_tlb_mm(mm);
+	destroy_context(mm);
+}
diff --git a/arch/microblaze/mm/pgtable.c b/arch/microblaze/mm/pgtable.c
new file mode 100644
index 0000000..46c4ca5
--- /dev/null
+++ b/arch/microblaze/mm/pgtable.c
@@ -0,0 +1,286 @@
+/*
+ *  This file contains the routines setting up the linux page tables.
+ *
+ * Copyright (C) 2008 Michal Simek
+ * Copyright (C) 2008 PetaLogix
+ *
+ *    Copyright (C) 2007 Xilinx, Inc.  All rights reserved.
+ *
+ *  Derived from arch/ppc/mm/pgtable.c:
+ *    -- paulus
+ *
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  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/module.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <linux/io.h>
+#include <asm/mmu.h>
+#include <asm/sections.h>
+
+#define flush_HPTE(X, va, pg)	_tlbie(va)
+
+unsigned long ioremap_base;
+unsigned long 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
+
+static void __iomem *__ioremap(phys_addr_t addr, unsigned long size,
+		unsigned long flags)
+{
+	unsigned long v, i;
+	phys_addr_t p;
+	int err;
+
+	/*
+	 * Choose an address to map it to.
+	 * Once the vmalloc system is running, we use it.
+	 * Before then, we use space going down from ioremap_base
+	 * (ioremap_bot records where we're up to).
+	 */
+	p = addr & PAGE_MASK;
+	size = PAGE_ALIGN(addr + size) - p;
+
+	/*
+	 * Don't allow anybody to remap normal RAM that we're using.
+	 * mem_init() sets high_memory so only do the check after that.
+	 *
+	 * However, allow remap of rootfs: TBD
+	 */
+	if (mem_init_done &&
+		p >= memory_start && p < virt_to_phys(high_memory) &&
+		!(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,
+			__builtin_return_address(0));
+		return NULL;
+	}
+
+	if (size == 0)
+		return NULL;
+
+	/*
+	 * Is it already mapped? If the whole area is mapped then we're
+	 * done, otherwise remap it since we want to keep the virt addrs for
+	 * each request contiguous.
+	 *
+	 * We make the assumption here that if the bottom and top
+	 * of the range we want are mapped then it's mapped to the
+	 * same virt address (and this is contiguous).
+	 *  -- Cort
+	 */
+
+	if (mem_init_done) {
+		struct vm_struct *area;
+		area = get_vm_area(size, VM_IOREMAP);
+		if (area == NULL)
+			return NULL;
+		v = VMALLOC_VMADDR(area->addr);
+	} else {
+		v = (ioremap_bot -= size);
+	}
+
+	if ((flags & _PAGE_PRESENT) == 0)
+		flags |= _PAGE_KERNEL;
+	if (flags & _PAGE_NO_CACHE)
+		flags |= _PAGE_GUARDED;
+
+	err = 0;
+	for (i = 0; i < size && err == 0; i += PAGE_SIZE)
+		err = map_page(v + i, p + i, flags);
+	if (err) {
+		if (mem_init_done)
+			vfree((void *)v);
+		return NULL;
+	}
+
+	return (void __iomem *) (v + ((unsigned long)addr & ~PAGE_MASK));
+}
+
+void __iomem *ioremap(phys_addr_t addr, unsigned long size)
+{
+	return __ioremap(addr, size, _PAGE_NO_CACHE);
+}
+EXPORT_SYMBOL(ioremap);
+
+void iounmap(void *addr)
+{
+	if (addr > high_memory && (unsigned long) addr < ioremap_bot)
+		vfree((void *) (PAGE_MASK & (unsigned long) addr));
+}
+EXPORT_SYMBOL(iounmap);
+
+
+int map_page(unsigned long va, phys_addr_t pa, int flags)
+{
+	pmd_t *pd;
+	pte_t *pg;
+	int err = -ENOMEM;
+	/* spin_lock(&init_mm.page_table_lock); */
+	/* Use upper 10 bits of VA to index the first level map */
+	pd = pmd_offset(pgd_offset_k(va), va);
+	/* Use middle 10 bits of VA to index the second-level map */
+	pg = pte_alloc_kernel(pd, va); /* from powerpc - pgtable.c */
+	/* pg = pte_alloc_kernel(&init_mm, pd, va); */
+
+	if (pg != NULL) {
+		err = 0;
+		set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT,
+				__pgprot(flags)));
+		if (mem_init_done)
+			flush_HPTE(0, va, pmd_val(*pd));
+			/* flush_HPTE(0, va, pg); */
+
+	}
+	/* spin_unlock(&init_mm.page_table_lock); */
+	return err;
+}
+
+void __init adjust_total_lowmem(void)
+{
+/* TBD */
+#if 0
+	unsigned long max_low_mem = MAX_LOW_MEM;
+
+	if (total_lowmem > max_low_mem) {
+		total_lowmem = max_low_mem;
+#ifndef CONFIG_HIGHMEM
+		printk(KERN_INFO "Warning, memory limited to %ld Mb, use "
+				"CONFIG_HIGHMEM to reach %ld Mb\n",
+				max_low_mem >> 20, total_memory >> 20);
+		total_memory = total_lowmem;
+#endif /* CONFIG_HIGHMEM */
+	}
+#endif
+}
+
+static void show_tmem(unsigned long tmem)
+{
+	volatile unsigned long a;
+	a = a + tmem;
+}
+
+/*
+ * Map in all of physical memory starting at CONFIG_KERNEL_START.
+ */
+void __init mapin_ram(void)
+{
+	unsigned long v, p, s, f;
+
+	v = CONFIG_KERNEL_START;
+	p = memory_start;
+	show_tmem(memory_size);
+	for (s = 0; s < memory_size; s += PAGE_SIZE) {
+		f = _PAGE_PRESENT | _PAGE_ACCESSED |
+				_PAGE_SHARED | _PAGE_HWEXEC;
+		if ((char *) v < _stext || (char *) v >= _etext)
+			f |= _PAGE_WRENABLE;
+		else
+			/* On the MicroBlaze, no user access
+			   forces R/W kernel access */
+			f |= _PAGE_USER;
+		map_page(v, p, f);
+		v += PAGE_SIZE;
+		p += PAGE_SIZE;
+	}
+}
+
+/* is x a power of 2? */
+#define is_power_of_2(x)	((x) != 0 && (((x) & ((x) - 1)) == 0))
+
+/*
+ * Set up a mapping for a block of I/O.
+ * virt, phys, size must all be page-aligned.
+ * This should only be called before ioremap is called.
+ */
+void __init io_block_mapping(unsigned long virt, phys_addr_t phys,
+			     unsigned int size, int flags)
+{
+	int i;
+
+	if (virt > CONFIG_KERNEL_START && virt < ioremap_bot)
+		ioremap_bot = ioremap_base = virt;
+
+	/* Put it in the page tables. */
+	for (i = 0; i < size; i += PAGE_SIZE)
+		map_page(virt + i, phys + i, flags);
+}
+
+/* Scan the real Linux page tables and return a PTE pointer for
+ * a virtual address in a context.
+ * Returns true (1) if PTE was found, zero otherwise.  The pointer to
+ * the PTE pointer is unmodified if PTE is not found.
+ */
+static int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep)
+{
+	pgd_t	*pgd;
+	pmd_t	*pmd;
+	pte_t	*pte;
+	int     retval = 0;
+
+	pgd = pgd_offset(mm, addr & PAGE_MASK);
+	if (pgd) {
+		pmd = pmd_offset(pgd, addr & PAGE_MASK);
+		if (pmd_present(*pmd)) {
+			pte = pte_offset_kernel(pmd, addr & PAGE_MASK);
+			if (pte) {
+				retval = 1;
+				*ptep = pte;
+			}
+		}
+	}
+	return retval;
+}
+
+/* Find physical address for this virtual address.  Normally used by
+ * I/O functions, but anyone can call it.
+ */
+unsigned long iopa(unsigned long addr)
+{
+	unsigned long pa;
+
+	pte_t *pte;
+	struct mm_struct *mm;
+
+	/* Allow mapping of user addresses (within the thread)
+	 * for DMA if necessary.
+	 */
+	if (addr < TASK_SIZE)
+		mm = current->mm;
+	else
+		mm = &init_mm;
+
+	pa = 0;
+	if (get_pteptr(mm, addr, &pte))
+		pa = (pte_val(*pte) & PAGE_MASK) | (addr & ~PAGE_MASK);
+
+	return pa;
+}
diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h
index 1b332e1..eb7f01c 100644
--- a/arch/mips/include/asm/atomic.h
+++ b/arch/mips/include/asm/atomic.h
@@ -793,6 +793,6 @@
 #define smp_mb__before_atomic_inc()	smp_llsc_mb()
 #define smp_mb__after_atomic_inc()	smp_llsc_mb()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 
 #endif /* _ASM_ATOMIC_H */
diff --git a/arch/mips/include/asm/bitsperlong.h b/arch/mips/include/asm/bitsperlong.h
new file mode 100644
index 0000000..3e4c10a
--- /dev/null
+++ b/arch/mips/include/asm/bitsperlong.h
@@ -0,0 +1,8 @@
+#ifndef __ASM_MIPS_BITSPERLONG_H
+#define __ASM_MIPS_BITSPERLONG_H
+
+#define __BITS_PER_LONG _MIPS_SZLONG
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_MIPS_BITSPERLONG_H */
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index 9f946e4..72c80d2 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -189,6 +189,6 @@
 #define CAC_ADDR(addr)		((addr) - UNCAC_BASE + PAGE_OFFSET)
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _ASM_PAGE_H */
diff --git a/arch/mips/include/asm/signal.h b/arch/mips/include/asm/signal.h
index bee5153..c783f36 100644
--- a/arch/mips/include/asm/signal.h
+++ b/arch/mips/include/asm/signal.h
@@ -109,7 +109,7 @@
 #define SIG_UNBLOCK	2	/* for unblocking signals */
 #define SIG_SETMASK	3	/* for setting the signal mask */
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 struct sigaction {
 	unsigned int	sa_flags;
diff --git a/arch/mips/include/asm/suspend.h b/arch/mips/include/asm/suspend.h
deleted file mode 100644
index 2562f8f..0000000
--- a/arch/mips/include/asm/suspend.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_SUSPEND_H
-#define __ASM_SUSPEND_H
-
-/* Somewhen...  Maybe :-)  */
-
-#endif /* __ASM_SUSPEND_H */
diff --git a/arch/mips/include/asm/types.h b/arch/mips/include/asm/types.h
index 7956e69..544a285 100644
--- a/arch/mips/include/asm/types.h
+++ b/arch/mips/include/asm/types.h
@@ -31,9 +31,6 @@
  * These aren't exported outside the kernel to avoid name space clashes
  */
 #ifdef __KERNEL__
-
-#define BITS_PER_LONG _MIPS_SZLONG
-
 #ifndef __ASSEMBLY__
 
 #if (defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) \
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c
index 1f60e27..3e9100d 100644
--- a/arch/mips/kernel/module.c
+++ b/arch/mips/kernel/module.c
@@ -68,8 +68,6 @@
 void module_free(struct module *mod, void *module_region)
 {
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h
index bc06482..5bf5be9 100644
--- a/arch/mn10300/include/asm/atomic.h
+++ b/arch/mn10300/include/asm/atomic.h
@@ -151,7 +151,7 @@
 #define smp_mb__before_atomic_inc()	barrier()
 #define smp_mb__after_atomic_inc()	barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_ATOMIC_H */
diff --git a/arch/mn10300/include/asm/bitsperlong.h b/arch/mn10300/include/asm/bitsperlong.h
new file mode 100644
index 0000000..6dc0bb0
--- /dev/null
+++ b/arch/mn10300/include/asm/bitsperlong.h
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
diff --git a/arch/mn10300/include/asm/mman.h b/arch/mn10300/include/asm/mman.h
index b7986b6..d04fac1 100644
--- a/arch/mn10300/include/asm/mman.h
+++ b/arch/mn10300/include/asm/mman.h
@@ -12,7 +12,7 @@
 #ifndef _ASM_MMAN_H
 #define _ASM_MMAN_H
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
diff --git a/arch/mn10300/include/asm/signal.h b/arch/mn10300/include/asm/signal.h
index e98817c..7e891fc 100644
--- a/arch/mn10300/include/asm/signal.h
+++ b/arch/mn10300/include/asm/signal.h
@@ -115,7 +115,7 @@
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/arch/mn10300/kernel/module.c b/arch/mn10300/kernel/module.c
index 6b287f2..4fa0e36 100644
--- a/arch/mn10300/kernel/module.c
+++ b/arch/mn10300/kernel/module.c
@@ -48,8 +48,6 @@
 void module_free(struct module *mod, void *module_region)
 {
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-	 * table entries. */
 }
 
 /*
diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h
index ada3e53..7eeaff9 100644
--- a/arch/parisc/include/asm/atomic.h
+++ b/arch/parisc/include/asm/atomic.h
@@ -338,6 +338,6 @@
 
 #endif /* CONFIG_64BIT */
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 
 #endif /* _ASM_PARISC_ATOMIC_H_ */
diff --git a/arch/parisc/include/asm/bitsperlong.h b/arch/parisc/include/asm/bitsperlong.h
new file mode 100644
index 0000000..75196b4
--- /dev/null
+++ b/arch/parisc/include/asm/bitsperlong.h
@@ -0,0 +1,20 @@
+#ifndef __ASM_PARISC_BITSPERLONG_H
+#define __ASM_PARISC_BITSPERLONG_H
+
+/*
+ * using CONFIG_* outside of __KERNEL__ is wrong,
+ * __LP64__ was also removed from headers, so what
+ * is the right approach on parisc?
+ *	-arnd
+ */
+#if (defined(__KERNEL__) && defined(CONFIG_64BIT)) || defined (__LP64__)
+#define __BITS_PER_LONG 64
+#define SHIFT_PER_LONG 6
+#else
+#define __BITS_PER_LONG 32
+#define SHIFT_PER_LONG 5
+#endif
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_PARISC_BITSPERLONG_H */
diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
index 7bc5125..a84cc1f 100644
--- a/arch/parisc/include/asm/page.h
+++ b/arch/parisc/include/asm/page.h
@@ -159,6 +159,6 @@
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _PARISC_PAGE_H */
diff --git a/arch/parisc/include/asm/types.h b/arch/parisc/include/asm/types.h
index 7f5a39b..20135cc 100644
--- a/arch/parisc/include/asm/types.h
+++ b/arch/parisc/include/asm/types.h
@@ -14,14 +14,6 @@
  */
 #ifdef __KERNEL__
 
-#ifdef CONFIG_64BIT
-#define BITS_PER_LONG 64
-#define SHIFT_PER_LONG 6
-#else
-#define BITS_PER_LONG 32
-#define SHIFT_PER_LONG 5
-#endif
-
 #ifndef __ASSEMBLY__
 
 /* Dma addresses are 32-bits wide.  */
diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h
index cd4c0b2..7cf799d 100644
--- a/arch/parisc/include/asm/uaccess.h
+++ b/arch/parisc/include/asm/uaccess.h
@@ -7,7 +7,7 @@
 #include <asm/page.h>
 #include <asm/system.h>
 #include <asm/cache.h>
-#include <asm-generic/uaccess.h>
+#include <asm-generic/uaccess-unaligned.h>
 
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
index ecd1c50..ef5caf2 100644
--- a/arch/parisc/kernel/module.c
+++ b/arch/parisc/kernel/module.c
@@ -267,8 +267,6 @@
 	mod->arch.section = NULL;
 
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* Additional bytes needed in front of individual sections */
diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h
index b401950..b7d2d07 100644
--- a/arch/powerpc/include/asm/atomic.h
+++ b/arch/powerpc/include/asm/atomic.h
@@ -472,6 +472,6 @@
 
 #endif /* __powerpc64__ */
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_ATOMIC_H_ */
diff --git a/arch/powerpc/include/asm/bitsperlong.h b/arch/powerpc/include/asm/bitsperlong.h
new file mode 100644
index 0000000..5f16590
--- /dev/null
+++ b/arch/powerpc/include/asm/bitsperlong.h
@@ -0,0 +1,12 @@
+#ifndef __ASM_POWERPC_BITSPERLONG_H
+#define __ASM_POWERPC_BITSPERLONG_H
+
+#if defined(__powerpc64__)
+# define __BITS_PER_LONG 64
+#else
+# define __BITS_PER_LONG 32
+#endif
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_POWERPC_BITSPERLONG_H */
diff --git a/arch/powerpc/include/asm/mman.h b/arch/powerpc/include/asm/mman.h
index e7b99ba..7b1c498 100644
--- a/arch/powerpc/include/asm/mman.h
+++ b/arch/powerpc/include/asm/mman.h
@@ -1,7 +1,7 @@
 #ifndef _ASM_POWERPC_MMAN_H
 #define _ASM_POWERPC_MMAN_H
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 /*
  * This program is free software; you can redistribute it and/or
diff --git a/arch/powerpc/include/asm/mpc52xx_psc.h b/arch/powerpc/include/asm/mpc52xx_psc.h
index a218da6..fb84120 100644
--- a/arch/powerpc/include/asm/mpc52xx_psc.h
+++ b/arch/powerpc/include/asm/mpc52xx_psc.h
@@ -28,6 +28,10 @@
 #define MPC52xx_PSC_MAXNUM	6
 
 /* Programmable Serial Controller (PSC) status register bits */
+#define MPC52xx_PSC_SR_UNEX_RX	0x0001
+#define MPC52xx_PSC_SR_DATA_VAL	0x0002
+#define MPC52xx_PSC_SR_DATA_OVR	0x0004
+#define MPC52xx_PSC_SR_CMDSEND	0x0008
 #define MPC52xx_PSC_SR_CDE	0x0080
 #define MPC52xx_PSC_SR_RXRDY	0x0100
 #define MPC52xx_PSC_SR_RXFULL	0x0200
@@ -61,6 +65,12 @@
 #define MPC52xx_PSC_RXTX_FIFO_EMPTY	0x0001
 
 /* PSC interrupt status/mask bits */
+#define MPC52xx_PSC_IMR_UNEX_RX_SLOT 0x0001
+#define MPC52xx_PSC_IMR_DATA_VALID	0x0002
+#define MPC52xx_PSC_IMR_DATA_OVR	0x0004
+#define MPC52xx_PSC_IMR_CMD_SEND	0x0008
+#define MPC52xx_PSC_IMR_ERROR		0x0040
+#define MPC52xx_PSC_IMR_DEOF		0x0080
 #define MPC52xx_PSC_IMR_TXRDY		0x0100
 #define MPC52xx_PSC_IMR_RXRDY		0x0200
 #define MPC52xx_PSC_IMR_DB		0x0400
@@ -117,6 +127,7 @@
 #define MPC52xx_PSC_SICR_SIM_FIR		(0x6 << 24)
 #define MPC52xx_PSC_SICR_SIM_CODEC_24		(0x7 << 24)
 #define MPC52xx_PSC_SICR_SIM_CODEC_32		(0xf << 24)
+#define MPC52xx_PSC_SICR_AWR			(1 << 30)
 #define MPC52xx_PSC_SICR_GENCLK			(1 << 23)
 #define MPC52xx_PSC_SICR_I2S			(1 << 22)
 #define MPC52xx_PSC_SICR_CLKPOL			(1 << 21)
diff --git a/arch/powerpc/include/asm/page_32.h b/arch/powerpc/include/asm/page_32.h
index a0e3f6e..bd0849d 100644
--- a/arch/powerpc/include/asm/page_32.h
+++ b/arch/powerpc/include/asm/page_32.h
@@ -41,7 +41,7 @@
 static inline void clear_page(void *page) { clear_pages(page, 0); }
 extern void copy_page(void *to, void *from);
 
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #define PGD_T_LOG2	(__builtin_ffs(sizeof(pgd_t)) - 1)
 #define PTE_T_LOG2	(__builtin_ffs(sizeof(pte_t)) - 1)
diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h
index 043bfdf..5817a3b 100644
--- a/arch/powerpc/include/asm/page_64.h
+++ b/arch/powerpc/include/asm/page_64.h
@@ -180,6 +180,6 @@
 	(test_thread_flag(TIF_32BIT) ? \
 	 VM_STACK_DEFAULT_FLAGS32 : VM_STACK_DEFAULT_FLAGS64)
 
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _ASM_POWERPC_PAGE_64_H */
diff --git a/arch/powerpc/include/asm/signal.h b/arch/powerpc/include/asm/signal.h
index 69f709d..3eb13be 100644
--- a/arch/powerpc/include/asm/signal.h
+++ b/arch/powerpc/include/asm/signal.h
@@ -94,7 +94,7 @@
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 struct old_sigaction {
 	__sighandler_t sa_handler;
diff --git a/arch/powerpc/include/asm/termios.h b/arch/powerpc/include/asm/termios.h
index 2c14fea..a24f487 100644
--- a/arch/powerpc/include/asm/termios.h
+++ b/arch/powerpc/include/asm/termios.h
@@ -78,7 +78,7 @@
 
 #ifdef __KERNEL__
 
-#include <asm-generic/termios.h>
+#include <asm-generic/termios-base.h>
 
 #endif	/* __KERNEL__ */
 
diff --git a/arch/powerpc/include/asm/types.h b/arch/powerpc/include/asm/types.h
index 7ce27a5..a5aea0c 100644
--- a/arch/powerpc/include/asm/types.h
+++ b/arch/powerpc/include/asm/types.h
@@ -40,15 +40,6 @@
 #endif /* __ASSEMBLY__ */
 
 #ifdef __KERNEL__
-/*
- * These aren't exported outside the kernel to avoid name space clashes
- */
-#ifdef __powerpc64__
-#define BITS_PER_LONG 64
-#else
-#define BITS_PER_LONG 32
-#endif
-
 #ifndef __ASSEMBLY__
 
 typedef __vector128 vector128;
diff --git a/arch/powerpc/kernel/module.c b/arch/powerpc/kernel/module.c
index 43e7e3a..477c663 100644
--- a/arch/powerpc/kernel/module.c
+++ b/arch/powerpc/kernel/module.c
@@ -43,8 +43,6 @@
 void module_free(struct module *mod, void *module_region)
 {
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
diff --git a/arch/powerpc/kernel/power7-pmu.c b/arch/powerpc/kernel/power7-pmu.c
index b3f7d12..b72e7a1 100644
--- a/arch/powerpc/kernel/power7-pmu.c
+++ b/arch/powerpc/kernel/power7-pmu.c
@@ -294,12 +294,12 @@
 }
 
 static int power7_generic_events[] = {
-	[PERF_COUNT_CPU_CYCLES] = 0x1e,
-	[PERF_COUNT_INSTRUCTIONS] = 2,
-	[PERF_COUNT_CACHE_REFERENCES] = 0xc880,		/* LD_REF_L1_LSU */
-	[PERF_COUNT_CACHE_MISSES] = 0x400f0,		/* LD_MISS_L1 */
-	[PERF_COUNT_BRANCH_INSTRUCTIONS] = 0x10068,	/* BRU_FIN */
-	[PERF_COUNT_BRANCH_MISSES] = 0x400f6,		/* BR_MPRED */
+	[PERF_COUNT_HW_CPU_CYCLES] = 0x1e,
+	[PERF_COUNT_HW_INSTRUCTIONS] = 2,
+	[PERF_COUNT_HW_CACHE_REFERENCES] = 0xc880,	/* LD_REF_L1_LSU*/
+	[PERF_COUNT_HW_CACHE_MISSES] = 0x400f0,		/* LD_MISS_L1	*/
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x10068,	/* BRU_FIN	*/
+	[PERF_COUNT_HW_BRANCH_MISSES] = 0x400f6,	/* BR_MPRED	*/
 };
 
 #define C(x)	PERF_COUNT_HW_CACHE_##x
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 2eca5fe..99dc3de 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -82,6 +82,11 @@
 	select USE_GENERIC_SMP_HELPERS if SMP
 	select HAVE_SYSCALL_WRAPPERS
 	select HAVE_FUNCTION_TRACER
+	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+	select HAVE_FTRACE_MCOUNT_RECORD
+	select HAVE_FTRACE_SYSCALLS
+	select HAVE_DYNAMIC_FTRACE
+	select HAVE_FUNCTION_GRAPH_TRACER
 	select HAVE_DEFAULT_NO_SPIN_MUTEXES
 	select HAVE_OPROFILE
 	select HAVE_KPROBES
@@ -567,6 +572,24 @@
 	  the KVM hypervisor. This will add detection for KVM as well  as a
 	  virtio transport. If KVM is detected, the virtio console will be
 	  the default console.
+
+config SECCOMP
+	bool "Enable seccomp to safely compute untrusted bytecode"
+	depends on PROC_FS
+	default y
+	help
+	  This kernel feature is useful for number crunching applications
+	  that may need to compute untrusted bytecode during their
+	  execution. By using pipes or other transports made available to
+	  the process as file descriptors supporting the read/write
+	  syscalls, it's possible to isolate those applications in
+	  their own address space using seccomp. Once seccomp is
+	  enabled via /proc/<pid>/seccomp, it cannot be disabled
+	  and the task is only allowed to execute a few safe syscalls
+	  defined by each seccomp mode.
+
+	  If unsure, say Y.
+
 endmenu
 
 source "net/Kconfig"
diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h
index de432f2..fca9dff 100644
--- a/arch/s390/include/asm/atomic.h
+++ b/arch/s390/include/asm/atomic.h
@@ -275,6 +275,6 @@
 #define smp_mb__before_atomic_inc()	smp_mb()
 #define smp_mb__after_atomic_inc()	smp_mb()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* __KERNEL__ */
 #endif /* __ARCH_S390_ATOMIC__  */
diff --git a/arch/s390/include/asm/bitsperlong.h b/arch/s390/include/asm/bitsperlong.h
new file mode 100644
index 0000000..6b235ae
--- /dev/null
+++ b/arch/s390/include/asm/bitsperlong.h
@@ -0,0 +1,13 @@
+#ifndef __ASM_S390_BITSPERLONG_H
+#define __ASM_S390_BITSPERLONG_H
+
+#ifndef __s390x__
+#define __BITS_PER_LONG 32
+#else
+#define __BITS_PER_LONG 64
+#endif
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_S390_BITSPERLONG_H */
+
diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
index de065b3..01a0802 100644
--- a/arch/s390/include/asm/compat.h
+++ b/arch/s390/include/asm/compat.h
@@ -5,6 +5,7 @@
  */
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <linux/thread_info.h>
 
 #define PSW32_MASK_PER		0x40000000UL
 #define PSW32_MASK_DAT		0x04000000UL
@@ -163,12 +164,28 @@
 	return (u32)(unsigned long)uptr;
 }
 
+#ifdef CONFIG_COMPAT
+
+static inline int is_compat_task(void)
+{
+	return test_thread_flag(TIF_31BIT);
+}
+
+#else
+
+static inline int is_compat_task(void)
+{
+	return 0;
+}
+
+#endif
+
 static inline void __user *compat_alloc_user_space(long len)
 {
 	unsigned long stack;
 
 	stack = KSTK_ESP(current);
-	if (test_thread_flag(TIF_31BIT))
+	if (is_compat_task())
 		stack &= 0x7fffffffUL;
 	return (void __user *) (stack - len);
 }
diff --git a/arch/s390/include/asm/cpu.h b/arch/s390/include/asm/cpu.h
deleted file mode 100644
index d60a2ee..0000000
--- a/arch/s390/include/asm/cpu.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *  include/asm-s390/cpu.h
- *
- *    Copyright IBM Corp. 2007
- *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
- */
-
-#ifndef _ASM_S390_CPU_H_
-#define _ASM_S390_CPU_H_
-
-#include <linux/types.h>
-#include <linux/percpu.h>
-#include <linux/spinlock.h>
-
-struct s390_idle_data {
-	spinlock_t lock;
-	unsigned long long idle_count;
-	unsigned long long idle_enter;
-	unsigned long long idle_time;
-};
-
-DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
-
-void vtime_start_cpu(void);
-
-static inline void s390_idle_check(void)
-{
-	if ((&__get_cpu_var(s390_idle))->idle_enter != 0ULL)
-		vtime_start_cpu();
-}
-
-#endif /* _ASM_S390_CPU_H_ */
diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h
index 941384f..ec917d4 100644
--- a/arch/s390/include/asm/cputime.h
+++ b/arch/s390/include/asm/cputime.h
@@ -9,6 +9,9 @@
 #ifndef _S390_CPUTIME_H
 #define _S390_CPUTIME_H
 
+#include <linux/types.h>
+#include <linux/percpu.h>
+#include <linux/spinlock.h>
 #include <asm/div64.h>
 
 /* We want to use full resolution of the CPU timer: 2**-12 micro-seconds. */
@@ -174,8 +177,24 @@
        return __div(cputime, 4096000000ULL / USER_HZ);
 }
 
+struct s390_idle_data {
+	spinlock_t lock;
+	unsigned long long idle_count;
+	unsigned long long idle_enter;
+	unsigned long long idle_time;
+};
+
+DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
+
+void vtime_start_cpu(void);
 cputime64_t s390_get_idle_time(int cpu);
 
 #define arch_idle_time(cpu) s390_get_idle_time(cpu)
 
+static inline void s390_idle_check(void)
+{
+	if ((&__get_cpu_var(s390_idle))->idle_enter != 0ULL)
+		vtime_start_cpu();
+}
+
 #endif /* _S390_CPUTIME_H */
diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h
index 5a5bc75..96c14a9 100644
--- a/arch/s390/include/asm/ftrace.h
+++ b/arch/s390/include/asm/ftrace.h
@@ -2,7 +2,28 @@
 #define _ASM_S390_FTRACE_H
 
 #ifndef __ASSEMBLY__
+
 extern void _mcount(void);
+extern unsigned long ftrace_dyn_func;
+
+struct dyn_arch_ftrace { };
+
+#define MCOUNT_ADDR ((long)_mcount)
+
+#ifdef CONFIG_64BIT
+#define MCOUNT_OFFSET_RET 18
+#define MCOUNT_INSN_SIZE  24
+#define MCOUNT_OFFSET	  14
+#else
+#define MCOUNT_OFFSET_RET 26
+#define MCOUNT_INSN_SIZE  30
+#define MCOUNT_OFFSET	   8
 #endif
 
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+	return addr - MCOUNT_OFFSET;
+}
+
+#endif /* __ASSEMBLY__ */
 #endif /* _ASM_S390_FTRACE_H */
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
index 3aeca49..5046ad6 100644
--- a/arch/s390/include/asm/lowcore.h
+++ b/arch/s390/include/asm/lowcore.h
@@ -30,6 +30,7 @@
 #define __LC_SUBCHANNEL_NR		0x00ba
 #define __LC_IO_INT_PARM		0x00bc
 #define __LC_IO_INT_WORD		0x00c0
+#define __LC_STFL_FAC_LIST		0x00c8
 #define __LC_MCCK_CODE			0x00e8
 
 #define __LC_DUMP_REIPL			0x0e00
@@ -67,6 +68,7 @@
 #define __LC_CPUID			0x02b0
 #define __LC_INT_CLOCK			0x02c8
 #define __LC_MACHINE_FLAGS		0x02d8
+#define __LC_FTRACE_FUNC		0x02dc
 #define __LC_IRB			0x0300
 #define __LC_PFAULT_INTPARM		0x0080
 #define __LC_CPU_TIMER_SAVE_AREA	0x00d8
@@ -112,6 +114,7 @@
 #define __LC_INT_CLOCK			0x0340
 #define __LC_VDSO_PER_CPU		0x0350
 #define __LC_MACHINE_FLAGS		0x0358
+#define __LC_FTRACE_FUNC		0x0360
 #define __LC_IRB			0x0380
 #define __LC_PASTE			0x03c0
 #define __LC_PFAULT_INTPARM		0x11b8
@@ -280,7 +283,8 @@
 	__u64	int_clock;			/* 0x02c8 */
 	__u64	clock_comparator;		/* 0x02d0 */
 	__u32	machine_flags;			/* 0x02d8 */
-	__u8	pad_0x02dc[0x0300-0x02dc];	/* 0x02dc */
+	__u32	ftrace_func;			/* 0x02dc */
+	__u8	pad_0x02f0[0x0300-0x02f0];	/* 0x02f0 */
 
 	/* Interrupt response block */
 	__u8	irb[64];			/* 0x0300 */
@@ -385,7 +389,8 @@
 	__u64	clock_comparator;		/* 0x0348 */
 	__u64	vdso_per_cpu_data;		/* 0x0350 */
 	__u64	machine_flags;			/* 0x0358 */
-	__u8	pad_0x0360[0x0380-0x0360];	/* 0x0360 */
+	__u64	ftrace_func;			/* 0x0360 */
+	__u8	pad_0x0368[0x0380-0x0368];	/* 0x0368 */
 
 	/* Interrupt response block. */
 	__u8	irb[64];			/* 0x0380 */
diff --git a/arch/s390/include/asm/mman.h b/arch/s390/include/asm/mman.h
index da01432..f63fe7b 100644
--- a/arch/s390/include/asm/mman.h
+++ b/arch/s390/include/asm/mman.h
@@ -9,7 +9,7 @@
 #ifndef __S390_MMAN_H__
 #define __S390_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index 32e8f6a..3e3594d 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -150,7 +150,7 @@
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #define __HAVE_ARCH_GATE_AREA 1
 
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 5caddd4..60a7b1a 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -112,12 +112,15 @@
  * effect, this also makes sure that 64 bit module code cannot be used
  * as system call address.
  */
+
+extern unsigned long VMALLOC_START;
+
 #ifndef __s390x__
-#define VMALLOC_START	0x78000000UL
+#define VMALLOC_SIZE	(96UL << 20)
 #define VMALLOC_END	0x7e000000UL
 #define VMEM_MAP_END	0x80000000UL
 #else /* __s390x__ */
-#define VMALLOC_START	0x3e000000000UL
+#define VMALLOC_SIZE	(1UL << 30)
 #define VMALLOC_END	0x3e040000000UL
 #define VMEM_MAP_END	0x40000000000UL
 #endif /* __s390x__ */
diff --git a/arch/s390/include/asm/seccomp.h b/arch/s390/include/asm/seccomp.h
new file mode 100644
index 0000000..781a9cf
--- /dev/null
+++ b/arch/s390/include/asm/seccomp.h
@@ -0,0 +1,16 @@
+#ifndef _ASM_S390_SECCOMP_H
+#define _ASM_S390_SECCOMP_H
+
+#include <linux/unistd.h>
+
+#define __NR_seccomp_read	__NR_read
+#define __NR_seccomp_write	__NR_write
+#define __NR_seccomp_exit	__NR_exit
+#define __NR_seccomp_sigreturn	__NR_sigreturn
+
+#define __NR_seccomp_read_32	__NR_read
+#define __NR_seccomp_write_32	__NR_write
+#define __NR_seccomp_exit_32	__NR_exit
+#define __NR_seccomp_sigreturn_32 __NR_sigreturn
+
+#endif	/* _ASM_S390_SECCOMP_H */
diff --git a/arch/s390/include/asm/signal.h b/arch/s390/include/asm/signal.h
index f6cfddb..cdf5cb2 100644
--- a/arch/s390/include/asm/signal.h
+++ b/arch/s390/include/asm/signal.h
@@ -115,7 +115,7 @@
 #define MINSIGSTKSZ     2048
 #define SIGSTKSZ        8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h
index f3861b0..c9af0d19 100644
--- a/arch/s390/include/asm/spinlock.h
+++ b/arch/s390/include/asm/spinlock.h
@@ -122,8 +122,10 @@
 #define __raw_write_can_lock(x) ((x)->lock == 0)
 
 extern void _raw_read_lock_wait(raw_rwlock_t *lp);
+extern void _raw_read_lock_wait_flags(raw_rwlock_t *lp, unsigned long flags);
 extern int _raw_read_trylock_retry(raw_rwlock_t *lp);
 extern void _raw_write_lock_wait(raw_rwlock_t *lp);
+extern void _raw_write_lock_wait_flags(raw_rwlock_t *lp, unsigned long flags);
 extern int _raw_write_trylock_retry(raw_rwlock_t *lp);
 
 static inline void __raw_read_lock(raw_rwlock_t *rw)
@@ -134,6 +136,14 @@
 		_raw_read_lock_wait(rw);
 }
 
+static inline void __raw_read_lock_flags(raw_rwlock_t *rw, unsigned long flags)
+{
+	unsigned int old;
+	old = rw->lock & 0x7fffffffU;
+	if (_raw_compare_and_swap(&rw->lock, old, old + 1) != old)
+		_raw_read_lock_wait_flags(rw, flags);
+}
+
 static inline void __raw_read_unlock(raw_rwlock_t *rw)
 {
 	unsigned int old, cmp;
@@ -151,6 +161,12 @@
 		_raw_write_lock_wait(rw);
 }
 
+static inline void __raw_write_lock_flags(raw_rwlock_t *rw, unsigned long flags)
+{
+	if (unlikely(_raw_compare_and_swap(&rw->lock, 0, 0x80000000) != 0))
+		_raw_write_lock_wait_flags(rw, flags);
+}
+
 static inline void __raw_write_unlock(raw_rwlock_t *rw)
 {
 	_raw_compare_and_swap(&rw->lock, 0x80000000, 0);
@@ -172,9 +188,6 @@
 	return _raw_write_trylock_retry(rw);
 }
 
-#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
-#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
-
 #define _raw_read_relax(lock)	cpu_relax()
 #define _raw_write_relax(lock)	cpu_relax()
 
diff --git a/arch/s390/include/asm/suspend.h b/arch/s390/include/asm/suspend.h
deleted file mode 100644
index 1f34580..0000000
--- a/arch/s390/include/asm/suspend.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifndef __ASM_S390_SUSPEND_H
-#define __ASM_S390_SUSPEND_H
-
-#endif
-
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
index 2429b87..e0a73d3 100644
--- a/arch/s390/include/asm/syscall.h
+++ b/arch/s390/include/asm/syscall.h
@@ -12,6 +12,7 @@
 #ifndef _ASM_SYSCALL_H
 #define _ASM_SYSCALL_H	1
 
+#include <linux/sched.h>
 #include <asm/ptrace.h>
 
 static inline long syscall_get_nr(struct task_struct *task,
diff --git a/arch/s390/include/asm/termios.h b/arch/s390/include/asm/termios.h
index 67f6627..bc3a35c 100644
--- a/arch/s390/include/asm/termios.h
+++ b/arch/s390/include/asm/termios.h
@@ -60,7 +60,7 @@
 #define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
 #define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
 
-#include <asm-generic/termios.h>
+#include <asm-generic/termios-base.h>
 
 #endif	/* __KERNEL__ */
 
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index 461f2ab..925bcc6 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -83,14 +83,16 @@
 /*
  * thread information flags bit numbers
  */
-#define TIF_SYSCALL_TRACE	0	/* syscall trace active */
 #define TIF_NOTIFY_RESUME	1	/* callback before returning to user */
 #define TIF_SIGPENDING		2	/* signal pending */
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_RESTART_SVC		4	/* restart svc with new svc number */
-#define TIF_SYSCALL_AUDIT	5	/* syscall auditing active */
 #define TIF_SINGLE_STEP		6	/* deliver sigtrap on return to user */
 #define TIF_MCCK_PENDING	7	/* machine check handling is pending */
+#define TIF_SYSCALL_TRACE	8	/* syscall trace active */
+#define TIF_SYSCALL_AUDIT	9	/* syscall auditing active */
+#define TIF_SECCOMP		10	/* secure computing */
+#define TIF_SYSCALL_FTRACE	11	/* ftrace syscall instrumentation */
 #define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling 
 					   TIF_NEED_RESCHED */
@@ -99,15 +101,17 @@
 #define TIF_RESTORE_SIGMASK	20	/* restore signal mask in do_signal() */
 #define TIF_FREEZE		21	/* thread is freezing for suspend */
 
-#define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_RESTART_SVC	(1<<TIF_RESTART_SVC)
-#define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SINGLE_STEP	(1<<TIF_SINGLE_STEP)
 #define _TIF_MCCK_PENDING	(1<<TIF_MCCK_PENDING)
+#define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
+#define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
+#define _TIF_SECCOMP		(1<<TIF_SECCOMP)
+#define _TIF_SYSCALL_FTRACE	(1<<TIF_SYSCALL_FTRACE)
 #define _TIF_USEDFPU		(1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_31BIT		(1<<TIF_31BIT)
diff --git a/arch/s390/include/asm/types.h b/arch/s390/include/asm/types.h
index 3dc3fc2..04d6b95 100644
--- a/arch/s390/include/asm/types.h
+++ b/arch/s390/include/asm/types.h
@@ -28,12 +28,6 @@
  */
 #ifdef __KERNEL__
 
-#ifndef __s390x__
-#define BITS_PER_LONG 32
-#else
-#define BITS_PER_LONG 64
-#endif
-
 #ifndef __ASSEMBLY__
 
 typedef u64 dma64_addr_t;
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index 0235970..8377e91 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -131,7 +131,7 @@
 
 #define put_user(x, ptr)					\
 ({								\
-	might_sleep();						\
+	might_fault();						\
 	__put_user(x, ptr);					\
 })
 
@@ -180,7 +180,7 @@
 
 #define get_user(x, ptr)					\
 ({								\
-	might_sleep();						\
+	might_fault();						\
 	__get_user(x, ptr);					\
 })
 
@@ -231,7 +231,7 @@
 static inline unsigned long __must_check
 copy_to_user(void __user *to, const void *from, unsigned long n)
 {
-	might_sleep();
+	might_fault();
 	if (access_ok(VERIFY_WRITE, to, n))
 		n = __copy_to_user(to, from, n);
 	return n;
@@ -282,7 +282,7 @@
 static inline unsigned long __must_check
 copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-	might_sleep();
+	might_fault();
 	if (access_ok(VERIFY_READ, from, n))
 		n = __copy_from_user(to, from, n);
 	else
@@ -299,7 +299,7 @@
 static inline unsigned long __must_check
 copy_in_user(void __user *to, const void __user *from, unsigned long n)
 {
-	might_sleep();
+	might_fault();
 	if (__access_ok(from,n) && __access_ok(to,n))
 		n = __copy_in_user(to, from, n);
 	return n;
@@ -312,7 +312,7 @@
 strncpy_from_user(char *dst, const char __user *src, long count)
 {
         long res = -EFAULT;
-        might_sleep();
+	might_fault();
         if (access_ok(VERIFY_READ, src, 1))
 		res = uaccess.strncpy_from_user(count, src, dst);
         return res;
@@ -321,7 +321,7 @@
 static inline unsigned long
 strnlen_user(const char __user * src, unsigned long n)
 {
-	might_sleep();
+	might_fault();
 	return uaccess.strnlen_user(n, src);
 }
 
@@ -354,7 +354,7 @@
 static inline unsigned long __must_check
 clear_user(void __user *to, unsigned long n)
 {
-	might_sleep();
+	might_fault();
 	if (access_ok(VERIFY_WRITE, to, n))
 		n = uaccess.clear_user(n, to);
 	return n;
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h
index f0f19e6..c80602d 100644
--- a/arch/s390/include/asm/unistd.h
+++ b/arch/s390/include/asm/unistd.h
@@ -267,7 +267,9 @@
 #define __NR_epoll_create1	327
 #define	__NR_preadv		328
 #define	__NR_pwritev		329
-#define NR_syscalls 330
+#define __NR_rt_tgsigqueueinfo	330
+#define __NR_perf_counter_open	331
+#define NR_syscalls 332
 
 /* 
  * There are some system calls that are not present on 64 bit, some
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 228e310..c75ed43 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -3,8 +3,9 @@
 #
 
 ifdef CONFIG_FUNCTION_TRACER
-# Do not trace early boot code
+# Don't trace early setup code and tracing code
 CFLAGS_REMOVE_early.o = -pg
+CFLAGS_REMOVE_ftrace.o = -pg
 endif
 
 #
@@ -22,7 +23,7 @@
 obj-y	:=  bitmap.o traps.o time.o process.o base.o early.o setup.o \
 	    processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
 	    s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o \
-	    vdso.o vtime.o sysinfo.o nmi.o
+	    vdso.o vtime.o sysinfo.o nmi.o sclp.o
 
 obj-y	+= $(if $(CONFIG_64BIT),entry64.o,entry.o)
 obj-y	+= $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
@@ -41,6 +42,8 @@
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_FUNCTION_TRACER)	+= mcount.o
+obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o
+obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
 
 # Kexec part
 S390_KEXEC_OBJS := machine_kexec.o crash.o
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index fb38af6..88a83366 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -1823,3 +1823,20 @@
 	llgfr	%r5,%r5			# u32
 	llgfr	%r6,%r6			# u32
 	jg	compat_sys_pwritev	# branch to system call
+
+	.globl	compat_sys_rt_tgsigqueueinfo_wrapper
+compat_sys_rt_tgsigqueueinfo_wrapper:
+	lgfr	%r2,%r2			# compat_pid_t
+	lgfr	%r3,%r3			# compat_pid_t
+	lgfr	%r4,%r4			# int
+	llgtr	%r5,%r5			# struct compat_siginfo *
+	jg	compat_sys_rt_tgsigqueueinfo_wrapper # branch to system call
+
+	.globl	sys_perf_counter_open_wrapper
+sys_perf_counter_open_wrapper:
+	llgtr	%r2,%r2			# const struct perf_counter_attr *
+	lgfr	%r3,%r3			# pid_t
+	lgfr	%r4,%r4			# int
+	lgfr	%r5,%r5			# int
+	llgfr	%r6,%r6			# unsigned long
+	jg	sys_perf_counter_open	# branch to system call
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index cf09948..fb26373 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -11,6 +11,7 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
+#include <linux/ftrace.h>
 #include <linux/lockdep.h>
 #include <linux/module.h>
 #include <linux/pfn.h>
@@ -410,5 +411,8 @@
 	sclp_facilities_detect();
 	detect_memory_layout(memory_chunk);
 	S390_lowcore.machine_flags = machine_flags;
+#ifdef CONFIG_DYNAMIC_FTRACE
+	S390_lowcore.ftrace_func = (unsigned long)ftrace_caller;
+#endif
 	lockdep_on();
 }
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index f3e2759..c4c80a2 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -53,6 +53,8 @@
 		 _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
 _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
 		 _TIF_MCCK_PENDING)
+_TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
+		_TIF_SECCOMP>>8 | _TIF_SYSCALL_FTRACE>>8)
 
 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
 STACK_SIZE  = 1 << STACK_SHIFT
@@ -265,7 +267,7 @@
 	sth	%r7,SP_SVCNR(%r15)
 	sll	%r7,2		  # svc number *4
 	l	%r8,BASED(.Lsysc_table)
-	tm	__TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+	tm	__TI_flags+2(%r9),_TIF_SYSCALL
 	l	%r8,0(%r7,%r8)	  # get system call addr.
 	bnz	BASED(sysc_tracesys)
 	basr	%r14,%r8	  # call sys_xxxx
@@ -405,7 +407,7 @@
 	basr	%r14,%r8		# call sys_xxx
 	st	%r2,SP_R2(%r15)		# store return value
 sysc_tracenogo:
-	tm	__TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+	tm	__TI_flags+2(%r9),_TIF_SYSCALL
 	bz	BASED(sysc_return)
 	l	%r1,BASED(.Ltrace_exit)
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
@@ -1107,6 +1109,7 @@
 
 		.section .rodata, "a"
 #define SYSCALL(esa,esame,emu)	.long esa
+	.globl	sys_call_table
 sys_call_table:
 #include "syscalls.S"
 #undef SYSCALL
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 84a1058..f6618e9 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -56,6 +56,8 @@
 		 _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
 _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
 		 _TIF_MCCK_PENDING)
+_TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
+		_TIF_SECCOMP>>8 | _TIF_SYSCALL_FTRACE>>8)
 
 #define BASED(name) name-system_call(%r13)
 
@@ -260,7 +262,7 @@
 	larl	%r10,sys_call_table_emu  # use 31 bit emulation system calls
 sysc_noemu:
 #endif
-	tm	__TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+	tm	__TI_flags+6(%r9),_TIF_SYSCALL
 	lgf	%r8,0(%r7,%r10) # load address of system call routine
 	jnz	sysc_tracesys
 	basr	%r14,%r8	# call sys_xxxx
@@ -391,7 +393,7 @@
 	basr	%r14,%r8		# call sys_xxx
 	stg	%r2,SP_R2(%r15)		# store return value
 sysc_tracenogo:
-	tm	__TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+	tm	__TI_flags+6(%r9),_TIF_SYSCALL
 	jz	sysc_return
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
 	larl	%r14,sysc_return	# return point is sysc_return
@@ -1058,6 +1060,7 @@
 
 		.section .rodata, "a"
 #define SYSCALL(esa,esame,emu)	.long esame
+	.globl	sys_call_table
 sys_call_table:
 #include "syscalls.S"
 #undef SYSCALL
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c
new file mode 100644
index 0000000..82ddfd3
--- /dev/null
+++ b/arch/s390/kernel/ftrace.c
@@ -0,0 +1,260 @@
+/*
+ * Dynamic function tracer architecture backend.
+ *
+ * Copyright IBM Corp. 2009
+ *
+ *   Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
+ *
+ */
+
+#include <linux/hardirq.h>
+#include <linux/uaccess.h>
+#include <linux/ftrace.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <trace/syscall.h>
+#include <asm/lowcore.h>
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+void ftrace_disable_code(void);
+void ftrace_disable_return(void);
+void ftrace_call_code(void);
+void ftrace_nop_code(void);
+
+#define FTRACE_INSN_SIZE 4
+
+#ifdef CONFIG_64BIT
+
+asm(
+	"	.align	4\n"
+	"ftrace_disable_code:\n"
+	"	j	0f\n"
+	"	.word	0x0024\n"
+	"	lg	%r1,"__stringify(__LC_FTRACE_FUNC)"\n"
+	"	basr	%r14,%r1\n"
+	"ftrace_disable_return:\n"
+	"	lg	%r14,8(15)\n"
+	"	lgr	%r0,%r0\n"
+	"0:\n");
+
+asm(
+	"	.align	4\n"
+	"ftrace_nop_code:\n"
+	"	j	.+"__stringify(MCOUNT_INSN_SIZE)"\n");
+
+asm(
+	"	.align	4\n"
+	"ftrace_call_code:\n"
+	"	stg	%r14,8(%r15)\n");
+
+#else /* CONFIG_64BIT */
+
+asm(
+	"	.align	4\n"
+	"ftrace_disable_code:\n"
+	"	j	0f\n"
+	"	l	%r1,"__stringify(__LC_FTRACE_FUNC)"\n"
+	"	basr	%r14,%r1\n"
+	"ftrace_disable_return:\n"
+	"	l	%r14,4(%r15)\n"
+	"	j	0f\n"
+	"	bcr	0,%r7\n"
+	"	bcr	0,%r7\n"
+	"	bcr	0,%r7\n"
+	"	bcr	0,%r7\n"
+	"	bcr	0,%r7\n"
+	"	bcr	0,%r7\n"
+	"0:\n");
+
+asm(
+	"	.align	4\n"
+	"ftrace_nop_code:\n"
+	"	j	.+"__stringify(MCOUNT_INSN_SIZE)"\n");
+
+asm(
+	"	.align	4\n"
+	"ftrace_call_code:\n"
+	"	st	%r14,4(%r15)\n");
+
+#endif /* CONFIG_64BIT */
+
+static int ftrace_modify_code(unsigned long ip,
+			      void *old_code, int old_size,
+			      void *new_code, int new_size)
+{
+	unsigned char replaced[MCOUNT_INSN_SIZE];
+
+	/*
+	 * Note: Due to modules code can disappear and change.
+	 *  We need to protect against faulting as well as code
+	 *  changing. We do this by using the probe_kernel_*
+	 *  functions.
+	 *  This however is just a simple sanity check.
+	 */
+	if (probe_kernel_read(replaced, (void *)ip, old_size))
+		return -EFAULT;
+	if (memcmp(replaced, old_code, old_size) != 0)
+		return -EINVAL;
+	if (probe_kernel_write((void *)ip, new_code, new_size))
+		return -EPERM;
+	return 0;
+}
+
+static int ftrace_make_initial_nop(struct module *mod, struct dyn_ftrace *rec,
+				   unsigned long addr)
+{
+	return ftrace_modify_code(rec->ip,
+				  ftrace_call_code, FTRACE_INSN_SIZE,
+				  ftrace_disable_code, MCOUNT_INSN_SIZE);
+}
+
+int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
+		    unsigned long addr)
+{
+	if (addr == MCOUNT_ADDR)
+		return ftrace_make_initial_nop(mod, rec, addr);
+	return ftrace_modify_code(rec->ip,
+				  ftrace_call_code, FTRACE_INSN_SIZE,
+				  ftrace_nop_code, FTRACE_INSN_SIZE);
+}
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+	return ftrace_modify_code(rec->ip,
+				  ftrace_nop_code, FTRACE_INSN_SIZE,
+				  ftrace_call_code, FTRACE_INSN_SIZE);
+}
+
+int ftrace_update_ftrace_func(ftrace_func_t func)
+{
+	ftrace_dyn_func = (unsigned long)func;
+	return 0;
+}
+
+int __init ftrace_dyn_arch_init(void *data)
+{
+	*(unsigned long *)data = 0;
+	return 0;
+}
+
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#ifdef CONFIG_DYNAMIC_FTRACE
+/*
+ * Patch the kernel code at ftrace_graph_caller location:
+ * The instruction there is branch relative on condition. The condition mask
+ * is either all ones (always branch aka disable ftrace_graph_caller) or all
+ * zeroes (nop aka enable ftrace_graph_caller).
+ * Instruction format for brc is a7m4xxxx where m is the condition mask.
+ */
+int ftrace_enable_ftrace_graph_caller(void)
+{
+	unsigned short opcode = 0xa704;
+
+	return probe_kernel_write(ftrace_graph_caller, &opcode, sizeof(opcode));
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+	unsigned short opcode = 0xa7f4;
+
+	return probe_kernel_write(ftrace_graph_caller, &opcode, sizeof(opcode));
+}
+
+static inline unsigned long ftrace_mcount_call_adjust(unsigned long addr)
+{
+	return addr - (ftrace_disable_return - ftrace_disable_code);
+}
+
+#else /* CONFIG_DYNAMIC_FTRACE */
+
+static inline unsigned long ftrace_mcount_call_adjust(unsigned long addr)
+{
+	return addr - MCOUNT_OFFSET_RET;
+}
+
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+/*
+ * Hook the return address and push it in the stack of return addresses
+ * in current thread info.
+ */
+unsigned long prepare_ftrace_return(unsigned long ip, unsigned long parent)
+{
+	struct ftrace_graph_ent trace;
+
+	/* Nmi's are currently unsupported. */
+	if (unlikely(in_nmi()))
+		goto out;
+	if (unlikely(atomic_read(&current->tracing_graph_pause)))
+		goto out;
+	if (ftrace_push_return_trace(parent, ip, &trace.depth) == -EBUSY)
+		goto out;
+	trace.func = ftrace_mcount_call_adjust(ip) & PSW_ADDR_INSN;
+	/* Only trace if the calling function expects to. */
+	if (!ftrace_graph_entry(&trace)) {
+		current->curr_ret_stack--;
+		goto out;
+	}
+	parent = (unsigned long)return_to_handler;
+out:
+	return parent;
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#ifdef CONFIG_FTRACE_SYSCALLS
+
+extern unsigned long __start_syscalls_metadata[];
+extern unsigned long __stop_syscalls_metadata[];
+extern unsigned int sys_call_table[];
+
+static struct syscall_metadata **syscalls_metadata;
+
+struct syscall_metadata *syscall_nr_to_meta(int nr)
+{
+	if (!syscalls_metadata || nr >= NR_syscalls || nr < 0)
+		return NULL;
+
+	return syscalls_metadata[nr];
+}
+
+static struct syscall_metadata *find_syscall_meta(unsigned long syscall)
+{
+	struct syscall_metadata *start;
+	struct syscall_metadata *stop;
+	char str[KSYM_SYMBOL_LEN];
+
+	start = (struct syscall_metadata *)__start_syscalls_metadata;
+	stop = (struct syscall_metadata *)__stop_syscalls_metadata;
+	kallsyms_lookup(syscall, NULL, NULL, NULL, str);
+
+	for ( ; start < stop; start++) {
+		if (start->name && !strcmp(start->name + 3, str + 3))
+			return start;
+	}
+	return NULL;
+}
+
+void arch_init_ftrace_syscalls(void)
+{
+	struct syscall_metadata *meta;
+	int i;
+	static atomic_t refs;
+
+	if (atomic_inc_return(&refs) != 1)
+		goto out;
+	syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * NR_syscalls,
+				    GFP_KERNEL);
+	if (!syscalls_metadata)
+		goto out;
+	for (i = 0; i < NR_syscalls; i++) {
+		meta = find_syscall_meta((unsigned long)sys_call_table[i]);
+		syscalls_metadata[i] = meta;
+	}
+	return;
+out:
+	atomic_dec(&refs);
+}
+#endif
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
index 2c54e970..ec68823 100644
--- a/arch/s390/kernel/head.S
+++ b/arch/s390/kernel/head.S
@@ -1,7 +1,5 @@
 /*
- *  arch/s390/kernel/head.S
- *
- * Copyright (C) IBM Corp. 1999,2006
+ * Copyright IBM Corp. 1999,2009
  *
  *    Author(s): Hartmut Penner <hp@de.ibm.com>
  *		 Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -479,27 +477,58 @@
 	mvc	__LC_LAST_UPDATE_TIMER(8),6f-.LPG0(%r13)
 	mvc	__LC_EXIT_TIMER(8),5f-.LPG0(%r13)
 #ifndef CONFIG_MARCH_G5
-	# check processor version against MARCH_{G5,Z900,Z990,Z9_109,Z10}
-	stidp	__LC_CPUID		# store cpuid
-	lhi	%r0,(3f-2f) / 2
-	la	%r1,2f-.LPG0(%r13)
-0:	clc	__LC_CPUID+4(2),0(%r1)
-	jne	3f
-	lpsw	1f-.LPG0(13)		# machine type not good enough, crash
+	# check capabilities against MARCH_{G5,Z900,Z990,Z9_109,Z10}
+	xc	__LC_STFL_FAC_LIST(8),__LC_STFL_FAC_LIST
+	stfl	__LC_STFL_FAC_LIST	# store facility list
+	tm	__LC_STFL_FAC_LIST,0x01	# stfle available ?
+	jz	0f
+	la	%r0,0
+	.insn	s,0xb2b00000,__LC_STFL_FAC_LIST	# store facility list extended
+0:	l	%r0,__LC_STFL_FAC_LIST
+	n	%r0,2f+8-.LPG0(%r13)
+	cl	%r0,2f+8-.LPG0(%r13)
+	jne	1f
+	l	%r0,__LC_STFL_FAC_LIST+4
+	n	%r0,2f+12-.LPG0(%r13)
+	cl	%r0,2f+12-.LPG0(%r13)
+	je	3f
+1:	l	%r15,.Lstack-.LPG0(%r13)
+	ahi	%r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union+THREAD_SIZE
+	ahi	%r15,-96
+	la	%r2,.Lals_string-.LPG0(%r13)
+	l	%r3,.Lsclp_print-.LPG0(%r13)
+	basr	%r14,%r3
+	lpsw	2f-.LPG0(%r13)		# machine type not good enough, crash
+.Lals_string:
+	.asciz	"The Linux kernel requires more recent processor hardware"
+.Lsclp_print:
+	.long	_sclp_print_early
+.Lstack:
+	.long	init_thread_union
 	.align 16
-1:	.long	0x000a0000,0x00000000
-2:
+2:	.long	0x000a0000,0x8badcccc
+#if defined(CONFIG_64BIT)
 #if defined(CONFIG_MARCH_Z10)
-	.short 0x9672, 0x2064, 0x2066, 0x2084, 0x2086, 0x2094, 0x2096
+	.long 0xc100efe3, 0xf0680000
 #elif defined(CONFIG_MARCH_Z9_109)
-	.short 0x9672, 0x2064, 0x2066, 0x2084, 0x2086
+	.long 0xc100efc3, 0x00000000
 #elif defined(CONFIG_MARCH_Z990)
-	.short 0x9672, 0x2064, 0x2066
+	.long 0xc0002000, 0x00000000
 #elif defined(CONFIG_MARCH_Z900)
-	.short 0x9672
+	.long 0xc0000000, 0x00000000
 #endif
-3:	la	%r1,2(%r1)
-	brct	%r0,0b
+#else
+#if defined(CONFIG_MARCH_Z10)
+	.long 0x8100c880, 0x00000000
+#elif defined(CONFIG_MARCH_Z9_109)
+	.long 0x8100c880, 0x00000000
+#elif defined(CONFIG_MARCH_Z990)
+	.long 0x80002000, 0x00000000
+#elif defined(CONFIG_MARCH_Z900)
+	.long 0x80000000, 0x00000000
+#endif
+#endif
+3:
 #endif
 
 	l	%r13,4f-.LPG0(%r13)
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index a01cf02..9bb2f62 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -25,9 +25,9 @@
 #include <linux/preempt.h>
 #include <linux/stop_machine.h>
 #include <linux/kdebug.h>
+#include <linux/uaccess.h>
 #include <asm/cacheflush.h>
 #include <asm/sections.h>
-#include <asm/uaccess.h>
 #include <linux/module.h>
 
 DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
@@ -155,35 +155,8 @@
 static int __kprobes swap_instruction(void *aref)
 {
 	struct ins_replace_args *args = aref;
-	u32 *addr;
-	u32 instr;
-	int err = -EFAULT;
 
-	/*
-	 * Text segment is read-only, hence we use stura to bypass dynamic
-	 * address translation to exchange the instruction. Since stura
-	 * always operates on four bytes, but we only want to exchange two
-	 * bytes do some calculations to get things right. In addition we
-	 * shall not cross any page boundaries (vmalloc area!) when writing
-	 * the new instruction.
-	 */
-	addr = (u32 *)((unsigned long)args->ptr & -4UL);
-	if ((unsigned long)args->ptr & 2)
-		instr = ((*addr) & 0xffff0000) | args->new;
-	else
-		instr = ((*addr) & 0x0000ffff) | args->new << 16;
-
-	asm volatile(
-		"	lra	%1,0(%1)\n"
-		"0:	stura	%2,%1\n"
-		"1:	la	%0,0\n"
-		"2:\n"
-		EX_TABLE(0b,2b)
-		: "+d" (err)
-		: "a" (addr), "d" (instr)
-		: "memory", "cc");
-
-	return err;
+	return probe_kernel_write(args->ptr, &args->new, sizeof(args->new));
 }
 
 void __kprobes arch_arm_kprobe(struct kprobe *p)
diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S
index 8064122..2a0a5e9 100644
--- a/arch/s390/kernel/mcount.S
+++ b/arch/s390/kernel/mcount.S
@@ -1,5 +1,5 @@
 /*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
  *
  *   Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
  *
@@ -7,36 +7,64 @@
 
 #include <asm/asm-offsets.h>
 
-#ifndef CONFIG_64BIT
-.globl _mcount
-_mcount:
-	stm	%r0,%r5,8(%r15)
-	st	%r14,56(%r15)
-	lr	%r1,%r15
-	ahi	%r15,-96
-	l	%r3,100(%r15)
-	la	%r2,0(%r14)
-	st	%r1,__SF_BACKCHAIN(%r15)
-	la	%r3,0(%r3)
-	bras	%r14,0f
-	.long	ftrace_trace_function
-0:	l	%r14,0(%r14)
-	l	%r14,0(%r14)
-	basr	%r14,%r14
-	ahi	%r15,96
-	lm	%r0,%r5,8(%r15)
-	l	%r14,56(%r15)
-	br	%r14
-
-.globl ftrace_stub
+	.globl ftrace_stub
 ftrace_stub:
 	br	%r14
 
-#else /* CONFIG_64BIT */
+#ifdef CONFIG_64BIT
 
-.globl _mcount
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+	.globl _mcount
 _mcount:
-	stmg	%r0,%r5,16(%r15)
+	br	%r14
+
+	.globl ftrace_caller
+ftrace_caller:
+	larl	%r1,function_trace_stop
+	icm	%r1,0xf,0(%r1)
+	bnzr	%r14
+	stmg	%r2,%r5,32(%r15)
+	stg	%r14,112(%r15)
+	lgr	%r1,%r15
+	aghi	%r15,-160
+	stg	%r1,__SF_BACKCHAIN(%r15)
+	lgr	%r2,%r14
+	lg	%r3,168(%r15)
+	larl	%r14,ftrace_dyn_func
+	lg	%r14,0(%r14)
+	basr	%r14,%r14
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	.globl	ftrace_graph_caller
+ftrace_graph_caller:
+	# This unconditional branch gets runtime patched. Change only if
+	# you know what you are doing. See ftrace_enable_graph_caller().
+	j	0f
+	lg	%r2,272(%r15)
+	lg	%r3,168(%r15)
+	brasl	%r14,prepare_ftrace_return
+	stg	%r2,168(%r15)
+0:
+#endif
+	aghi	%r15,160
+	lmg	%r2,%r5,32(%r15)
+	lg	%r14,112(%r15)
+	br	%r14
+
+	.data
+	.globl	ftrace_dyn_func
+ftrace_dyn_func:
+	.quad	ftrace_stub
+	.previous
+
+#else /* CONFIG_DYNAMIC_FTRACE */
+
+	.globl _mcount
+_mcount:
+	larl	%r1,function_trace_stop
+	icm	%r1,0xf,0(%r1)
+	bnzr	%r14
+	stmg	%r2,%r5,32(%r15)
 	stg	%r14,112(%r15)
 	lgr	%r1,%r15
 	aghi	%r15,-160
@@ -46,13 +74,143 @@
 	larl	%r14,ftrace_trace_function
 	lg	%r14,0(%r14)
 	basr	%r14,%r14
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	lg	%r2,272(%r15)
+	lg	%r3,168(%r15)
+	brasl	%r14,prepare_ftrace_return
+	stg	%r2,168(%r15)
+#endif
 	aghi	%r15,160
-	lmg	%r0,%r5,16(%r15)
+	lmg	%r2,%r5,32(%r15)
 	lg	%r14,112(%r15)
 	br	%r14
 
-.globl ftrace_stub
-ftrace_stub:
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+	.globl	return_to_handler
+return_to_handler:
+	stmg	%r2,%r5,32(%r15)
+	lgr	%r1,%r15
+	aghi	%r15,-160
+	stg	%r1,__SF_BACKCHAIN(%r15)
+	brasl	%r14,ftrace_return_to_handler
+	aghi	%r15,160
+	lgr	%r14,%r2
+	lmg	%r2,%r5,32(%r15)
 	br	%r14
 
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#else /* CONFIG_64BIT */
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+	.globl _mcount
+_mcount:
+	br	%r14
+
+	.globl ftrace_caller
+ftrace_caller:
+	stm	%r2,%r5,16(%r15)
+	bras	%r1,2f
+0:	.long	ftrace_trace_function
+1:	.long	function_trace_stop
+2:	l	%r2,1b-0b(%r1)
+	icm	%r2,0xf,0(%r2)
+	jnz	3f
+	st	%r14,56(%r15)
+	lr	%r0,%r15
+	ahi	%r15,-96
+	l	%r3,100(%r15)
+	la	%r2,0(%r14)
+	st	%r0,__SF_BACKCHAIN(%r15)
+	la	%r3,0(%r3)
+	l	%r14,0b-0b(%r1)
+	l	%r14,0(%r14)
+	basr	%r14,%r14
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	.globl	ftrace_graph_caller
+ftrace_graph_caller:
+	# This unconditional branch gets runtime patched. Change only if
+	# you know what you are doing. See ftrace_enable_graph_caller().
+	j	1f
+	bras	%r1,0f
+	.long	prepare_ftrace_return
+0:	l	%r2,152(%r15)
+	l	%r4,0(%r1)
+	l	%r3,100(%r15)
+	basr	%r14,%r4
+	st	%r2,100(%r15)
+1:
+#endif
+	ahi	%r15,96
+	l	%r14,56(%r15)
+3:	lm	%r2,%r5,16(%r15)
+	br	%r14
+
+	.data
+	.globl	ftrace_dyn_func
+ftrace_dyn_func:
+	.long	ftrace_stub
+	.previous
+
+#else /* CONFIG_DYNAMIC_FTRACE */
+
+	.globl _mcount
+_mcount:
+	stm	%r2,%r5,16(%r15)
+	bras	%r1,2f
+0:	.long	ftrace_trace_function
+1:	.long	function_trace_stop
+2:	l	%r2,1b-0b(%r1)
+	icm	%r2,0xf,0(%r2)
+	jnz	3f
+	st	%r14,56(%r15)
+	lr	%r0,%r15
+	ahi	%r15,-96
+	l	%r3,100(%r15)
+	la	%r2,0(%r14)
+	st	%r0,__SF_BACKCHAIN(%r15)
+	la	%r3,0(%r3)
+	l	%r14,0b-0b(%r1)
+	l	%r14,0(%r14)
+	basr	%r14,%r14
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	bras	%r1,0f
+	.long	prepare_ftrace_return
+0:	l	%r2,152(%r15)
+	l	%r4,0(%r1)
+	l	%r3,100(%r15)
+	basr	%r14,%r4
+	st	%r2,100(%r15)
+#endif
+	ahi	%r15,96
+	l	%r14,56(%r15)
+3:	lm	%r2,%r5,16(%r15)
+	br	%r14
+
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+	.globl	return_to_handler
+return_to_handler:
+	stm	%r2,%r5,16(%r15)
+	st	%r14,56(%r15)
+	lr	%r0,%r15
+	ahi	%r15,-96
+	st	%r0,__SF_BACKCHAIN(%r15)
+	bras	%r1,0f
+	.long	ftrace_return_to_handler
+0:	l	%r2,0b-0b(%r1)
+	basr	%r14,%r2
+	lr	%r14,%r2
+	ahi	%r15,96
+	lm	%r2,%r5,16(%r15)
+	br	%r14
+
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
 #endif /* CONFIG_64BIT */
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index eed4a00..ab2e3ed 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -56,8 +56,6 @@
 void module_free(struct module *mod, void *module_region)
 {
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 static void
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c
index 28cf196..015e27d 100644
--- a/arch/s390/kernel/nmi.c
+++ b/arch/s390/kernel/nmi.c
@@ -16,7 +16,7 @@
 #include <asm/lowcore.h>
 #include <asm/smp.h>
 #include <asm/etr.h>
-#include <asm/cpu.h>
+#include <asm/cputime.h>
 #include <asm/nmi.h>
 #include <asm/crw.h>
 
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index a3acd8e..355f7a3 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -32,6 +32,7 @@
 #include <linux/elfcore.h>
 #include <linux/kernel_stat.h>
 #include <linux/syscalls.h>
+#include <asm/compat.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -204,7 +205,7 @@
 	save_fp_regs(&p->thread.fp_regs);
 	/* Set a new TLS ?  */
 	if (clone_flags & CLONE_SETTLS) {
-		if (test_thread_flag(TIF_31BIT)) {
+		if (is_compat_task()) {
 			p->thread.acrs[0] = (unsigned int) regs->gprs[6];
 		} else {
 			p->thread.acrs[0] = (unsigned int)(regs->gprs[6] >> 32);
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 75c496f..490b399 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -36,7 +36,9 @@
 #include <linux/elf.h>
 #include <linux/regset.h>
 #include <linux/tracehook.h>
-
+#include <linux/seccomp.h>
+#include <trace/syscall.h>
+#include <asm/compat.h>
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -69,7 +71,7 @@
 	if (per_info->single_step) {
 		per_info->control_regs.bits.starting_addr = 0;
 #ifdef CONFIG_COMPAT
-		if (test_thread_flag(TIF_31BIT))
+		if (is_compat_task())
 			per_info->control_regs.bits.ending_addr = 0x7fffffffUL;
 		else
 #endif
@@ -482,8 +484,7 @@
 {
 	__u32 tmp;
 
-	if (!test_thread_flag(TIF_31BIT) ||
-	    (addr & 3) || addr > sizeof(struct user) - 3)
+	if (!is_compat_task() || (addr & 3) || addr > sizeof(struct user) - 3)
 		return -EIO;
 
 	tmp = __peek_user_compat(child, addr);
@@ -584,8 +585,7 @@
 static int poke_user_compat(struct task_struct *child,
 			    addr_t addr, addr_t data)
 {
-	if (!test_thread_flag(TIF_31BIT) ||
-	    (addr & 3) || addr > sizeof(struct user32) - 3)
+	if (!is_compat_task() || (addr & 3) || addr > sizeof(struct user32) - 3)
 		return -EIO;
 
 	return __poke_user_compat(child, addr, data);
@@ -642,6 +642,9 @@
 {
 	long ret;
 
+	/* Do the secure computing check first. */
+	secure_computing(regs->gprs[2]);
+
 	/*
 	 * The sysc_tracesys code in entry.S stored the system
 	 * call number to gprs[2].
@@ -659,8 +662,11 @@
 		ret = -1;
 	}
 
+	if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
+		ftrace_syscall_enter(regs);
+
 	if (unlikely(current->audit_context))
-		audit_syscall_entry(test_thread_flag(TIF_31BIT) ?
+		audit_syscall_entry(is_compat_task() ?
 					AUDIT_ARCH_S390 : AUDIT_ARCH_S390X,
 				    regs->gprs[2], regs->orig_gpr2,
 				    regs->gprs[3], regs->gprs[4],
@@ -674,6 +680,9 @@
 		audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]),
 				   regs->gprs[2]);
 
+	if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
+		ftrace_syscall_exit(regs);
+
 	if (test_thread_flag(TIF_SYSCALL_TRACE))
 		tracehook_report_syscall_exit(regs, 0);
 }
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
index a0d2d55..0de305b 100644
--- a/arch/s390/kernel/s390_ext.c
+++ b/arch/s390/kernel/s390_ext.c
@@ -10,10 +10,11 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/ftrace.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
-#include <asm/cpu.h>
+#include <asm/cputime.h>
 #include <asm/lowcore.h>
 #include <asm/s390_ext.h>
 #include <asm/irq_regs.h>
@@ -112,7 +113,7 @@
 	return 0;
 }
 
-void do_extint(struct pt_regs *regs, unsigned short code)
+void __irq_entry do_extint(struct pt_regs *regs, unsigned short code)
 {
         ext_int_info_t *p;
         int index;
diff --git a/arch/s390/kernel/sclp.S b/arch/s390/kernel/sclp.S
new file mode 100644
index 0000000..20639df
--- /dev/null
+++ b/arch/s390/kernel/sclp.S
@@ -0,0 +1,327 @@
+/*
+ * Mini SCLP driver.
+ *
+ * Copyright IBM Corp. 2004,2009
+ *
+ *   Author(s):	Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>,
+ *		Heiko Carstens <heiko.carstens@de.ibm.com>,
+ *
+ */
+
+LC_EXT_NEW_PSW		= 0x58			# addr of ext int handler
+LC_EXT_INT_PARAM	= 0x80			# addr of ext int parameter
+LC_EXT_INT_CODE		= 0x86			# addr of ext int code
+
+#
+# Subroutine which waits synchronously until either an external interruption
+# or a timeout occurs.
+#
+# Parameters:
+#   R2	= 0 for no timeout, non-zero for timeout in (approximated) seconds
+#
+# Returns:
+#   R2	= 0 on interrupt, 2 on timeout
+#   R3	= external interruption parameter if R2=0
+#
+
+.section ".init.text","ax"
+
+_sclp_wait_int:
+	stm	%r6,%r15,24(%r15)		# save registers
+	basr	%r13,0				# get base register
+.LbaseS1:
+	ahi	%r15,-96			# create stack frame
+	la	%r8,LC_EXT_NEW_PSW		# register int handler
+	mvc	.LoldpswS1-.LbaseS1(8,%r13),0(%r8)
+	mvc	0(8,%r8),.LextpswS1-.LbaseS1(%r13)
+	lhi	%r6,0x0200			# cr mask for ext int (cr0.54)
+	ltr	%r2,%r2
+	jz	.LsetctS1
+	ahi	%r6,0x0800			# cr mask for clock int (cr0.52)
+	stck	.LtimeS1-.LbaseS1(%r13)		# initiate timeout
+	al	%r2,.LtimeS1-.LbaseS1(%r13)
+	st	%r2,.LtimeS1-.LbaseS1(%r13)
+	sckc	.LtimeS1-.LbaseS1(%r13)
+
+.LsetctS1:
+	stctl	%c0,%c0,.LctlS1-.LbaseS1(%r13)	# enable required interrupts
+	l	%r0,.LctlS1-.LbaseS1(%r13)
+	lhi	%r1,~(0x200 | 0x800)		# clear old values
+	nr	%r1,%r0
+	or	%r1,%r6				# set new value
+	st	%r1,.LctlS1-.LbaseS1(%r13)
+	lctl	%c0,%c0,.LctlS1-.LbaseS1(%r13)
+	st	%r0,.LctlS1-.LbaseS1(%r13)
+	lhi	%r2,2				# return code for timeout
+.LloopS1:
+	lpsw	.LwaitpswS1-.LbaseS1(%r13)	# wait until interrupt
+.LwaitS1:
+	lh	%r7,LC_EXT_INT_CODE
+	chi	%r7,0x1004			# timeout?
+	je	.LtimeoutS1
+	chi	%r7,0x2401			# service int?
+	jne	.LloopS1
+	sr	%r2,%r2
+	l	%r3,LC_EXT_INT_PARAM
+.LtimeoutS1:
+	lctl	%c0,%c0,.LctlS1-.LbaseS1(%r13)	# restore interrupt setting
+	# restore old handler
+	mvc	0(8,%r8),.LoldpswS1-.LbaseS1(%r13)
+	lm	%r6,%r15,120(%r15)		# restore registers
+	br	%r14				# return to caller
+
+	.align	8
+.LoldpswS1:
+	.long	0, 0				# old ext int PSW
+.LextpswS1:
+	.long	0x00080000, 0x80000000+.LwaitS1	# PSW to handle ext int
+.LwaitpswS1:
+	.long	0x010a0000, 0x00000000+.LloopS1	# PSW to wait for ext int
+.LtimeS1:
+	.quad	0				# current time
+.LctlS1:
+	.long	0				# CT0 contents
+
+#
+# Subroutine to synchronously issue a service call.
+#
+# Parameters:
+#   R2	= command word
+#   R3	= sccb address
+#
+# Returns:
+#   R2	= 0 on success, 1 on failure
+#   R3	= sccb response code if R2 = 0
+#
+
+_sclp_servc:
+	stm	%r6,%r15,24(%r15)		# save registers
+	ahi	%r15,-96			# create stack frame
+	lr	%r6,%r2				# save command word
+	lr	%r7,%r3				# save sccb address
+.LretryS2:
+	lhi	%r2,1				# error return code
+	.insn	rre,0xb2200000,%r6,%r7		# servc
+	brc	1,.LendS2			# exit if not operational
+	brc	8,.LnotbusyS2			# go on if not busy
+	sr	%r2,%r2				# wait until no longer busy
+	bras	%r14,_sclp_wait_int
+	j	.LretryS2			# retry
+.LnotbusyS2:
+	sr	%r2,%r2				# wait until result
+	bras	%r14,_sclp_wait_int
+	sr	%r2,%r2
+	lh	%r3,6(%r7)
+.LendS2:
+	lm	%r6,%r15,120(%r15)		# restore registers
+	br	%r14
+
+#
+# Subroutine to set up the SCLP interface.
+#
+# Parameters:
+#   R2	= 0 to activate, non-zero to deactivate
+#
+# Returns:
+#   R2	= 0 on success, non-zero on failure
+#
+
+_sclp_setup:
+	stm	%r6,%r15,24(%r15)		# save registers
+	ahi	%r15,-96			# create stack frame
+	basr	%r13,0				# get base register
+.LbaseS3:
+	l	%r6,.LsccbS0-.LbaseS3(%r13)	# prepare init mask sccb
+	mvc	0(.LinitendS3-.LinitsccbS3,%r6),.LinitsccbS3-.LbaseS3(%r13)
+	ltr	%r2,%r2				# initialization?
+	jz	.LdoinitS3			# go ahead
+	# clear masks
+	xc	.LinitmaskS3-.LinitsccbS3(8,%r6),.LinitmaskS3-.LinitsccbS3(%r6)
+.LdoinitS3:
+	l	%r2,.LwritemaskS3-.LbaseS3(%r13)# get command word
+	lr	%r3,%r6				# get sccb address
+	bras	%r14,_sclp_servc		# issue service call
+	ltr	%r2,%r2				# servc successful?
+	jnz	.LerrorS3
+	chi	%r3,0x20			# write mask successful?
+	jne	.LerrorS3
+	# check masks
+	la	%r2,.LinitmaskS3-.LinitsccbS3(%r6)
+	l	%r1,0(%r2)			# receive mask ok?
+	n	%r1,12(%r2)
+	cl	%r1,0(%r2)
+	jne	.LerrorS3
+	l	%r1,4(%r2)			# send mask ok?
+	n	%r1,8(%r2)
+	cl	%r1,4(%r2)
+	sr	%r2,%r2
+	je	.LendS3
+.LerrorS3:
+	lhi	%r2,1				# error return code
+.LendS3:
+	lm	%r6,%r15,120(%r15)		# restore registers
+	br	%r14
+.LwritemaskS3:
+	.long	0x00780005			# SCLP command for write mask
+.LinitsccbS3:
+	.word	.LinitendS3-.LinitsccbS3
+	.byte	0,0,0,0
+	.word	0
+	.word	0
+	.word	4
+.LinitmaskS3:
+	.long	0x80000000
+	.long	0x40000000
+	.long	0
+	.long	0
+.LinitendS3:
+
+#
+# Subroutine which prints a given text to the SCLP console.
+#
+# Parameters:
+#   R2	= address of nil-terminated ASCII text
+#
+# Returns:
+#   R2	= 0 on success, 1 on failure
+#
+
+_sclp_print:
+	stm	%r6,%r15,24(%r15)		# save registers
+	ahi	%r15,-96			# create stack frame
+	basr	%r13,0				# get base register
+.LbaseS4:
+	l	%r8,.LsccbS0-.LbaseS4(%r13)	# prepare write data sccb
+	mvc	0(.LmtoS4-.LwritesccbS4,%r8),.LwritesccbS4-.LbaseS4(%r13)
+	la	%r7,.LmtoS4-.LwritesccbS4(%r8)	# current mto addr
+	sr	%r0,%r0
+	l	%r10,.Lascebc-.LbaseS4(%r13)	# address of translation table
+.LinitmtoS4:
+	# initialize mto
+	mvc	0(.LmtoendS4-.LmtoS4,%r7),.LmtoS4-.LbaseS4(%r13)
+	lhi	%r6,.LmtoendS4-.LmtoS4		# current mto length
+.LloopS4:
+	ic	%r0,0(%r2)			# get character
+	ahi	%r2,1
+	ltr	%r0,%r0				# end of string?
+	jz	.LfinalizemtoS4
+	chi	%r0,0x15			# end of line (NL)?
+	jz	.LfinalizemtoS4
+	stc	%r0,0(%r6,%r7)			# copy to mto
+	la	%r11,0(%r6,%r7)
+	tr	0(1,%r11),0(%r10)		# translate to EBCDIC
+	ahi	%r6,1
+	j	.LloopS4
+.LfinalizemtoS4:
+	sth	%r6,0(%r7)			# update mto length
+	lh	%r9,.LmdbS4-.LwritesccbS4(%r8)	# update mdb length
+	ar	%r9,%r6
+	sth	%r9,.LmdbS4-.LwritesccbS4(%r8)
+	lh	%r9,.LevbufS4-.LwritesccbS4(%r8)# update evbuf length
+	ar	%r9,%r6
+	sth	%r9,.LevbufS4-.LwritesccbS4(%r8)
+	lh	%r9,0(%r8)			# update sccb length
+	ar	%r9,%r6
+	sth	%r9,0(%r8)
+	ar	%r7,%r6				# update current mto adress
+	ltr	%r0,%r0				# more characters?
+	jnz	.LinitmtoS4
+	l	%r2,.LwritedataS4-.LbaseS4(%r13)# write data
+	lr	%r3,%r8
+	bras	%r14,_sclp_servc
+	ltr	%r2,%r2				# servc successful?
+	jnz	.LendS4
+	chi	%r3,0x20			# write data successful?
+	je	.LendS4
+	lhi	%r2,1				# error return code
+.LendS4:
+	lm	%r6,%r15,120(%r15)		# restore registers
+	br	%r14
+
+#
+# Function which prints a given text to the SCLP console.
+#
+# Parameters:
+#   R2	= address of nil-terminated ASCII text
+#
+# Returns:
+#   R2	= 0 on success, 1 on failure
+#
+
+	.globl _sclp_print_early
+_sclp_print_early:
+	stm	%r6,%r15,24(%r15)		# save registers
+	ahi	%r15,-96			# create stack frame
+	lr	%r10,%r2			# save string pointer
+	lhi	%r2,0
+	bras	%r14,_sclp_setup		# enable console
+	ltr	%r2,%r2
+	jnz	.LendS5
+	lr	%r2,%r10
+	bras	%r14,_sclp_print		# print string
+	ltr	%r2,%r2
+	jnz	.LendS5
+	lhi	%r2,1
+	bras	%r14,_sclp_setup		# disable console
+.LendS5:
+	lm	%r6,%r15,120(%r15)		# restore registers
+	br	%r14
+
+.LwritedataS4:
+	.long	0x00760005			# SCLP command for write data
+.LwritesccbS4:
+	# sccb
+	.word	.LmtoS4-.LwritesccbS4
+	.byte	0
+	.byte	0,0,0
+	.word	0
+
+	# evbuf
+.LevbufS4:
+	.word	.LmtoS4-.LevbufS4
+	.byte	0x02
+	.byte	0
+	.word	0
+
+.LmdbS4:
+	# mdb
+	.word	.LmtoS4-.LmdbS4
+	.word	1
+	.long	0xd4c4c240
+	.long	1
+
+	# go
+.LgoS4:
+	.word	.LmtoS4-.LgoS4
+	.word	1
+	.long	0
+	.byte	0,0,0,0,0,0,0,0
+	.byte	0,0,0
+	.byte	0
+	.byte	0,0,0,0,0,0,0
+	.byte	0
+	.word	0
+	.byte	0,0,0,0,0,0,0,0,0,0
+	.byte	0,0,0,0,0,0,0,0
+	.byte	0,0,0,0,0,0,0,0
+
+.LmtoS4:
+	.word	.LmtoendS4-.LmtoS4
+	.word	4
+	.word	0x1000
+	.byte	0
+	.byte	0,0,0
+.LmtoendS4:
+
+	# Global constants
+.LsccbS0:
+	.long	_sclp_work_area
+.Lascebc:
+	.long	_ascebc
+.previous
+
+.section ".init.data","a"
+	.balign 4096
+_sclp_work_area:
+	.fill	4096
+.previous
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 7402b6a..9717717 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -42,6 +42,7 @@
 #include <linux/ctype.h>
 #include <linux/reboot.h>
 #include <linux/topology.h>
+#include <linux/ftrace.h>
 
 #include <asm/ipl.h>
 #include <asm/uaccess.h>
@@ -442,6 +443,7 @@
 	lc->steal_timer = S390_lowcore.steal_timer;
 	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;
 	set_prefix((u32)(unsigned long) lc);
 	lowcore_ptr[0] = lc;
 }
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 3cf74c3..062bd64 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -26,6 +26,7 @@
 #include <linux/binfmts.h>
 #include <linux/tracehook.h>
 #include <linux/syscalls.h>
+#include <linux/compat.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/lowcore.h>
@@ -482,7 +483,7 @@
 		/* Whee!  Actually deliver the signal.  */
 		int ret;
 #ifdef CONFIG_COMPAT
-		if (test_thread_flag(TIF_31BIT)) {
+		if (is_compat_task()) {
 			ret = handle_signal32(signr, &ka, &info, oldset, regs);
 	        }
 		else
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index a985a3b..cc8c4849 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -47,7 +47,7 @@
 #include <asm/timer.h>
 #include <asm/lowcore.h>
 #include <asm/sclp.h>
-#include <asm/cpu.h>
+#include <asm/cputime.h>
 #include <asm/vdso.h>
 #include "entry.h"
 
@@ -572,6 +572,7 @@
 	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;
 	eieio();
 
 	while (signal_processor(cpu, sigp_restart) == sigp_busy)
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 2c7739f..ad1acd2 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -338,3 +338,5 @@
 SYSCALL(sys_epoll_create1,sys_epoll_create1,sys_epoll_create1_wrapper)
 SYSCALL(sys_preadv,sys_preadv,compat_sys_preadv_wrapper)
 SYSCALL(sys_pwritev,sys_pwritev,compat_sys_pwritev_wrapper)
+SYSCALL(sys_rt_tgsigqueueinfo,sys_rt_tgsigqueueinfo,compat_sys_rt_tgsigqueueinfo_wrapper) /* 330 */
+SYSCALL(sys_perf_counter_open,sys_perf_counter_open,sys_perf_counter_open_wrapper)
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index ef596d0..215330a 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -70,7 +70,7 @@
 /*
  * Scheduler clock - returns current time in nanosec units.
  */
-unsigned long long sched_clock(void)
+unsigned long long notrace sched_clock(void)
 {
 	return ((get_clock_xt() - sched_clock_base_cc) * 125) >> 9;
 }
@@ -95,12 +95,6 @@
 	xtime->tv_nsec = ((todval * 1000) >> 12);
 }
 
-#ifdef CONFIG_PROFILING
-#define s390_do_profile()	profile_tick(CPU_PROFILING)
-#else
-#define s390_do_profile()	do { ; } while(0)
-#endif /* CONFIG_PROFILING */
-
 void clock_comparator_work(void)
 {
 	struct clock_event_device *cd;
@@ -109,7 +103,6 @@
 	set_clock_comparator(S390_lowcore.clock_comparator);
 	cd = &__get_cpu_var(comparators);
 	cd->event_handler(cd);
-	s390_do_profile();
 }
 
 /*
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index 89b2e7f..45e1708 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -22,7 +22,7 @@
 #include <linux/elf.h>
 #include <linux/security.h>
 #include <linux/bootmem.h>
-
+#include <linux/compat.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/processor.h>
@@ -53,8 +53,19 @@
 
 static int __init vdso_setup(char *s)
 {
-	vdso_enabled = simple_strtoul(s, NULL, 0);
-	return 1;
+	unsigned long val;
+	int rc;
+
+	rc = 0;
+	if (strncmp(s, "on", 3) == 0)
+		vdso_enabled = 1;
+	else if (strncmp(s, "off", 4) == 0)
+		vdso_enabled = 0;
+	else {
+		rc = strict_strtoul(s, 0, &val);
+		vdso_enabled = rc ? 0 : !!val;
+	}
+	return !rc;
 }
 __setup("vdso=", vdso_setup);
 
@@ -203,7 +214,7 @@
 	vdso_pagelist = vdso64_pagelist;
 	vdso_pages = vdso64_pages;
 #ifdef CONFIG_COMPAT
-	if (test_thread_flag(TIF_31BIT)) {
+	if (is_compat_task()) {
 		vdso_pagelist = vdso32_pagelist;
 		vdso_pages = vdso32_pages;
 	}
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index 89399b8..a53db23 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -34,6 +34,7 @@
 		SCHED_TEXT
 		LOCK_TEXT
 		KPROBES_TEXT
+		IRQENTRY_TEXT
 		*(.fixup)
 		*(.gnu.warning)
 	} :text = 0x0700
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index c87f59b..c8eb725 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -23,7 +23,7 @@
 #include <asm/s390_ext.h>
 #include <asm/timer.h>
 #include <asm/irq_regs.h>
-#include <asm/cpu.h>
+#include <asm/cputime.h>
 
 static ext_int_info_t ext_int_info_timer;
 
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 10bccd1..c18b21d 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -512,7 +512,7 @@
 		BUG();
 	}
 
-	might_sleep();
+	might_fault();
 
 	do {
 		__vcpu_run(vcpu);
diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c
index e41f400..f7e0d30 100644
--- a/arch/s390/lib/spinlock.c
+++ b/arch/s390/lib/spinlock.c
@@ -124,6 +124,27 @@
 }
 EXPORT_SYMBOL(_raw_read_lock_wait);
 
+void _raw_read_lock_wait_flags(raw_rwlock_t *rw, unsigned long flags)
+{
+	unsigned int old;
+	int count = spin_retry;
+
+	local_irq_restore(flags);
+	while (1) {
+		if (count-- <= 0) {
+			_raw_yield();
+			count = spin_retry;
+		}
+		if (!__raw_read_can_lock(rw))
+			continue;
+		old = rw->lock & 0x7fffffffU;
+		local_irq_disable();
+		if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
+			return;
+	}
+}
+EXPORT_SYMBOL(_raw_read_lock_wait_flags);
+
 int _raw_read_trylock_retry(raw_rwlock_t *rw)
 {
 	unsigned int old;
@@ -157,6 +178,25 @@
 }
 EXPORT_SYMBOL(_raw_write_lock_wait);
 
+void _raw_write_lock_wait_flags(raw_rwlock_t *rw, unsigned long flags)
+{
+	int count = spin_retry;
+
+	local_irq_restore(flags);
+	while (1) {
+		if (count-- <= 0) {
+			_raw_yield();
+			count = spin_retry;
+		}
+		if (!__raw_write_can_lock(rw))
+			continue;
+		local_irq_disable();
+		if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
+			return;
+	}
+}
+EXPORT_SYMBOL(_raw_write_lock_wait_flags);
+
 int _raw_write_trylock_retry(raw_rwlock_t *rw)
 {
 	int count = spin_retry;
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile
index 2a74581..db05661 100644
--- a/arch/s390/mm/Makefile
+++ b/arch/s390/mm/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the linux s390-specific parts of the memory manager.
 #
 
-obj-y	 := init.o fault.o extmem.o mmap.o vmem.o pgtable.o
+obj-y	 := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o
 obj-$(CONFIG_CMM) += cmm.o
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
 obj-$(CONFIG_PAGE_STATES) += page-states.o
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 833e836..220a152 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -19,6 +19,7 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/compat.h>
 #include <linux/smp.h>
 #include <linux/kdebug.h>
 #include <linux/smp_lock.h>
@@ -239,7 +240,7 @@
 	up_read(&mm->mmap_sem);
 	clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
 #ifdef CONFIG_COMPAT
-	compat = test_tsk_thread_flag(current, TIF_31BIT);
+	compat = is_compat_task();
 	if (compat && instruction == 0x0a77)
 		sys32_sigreturn();
 	else if (compat && instruction == 0x0aad)
diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c
new file mode 100644
index 0000000..8175627
--- /dev/null
+++ b/arch/s390/mm/maccess.c
@@ -0,0 +1,61 @@
+/*
+ * Access kernel memory without faulting -- s390 specific implementation.
+ *
+ * Copyright IBM Corp. 2009
+ *
+ *   Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
+ *
+ */
+
+#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+
+/*
+ * This function writes to kernel memory bypassing DAT and possible
+ * write protection. It copies one to four bytes from src to dst
+ * using the stura instruction.
+ * Returns the number of bytes copied or -EFAULT.
+ */
+static long probe_kernel_write_odd(void *dst, void *src, size_t size)
+{
+	unsigned long count, aligned;
+	int offset, mask;
+	int rc = -EFAULT;
+
+	aligned = (unsigned long) dst & ~3UL;
+	offset = (unsigned long) dst & 3;
+	count = min_t(unsigned long, 4 - offset, size);
+	mask = (0xf << (4 - count)) & 0xf;
+	mask >>= offset;
+	asm volatile(
+		"	bras	1,0f\n"
+		"	icm	0,0,0(%3)\n"
+		"0:	l	0,0(%1)\n"
+		"	lra	%1,0(%1)\n"
+		"1:	ex	%2,0(1)\n"
+		"2:	stura	0,%1\n"
+		"	la	%0,0\n"
+		"3:\n"
+		EX_TABLE(0b,3b) EX_TABLE(1b,3b) EX_TABLE(2b,3b)
+		: "+d" (rc), "+a" (aligned)
+		: "a" (mask), "a" (src) : "cc", "memory", "0", "1");
+	return rc ? rc : count;
+}
+
+long probe_kernel_write(void *dst, void *src, size_t size)
+{
+	long copied = 0;
+
+	while (size) {
+		copied = probe_kernel_write_odd(dst, src, size);
+		if (copied < 0)
+			break;
+		dst += copied;
+		src += copied;
+		size -= copied;
+	}
+	return copied < 0 ? -EFAULT : 0;
+}
diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
index e008d23..f4558cc 100644
--- a/arch/s390/mm/mmap.c
+++ b/arch/s390/mm/mmap.c
@@ -28,6 +28,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <asm/pgalloc.h>
+#include <asm/compat.h>
 
 /*
  * Top of mmap area (just below the process stack).
@@ -55,7 +56,7 @@
 	/*
 	 * Force standard allocation for 64 bit programs.
 	 */
-	if (!test_thread_flag(TIF_31BIT))
+	if (!is_compat_task())
 		return 1;
 #endif
 	return sysctl_legacy_va_layout ||
@@ -91,7 +92,7 @@
 
 int s390_mmap_check(unsigned long addr, unsigned long len)
 {
-	if (!test_thread_flag(TIF_31BIT) &&
+	if (!is_compat_task() &&
 	    len >= TASK_SIZE && TASK_SIZE < (1UL << 53))
 		return crst_table_upgrade(current->mm, 1UL << 53);
 	return 0;
@@ -108,8 +109,7 @@
 	area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
 	if (!(area & ~PAGE_MASK))
 		return area;
-	if (area == -ENOMEM &&
-	    !test_thread_flag(TIF_31BIT) && TASK_SIZE < (1UL << 53)) {
+	if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < (1UL << 53)) {
 		/* Upgrade the page table to 4 levels and retry. */
 		rc = crst_table_upgrade(mm, 1UL << 53);
 		if (rc)
@@ -131,8 +131,7 @@
 	area = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags);
 	if (!(area & ~PAGE_MASK))
 		return area;
-	if (area == -ENOMEM &&
-	    !test_thread_flag(TIF_31BIT) && TASK_SIZE < (1UL << 53)) {
+	if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < (1UL << 53)) {
 		/* Upgrade the page table to 4 levels and retry. */
 		rc = crst_table_upgrade(mm, 1UL << 53);
 		if (rc)
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index be6c1cf..4ca8e82 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -1,7 +1,5 @@
 /*
- *  arch/s390/mm/pgtable.c
- *
- *    Copyright IBM Corp. 2007
+ *    Copyright IBM Corp. 2007,2009
  *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
@@ -53,6 +51,18 @@
 
 #endif
 
+unsigned long VMALLOC_START = VMALLOC_END - VMALLOC_SIZE;
+EXPORT_SYMBOL(VMALLOC_START);
+
+static int __init parse_vmalloc(char *arg)
+{
+	if (!arg)
+		return -EINVAL;
+	VMALLOC_START = (VMALLOC_END - memparse(arg, &arg)) & PAGE_MASK;
+	return 0;
+}
+early_param("vmalloc", parse_vmalloc);
+
 unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec)
 {
 	struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h
index 978b58e..157c320 100644
--- a/arch/sh/include/asm/atomic.h
+++ b/arch/sh/include/asm/atomic.h
@@ -84,5 +84,5 @@
 #define smp_mb__before_atomic_inc()	barrier()
 #define smp_mb__after_atomic_inc()	barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* __ASM_SH_ATOMIC_H */
diff --git a/arch/sh/include/asm/bitsperlong.h b/arch/sh/include/asm/bitsperlong.h
new file mode 100644
index 0000000..6dc0bb0
--- /dev/null
+++ b/arch/sh/include/asm/bitsperlong.h
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
diff --git a/arch/sh/include/asm/mman.h b/arch/sh/include/asm/mman.h
index 156eb02..7d8b72c 100644
--- a/arch/sh/include/asm/mman.h
+++ b/arch/sh/include/asm/mman.h
@@ -1,7 +1,7 @@
 #ifndef __ASM_SH_MMAN_H
 #define __ASM_SH_MMAN_H
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h
index 9c6d21e..49592c7 100644
--- a/arch/sh/include/asm/page.h
+++ b/arch/sh/include/asm/page.h
@@ -163,7 +163,7 @@
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 /* vDSO support */
 #ifdef CONFIG_VSYSCALL
diff --git a/arch/sh/include/asm/signal.h b/arch/sh/include/asm/signal.h
index 5c5c1e8..9cc5f01 100644
--- a/arch/sh/include/asm/signal.h
+++ b/arch/sh/include/asm/signal.h
@@ -106,7 +106,7 @@
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c
index c19b0f7..c2efdcd 100644
--- a/arch/sh/kernel/module.c
+++ b/arch/sh/kernel/module.c
@@ -46,8 +46,6 @@
 void module_free(struct module *mod, void *module_region)
 {
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h
index bb91b12..f0d343c 100644
--- a/arch/sparc/include/asm/atomic_32.h
+++ b/arch/sparc/include/asm/atomic_32.h
@@ -161,5 +161,5 @@
 
 #endif /* !(__KERNEL__) */
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* !(__ARCH_SPARC_ATOMIC__) */
diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h
index a0a7064..f2e4800 100644
--- a/arch/sparc/include/asm/atomic_64.h
+++ b/arch/sparc/include/asm/atomic_64.h
@@ -114,5 +114,5 @@
 #define smp_mb__before_atomic_inc()	barrier()
 #define smp_mb__after_atomic_inc()	barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* !(__ARCH_SPARC64_ATOMIC__) */
diff --git a/arch/sparc/include/asm/bitsperlong.h b/arch/sparc/include/asm/bitsperlong.h
new file mode 100644
index 0000000..40dcaa3
--- /dev/null
+++ b/arch/sparc/include/asm/bitsperlong.h
@@ -0,0 +1,13 @@
+#ifndef __ASM_ALPHA_BITSPERLONG_H
+#define __ASM_ALPHA_BITSPERLONG_H
+
+#if defined(__sparc__) && defined(__arch64__)
+#define __BITS_PER_LONG 64
+#else
+#define __BITS_PER_LONG 32
+#endif
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_ALPHA_BITSPERLONG_H */
+
diff --git a/arch/sparc/include/asm/mman.h b/arch/sparc/include/asm/mman.h
index fdfbbf0..988192e 100644
--- a/arch/sparc/include/asm/mman.h
+++ b/arch/sparc/include/asm/mman.h
@@ -1,7 +1,7 @@
 #ifndef __SPARC_MMAN_H__
 #define __SPARC_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 /* SunOS'ified... */
 
diff --git a/arch/sparc/include/asm/page_32.h b/arch/sparc/include/asm/page_32.h
index d1806ed..f72080b 100644
--- a/arch/sparc/include/asm/page_32.h
+++ b/arch/sparc/include/asm/page_32.h
@@ -152,6 +152,6 @@
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _SPARC_PAGE_H */
diff --git a/arch/sparc/include/asm/page_64.h b/arch/sparc/include/asm/page_64.h
index 4274ed1..f0d09b4 100644
--- a/arch/sparc/include/asm/page_64.h
+++ b/arch/sparc/include/asm/page_64.h
@@ -132,6 +132,6 @@
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _SPARC64_PAGE_H */
diff --git a/arch/sparc/include/asm/signal.h b/arch/sparc/include/asm/signal.h
index cba4520..e49b828 100644
--- a/arch/sparc/include/asm/signal.h
+++ b/arch/sparc/include/asm/signal.h
@@ -176,7 +176,7 @@
 #define SA_STATIC_ALLOC         0x8000
 #endif
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 struct __new_sigaction {
 	__sighandler_t		sa_handler;
diff --git a/arch/sparc/include/asm/types.h b/arch/sparc/include/asm/types.h
index 22371188..de671d7 100644
--- a/arch/sparc/include/asm/types.h
+++ b/arch/sparc/include/asm/types.h
@@ -21,8 +21,6 @@
 
 #ifdef __KERNEL__
 
-#define BITS_PER_LONG 64
-
 #ifndef __ASSEMBLY__
 
 /* Dma addresses come in generic and 64-bit flavours.  */
@@ -46,8 +44,6 @@
 
 #ifdef __KERNEL__
 
-#define BITS_PER_LONG 32
-
 #ifndef __ASSEMBLY__
 
 typedef u32 dma_addr_t;
diff --git a/arch/sparc/include/asm/uaccess_32.h b/arch/sparc/include/asm/uaccess_32.h
index 47d5619..8303ac4 100644
--- a/arch/sparc/include/asm/uaccess_32.h
+++ b/arch/sparc/include/asm/uaccess_32.h
@@ -17,6 +17,9 @@
 
 #ifndef __ASSEMBLY__
 
+#define ARCH_HAS_SORT_EXTABLE
+#define ARCH_HAS_SEARCH_EXTABLE
+
 /* Sparc is not segmented, however we need to be able to fool access_ok()
  * when doing system calls from kernel mode legitimately.
  *
diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h
index c64e767..a38c032 100644
--- a/arch/sparc/include/asm/uaccess_64.h
+++ b/arch/sparc/include/asm/uaccess_64.h
@@ -12,7 +12,7 @@
 #include <asm/asi.h>
 #include <asm/system.h>
 #include <asm/spitfire.h>
-#include <asm-generic/uaccess.h>
+#include <asm-generic/uaccess-unaligned.h>
 #endif
 
 #ifndef __ASSEMBLY__
diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c
index 9027376..0ee642f 100644
--- a/arch/sparc/kernel/module.c
+++ b/arch/sparc/kernel/module.c
@@ -75,8 +75,6 @@
 void module_free(struct module *mod, void *module_region)
 {
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* Make generic code ignore STT_REGISTER dummy undefined symbols.  */
diff --git a/arch/sparc/mm/extable.c b/arch/sparc/mm/extable.c
index 16cc289..a61c349 100644
--- a/arch/sparc/mm/extable.c
+++ b/arch/sparc/mm/extable.c
@@ -28,6 +28,10 @@
 	 *	word 3: last insn address + 4 bytes
 	 *	word 4: fixup code address
 	 *
+	 * Deleted entries are encoded as:
+	 *	word 1: unused
+	 *	word 2: -1
+	 *
 	 * See asm/uaccess.h for more details.
 	 */
 
@@ -39,6 +43,10 @@
 			continue;
 		}
 
+		/* A deleted entry; see trim_init_extable */
+		if (walk->fixup == -1)
+			continue;
+
 		if (walk->insn == value)
 			return walk;
 	}
@@ -57,6 +65,27 @@
         return NULL;
 }
 
+#ifdef CONFIG_MODULES
+/* We could memmove them around; easier to mark the trimmed ones. */
+void trim_init_extable(struct module *m)
+{
+	unsigned int i;
+	bool range;
+
+	for (i = 0; i < m->num_exentries; i += range ? 2 : 1) {
+		range = m->extable[i].fixup == 0;
+
+		if (within_module_init(m->extable[i].insn, m)) {
+			m->extable[i].fixup = -1;
+			if (range)
+				m->extable[i+1].fixup = -1;
+		}
+		if (range)
+			i++;
+	}
+}
+#endif /* CONFIG_MODULES */
+
 /* Special extable search, which handles ranges.  Returns fixup */
 unsigned long search_extables_range(unsigned long addr, unsigned long *g2)
 {
diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h
index 55f28a0..4cc9b6c 100644
--- a/arch/um/include/asm/page.h
+++ b/arch/um/include/asm/page.h
@@ -116,7 +116,7 @@
 #define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v)))
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif	/* __ASSEMBLY__ */
 #endif	/* __UM_PAGE_H */
diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h
index 58da248..9ce3f16 100644
--- a/arch/um/include/asm/pgtable.h
+++ b/arch/um/include/asm/pgtable.h
@@ -53,16 +53,21 @@
 #else
 # define VMALLOC_END	(FIXADDR_START-2*PAGE_SIZE)
 #endif
+#define MODULES_VADDR	VMALLOC_START
+#define MODULES_END	VMALLOC_END
+#define MODULES_LEN	(MODULES_VADDR - MODULES_END)
 
 #define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _KERNPG_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
-
+#define __PAGE_KERNEL_EXEC                                              \
+	 (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
 #define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
 #define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define PAGE_KERNEL_EXEC	__pgprot(__PAGE_KERNEL_EXEC)
 
 /*
  * The i386 can't do page protection for execute, and considers that the same
diff --git a/arch/um/include/asm/suspend.h b/arch/um/include/asm/suspend.h
deleted file mode 100644
index f4e8e00..0000000
--- a/arch/um/include/asm/suspend.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef __UM_SUSPEND_H
-#define __UM_SUSPEND_H
-
-#endif
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 598b5c1..1b549bc 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -8,7 +8,7 @@
 
 subarch-obj-y = lib/semaphore_32.o lib/string_32.o
 subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o
-subarch-obj-$(CONFIG_MODULES) += kernel/module_32.o
+subarch-obj-$(CONFIG_MODULES) += kernel/module.o
 
 USER_OBJS := bugs.o ptrace_user.o fault.o
 
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
index c8b4cce..2201e9c 100644
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -8,10 +8,8 @@
 	setjmp.o signal.o stub.o stub_segv.o syscalls.o syscall_table.o \
 	sysrq.o ksyms.o tls.o
 
-obj-$(CONFIG_MODULES) += um_module.o
-
 subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o
-subarch-obj-$(CONFIG_MODULES) += kernel/module_64.o
+subarch-obj-$(CONFIG_MODULES) += kernel/module.o
 
 ldt-y = ../sys-i386/ldt.o
 
diff --git a/arch/um/sys-x86_64/um_module.c b/arch/um/sys-x86_64/um_module.c
deleted file mode 100644
index 3dead39..0000000
--- a/arch/um/sys-x86_64/um_module.c
+++ /dev/null
@@ -1,21 +0,0 @@
-#include <linux/vmalloc.h>
-#include <linux/moduleloader.h>
-
-/* Copied from i386 arch/i386/kernel/module.c */
-void *module_alloc(unsigned long size)
-{
-	if (size == 0)
-		return NULL;
-	return vmalloc_exec(size);
-}
-
-/* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
-{
-	vfree(module_region);
-	/*
-	 * FIXME: If module_region == mod->init_region, trim exception
-	 * table entries.
-	 */
-}
-
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 68f5578..356d2ec 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -789,10 +789,26 @@
 	  to disable it.  MCE support simply ignores non-MCE processors like
 	  the 386 and 486, so nearly everyone can say Y here.
 
+config X86_OLD_MCE
+	depends on X86_32 && X86_MCE
+	bool "Use legacy machine check code (will go away)"
+	default n
+	select X86_ANCIENT_MCE
+	---help---
+	  Use the old i386 machine check code. This is merely intended for
+	  testing in a transition period. Try this if you run into any machine
+	  check related software problems, but report the problem to
+	  linux-kernel.  When in doubt say no.
+
+config X86_NEW_MCE
+	depends on X86_MCE
+	bool
+	default y if (!X86_OLD_MCE && X86_32) || X86_64
+
 config X86_MCE_INTEL
 	def_bool y
 	prompt "Intel MCE features"
-	depends on X86_64 && X86_MCE && X86_LOCAL_APIC
+	depends on X86_NEW_MCE && X86_LOCAL_APIC
 	---help---
 	   Additional support for intel specific MCE features such as
 	   the thermal monitor.
@@ -800,19 +816,36 @@
 config X86_MCE_AMD
 	def_bool y
 	prompt "AMD MCE features"
-	depends on X86_64 && X86_MCE && X86_LOCAL_APIC
+	depends on X86_NEW_MCE && X86_LOCAL_APIC
 	---help---
 	   Additional support for AMD specific MCE features such as
 	   the DRAM Error Threshold.
 
+config X86_ANCIENT_MCE
+	def_bool n
+	depends on X86_32
+	prompt "Support for old Pentium 5 / WinChip machine checks"
+	---help---
+	  Include support for machine check handling on old Pentium 5 or WinChip
+	  systems. These typically need to be enabled explicitely on the command
+	  line.
+
 config X86_MCE_THRESHOLD
 	depends on X86_MCE_AMD || X86_MCE_INTEL
 	bool
 	default y
 
+config X86_MCE_INJECT
+	depends on X86_NEW_MCE
+	tristate "Machine check injector support"
+	---help---
+	  Provide support for injecting machine checks for testing purposes.
+	  If you don't know what a machine check is and you don't do kernel
+	  QA it is safe to say n.
+
 config X86_MCE_NONFATAL
 	tristate "Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4"
-	depends on X86_32 && X86_MCE
+	depends on X86_OLD_MCE
 	---help---
 	  Enabling this feature starts a timer that triggers every 5 seconds which
 	  will look at the machine check registers to see if anything happened.
@@ -825,11 +858,15 @@
 
 config X86_MCE_P4THERMAL
 	bool "check for P4 thermal throttling interrupt."
-	depends on X86_32 && X86_MCE && (X86_UP_APIC || SMP)
+	depends on X86_OLD_MCE && X86_MCE && (X86_UP_APIC || SMP)
 	---help---
 	  Enabling this feature will cause a message to be printed when the P4
 	  enters thermal throttling.
 
+config X86_THERMAL_VECTOR
+	def_bool y
+	depends on X86_MCE_P4THERMAL || X86_MCE_INTEL
+
 config VM86
 	bool "Enable VM86 support" if EMBEDDED
 	default y
diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile
index ebe7dee..cfb0010 100644
--- a/arch/x86/crypto/Makefile
+++ b/arch/x86/crypto/Makefile
@@ -2,6 +2,8 @@
 # Arch-specific CryptoAPI modules.
 #
 
+obj-$(CONFIG_CRYPTO_FPU) += fpu.o
+
 obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o
 obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o
 obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
index 02af0af..4e66339 100644
--- a/arch/x86/crypto/aesni-intel_glue.c
+++ b/arch/x86/crypto/aesni-intel_glue.c
@@ -21,6 +21,22 @@
 #include <asm/i387.h>
 #include <asm/aes.h>
 
+#if defined(CONFIG_CRYPTO_CTR) || defined(CONFIG_CRYPTO_CTR_MODULE)
+#define HAS_CTR
+#endif
+
+#if defined(CONFIG_CRYPTO_LRW) || defined(CONFIG_CRYPTO_LRW_MODULE)
+#define HAS_LRW
+#endif
+
+#if defined(CONFIG_CRYPTO_PCBC) || defined(CONFIG_CRYPTO_PCBC_MODULE)
+#define HAS_PCBC
+#endif
+
+#if defined(CONFIG_CRYPTO_XTS) || defined(CONFIG_CRYPTO_XTS_MODULE)
+#define HAS_XTS
+#endif
+
 struct async_aes_ctx {
 	struct cryptd_ablkcipher *cryptd_tfm;
 };
@@ -137,6 +153,41 @@
 	}
 };
 
+static void __aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+	struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
+
+	aesni_enc(ctx, dst, src);
+}
+
+static void __aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+	struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
+
+	aesni_dec(ctx, dst, src);
+}
+
+static struct crypto_alg __aesni_alg = {
+	.cra_name		= "__aes-aesni",
+	.cra_driver_name	= "__driver-aes-aesni",
+	.cra_priority		= 0,
+	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
+	.cra_alignmask		= 0,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(__aesni_alg.cra_list),
+	.cra_u	= {
+		.cipher	= {
+			.cia_min_keysize	= AES_MIN_KEY_SIZE,
+			.cia_max_keysize	= AES_MAX_KEY_SIZE,
+			.cia_setkey		= aes_set_key,
+			.cia_encrypt		= __aes_encrypt,
+			.cia_decrypt		= __aes_decrypt
+		}
+	}
+};
+
 static int ecb_encrypt(struct blkcipher_desc *desc,
 		       struct scatterlist *dst, struct scatterlist *src,
 		       unsigned int nbytes)
@@ -277,8 +328,16 @@
 			unsigned int key_len)
 {
 	struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+	struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base;
+	int err;
 
-	return crypto_ablkcipher_setkey(&ctx->cryptd_tfm->base, key, key_len);
+	crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+	crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm)
+				    & CRYPTO_TFM_REQ_MASK);
+	err = crypto_ablkcipher_setkey(child, key, key_len);
+	crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child)
+				    & CRYPTO_TFM_RES_MASK);
+	return err;
 }
 
 static int ablk_encrypt(struct ablkcipher_request *req)
@@ -411,6 +470,163 @@
 	},
 };
 
+#ifdef HAS_CTR
+static int ablk_ctr_init(struct crypto_tfm *tfm)
+{
+	struct cryptd_ablkcipher *cryptd_tfm;
+
+	cryptd_tfm = cryptd_alloc_ablkcipher("fpu(ctr(__driver-aes-aesni))",
+					     0, 0);
+	if (IS_ERR(cryptd_tfm))
+		return PTR_ERR(cryptd_tfm);
+	ablk_init_common(tfm, cryptd_tfm);
+	return 0;
+}
+
+static struct crypto_alg ablk_ctr_alg = {
+	.cra_name		= "ctr(aes)",
+	.cra_driver_name	= "ctr-aes-aesni",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct async_aes_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(ablk_ctr_alg.cra_list),
+	.cra_init		= ablk_ctr_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= AES_MIN_KEY_SIZE,
+			.max_keysize	= AES_MAX_KEY_SIZE,
+			.ivsize		= AES_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+			.geniv		= "chainiv",
+		},
+	},
+};
+#endif
+
+#ifdef HAS_LRW
+static int ablk_lrw_init(struct crypto_tfm *tfm)
+{
+	struct cryptd_ablkcipher *cryptd_tfm;
+
+	cryptd_tfm = cryptd_alloc_ablkcipher("fpu(lrw(__driver-aes-aesni))",
+					     0, 0);
+	if (IS_ERR(cryptd_tfm))
+		return PTR_ERR(cryptd_tfm);
+	ablk_init_common(tfm, cryptd_tfm);
+	return 0;
+}
+
+static struct crypto_alg ablk_lrw_alg = {
+	.cra_name		= "lrw(aes)",
+	.cra_driver_name	= "lrw-aes-aesni",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_aes_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(ablk_lrw_alg.cra_list),
+	.cra_init		= ablk_lrw_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= AES_MIN_KEY_SIZE + AES_BLOCK_SIZE,
+			.max_keysize	= AES_MAX_KEY_SIZE + AES_BLOCK_SIZE,
+			.ivsize		= AES_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+};
+#endif
+
+#ifdef HAS_PCBC
+static int ablk_pcbc_init(struct crypto_tfm *tfm)
+{
+	struct cryptd_ablkcipher *cryptd_tfm;
+
+	cryptd_tfm = cryptd_alloc_ablkcipher("fpu(pcbc(__driver-aes-aesni))",
+					     0, 0);
+	if (IS_ERR(cryptd_tfm))
+		return PTR_ERR(cryptd_tfm);
+	ablk_init_common(tfm, cryptd_tfm);
+	return 0;
+}
+
+static struct crypto_alg ablk_pcbc_alg = {
+	.cra_name		= "pcbc(aes)",
+	.cra_driver_name	= "pcbc-aes-aesni",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_aes_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(ablk_pcbc_alg.cra_list),
+	.cra_init		= ablk_pcbc_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= AES_MIN_KEY_SIZE,
+			.max_keysize	= AES_MAX_KEY_SIZE,
+			.ivsize		= AES_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+};
+#endif
+
+#ifdef HAS_XTS
+static int ablk_xts_init(struct crypto_tfm *tfm)
+{
+	struct cryptd_ablkcipher *cryptd_tfm;
+
+	cryptd_tfm = cryptd_alloc_ablkcipher("fpu(xts(__driver-aes-aesni))",
+					     0, 0);
+	if (IS_ERR(cryptd_tfm))
+		return PTR_ERR(cryptd_tfm);
+	ablk_init_common(tfm, cryptd_tfm);
+	return 0;
+}
+
+static struct crypto_alg ablk_xts_alg = {
+	.cra_name		= "xts(aes)",
+	.cra_driver_name	= "xts-aes-aesni",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct async_aes_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(ablk_xts_alg.cra_list),
+	.cra_init		= ablk_xts_init,
+	.cra_exit		= ablk_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.min_keysize	= 2 * AES_MIN_KEY_SIZE,
+			.max_keysize	= 2 * AES_MAX_KEY_SIZE,
+			.ivsize		= AES_BLOCK_SIZE,
+			.setkey		= ablk_set_key,
+			.encrypt	= ablk_encrypt,
+			.decrypt	= ablk_decrypt,
+		},
+	},
+};
+#endif
+
 static int __init aesni_init(void)
 {
 	int err;
@@ -421,6 +637,8 @@
 	}
 	if ((err = crypto_register_alg(&aesni_alg)))
 		goto aes_err;
+	if ((err = crypto_register_alg(&__aesni_alg)))
+		goto __aes_err;
 	if ((err = crypto_register_alg(&blk_ecb_alg)))
 		goto blk_ecb_err;
 	if ((err = crypto_register_alg(&blk_cbc_alg)))
@@ -429,9 +647,41 @@
 		goto ablk_ecb_err;
 	if ((err = crypto_register_alg(&ablk_cbc_alg)))
 		goto ablk_cbc_err;
+#ifdef HAS_CTR
+	if ((err = crypto_register_alg(&ablk_ctr_alg)))
+		goto ablk_ctr_err;
+#endif
+#ifdef HAS_LRW
+	if ((err = crypto_register_alg(&ablk_lrw_alg)))
+		goto ablk_lrw_err;
+#endif
+#ifdef HAS_PCBC
+	if ((err = crypto_register_alg(&ablk_pcbc_alg)))
+		goto ablk_pcbc_err;
+#endif
+#ifdef HAS_XTS
+	if ((err = crypto_register_alg(&ablk_xts_alg)))
+		goto ablk_xts_err;
+#endif
 
 	return err;
 
+#ifdef HAS_XTS
+ablk_xts_err:
+#endif
+#ifdef HAS_PCBC
+	crypto_unregister_alg(&ablk_pcbc_alg);
+ablk_pcbc_err:
+#endif
+#ifdef HAS_LRW
+	crypto_unregister_alg(&ablk_lrw_alg);
+ablk_lrw_err:
+#endif
+#ifdef HAS_CTR
+	crypto_unregister_alg(&ablk_ctr_alg);
+ablk_ctr_err:
+#endif
+	crypto_unregister_alg(&ablk_cbc_alg);
 ablk_cbc_err:
 	crypto_unregister_alg(&ablk_ecb_alg);
 ablk_ecb_err:
@@ -439,6 +689,8 @@
 blk_cbc_err:
 	crypto_unregister_alg(&blk_ecb_alg);
 blk_ecb_err:
+	crypto_unregister_alg(&__aesni_alg);
+__aes_err:
 	crypto_unregister_alg(&aesni_alg);
 aes_err:
 	return err;
@@ -446,10 +698,23 @@
 
 static void __exit aesni_exit(void)
 {
+#ifdef HAS_XTS
+	crypto_unregister_alg(&ablk_xts_alg);
+#endif
+#ifdef HAS_PCBC
+	crypto_unregister_alg(&ablk_pcbc_alg);
+#endif
+#ifdef HAS_LRW
+	crypto_unregister_alg(&ablk_lrw_alg);
+#endif
+#ifdef HAS_CTR
+	crypto_unregister_alg(&ablk_ctr_alg);
+#endif
 	crypto_unregister_alg(&ablk_cbc_alg);
 	crypto_unregister_alg(&ablk_ecb_alg);
 	crypto_unregister_alg(&blk_cbc_alg);
 	crypto_unregister_alg(&blk_ecb_alg);
+	crypto_unregister_alg(&__aesni_alg);
 	crypto_unregister_alg(&aesni_alg);
 }
 
diff --git a/arch/x86/crypto/fpu.c b/arch/x86/crypto/fpu.c
new file mode 100644
index 0000000..5f9781a
--- /dev/null
+++ b/arch/x86/crypto/fpu.c
@@ -0,0 +1,166 @@
+/*
+ * FPU: Wrapper for blkcipher touching fpu
+ *
+ * Copyright (c) Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.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 <crypto/algapi.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/i387.h>
+
+struct crypto_fpu_ctx {
+	struct crypto_blkcipher *child;
+};
+
+static int crypto_fpu_setkey(struct crypto_tfm *parent, const u8 *key,
+			     unsigned int keylen)
+{
+	struct crypto_fpu_ctx *ctx = crypto_tfm_ctx(parent);
+	struct crypto_blkcipher *child = ctx->child;
+	int err;
+
+	crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+	crypto_blkcipher_set_flags(child, crypto_tfm_get_flags(parent) &
+				   CRYPTO_TFM_REQ_MASK);
+	err = crypto_blkcipher_setkey(child, key, keylen);
+	crypto_tfm_set_flags(parent, crypto_blkcipher_get_flags(child) &
+				     CRYPTO_TFM_RES_MASK);
+	return err;
+}
+
+static int crypto_fpu_encrypt(struct blkcipher_desc *desc_in,
+			      struct scatterlist *dst, struct scatterlist *src,
+			      unsigned int nbytes)
+{
+	int err;
+	struct crypto_fpu_ctx *ctx = crypto_blkcipher_ctx(desc_in->tfm);
+	struct crypto_blkcipher *child = ctx->child;
+	struct blkcipher_desc desc = {
+		.tfm = child,
+		.info = desc_in->info,
+		.flags = desc_in->flags,
+	};
+
+	kernel_fpu_begin();
+	err = crypto_blkcipher_crt(desc.tfm)->encrypt(&desc, dst, src, nbytes);
+	kernel_fpu_end();
+	return err;
+}
+
+static int crypto_fpu_decrypt(struct blkcipher_desc *desc_in,
+			      struct scatterlist *dst, struct scatterlist *src,
+			      unsigned int nbytes)
+{
+	int err;
+	struct crypto_fpu_ctx *ctx = crypto_blkcipher_ctx(desc_in->tfm);
+	struct crypto_blkcipher *child = ctx->child;
+	struct blkcipher_desc desc = {
+		.tfm = child,
+		.info = desc_in->info,
+		.flags = desc_in->flags,
+	};
+
+	kernel_fpu_begin();
+	err = crypto_blkcipher_crt(desc.tfm)->decrypt(&desc, dst, src, nbytes);
+	kernel_fpu_end();
+	return err;
+}
+
+static int crypto_fpu_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
+	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
+	struct crypto_fpu_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_blkcipher *cipher;
+
+	cipher = crypto_spawn_blkcipher(spawn);
+	if (IS_ERR(cipher))
+		return PTR_ERR(cipher);
+
+	ctx->child = cipher;
+	return 0;
+}
+
+static void crypto_fpu_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_fpu_ctx *ctx = crypto_tfm_ctx(tfm);
+	crypto_free_blkcipher(ctx->child);
+}
+
+static struct crypto_instance *crypto_fpu_alloc(struct rtattr **tb)
+{
+	struct crypto_instance *inst;
+	struct crypto_alg *alg;
+	int err;
+
+	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+	if (err)
+		return ERR_PTR(err);
+
+	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER,
+				  CRYPTO_ALG_TYPE_MASK);
+	if (IS_ERR(alg))
+		return ERR_CAST(alg);
+
+	inst = crypto_alloc_instance("fpu", alg);
+	if (IS_ERR(inst))
+		goto out_put_alg;
+
+	inst->alg.cra_flags = alg->cra_flags;
+	inst->alg.cra_priority = alg->cra_priority;
+	inst->alg.cra_blocksize = alg->cra_blocksize;
+	inst->alg.cra_alignmask = alg->cra_alignmask;
+	inst->alg.cra_type = alg->cra_type;
+	inst->alg.cra_blkcipher.ivsize = alg->cra_blkcipher.ivsize;
+	inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
+	inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize;
+	inst->alg.cra_ctxsize = sizeof(struct crypto_fpu_ctx);
+	inst->alg.cra_init = crypto_fpu_init_tfm;
+	inst->alg.cra_exit = crypto_fpu_exit_tfm;
+	inst->alg.cra_blkcipher.setkey = crypto_fpu_setkey;
+	inst->alg.cra_blkcipher.encrypt = crypto_fpu_encrypt;
+	inst->alg.cra_blkcipher.decrypt = crypto_fpu_decrypt;
+
+out_put_alg:
+	crypto_mod_put(alg);
+	return inst;
+}
+
+static void crypto_fpu_free(struct crypto_instance *inst)
+{
+	crypto_drop_spawn(crypto_instance_ctx(inst));
+	kfree(inst);
+}
+
+static struct crypto_template crypto_fpu_tmpl = {
+	.name = "fpu",
+	.alloc = crypto_fpu_alloc,
+	.free = crypto_fpu_free,
+	.module = THIS_MODULE,
+};
+
+static int __init crypto_fpu_module_init(void)
+{
+	return crypto_register_template(&crypto_fpu_tmpl);
+}
+
+static void __exit crypto_fpu_module_exit(void)
+{
+	crypto_unregister_template(&crypto_fpu_tmpl);
+}
+
+module_init(crypto_fpu_module_init);
+module_exit(crypto_fpu_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FPU block cipher wrapper");
diff --git a/arch/x86/include/asm/atomic_32.h b/arch/x86/include/asm/atomic_32.h
index aff9f1f..8cb9c81 100644
--- a/arch/x86/include/asm/atomic_32.h
+++ b/arch/x86/include/asm/atomic_32.h
@@ -483,5 +483,5 @@
 	return old_val < 0;
 }
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* _ASM_X86_ATOMIC_32_H */
diff --git a/arch/x86/include/asm/atomic_64.h b/arch/x86/include/asm/atomic_64.h
index 8c21731..0d63602 100644
--- a/arch/x86/include/asm/atomic_64.h
+++ b/arch/x86/include/asm/atomic_64.h
@@ -455,5 +455,5 @@
 #define smp_mb__before_atomic_inc()	barrier()
 #define smp_mb__after_atomic_inc()	barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* _ASM_X86_ATOMIC_64_H */
diff --git a/arch/x86/include/asm/bitsperlong.h b/arch/x86/include/asm/bitsperlong.h
new file mode 100644
index 0000000..b0ae1c4
--- /dev/null
+++ b/arch/x86/include/asm/bitsperlong.h
@@ -0,0 +1,13 @@
+#ifndef __ASM_X86_BITSPERLONG_H
+#define __ASM_X86_BITSPERLONG_H
+
+#ifdef __x86_64__
+# define __BITS_PER_LONG 64
+#else
+# define __BITS_PER_LONG 32
+#endif
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_X86_BITSPERLONG_H */
+
diff --git a/arch/x86/include/asm/entry_arch.h b/arch/x86/include/asm/entry_arch.h
index d750a10..ff8cbfa 100644
--- a/arch/x86/include/asm/entry_arch.h
+++ b/arch/x86/include/asm/entry_arch.h
@@ -14,6 +14,7 @@
 BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
 BUILD_INTERRUPT(call_function_single_interrupt,CALL_FUNCTION_SINGLE_VECTOR)
 BUILD_INTERRUPT(irq_move_cleanup_interrupt,IRQ_MOVE_CLEANUP_VECTOR)
+BUILD_INTERRUPT(reboot_interrupt,REBOOT_VECTOR)
 
 BUILD_INTERRUPT3(invalidate_interrupt0,INVALIDATE_TLB_VECTOR_START+0,
 		 smp_invalidate_interrupt)
@@ -52,8 +53,16 @@
 BUILD_INTERRUPT(perf_pending_interrupt, LOCAL_PENDING_VECTOR)
 #endif
 
-#ifdef CONFIG_X86_MCE_P4THERMAL
+#ifdef CONFIG_X86_THERMAL_VECTOR
 BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR)
 #endif
 
+#ifdef CONFIG_X86_MCE_THRESHOLD
+BUILD_INTERRUPT(threshold_interrupt,THRESHOLD_APIC_VECTOR)
+#endif
+
+#ifdef CONFIG_X86_NEW_MCE
+BUILD_INTERRUPT(mce_self_interrupt,MCE_SELF_VECTOR)
+#endif
+
 #endif
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index 9ebc5c2..82e3e8f 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -22,7 +22,7 @@
 #endif
 #ifdef CONFIG_X86_MCE
 	unsigned int irq_thermal_count;
-# ifdef CONFIG_X86_64
+# ifdef CONFIG_X86_MCE_THRESHOLD
 	unsigned int irq_threshold_count;
 # endif
 #endif
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index 6df45f6..ba180d9 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -34,6 +34,7 @@
 extern void spurious_interrupt(void);
 extern void thermal_interrupt(void);
 extern void reschedule_interrupt(void);
+extern void mce_self_interrupt(void);
 
 extern void invalidate_interrupt(void);
 extern void invalidate_interrupt0(void);
@@ -46,6 +47,7 @@
 extern void invalidate_interrupt7(void);
 
 extern void irq_move_cleanup_interrupt(void);
+extern void reboot_interrupt(void);
 extern void threshold_interrupt(void);
 
 extern void call_function_interrupt(void);
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h
index e997be9..5b21f0e 100644
--- a/arch/x86/include/asm/irq_vectors.h
+++ b/arch/x86/include/asm/irq_vectors.h
@@ -25,6 +25,7 @@
  */
 
 #define NMI_VECTOR			0x02
+#define MCE_VECTOR			0x12
 
 /*
  * IDT vectors usable for external interrupt sources start
@@ -87,13 +88,8 @@
 #define CALL_FUNCTION_VECTOR		0xfc
 #define CALL_FUNCTION_SINGLE_VECTOR	0xfb
 #define THERMAL_APIC_VECTOR		0xfa
-
-#ifdef CONFIG_X86_32
-/* 0xf8 - 0xf9 : free */
-#else
-# define THRESHOLD_APIC_VECTOR		0xf9
-# define UV_BAU_MESSAGE			0xf8
-#endif
+#define THRESHOLD_APIC_VECTOR		0xf9
+#define REBOOT_VECTOR			0xf8
 
 /* f0-f7 used for spreading out TLB flushes: */
 #define INVALIDATE_TLB_VECTOR_END	0xf7
@@ -117,6 +113,13 @@
  */
 #define LOCAL_PENDING_VECTOR		0xec
 
+#define UV_BAU_MESSAGE			0xec
+
+/*
+ * Self IPI vector for machine checks
+ */
+#define MCE_SELF_VECTOR			0xeb
+
 /*
  * First APIC vector available to drivers: (vectors 0x30-0xee) we
  * start at 0x31(0x41) to spread out vectors evenly between priority
diff --git a/arch/x86/include/asm/lguest.h b/arch/x86/include/asm/lguest.h
index 1caf576..313389c 100644
--- a/arch/x86/include/asm/lguest.h
+++ b/arch/x86/include/asm/lguest.h
@@ -17,8 +17,13 @@
 /* Pages for switcher itself, then two pages per cpu */
 #define TOTAL_SWITCHER_PAGES (SHARED_SWITCHER_PAGES + 2 * nr_cpu_ids)
 
-/* We map at -4M for ease of mapping into the guest (one PTE page). */
+/* We map at -4M (-2M when PAE is activated) for ease of mapping
+ * into the guest (one PTE page). */
+#ifdef CONFIG_X86_PAE
+#define SWITCHER_ADDR 0xFFE00000
+#else
 #define SWITCHER_ADDR 0xFFC00000
+#endif
 
 /* Found in switcher.S */
 extern unsigned long default_idt_entries[];
diff --git a/arch/x86/include/asm/lguest_hcall.h b/arch/x86/include/asm/lguest_hcall.h
index faae199..d31c4a6 100644
--- a/arch/x86/include/asm/lguest_hcall.h
+++ b/arch/x86/include/asm/lguest_hcall.h
@@ -12,11 +12,13 @@
 #define LHCALL_TS		8
 #define LHCALL_SET_CLOCKEVENT	9
 #define LHCALL_HALT		10
+#define LHCALL_SET_PMD		13
 #define LHCALL_SET_PTE		14
-#define LHCALL_SET_PMD		15
+#define LHCALL_SET_PGD		15
 #define LHCALL_LOAD_TLS		16
 #define LHCALL_NOTIFY		17
 #define LHCALL_LOAD_GDT_ENTRY	18
+#define LHCALL_SEND_INTERRUPTS	19
 
 #define LGUEST_TRAP_ENTRY 0x1F
 
@@ -32,10 +34,10 @@
  * operations?  There are two ways: the direct way is to make a "hypercall",
  * to make requests of the Host Itself.
  *
- * We use the KVM hypercall mechanism. Eighteen hypercalls are
+ * We use the KVM hypercall mechanism. Seventeen hypercalls are
  * available: the hypercall number is put in the %eax register, and the
- * arguments (when required) are placed in %ebx, %ecx and %edx.  If a return
- * value makes sense, it's returned in %eax.
+ * arguments (when required) are placed in %ebx, %ecx, %edx and %esi.
+ * If a return value makes sense, it's returned in %eax.
  *
  * Grossly invalid calls result in Sudden Death at the hands of the vengeful
  * Host, rather than returning failure.  This reflects Winston Churchill's
@@ -47,8 +49,9 @@
 
 #define LHCALL_RING_SIZE 64
 struct hcall_args {
-	/* These map directly onto eax, ebx, ecx, edx in struct lguest_regs */
-	unsigned long arg0, arg1, arg2, arg3;
+	/* These map directly onto eax, ebx, ecx, edx and esi
+	 * in struct lguest_regs */
+	unsigned long arg0, arg1, arg2, arg3, arg4;
 };
 
 #endif /* !__ASSEMBLY__ */
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index 4f8c199..540a466 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -1,8 +1,6 @@
 #ifndef _ASM_X86_MCE_H
 #define _ASM_X86_MCE_H
 
-#ifdef __x86_64__
-
 #include <linux/types.h>
 #include <asm/ioctls.h>
 
@@ -10,21 +8,35 @@
  * Machine Check support for x86
  */
 
-#define MCG_CTL_P	 (1UL<<8)   /* MCG_CAP register available */
-#define MCG_EXT_P	 (1ULL<<9)   /* Extended registers available */
-#define MCG_CMCI_P	 (1ULL<<10)  /* CMCI supported */
+#define MCG_BANKCNT_MASK	0xff         /* Number of Banks */
+#define MCG_CTL_P		(1ULL<<8)    /* MCG_CAP register available */
+#define MCG_EXT_P		(1ULL<<9)    /* Extended registers available */
+#define MCG_CMCI_P		(1ULL<<10)   /* CMCI supported */
+#define MCG_EXT_CNT_MASK	0xff0000     /* Number of Extended registers */
+#define MCG_EXT_CNT_SHIFT	16
+#define MCG_EXT_CNT(c)		(((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT)
+#define MCG_SER_P	 	(1ULL<<24)   /* MCA recovery/new status bits */
 
-#define MCG_STATUS_RIPV  (1UL<<0)   /* restart ip valid */
-#define MCG_STATUS_EIPV  (1UL<<1)   /* ip points to correct instruction */
-#define MCG_STATUS_MCIP  (1UL<<2)   /* machine check in progress */
+#define MCG_STATUS_RIPV  (1ULL<<0)   /* restart ip valid */
+#define MCG_STATUS_EIPV  (1ULL<<1)   /* ip points to correct instruction */
+#define MCG_STATUS_MCIP  (1ULL<<2)   /* machine check in progress */
 
-#define MCI_STATUS_VAL   (1UL<<63)  /* valid error */
-#define MCI_STATUS_OVER  (1UL<<62)  /* previous errors lost */
-#define MCI_STATUS_UC    (1UL<<61)  /* uncorrected error */
-#define MCI_STATUS_EN    (1UL<<60)  /* error enabled */
-#define MCI_STATUS_MISCV (1UL<<59)  /* misc error reg. valid */
-#define MCI_STATUS_ADDRV (1UL<<58)  /* addr reg. valid */
-#define MCI_STATUS_PCC   (1UL<<57)  /* processor context corrupt */
+#define MCI_STATUS_VAL   (1ULL<<63)  /* valid error */
+#define MCI_STATUS_OVER  (1ULL<<62)  /* previous errors lost */
+#define MCI_STATUS_UC    (1ULL<<61)  /* uncorrected error */
+#define MCI_STATUS_EN    (1ULL<<60)  /* error enabled */
+#define MCI_STATUS_MISCV (1ULL<<59)  /* misc error reg. valid */
+#define MCI_STATUS_ADDRV (1ULL<<58)  /* addr reg. valid */
+#define MCI_STATUS_PCC   (1ULL<<57)  /* processor context corrupt */
+#define MCI_STATUS_S	 (1ULL<<56)  /* Signaled machine check */
+#define MCI_STATUS_AR	 (1ULL<<55)  /* Action required */
+
+/* MISC register defines */
+#define MCM_ADDR_SEGOFF  0	/* segment offset */
+#define MCM_ADDR_LINEAR  1	/* linear address */
+#define MCM_ADDR_PHYS	 2	/* physical address */
+#define MCM_ADDR_MEM	 3	/* memory address */
+#define MCM_ADDR_GENERIC 7	/* generic */
 
 /* Fields are zero when not available */
 struct mce {
@@ -34,13 +46,19 @@
 	__u64 mcgstatus;
 	__u64 ip;
 	__u64 tsc;	/* cpu time stamp counter */
-	__u64 res1;	/* for future extension */
-	__u64 res2;	/* dito. */
+	__u64 time;	/* wall time_t when error was detected */
+	__u8  cpuvendor;	/* cpu vendor as encoded in system.h */
+	__u8  pad1;
+	__u16 pad2;
+	__u32 cpuid;	/* CPUID 1 EAX */
 	__u8  cs;		/* code segment */
 	__u8  bank;	/* machine check bank */
-	__u8  cpu;	/* cpu that raised the error */
+	__u8  cpu;	/* cpu number; obsolete; use extcpu now */
 	__u8  finished;   /* entry is valid */
-	__u32 pad;
+	__u32 extcpu;	/* linux cpu number that detected the error */
+	__u32 socketid;	/* CPU socket ID */
+	__u32 apicid;	/* CPU initial apic ID */
+	__u64 mcgcap;	/* MCGCAP MSR: machine check capabilities of CPU */
 };
 
 /*
@@ -57,7 +75,7 @@
 	unsigned len;	    /* = MCE_LOG_LEN */
 	unsigned next;
 	unsigned flags;
-	unsigned pad0;
+	unsigned recordlen;	/* length of struct mce */
 	struct mce entry[MCE_LOG_LEN];
 };
 
@@ -82,19 +100,16 @@
 #define K8_MCE_THRESHOLD_BANK_5    (MCE_THRESHOLD_BASE + 5 * 9)
 #define K8_MCE_THRESHOLD_DRAM_ECC  (MCE_THRESHOLD_BANK_4 + 0)
 
-#endif /* __x86_64__ */
-
 #ifdef __KERNEL__
 
-#ifdef CONFIG_X86_32
 extern int mce_disabled;
-#else /* CONFIG_X86_32 */
 
 #include <asm/atomic.h>
+#include <linux/percpu.h>
 
 void mce_setup(struct mce *m);
 void mce_log(struct mce *m);
-DECLARE_PER_CPU(struct sys_device, device_mce);
+DECLARE_PER_CPU(struct sys_device, mce_dev);
 extern void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu);
 
 /*
@@ -104,6 +119,8 @@
 #define MAX_NR_BANKS (MCE_EXTENDED_BANK - 1)
 
 #ifdef CONFIG_X86_MCE_INTEL
+extern int mce_cmci_disabled;
+extern int mce_ignore_ce;
 void mce_intel_feature_init(struct cpuinfo_x86 *c);
 void cmci_clear(void);
 void cmci_reenable(void);
@@ -123,13 +140,16 @@
 static inline void mce_amd_feature_init(struct cpuinfo_x86 *c) { }
 #endif
 
-extern int mce_available(struct cpuinfo_x86 *c);
+int mce_available(struct cpuinfo_x86 *c);
+
+DECLARE_PER_CPU(unsigned, mce_exception_count);
+DECLARE_PER_CPU(unsigned, mce_poll_count);
 
 void mce_log_therm_throt_event(__u64 status);
 
 extern atomic_t mce_entry;
 
-extern void do_machine_check(struct pt_regs *, long);
+void do_machine_check(struct pt_regs *, long);
 
 typedef DECLARE_BITMAP(mce_banks_t, MAX_NR_BANKS);
 DECLARE_PER_CPU(mce_banks_t, mce_poll_banks);
@@ -139,14 +159,16 @@
 	MCP_UC = (1 << 1),		/* log uncorrected errors */
 	MCP_DONTLOG = (1 << 2),		/* only clear, don't log */
 };
-extern void machine_check_poll(enum mcp_flags flags, mce_banks_t *b);
+void machine_check_poll(enum mcp_flags flags, mce_banks_t *b);
 
-extern int mce_notify_user(void);
+int mce_notify_irq(void);
+void mce_notify_process(void);
 
-#endif /* !CONFIG_X86_32 */
+DECLARE_PER_CPU(struct mce, injectm);
+extern struct file_operations mce_chrdev_ops;
 
 #ifdef CONFIG_X86_MCE
-extern void mcheck_init(struct cpuinfo_x86 *c);
+void mcheck_init(struct cpuinfo_x86 *c);
 #else
 #define mcheck_init(c) do { } while (0)
 #endif
diff --git a/arch/x86/include/asm/mman.h b/arch/x86/include/asm/mman.h
index 90bc410..751af25 100644
--- a/arch/x86/include/asm/mman.h
+++ b/arch/x86/include/asm/mman.h
@@ -1,7 +1,7 @@
 #ifndef _ASM_X86_MMAN_H
 #define _ASM_X86_MMAN_H
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_32BIT	0x40		/* only give out 32bit addresses */
 
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 4d58d04..1692fb5 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -207,7 +207,14 @@
 
 #define MSR_IA32_THERM_CONTROL		0x0000019a
 #define MSR_IA32_THERM_INTERRUPT	0x0000019b
+
+#define THERM_INT_LOW_ENABLE		(1 << 0)
+#define THERM_INT_HIGH_ENABLE		(1 << 1)
+
 #define MSR_IA32_THERM_STATUS		0x0000019c
+
+#define THERM_STATUS_PROCHOT		(1 << 0)
+
 #define MSR_IA32_MISC_ENABLE		0x000001a0
 
 /* MISC_ENABLE bits: architectural */
diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h
index 89ed9d7..625c3f0 100644
--- a/arch/x86/include/asm/page.h
+++ b/arch/x86/include/asm/page.h
@@ -56,7 +56,7 @@
 #endif	/* __ASSEMBLY__ */
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #define __HAVE_ARCH_GATE_AREA 1
 
diff --git a/arch/x86/include/asm/pgtable_32_types.h b/arch/x86/include/asm/pgtable_32_types.h
index 2733fad..5e67c15 100644
--- a/arch/x86/include/asm/pgtable_32_types.h
+++ b/arch/x86/include/asm/pgtable_32_types.h
@@ -46,6 +46,10 @@
 # define VMALLOC_END	(FIXADDR_START - 2 * PAGE_SIZE)
 #endif
 
+#define MODULES_VADDR	VMALLOC_START
+#define MODULES_END	VMALLOC_END
+#define MODULES_LEN	(MODULES_VADDR - MODULES_END)
+
 #define MAXMEM	(VMALLOC_END - PAGE_OFFSET - __VMALLOC_RESERVE)
 
 #endif /* _ASM_X86_PGTABLE_32_DEFS_H */
diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h
index 7761a5d..598457c 100644
--- a/arch/x86/include/asm/signal.h
+++ b/arch/x86/include/asm/signal.h
@@ -117,7 +117,7 @@
 #define MINSIGSTKSZ	2048
 #define SIGSTKSZ	8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
index a5ecc9c..7f3eba0 100644
--- a/arch/x86/include/asm/tlbflush.h
+++ b/arch/x86/include/asm/tlbflush.h
@@ -172,6 +172,6 @@
 	flush_tlb_all();
 }
 
-extern void zap_low_mappings(void);
+extern void zap_low_mappings(bool early);
 
 #endif /* _ASM_X86_TLBFLUSH_H */
diff --git a/arch/x86/include/asm/types.h b/arch/x86/include/asm/types.h
index e6f7363..09b9774 100644
--- a/arch/x86/include/asm/types.h
+++ b/arch/x86/include/asm/types.h
@@ -14,12 +14,6 @@
  */
 #ifdef __KERNEL__
 
-#ifdef CONFIG_X86_32
-# define BITS_PER_LONG 32
-#else
-# define BITS_PER_LONG 64
-#endif
-
 #ifndef __ASSEMBLY__
 
 typedef u64 dma64_addr_t;
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 4f78bd6..f3477bb 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -73,7 +73,7 @@
 obj-$(CONFIG_KEXEC)		+= relocate_kernel_$(BITS).o crash.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump_$(BITS).o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
-obj-$(CONFIG_MODULES)		+= module_$(BITS).o
+obj-$(CONFIG_MODULES)		+= module.o
 obj-$(CONFIG_EFI) 		+= efi.o efi_$(BITS).o efi_stub_$(BITS).o
 obj-$(CONFIG_DOUBLEFAULT) 	+= doublefault_32.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 7c243a2..ca93638 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -104,7 +104,7 @@
 	initial_gs = per_cpu_offset(smp_processor_id());
 #endif
 	initial_code = (unsigned long)wakeup_long64;
-	saved_magic = 0x123456789abcdef0;
+       saved_magic = 0x123456789abcdef0L;
 #endif /* CONFIG_64BIT */
 
 	return 0;
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 076d388..8c7c042 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -899,7 +899,7 @@
 	}
 
 	/* lets not touch this if we didn't frob it */
-#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
+#ifdef CONFIG_X86_THERMAL_VECTOR
 	if (maxlvt >= 5) {
 		v = apic_read(APIC_LVTTHMR);
 		apic_write(APIC_LVTTHMR, v | APIC_LVT_MASKED);
@@ -2017,7 +2017,7 @@
 	apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR);
 	apic_pm_state.apic_tmict = apic_read(APIC_TMICT);
 	apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
-#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
+#ifdef CONFIG_X86_THERMAL_VECTOR
 	if (maxlvt >= 5)
 		apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
 #endif
diff --git a/arch/x86/kernel/apic/nmi.c b/arch/x86/kernel/apic/nmi.c
index a691302..b3025b4 100644
--- a/arch/x86/kernel/apic/nmi.c
+++ b/arch/x86/kernel/apic/nmi.c
@@ -66,7 +66,7 @@
 
 static inline int mce_in_progress(void)
 {
-#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
+#if defined(CONFIG_X86_NEW_MCE)
 	return atomic_read(&mce_entry) > 0;
 #endif
 	return 0;
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index 49e0939..79302e9 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -1233,9 +1233,9 @@
 	int err;
 	struct apm_user	*as;
 
-	device_suspend(PMSG_SUSPEND);
+	dpm_suspend_start(PMSG_SUSPEND);
 
-	device_power_down(PMSG_SUSPEND);
+	dpm_suspend_noirq(PMSG_SUSPEND);
 
 	local_irq_disable();
 	sysdev_suspend(PMSG_SUSPEND);
@@ -1259,9 +1259,9 @@
 	sysdev_resume();
 	local_irq_enable();
 
-	device_power_up(PMSG_RESUME);
+	dpm_resume_noirq(PMSG_RESUME);
 
-	device_resume(PMSG_RESUME);
+	dpm_resume_end(PMSG_RESUME);
 	queue_event(APM_NORMAL_RESUME, NULL);
 	spin_lock(&user_list_lock);
 	for (as = user_list; as != NULL; as = as->next) {
@@ -1277,7 +1277,7 @@
 {
 	int err;
 
-	device_power_down(PMSG_SUSPEND);
+	dpm_suspend_noirq(PMSG_SUSPEND);
 
 	local_irq_disable();
 	sysdev_suspend(PMSG_SUSPEND);
@@ -1291,7 +1291,7 @@
 	sysdev_resume();
 	local_irq_enable();
 
-	device_power_up(PMSG_RESUME);
+	dpm_resume_noirq(PMSG_RESUME);
 }
 
 static apm_event_t get_event(void)
@@ -1376,7 +1376,7 @@
 			ignore_bounce = 1;
 			if ((event != APM_NORMAL_RESUME)
 			    || (ignore_normal_resume == 0)) {
-				device_resume(PMSG_RESUME);
+				dpm_resume_end(PMSG_RESUME);
 				queue_event(event, NULL);
 			}
 			ignore_normal_resume = 0;
diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c
index 1a830cb..dfdbf64 100644
--- a/arch/x86/kernel/asm-offsets_32.c
+++ b/arch/x86/kernel/asm-offsets_32.c
@@ -126,6 +126,7 @@
 #if defined(CONFIG_LGUEST) || defined(CONFIG_LGUEST_GUEST) || defined(CONFIG_LGUEST_MODULE)
 	BLANK();
 	OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled);
+	OFFSET(LGUEST_DATA_irq_pending, lguest_data, irq_pending);
 	OFFSET(LGUEST_DATA_pgdir, lguest_data, pgdir);
 
 	BLANK();
diff --git a/arch/x86/kernel/cpu/mcheck/Makefile b/arch/x86/kernel/cpu/mcheck/Makefile
index b2f8982..45004fa 100644
--- a/arch/x86/kernel/cpu/mcheck/Makefile
+++ b/arch/x86/kernel/cpu/mcheck/Makefile
@@ -1,7 +1,11 @@
-obj-y				=  mce_$(BITS).o therm_throt.o
+obj-y				=  mce.o therm_throt.o
 
-obj-$(CONFIG_X86_32)		+= k7.o p4.o p5.o p6.o winchip.o
-obj-$(CONFIG_X86_MCE_INTEL)	+= mce_intel_64.o
+obj-$(CONFIG_X86_NEW_MCE)	+= mce-severity.o
+obj-$(CONFIG_X86_OLD_MCE)	+= k7.o p4.o p6.o
+obj-$(CONFIG_X86_ANCIENT_MCE)	+= winchip.o p5.o
+obj-$(CONFIG_X86_MCE_P4THERMAL)	+= mce_intel.o
+obj-$(CONFIG_X86_MCE_INTEL)	+= mce_intel_64.o mce_intel.o
 obj-$(CONFIG_X86_MCE_AMD)	+= mce_amd_64.o
 obj-$(CONFIG_X86_MCE_NONFATAL)	+= non-fatal.o
 obj-$(CONFIG_X86_MCE_THRESHOLD) += threshold.o
+obj-$(CONFIG_X86_MCE_INJECT)	+= mce-inject.o
diff --git a/arch/x86/kernel/cpu/mcheck/k7.c b/arch/x86/kernel/cpu/mcheck/k7.c
index dd3af6e..89e5104 100644
--- a/arch/x86/kernel/cpu/mcheck/k7.c
+++ b/arch/x86/kernel/cpu/mcheck/k7.c
@@ -2,11 +2,10 @@
  * Athlon specific Machine Check Exception Reporting
  * (C) Copyright 2002 Dave Jones <davej@redhat.com>
  */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
 #include <linux/smp.h>
 
 #include <asm/processor.h>
@@ -15,12 +14,12 @@
 
 #include "mce.h"
 
-/* Machine Check Handler For AMD Athlon/Duron */
+/* Machine Check Handler For AMD Athlon/Duron: */
 static void k7_machine_check(struct pt_regs *regs, long error_code)
 {
-	int recover = 1;
 	u32 alow, ahigh, high, low;
 	u32 mcgstl, mcgsth;
+	int recover = 1;
 	int i;
 
 	rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
@@ -32,15 +31,19 @@
 
 	for (i = 1; i < nr_mce_banks; i++) {
 		rdmsr(MSR_IA32_MC0_STATUS+i*4, low, high);
-		if (high&(1<<31)) {
+		if (high & (1<<31)) {
 			char misc[20];
 			char addr[24];
-			misc[0] = addr[0] = '\0';
+
+			misc[0] = '\0';
+			addr[0] = '\0';
+
 			if (high & (1<<29))
 				recover |= 1;
 			if (high & (1<<25))
 				recover |= 2;
 			high &= ~(1<<31);
+
 			if (high & (1<<27)) {
 				rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh);
 				snprintf(misc, 20, "[%08x%08x]", ahigh, alow);
@@ -49,27 +52,31 @@
 				rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
 				snprintf(addr, 24, " at %08x%08x", ahigh, alow);
 			}
+
 			printk(KERN_EMERG "CPU %d: Bank %d: %08x%08x%s%s\n",
 				smp_processor_id(), i, high, low, misc, addr);
-			/* Clear it */
+
+			/* Clear it: */
 			wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
-			/* Serialize */
+			/* Serialize: */
 			wmb();
 			add_taint(TAINT_MACHINE_CHECK);
 		}
 	}
 
-	if (recover&2)
+	if (recover & 2)
 		panic("CPU context corrupt");
-	if (recover&1)
+	if (recover & 1)
 		panic("Unable to continue");
+
 	printk(KERN_EMERG "Attempting to continue.\n");
+
 	mcgstl &= ~(1<<2);
 	wrmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
 }
 
 
-/* AMD K7 machine check is Intel like */
+/* AMD K7 machine check is Intel like: */
 void amd_mcheck_init(struct cpuinfo_x86 *c)
 {
 	u32 l, h;
@@ -79,21 +86,26 @@
 		return;
 
 	machine_check_vector = k7_machine_check;
+	/* Make sure the vector pointer is visible before we enable MCEs: */
 	wmb();
 
 	printk(KERN_INFO "Intel machine check architecture supported.\n");
+
 	rdmsr(MSR_IA32_MCG_CAP, l, h);
 	if (l & (1<<8))	/* Control register present ? */
 		wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
 	nr_mce_banks = l & 0xff;
 
-	/* Clear status for MC index 0 separately, we don't touch CTL,
-	 * as some K7 Athlons cause spurious MCEs when its enabled. */
+	/*
+	 * Clear status for MC index 0 separately, we don't touch CTL,
+	 * as some K7 Athlons cause spurious MCEs when its enabled:
+	 */
 	if (boot_cpu_data.x86 == 6) {
 		wrmsr(MSR_IA32_MC0_STATUS, 0x0, 0x0);
 		i = 1;
 	} else
 		i = 0;
+
 	for (; i < nr_mce_banks; i++) {
 		wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
 		wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
diff --git a/arch/x86/kernel/cpu/mcheck/mce-inject.c b/arch/x86/kernel/cpu/mcheck/mce-inject.c
new file mode 100644
index 0000000..a3a235a
--- /dev/null
+++ b/arch/x86/kernel/cpu/mcheck/mce-inject.c
@@ -0,0 +1,127 @@
+/*
+ * Machine check injection support.
+ * Copyright 2008 Intel 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.
+ *
+ * Authors:
+ * Andi Kleen
+ * Ying Huang
+ */
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/smp.h>
+#include <asm/mce.h>
+
+/* Update fake mce registers on current CPU. */
+static void inject_mce(struct mce *m)
+{
+	struct mce *i = &per_cpu(injectm, m->extcpu);
+
+	/* Make sure noone reads partially written injectm */
+	i->finished = 0;
+	mb();
+	m->finished = 0;
+	/* First set the fields after finished */
+	i->extcpu = m->extcpu;
+	mb();
+	/* Now write record in order, finished last (except above) */
+	memcpy(i, m, sizeof(struct mce));
+	/* Finally activate it */
+	mb();
+	i->finished = 1;
+}
+
+struct delayed_mce {
+	struct timer_list timer;
+	struct mce m;
+};
+
+/* Inject mce on current CPU */
+static void raise_mce(unsigned long data)
+{
+	struct delayed_mce *dm = (struct delayed_mce *)data;
+	struct mce *m = &dm->m;
+	int cpu = m->extcpu;
+
+	inject_mce(m);
+	if (m->status & MCI_STATUS_UC) {
+		struct pt_regs regs;
+		memset(&regs, 0, sizeof(struct pt_regs));
+		regs.ip = m->ip;
+		regs.cs = m->cs;
+		printk(KERN_INFO "Triggering MCE exception on CPU %d\n", cpu);
+		do_machine_check(&regs, 0);
+		printk(KERN_INFO "MCE exception done on CPU %d\n", cpu);
+	} else {
+		mce_banks_t b;
+		memset(&b, 0xff, sizeof(mce_banks_t));
+		printk(KERN_INFO "Starting machine check poll CPU %d\n", cpu);
+		machine_check_poll(0, &b);
+		mce_notify_irq();
+		printk(KERN_INFO "Finished machine check poll on CPU %d\n",
+		       cpu);
+	}
+	kfree(dm);
+}
+
+/* Error injection interface */
+static ssize_t mce_write(struct file *filp, const char __user *ubuf,
+			 size_t usize, loff_t *off)
+{
+	struct delayed_mce *dm;
+	struct mce m;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	/*
+	 * There are some cases where real MSR reads could slip
+	 * through.
+	 */
+	if (!boot_cpu_has(X86_FEATURE_MCE) || !boot_cpu_has(X86_FEATURE_MCA))
+		return -EIO;
+
+	if ((unsigned long)usize > sizeof(struct mce))
+		usize = sizeof(struct mce);
+	if (copy_from_user(&m, ubuf, usize))
+		return -EFAULT;
+
+	if (m.extcpu >= num_possible_cpus() || !cpu_online(m.extcpu))
+		return -EINVAL;
+
+	dm = kmalloc(sizeof(struct delayed_mce), GFP_KERNEL);
+	if (!dm)
+		return -ENOMEM;
+
+	/*
+	 * Need to give user space some time to set everything up,
+	 * so do it a jiffie or two later everywhere.
+	 * Should we use a hrtimer here for better synchronization?
+	 */
+	memcpy(&dm->m, &m, sizeof(struct mce));
+	setup_timer(&dm->timer, raise_mce, (unsigned long)dm);
+	dm->timer.expires = jiffies + 2;
+	add_timer_on(&dm->timer, m.extcpu);
+	return usize;
+}
+
+static int inject_init(void)
+{
+	printk(KERN_INFO "Machine check injector initialized\n");
+	mce_chrdev_ops.write = mce_write;
+	return 0;
+}
+
+module_init(inject_init);
+/*
+ * Cannot tolerate unloading currently because we cannot
+ * guarantee all openers of mce_chrdev will get a reference to us.
+ */
+MODULE_LICENSE("GPL");
diff --git a/arch/x86/kernel/cpu/mcheck/mce-internal.h b/arch/x86/kernel/cpu/mcheck/mce-internal.h
new file mode 100644
index 0000000..54dcb8f
--- /dev/null
+++ b/arch/x86/kernel/cpu/mcheck/mce-internal.h
@@ -0,0 +1,15 @@
+#include <asm/mce.h>
+
+enum severity_level {
+	MCE_NO_SEVERITY,
+	MCE_KEEP_SEVERITY,
+	MCE_SOME_SEVERITY,
+	MCE_AO_SEVERITY,
+	MCE_UC_SEVERITY,
+	MCE_AR_SEVERITY,
+	MCE_PANIC_SEVERITY,
+};
+
+int mce_severity(struct mce *a, int tolerant, char **msg);
+
+extern int mce_ser;
diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c
new file mode 100644
index 0000000..ff0807f
--- /dev/null
+++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c
@@ -0,0 +1,218 @@
+/*
+ * MCE grading rules.
+ * Copyright 2008, 2009 Intel 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.
+ *
+ * Author: Andi Kleen
+ */
+#include <linux/kernel.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <asm/mce.h>
+
+#include "mce-internal.h"
+
+/*
+ * Grade an mce by severity. In general the most severe ones are processed
+ * first. Since there are quite a lot of combinations test the bits in a
+ * table-driven way. The rules are simply processed in order, first
+ * match wins.
+ *
+ * Note this is only used for machine check exceptions, the corrected
+ * errors use much simpler rules. The exceptions still check for the corrected
+ * errors, but only to leave them alone for the CMCI handler (except for
+ * panic situations)
+ */
+
+enum context { IN_KERNEL = 1, IN_USER = 2 };
+enum ser { SER_REQUIRED = 1, NO_SER = 2 };
+
+static struct severity {
+	u64 mask;
+	u64 result;
+	unsigned char sev;
+	unsigned char mcgmask;
+	unsigned char mcgres;
+	unsigned char ser;
+	unsigned char context;
+	unsigned char covered;
+	char *msg;
+} severities[] = {
+#define KERNEL .context = IN_KERNEL
+#define USER .context = IN_USER
+#define SER .ser = SER_REQUIRED
+#define NOSER .ser = NO_SER
+#define SEV(s) .sev = MCE_ ## s ## _SEVERITY
+#define BITCLR(x, s, m, r...) { .mask = x, .result = 0, SEV(s), .msg = m, ## r }
+#define BITSET(x, s, m, r...) { .mask = x, .result = x, SEV(s), .msg = m, ## r }
+#define MCGMASK(x, res, s, m, r...) \
+	{ .mcgmask = x, .mcgres = res, SEV(s), .msg = m, ## r }
+#define MASK(x, y, s, m, r...) \
+	{ .mask = x, .result = y, SEV(s), .msg = m, ## r }
+#define MCI_UC_S (MCI_STATUS_UC|MCI_STATUS_S)
+#define MCI_UC_SAR (MCI_STATUS_UC|MCI_STATUS_S|MCI_STATUS_AR)
+#define MCACOD 0xffff
+
+	BITCLR(MCI_STATUS_VAL, NO, "Invalid"),
+	BITCLR(MCI_STATUS_EN, NO, "Not enabled"),
+	BITSET(MCI_STATUS_PCC, PANIC, "Processor context corrupt"),
+	/* When MCIP is not set something is very confused */
+	MCGMASK(MCG_STATUS_MCIP, 0, PANIC, "MCIP not set in MCA handler"),
+	/* Neither return not error IP -- no chance to recover -> PANIC */
+	MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, 0, PANIC,
+		"Neither restart nor error IP"),
+	MCGMASK(MCG_STATUS_RIPV, 0, PANIC, "In kernel and no restart IP",
+		KERNEL),
+	BITCLR(MCI_STATUS_UC, KEEP, "Corrected error", NOSER),
+	MASK(MCI_STATUS_OVER|MCI_STATUS_UC|MCI_STATUS_EN, MCI_STATUS_UC, SOME,
+	     "Spurious not enabled", SER),
+
+	/* ignore OVER for UCNA */
+	MASK(MCI_UC_SAR, MCI_STATUS_UC, KEEP,
+	     "Uncorrected no action required", SER),
+	MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_UC|MCI_STATUS_AR, PANIC,
+	     "Illegal combination (UCNA with AR=1)", SER),
+	MASK(MCI_STATUS_S, 0, KEEP, "Non signalled machine check", SER),
+
+	/* AR add known MCACODs here */
+	MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_OVER|MCI_UC_SAR, PANIC,
+	     "Action required with lost events", SER),
+	MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCACOD, MCI_UC_SAR, PANIC,
+	     "Action required; unknown MCACOD", SER),
+
+	/* known AO MCACODs: */
+	MASK(MCI_UC_SAR|MCI_STATUS_OVER|0xfff0, MCI_UC_S|0xc0, AO,
+	     "Action optional: memory scrubbing error", SER),
+	MASK(MCI_UC_SAR|MCI_STATUS_OVER|MCACOD, MCI_UC_S|0x17a, AO,
+	     "Action optional: last level cache writeback error", SER),
+
+	MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_S, SOME,
+	     "Action optional unknown MCACOD", SER),
+	MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_S|MCI_STATUS_OVER, SOME,
+	     "Action optional with lost events", SER),
+	BITSET(MCI_STATUS_UC|MCI_STATUS_OVER, PANIC, "Overflowed uncorrected"),
+	BITSET(MCI_STATUS_UC, UC, "Uncorrected"),
+	BITSET(0, SOME, "No match")	/* always matches. keep at end */
+};
+
+/*
+ * If the EIPV bit is set, it means the saved IP is the
+ * instruction which caused the MCE.
+ */
+static int error_context(struct mce *m)
+{
+	if (m->mcgstatus & MCG_STATUS_EIPV)
+		return (m->ip && (m->cs & 3) == 3) ? IN_USER : IN_KERNEL;
+	/* Unknown, assume kernel */
+	return IN_KERNEL;
+}
+
+int mce_severity(struct mce *a, int tolerant, char **msg)
+{
+	enum context ctx = error_context(a);
+	struct severity *s;
+
+	for (s = severities;; s++) {
+		if ((a->status & s->mask) != s->result)
+			continue;
+		if ((a->mcgstatus & s->mcgmask) != s->mcgres)
+			continue;
+		if (s->ser == SER_REQUIRED && !mce_ser)
+			continue;
+		if (s->ser == NO_SER && mce_ser)
+			continue;
+		if (s->context && ctx != s->context)
+			continue;
+		if (msg)
+			*msg = s->msg;
+		s->covered = 1;
+		if (s->sev >= MCE_UC_SEVERITY && ctx == IN_KERNEL) {
+			if (panic_on_oops || tolerant < 1)
+				return MCE_PANIC_SEVERITY;
+		}
+		return s->sev;
+	}
+}
+
+static void *s_start(struct seq_file *f, loff_t *pos)
+{
+	if (*pos >= ARRAY_SIZE(severities))
+		return NULL;
+	return &severities[*pos];
+}
+
+static void *s_next(struct seq_file *f, void *data, loff_t *pos)
+{
+	if (++(*pos) >= ARRAY_SIZE(severities))
+		return NULL;
+	return &severities[*pos];
+}
+
+static void s_stop(struct seq_file *f, void *data)
+{
+}
+
+static int s_show(struct seq_file *f, void *data)
+{
+	struct severity *ser = data;
+	seq_printf(f, "%d\t%s\n", ser->covered, ser->msg);
+	return 0;
+}
+
+static const struct seq_operations severities_seq_ops = {
+	.start	= s_start,
+	.next	= s_next,
+	.stop	= s_stop,
+	.show	= s_show,
+};
+
+static int severities_coverage_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &severities_seq_ops);
+}
+
+static ssize_t severities_coverage_write(struct file *file,
+					 const char __user *ubuf,
+					 size_t count, loff_t *ppos)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(severities); i++)
+		severities[i].covered = 0;
+	return count;
+}
+
+static const struct file_operations severities_coverage_fops = {
+	.open		= severities_coverage_open,
+	.release	= seq_release,
+	.read		= seq_read,
+	.write		= severities_coverage_write,
+};
+
+static int __init severities_debugfs_init(void)
+{
+	struct dentry *dmce = NULL, *fseverities_coverage = NULL;
+
+	dmce = debugfs_create_dir("mce", NULL);
+	if (dmce == NULL)
+		goto err_out;
+	fseverities_coverage = debugfs_create_file("severities-coverage",
+						   0444, dmce, NULL,
+						   &severities_coverage_fops);
+	if (fseverities_coverage == NULL)
+		goto err_out;
+
+	return 0;
+
+err_out:
+	if (fseverities_coverage)
+		debugfs_remove(fseverities_coverage);
+	if (dmce)
+		debugfs_remove(dmce);
+	return -ENOMEM;
+}
+late_initcall(severities_debugfs_init);
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
new file mode 100644
index 0000000..fabba15
--- /dev/null
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -0,0 +1,1964 @@
+/*
+ * Machine check handler.
+ *
+ * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs.
+ * Rest from unknown author(s).
+ * 2004 Andi Kleen. Rewrote most of it.
+ * Copyright 2008 Intel Corporation
+ * Author: Andi Kleen
+ */
+#include <linux/thread_info.h>
+#include <linux/capability.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/ratelimit.h>
+#include <linux/kallsyms.h>
+#include <linux/rcupdate.h>
+#include <linux/kobject.h>
+#include <linux/uaccess.h>
+#include <linux/kdebug.h>
+#include <linux/kernel.h>
+#include <linux/percpu.h>
+#include <linux/string.h>
+#include <linux/sysdev.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/sched.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/poll.h>
+#include <linux/nmi.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+
+#include <asm/processor.h>
+#include <asm/hw_irq.h>
+#include <asm/apic.h>
+#include <asm/idle.h>
+#include <asm/ipi.h>
+#include <asm/mce.h>
+#include <asm/msr.h>
+
+#include "mce-internal.h"
+#include "mce.h"
+
+/* Handle unconfigured int18 (should never happen) */
+static void unexpected_machine_check(struct pt_regs *regs, long error_code)
+{
+	printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n",
+	       smp_processor_id());
+}
+
+/* Call the installed machine check handler for this CPU setup. */
+void (*machine_check_vector)(struct pt_regs *, long error_code) =
+						unexpected_machine_check;
+
+int				mce_disabled;
+
+#ifdef CONFIG_X86_NEW_MCE
+
+#define MISC_MCELOG_MINOR	227
+
+#define SPINUNIT 100	/* 100ns */
+
+atomic_t mce_entry;
+
+DEFINE_PER_CPU(unsigned, mce_exception_count);
+
+/*
+ * Tolerant levels:
+ *   0: always panic on uncorrected errors, log corrected errors
+ *   1: panic or SIGBUS on uncorrected errors, log corrected errors
+ *   2: SIGBUS or log uncorrected errors (if possible), log corrected errors
+ *   3: never panic or SIGBUS, log all errors (for testing only)
+ */
+static int			tolerant = 1;
+static int			banks;
+static u64			*bank;
+static unsigned long		notify_user;
+static int			rip_msr;
+static int			mce_bootlog = -1;
+static int			monarch_timeout = -1;
+static int			mce_panic_timeout;
+static int			mce_dont_log_ce;
+int				mce_cmci_disabled;
+int				mce_ignore_ce;
+int				mce_ser;
+
+static char			trigger[128];
+static char			*trigger_argv[2] = { trigger, NULL };
+
+static unsigned long		dont_init_banks;
+
+static DECLARE_WAIT_QUEUE_HEAD(mce_wait);
+static DEFINE_PER_CPU(struct mce, mces_seen);
+static int			cpu_missing;
+
+
+/* MCA banks polled by the period polling timer for corrected events */
+DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
+	[0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL
+};
+
+static inline int skip_bank_init(int i)
+{
+	return i < BITS_PER_LONG && test_bit(i, &dont_init_banks);
+}
+
+static DEFINE_PER_CPU(struct work_struct, mce_work);
+
+/* Do initial initialization of a struct mce */
+void mce_setup(struct mce *m)
+{
+	memset(m, 0, sizeof(struct mce));
+	m->cpu = m->extcpu = smp_processor_id();
+	rdtscll(m->tsc);
+	/* We hope get_seconds stays lockless */
+	m->time = get_seconds();
+	m->cpuvendor = boot_cpu_data.x86_vendor;
+	m->cpuid = cpuid_eax(1);
+#ifdef CONFIG_SMP
+	m->socketid = cpu_data(m->extcpu).phys_proc_id;
+#endif
+	m->apicid = cpu_data(m->extcpu).initial_apicid;
+	rdmsrl(MSR_IA32_MCG_CAP, m->mcgcap);
+}
+
+DEFINE_PER_CPU(struct mce, injectm);
+EXPORT_PER_CPU_SYMBOL_GPL(injectm);
+
+/*
+ * Lockless MCE logging infrastructure.
+ * This avoids deadlocks on printk locks without having to break locks. Also
+ * separate MCEs from kernel messages to avoid bogus bug reports.
+ */
+
+static struct mce_log mcelog = {
+	.signature	= MCE_LOG_SIGNATURE,
+	.len		= MCE_LOG_LEN,
+	.recordlen	= sizeof(struct mce),
+};
+
+void mce_log(struct mce *mce)
+{
+	unsigned next, entry;
+
+	mce->finished = 0;
+	wmb();
+	for (;;) {
+		entry = rcu_dereference(mcelog.next);
+		for (;;) {
+			/*
+			 * When the buffer fills up discard new entries.
+			 * Assume that the earlier errors are the more
+			 * interesting ones:
+			 */
+			if (entry >= MCE_LOG_LEN) {
+				set_bit(MCE_OVERFLOW,
+					(unsigned long *)&mcelog.flags);
+				return;
+			}
+			/* Old left over entry. Skip: */
+			if (mcelog.entry[entry].finished) {
+				entry++;
+				continue;
+			}
+			break;
+		}
+		smp_rmb();
+		next = entry + 1;
+		if (cmpxchg(&mcelog.next, entry, next) == entry)
+			break;
+	}
+	memcpy(mcelog.entry + entry, mce, sizeof(struct mce));
+	wmb();
+	mcelog.entry[entry].finished = 1;
+	wmb();
+
+	mce->finished = 1;
+	set_bit(0, &notify_user);
+}
+
+static void print_mce(struct mce *m)
+{
+	printk(KERN_EMERG
+	       "CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n",
+	       m->extcpu, m->mcgstatus, m->bank, m->status);
+	if (m->ip) {
+		printk(KERN_EMERG "RIP%s %02x:<%016Lx> ",
+		       !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "",
+		       m->cs, m->ip);
+		if (m->cs == __KERNEL_CS)
+			print_symbol("{%s}", m->ip);
+		printk("\n");
+	}
+	printk(KERN_EMERG "TSC %llx ", m->tsc);
+	if (m->addr)
+		printk("ADDR %llx ", m->addr);
+	if (m->misc)
+		printk("MISC %llx ", m->misc);
+	printk("\n");
+	printk(KERN_EMERG "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n",
+			m->cpuvendor, m->cpuid, m->time, m->socketid,
+			m->apicid);
+}
+
+static void print_mce_head(void)
+{
+	printk(KERN_EMERG "\n" KERN_EMERG "HARDWARE ERROR\n");
+}
+
+static void print_mce_tail(void)
+{
+	printk(KERN_EMERG "This is not a software problem!\n"
+	       KERN_EMERG "Run through mcelog --ascii to decode and contact your hardware vendor\n");
+}
+
+#define PANIC_TIMEOUT 5 /* 5 seconds */
+
+static atomic_t mce_paniced;
+
+/* Panic in progress. Enable interrupts and wait for final IPI */
+static void wait_for_panic(void)
+{
+	long timeout = PANIC_TIMEOUT*USEC_PER_SEC;
+	preempt_disable();
+	local_irq_enable();
+	while (timeout-- > 0)
+		udelay(1);
+	if (panic_timeout == 0)
+		panic_timeout = mce_panic_timeout;
+	panic("Panicing machine check CPU died");
+}
+
+static void mce_panic(char *msg, struct mce *final, char *exp)
+{
+	int i;
+
+	/*
+	 * Make sure only one CPU runs in machine check panic
+	 */
+	if (atomic_add_return(1, &mce_paniced) > 1)
+		wait_for_panic();
+	barrier();
+
+	bust_spinlocks(1);
+	console_verbose();
+	print_mce_head();
+	/* First print corrected ones that are still unlogged */
+	for (i = 0; i < MCE_LOG_LEN; i++) {
+		struct mce *m = &mcelog.entry[i];
+		if (!(m->status & MCI_STATUS_VAL))
+			continue;
+		if (!(m->status & MCI_STATUS_UC))
+			print_mce(m);
+	}
+	/* Now print uncorrected but with the final one last */
+	for (i = 0; i < MCE_LOG_LEN; i++) {
+		struct mce *m = &mcelog.entry[i];
+		if (!(m->status & MCI_STATUS_VAL))
+			continue;
+		if (!(m->status & MCI_STATUS_UC))
+			continue;
+		if (!final || memcmp(m, final, sizeof(struct mce)))
+			print_mce(m);
+	}
+	if (final)
+		print_mce(final);
+	if (cpu_missing)
+		printk(KERN_EMERG "Some CPUs didn't answer in synchronization\n");
+	print_mce_tail();
+	if (exp)
+		printk(KERN_EMERG "Machine check: %s\n", exp);
+	if (panic_timeout == 0)
+		panic_timeout = mce_panic_timeout;
+	panic(msg);
+}
+
+/* Support code for software error injection */
+
+static int msr_to_offset(u32 msr)
+{
+	unsigned bank = __get_cpu_var(injectm.bank);
+	if (msr == rip_msr)
+		return offsetof(struct mce, ip);
+	if (msr == MSR_IA32_MC0_STATUS + bank*4)
+		return offsetof(struct mce, status);
+	if (msr == MSR_IA32_MC0_ADDR + bank*4)
+		return offsetof(struct mce, addr);
+	if (msr == MSR_IA32_MC0_MISC + bank*4)
+		return offsetof(struct mce, misc);
+	if (msr == MSR_IA32_MCG_STATUS)
+		return offsetof(struct mce, mcgstatus);
+	return -1;
+}
+
+/* MSR access wrappers used for error injection */
+static u64 mce_rdmsrl(u32 msr)
+{
+	u64 v;
+	if (__get_cpu_var(injectm).finished) {
+		int offset = msr_to_offset(msr);
+		if (offset < 0)
+			return 0;
+		return *(u64 *)((char *)&__get_cpu_var(injectm) + offset);
+	}
+	rdmsrl(msr, v);
+	return v;
+}
+
+static void mce_wrmsrl(u32 msr, u64 v)
+{
+	if (__get_cpu_var(injectm).finished) {
+		int offset = msr_to_offset(msr);
+		if (offset >= 0)
+			*(u64 *)((char *)&__get_cpu_var(injectm) + offset) = v;
+		return;
+	}
+	wrmsrl(msr, v);
+}
+
+/*
+ * Simple lockless ring to communicate PFNs from the exception handler with the
+ * process context work function. This is vastly simplified because there's
+ * only a single reader and a single writer.
+ */
+#define MCE_RING_SIZE 16	/* we use one entry less */
+
+struct mce_ring {
+	unsigned short start;
+	unsigned short end;
+	unsigned long ring[MCE_RING_SIZE];
+};
+static DEFINE_PER_CPU(struct mce_ring, mce_ring);
+
+/* Runs with CPU affinity in workqueue */
+static int mce_ring_empty(void)
+{
+	struct mce_ring *r = &__get_cpu_var(mce_ring);
+
+	return r->start == r->end;
+}
+
+static int mce_ring_get(unsigned long *pfn)
+{
+	struct mce_ring *r;
+	int ret = 0;
+
+	*pfn = 0;
+	get_cpu();
+	r = &__get_cpu_var(mce_ring);
+	if (r->start == r->end)
+		goto out;
+	*pfn = r->ring[r->start];
+	r->start = (r->start + 1) % MCE_RING_SIZE;
+	ret = 1;
+out:
+	put_cpu();
+	return ret;
+}
+
+/* Always runs in MCE context with preempt off */
+static int mce_ring_add(unsigned long pfn)
+{
+	struct mce_ring *r = &__get_cpu_var(mce_ring);
+	unsigned next;
+
+	next = (r->end + 1) % MCE_RING_SIZE;
+	if (next == r->start)
+		return -1;
+	r->ring[r->end] = pfn;
+	wmb();
+	r->end = next;
+	return 0;
+}
+
+int mce_available(struct cpuinfo_x86 *c)
+{
+	if (mce_disabled)
+		return 0;
+	return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA);
+}
+
+static void mce_schedule_work(void)
+{
+	if (!mce_ring_empty()) {
+		struct work_struct *work = &__get_cpu_var(mce_work);
+		if (!work_pending(work))
+			schedule_work(work);
+	}
+}
+
+/*
+ * Get the address of the instruction at the time of the machine check
+ * error.
+ */
+static inline void mce_get_rip(struct mce *m, struct pt_regs *regs)
+{
+
+	if (regs && (m->mcgstatus & (MCG_STATUS_RIPV|MCG_STATUS_EIPV))) {
+		m->ip = regs->ip;
+		m->cs = regs->cs;
+	} else {
+		m->ip = 0;
+		m->cs = 0;
+	}
+	if (rip_msr)
+		m->ip = mce_rdmsrl(rip_msr);
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC 
+/*
+ * Called after interrupts have been reenabled again
+ * when a MCE happened during an interrupts off region
+ * in the kernel.
+ */
+asmlinkage void smp_mce_self_interrupt(struct pt_regs *regs)
+{
+	ack_APIC_irq();
+	exit_idle();
+	irq_enter();
+	mce_notify_irq();
+	mce_schedule_work();
+	irq_exit();
+}
+#endif
+
+static void mce_report_event(struct pt_regs *regs)
+{
+	if (regs->flags & (X86_VM_MASK|X86_EFLAGS_IF)) {
+		mce_notify_irq();
+		/*
+		 * Triggering the work queue here is just an insurance
+		 * policy in case the syscall exit notify handler
+		 * doesn't run soon enough or ends up running on the
+		 * wrong CPU (can happen when audit sleeps)
+		 */
+		mce_schedule_work();
+		return;
+	}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+	/*
+	 * Without APIC do not notify. The event will be picked
+	 * up eventually.
+	 */
+	if (!cpu_has_apic)
+		return;
+
+	/*
+	 * When interrupts are disabled we cannot use
+	 * kernel services safely. Trigger an self interrupt
+	 * through the APIC to instead do the notification
+	 * after interrupts are reenabled again.
+	 */
+	apic->send_IPI_self(MCE_SELF_VECTOR);
+
+	/*
+	 * Wait for idle afterwards again so that we don't leave the
+	 * APIC in a non idle state because the normal APIC writes
+	 * cannot exclude us.
+	 */
+	apic_wait_icr_idle();
+#endif
+}
+
+DEFINE_PER_CPU(unsigned, mce_poll_count);
+
+/*
+ * Poll for corrected events or events that happened before reset.
+ * Those are just logged through /dev/mcelog.
+ *
+ * This is executed in standard interrupt context.
+ *
+ * Note: spec recommends to panic for fatal unsignalled
+ * errors here. However this would be quite problematic --
+ * we would need to reimplement the Monarch handling and
+ * it would mess up the exclusion between exception handler
+ * and poll hander -- * so we skip this for now.
+ * These cases should not happen anyways, or only when the CPU
+ * is already totally * confused. In this case it's likely it will
+ * not fully execute the machine check handler either.
+ */
+void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
+{
+	struct mce m;
+	int i;
+
+	__get_cpu_var(mce_poll_count)++;
+
+	mce_setup(&m);
+
+	m.mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS);
+	for (i = 0; i < banks; i++) {
+		if (!bank[i] || !test_bit(i, *b))
+			continue;
+
+		m.misc = 0;
+		m.addr = 0;
+		m.bank = i;
+		m.tsc = 0;
+
+		barrier();
+		m.status = mce_rdmsrl(MSR_IA32_MC0_STATUS + i*4);
+		if (!(m.status & MCI_STATUS_VAL))
+			continue;
+
+		/*
+		 * Uncorrected or signalled events are handled by the exception
+		 * handler when it is enabled, so don't process those here.
+		 *
+		 * TBD do the same check for MCI_STATUS_EN here?
+		 */
+		if (!(flags & MCP_UC) &&
+		    (m.status & (mce_ser ? MCI_STATUS_S : MCI_STATUS_UC)))
+			continue;
+
+		if (m.status & MCI_STATUS_MISCV)
+			m.misc = mce_rdmsrl(MSR_IA32_MC0_MISC + i*4);
+		if (m.status & MCI_STATUS_ADDRV)
+			m.addr = mce_rdmsrl(MSR_IA32_MC0_ADDR + i*4);
+
+		if (!(flags & MCP_TIMESTAMP))
+			m.tsc = 0;
+		/*
+		 * Don't get the IP here because it's unlikely to
+		 * have anything to do with the actual error location.
+		 */
+		if (!(flags & MCP_DONTLOG) && !mce_dont_log_ce) {
+			mce_log(&m);
+			add_taint(TAINT_MACHINE_CHECK);
+		}
+
+		/*
+		 * Clear state for this bank.
+		 */
+		mce_wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
+	}
+
+	/*
+	 * Don't clear MCG_STATUS here because it's only defined for
+	 * exceptions.
+	 */
+
+	sync_core();
+}
+EXPORT_SYMBOL_GPL(machine_check_poll);
+
+/*
+ * Do a quick check if any of the events requires a panic.
+ * This decides if we keep the events around or clear them.
+ */
+static int mce_no_way_out(struct mce *m, char **msg)
+{
+	int i;
+
+	for (i = 0; i < banks; i++) {
+		m->status = mce_rdmsrl(MSR_IA32_MC0_STATUS + i*4);
+		if (mce_severity(m, tolerant, msg) >= MCE_PANIC_SEVERITY)
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * Variable to establish order between CPUs while scanning.
+ * Each CPU spins initially until executing is equal its number.
+ */
+static atomic_t mce_executing;
+
+/*
+ * Defines order of CPUs on entry. First CPU becomes Monarch.
+ */
+static atomic_t mce_callin;
+
+/*
+ * Check if a timeout waiting for other CPUs happened.
+ */
+static int mce_timed_out(u64 *t)
+{
+	/*
+	 * The others already did panic for some reason.
+	 * Bail out like in a timeout.
+	 * rmb() to tell the compiler that system_state
+	 * might have been modified by someone else.
+	 */
+	rmb();
+	if (atomic_read(&mce_paniced))
+		wait_for_panic();
+	if (!monarch_timeout)
+		goto out;
+	if ((s64)*t < SPINUNIT) {
+		/* CHECKME: Make panic default for 1 too? */
+		if (tolerant < 1)
+			mce_panic("Timeout synchronizing machine check over CPUs",
+				  NULL, NULL);
+		cpu_missing = 1;
+		return 1;
+	}
+	*t -= SPINUNIT;
+out:
+	touch_nmi_watchdog();
+	return 0;
+}
+
+/*
+ * The Monarch's reign.  The Monarch is the CPU who entered
+ * the machine check handler first. It waits for the others to
+ * raise the exception too and then grades them. When any
+ * error is fatal panic. Only then let the others continue.
+ *
+ * The other CPUs entering the MCE handler will be controlled by the
+ * Monarch. They are called Subjects.
+ *
+ * This way we prevent any potential data corruption in a unrecoverable case
+ * and also makes sure always all CPU's errors are examined.
+ *
+ * Also this detects the case of an machine check event coming from outer
+ * space (not detected by any CPUs) In this case some external agent wants
+ * us to shut down, so panic too.
+ *
+ * The other CPUs might still decide to panic if the handler happens
+ * in a unrecoverable place, but in this case the system is in a semi-stable
+ * state and won't corrupt anything by itself. It's ok to let the others
+ * continue for a bit first.
+ *
+ * All the spin loops have timeouts; when a timeout happens a CPU
+ * typically elects itself to be Monarch.
+ */
+static void mce_reign(void)
+{
+	int cpu;
+	struct mce *m = NULL;
+	int global_worst = 0;
+	char *msg = NULL;
+	char *nmsg = NULL;
+
+	/*
+	 * This CPU is the Monarch and the other CPUs have run
+	 * through their handlers.
+	 * Grade the severity of the errors of all the CPUs.
+	 */
+	for_each_possible_cpu(cpu) {
+		int severity = mce_severity(&per_cpu(mces_seen, cpu), tolerant,
+					    &nmsg);
+		if (severity > global_worst) {
+			msg = nmsg;
+			global_worst = severity;
+			m = &per_cpu(mces_seen, cpu);
+		}
+	}
+
+	/*
+	 * Cannot recover? Panic here then.
+	 * This dumps all the mces in the log buffer and stops the
+	 * other CPUs.
+	 */
+	if (m && global_worst >= MCE_PANIC_SEVERITY && tolerant < 3)
+		mce_panic("Fatal Machine check", m, msg);
+
+	/*
+	 * For UC somewhere we let the CPU who detects it handle it.
+	 * Also must let continue the others, otherwise the handling
+	 * CPU could deadlock on a lock.
+	 */
+
+	/*
+	 * No machine check event found. Must be some external
+	 * source or one CPU is hung. Panic.
+	 */
+	if (!m && tolerant < 3)
+		mce_panic("Machine check from unknown source", NULL, NULL);
+
+	/*
+	 * Now clear all the mces_seen so that they don't reappear on
+	 * the next mce.
+	 */
+	for_each_possible_cpu(cpu)
+		memset(&per_cpu(mces_seen, cpu), 0, sizeof(struct mce));
+}
+
+static atomic_t global_nwo;
+
+/*
+ * Start of Monarch synchronization. This waits until all CPUs have
+ * entered the exception handler and then determines if any of them
+ * saw a fatal event that requires panic. Then it executes them
+ * in the entry order.
+ * TBD double check parallel CPU hotunplug
+ */
+static int mce_start(int no_way_out, int *order)
+{
+	int nwo;
+	int cpus = num_online_cpus();
+	u64 timeout = (u64)monarch_timeout * NSEC_PER_USEC;
+
+	if (!timeout) {
+		*order = -1;
+		return no_way_out;
+	}
+
+	atomic_add(no_way_out, &global_nwo);
+
+	/*
+	 * Wait for everyone.
+	 */
+	while (atomic_read(&mce_callin) != cpus) {
+		if (mce_timed_out(&timeout)) {
+			atomic_set(&global_nwo, 0);
+			*order = -1;
+			return no_way_out;
+		}
+		ndelay(SPINUNIT);
+	}
+
+	/*
+	 * Cache the global no_way_out state.
+	 */
+	nwo = atomic_read(&global_nwo);
+
+	/*
+	 * Monarch starts executing now, the others wait.
+	 */
+	if (*order == 1) {
+		atomic_set(&mce_executing, 1);
+		return nwo;
+	}
+
+	/*
+	 * Now start the scanning loop one by one
+	 * in the original callin order.
+	 * This way when there are any shared banks it will
+	 * be only seen by one CPU before cleared, avoiding duplicates.
+	 */
+	while (atomic_read(&mce_executing) < *order) {
+		if (mce_timed_out(&timeout)) {
+			atomic_set(&global_nwo, 0);
+			*order = -1;
+			return no_way_out;
+		}
+		ndelay(SPINUNIT);
+	}
+	return nwo;
+}
+
+/*
+ * Synchronize between CPUs after main scanning loop.
+ * This invokes the bulk of the Monarch processing.
+ */
+static int mce_end(int order)
+{
+	int ret = -1;
+	u64 timeout = (u64)monarch_timeout * NSEC_PER_USEC;
+
+	if (!timeout)
+		goto reset;
+	if (order < 0)
+		goto reset;
+
+	/*
+	 * Allow others to run.
+	 */
+	atomic_inc(&mce_executing);
+
+	if (order == 1) {
+		/* CHECKME: Can this race with a parallel hotplug? */
+		int cpus = num_online_cpus();
+
+		/*
+		 * Monarch: Wait for everyone to go through their scanning
+		 * loops.
+		 */
+		while (atomic_read(&mce_executing) <= cpus) {
+			if (mce_timed_out(&timeout))
+				goto reset;
+			ndelay(SPINUNIT);
+		}
+
+		mce_reign();
+		barrier();
+		ret = 0;
+	} else {
+		/*
+		 * Subject: Wait for Monarch to finish.
+		 */
+		while (atomic_read(&mce_executing) != 0) {
+			if (mce_timed_out(&timeout))
+				goto reset;
+			ndelay(SPINUNIT);
+		}
+
+		/*
+		 * Don't reset anything. That's done by the Monarch.
+		 */
+		return 0;
+	}
+
+	/*
+	 * Reset all global state.
+	 */
+reset:
+	atomic_set(&global_nwo, 0);
+	atomic_set(&mce_callin, 0);
+	barrier();
+
+	/*
+	 * Let others run again.
+	 */
+	atomic_set(&mce_executing, 0);
+	return ret;
+}
+
+/*
+ * Check if the address reported by the CPU is in a format we can parse.
+ * It would be possible to add code for most other cases, but all would
+ * be somewhat complicated (e.g. segment offset would require an instruction
+ * parser). So only support physical addresses upto page granuality for now.
+ */
+static int mce_usable_address(struct mce *m)
+{
+	if (!(m->status & MCI_STATUS_MISCV) || !(m->status & MCI_STATUS_ADDRV))
+		return 0;
+	if ((m->misc & 0x3f) > PAGE_SHIFT)
+		return 0;
+	if (((m->misc >> 6) & 7) != MCM_ADDR_PHYS)
+		return 0;
+	return 1;
+}
+
+static void mce_clear_state(unsigned long *toclear)
+{
+	int i;
+
+	for (i = 0; i < banks; i++) {
+		if (test_bit(i, toclear))
+			mce_wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
+	}
+}
+
+/*
+ * The actual machine check handler. This only handles real
+ * exceptions when something got corrupted coming in through int 18.
+ *
+ * This is executed in NMI context not subject to normal locking rules. This
+ * implies that most kernel services cannot be safely used. Don't even
+ * think about putting a printk in there!
+ *
+ * On Intel systems this is entered on all CPUs in parallel through
+ * MCE broadcast. However some CPUs might be broken beyond repair,
+ * so be always careful when synchronizing with others.
+ */
+void do_machine_check(struct pt_regs *regs, long error_code)
+{
+	struct mce m, *final;
+	int i;
+	int worst = 0;
+	int severity;
+	/*
+	 * Establish sequential order between the CPUs entering the machine
+	 * check handler.
+	 */
+	int order;
+
+	/*
+	 * If no_way_out gets set, there is no safe way to recover from this
+	 * MCE.  If tolerant is cranked up, we'll try anyway.
+	 */
+	int no_way_out = 0;
+	/*
+	 * If kill_it gets set, there might be a way to recover from this
+	 * error.
+	 */
+	int kill_it = 0;
+	DECLARE_BITMAP(toclear, MAX_NR_BANKS);
+	char *msg = "Unknown";
+
+	atomic_inc(&mce_entry);
+
+	__get_cpu_var(mce_exception_count)++;
+
+	if (notify_die(DIE_NMI, "machine check", regs, error_code,
+			   18, SIGKILL) == NOTIFY_STOP)
+		goto out;
+	if (!banks)
+		goto out;
+
+	order = atomic_add_return(1, &mce_callin);
+	mce_setup(&m);
+
+	m.mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS);
+	no_way_out = mce_no_way_out(&m, &msg);
+
+	final = &__get_cpu_var(mces_seen);
+	*final = m;
+
+	barrier();
+
+	/*
+	 * When no restart IP must always kill or panic.
+	 */
+	if (!(m.mcgstatus & MCG_STATUS_RIPV))
+		kill_it = 1;
+
+	/*
+	 * Go through all the banks in exclusion of the other CPUs.
+	 * This way we don't report duplicated events on shared banks
+	 * because the first one to see it will clear it.
+	 */
+	no_way_out = mce_start(no_way_out, &order);
+	for (i = 0; i < banks; i++) {
+		__clear_bit(i, toclear);
+		if (!bank[i])
+			continue;
+
+		m.misc = 0;
+		m.addr = 0;
+		m.bank = i;
+
+		m.status = mce_rdmsrl(MSR_IA32_MC0_STATUS + i*4);
+		if ((m.status & MCI_STATUS_VAL) == 0)
+			continue;
+
+		/*
+		 * Non uncorrected or non signaled errors are handled by
+		 * machine_check_poll. Leave them alone, unless this panics.
+		 */
+		if (!(m.status & (mce_ser ? MCI_STATUS_S : MCI_STATUS_UC)) &&
+			!no_way_out)
+			continue;
+
+		/*
+		 * Set taint even when machine check was not enabled.
+		 */
+		add_taint(TAINT_MACHINE_CHECK);
+
+		severity = mce_severity(&m, tolerant, NULL);
+
+		/*
+		 * When machine check was for corrected handler don't touch,
+		 * unless we're panicing.
+		 */
+		if (severity == MCE_KEEP_SEVERITY && !no_way_out)
+			continue;
+		__set_bit(i, toclear);
+		if (severity == MCE_NO_SEVERITY) {
+			/*
+			 * Machine check event was not enabled. Clear, but
+			 * ignore.
+			 */
+			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_MC0_MISC + i*4);
+		if (m.status & MCI_STATUS_ADDRV)
+			m.addr = mce_rdmsrl(MSR_IA32_MC0_ADDR + i*4);
+
+		/*
+		 * Action optional error. Queue address for later processing.
+		 * When the ring overflows we just ignore the AO error.
+		 * RED-PEN add some logging mechanism when
+		 * usable_address or mce_add_ring fails.
+		 * RED-PEN don't ignore overflow for tolerant == 0
+		 */
+		if (severity == MCE_AO_SEVERITY && mce_usable_address(&m))
+			mce_ring_add(m.addr >> PAGE_SHIFT);
+
+		mce_get_rip(&m, regs);
+		mce_log(&m);
+
+		if (severity > worst) {
+			*final = m;
+			worst = severity;
+		}
+	}
+
+	if (!no_way_out)
+		mce_clear_state(toclear);
+
+	/*
+	 * Do most of the synchronization with other CPUs.
+	 * When there's any problem use only local no_way_out state.
+	 */
+	if (mce_end(order) < 0)
+		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.
+	 */
+	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 (worst > 0)
+		mce_report_event(regs);
+	mce_wrmsrl(MSR_IA32_MCG_STATUS, 0);
+out:
+	atomic_dec(&mce_entry);
+	sync_core();
+}
+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)
+{
+	printk(KERN_ERR "Action optional memory failure at %lx ignored\n", pfn);
+}
+
+/*
+ * 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.
+ */
+void mce_notify_process(void)
+{
+	unsigned long pfn;
+	mce_notify_irq();
+	while (mce_ring_get(&pfn))
+		memory_failure(pfn, MCE_VECTOR);
+}
+
+static void mce_process_work(struct work_struct *dummy)
+{
+	mce_notify_process();
+}
+
+#ifdef CONFIG_X86_MCE_INTEL
+/***
+ * mce_log_therm_throt_event - Logs the thermal throttling event to mcelog
+ * @cpu: The CPU on which the event occurred.
+ * @status: Event status information
+ *
+ * This function should be called by the thermal interrupt after the
+ * event has been processed and the decision was made to log the event
+ * further.
+ *
+ * The status parameter will be saved to the 'status' field of 'struct mce'
+ * and historically has been the register value of the
+ * MSR_IA32_THERMAL_STATUS (Intel) msr.
+ */
+void mce_log_therm_throt_event(__u64 status)
+{
+	struct mce m;
+
+	mce_setup(&m);
+	m.bank = MCE_THERMAL_BANK;
+	m.status = status;
+	mce_log(&m);
+}
+#endif /* CONFIG_X86_MCE_INTEL */
+
+/*
+ * Periodic polling timer for "silent" machine check errors.  If the
+ * poller finds an MCE, poll 2x faster.  When the poller finds no more
+ * errors, poll 2x slower (up to check_interval seconds).
+ */
+static int check_interval = 5 * 60; /* 5 minutes */
+
+static DEFINE_PER_CPU(int, next_interval); /* in jiffies */
+static DEFINE_PER_CPU(struct timer_list, mce_timer);
+
+static void mcheck_timer(unsigned long data)
+{
+	struct timer_list *t = &per_cpu(mce_timer, data);
+	int *n;
+
+	WARN_ON(smp_processor_id() != data);
+
+	if (mce_available(&current_cpu_data)) {
+		machine_check_poll(MCP_TIMESTAMP,
+				&__get_cpu_var(mce_poll_banks));
+	}
+
+	/*
+	 * Alert userspace if needed.  If we logged an MCE, reduce the
+	 * polling interval, otherwise increase the polling interval.
+	 */
+	n = &__get_cpu_var(next_interval);
+	if (mce_notify_irq())
+		*n = max(*n/2, HZ/100);
+	else
+		*n = min(*n*2, (int)round_jiffies_relative(check_interval*HZ));
+
+	t->expires = jiffies + *n;
+	add_timer(t);
+}
+
+static void mce_do_trigger(struct work_struct *work)
+{
+	call_usermodehelper(trigger, trigger_argv, NULL, UMH_NO_WAIT);
+}
+
+static DECLARE_WORK(mce_trigger_work, mce_do_trigger);
+
+/*
+ * Notify the user(s) about new machine check events.
+ * Can be called from interrupt context, but not from machine check/NMI
+ * context.
+ */
+int mce_notify_irq(void)
+{
+	/* 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, &notify_user)) {
+		wake_up_interruptible(&mce_wait);
+
+		/*
+		 * There is no risk of missing notifications because
+		 * work_pending is always cleared before the function is
+		 * executed.
+		 */
+		if (trigger[0] && !work_pending(&mce_trigger_work))
+			schedule_work(&mce_trigger_work);
+
+		if (__ratelimit(&ratelimit))
+			printk(KERN_INFO "Machine check events logged\n");
+
+		return 1;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mce_notify_irq);
+
+/*
+ * Initialize Machine Checks for a CPU.
+ */
+static int mce_cap_init(void)
+{
+	unsigned b;
+	u64 cap;
+
+	rdmsrl(MSR_IA32_MCG_CAP, cap);
+
+	b = cap & MCG_BANKCNT_MASK;
+	printk(KERN_INFO "mce: CPU supports %d MCE banks\n", b);
+
+	if (b > MAX_NR_BANKS) {
+		printk(KERN_WARNING
+		       "MCE: Using only %u machine check banks out of %u\n",
+			MAX_NR_BANKS, b);
+		b = MAX_NR_BANKS;
+	}
+
+	/* Don't support asymmetric configurations today */
+	WARN_ON(banks != 0 && b != banks);
+	banks = b;
+	if (!bank) {
+		bank = kmalloc(banks * sizeof(u64), GFP_KERNEL);
+		if (!bank)
+			return -ENOMEM;
+		memset(bank, 0xff, banks * sizeof(u64));
+	}
+
+	/* Use accurate RIP reporting if available. */
+	if ((cap & MCG_EXT_P) && MCG_EXT_CNT(cap) >= 9)
+		rip_msr = MSR_IA32_MCG_EIP;
+
+	if (cap & MCG_SER_P)
+		mce_ser = 1;
+
+	return 0;
+}
+
+static void mce_init(void)
+{
+	mce_banks_t all_banks;
+	u64 cap;
+	int i;
+
+	/*
+	 * Log the machine checks left over from the previous reset.
+	 */
+	bitmap_fill(all_banks, MAX_NR_BANKS);
+	machine_check_poll(MCP_UC|(!mce_bootlog ? MCP_DONTLOG : 0), &all_banks);
+
+	set_in_cr4(X86_CR4_MCE);
+
+	rdmsrl(MSR_IA32_MCG_CAP, cap);
+	if (cap & MCG_CTL_P)
+		wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
+
+	for (i = 0; i < banks; i++) {
+		if (skip_bank_init(i))
+			continue;
+		wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
+		wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
+	}
+}
+
+/* Add per CPU specific workarounds here */
+static void mce_cpu_quirks(struct cpuinfo_x86 *c)
+{
+	/* This should be disabled by the BIOS, but isn't always */
+	if (c->x86_vendor == X86_VENDOR_AMD) {
+		if (c->x86 == 15 && banks > 4) {
+			/*
+			 * disable GART TBL walk error reporting, which
+			 * trips off incorrectly with the IOMMU & 3ware
+			 * & Cerberus:
+			 */
+			clear_bit(10, (unsigned long *)&bank[4]);
+		}
+		if (c->x86 <= 17 && mce_bootlog < 0) {
+			/*
+			 * Lots of broken BIOS around that don't clear them
+			 * by default and leave crap in there. Don't log:
+			 */
+			mce_bootlog = 0;
+		}
+		/*
+		 * Various K7s with broken bank 0 around. Always disable
+		 * by default.
+		 */
+		 if (c->x86 == 6)
+			bank[0] = 0;
+	}
+
+	if (c->x86_vendor == X86_VENDOR_INTEL) {
+		/*
+		 * SDM documents that on family 6 bank 0 should not be written
+		 * because it aliases to another special BIOS controlled
+		 * register.
+		 * But it's not aliased anymore on model 0x1a+
+		 * Don't ignore bank 0 completely because there could be a
+		 * valid event later, merely don't write CTL0.
+		 */
+
+		if (c->x86 == 6 && c->x86_model < 0x1A)
+			__set_bit(0, &dont_init_banks);
+
+		/*
+		 * All newer Intel systems support MCE broadcasting. Enable
+		 * synchronization with a one second timeout.
+		 */
+		if ((c->x86 > 6 || (c->x86 == 6 && c->x86_model >= 0xe)) &&
+			monarch_timeout < 0)
+			monarch_timeout = USEC_PER_SEC;
+	}
+	if (monarch_timeout < 0)
+		monarch_timeout = 0;
+	if (mce_bootlog != 0)
+		mce_panic_timeout = 30;
+}
+
+static void __cpuinit mce_ancient_init(struct cpuinfo_x86 *c)
+{
+	if (c->x86 != 5)
+		return;
+	switch (c->x86_vendor) {
+	case X86_VENDOR_INTEL:
+		if (mce_p5_enabled())
+			intel_p5_mcheck_init(c);
+		break;
+	case X86_VENDOR_CENTAUR:
+		winchip_mcheck_init(c);
+		break;
+	}
+}
+
+static void mce_cpu_features(struct cpuinfo_x86 *c)
+{
+	switch (c->x86_vendor) {
+	case X86_VENDOR_INTEL:
+		mce_intel_feature_init(c);
+		break;
+	case X86_VENDOR_AMD:
+		mce_amd_feature_init(c);
+		break;
+	default:
+		break;
+	}
+}
+
+static void mce_init_timer(void)
+{
+	struct timer_list *t = &__get_cpu_var(mce_timer);
+	int *n = &__get_cpu_var(next_interval);
+
+	if (mce_ignore_ce)
+		return;
+
+	*n = check_interval * HZ;
+	if (!*n)
+		return;
+	setup_timer(t, mcheck_timer, smp_processor_id());
+	t->expires = round_jiffies(jiffies + *n);
+	add_timer(t);
+}
+
+/*
+ * Called for each booted CPU to set up machine checks.
+ * Must be called with preempt off:
+ */
+void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
+{
+	if (mce_disabled)
+		return;
+
+	mce_ancient_init(c);
+
+	if (!mce_available(c))
+		return;
+
+	if (mce_cap_init() < 0) {
+		mce_disabled = 1;
+		return;
+	}
+	mce_cpu_quirks(c);
+
+	machine_check_vector = do_machine_check;
+
+	mce_init();
+	mce_cpu_features(c);
+	mce_init_timer();
+	INIT_WORK(&__get_cpu_var(mce_work), mce_process_work);
+}
+
+/*
+ * Character device to read and clear the MCE log.
+ */
+
+static DEFINE_SPINLOCK(mce_state_lock);
+static int		open_count;		/* #times opened */
+static int		open_exclu;		/* already open exclusive? */
+
+static int mce_open(struct inode *inode, struct file *file)
+{
+	spin_lock(&mce_state_lock);
+
+	if (open_exclu || (open_count && (file->f_flags & O_EXCL))) {
+		spin_unlock(&mce_state_lock);
+
+		return -EBUSY;
+	}
+
+	if (file->f_flags & O_EXCL)
+		open_exclu = 1;
+	open_count++;
+
+	spin_unlock(&mce_state_lock);
+
+	return nonseekable_open(inode, file);
+}
+
+static int mce_release(struct inode *inode, struct file *file)
+{
+	spin_lock(&mce_state_lock);
+
+	open_count--;
+	open_exclu = 0;
+
+	spin_unlock(&mce_state_lock);
+
+	return 0;
+}
+
+static void collect_tscs(void *data)
+{
+	unsigned long *cpu_tsc = (unsigned long *)data;
+
+	rdtscll(cpu_tsc[smp_processor_id()]);
+}
+
+static DEFINE_MUTEX(mce_read_mutex);
+
+static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize,
+			loff_t *off)
+{
+	char __user *buf = ubuf;
+	unsigned long *cpu_tsc;
+	unsigned prev, next;
+	int i, err;
+
+	cpu_tsc = kmalloc(nr_cpu_ids * sizeof(long), GFP_KERNEL);
+	if (!cpu_tsc)
+		return -ENOMEM;
+
+	mutex_lock(&mce_read_mutex);
+	next = rcu_dereference(mcelog.next);
+
+	/* Only supports full reads right now */
+	if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) {
+		mutex_unlock(&mce_read_mutex);
+		kfree(cpu_tsc);
+
+		return -EINVAL;
+	}
+
+	err = 0;
+	prev = 0;
+	do {
+		for (i = prev; i < next; i++) {
+			unsigned long start = jiffies;
+
+			while (!mcelog.entry[i].finished) {
+				if (time_after_eq(jiffies, start + 2)) {
+					memset(mcelog.entry + i, 0,
+					       sizeof(struct mce));
+					goto timeout;
+				}
+				cpu_relax();
+			}
+			smp_rmb();
+			err |= copy_to_user(buf, mcelog.entry + i,
+					    sizeof(struct mce));
+			buf += sizeof(struct mce);
+timeout:
+			;
+		}
+
+		memset(mcelog.entry + prev, 0,
+		       (next - prev) * sizeof(struct mce));
+		prev = next;
+		next = cmpxchg(&mcelog.next, prev, 0);
+	} while (next != prev);
+
+	synchronize_sched();
+
+	/*
+	 * Collect entries that were still getting written before the
+	 * synchronize.
+	 */
+	on_each_cpu(collect_tscs, cpu_tsc, 1);
+
+	for (i = next; i < MCE_LOG_LEN; i++) {
+		if (mcelog.entry[i].finished &&
+		    mcelog.entry[i].tsc < cpu_tsc[mcelog.entry[i].cpu]) {
+			err |= copy_to_user(buf, mcelog.entry+i,
+					    sizeof(struct mce));
+			smp_rmb();
+			buf += sizeof(struct mce);
+			memset(&mcelog.entry[i], 0, sizeof(struct mce));
+		}
+	}
+	mutex_unlock(&mce_read_mutex);
+	kfree(cpu_tsc);
+
+	return err ? -EFAULT : buf - ubuf;
+}
+
+static unsigned int mce_poll(struct file *file, poll_table *wait)
+{
+	poll_wait(file, &mce_wait, wait);
+	if (rcu_dereference(mcelog.next))
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static long mce_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+	int __user *p = (int __user *)arg;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	switch (cmd) {
+	case MCE_GET_RECORD_LEN:
+		return put_user(sizeof(struct mce), p);
+	case MCE_GET_LOG_LEN:
+		return put_user(MCE_LOG_LEN, p);
+	case MCE_GETCLEAR_FLAGS: {
+		unsigned flags;
+
+		do {
+			flags = mcelog.flags;
+		} while (cmpxchg(&mcelog.flags, flags, 0) != flags);
+
+		return put_user(flags, p);
+	}
+	default:
+		return -ENOTTY;
+	}
+}
+
+/* Modified in mce-inject.c, so not static or const */
+struct file_operations mce_chrdev_ops = {
+	.open			= mce_open,
+	.release		= mce_release,
+	.read			= mce_read,
+	.poll			= mce_poll,
+	.unlocked_ioctl		= mce_ioctl,
+};
+EXPORT_SYMBOL_GPL(mce_chrdev_ops);
+
+static struct miscdevice mce_log_device = {
+	MISC_MCELOG_MINOR,
+	"mcelog",
+	&mce_chrdev_ops,
+};
+
+/*
+ * mce=off Disables machine check
+ * mce=no_cmci Disables CMCI
+ * mce=dont_log_ce Clears corrected events silently, no log created for CEs.
+ * mce=ignore_ce Disables polling and CMCI, corrected events are not cleared.
+ * mce=TOLERANCELEVEL[,monarchtimeout] (number, see above)
+ *	monarchtimeout is how long to wait for other CPUs on machine
+ *	check, or 0 to not wait
+ * mce=bootlog Log MCEs from before booting. Disabled by default on AMD.
+ * mce=nobootlog Don't log MCEs from before booting.
+ */
+static int __init mcheck_enable(char *str)
+{
+	if (*str == 0)
+		enable_p5_mce();
+	if (*str == '=')
+		str++;
+	if (!strcmp(str, "off"))
+		mce_disabled = 1;
+	else if (!strcmp(str, "no_cmci"))
+		mce_cmci_disabled = 1;
+	else if (!strcmp(str, "dont_log_ce"))
+		mce_dont_log_ce = 1;
+	else if (!strcmp(str, "ignore_ce"))
+		mce_ignore_ce = 1;
+	else if (!strcmp(str, "bootlog") || !strcmp(str, "nobootlog"))
+		mce_bootlog = (str[0] == 'b');
+	else if (isdigit(str[0])) {
+		get_option(&str, &tolerant);
+		if (*str == ',') {
+			++str;
+			get_option(&str, &monarch_timeout);
+		}
+	} else {
+		printk(KERN_INFO "mce argument %s ignored. Please use /sys\n",
+		       str);
+		return 0;
+	}
+	return 1;
+}
+__setup("mce", mcheck_enable);
+
+/*
+ * Sysfs support
+ */
+
+/*
+ * Disable machine checks on suspend and shutdown. We can't really handle
+ * them later.
+ */
+static int mce_disable(void)
+{
+	int i;
+
+	for (i = 0; i < banks; i++) {
+		if (!skip_bank_init(i))
+			wrmsrl(MSR_IA32_MC0_CTL + i*4, 0);
+	}
+	return 0;
+}
+
+static int mce_suspend(struct sys_device *dev, pm_message_t state)
+{
+	return mce_disable();
+}
+
+static int mce_shutdown(struct sys_device *dev)
+{
+	return mce_disable();
+}
+
+/*
+ * On resume clear all MCE state. Don't want to see leftovers from the BIOS.
+ * Only one CPU is active at this time, the others get re-added later using
+ * CPU hotplug:
+ */
+static int mce_resume(struct sys_device *dev)
+{
+	mce_init();
+	mce_cpu_features(&current_cpu_data);
+
+	return 0;
+}
+
+static void mce_cpu_restart(void *data)
+{
+	del_timer_sync(&__get_cpu_var(mce_timer));
+	if (mce_available(&current_cpu_data))
+		mce_init();
+	mce_init_timer();
+}
+
+/* Reinit MCEs after user configuration changes */
+static void mce_restart(void)
+{
+	on_each_cpu(mce_cpu_restart, NULL, 1);
+}
+
+static struct sysdev_class mce_sysclass = {
+	.suspend	= mce_suspend,
+	.shutdown	= mce_shutdown,
+	.resume		= mce_resume,
+	.name		= "machinecheck",
+};
+
+DEFINE_PER_CPU(struct sys_device, mce_dev);
+
+__cpuinitdata
+void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu);
+
+static struct sysdev_attribute *bank_attrs;
+
+static ssize_t show_bank(struct sys_device *s, struct sysdev_attribute *attr,
+			 char *buf)
+{
+	u64 b = bank[attr - bank_attrs];
+
+	return sprintf(buf, "%llx\n", b);
+}
+
+static ssize_t set_bank(struct sys_device *s, struct sysdev_attribute *attr,
+			const char *buf, size_t size)
+{
+	u64 new;
+
+	if (strict_strtoull(buf, 0, &new) < 0)
+		return -EINVAL;
+
+	bank[attr - bank_attrs] = new;
+	mce_restart();
+
+	return size;
+}
+
+static ssize_t
+show_trigger(struct sys_device *s, struct sysdev_attribute *attr, char *buf)
+{
+	strcpy(buf, trigger);
+	strcat(buf, "\n");
+	return strlen(trigger) + 1;
+}
+
+static ssize_t set_trigger(struct sys_device *s, struct sysdev_attribute *attr,
+				const char *buf, size_t siz)
+{
+	char *p;
+	int len;
+
+	strncpy(trigger, buf, sizeof(trigger));
+	trigger[sizeof(trigger)-1] = 0;
+	len = strlen(trigger);
+	p = strchr(trigger, '\n');
+
+	if (*p)
+		*p = 0;
+
+	return len;
+}
+
+static ssize_t store_int_with_restart(struct sys_device *s,
+				      struct sysdev_attribute *attr,
+				      const char *buf, size_t size)
+{
+	ssize_t ret = sysdev_store_int(s, attr, buf, size);
+	mce_restart();
+	return ret;
+}
+
+static SYSDEV_ATTR(trigger, 0644, show_trigger, set_trigger);
+static SYSDEV_INT_ATTR(tolerant, 0644, tolerant);
+static SYSDEV_INT_ATTR(monarch_timeout, 0644, monarch_timeout);
+
+static struct sysdev_ext_attribute attr_check_interval = {
+	_SYSDEV_ATTR(check_interval, 0644, sysdev_show_int,
+		     store_int_with_restart),
+	&check_interval
+};
+
+static struct sysdev_attribute *mce_attrs[] = {
+	&attr_tolerant.attr, &attr_check_interval.attr, &attr_trigger,
+	&attr_monarch_timeout.attr,
+	NULL
+};
+
+static cpumask_var_t mce_dev_initialized;
+
+/* Per cpu sysdev init. All of the cpus still share the same ctrl bank: */
+static __cpuinit int mce_create_device(unsigned int cpu)
+{
+	int err;
+	int i;
+
+	if (!mce_available(&boot_cpu_data))
+		return -EIO;
+
+	memset(&per_cpu(mce_dev, cpu).kobj, 0, sizeof(struct kobject));
+	per_cpu(mce_dev, cpu).id	= cpu;
+	per_cpu(mce_dev, cpu).cls	= &mce_sysclass;
+
+	err = sysdev_register(&per_cpu(mce_dev, cpu));
+	if (err)
+		return err;
+
+	for (i = 0; mce_attrs[i]; i++) {
+		err = sysdev_create_file(&per_cpu(mce_dev, cpu), mce_attrs[i]);
+		if (err)
+			goto error;
+	}
+	for (i = 0; i < banks; i++) {
+		err = sysdev_create_file(&per_cpu(mce_dev, cpu),
+					&bank_attrs[i]);
+		if (err)
+			goto error2;
+	}
+	cpumask_set_cpu(cpu, mce_dev_initialized);
+
+	return 0;
+error2:
+	while (--i >= 0)
+		sysdev_remove_file(&per_cpu(mce_dev, cpu), &bank_attrs[i]);
+error:
+	while (--i >= 0)
+		sysdev_remove_file(&per_cpu(mce_dev, cpu), mce_attrs[i]);
+
+	sysdev_unregister(&per_cpu(mce_dev, cpu));
+
+	return err;
+}
+
+static __cpuinit void mce_remove_device(unsigned int cpu)
+{
+	int i;
+
+	if (!cpumask_test_cpu(cpu, mce_dev_initialized))
+		return;
+
+	for (i = 0; mce_attrs[i]; i++)
+		sysdev_remove_file(&per_cpu(mce_dev, cpu), mce_attrs[i]);
+
+	for (i = 0; i < banks; i++)
+		sysdev_remove_file(&per_cpu(mce_dev, cpu), &bank_attrs[i]);
+
+	sysdev_unregister(&per_cpu(mce_dev, cpu));
+	cpumask_clear_cpu(cpu, mce_dev_initialized);
+}
+
+/* Make sure there are no machine checks on offlined CPUs. */
+static void mce_disable_cpu(void *h)
+{
+	unsigned long action = *(unsigned long *)h;
+	int i;
+
+	if (!mce_available(&current_cpu_data))
+		return;
+	if (!(action & CPU_TASKS_FROZEN))
+		cmci_clear();
+	for (i = 0; i < banks; i++) {
+		if (!skip_bank_init(i))
+			wrmsrl(MSR_IA32_MC0_CTL + i*4, 0);
+	}
+}
+
+static void mce_reenable_cpu(void *h)
+{
+	unsigned long action = *(unsigned long *)h;
+	int i;
+
+	if (!mce_available(&current_cpu_data))
+		return;
+
+	if (!(action & CPU_TASKS_FROZEN))
+		cmci_reenable();
+	for (i = 0; i < banks; i++) {
+		if (!skip_bank_init(i))
+			wrmsrl(MSR_IA32_MC0_CTL + i*4, bank[i]);
+	}
+}
+
+/* Get notified when a cpu comes on/off. Be hotplug friendly. */
+static int __cpuinit
+mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+	struct timer_list *t = &per_cpu(mce_timer, cpu);
+
+	switch (action) {
+	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
+		mce_create_device(cpu);
+		if (threshold_cpu_callback)
+			threshold_cpu_callback(action, cpu);
+		break;
+	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
+		if (threshold_cpu_callback)
+			threshold_cpu_callback(action, cpu);
+		mce_remove_device(cpu);
+		break;
+	case CPU_DOWN_PREPARE:
+	case CPU_DOWN_PREPARE_FROZEN:
+		del_timer_sync(t);
+		smp_call_function_single(cpu, mce_disable_cpu, &action, 1);
+		break;
+	case CPU_DOWN_FAILED:
+	case CPU_DOWN_FAILED_FROZEN:
+		t->expires = round_jiffies(jiffies +
+						__get_cpu_var(next_interval));
+		add_timer_on(t, cpu);
+		smp_call_function_single(cpu, mce_reenable_cpu, &action, 1);
+		break;
+	case CPU_POST_DEAD:
+		/* intentionally ignoring frozen here */
+		cmci_rediscover(cpu);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block mce_cpu_notifier __cpuinitdata = {
+	.notifier_call = mce_cpu_callback,
+};
+
+static __init int mce_init_banks(void)
+{
+	int i;
+
+	bank_attrs = kzalloc(sizeof(struct sysdev_attribute) * banks,
+				GFP_KERNEL);
+	if (!bank_attrs)
+		return -ENOMEM;
+
+	for (i = 0; i < banks; i++) {
+		struct sysdev_attribute *a = &bank_attrs[i];
+
+		a->attr.name	= kasprintf(GFP_KERNEL, "bank%d", i);
+		if (!a->attr.name)
+			goto nomem;
+
+		a->attr.mode	= 0644;
+		a->show		= show_bank;
+		a->store	= set_bank;
+	}
+	return 0;
+
+nomem:
+	while (--i >= 0)
+		kfree(bank_attrs[i].attr.name);
+	kfree(bank_attrs);
+	bank_attrs = NULL;
+
+	return -ENOMEM;
+}
+
+static __init int mce_init_device(void)
+{
+	int err;
+	int i = 0;
+
+	if (!mce_available(&boot_cpu_data))
+		return -EIO;
+
+	alloc_cpumask_var(&mce_dev_initialized, GFP_KERNEL);
+
+	err = mce_init_banks();
+	if (err)
+		return err;
+
+	err = sysdev_class_register(&mce_sysclass);
+	if (err)
+		return err;
+
+	for_each_online_cpu(i) {
+		err = mce_create_device(i);
+		if (err)
+			return err;
+	}
+
+	register_hotcpu_notifier(&mce_cpu_notifier);
+	misc_register(&mce_log_device);
+
+	return err;
+}
+
+device_initcall(mce_init_device);
+
+#else /* CONFIG_X86_OLD_MCE: */
+
+int nr_mce_banks;
+EXPORT_SYMBOL_GPL(nr_mce_banks);	/* non-fatal.o */
+
+/* This has to be run for each processor */
+void mcheck_init(struct cpuinfo_x86 *c)
+{
+	if (mce_disabled == 1)
+		return;
+
+	switch (c->x86_vendor) {
+	case X86_VENDOR_AMD:
+		amd_mcheck_init(c);
+		break;
+
+	case X86_VENDOR_INTEL:
+		if (c->x86 == 5)
+			intel_p5_mcheck_init(c);
+		if (c->x86 == 6)
+			intel_p6_mcheck_init(c);
+		if (c->x86 == 15)
+			intel_p4_mcheck_init(c);
+		break;
+
+	case X86_VENDOR_CENTAUR:
+		if (c->x86 == 5)
+			winchip_mcheck_init(c);
+		break;
+
+	default:
+		break;
+	}
+	printk(KERN_INFO "mce: CPU supports %d MCE banks\n", nr_mce_banks);
+}
+
+static int __init mcheck_enable(char *str)
+{
+	mce_disabled = -1;
+	return 1;
+}
+
+__setup("mce", mcheck_enable);
+
+#endif /* CONFIG_X86_OLD_MCE */
+
+/*
+ * Old style boot options parsing. Only for compatibility.
+ */
+static int __init mcheck_disable(char *str)
+{
+	mce_disabled = 1;
+	return 1;
+}
+__setup("nomce", mcheck_disable);
diff --git a/arch/x86/kernel/cpu/mcheck/mce.h b/arch/x86/kernel/cpu/mcheck/mce.h
index ae9f628..84a552b 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.h
+++ b/arch/x86/kernel/cpu/mcheck/mce.h
@@ -1,14 +1,38 @@
 #include <linux/init.h>
 #include <asm/mce.h>
 
+#ifdef CONFIG_X86_OLD_MCE
 void amd_mcheck_init(struct cpuinfo_x86 *c);
 void intel_p4_mcheck_init(struct cpuinfo_x86 *c);
-void intel_p5_mcheck_init(struct cpuinfo_x86 *c);
 void intel_p6_mcheck_init(struct cpuinfo_x86 *c);
+#endif
+
+#ifdef CONFIG_X86_ANCIENT_MCE
+void intel_p5_mcheck_init(struct cpuinfo_x86 *c);
 void winchip_mcheck_init(struct cpuinfo_x86 *c);
+extern int mce_p5_enable;
+static inline int mce_p5_enabled(void) { return mce_p5_enable; }
+static inline void enable_p5_mce(void) { mce_p5_enable = 1; }
+#else
+static inline void intel_p5_mcheck_init(struct cpuinfo_x86 *c) {}
+static inline void winchip_mcheck_init(struct cpuinfo_x86 *c) {}
+static inline int mce_p5_enabled(void) { return 0; }
+static inline void enable_p5_mce(void) { }
+#endif
 
 /* Call the installed machine check handler for this CPU setup. */
 extern void (*machine_check_vector)(struct pt_regs *, long error_code);
 
+#ifdef CONFIG_X86_OLD_MCE
+
 extern int nr_mce_banks;
 
+void intel_set_thermal_handler(void);
+
+#else
+
+static inline void intel_set_thermal_handler(void) { }
+
+#endif
+
+void intel_init_thermal(struct cpuinfo_x86 *c);
diff --git a/arch/x86/kernel/cpu/mcheck/mce_32.c b/arch/x86/kernel/cpu/mcheck/mce_32.c
deleted file mode 100644
index 3552119..0000000
--- a/arch/x86/kernel/cpu/mcheck/mce_32.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * mce.c - x86 Machine Check Exception Reporting
- * (c) 2002 Alan Cox <alan@lxorguk.ukuu.org.uk>, Dave Jones <davej@redhat.com>
- */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/smp.h>
-#include <linux/thread_info.h>
-
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/mce.h>
-
-#include "mce.h"
-
-int mce_disabled;
-int nr_mce_banks;
-
-EXPORT_SYMBOL_GPL(nr_mce_banks);	/* non-fatal.o */
-
-/* Handle unconfigured int18 (should never happen) */
-static void unexpected_machine_check(struct pt_regs *regs, long error_code)
-{
-	printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", smp_processor_id());
-}
-
-/* Call the installed machine check handler for this CPU setup. */
-void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
-
-/* This has to be run for each processor */
-void mcheck_init(struct cpuinfo_x86 *c)
-{
-	if (mce_disabled == 1)
-		return;
-
-	switch (c->x86_vendor) {
-	case X86_VENDOR_AMD:
-		amd_mcheck_init(c);
-		break;
-
-	case X86_VENDOR_INTEL:
-		if (c->x86 == 5)
-			intel_p5_mcheck_init(c);
-		if (c->x86 == 6)
-			intel_p6_mcheck_init(c);
-		if (c->x86 == 15)
-			intel_p4_mcheck_init(c);
-		break;
-
-	case X86_VENDOR_CENTAUR:
-		if (c->x86 == 5)
-			winchip_mcheck_init(c);
-		break;
-
-	default:
-		break;
-	}
-}
-
-static int __init mcheck_disable(char *str)
-{
-	mce_disabled = 1;
-	return 1;
-}
-
-static int __init mcheck_enable(char *str)
-{
-	mce_disabled = -1;
-	return 1;
-}
-
-__setup("nomce", mcheck_disable);
-__setup("mce", mcheck_enable);
diff --git a/arch/x86/kernel/cpu/mcheck/mce_64.c b/arch/x86/kernel/cpu/mcheck/mce_64.c
deleted file mode 100644
index 289cc48..0000000
--- a/arch/x86/kernel/cpu/mcheck/mce_64.c
+++ /dev/null
@@ -1,1188 +0,0 @@
-/*
- * Machine check handler.
- * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs.
- * Rest from unknown author(s).
- * 2004 Andi Kleen. Rewrote most of it.
- * Copyright 2008 Intel Corporation
- * Author: Andi Kleen
- */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/string.h>
-#include <linux/rcupdate.h>
-#include <linux/kallsyms.h>
-#include <linux/sysdev.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-#include <linux/capability.h>
-#include <linux/cpu.h>
-#include <linux/percpu.h>
-#include <linux/poll.h>
-#include <linux/thread_info.h>
-#include <linux/ctype.h>
-#include <linux/kmod.h>
-#include <linux/kdebug.h>
-#include <linux/kobject.h>
-#include <linux/sysfs.h>
-#include <linux/ratelimit.h>
-#include <asm/processor.h>
-#include <asm/msr.h>
-#include <asm/mce.h>
-#include <asm/uaccess.h>
-#include <asm/smp.h>
-#include <asm/idle.h>
-
-#define MISC_MCELOG_MINOR 227
-
-atomic_t mce_entry;
-
-static int mce_dont_init;
-
-/*
- * Tolerant levels:
- *   0: always panic on uncorrected errors, log corrected errors
- *   1: panic or SIGBUS on uncorrected errors, log corrected errors
- *   2: SIGBUS or log uncorrected errors (if possible), log corrected errors
- *   3: never panic or SIGBUS, log all errors (for testing only)
- */
-static int tolerant = 1;
-static int banks;
-static u64 *bank;
-static unsigned long notify_user;
-static int rip_msr;
-static int mce_bootlog = -1;
-static atomic_t mce_events;
-
-static char trigger[128];
-static char *trigger_argv[2] = { trigger, NULL };
-
-static DECLARE_WAIT_QUEUE_HEAD(mce_wait);
-
-/* MCA banks polled by the period polling timer for corrected events */
-DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
-	[0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL
-};
-
-/* Do initial initialization of a struct mce */
-void mce_setup(struct mce *m)
-{
-	memset(m, 0, sizeof(struct mce));
-	m->cpu = smp_processor_id();
-	rdtscll(m->tsc);
-}
-
-/*
- * Lockless MCE logging infrastructure.
- * This avoids deadlocks on printk locks without having to break locks. Also
- * separate MCEs from kernel messages to avoid bogus bug reports.
- */
-
-static struct mce_log mcelog = {
-	MCE_LOG_SIGNATURE,
-	MCE_LOG_LEN,
-};
-
-void mce_log(struct mce *mce)
-{
-	unsigned next, entry;
-	atomic_inc(&mce_events);
-	mce->finished = 0;
-	wmb();
-	for (;;) {
-		entry = rcu_dereference(mcelog.next);
-		for (;;) {
-			/* When the buffer fills up discard new entries. Assume
-			   that the earlier errors are the more interesting. */
-			if (entry >= MCE_LOG_LEN) {
-				set_bit(MCE_OVERFLOW, (unsigned long *)&mcelog.flags);
-				return;
-			}
-			/* Old left over entry. Skip. */
-			if (mcelog.entry[entry].finished) {
-				entry++;
-				continue;
-			}
-			break;
-		}
-		smp_rmb();
-		next = entry + 1;
-		if (cmpxchg(&mcelog.next, entry, next) == entry)
-			break;
-	}
-	memcpy(mcelog.entry + entry, mce, sizeof(struct mce));
-	wmb();
-	mcelog.entry[entry].finished = 1;
-	wmb();
-
-	set_bit(0, &notify_user);
-}
-
-static void print_mce(struct mce *m)
-{
-	printk(KERN_EMERG "\n"
-	       KERN_EMERG "HARDWARE ERROR\n"
-	       KERN_EMERG
-	       "CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n",
-	       m->cpu, m->mcgstatus, m->bank, m->status);
-	if (m->ip) {
-		printk(KERN_EMERG "RIP%s %02x:<%016Lx> ",
-		       !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "",
-		       m->cs, m->ip);
-		if (m->cs == __KERNEL_CS)
-			print_symbol("{%s}", m->ip);
-		printk("\n");
-	}
-	printk(KERN_EMERG "TSC %llx ", m->tsc);
-	if (m->addr)
-		printk("ADDR %llx ", m->addr);
-	if (m->misc)
-		printk("MISC %llx ", m->misc);
-	printk("\n");
-	printk(KERN_EMERG "This is not a software problem!\n");
-	printk(KERN_EMERG "Run through mcelog --ascii to decode "
-	       "and contact your hardware vendor\n");
-}
-
-static void mce_panic(char *msg, struct mce *backup, unsigned long start)
-{
-	int i;
-
-	oops_begin();
-	for (i = 0; i < MCE_LOG_LEN; i++) {
-		unsigned long tsc = mcelog.entry[i].tsc;
-
-		if (time_before(tsc, start))
-			continue;
-		print_mce(&mcelog.entry[i]);
-		if (backup && mcelog.entry[i].tsc == backup->tsc)
-			backup = NULL;
-	}
-	if (backup)
-		print_mce(backup);
-	panic(msg);
-}
-
-int mce_available(struct cpuinfo_x86 *c)
-{
-	if (mce_dont_init)
-		return 0;
-	return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA);
-}
-
-static inline void mce_get_rip(struct mce *m, struct pt_regs *regs)
-{
-	if (regs && (m->mcgstatus & MCG_STATUS_RIPV)) {
-		m->ip = regs->ip;
-		m->cs = regs->cs;
-	} else {
-		m->ip = 0;
-		m->cs = 0;
-	}
-	if (rip_msr) {
-		/* Assume the RIP in the MSR is exact. Is this true? */
-		m->mcgstatus |= MCG_STATUS_EIPV;
-		rdmsrl(rip_msr, m->ip);
-		m->cs = 0;
-	}
-}
-
-/*
- * Poll for corrected events or events that happened before reset.
- * Those are just logged through /dev/mcelog.
- *
- * This is executed in standard interrupt context.
- */
-void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
-{
-	struct mce m;
-	int i;
-
-	mce_setup(&m);
-
-	rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
-	for (i = 0; i < banks; i++) {
-		if (!bank[i] || !test_bit(i, *b))
-			continue;
-
-		m.misc = 0;
-		m.addr = 0;
-		m.bank = i;
-		m.tsc = 0;
-
-		barrier();
-		rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status);
-		if (!(m.status & MCI_STATUS_VAL))
-			continue;
-
-		/*
-		 * Uncorrected events are handled by the exception handler
-		 * when it is enabled. But when the exception is disabled log
-		 * everything.
-		 *
-		 * TBD do the same check for MCI_STATUS_EN here?
-		 */
-		if ((m.status & MCI_STATUS_UC) && !(flags & MCP_UC))
-			continue;
-
-		if (m.status & MCI_STATUS_MISCV)
-			rdmsrl(MSR_IA32_MC0_MISC + i*4, m.misc);
-		if (m.status & MCI_STATUS_ADDRV)
-			rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr);
-
-		if (!(flags & MCP_TIMESTAMP))
-			m.tsc = 0;
-		/*
-		 * Don't get the IP here because it's unlikely to
-		 * have anything to do with the actual error location.
-		 */
-		if (!(flags & MCP_DONTLOG)) {
-			mce_log(&m);
-			add_taint(TAINT_MACHINE_CHECK);
-		}
-
-		/*
-		 * Clear state for this bank.
-		 */
-		wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
-	}
-
-	/*
-	 * Don't clear MCG_STATUS here because it's only defined for
-	 * exceptions.
-	 */
-}
-
-/*
- * The actual machine check handler. This only handles real
- * exceptions when something got corrupted coming in through int 18.
- *
- * This is executed in NMI context not subject to normal locking rules. This
- * implies that most kernel services cannot be safely used. Don't even
- * think about putting a printk in there!
- */
-void do_machine_check(struct pt_regs * regs, long error_code)
-{
-	struct mce m, panicm;
-	u64 mcestart = 0;
-	int i;
-	int panicm_found = 0;
-	/*
-	 * If no_way_out gets set, there is no safe way to recover from this
-	 * MCE.  If tolerant is cranked up, we'll try anyway.
-	 */
-	int no_way_out = 0;
-	/*
-	 * If kill_it gets set, there might be a way to recover from this
-	 * error.
-	 */
-	int kill_it = 0;
-	DECLARE_BITMAP(toclear, MAX_NR_BANKS);
-
-	atomic_inc(&mce_entry);
-
-	if (notify_die(DIE_NMI, "machine check", regs, error_code,
-			   18, SIGKILL) == NOTIFY_STOP)
-		goto out2;
-	if (!banks)
-		goto out2;
-
-	mce_setup(&m);
-
-	rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
-	/* if the restart IP is not valid, we're done for */
-	if (!(m.mcgstatus & MCG_STATUS_RIPV))
-		no_way_out = 1;
-
-	rdtscll(mcestart);
-	barrier();
-
-	for (i = 0; i < banks; i++) {
-		__clear_bit(i, toclear);
-		if (!bank[i])
-			continue;
-
-		m.misc = 0;
-		m.addr = 0;
-		m.bank = i;
-
-		rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status);
-		if ((m.status & MCI_STATUS_VAL) == 0)
-			continue;
-
-		/*
-		 * Non uncorrected errors are handled by machine_check_poll
-		 * Leave them alone.
-		 */
-		if ((m.status & MCI_STATUS_UC) == 0)
-			continue;
-
-		/*
-		 * Set taint even when machine check was not enabled.
-		 */
-		add_taint(TAINT_MACHINE_CHECK);
-
-		__set_bit(i, toclear);
-
-		if (m.status & MCI_STATUS_EN) {
-			/* if PCC was set, there's no way out */
-			no_way_out |= !!(m.status & MCI_STATUS_PCC);
-			/*
-			 * If this error was uncorrectable and there was
-			 * an overflow, we're in trouble.  If no overflow,
-			 * we might get away with just killing a task.
-			 */
-			if (m.status & MCI_STATUS_UC) {
-				if (tolerant < 1 || m.status & MCI_STATUS_OVER)
-					no_way_out = 1;
-				kill_it = 1;
-			}
-		} else {
-			/*
-			 * Machine check event was not enabled. Clear, but
-			 * ignore.
-			 */
-			continue;
-		}
-
-		if (m.status & MCI_STATUS_MISCV)
-			rdmsrl(MSR_IA32_MC0_MISC + i*4, m.misc);
-		if (m.status & MCI_STATUS_ADDRV)
-			rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr);
-
-		mce_get_rip(&m, regs);
-		mce_log(&m);
-
-		/* Did this bank cause the exception? */
-		/* Assume that the bank with uncorrectable errors did it,
-		   and that there is only a single one. */
-		if ((m.status & MCI_STATUS_UC) && (m.status & MCI_STATUS_EN)) {
-			panicm = m;
-			panicm_found = 1;
-		}
-	}
-
-	/* If we didn't find an uncorrectable error, pick
-	   the last one (shouldn't happen, just being safe). */
-	if (!panicm_found)
-		panicm = m;
-
-	/*
-	 * 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.
-	 */
-	if (no_way_out && tolerant < 3)
-		mce_panic("Machine check", &panicm, mcestart);
-
-	/*
-	 * 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) {
-		int user_space = 0;
-
-		/*
-		 * If the EIPV bit is set, it means the saved IP is the
-		 * instruction which caused the MCE.
-		 */
-		if (m.mcgstatus & MCG_STATUS_EIPV)
-			user_space = panicm.ip && (panicm.cs & 3);
-
-		/*
-		 * If we know that the error was in user space, send a
-		 * SIGBUS.  Otherwise, panic if tolerance is low.
-		 *
-		 * force_sig() takes an awful lot of locks and has a slight
-		 * risk of deadlocking.
-		 */
-		if (user_space) {
-			force_sig(SIGBUS, current);
-		} else if (panic_on_oops || tolerant < 2) {
-			mce_panic("Uncorrected machine check",
-				&panicm, mcestart);
-		}
-	}
-
-	/* notify userspace ASAP */
-	set_thread_flag(TIF_MCE_NOTIFY);
-
-	/* the last thing we do is clear state */
-	for (i = 0; i < banks; i++) {
-		if (test_bit(i, toclear))
-			wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
-	}
-	wrmsrl(MSR_IA32_MCG_STATUS, 0);
- out2:
-	atomic_dec(&mce_entry);
-}
-EXPORT_SYMBOL_GPL(do_machine_check);
-
-#ifdef CONFIG_X86_MCE_INTEL
-/***
- * mce_log_therm_throt_event - Logs the thermal throttling event to mcelog
- * @cpu: The CPU on which the event occurred.
- * @status: Event status information
- *
- * This function should be called by the thermal interrupt after the
- * event has been processed and the decision was made to log the event
- * further.
- *
- * The status parameter will be saved to the 'status' field of 'struct mce'
- * and historically has been the register value of the
- * MSR_IA32_THERMAL_STATUS (Intel) msr.
- */
-void mce_log_therm_throt_event(__u64 status)
-{
-	struct mce m;
-
-	mce_setup(&m);
-	m.bank = MCE_THERMAL_BANK;
-	m.status = status;
-	mce_log(&m);
-}
-#endif /* CONFIG_X86_MCE_INTEL */
-
-/*
- * Periodic polling timer for "silent" machine check errors.  If the
- * poller finds an MCE, poll 2x faster.  When the poller finds no more
- * errors, poll 2x slower (up to check_interval seconds).
- */
-
-static int check_interval = 5 * 60; /* 5 minutes */
-static DEFINE_PER_CPU(int, next_interval); /* in jiffies */
-static void mcheck_timer(unsigned long);
-static DEFINE_PER_CPU(struct timer_list, mce_timer);
-
-static void mcheck_timer(unsigned long data)
-{
-	struct timer_list *t = &per_cpu(mce_timer, data);
-	int *n;
-
-	WARN_ON(smp_processor_id() != data);
-
-	if (mce_available(&current_cpu_data))
-		machine_check_poll(MCP_TIMESTAMP,
-				&__get_cpu_var(mce_poll_banks));
-
-	/*
-	 * Alert userspace if needed.  If we logged an MCE, reduce the
-	 * polling interval, otherwise increase the polling interval.
-	 */
-	n = &__get_cpu_var(next_interval);
-	if (mce_notify_user()) {
-		*n = max(*n/2, HZ/100);
-	} else {
-		*n = min(*n*2, (int)round_jiffies_relative(check_interval*HZ));
-	}
-
-	t->expires = jiffies + *n;
-	add_timer(t);
-}
-
-static void mce_do_trigger(struct work_struct *work)
-{
-	call_usermodehelper(trigger, trigger_argv, NULL, UMH_NO_WAIT);
-}
-
-static DECLARE_WORK(mce_trigger_work, mce_do_trigger);
-
-/*
- * Notify the user(s) about new machine check events.
- * Can be called from interrupt context, but not from machine check/NMI
- * context.
- */
-int mce_notify_user(void)
-{
-	/* 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, &notify_user)) {
-		wake_up_interruptible(&mce_wait);
-
-		/*
-		 * There is no risk of missing notifications because
-		 * work_pending is always cleared before the function is
-		 * executed.
-		 */
-		if (trigger[0] && !work_pending(&mce_trigger_work))
-			schedule_work(&mce_trigger_work);
-
-		if (__ratelimit(&ratelimit))
-			printk(KERN_INFO "Machine check events logged\n");
-
-		return 1;
-	}
-	return 0;
-}
-
-/* see if the idle task needs to notify userspace */
-static int
-mce_idle_callback(struct notifier_block *nfb, unsigned long action, void *junk)
-{
-	/* IDLE_END should be safe - interrupts are back on */
-	if (action == IDLE_END && test_thread_flag(TIF_MCE_NOTIFY))
-		mce_notify_user();
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block mce_idle_notifier = {
-	.notifier_call = mce_idle_callback,
-};
-
-static __init int periodic_mcheck_init(void)
-{
-       idle_notifier_register(&mce_idle_notifier);
-       return 0;
-}
-__initcall(periodic_mcheck_init);
-
-/*
- * Initialize Machine Checks for a CPU.
- */
-static int mce_cap_init(void)
-{
-	u64 cap;
-	unsigned b;
-
-	rdmsrl(MSR_IA32_MCG_CAP, cap);
-	b = cap & 0xff;
-	if (b > MAX_NR_BANKS) {
-		printk(KERN_WARNING
-		       "MCE: Using only %u machine check banks out of %u\n",
-			MAX_NR_BANKS, b);
-		b = MAX_NR_BANKS;
-	}
-
-	/* Don't support asymmetric configurations today */
-	WARN_ON(banks != 0 && b != banks);
-	banks = b;
-	if (!bank) {
-		bank = kmalloc(banks * sizeof(u64), GFP_KERNEL);
-		if (!bank)
-			return -ENOMEM;
-		memset(bank, 0xff, banks * sizeof(u64));
-	}
-
-	/* Use accurate RIP reporting if available. */
-	if ((cap & (1<<9)) && ((cap >> 16) & 0xff) >= 9)
-		rip_msr = MSR_IA32_MCG_EIP;
-
-	return 0;
-}
-
-static void mce_init(void *dummy)
-{
-	u64 cap;
-	int i;
-	mce_banks_t all_banks;
-
-	/*
-	 * Log the machine checks left over from the previous reset.
-	 */
-	bitmap_fill(all_banks, MAX_NR_BANKS);
-	machine_check_poll(MCP_UC|(!mce_bootlog ? MCP_DONTLOG : 0), &all_banks);
-
-	set_in_cr4(X86_CR4_MCE);
-
-	rdmsrl(MSR_IA32_MCG_CAP, cap);
-	if (cap & MCG_CTL_P)
-		wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
-
-	for (i = 0; i < banks; i++) {
-		wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
-		wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
-	}
-}
-
-/* Add per CPU specific workarounds here */
-static void mce_cpu_quirks(struct cpuinfo_x86 *c)
-{
-	/* This should be disabled by the BIOS, but isn't always */
-	if (c->x86_vendor == X86_VENDOR_AMD) {
-		if (c->x86 == 15 && banks > 4)
-			/* disable GART TBL walk error reporting, which trips off
-			   incorrectly with the IOMMU & 3ware & Cerberus. */
-			clear_bit(10, (unsigned long *)&bank[4]);
-		if(c->x86 <= 17 && mce_bootlog < 0)
-			/* Lots of broken BIOS around that don't clear them
-			   by default and leave crap in there. Don't log. */
-			mce_bootlog = 0;
-	}
-
-}
-
-static void mce_cpu_features(struct cpuinfo_x86 *c)
-{
-	switch (c->x86_vendor) {
-	case X86_VENDOR_INTEL:
-		mce_intel_feature_init(c);
-		break;
-	case X86_VENDOR_AMD:
-		mce_amd_feature_init(c);
-		break;
-	default:
-		break;
-	}
-}
-
-static void mce_init_timer(void)
-{
-	struct timer_list *t = &__get_cpu_var(mce_timer);
-	int *n = &__get_cpu_var(next_interval);
-
-	*n = check_interval * HZ;
-	if (!*n)
-		return;
-	setup_timer(t, mcheck_timer, smp_processor_id());
-	t->expires = round_jiffies(jiffies + *n);
-	add_timer(t);
-}
-
-/*
- * Called for each booted CPU to set up machine checks.
- * Must be called with preempt off.
- */
-void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
-{
-	if (!mce_available(c))
-		return;
-
-	if (mce_cap_init() < 0) {
-		mce_dont_init = 1;
-		return;
-	}
-	mce_cpu_quirks(c);
-
-	mce_init(NULL);
-	mce_cpu_features(c);
-	mce_init_timer();
-}
-
-/*
- * Character device to read and clear the MCE log.
- */
-
-static DEFINE_SPINLOCK(mce_state_lock);
-static int open_count;	/* #times opened */
-static int open_exclu;	/* already open exclusive? */
-
-static int mce_open(struct inode *inode, struct file *file)
-{
-	lock_kernel();
-	spin_lock(&mce_state_lock);
-
-	if (open_exclu || (open_count && (file->f_flags & O_EXCL))) {
-		spin_unlock(&mce_state_lock);
-		unlock_kernel();
-		return -EBUSY;
-	}
-
-	if (file->f_flags & O_EXCL)
-		open_exclu = 1;
-	open_count++;
-
-	spin_unlock(&mce_state_lock);
-	unlock_kernel();
-
-	return nonseekable_open(inode, file);
-}
-
-static int mce_release(struct inode *inode, struct file *file)
-{
-	spin_lock(&mce_state_lock);
-
-	open_count--;
-	open_exclu = 0;
-
-	spin_unlock(&mce_state_lock);
-
-	return 0;
-}
-
-static void collect_tscs(void *data)
-{
-	unsigned long *cpu_tsc = (unsigned long *)data;
-
-	rdtscll(cpu_tsc[smp_processor_id()]);
-}
-
-static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize,
-			loff_t *off)
-{
-	unsigned long *cpu_tsc;
-	static DEFINE_MUTEX(mce_read_mutex);
-	unsigned prev, next;
-	char __user *buf = ubuf;
-	int i, err;
-
-	cpu_tsc = kmalloc(nr_cpu_ids * sizeof(long), GFP_KERNEL);
-	if (!cpu_tsc)
-		return -ENOMEM;
-
-	mutex_lock(&mce_read_mutex);
-	next = rcu_dereference(mcelog.next);
-
-	/* Only supports full reads right now */
-	if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) {
-		mutex_unlock(&mce_read_mutex);
-		kfree(cpu_tsc);
-		return -EINVAL;
-	}
-
-	err = 0;
-	prev = 0;
-	do {
-		for (i = prev; i < next; i++) {
-			unsigned long start = jiffies;
-
-			while (!mcelog.entry[i].finished) {
-				if (time_after_eq(jiffies, start + 2)) {
-					memset(mcelog.entry + i, 0,
-					       sizeof(struct mce));
-					goto timeout;
-				}
-				cpu_relax();
-			}
-			smp_rmb();
-			err |= copy_to_user(buf, mcelog.entry + i,
-					    sizeof(struct mce));
-			buf += sizeof(struct mce);
-timeout:
-			;
-		}
-
-		memset(mcelog.entry + prev, 0,
-		       (next - prev) * sizeof(struct mce));
-		prev = next;
-		next = cmpxchg(&mcelog.next, prev, 0);
-	} while (next != prev);
-
-	synchronize_sched();
-
-	/*
-	 * Collect entries that were still getting written before the
-	 * synchronize.
-	 */
-	on_each_cpu(collect_tscs, cpu_tsc, 1);
-	for (i = next; i < MCE_LOG_LEN; i++) {
-		if (mcelog.entry[i].finished &&
-		    mcelog.entry[i].tsc < cpu_tsc[mcelog.entry[i].cpu]) {
-			err |= copy_to_user(buf, mcelog.entry+i,
-					    sizeof(struct mce));
-			smp_rmb();
-			buf += sizeof(struct mce);
-			memset(&mcelog.entry[i], 0, sizeof(struct mce));
-		}
-	}
-	mutex_unlock(&mce_read_mutex);
-	kfree(cpu_tsc);
-	return err ? -EFAULT : buf - ubuf;
-}
-
-static unsigned int mce_poll(struct file *file, poll_table *wait)
-{
-	poll_wait(file, &mce_wait, wait);
-	if (rcu_dereference(mcelog.next))
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-static long mce_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
-{
-	int __user *p = (int __user *)arg;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	switch (cmd) {
-	case MCE_GET_RECORD_LEN:
-		return put_user(sizeof(struct mce), p);
-	case MCE_GET_LOG_LEN:
-		return put_user(MCE_LOG_LEN, p);
-	case MCE_GETCLEAR_FLAGS: {
-		unsigned flags;
-
-		do {
-			flags = mcelog.flags;
-		} while (cmpxchg(&mcelog.flags, flags, 0) != flags);
-		return put_user(flags, p);
-	}
-	default:
-		return -ENOTTY;
-	}
-}
-
-static const struct file_operations mce_chrdev_ops = {
-	.open = mce_open,
-	.release = mce_release,
-	.read = mce_read,
-	.poll = mce_poll,
-	.unlocked_ioctl = mce_ioctl,
-};
-
-static struct miscdevice mce_log_device = {
-	MISC_MCELOG_MINOR,
-	"mcelog",
-	&mce_chrdev_ops,
-};
-
-/*
- * Old style boot options parsing. Only for compatibility.
- */
-static int __init mcheck_disable(char *str)
-{
-	mce_dont_init = 1;
-	return 1;
-}
-
-/* mce=off disables machine check.
-   mce=TOLERANCELEVEL (number, see above)
-   mce=bootlog Log MCEs from before booting. Disabled by default on AMD.
-   mce=nobootlog Don't log MCEs from before booting. */
-static int __init mcheck_enable(char *str)
-{
-	if (!strcmp(str, "off"))
-		mce_dont_init = 1;
-	else if (!strcmp(str, "bootlog") || !strcmp(str,"nobootlog"))
-		mce_bootlog = str[0] == 'b';
-	else if (isdigit(str[0]))
-		get_option(&str, &tolerant);
-	else
-		printk("mce= argument %s ignored. Please use /sys", str);
-	return 1;
-}
-
-__setup("nomce", mcheck_disable);
-__setup("mce=", mcheck_enable);
-
-/*
- * Sysfs support
- */
-
-/*
- * Disable machine checks on suspend and shutdown. We can't really handle
- * them later.
- */
-static int mce_disable(void)
-{
-	int i;
-
-	for (i = 0; i < banks; i++)
-		wrmsrl(MSR_IA32_MC0_CTL + i*4, 0);
-	return 0;
-}
-
-static int mce_suspend(struct sys_device *dev, pm_message_t state)
-{
-	return mce_disable();
-}
-
-static int mce_shutdown(struct sys_device *dev)
-{
-	return mce_disable();
-}
-
-/* On resume clear all MCE state. Don't want to see leftovers from the BIOS.
-   Only one CPU is active at this time, the others get readded later using
-   CPU hotplug. */
-static int mce_resume(struct sys_device *dev)
-{
-	mce_init(NULL);
-	mce_cpu_features(&current_cpu_data);
-	return 0;
-}
-
-static void mce_cpu_restart(void *data)
-{
-	del_timer_sync(&__get_cpu_var(mce_timer));
-	if (mce_available(&current_cpu_data))
-		mce_init(NULL);
-	mce_init_timer();
-}
-
-/* Reinit MCEs after user configuration changes */
-static void mce_restart(void)
-{
-	on_each_cpu(mce_cpu_restart, NULL, 1);
-}
-
-static struct sysdev_class mce_sysclass = {
-	.suspend = mce_suspend,
-	.shutdown = mce_shutdown,
-	.resume = mce_resume,
-	.name = "machinecheck",
-};
-
-DEFINE_PER_CPU(struct sys_device, device_mce);
-void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu) __cpuinitdata;
-
-/* Why are there no generic functions for this? */
-#define ACCESSOR(name, var, start) \
-	static ssize_t show_ ## name(struct sys_device *s,		\
-				     struct sysdev_attribute *attr,	\
-				     char *buf) {			\
-		return sprintf(buf, "%lx\n", (unsigned long)var);	\
-	}								\
-	static ssize_t set_ ## name(struct sys_device *s,		\
-				    struct sysdev_attribute *attr,	\
-				    const char *buf, size_t siz) {	\
-		char *end;						\
-		unsigned long new = simple_strtoul(buf, &end, 0);	\
-		if (end == buf) return -EINVAL;				\
-		var = new;						\
-		start;							\
-		return end-buf;						\
-	}								\
-	static SYSDEV_ATTR(name, 0644, show_ ## name, set_ ## name);
-
-static struct sysdev_attribute *bank_attrs;
-
-static ssize_t show_bank(struct sys_device *s, struct sysdev_attribute *attr,
-			 char *buf)
-{
-	u64 b = bank[attr - bank_attrs];
-	return sprintf(buf, "%llx\n", b);
-}
-
-static ssize_t set_bank(struct sys_device *s, struct sysdev_attribute *attr,
-			const char *buf, size_t siz)
-{
-	char *end;
-	u64 new = simple_strtoull(buf, &end, 0);
-	if (end == buf)
-		return -EINVAL;
-	bank[attr - bank_attrs] = new;
-	mce_restart();
-	return end-buf;
-}
-
-static ssize_t show_trigger(struct sys_device *s, struct sysdev_attribute *attr,
-				char *buf)
-{
-	strcpy(buf, trigger);
-	strcat(buf, "\n");
-	return strlen(trigger) + 1;
-}
-
-static ssize_t set_trigger(struct sys_device *s, struct sysdev_attribute *attr,
-				const char *buf,size_t siz)
-{
-	char *p;
-	int len;
-	strncpy(trigger, buf, sizeof(trigger));
-	trigger[sizeof(trigger)-1] = 0;
-	len = strlen(trigger);
-	p = strchr(trigger, '\n');
-	if (*p) *p = 0;
-	return len;
-}
-
-static SYSDEV_ATTR(trigger, 0644, show_trigger, set_trigger);
-static SYSDEV_INT_ATTR(tolerant, 0644, tolerant);
-ACCESSOR(check_interval,check_interval,mce_restart())
-static struct sysdev_attribute *mce_attributes[] = {
-	&attr_tolerant.attr, &attr_check_interval, &attr_trigger,
-	NULL
-};
-
-static cpumask_var_t mce_device_initialized;
-
-/* Per cpu sysdev init.  All of the cpus still share the same ctl bank */
-static __cpuinit int mce_create_device(unsigned int cpu)
-{
-	int err;
-	int i;
-
-	if (!mce_available(&boot_cpu_data))
-		return -EIO;
-
-	memset(&per_cpu(device_mce, cpu).kobj, 0, sizeof(struct kobject));
-	per_cpu(device_mce,cpu).id = cpu;
-	per_cpu(device_mce,cpu).cls = &mce_sysclass;
-
-	err = sysdev_register(&per_cpu(device_mce,cpu));
-	if (err)
-		return err;
-
-	for (i = 0; mce_attributes[i]; i++) {
-		err = sysdev_create_file(&per_cpu(device_mce,cpu),
-					 mce_attributes[i]);
-		if (err)
-			goto error;
-	}
-	for (i = 0; i < banks; i++) {
-		err = sysdev_create_file(&per_cpu(device_mce, cpu),
-					&bank_attrs[i]);
-		if (err)
-			goto error2;
-	}
-	cpumask_set_cpu(cpu, mce_device_initialized);
-
-	return 0;
-error2:
-	while (--i >= 0) {
-		sysdev_remove_file(&per_cpu(device_mce, cpu),
-					&bank_attrs[i]);
-	}
-error:
-	while (--i >= 0) {
-		sysdev_remove_file(&per_cpu(device_mce,cpu),
-				   mce_attributes[i]);
-	}
-	sysdev_unregister(&per_cpu(device_mce,cpu));
-
-	return err;
-}
-
-static __cpuinit void mce_remove_device(unsigned int cpu)
-{
-	int i;
-
-	if (!cpumask_test_cpu(cpu, mce_device_initialized))
-		return;
-
-	for (i = 0; mce_attributes[i]; i++)
-		sysdev_remove_file(&per_cpu(device_mce,cpu),
-			mce_attributes[i]);
-	for (i = 0; i < banks; i++)
-		sysdev_remove_file(&per_cpu(device_mce, cpu),
-			&bank_attrs[i]);
-	sysdev_unregister(&per_cpu(device_mce,cpu));
-	cpumask_clear_cpu(cpu, mce_device_initialized);
-}
-
-/* Make sure there are no machine checks on offlined CPUs. */
-static void mce_disable_cpu(void *h)
-{
-	int i;
-	unsigned long action = *(unsigned long *)h;
-
-	if (!mce_available(&current_cpu_data))
-		return;
-	if (!(action & CPU_TASKS_FROZEN))
-		cmci_clear();
-	for (i = 0; i < banks; i++)
-		wrmsrl(MSR_IA32_MC0_CTL + i*4, 0);
-}
-
-static void mce_reenable_cpu(void *h)
-{
-	int i;
-	unsigned long action = *(unsigned long *)h;
-
-	if (!mce_available(&current_cpu_data))
-		return;
-	if (!(action & CPU_TASKS_FROZEN))
-		cmci_reenable();
-	for (i = 0; i < banks; i++)
-		wrmsrl(MSR_IA32_MC0_CTL + i*4, bank[i]);
-}
-
-/* Get notified when a cpu comes on/off. Be hotplug friendly. */
-static int __cpuinit mce_cpu_callback(struct notifier_block *nfb,
-				      unsigned long action, void *hcpu)
-{
-	unsigned int cpu = (unsigned long)hcpu;
-	struct timer_list *t = &per_cpu(mce_timer, cpu);
-
-	switch (action) {
-	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
-		mce_create_device(cpu);
-		if (threshold_cpu_callback)
-			threshold_cpu_callback(action, cpu);
-		break;
-	case CPU_DEAD:
-	case CPU_DEAD_FROZEN:
-		if (threshold_cpu_callback)
-			threshold_cpu_callback(action, cpu);
-		mce_remove_device(cpu);
-		break;
-	case CPU_DOWN_PREPARE:
-	case CPU_DOWN_PREPARE_FROZEN:
-		del_timer_sync(t);
-		smp_call_function_single(cpu, mce_disable_cpu, &action, 1);
-		break;
-	case CPU_DOWN_FAILED:
-	case CPU_DOWN_FAILED_FROZEN:
-		t->expires = round_jiffies(jiffies +
-						__get_cpu_var(next_interval));
-		add_timer_on(t, cpu);
-		smp_call_function_single(cpu, mce_reenable_cpu, &action, 1);
-		break;
-	case CPU_POST_DEAD:
-		/* intentionally ignoring frozen here */
-		cmci_rediscover(cpu);
-		break;
-	}
-	return NOTIFY_OK;
-}
-
-static struct notifier_block mce_cpu_notifier __cpuinitdata = {
-	.notifier_call = mce_cpu_callback,
-};
-
-static __init int mce_init_banks(void)
-{
-	int i;
-
-	bank_attrs = kzalloc(sizeof(struct sysdev_attribute) * banks,
-				GFP_KERNEL);
-	if (!bank_attrs)
-		return -ENOMEM;
-
-	for (i = 0; i < banks; i++) {
-		struct sysdev_attribute *a = &bank_attrs[i];
-		a->attr.name = kasprintf(GFP_KERNEL, "bank%d", i);
-		if (!a->attr.name)
-			goto nomem;
-		a->attr.mode = 0644;
-		a->show = show_bank;
-		a->store = set_bank;
-	}
-	return 0;
-
-nomem:
-	while (--i >= 0)
-		kfree(bank_attrs[i].attr.name);
-	kfree(bank_attrs);
-	bank_attrs = NULL;
-	return -ENOMEM;
-}
-
-static __init int mce_init_device(void)
-{
-	int err;
-	int i = 0;
-
-	if (!mce_available(&boot_cpu_data))
-		return -EIO;
-
-	zalloc_cpumask_var(&mce_device_initialized, GFP_KERNEL);
-
-	err = mce_init_banks();
-	if (err)
-		return err;
-
-	err = sysdev_class_register(&mce_sysclass);
-	if (err)
-		return err;
-
-	for_each_online_cpu(i) {
-		err = mce_create_device(i);
-		if (err)
-			return err;
-	}
-
-	register_hotcpu_notifier(&mce_cpu_notifier);
-	misc_register(&mce_log_device);
-	return err;
-}
-
-device_initcall(mce_init_device);
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd_64.c b/arch/x86/kernel/cpu/mcheck/mce_amd_64.c
index 56dde9c..ddae216 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd_64.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd_64.c
@@ -13,22 +13,22 @@
  *
  *  All MC4_MISCi registers are shared between multi-cores
  */
-
-#include <linux/cpu.h>
-#include <linux/errno.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/kobject.h>
 #include <linux/notifier.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
+#include <linux/kobject.h>
+#include <linux/percpu.h>
 #include <linux/sysdev.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
 #include <linux/sysfs.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+
 #include <asm/apic.h>
+#include <asm/idle.h>
 #include <asm/mce.h>
 #include <asm/msr.h>
-#include <asm/percpu.h>
-#include <asm/idle.h>
 
 #define PFX               "mce_threshold: "
 #define VERSION           "version 1.1.1"
@@ -48,26 +48,26 @@
 #define MCG_XBLK_ADDR     0xC0000400
 
 struct threshold_block {
-	unsigned int block;
-	unsigned int bank;
-	unsigned int cpu;
-	u32 address;
-	u16 interrupt_enable;
-	u16 threshold_limit;
-	struct kobject kobj;
-	struct list_head miscj;
+	unsigned int		block;
+	unsigned int		bank;
+	unsigned int		cpu;
+	u32			address;
+	u16			interrupt_enable;
+	u16			threshold_limit;
+	struct kobject		kobj;
+	struct list_head	miscj;
 };
 
 /* defaults used early on boot */
 static struct threshold_block threshold_defaults = {
-	.interrupt_enable = 0,
-	.threshold_limit = THRESHOLD_MAX,
+	.interrupt_enable	= 0,
+	.threshold_limit	= THRESHOLD_MAX,
 };
 
 struct threshold_bank {
-	struct kobject *kobj;
-	struct threshold_block *blocks;
-	cpumask_var_t cpus;
+	struct kobject		*kobj;
+	struct threshold_block	*blocks;
+	cpumask_var_t		cpus;
 };
 static DEFINE_PER_CPU(struct threshold_bank *, threshold_banks[NR_BANKS]);
 
@@ -86,9 +86,9 @@
  */
 
 struct thresh_restart {
-	struct threshold_block *b;
-	int reset;
-	u16 old_limit;
+	struct threshold_block	*b;
+	int			reset;
+	u16			old_limit;
 };
 
 /* must be called with correct cpu affinity */
@@ -110,6 +110,7 @@
 	} else if (tr->old_limit) {	/* change limit w/o reset */
 		int new_count = (mci_misc_hi & THRESHOLD_MAX) +
 		    (tr->old_limit - tr->b->threshold_limit);
+
 		mci_misc_hi = (mci_misc_hi & ~MASK_ERR_COUNT_HI) |
 		    (new_count & THRESHOLD_MAX);
 	}
@@ -125,11 +126,11 @@
 /* cpu init entry point, called from mce.c with preempt off */
 void mce_amd_feature_init(struct cpuinfo_x86 *c)
 {
-	unsigned int bank, block;
 	unsigned int cpu = smp_processor_id();
-	u8 lvt_off;
 	u32 low = 0, high = 0, address = 0;
+	unsigned int bank, block;
 	struct thresh_restart tr;
+	u8 lvt_off;
 
 	for (bank = 0; bank < NR_BANKS; ++bank) {
 		for (block = 0; block < NR_BLOCKS; ++block) {
@@ -140,8 +141,7 @@
 				if (!address)
 					break;
 				address += MCG_XBLK_ADDR;
-			}
-			else
+			} else
 				++address;
 
 			if (rdmsr_safe(address, &low, &high))
@@ -193,9 +193,9 @@
  */
 static void amd_threshold_interrupt(void)
 {
+	u32 low = 0, high = 0, address = 0;
 	unsigned int bank, block;
 	struct mce m;
-	u32 low = 0, high = 0, address = 0;
 
 	mce_setup(&m);
 
@@ -204,16 +204,16 @@
 		if (!(per_cpu(bank_map, m.cpu) & (1 << bank)))
 			continue;
 		for (block = 0; block < NR_BLOCKS; ++block) {
-			if (block == 0)
+			if (block == 0) {
 				address = MSR_IA32_MC0_MISC + bank * 4;
-			else if (block == 1) {
+			} else if (block == 1) {
 				address = (low & MASK_BLKPTR_LO) >> 21;
 				if (!address)
 					break;
 				address += MCG_XBLK_ADDR;
-			}
-			else
+			} else {
 				++address;
+			}
 
 			if (rdmsr_safe(address, &low, &high))
 				break;
@@ -229,8 +229,10 @@
 			     (high & MASK_LOCKED_HI))
 				continue;
 
-			/* Log the machine check that caused the threshold
-			   event. */
+			/*
+			 * Log the machine check that caused the threshold
+			 * event.
+			 */
 			machine_check_poll(MCP_TIMESTAMP,
 					&__get_cpu_var(mce_poll_banks));
 
@@ -254,48 +256,52 @@
 
 struct threshold_attr {
 	struct attribute attr;
-	ssize_t(*show) (struct threshold_block *, char *);
-	ssize_t(*store) (struct threshold_block *, const char *, size_t count);
+	ssize_t (*show) (struct threshold_block *, char *);
+	ssize_t (*store) (struct threshold_block *, const char *, size_t count);
 };
 
-#define SHOW_FIELDS(name)                                           \
-static ssize_t show_ ## name(struct threshold_block * b, char *buf) \
-{                                                                   \
-        return sprintf(buf, "%lx\n", (unsigned long) b->name);      \
+#define SHOW_FIELDS(name)						\
+static ssize_t show_ ## name(struct threshold_block *b, char *buf)	\
+{									\
+	return sprintf(buf, "%lx\n", (unsigned long) b->name);		\
 }
 SHOW_FIELDS(interrupt_enable)
 SHOW_FIELDS(threshold_limit)
 
-static ssize_t store_interrupt_enable(struct threshold_block *b,
-				      const char *buf, size_t count)
+static ssize_t
+store_interrupt_enable(struct threshold_block *b, const char *buf, size_t size)
 {
-	char *end;
 	struct thresh_restart tr;
-	unsigned long new = simple_strtoul(buf, &end, 0);
-	if (end == buf)
+	unsigned long new;
+
+	if (strict_strtoul(buf, 0, &new) < 0)
 		return -EINVAL;
+
 	b->interrupt_enable = !!new;
 
-	tr.b = b;
-	tr.reset = 0;
-	tr.old_limit = 0;
+	tr.b		= b;
+	tr.reset	= 0;
+	tr.old_limit	= 0;
+
 	smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1);
 
-	return end - buf;
+	return size;
 }
 
-static ssize_t store_threshold_limit(struct threshold_block *b,
-				     const char *buf, size_t count)
+static ssize_t
+store_threshold_limit(struct threshold_block *b, const char *buf, size_t size)
 {
-	char *end;
 	struct thresh_restart tr;
-	unsigned long new = simple_strtoul(buf, &end, 0);
-	if (end == buf)
+	unsigned long new;
+
+	if (strict_strtoul(buf, 0, &new) < 0)
 		return -EINVAL;
+
 	if (new > THRESHOLD_MAX)
 		new = THRESHOLD_MAX;
 	if (new < 1)
 		new = 1;
+
 	tr.old_limit = b->threshold_limit;
 	b->threshold_limit = new;
 	tr.b = b;
@@ -303,12 +309,12 @@
 
 	smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1);
 
-	return end - buf;
+	return size;
 }
 
 struct threshold_block_cross_cpu {
-	struct threshold_block *tb;
-	long retval;
+	struct threshold_block	*tb;
+	long			retval;
 };
 
 static void local_error_count_handler(void *_tbcc)
@@ -338,16 +344,13 @@
 	return 1;
 }
 
-#define THRESHOLD_ATTR(_name,_mode,_show,_store) {            \
-        .attr = {.name = __stringify(_name), .mode = _mode }, \
-        .show = _show,                                        \
-        .store = _store,                                      \
+#define RW_ATTR(val)							\
+static struct threshold_attr val = {					\
+	.attr	= {.name = __stringify(val), .mode = 0644 },		\
+	.show	= show_## val,						\
+	.store	= store_## val,						\
 };
 
-#define RW_ATTR(name)                                           \
-static struct threshold_attr name =                             \
-        THRESHOLD_ATTR(name, 0644, show_## name, store_## name)
-
 RW_ATTR(interrupt_enable);
 RW_ATTR(threshold_limit);
 RW_ATTR(error_count);
@@ -359,15 +362,17 @@
 	NULL
 };
 
-#define to_block(k) container_of(k, struct threshold_block, kobj)
-#define to_attr(a) container_of(a, struct threshold_attr, attr)
+#define to_block(k)	container_of(k, struct threshold_block, kobj)
+#define to_attr(a)	container_of(a, struct threshold_attr, attr)
 
 static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
 {
 	struct threshold_block *b = to_block(kobj);
 	struct threshold_attr *a = to_attr(attr);
 	ssize_t ret;
+
 	ret = a->show ? a->show(b, buf) : -EIO;
+
 	return ret;
 }
 
@@ -377,18 +382,20 @@
 	struct threshold_block *b = to_block(kobj);
 	struct threshold_attr *a = to_attr(attr);
 	ssize_t ret;
+
 	ret = a->store ? a->store(b, buf, count) : -EIO;
+
 	return ret;
 }
 
 static struct sysfs_ops threshold_ops = {
-	.show = show,
-	.store = store,
+	.show			= show,
+	.store			= store,
 };
 
 static struct kobj_type threshold_ktype = {
-	.sysfs_ops = &threshold_ops,
-	.default_attrs = default_attrs,
+	.sysfs_ops		= &threshold_ops,
+	.default_attrs		= default_attrs,
 };
 
 static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
@@ -396,9 +403,9 @@
 					       unsigned int block,
 					       u32 address)
 {
-	int err;
-	u32 low, high;
 	struct threshold_block *b = NULL;
+	u32 low, high;
+	int err;
 
 	if ((bank >= NR_BANKS) || (block >= NR_BLOCKS))
 		return 0;
@@ -421,20 +428,21 @@
 	if (!b)
 		return -ENOMEM;
 
-	b->block = block;
-	b->bank = bank;
-	b->cpu = cpu;
-	b->address = address;
-	b->interrupt_enable = 0;
-	b->threshold_limit = THRESHOLD_MAX;
+	b->block		= block;
+	b->bank			= bank;
+	b->cpu			= cpu;
+	b->address		= address;
+	b->interrupt_enable	= 0;
+	b->threshold_limit	= THRESHOLD_MAX;
 
 	INIT_LIST_HEAD(&b->miscj);
 
-	if (per_cpu(threshold_banks, cpu)[bank]->blocks)
+	if (per_cpu(threshold_banks, cpu)[bank]->blocks) {
 		list_add(&b->miscj,
 			 &per_cpu(threshold_banks, cpu)[bank]->blocks->miscj);
-	else
+	} else {
 		per_cpu(threshold_banks, cpu)[bank]->blocks = b;
+	}
 
 	err = kobject_init_and_add(&b->kobj, &threshold_ktype,
 				   per_cpu(threshold_banks, cpu)[bank]->kobj,
@@ -447,8 +455,9 @@
 		if (!address)
 			return 0;
 		address += MCG_XBLK_ADDR;
-	} else
+	} else {
 		++address;
+	}
 
 	err = allocate_threshold_blocks(cpu, bank, ++block, address);
 	if (err)
@@ -500,13 +509,14 @@
 		if (!b)
 			goto out;
 
-		err = sysfs_create_link(&per_cpu(device_mce, cpu).kobj,
+		err = sysfs_create_link(&per_cpu(mce_dev, cpu).kobj,
 					b->kobj, name);
 		if (err)
 			goto out;
 
 		cpumask_copy(b->cpus, cpu_core_mask(cpu));
 		per_cpu(threshold_banks, cpu)[bank] = b;
+
 		goto out;
 	}
 #endif
@@ -522,7 +532,7 @@
 		goto out;
 	}
 
-	b->kobj = kobject_create_and_add(name, &per_cpu(device_mce, cpu).kobj);
+	b->kobj = kobject_create_and_add(name, &per_cpu(mce_dev, cpu).kobj);
 	if (!b->kobj)
 		goto out_free;
 
@@ -542,7 +552,7 @@
 		if (i == cpu)
 			continue;
 
-		err = sysfs_create_link(&per_cpu(device_mce, i).kobj,
+		err = sysfs_create_link(&per_cpu(mce_dev, i).kobj,
 					b->kobj, name);
 		if (err)
 			goto out;
@@ -605,15 +615,13 @@
 
 static void threshold_remove_bank(unsigned int cpu, int bank)
 {
-	int i = 0;
 	struct threshold_bank *b;
 	char name[32];
+	int i = 0;
 
 	b = per_cpu(threshold_banks, cpu)[bank];
-
 	if (!b)
 		return;
-
 	if (!b->blocks)
 		goto free_out;
 
@@ -622,8 +630,9 @@
 #ifdef CONFIG_SMP
 	/* sibling symlink */
 	if (shared_bank[bank] && b->blocks->cpu != cpu) {
-		sysfs_remove_link(&per_cpu(device_mce, cpu).kobj, name);
+		sysfs_remove_link(&per_cpu(mce_dev, cpu).kobj, name);
 		per_cpu(threshold_banks, cpu)[bank] = NULL;
+
 		return;
 	}
 #endif
@@ -633,7 +642,7 @@
 		if (i == cpu)
 			continue;
 
-		sysfs_remove_link(&per_cpu(device_mce, i).kobj, name);
+		sysfs_remove_link(&per_cpu(mce_dev, i).kobj, name);
 		per_cpu(threshold_banks, i)[bank] = NULL;
 	}
 
@@ -659,12 +668,9 @@
 }
 
 /* get notified when a cpu comes on/off */
-static void __cpuinit amd_64_threshold_cpu_callback(unsigned long action,
-						     unsigned int cpu)
+static void __cpuinit
+amd_64_threshold_cpu_callback(unsigned long action, unsigned int cpu)
 {
-	if (cpu >= NR_CPUS)
-		return;
-
 	switch (action) {
 	case CPU_ONLINE:
 	case CPU_ONLINE_FROZEN:
@@ -686,11 +692,12 @@
 	/* to hit CPUs online before the notifier is up */
 	for_each_online_cpu(lcpu) {
 		int err = threshold_create_device(lcpu);
+
 		if (err)
 			return err;
 	}
 	threshold_cpu_callback = amd_64_threshold_cpu_callback;
+
 	return 0;
 }
-
 device_initcall(threshold_init_device);
diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c
new file mode 100644
index 0000000..2b011d2
--- /dev/null
+++ b/arch/x86/kernel/cpu/mcheck/mce_intel.c
@@ -0,0 +1,74 @@
+/*
+ * Common code for Intel machine checks
+ */
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+
+#include <asm/therm_throt.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/apic.h>
+#include <asm/msr.h>
+
+#include "mce.h"
+
+void intel_init_thermal(struct cpuinfo_x86 *c)
+{
+	unsigned int cpu = smp_processor_id();
+	int tm2 = 0;
+	u32 l, h;
+
+	/* Thermal monitoring depends on ACPI and clock modulation*/
+	if (!cpu_has(c, X86_FEATURE_ACPI) || !cpu_has(c, X86_FEATURE_ACC))
+		return;
+
+	/*
+	 * First check if its enabled already, in which case there might
+	 * be some SMM goo which handles it, so we can't even put a handler
+	 * since it might be delivered via SMI already:
+	 */
+	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
+	h = apic_read(APIC_LVTTHMR);
+	if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) {
+		printk(KERN_DEBUG
+		       "CPU%d: Thermal monitoring handled by SMI\n", cpu);
+		return;
+	}
+
+	if (cpu_has(c, X86_FEATURE_TM2) && (l & MSR_IA32_MISC_ENABLE_TM2))
+		tm2 = 1;
+
+	/* Check whether a vector already exists */
+	if (h & APIC_VECTOR_MASK) {
+		printk(KERN_DEBUG
+		       "CPU%d: Thermal LVT vector (%#x) already installed\n",
+		       cpu, (h & APIC_VECTOR_MASK));
+		return;
+	}
+
+	/* We'll mask the thermal vector in the lapic till we're ready: */
+	h = THERMAL_APIC_VECTOR | APIC_DM_FIXED | APIC_LVT_MASKED;
+	apic_write(APIC_LVTTHMR, h);
+
+	rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
+	wrmsr(MSR_IA32_THERM_INTERRUPT,
+		l | (THERM_INT_LOW_ENABLE | THERM_INT_HIGH_ENABLE), h);
+
+	intel_set_thermal_handler();
+
+	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
+	wrmsr(MSR_IA32_MISC_ENABLE, l | MSR_IA32_MISC_ENABLE_TM1, h);
+
+	/* Unmask the thermal vector: */
+	l = apic_read(APIC_LVTTHMR);
+	apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
+
+	printk(KERN_INFO "CPU%d: Thermal monitoring enabled (%s)\n",
+	       cpu, tm2 ? "TM2" : "TM1");
+
+	/* enable thermal throttle processing */
+	atomic_set(&therm_throt_en, 1);
+}
diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel_64.c b/arch/x86/kernel/cpu/mcheck/mce_intel_64.c
index 65a0fce..f2ef695 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_intel_64.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_intel_64.c
@@ -16,6 +16,8 @@
 #include <asm/idle.h>
 #include <asm/therm_throt.h>
 
+#include "mce.h"
+
 asmlinkage void smp_thermal_interrupt(void)
 {
 	__u64 msr_val;
@@ -26,67 +28,13 @@
 	irq_enter();
 
 	rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
-	if (therm_throt_process(msr_val & 1))
+	if (therm_throt_process(msr_val & THERM_STATUS_PROCHOT))
 		mce_log_therm_throt_event(msr_val);
 
 	inc_irq_stat(irq_thermal_count);
 	irq_exit();
 }
 
-static void intel_init_thermal(struct cpuinfo_x86 *c)
-{
-	u32 l, h;
-	int tm2 = 0;
-	unsigned int cpu = smp_processor_id();
-
-	if (!cpu_has(c, X86_FEATURE_ACPI))
-		return;
-
-	if (!cpu_has(c, X86_FEATURE_ACC))
-		return;
-
-	/* first check if TM1 is already enabled by the BIOS, in which
-	 * case there might be some SMM goo which handles it, so we can't even
-	 * put a handler since it might be delivered via SMI already.
-	 */
-	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
-	h = apic_read(APIC_LVTTHMR);
-	if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) {
-		printk(KERN_DEBUG
-		       "CPU%d: Thermal monitoring handled by SMI\n", cpu);
-		return;
-	}
-
-	if (cpu_has(c, X86_FEATURE_TM2) && (l & MSR_IA32_MISC_ENABLE_TM2))
-		tm2 = 1;
-
-	if (h & APIC_VECTOR_MASK) {
-		printk(KERN_DEBUG
-		       "CPU%d: Thermal LVT vector (%#x) already "
-		       "installed\n", cpu, (h & APIC_VECTOR_MASK));
-		return;
-	}
-
-	h = THERMAL_APIC_VECTOR;
-	h |= (APIC_DM_FIXED | APIC_LVT_MASKED);
-	apic_write(APIC_LVTTHMR, h);
-
-	rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
-	wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03, h);
-
-	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
-	wrmsr(MSR_IA32_MISC_ENABLE, l | MSR_IA32_MISC_ENABLE_TM1, h);
-
-	l = apic_read(APIC_LVTTHMR);
-	apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
-	printk(KERN_INFO "CPU%d: Thermal monitoring enabled (%s)\n",
-		cpu, tm2 ? "TM2" : "TM1");
-
-	/* enable thermal throttle processing */
-	atomic_set(&therm_throt_en, 1);
-	return;
-}
-
 /*
  * Support for Intel Correct Machine Check Interrupts. This allows
  * the CPU to raise an interrupt when a corrected machine check happened.
@@ -108,6 +56,9 @@
 {
 	u64 cap;
 
+	if (mce_cmci_disabled || mce_ignore_ce)
+		return 0;
+
 	/*
 	 * Vendor check is not strictly needed, but the initial
 	 * initialization is vendor keyed and this
@@ -131,7 +82,7 @@
 static void intel_threshold_interrupt(void)
 {
 	machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_banks_owned));
-	mce_notify_user();
+	mce_notify_irq();
 }
 
 static void print_update(char *type, int *hdr, int num)
@@ -247,7 +198,7 @@
 		return;
 	cpumask_copy(old, &current->cpus_allowed);
 
-	for_each_online_cpu (cpu) {
+	for_each_online_cpu(cpu) {
 		if (cpu == dying)
 			continue;
 		if (set_cpus_allowed_ptr(current, cpumask_of(cpu)))
diff --git a/arch/x86/kernel/cpu/mcheck/non-fatal.c b/arch/x86/kernel/cpu/mcheck/non-fatal.c
index a74af12..70b7104 100644
--- a/arch/x86/kernel/cpu/mcheck/non-fatal.c
+++ b/arch/x86/kernel/cpu/mcheck/non-fatal.c
@@ -6,15 +6,14 @@
  * This file contains routines to check for non-fatal MCEs every 15s
  *
  */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
 #include <linux/interrupt.h>
-#include <linux/smp.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/smp.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -22,9 +21,9 @@
 
 #include "mce.h"
 
-static int firstbank;
+static int		firstbank;
 
-#define MCE_RATE	15*HZ	/* timer rate is 15s */
+#define MCE_RATE	(15*HZ)	/* timer rate is 15s */
 
 static void mce_checkregs(void *info)
 {
@@ -34,23 +33,24 @@
 	for (i = firstbank; i < nr_mce_banks; i++) {
 		rdmsr(MSR_IA32_MC0_STATUS+i*4, low, high);
 
-		if (high & (1<<31)) {
-			printk(KERN_INFO "MCE: The hardware reports a non "
-				"fatal, correctable incident occurred on "
-				"CPU %d.\n",
+		if (!(high & (1<<31)))
+			continue;
+
+		printk(KERN_INFO "MCE: The hardware reports a non fatal, "
+			"correctable incident occurred on CPU %d.\n",
 				smp_processor_id());
-			printk(KERN_INFO "Bank %d: %08x%08x\n", i, high, low);
 
-			/*
-			 * Scrub the error so we don't pick it up in MCE_RATE
-			 * seconds time.
-			 */
-			wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
+		printk(KERN_INFO "Bank %d: %08x%08x\n", i, high, low);
 
-			/* Serialize */
-			wmb();
-			add_taint(TAINT_MACHINE_CHECK);
-		}
+		/*
+		 * Scrub the error so we don't pick it up in MCE_RATE
+		 * seconds time:
+		 */
+		wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
+
+		/* Serialize: */
+		wmb();
+		add_taint(TAINT_MACHINE_CHECK);
 	}
 }
 
@@ -77,16 +77,17 @@
 
 	/* Some Athlons misbehave when we frob bank 0 */
 	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
-		boot_cpu_data.x86 == 6)
-			firstbank = 1;
+						boot_cpu_data.x86 == 6)
+		firstbank = 1;
 	else
-			firstbank = 0;
+		firstbank = 0;
 
 	/*
 	 * Check for non-fatal errors every MCE_RATE s
 	 */
 	schedule_delayed_work(&mce_work, round_jiffies_relative(MCE_RATE));
 	printk(KERN_INFO "Machine check exception polling timer started.\n");
+
 	return 0;
 }
 module_init(init_nonfatal_mce_checker);
diff --git a/arch/x86/kernel/cpu/mcheck/p4.c b/arch/x86/kernel/cpu/mcheck/p4.c
index f53bdcb..82cee10 100644
--- a/arch/x86/kernel/cpu/mcheck/p4.c
+++ b/arch/x86/kernel/cpu/mcheck/p4.c
@@ -2,18 +2,17 @@
  * P4 specific Machine Check Exception Reporting
  */
 
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
 #include <linux/smp.h>
 
+#include <asm/therm_throt.h>
 #include <asm/processor.h>
 #include <asm/system.h>
-#include <asm/msr.h>
 #include <asm/apic.h>
-
-#include <asm/therm_throt.h>
+#include <asm/msr.h>
 
 #include "mce.h"
 
@@ -36,6 +35,7 @@
 
 
 #ifdef CONFIG_X86_MCE_P4THERMAL
+
 static void unexpected_thermal_interrupt(struct pt_regs *regs)
 {
 	printk(KERN_ERR "CPU%d: Unexpected LVT TMR interrupt!\n",
@@ -43,7 +43,7 @@
 	add_taint(TAINT_MACHINE_CHECK);
 }
 
-/* P4/Xeon Thermal transition interrupt handler */
+/* P4/Xeon Thermal transition interrupt handler: */
 static void intel_thermal_interrupt(struct pt_regs *regs)
 {
 	__u64 msr_val;
@@ -51,11 +51,12 @@
 	ack_APIC_irq();
 
 	rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
-	therm_throt_process(msr_val & 0x1);
+	therm_throt_process(msr_val & THERM_STATUS_PROCHOT);
 }
 
-/* Thermal interrupt handler for this CPU setup */
-static void (*vendor_thermal_interrupt)(struct pt_regs *regs) = unexpected_thermal_interrupt;
+/* Thermal interrupt handler for this CPU setup: */
+static void (*vendor_thermal_interrupt)(struct pt_regs *regs) =
+						unexpected_thermal_interrupt;
 
 void smp_thermal_interrupt(struct pt_regs *regs)
 {
@@ -65,67 +66,15 @@
 	irq_exit();
 }
 
-/* P4/Xeon Thermal regulation detect and init */
-static void intel_init_thermal(struct cpuinfo_x86 *c)
+void intel_set_thermal_handler(void)
 {
-	u32 l, h;
-	unsigned int cpu = smp_processor_id();
-
-	/* Thermal monitoring */
-	if (!cpu_has(c, X86_FEATURE_ACPI))
-		return;	/* -ENODEV */
-
-	/* Clock modulation */
-	if (!cpu_has(c, X86_FEATURE_ACC))
-		return;	/* -ENODEV */
-
-	/* first check if its enabled already, in which case there might
-	 * be some SMM goo which handles it, so we can't even put a handler
-	 * since it might be delivered via SMI already -zwanem.
-	 */
-	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
-	h = apic_read(APIC_LVTTHMR);
-	if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) {
-		printk(KERN_DEBUG "CPU%d: Thermal monitoring handled by SMI\n",
-				cpu);
-		return; /* -EBUSY */
-	}
-
-	/* check whether a vector already exists, temporarily masked? */
-	if (h & APIC_VECTOR_MASK) {
-		printk(KERN_DEBUG "CPU%d: Thermal LVT vector (%#x) already "
-				"installed\n",
-			cpu, (h & APIC_VECTOR_MASK));
-		return; /* -EBUSY */
-	}
-
-	/* The temperature transition interrupt handler setup */
-	h = THERMAL_APIC_VECTOR;		/* our delivery vector */
-	h |= (APIC_DM_FIXED | APIC_LVT_MASKED);	/* we'll mask till we're ready */
-	apic_write(APIC_LVTTHMR, h);
-
-	rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
-	wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03 , h);
-
-	/* ok we're good to go... */
 	vendor_thermal_interrupt = intel_thermal_interrupt;
-
-	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
-	wrmsr(MSR_IA32_MISC_ENABLE, l | MSR_IA32_MISC_ENABLE_TM1, h);
-
-	l = apic_read(APIC_LVTTHMR);
-	apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
-	printk(KERN_INFO "CPU%d: Thermal monitoring enabled\n", cpu);
-
-	/* enable thermal throttle processing */
-	atomic_set(&therm_throt_en, 1);
-	return;
 }
+
 #endif /* CONFIG_X86_MCE_P4THERMAL */
 
-
 /* P4/Xeon Extended MCE MSR retrieval, return 0 if unsupported */
-static inline void intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
+static void intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
 {
 	u32 h;
 
@@ -143,9 +92,9 @@
 
 static void intel_machine_check(struct pt_regs *regs, long error_code)
 {
-	int recover = 1;
 	u32 alow, ahigh, high, low;
 	u32 mcgstl, mcgsth;
+	int recover = 1;
 	int i;
 
 	rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
@@ -157,7 +106,9 @@
 
 	if (mce_num_extended_msrs > 0) {
 		struct intel_mce_extended_msrs dbg;
+
 		intel_get_extended_msrs(&dbg);
+
 		printk(KERN_DEBUG "CPU %d: EIP: %08x EFLAGS: %08x\n"
 			"\teax: %08x ebx: %08x ecx: %08x edx: %08x\n"
 			"\tesi: %08x edi: %08x ebp: %08x esp: %08x\n",
@@ -171,6 +122,7 @@
 		if (high & (1<<31)) {
 			char misc[20];
 			char addr[24];
+
 			misc[0] = addr[0] = '\0';
 			if (high & (1<<29))
 				recover |= 1;
@@ -196,6 +148,7 @@
 		panic("Unable to continue");
 
 	printk(KERN_EMERG "Attempting to continue.\n");
+
 	/*
 	 * Do not clear the MSR_IA32_MCi_STATUS if the error is not
 	 * recoverable/continuable.This will allow BIOS to look at the MSRs
@@ -217,7 +170,6 @@
 	wrmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
 }
 
-
 void intel_p4_mcheck_init(struct cpuinfo_x86 *c)
 {
 	u32 l, h;
diff --git a/arch/x86/kernel/cpu/mcheck/p5.c b/arch/x86/kernel/cpu/mcheck/p5.c
index c9f77ea..015f481 100644
--- a/arch/x86/kernel/cpu/mcheck/p5.c
+++ b/arch/x86/kernel/cpu/mcheck/p5.c
@@ -2,11 +2,10 @@
  * P5 specific Machine Check Exception Reporting
  * (C) Copyright 2002 Alan Cox <alan@lxorguk.ukuu.org.uk>
  */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
 #include <linux/smp.h>
 
 #include <asm/processor.h>
@@ -15,39 +14,58 @@
 
 #include "mce.h"
 
-/* Machine check handler for Pentium class Intel */
+/* By default disabled */
+int		mce_p5_enable;
+
+/* Machine check handler for Pentium class Intel CPUs: */
 static void pentium_machine_check(struct pt_regs *regs, long error_code)
 {
 	u32 loaddr, hi, lotype;
+
 	rdmsr(MSR_IA32_P5_MC_ADDR, loaddr, hi);
 	rdmsr(MSR_IA32_P5_MC_TYPE, lotype, hi);
-	printk(KERN_EMERG "CPU#%d: Machine Check Exception:  0x%8X (type 0x%8X).\n", smp_processor_id(), loaddr, lotype);
-	if (lotype&(1<<5))
-		printk(KERN_EMERG "CPU#%d: Possible thermal failure (CPU on fire ?).\n", smp_processor_id());
+
+	printk(KERN_EMERG
+		"CPU#%d: Machine Check Exception:  0x%8X (type 0x%8X).\n",
+		smp_processor_id(), loaddr, lotype);
+
+	if (lotype & (1<<5)) {
+		printk(KERN_EMERG
+			"CPU#%d: Possible thermal failure (CPU on fire ?).\n",
+			smp_processor_id());
+	}
+
 	add_taint(TAINT_MACHINE_CHECK);
 }
 
-/* Set up machine check reporting for processors with Intel style MCE */
+/* Set up machine check reporting for processors with Intel style MCE: */
 void intel_p5_mcheck_init(struct cpuinfo_x86 *c)
 {
 	u32 l, h;
 
-	/*Check for MCE support */
+	/* Check for MCE support: */
 	if (!cpu_has(c, X86_FEATURE_MCE))
 		return;
 
-	/* Default P5 to off as its often misconnected */
+#ifdef CONFIG_X86_OLD_MCE
+	/* Default P5 to off as its often misconnected: */
 	if (mce_disabled != -1)
 		return;
+#endif
+
 	machine_check_vector = pentium_machine_check;
+	/* Make sure the vector pointer is visible before we enable MCEs: */
 	wmb();
 
-	/* Read registers before enabling */
+	/* Read registers before enabling: */
 	rdmsr(MSR_IA32_P5_MC_ADDR, l, h);
 	rdmsr(MSR_IA32_P5_MC_TYPE, l, h);
-	printk(KERN_INFO "Intel old style machine check architecture supported.\n");
+	printk(KERN_INFO
+	       "Intel old style machine check architecture supported.\n");
 
-	/* Enable MCE */
+	/* Enable MCE: */
 	set_in_cr4(X86_CR4_MCE);
-	printk(KERN_INFO "Intel old style machine check reporting enabled on CPU#%d.\n", smp_processor_id());
+	printk(KERN_INFO
+	       "Intel old style machine check reporting enabled on CPU#%d.\n",
+	       smp_processor_id());
 }
diff --git a/arch/x86/kernel/cpu/mcheck/p6.c b/arch/x86/kernel/cpu/mcheck/p6.c
index 2ac52d7..43c24e6 100644
--- a/arch/x86/kernel/cpu/mcheck/p6.c
+++ b/arch/x86/kernel/cpu/mcheck/p6.c
@@ -2,11 +2,10 @@
  * P6 specific Machine Check Exception Reporting
  * (C) Copyright 2002 Alan Cox <alan@lxorguk.ukuu.org.uk>
  */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
 #include <linux/smp.h>
 
 #include <asm/processor.h>
@@ -18,9 +17,9 @@
 /* Machine Check Handler For PII/PIII */
 static void intel_machine_check(struct pt_regs *regs, long error_code)
 {
-	int recover = 1;
 	u32 alow, ahigh, high, low;
 	u32 mcgstl, mcgsth;
+	int recover = 1;
 	int i;
 
 	rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
@@ -35,12 +34,16 @@
 		if (high & (1<<31)) {
 			char misc[20];
 			char addr[24];
-			misc[0] = addr[0] = '\0';
+
+			misc[0] = '\0';
+			addr[0] = '\0';
+
 			if (high & (1<<29))
 				recover |= 1;
 			if (high & (1<<25))
 				recover |= 2;
 			high &= ~(1<<31);
+
 			if (high & (1<<27)) {
 				rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh);
 				snprintf(misc, 20, "[%08x%08x]", ahigh, alow);
@@ -49,6 +52,7 @@
 				rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
 				snprintf(addr, 24, " at %08x%08x", ahigh, alow);
 			}
+
 			printk(KERN_EMERG "CPU %d: Bank %d: %08x%08x%s%s\n",
 				smp_processor_id(), i, high, low, misc, addr);
 		}
@@ -63,16 +67,17 @@
 	/*
 	 * Do not clear the MSR_IA32_MCi_STATUS if the error is not
 	 * recoverable/continuable.This will allow BIOS to look at the MSRs
-	 * for errors if the OS could not log the error.
+	 * for errors if the OS could not log the error:
 	 */
 	for (i = 0; i < nr_mce_banks; i++) {
 		unsigned int msr;
+
 		msr = MSR_IA32_MC0_STATUS+i*4;
 		rdmsr(msr, low, high);
 		if (high & (1<<31)) {
-			/* Clear it */
+			/* Clear it: */
 			wrmsr(msr, 0UL, 0UL);
-			/* Serialize */
+			/* Serialize: */
 			wmb();
 			add_taint(TAINT_MACHINE_CHECK);
 		}
@@ -81,7 +86,7 @@
 	wrmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
 }
 
-/* Set up machine check reporting for processors with Intel style MCE */
+/* Set up machine check reporting for processors with Intel style MCE: */
 void intel_p6_mcheck_init(struct cpuinfo_x86 *c)
 {
 	u32 l, h;
@@ -97,6 +102,7 @@
 
 	/* Ok machine check is available */
 	machine_check_vector = intel_machine_check;
+	/* Make sure the vector pointer is visible before we enable MCEs: */
 	wmb();
 
 	printk(KERN_INFO "Intel machine check architecture supported.\n");
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
index d5ae224..7b1ae2e 100644
--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -1,7 +1,7 @@
 /*
- *
  * Thermal throttle event support code (such as syslog messaging and rate
  * limiting) that was factored out from x86_64 (mce_intel.c) and i386 (p4.c).
+ *
  * This allows consistent reporting of CPU thermal throttle events.
  *
  * Maintains a counter in /sys that keeps track of the number of thermal
@@ -13,43 +13,43 @@
  * Credits: Adapted from Zwane Mwaikambo's original code in mce_intel.c.
  *          Inspired by Ross Biro's and Al Borchers' counter code.
  */
-
+#include <linux/notifier.h>
+#include <linux/jiffies.h>
 #include <linux/percpu.h>
 #include <linux/sysdev.h>
 #include <linux/cpu.h>
-#include <asm/cpu.h>
-#include <linux/notifier.h>
-#include <linux/jiffies.h>
+
 #include <asm/therm_throt.h>
 
 /* How long to wait between reporting thermal events */
-#define CHECK_INTERVAL              (300 * HZ)
+#define CHECK_INTERVAL		(300 * HZ)
 
 static DEFINE_PER_CPU(__u64, next_check) = INITIAL_JIFFIES;
 static DEFINE_PER_CPU(unsigned long, thermal_throttle_count);
-atomic_t therm_throt_en = ATOMIC_INIT(0);
+
+atomic_t therm_throt_en		= ATOMIC_INIT(0);
 
 #ifdef CONFIG_SYSFS
-#define define_therm_throt_sysdev_one_ro(_name)                              \
-        static SYSDEV_ATTR(_name, 0444, therm_throt_sysdev_show_##_name, NULL)
+#define define_therm_throt_sysdev_one_ro(_name)				\
+	static SYSDEV_ATTR(_name, 0444, therm_throt_sysdev_show_##_name, NULL)
 
-#define define_therm_throt_sysdev_show_func(name)                            \
-static ssize_t therm_throt_sysdev_show_##name(struct sys_device *dev,        \
-					struct sysdev_attribute *attr,	     \
-                                              char *buf)                     \
-{                                                                            \
-	unsigned int cpu = dev->id;                                          \
-	ssize_t ret;                                                         \
-                                                                             \
-	preempt_disable();              /* CPU hotplug */                    \
-	if (cpu_online(cpu))                                                 \
-		ret = sprintf(buf, "%lu\n",                                  \
-			      per_cpu(thermal_throttle_##name, cpu));        \
-	else                                                                 \
-		ret = 0;                                                     \
-	preempt_enable();                                                    \
-                                                                             \
-	return ret;                                                          \
+#define define_therm_throt_sysdev_show_func(name)			\
+static ssize_t therm_throt_sysdev_show_##name(struct sys_device *dev,	\
+					struct sysdev_attribute *attr,	\
+					      char *buf)		\
+{									\
+	unsigned int cpu = dev->id;					\
+	ssize_t ret;							\
+									\
+	preempt_disable();	/* CPU hotplug */			\
+	if (cpu_online(cpu))						\
+		ret = sprintf(buf, "%lu\n",				\
+			      per_cpu(thermal_throttle_##name, cpu));	\
+	else								\
+		ret = 0;						\
+	preempt_enable();						\
+									\
+	return ret;							\
 }
 
 define_therm_throt_sysdev_show_func(count);
@@ -61,8 +61,8 @@
 };
 
 static struct attribute_group thermal_throttle_attr_group = {
-	.attrs = thermal_throttle_attrs,
-	.name = "thermal_throttle"
+	.attrs	= thermal_throttle_attrs,
+	.name	= "thermal_throttle"
 };
 #endif /* CONFIG_SYSFS */
 
@@ -110,10 +110,11 @@
 }
 
 #ifdef CONFIG_SYSFS
-/* Add/Remove thermal_throttle interface for CPU device */
+/* Add/Remove thermal_throttle interface for CPU device: */
 static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev)
 {
-	return sysfs_create_group(&sys_dev->kobj, &thermal_throttle_attr_group);
+	return sysfs_create_group(&sys_dev->kobj,
+				  &thermal_throttle_attr_group);
 }
 
 static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev)
@@ -121,19 +122,21 @@
 	sysfs_remove_group(&sys_dev->kobj, &thermal_throttle_attr_group);
 }
 
-/* Mutex protecting device creation against CPU hotplug */
+/* Mutex protecting device creation against CPU hotplug: */
 static DEFINE_MUTEX(therm_cpu_lock);
 
 /* Get notified when a cpu comes on/off. Be hotplug friendly. */
-static __cpuinit int thermal_throttle_cpu_callback(struct notifier_block *nfb,
-						   unsigned long action,
-						   void *hcpu)
+static __cpuinit int
+thermal_throttle_cpu_callback(struct notifier_block *nfb,
+			      unsigned long action,
+			      void *hcpu)
 {
 	unsigned int cpu = (unsigned long)hcpu;
 	struct sys_device *sys_dev;
 	int err = 0;
 
 	sys_dev = get_cpu_sysdev(cpu);
+
 	switch (action) {
 	case CPU_UP_PREPARE:
 	case CPU_UP_PREPARE_FROZEN:
diff --git a/arch/x86/kernel/cpu/mcheck/threshold.c b/arch/x86/kernel/cpu/mcheck/threshold.c
index 23ee9e7..d746df2 100644
--- a/arch/x86/kernel/cpu/mcheck/threshold.c
+++ b/arch/x86/kernel/cpu/mcheck/threshold.c
@@ -17,7 +17,7 @@
 
 void (*mce_threshold_vector)(void) = default_threshold_interrupt;
 
-asmlinkage void mce_threshold_interrupt(void)
+asmlinkage void smp_threshold_interrupt(void)
 {
 	exit_idle();
 	irq_enter();
diff --git a/arch/x86/kernel/cpu/mcheck/winchip.c b/arch/x86/kernel/cpu/mcheck/winchip.c
index 2a043d8..81b0248 100644
--- a/arch/x86/kernel/cpu/mcheck/winchip.c
+++ b/arch/x86/kernel/cpu/mcheck/winchip.c
@@ -2,11 +2,10 @@
  * IDT Winchip specific Machine Check Exception Reporting
  * (C) Copyright 2002 Alan Cox <alan@lxorguk.ukuu.org.uk>
  */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -14,7 +13,7 @@
 
 #include "mce.h"
 
-/* Machine check handler for WinChip C6 */
+/* Machine check handler for WinChip C6: */
 static void winchip_machine_check(struct pt_regs *regs, long error_code)
 {
 	printk(KERN_EMERG "CPU0: Machine Check Exception.\n");
@@ -25,12 +24,18 @@
 void winchip_mcheck_init(struct cpuinfo_x86 *c)
 {
 	u32 lo, hi;
+
 	machine_check_vector = winchip_machine_check;
+	/* Make sure the vector pointer is visible before we enable MCEs: */
 	wmb();
+
 	rdmsr(MSR_IDT_FCR1, lo, hi);
 	lo |= (1<<2);	/* Enable EIERRINT (int 18 MCE) */
 	lo &= ~(1<<4);	/* Enable MCE */
 	wrmsr(MSR_IDT_FCR1, lo, hi);
+
 	set_in_cr4(X86_CR4_MCE);
-	printk(KERN_INFO "Winchip machine check reporting enabled on CPU#0.\n");
+
+	printk(KERN_INFO
+	       "Winchip machine check reporting enabled on CPU#0.\n");
 }
diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index 895c82e..275bc14 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -968,6 +968,13 @@
 	if (!x86_pmu.num_counters_fixed)
 		return -1;
 
+	/*
+	 * Quirk, IA32_FIXED_CTRs do not work on current Atom processors:
+	 */
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+					boot_cpu_data.x86_model == 28)
+		return -1;
+
 	event = hwc->config & ARCH_PERFMON_EVENT_MASK;
 
 	if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS)))
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index a4742a3..de74f0a 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -963,6 +963,8 @@
 #ifdef CONFIG_SMP
 apicinterrupt IRQ_MOVE_CLEANUP_VECTOR \
 	irq_move_cleanup_interrupt smp_irq_move_cleanup_interrupt
+apicinterrupt REBOOT_VECTOR \
+	reboot_interrupt smp_reboot_interrupt
 #endif
 
 #ifdef CONFIG_X86_UV
@@ -994,10 +996,15 @@
 #endif
 
 apicinterrupt THRESHOLD_APIC_VECTOR \
-	threshold_interrupt mce_threshold_interrupt
+	threshold_interrupt smp_threshold_interrupt
 apicinterrupt THERMAL_APIC_VECTOR \
 	thermal_interrupt smp_thermal_interrupt
 
+#ifdef CONFIG_X86_MCE
+apicinterrupt MCE_SELF_VECTOR \
+	mce_self_interrupt smp_mce_self_interrupt
+#endif
+
 #ifdef CONFIG_SMP
 apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \
 	call_function_single_interrupt smp_call_function_single_interrupt
@@ -1379,7 +1386,7 @@
 errorentry general_protection do_general_protection
 errorentry page_fault do_page_fault
 #ifdef CONFIG_X86_MCE
-paranoidzeroentry machine_check do_machine_check
+paranoidzeroentry machine_check *machine_check_vector(%rip)
 #endif
 
 	/*
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 38287b5..b0cdde6 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -12,6 +12,7 @@
 #include <asm/io_apic.h>
 #include <asm/irq.h>
 #include <asm/idle.h>
+#include <asm/mce.h>
 #include <asm/hw_irq.h>
 
 atomic_t irq_err_count;
@@ -96,13 +97,23 @@
 	for_each_online_cpu(j)
 		seq_printf(p, "%10u ", irq_stats(j)->irq_thermal_count);
 	seq_printf(p, "  Thermal event interrupts\n");
-# ifdef CONFIG_X86_64
+# ifdef CONFIG_X86_MCE_THRESHOLD
 	seq_printf(p, "%*s: ", prec, "THR");
 	for_each_online_cpu(j)
 		seq_printf(p, "%10u ", irq_stats(j)->irq_threshold_count);
 	seq_printf(p, "  Threshold APIC interrupts\n");
 # endif
 #endif
+#ifdef CONFIG_X86_NEW_MCE
+	seq_printf(p, "%*s: ", prec, "MCE");
+	for_each_online_cpu(j)
+		seq_printf(p, "%10u ", per_cpu(mce_exception_count, j));
+	seq_printf(p, "  Machine check exceptions\n");
+	seq_printf(p, "%*s: ", prec, "MCP");
+	for_each_online_cpu(j)
+		seq_printf(p, "%10u ", per_cpu(mce_poll_count, j));
+	seq_printf(p, "  Machine check polls\n");
+#endif
 	seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
 #if defined(CONFIG_X86_IO_APIC)
 	seq_printf(p, "%*s: %10u\n", prec, "MIS", atomic_read(&irq_mis_count));
@@ -185,10 +196,14 @@
 #endif
 #ifdef CONFIG_X86_MCE
 	sum += irq_stats(cpu)->irq_thermal_count;
-# ifdef CONFIG_X86_64
+# ifdef CONFIG_X86_MCE_THRESHOLD
 	sum += irq_stats(cpu)->irq_threshold_count;
 # endif
 #endif
+#ifdef CONFIG_X86_NEW_MCE
+	sum += per_cpu(mce_exception_count, cpu);
+	sum += per_cpu(mce_poll_count, cpu);
+#endif
 	return sum;
 }
 
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c
index 267c662..696f0e4 100644
--- a/arch/x86/kernel/irqinit.c
+++ b/arch/x86/kernel/irqinit.c
@@ -173,6 +173,9 @@
 	/* Low priority IPI to cleanup after moving an irq */
 	set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
 	set_bit(IRQ_MOVE_CLEANUP_VECTOR, used_vectors);
+
+	/* IPI used for rebooting/stopping */
+	alloc_intr_gate(REBOOT_VECTOR, reboot_interrupt);
 #endif
 #endif /* CONFIG_SMP */
 }
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c
new file mode 100644
index 0000000..89f386f
--- /dev/null
+++ b/arch/x86/kernel/module.c
@@ -0,0 +1,248 @@
+/*  Kernel module help for x86.
+    Copyright (C) 2001 Rusty Russell.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the 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/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/mm.h>
+
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt...)
+#endif
+
+void *module_alloc(unsigned long size)
+{
+	struct vm_struct *area;
+
+	if (!size)
+		return NULL;
+	size = PAGE_ALIGN(size);
+	if (size > MODULES_LEN)
+		return NULL;
+
+	area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
+	if (!area)
+		return NULL;
+
+	return __vmalloc_area(area, GFP_KERNEL | __GFP_HIGHMEM,
+					PAGE_KERNEL_EXEC);
+}
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+	vfree(module_region);
+}
+
+/* We don't need anything special. */
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+			      Elf_Shdr *sechdrs,
+			      char *secstrings,
+			      struct module *mod)
+{
+	return 0;
+}
+
+#ifdef CONFIG_X86_32
+int apply_relocate(Elf32_Shdr *sechdrs,
+		   const char *strtab,
+		   unsigned int symindex,
+		   unsigned int relsec,
+		   struct module *me)
+{
+	unsigned int i;
+	Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
+	Elf32_Sym *sym;
+	uint32_t *location;
+
+	DEBUGP("Applying relocate section %u to %u\n", relsec,
+	       sechdrs[relsec].sh_info);
+	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+		/* This is where to make the change */
+		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+			+ rel[i].r_offset;
+		/* This is the symbol it is referring to.  Note that all
+		   undefined symbols have been resolved.  */
+		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+			+ ELF32_R_SYM(rel[i].r_info);
+
+		switch (ELF32_R_TYPE(rel[i].r_info)) {
+		case R_386_32:
+			/* We add the value into the location given */
+			*location += sym->st_value;
+			break;
+		case R_386_PC32:
+			/* Add the value, subtract its postition */
+			*location += sym->st_value - (uint32_t)location;
+			break;
+		default:
+			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+			       me->name, ELF32_R_TYPE(rel[i].r_info));
+			return -ENOEXEC;
+		}
+	}
+	return 0;
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+		       const char *strtab,
+		       unsigned int symindex,
+		       unsigned int relsec,
+		       struct module *me)
+{
+	printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
+	       me->name);
+	return -ENOEXEC;
+}
+#else /*X86_64*/
+int apply_relocate_add(Elf64_Shdr *sechdrs,
+		   const char *strtab,
+		   unsigned int symindex,
+		   unsigned int relsec,
+		   struct module *me)
+{
+	unsigned int i;
+	Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+	Elf64_Sym *sym;
+	void *loc;
+	u64 val;
+
+	DEBUGP("Applying relocate section %u to %u\n", relsec,
+	       sechdrs[relsec].sh_info);
+	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+		/* This is where to make the change */
+		loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+			+ rel[i].r_offset;
+
+		/* This is the symbol it is referring to.  Note that all
+		   undefined symbols have been resolved.  */
+		sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
+			+ ELF64_R_SYM(rel[i].r_info);
+
+		DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
+			(int)ELF64_R_TYPE(rel[i].r_info),
+			sym->st_value, rel[i].r_addend, (u64)loc);
+
+		val = sym->st_value + rel[i].r_addend;
+
+		switch (ELF64_R_TYPE(rel[i].r_info)) {
+		case R_X86_64_NONE:
+			break;
+		case R_X86_64_64:
+			*(u64 *)loc = val;
+			break;
+		case R_X86_64_32:
+			*(u32 *)loc = val;
+			if (val != *(u32 *)loc)
+				goto overflow;
+			break;
+		case R_X86_64_32S:
+			*(s32 *)loc = val;
+			if ((s64)val != *(s32 *)loc)
+				goto overflow;
+			break;
+		case R_X86_64_PC32:
+			val -= (u64)loc;
+			*(u32 *)loc = val;
+#if 0
+			if ((s64)val != *(s32 *)loc)
+				goto overflow;
+#endif
+			break;
+		default:
+			printk(KERN_ERR "module %s: Unknown rela relocation: %llu\n",
+			       me->name, ELF64_R_TYPE(rel[i].r_info));
+			return -ENOEXEC;
+		}
+	}
+	return 0;
+
+overflow:
+	printk(KERN_ERR "overflow in relocation type %d val %Lx\n",
+	       (int)ELF64_R_TYPE(rel[i].r_info), val);
+	printk(KERN_ERR "`%s' likely not compiled with -mcmodel=kernel\n",
+	       me->name);
+	return -ENOEXEC;
+}
+
+int apply_relocate(Elf_Shdr *sechdrs,
+		   const char *strtab,
+		   unsigned int symindex,
+		   unsigned int relsec,
+		   struct module *me)
+{
+	printk(KERN_ERR "non add relocation not supported\n");
+	return -ENOSYS;
+}
+
+#endif
+
+int module_finalize(const Elf_Ehdr *hdr,
+		    const Elf_Shdr *sechdrs,
+		    struct module *me)
+{
+	const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
+		*para = NULL;
+	char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
+		if (!strcmp(".text", secstrings + s->sh_name))
+			text = s;
+		if (!strcmp(".altinstructions", secstrings + s->sh_name))
+			alt = s;
+		if (!strcmp(".smp_locks", secstrings + s->sh_name))
+			locks = s;
+		if (!strcmp(".parainstructions", secstrings + s->sh_name))
+			para = s;
+	}
+
+	if (alt) {
+		/* patch .altinstructions */
+		void *aseg = (void *)alt->sh_addr;
+		apply_alternatives(aseg, aseg + alt->sh_size);
+	}
+	if (locks && text) {
+		void *lseg = (void *)locks->sh_addr;
+		void *tseg = (void *)text->sh_addr;
+		alternatives_smp_module_add(me, me->name,
+					    lseg, lseg + locks->sh_size,
+					    tseg, tseg + text->sh_size);
+	}
+
+	if (para) {
+		void *pseg = (void *)para->sh_addr;
+		apply_paravirt(pseg, pseg + para->sh_size);
+	}
+
+	return module_bug_finalize(hdr, sechdrs, me);
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+	alternatives_smp_module_del(mod);
+	module_bug_cleanup(mod);
+}
diff --git a/arch/x86/kernel/module_32.c b/arch/x86/kernel/module_32.c
deleted file mode 100644
index 0edd819..0000000
--- a/arch/x86/kernel/module_32.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*  Kernel module help for i386.
-    Copyright (C) 2001 Rusty Russell.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the 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/moduleloader.h>
-#include <linux/elf.h>
-#include <linux/vmalloc.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/bug.h>
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(fmt...)
-#endif
-
-void *module_alloc(unsigned long size)
-{
-	if (size == 0)
-		return NULL;
-	return vmalloc_exec(size);
-}
-
-
-/* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
-{
-	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-	   table entries. */
-}
-
-/* We don't need anything special. */
-int module_frob_arch_sections(Elf_Ehdr *hdr,
-			      Elf_Shdr *sechdrs,
-			      char *secstrings,
-			      struct module *mod)
-{
-	return 0;
-}
-
-int apply_relocate(Elf32_Shdr *sechdrs,
-		   const char *strtab,
-		   unsigned int symindex,
-		   unsigned int relsec,
-		   struct module *me)
-{
-	unsigned int i;
-	Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
-	Elf32_Sym *sym;
-	uint32_t *location;
-
-	DEBUGP("Applying relocate section %u to %u\n", relsec,
-	       sechdrs[relsec].sh_info);
-	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
-		/* This is where to make the change */
-		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
-			+ rel[i].r_offset;
-		/* This is the symbol it is referring to.  Note that all
-		   undefined symbols have been resolved.  */
-		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
-			+ ELF32_R_SYM(rel[i].r_info);
-
-		switch (ELF32_R_TYPE(rel[i].r_info)) {
-		case R_386_32:
-			/* We add the value into the location given */
-			*location += sym->st_value;
-			break;
-		case R_386_PC32:
-			/* Add the value, subtract its postition */
-			*location += sym->st_value - (uint32_t)location;
-			break;
-		default:
-			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
-			       me->name, ELF32_R_TYPE(rel[i].r_info));
-			return -ENOEXEC;
-		}
-	}
-	return 0;
-}
-
-int apply_relocate_add(Elf32_Shdr *sechdrs,
-		       const char *strtab,
-		       unsigned int symindex,
-		       unsigned int relsec,
-		       struct module *me)
-{
-	printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
-	       me->name);
-	return -ENOEXEC;
-}
-
-int module_finalize(const Elf_Ehdr *hdr,
-		    const Elf_Shdr *sechdrs,
-		    struct module *me)
-{
-	const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
-		*para = NULL;
-	char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
-
-	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
-		if (!strcmp(".text", secstrings + s->sh_name))
-			text = s;
-		if (!strcmp(".altinstructions", secstrings + s->sh_name))
-			alt = s;
-		if (!strcmp(".smp_locks", secstrings + s->sh_name))
-			locks = s;
-		if (!strcmp(".parainstructions", secstrings + s->sh_name))
-			para = s;
-	}
-
-	if (alt) {
-		/* patch .altinstructions */
-		void *aseg = (void *)alt->sh_addr;
-		apply_alternatives(aseg, aseg + alt->sh_size);
-	}
-	if (locks && text) {
-		void *lseg = (void *)locks->sh_addr;
-		void *tseg = (void *)text->sh_addr;
-		alternatives_smp_module_add(me, me->name,
-					    lseg, lseg + locks->sh_size,
-					    tseg, tseg + text->sh_size);
-	}
-
-	if (para) {
-		void *pseg = (void *)para->sh_addr;
-		apply_paravirt(pseg, pseg + para->sh_size);
-	}
-
-	return module_bug_finalize(hdr, sechdrs, me);
-}
-
-void module_arch_cleanup(struct module *mod)
-{
-	alternatives_smp_module_del(mod);
-	module_bug_cleanup(mod);
-}
diff --git a/arch/x86/kernel/module_64.c b/arch/x86/kernel/module_64.c
deleted file mode 100644
index c23880b..0000000
--- a/arch/x86/kernel/module_64.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*  Kernel module help for x86-64
-    Copyright (C) 2001 Rusty Russell.
-    Copyright (C) 2002,2003 Andi Kleen, SuSE Labs.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the 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/moduleloader.h>
-#include <linux/elf.h>
-#include <linux/vmalloc.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/bug.h>
-
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-
-#define DEBUGP(fmt...)
-
-#ifndef CONFIG_UML
-void module_free(struct module *mod, void *module_region)
-{
-	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-	   table entries. */
-}
-
-void *module_alloc(unsigned long size)
-{
-	struct vm_struct *area;
-
-	if (!size)
-		return NULL;
-	size = PAGE_ALIGN(size);
-	if (size > MODULES_LEN)
-		return NULL;
-
-	area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
-	if (!area)
-		return NULL;
-
-	return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC);
-}
-#endif
-
-/* We don't need anything special. */
-int module_frob_arch_sections(Elf_Ehdr *hdr,
-			      Elf_Shdr *sechdrs,
-			      char *secstrings,
-			      struct module *mod)
-{
-	return 0;
-}
-
-int apply_relocate_add(Elf64_Shdr *sechdrs,
-		   const char *strtab,
-		   unsigned int symindex,
-		   unsigned int relsec,
-		   struct module *me)
-{
-	unsigned int i;
-	Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
-	Elf64_Sym *sym;
-	void *loc;
-	u64 val;
-
-	DEBUGP("Applying relocate section %u to %u\n", relsec,
-	       sechdrs[relsec].sh_info);
-	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
-		/* This is where to make the change */
-		loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
-			+ rel[i].r_offset;
-
-		/* This is the symbol it is referring to.  Note that all
-		   undefined symbols have been resolved.  */
-		sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
-			+ ELF64_R_SYM(rel[i].r_info);
-
-		DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
-			(int)ELF64_R_TYPE(rel[i].r_info),
-			sym->st_value, rel[i].r_addend, (u64)loc);
-
-		val = sym->st_value + rel[i].r_addend;
-
-		switch (ELF64_R_TYPE(rel[i].r_info)) {
-		case R_X86_64_NONE:
-			break;
-		case R_X86_64_64:
-			*(u64 *)loc = val;
-			break;
-		case R_X86_64_32:
-			*(u32 *)loc = val;
-			if (val != *(u32 *)loc)
-				goto overflow;
-			break;
-		case R_X86_64_32S:
-			*(s32 *)loc = val;
-			if ((s64)val != *(s32 *)loc)
-				goto overflow;
-			break;
-		case R_X86_64_PC32:
-			val -= (u64)loc;
-			*(u32 *)loc = val;
-#if 0
-			if ((s64)val != *(s32 *)loc)
-				goto overflow;
-#endif
-			break;
-		default:
-			printk(KERN_ERR "module %s: Unknown rela relocation: %llu\n",
-			       me->name, ELF64_R_TYPE(rel[i].r_info));
-			return -ENOEXEC;
-		}
-	}
-	return 0;
-
-overflow:
-	printk(KERN_ERR "overflow in relocation type %d val %Lx\n",
-	       (int)ELF64_R_TYPE(rel[i].r_info), val);
-	printk(KERN_ERR "`%s' likely not compiled with -mcmodel=kernel\n",
-	       me->name);
-	return -ENOEXEC;
-}
-
-int apply_relocate(Elf_Shdr *sechdrs,
-		   const char *strtab,
-		   unsigned int symindex,
-		   unsigned int relsec,
-		   struct module *me)
-{
-	printk(KERN_ERR "non add relocation not supported\n");
-	return -ENOSYS;
-}
-
-int module_finalize(const Elf_Ehdr *hdr,
-		    const Elf_Shdr *sechdrs,
-		    struct module *me)
-{
-	const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
-		*para = NULL;
-	char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
-
-	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
-		if (!strcmp(".text", secstrings + s->sh_name))
-			text = s;
-		if (!strcmp(".altinstructions", secstrings + s->sh_name))
-			alt = s;
-		if (!strcmp(".smp_locks", secstrings + s->sh_name))
-			locks = s;
-		if (!strcmp(".parainstructions", secstrings + s->sh_name))
-			para = s;
-	}
-
-	if (alt) {
-		/* patch .altinstructions */
-		void *aseg = (void *)alt->sh_addr;
-		apply_alternatives(aseg, aseg + alt->sh_size);
-	}
-	if (locks && text) {
-		void *lseg = (void *)locks->sh_addr;
-		void *tseg = (void *)text->sh_addr;
-		alternatives_smp_module_add(me, me->name,
-					    lseg, lseg + locks->sh_size,
-					    tseg, tseg + text->sh_size);
-	}
-
-	if (para) {
-		void *pseg = (void *)para->sh_addr;
-		apply_paravirt(pseg, pseg + para->sh_size);
-	}
-
-	return module_bug_finalize(hdr, sechdrs, me);
-}
-
-void module_arch_cleanup(struct module *mod)
-{
-	alternatives_smp_module_del(mod);
-	module_bug_cleanup(mod);
-}
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index d1c636b..be5ae80 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -301,15 +301,13 @@
 
 #ifdef CONFIG_BLK_DEV_INITRD
 
-#ifdef CONFIG_X86_32
-
 #define MAX_MAP_CHUNK	(NR_FIX_BTMAPS << PAGE_SHIFT)
 static void __init relocate_initrd(void)
 {
 
 	u64 ramdisk_image = boot_params.hdr.ramdisk_image;
 	u64 ramdisk_size  = boot_params.hdr.ramdisk_size;
-	u64 end_of_lowmem = max_low_pfn << PAGE_SHIFT;
+	u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT;
 	u64 ramdisk_here;
 	unsigned long slop, clen, mapaddr;
 	char *p, *q;
@@ -365,14 +363,13 @@
 		ramdisk_image, ramdisk_image + ramdisk_size - 1,
 		ramdisk_here, ramdisk_here + ramdisk_size - 1);
 }
-#endif
 
 static void __init reserve_initrd(void)
 {
 	u64 ramdisk_image = boot_params.hdr.ramdisk_image;
 	u64 ramdisk_size  = boot_params.hdr.ramdisk_size;
 	u64 ramdisk_end   = ramdisk_image + ramdisk_size;
-	u64 end_of_lowmem = max_low_pfn << PAGE_SHIFT;
+	u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT;
 
 	if (!boot_params.hdr.type_of_loader ||
 	    !ramdisk_image || !ramdisk_size)
@@ -402,14 +399,8 @@
 		return;
 	}
 
-#ifdef CONFIG_X86_32
 	relocate_initrd();
-#else
-	printk(KERN_ERR "initrd extends beyond end of memory "
-	       "(0x%08llx > 0x%08llx)\ndisabling initrd\n",
-	       ramdisk_end, end_of_lowmem);
-	initrd_start = 0;
-#endif
+
 	free_early(ramdisk_image, ramdisk_end);
 }
 #else
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 0a813b1..4c57875 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -24,11 +24,11 @@
 #include <asm/ucontext.h>
 #include <asm/i387.h>
 #include <asm/vdso.h>
+#include <asm/mce.h>
 
 #ifdef CONFIG_X86_64
 #include <asm/proto.h>
 #include <asm/ia32_unistd.h>
-#include <asm/mce.h>
 #endif /* CONFIG_X86_64 */
 
 #include <asm/syscall.h>
@@ -856,10 +856,10 @@
 void
 do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 {
-#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
+#ifdef CONFIG_X86_NEW_MCE
 	/* notify userspace of pending MCEs */
 	if (thread_info_flags & _TIF_MCE_NOTIFY)
-		mce_notify_user();
+		mce_notify_process();
 #endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
 
 	/* deal with pending signal delivery */
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index 28f5fb4..ec1de97 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -150,14 +150,40 @@
  * this function calls the 'stop' function on all other CPUs in the system.
  */
 
+asmlinkage void smp_reboot_interrupt(void)
+{
+	ack_APIC_irq();
+	irq_enter();
+	stop_this_cpu(NULL);
+	irq_exit();
+}
+
 static void native_smp_send_stop(void)
 {
 	unsigned long flags;
+	unsigned long wait;
 
 	if (reboot_force)
 		return;
 
-	smp_call_function(stop_this_cpu, NULL, 0);
+	/*
+	 * Use an own vector here because smp_call_function
+	 * does lots of things not suitable in a panic situation.
+	 * On most systems we could also use an NMI here,
+	 * but there are a few systems around where NMI
+	 * is problematic so stay with an non NMI for now
+	 * (this implies we cannot stop CPUs spinning with irq off
+	 * currently)
+	 */
+	if (num_online_cpus() > 1) {
+		apic->send_IPI_allbutself(REBOOT_VECTOR);
+
+		/* Don't wait longer than a second */
+		wait = USEC_PER_SEC;
+		while (num_online_cpus() > 1 && wait--)
+			udelay(1);
+	}
+
 	local_irq_save(flags);
 	disable_local_APIC();
 	local_irq_restore(flags);
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 7c80007..2fecda6 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -873,7 +873,7 @@
 
 	err = do_boot_cpu(apicid, cpu);
 
-	zap_low_mappings();
+	zap_low_mappings(false);
 	low_mappings = 0;
 #else
 	err = do_boot_cpu(apicid, cpu);
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 07d60c8..1e1e27b 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -798,15 +798,15 @@
 
 	return new_kesp;
 }
-#else
+#endif
+
 asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
 {
 }
 
-asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
+asmlinkage void __attribute__((weak)) smp_threshold_interrupt(void)
 {
 }
-#endif
 
 /*
  * 'math_state_restore()' saves the current math information in the
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 4c85b2e..367e878 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -108,6 +108,8 @@
 	/* Data */
 	. = ALIGN(PAGE_SIZE);
 	.data : AT(ADDR(.data) - LOAD_OFFSET) {
+		/* Start of data section */
+		_sdata = .;
 		DATA_DATA
 		CONSTRUCTORS
 
diff --git a/arch/x86/lguest/Kconfig b/arch/x86/lguest/Kconfig
index 8dab8f7..3871804 100644
--- a/arch/x86/lguest/Kconfig
+++ b/arch/x86/lguest/Kconfig
@@ -2,7 +2,6 @@
 	bool "Lguest guest support"
 	select PARAVIRT
 	depends on X86_32
-	depends on !X86_PAE
 	select VIRTIO
 	select VIRTIO_RING
 	select VIRTIO_CONSOLE
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 4e0c265..7bc65f0 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -87,7 +87,7 @@
 
 /*G:037 async_hcall() is pretty simple: I'm quite proud of it really.  We have a
  * ring buffer of stored hypercalls which the Host will run though next time we
- * do a normal hypercall.  Each entry in the ring has 4 slots for the hypercall
+ * do a normal hypercall.  Each entry in the ring has 5 slots for the hypercall
  * arguments, and a "hcall_status" word which is 0 if the call is ready to go,
  * and 255 once the Host has finished with it.
  *
@@ -96,7 +96,8 @@
  * effect of causing the Host to run all the stored calls in the ring buffer
  * which empties it for next time! */
 static void async_hcall(unsigned long call, unsigned long arg1,
-			unsigned long arg2, unsigned long arg3)
+			unsigned long arg2, unsigned long arg3,
+			unsigned long arg4)
 {
 	/* Note: This code assumes we're uniprocessor. */
 	static unsigned int next_call;
@@ -108,12 +109,13 @@
 	local_irq_save(flags);
 	if (lguest_data.hcall_status[next_call] != 0xFF) {
 		/* Table full, so do normal hcall which will flush table. */
-		kvm_hypercall3(call, arg1, arg2, arg3);
+		kvm_hypercall4(call, arg1, arg2, arg3, arg4);
 	} else {
 		lguest_data.hcalls[next_call].arg0 = call;
 		lguest_data.hcalls[next_call].arg1 = arg1;
 		lguest_data.hcalls[next_call].arg2 = arg2;
 		lguest_data.hcalls[next_call].arg3 = arg3;
+		lguest_data.hcalls[next_call].arg4 = arg4;
 		/* Arguments must all be written before we mark it to go */
 		wmb();
 		lguest_data.hcall_status[next_call] = 0;
@@ -141,7 +143,7 @@
 	if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
 		kvm_hypercall1(call, arg1);
 	else
-		async_hcall(call, arg1, 0, 0);
+		async_hcall(call, arg1, 0, 0, 0);
 }
 
 static void lazy_hcall2(unsigned long call,
@@ -151,7 +153,7 @@
 	if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
 		kvm_hypercall2(call, arg1, arg2);
 	else
-		async_hcall(call, arg1, arg2, 0);
+		async_hcall(call, arg1, arg2, 0, 0);
 }
 
 static void lazy_hcall3(unsigned long call,
@@ -162,9 +164,23 @@
 	if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
 		kvm_hypercall3(call, arg1, arg2, arg3);
 	else
-		async_hcall(call, arg1, arg2, arg3);
+		async_hcall(call, arg1, arg2, arg3, 0);
 }
 
+#ifdef CONFIG_X86_PAE
+static void lazy_hcall4(unsigned long call,
+		       unsigned long arg1,
+		       unsigned long arg2,
+		       unsigned long arg3,
+		       unsigned long arg4)
+{
+	if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
+		kvm_hypercall4(call, arg1, arg2, arg3, arg4);
+	else
+		async_hcall(call, arg1, arg2, arg3, arg4);
+}
+#endif
+
 /* When lazy mode is turned off reset the per-cpu lazy mode variable and then
  * issue the do-nothing hypercall to flush any stored calls. */
 static void lguest_leave_lazy_mmu_mode(void)
@@ -179,7 +195,7 @@
 	paravirt_end_context_switch(next);
 }
 
-/*G:033
+/*G:032
  * After that diversion we return to our first native-instruction
  * replacements: four functions for interrupt control.
  *
@@ -199,30 +215,28 @@
 {
 	return lguest_data.irq_enabled;
 }
-PV_CALLEE_SAVE_REGS_THUNK(save_fl);
-
-/* restore_flags() just sets the flags back to the value given. */
-static void restore_fl(unsigned long flags)
-{
-	lguest_data.irq_enabled = flags;
-}
-PV_CALLEE_SAVE_REGS_THUNK(restore_fl);
 
 /* Interrupts go off... */
 static void irq_disable(void)
 {
 	lguest_data.irq_enabled = 0;
 }
+
+/* Let's pause a moment.  Remember how I said these are called so often?
+ * Jeremy Fitzhardinge optimized them so hard early in 2009 that he had to
+ * break some rules.  In particular, these functions are assumed to save their
+ * own registers if they need to: normal C functions assume they can trash the
+ * eax register.  To use normal C functions, we use
+ * PV_CALLEE_SAVE_REGS_THUNK(), which pushes %eax onto the stack, calls the
+ * C function, then restores it. */
+PV_CALLEE_SAVE_REGS_THUNK(save_fl);
 PV_CALLEE_SAVE_REGS_THUNK(irq_disable);
-
-/* Interrupts go on... */
-static void irq_enable(void)
-{
-	lguest_data.irq_enabled = X86_EFLAGS_IF;
-}
-PV_CALLEE_SAVE_REGS_THUNK(irq_enable);
-
 /*:*/
+
+/* These are in i386_head.S */
+extern void lg_irq_enable(void);
+extern void lg_restore_fl(unsigned long flags);
+
 /*M:003 Note that we don't check for outstanding interrupts when we re-enable
  * them (or when we unmask an interrupt).  This seems to work for the moment,
  * since interrupts are rare and we'll just get the interrupt on the next timer
@@ -368,8 +382,8 @@
 	case 1:	/* Basic feature request. */
 		/* We only allow kernel to see SSE3, CMPXCHG16B and SSSE3 */
 		*cx &= 0x00002201;
-		/* SSE, SSE2, FXSR, MMX, CMOV, CMPXCHG8B, TSC, FPU. */
-		*dx &= 0x07808111;
+		/* SSE, SSE2, FXSR, MMX, CMOV, CMPXCHG8B, TSC, FPU, PAE. */
+		*dx &= 0x07808151;
 		/* The Host can do a nice optimization if it knows that the
 		 * kernel mappings (addresses above 0xC0000000 or whatever
 		 * PAGE_OFFSET is set to) haven't changed.  But Linux calls
@@ -388,6 +402,11 @@
 		if (*ax > 0x80000008)
 			*ax = 0x80000008;
 		break;
+	case 0x80000001:
+		/* Here we should fix nx cap depending on host. */
+		/* For this version of PAE, we just clear NX bit. */
+		*dx &= ~(1 << 20);
+		break;
 	}
 }
 
@@ -521,25 +540,52 @@
 static void lguest_pte_update(struct mm_struct *mm, unsigned long addr,
 			       pte_t *ptep)
 {
+#ifdef CONFIG_X86_PAE
+	lazy_hcall4(LHCALL_SET_PTE, __pa(mm->pgd), addr,
+		    ptep->pte_low, ptep->pte_high);
+#else
 	lazy_hcall3(LHCALL_SET_PTE, __pa(mm->pgd), addr, ptep->pte_low);
+#endif
 }
 
 static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr,
 			      pte_t *ptep, pte_t pteval)
 {
-	*ptep = pteval;
+	native_set_pte(ptep, pteval);
 	lguest_pte_update(mm, addr, ptep);
 }
 
-/* The Guest calls this to set a top-level entry.  Again, we set the entry then
- * tell the Host which top-level page we changed, and the index of the entry we
- * changed. */
+/* The Guest calls lguest_set_pud to set a top-level entry and lguest_set_pmd
+ * to set a middle-level entry when PAE is activated.
+ * Again, we set the entry then tell the Host which page we changed,
+ * and the index of the entry we changed. */
+#ifdef CONFIG_X86_PAE
+static void lguest_set_pud(pud_t *pudp, pud_t pudval)
+{
+	native_set_pud(pudp, pudval);
+
+	/* 32 bytes aligned pdpt address and the index. */
+	lazy_hcall2(LHCALL_SET_PGD, __pa(pudp) & 0xFFFFFFE0,
+		   (__pa(pudp) & 0x1F) / sizeof(pud_t));
+}
+
 static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
 {
-	*pmdp = pmdval;
+	native_set_pmd(pmdp, pmdval);
 	lazy_hcall2(LHCALL_SET_PMD, __pa(pmdp) & PAGE_MASK,
-		   (__pa(pmdp) & (PAGE_SIZE - 1)) / 4);
+		   (__pa(pmdp) & (PAGE_SIZE - 1)) / sizeof(pmd_t));
 }
+#else
+
+/* The Guest calls lguest_set_pmd to set a top-level entry when PAE is not
+ * activated. */
+static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+	native_set_pmd(pmdp, pmdval);
+	lazy_hcall2(LHCALL_SET_PGD, __pa(pmdp) & PAGE_MASK,
+		   (__pa(pmdp) & (PAGE_SIZE - 1)) / sizeof(pmd_t));
+}
+#endif
 
 /* There are a couple of legacy places where the kernel sets a PTE, but we
  * don't know the top level any more.  This is useless for us, since we don't
@@ -552,11 +598,31 @@
  * which brings boot back to 0.25 seconds. */
 static void lguest_set_pte(pte_t *ptep, pte_t pteval)
 {
-	*ptep = pteval;
+	native_set_pte(ptep, pteval);
 	if (cr3_changed)
 		lazy_hcall1(LHCALL_FLUSH_TLB, 1);
 }
 
+#ifdef CONFIG_X86_PAE
+static void lguest_set_pte_atomic(pte_t *ptep, pte_t pte)
+{
+	native_set_pte_atomic(ptep, pte);
+	if (cr3_changed)
+		lazy_hcall1(LHCALL_FLUSH_TLB, 1);
+}
+
+void lguest_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+	native_pte_clear(mm, addr, ptep);
+	lguest_pte_update(mm, addr, ptep);
+}
+
+void lguest_pmd_clear(pmd_t *pmdp)
+{
+	lguest_set_pmd(pmdp, __pmd(0));
+}
+#endif
+
 /* Unfortunately for Lguest, the pv_mmu_ops for page tables were based on
  * native page table operations.  On native hardware you can set a new page
  * table entry whenever you want, but if you want to remove one you have to do
@@ -628,13 +694,12 @@
 {
 	unsigned int i;
 
-	for (i = 0; i < LGUEST_IRQS; i++) {
-		int vector = FIRST_EXTERNAL_VECTOR + i;
+	for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) {
 		/* Some systems map "vectors" to interrupts weirdly.  Lguest has
 		 * a straightforward 1 to 1 mapping, so force that here. */
-		__get_cpu_var(vector_irq)[vector] = i;
-		if (vector != SYSCALL_VECTOR)
-			set_intr_gate(vector, interrupt[i]);
+		__get_cpu_var(vector_irq)[i] = i - FIRST_EXTERNAL_VECTOR;
+		if (i != SYSCALL_VECTOR)
+			set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]);
 	}
 	/* This call is required to set up for 4k stacks, where we have
 	 * separate stacks for hard and soft interrupts. */
@@ -973,10 +1038,10 @@
  *
  * Our current solution is to allow the paravirt back end to optionally patch
  * over the indirect calls to replace them with something more efficient.  We
- * patch the four most commonly called functions: disable interrupts, enable
- * interrupts, restore interrupts and save interrupts.  We usually have 6 or 10
- * bytes to patch into: the Guest versions of these operations are small enough
- * that we can fit comfortably.
+ * patch two of the simplest of the most commonly called functions: disable
+ * interrupts and save interrupts.  We usually have 6 or 10 bytes to patch
+ * into: the Guest versions of these operations are small enough that we can
+ * fit comfortably.
  *
  * First we need assembly templates of each of the patchable Guest operations,
  * and these are in i386_head.S. */
@@ -987,8 +1052,6 @@
 	const char *start, *end;
 } lguest_insns[] = {
 	[PARAVIRT_PATCH(pv_irq_ops.irq_disable)] = { lgstart_cli, lgend_cli },
-	[PARAVIRT_PATCH(pv_irq_ops.irq_enable)] = { lgstart_sti, lgend_sti },
-	[PARAVIRT_PATCH(pv_irq_ops.restore_fl)] = { lgstart_popf, lgend_popf },
 	[PARAVIRT_PATCH(pv_irq_ops.save_fl)] = { lgstart_pushf, lgend_pushf },
 };
 
@@ -1026,6 +1089,7 @@
 	pv_info.name = "lguest";
 	pv_info.paravirt_enabled = 1;
 	pv_info.kernel_rpl = 1;
+	pv_info.shared_kernel_pmd = 1;
 
 	/* We set up all the lguest overrides for sensitive operations.  These
 	 * are detailed with the operations themselves. */
@@ -1033,9 +1097,9 @@
 	/* interrupt-related operations */
 	pv_irq_ops.init_IRQ = lguest_init_IRQ;
 	pv_irq_ops.save_fl = PV_CALLEE_SAVE(save_fl);
-	pv_irq_ops.restore_fl = PV_CALLEE_SAVE(restore_fl);
+	pv_irq_ops.restore_fl = __PV_IS_CALLEE_SAVE(lg_restore_fl);
 	pv_irq_ops.irq_disable = PV_CALLEE_SAVE(irq_disable);
-	pv_irq_ops.irq_enable = PV_CALLEE_SAVE(irq_enable);
+	pv_irq_ops.irq_enable = __PV_IS_CALLEE_SAVE(lg_irq_enable);
 	pv_irq_ops.safe_halt = lguest_safe_halt;
 
 	/* init-time operations */
@@ -1071,6 +1135,12 @@
 	pv_mmu_ops.set_pte = lguest_set_pte;
 	pv_mmu_ops.set_pte_at = lguest_set_pte_at;
 	pv_mmu_ops.set_pmd = lguest_set_pmd;
+#ifdef CONFIG_X86_PAE
+	pv_mmu_ops.set_pte_atomic = lguest_set_pte_atomic;
+	pv_mmu_ops.pte_clear = lguest_pte_clear;
+	pv_mmu_ops.pmd_clear = lguest_pmd_clear;
+	pv_mmu_ops.set_pud = lguest_set_pud;
+#endif
 	pv_mmu_ops.read_cr2 = lguest_read_cr2;
 	pv_mmu_ops.read_cr3 = lguest_read_cr3;
 	pv_mmu_ops.lazy_mode.enter = paravirt_enter_lazy_mmu;
diff --git a/arch/x86/lguest/i386_head.S b/arch/x86/lguest/i386_head.S
index f795419..a9c8cfe 100644
--- a/arch/x86/lguest/i386_head.S
+++ b/arch/x86/lguest/i386_head.S
@@ -46,10 +46,64 @@
 	.globl lgstart_##name; .globl lgend_##name
 
 LGUEST_PATCH(cli, movl $0, lguest_data+LGUEST_DATA_irq_enabled)
-LGUEST_PATCH(sti, movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled)
-LGUEST_PATCH(popf, movl %eax, lguest_data+LGUEST_DATA_irq_enabled)
 LGUEST_PATCH(pushf, movl lguest_data+LGUEST_DATA_irq_enabled, %eax)
-/*:*/
+
+/*G:033 But using those wrappers is inefficient (we'll see why that doesn't
+ * matter for save_fl and irq_disable later).  If we write our routines
+ * carefully in assembler, we can avoid clobbering any registers and avoid
+ * jumping through the wrapper functions.
+ *
+ * I skipped over our first piece of assembler, but this one is worth studying
+ * in a bit more detail so I'll describe in easy stages.  First, the routine
+ * to enable interrupts: */
+ENTRY(lg_irq_enable)
+	/* The reverse of irq_disable, this sets lguest_data.irq_enabled to
+	 * X86_EFLAGS_IF (ie. "Interrupts enabled"). */
+	movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled
+	/* But now we need to check if the Host wants to know: there might have
+	 * been interrupts waiting to be delivered, in which case it will have
+	 * set lguest_data.irq_pending to X86_EFLAGS_IF.  If it's not zero, we
+	 * jump to send_interrupts, otherwise we're done. */
+	testl $0, lguest_data+LGUEST_DATA_irq_pending
+	jnz send_interrupts
+	/* One cool thing about x86 is that you can do many things without using
+	 * a register.  In this case, the normal path hasn't needed to save or
+	 * restore any registers at all! */
+	ret
+send_interrupts:
+	/* OK, now we need a register: eax is used for the hypercall number,
+	 * which is LHCALL_SEND_INTERRUPTS.
+	 *
+	 * We used not to bother with this pending detection at all, which was
+	 * much simpler.  Sooner or later the Host would realize it had to
+	 * send us an interrupt.  But that turns out to make performance 7
+	 * times worse on a simple tcp benchmark.  So now we do this the hard
+	 * way. */
+	pushl %eax
+	movl $LHCALL_SEND_INTERRUPTS, %eax
+	/* This is a vmcall instruction (same thing that KVM uses).  Older
+	 * assembler versions might not know the "vmcall" instruction, so we
+	 * create one manually here. */
+	.byte 0x0f,0x01,0xc1 /* KVM_HYPERCALL */
+	popl %eax
+	ret
+
+/* Finally, the "popf" or "restore flags" routine.  The %eax register holds the
+ * flags (in practice, either X86_EFLAGS_IF or 0): if it's X86_EFLAGS_IF we're
+ * enabling interrupts again, if it's 0 we're leaving them off. */
+ENTRY(lg_restore_fl)
+	/* This is just "lguest_data.irq_enabled = flags;" */
+	movl %eax, lguest_data+LGUEST_DATA_irq_enabled
+	/* Now, if the %eax value has enabled interrupts and
+	 * lguest_data.irq_pending is set, we want to tell the Host so it can
+	 * deliver any outstanding interrupts.  Fortunately, both values will
+	 * be X86_EFLAGS_IF (ie. 512) in that case, and the "testl"
+	 * instruction will AND them together for us.  If both are set, we
+	 * jump to send_interrupts. */
+	testl lguest_data+LGUEST_DATA_irq_pending, %eax
+	jnz send_interrupts
+	/* Again, the normal path has used no extra registers.  Clever, huh? */
+	ret
 
 /* These demark the EIP range where host should never deliver interrupts. */
 .global lguest_noirq_start
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 949708d..9ff3c08 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -564,7 +564,7 @@
 }
 #endif /* !CONFIG_ACPI_SLEEP */
 
-void zap_low_mappings(void)
+void zap_low_mappings(bool early)
 {
 	int i;
 
@@ -581,7 +581,11 @@
 		set_pgd(swapper_pg_dir+i, __pgd(0));
 #endif
 	}
-	flush_tlb_all();
+
+	if (early)
+		__flush_tlb();
+	else
+		flush_tlb_all();
 }
 
 pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP);
@@ -956,7 +960,7 @@
 		test_wp_bit();
 
 	save_pg_dir();
-	zap_low_mappings();
+	zap_low_mappings(true);
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
diff --git a/arch/x86/power/Makefile b/arch/x86/power/Makefile
index 58b32db..de2abbd 100644
--- a/arch/x86/power/Makefile
+++ b/arch/x86/power/Makefile
@@ -3,5 +3,5 @@
 nostackp := $(call cc-option, -fno-stack-protector)
 CFLAGS_cpu_$(BITS).o	:= $(nostackp)
 
-obj-$(CONFIG_PM_SLEEP)		+= cpu_$(BITS).o
+obj-$(CONFIG_PM_SLEEP)		+= cpu.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate_$(BITS).o hibernate_asm_$(BITS).o
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
new file mode 100644
index 0000000..d277ef1
--- /dev/null
+++ b/arch/x86/power/cpu.c
@@ -0,0 +1,259 @@
+/*
+ * Suspend support specific for i386/x86-64.
+ *
+ * Distribute under GPLv2
+ *
+ * Copyright (c) 2007 Rafael J. Wysocki <rjw@sisk.pl>
+ * Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
+ */
+
+#include <linux/suspend.h>
+#include <linux/smp.h>
+
+#include <asm/pgtable.h>
+#include <asm/proto.h>
+#include <asm/mtrr.h>
+#include <asm/page.h>
+#include <asm/mce.h>
+#include <asm/xcr.h>
+#include <asm/suspend.h>
+
+#ifdef CONFIG_X86_32
+static struct saved_context saved_context;
+
+unsigned long saved_context_ebx;
+unsigned long saved_context_esp, saved_context_ebp;
+unsigned long saved_context_esi, saved_context_edi;
+unsigned long saved_context_eflags;
+#else
+/* CONFIG_X86_64 */
+struct saved_context saved_context;
+#endif
+
+/**
+ *	__save_processor_state - save CPU registers before creating a
+ *		hibernation image and before restoring the memory state from it
+ *	@ctxt - structure to store the registers contents in
+ *
+ *	NOTE: If there is a CPU register the modification of which by the
+ *	boot kernel (ie. the kernel used for loading the hibernation image)
+ *	might affect the operations of the restored target kernel (ie. the one
+ *	saved in the hibernation image), then its contents must be saved by this
+ *	function.  In other words, if kernel A is hibernated and different
+ *	kernel B is used for loading the hibernation image into memory, the
+ *	kernel A's __save_processor_state() function must save all registers
+ *	needed by kernel A, so that it can operate correctly after the resume
+ *	regardless of what kernel B does in the meantime.
+ */
+static void __save_processor_state(struct saved_context *ctxt)
+{
+#ifdef CONFIG_X86_32
+	mtrr_save_fixed_ranges(NULL);
+#endif
+	kernel_fpu_begin();
+
+	/*
+	 * descriptor tables
+	 */
+#ifdef CONFIG_X86_32
+	store_gdt(&ctxt->gdt);
+	store_idt(&ctxt->idt);
+#else
+/* CONFIG_X86_64 */
+	store_gdt((struct desc_ptr *)&ctxt->gdt_limit);
+	store_idt((struct desc_ptr *)&ctxt->idt_limit);
+#endif
+	store_tr(ctxt->tr);
+
+	/* XMM0..XMM15 should be handled by kernel_fpu_begin(). */
+	/*
+	 * segment registers
+	 */
+#ifdef CONFIG_X86_32
+	savesegment(es, ctxt->es);
+	savesegment(fs, ctxt->fs);
+	savesegment(gs, ctxt->gs);
+	savesegment(ss, ctxt->ss);
+#else
+/* CONFIG_X86_64 */
+	asm volatile ("movw %%ds, %0" : "=m" (ctxt->ds));
+	asm volatile ("movw %%es, %0" : "=m" (ctxt->es));
+	asm volatile ("movw %%fs, %0" : "=m" (ctxt->fs));
+	asm volatile ("movw %%gs, %0" : "=m" (ctxt->gs));
+	asm volatile ("movw %%ss, %0" : "=m" (ctxt->ss));
+
+	rdmsrl(MSR_FS_BASE, ctxt->fs_base);
+	rdmsrl(MSR_GS_BASE, ctxt->gs_base);
+	rdmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
+	mtrr_save_fixed_ranges(NULL);
+
+	rdmsrl(MSR_EFER, ctxt->efer);
+#endif
+
+	/*
+	 * control registers
+	 */
+	ctxt->cr0 = read_cr0();
+	ctxt->cr2 = read_cr2();
+	ctxt->cr3 = read_cr3();
+#ifdef CONFIG_X86_32
+	ctxt->cr4 = read_cr4_safe();
+#else
+/* CONFIG_X86_64 */
+	ctxt->cr4 = read_cr4();
+	ctxt->cr8 = read_cr8();
+#endif
+}
+
+/* Needed by apm.c */
+void save_processor_state(void)
+{
+	__save_processor_state(&saved_context);
+}
+#ifdef CONFIG_X86_32
+EXPORT_SYMBOL(save_processor_state);
+#endif
+
+static void do_fpu_end(void)
+{
+	/*
+	 * Restore FPU regs if necessary.
+	 */
+	kernel_fpu_end();
+}
+
+static void fix_processor_context(void)
+{
+	int cpu = smp_processor_id();
+	struct tss_struct *t = &per_cpu(init_tss, cpu);
+
+	set_tss_desc(cpu, t);	/*
+				 * This just modifies memory; should not be
+				 * necessary. But... This is necessary, because
+				 * 386 hardware has concept of busy TSS or some
+				 * similar stupidity.
+				 */
+
+#ifdef CONFIG_X86_64
+	get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9;
+
+	syscall_init();				/* This sets MSR_*STAR and related */
+#endif
+	load_TR_desc();				/* This does ltr */
+	load_LDT(&current->active_mm->context);	/* This does lldt */
+
+	/*
+	 * Now maybe reload the debug registers
+	 */
+	if (current->thread.debugreg7) {
+#ifdef CONFIG_X86_32
+		set_debugreg(current->thread.debugreg0, 0);
+		set_debugreg(current->thread.debugreg1, 1);
+		set_debugreg(current->thread.debugreg2, 2);
+		set_debugreg(current->thread.debugreg3, 3);
+		/* no 4 and 5 */
+		set_debugreg(current->thread.debugreg6, 6);
+		set_debugreg(current->thread.debugreg7, 7);
+#else
+		/* CONFIG_X86_64 */
+		loaddebug(&current->thread, 0);
+		loaddebug(&current->thread, 1);
+		loaddebug(&current->thread, 2);
+		loaddebug(&current->thread, 3);
+		/* no 4 and 5 */
+		loaddebug(&current->thread, 6);
+		loaddebug(&current->thread, 7);
+#endif
+	}
+
+}
+
+/**
+ *	__restore_processor_state - restore the contents of CPU registers saved
+ *		by __save_processor_state()
+ *	@ctxt - structure to load the registers contents from
+ */
+static void __restore_processor_state(struct saved_context *ctxt)
+{
+	/*
+	 * control registers
+	 */
+	/* cr4 was introduced in the Pentium CPU */
+#ifdef CONFIG_X86_32
+	if (ctxt->cr4)
+		write_cr4(ctxt->cr4);
+#else
+/* CONFIG X86_64 */
+	wrmsrl(MSR_EFER, ctxt->efer);
+	write_cr8(ctxt->cr8);
+	write_cr4(ctxt->cr4);
+#endif
+	write_cr3(ctxt->cr3);
+	write_cr2(ctxt->cr2);
+	write_cr0(ctxt->cr0);
+
+	/*
+	 * now restore the descriptor tables to their proper values
+	 * ltr is done i fix_processor_context().
+	 */
+#ifdef CONFIG_X86_32
+	load_gdt(&ctxt->gdt);
+	load_idt(&ctxt->idt);
+#else
+/* CONFIG_X86_64 */
+	load_gdt((const struct desc_ptr *)&ctxt->gdt_limit);
+	load_idt((const struct desc_ptr *)&ctxt->idt_limit);
+#endif
+
+	/*
+	 * segment registers
+	 */
+#ifdef CONFIG_X86_32
+	loadsegment(es, ctxt->es);
+	loadsegment(fs, ctxt->fs);
+	loadsegment(gs, ctxt->gs);
+	loadsegment(ss, ctxt->ss);
+
+	/*
+	 * sysenter MSRs
+	 */
+	if (boot_cpu_has(X86_FEATURE_SEP))
+		enable_sep_cpu();
+#else
+/* CONFIG_X86_64 */
+	asm volatile ("movw %0, %%ds" :: "r" (ctxt->ds));
+	asm volatile ("movw %0, %%es" :: "r" (ctxt->es));
+	asm volatile ("movw %0, %%fs" :: "r" (ctxt->fs));
+	load_gs_index(ctxt->gs);
+	asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
+
+	wrmsrl(MSR_FS_BASE, ctxt->fs_base);
+	wrmsrl(MSR_GS_BASE, ctxt->gs_base);
+	wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
+#endif
+
+	/*
+	 * restore XCR0 for xsave capable cpu's.
+	 */
+	if (cpu_has_xsave)
+		xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
+
+	fix_processor_context();
+
+	do_fpu_end();
+	mtrr_ap_init();
+
+#ifdef CONFIG_X86_32
+	mcheck_init(&boot_cpu_data);
+#endif
+}
+
+/* Needed by apm.c */
+void restore_processor_state(void)
+{
+	__restore_processor_state(&saved_context);
+}
+#ifdef CONFIG_X86_32
+EXPORT_SYMBOL(restore_processor_state);
+#endif
diff --git a/arch/x86/power/cpu_32.c b/arch/x86/power/cpu_32.c
deleted file mode 100644
index ce702c5..0000000
--- a/arch/x86/power/cpu_32.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Suspend support specific for i386.
- *
- * Distribute under GPLv2
- *
- * Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
- * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
- */
-
-#include <linux/module.h>
-#include <linux/suspend.h>
-#include <asm/mtrr.h>
-#include <asm/mce.h>
-#include <asm/xcr.h>
-#include <asm/suspend.h>
-
-static struct saved_context saved_context;
-
-unsigned long saved_context_ebx;
-unsigned long saved_context_esp, saved_context_ebp;
-unsigned long saved_context_esi, saved_context_edi;
-unsigned long saved_context_eflags;
-
-static void __save_processor_state(struct saved_context *ctxt)
-{
-	mtrr_save_fixed_ranges(NULL);
-	kernel_fpu_begin();
-
-	/*
-	 * descriptor tables
-	 */
-	store_gdt(&ctxt->gdt);
-	store_idt(&ctxt->idt);
-	store_tr(ctxt->tr);
-
-	/*
-	 * segment registers
-	 */
-	savesegment(es, ctxt->es);
-	savesegment(fs, ctxt->fs);
-	savesegment(gs, ctxt->gs);
-	savesegment(ss, ctxt->ss);
-
-	/*
-	 * control registers
-	 */
-	ctxt->cr0 = read_cr0();
-	ctxt->cr2 = read_cr2();
-	ctxt->cr3 = read_cr3();
-	ctxt->cr4 = read_cr4_safe();
-}
-
-/* Needed by apm.c */
-void save_processor_state(void)
-{
-	__save_processor_state(&saved_context);
-}
-EXPORT_SYMBOL(save_processor_state);
-
-static void do_fpu_end(void)
-{
-	/*
-	 * Restore FPU regs if necessary.
-	 */
-	kernel_fpu_end();
-}
-
-static void fix_processor_context(void)
-{
-	int cpu = smp_processor_id();
-	struct tss_struct *t = &per_cpu(init_tss, cpu);
-
-	set_tss_desc(cpu, t);	/*
-				 * This just modifies memory; should not be
-				 * necessary. But... This is necessary, because
-				 * 386 hardware has concept of busy TSS or some
-				 * similar stupidity.
-				 */
-
-	load_TR_desc();				/* This does ltr */
-	load_LDT(&current->active_mm->context);	/* This does lldt */
-
-	/*
-	 * Now maybe reload the debug registers
-	 */
-	if (current->thread.debugreg7) {
-		set_debugreg(current->thread.debugreg0, 0);
-		set_debugreg(current->thread.debugreg1, 1);
-		set_debugreg(current->thread.debugreg2, 2);
-		set_debugreg(current->thread.debugreg3, 3);
-		/* no 4 and 5 */
-		set_debugreg(current->thread.debugreg6, 6);
-		set_debugreg(current->thread.debugreg7, 7);
-	}
-
-}
-
-static void __restore_processor_state(struct saved_context *ctxt)
-{
-	/*
-	 * control registers
-	 */
-	/* cr4 was introduced in the Pentium CPU */
-	if (ctxt->cr4)
-		write_cr4(ctxt->cr4);
-	write_cr3(ctxt->cr3);
-	write_cr2(ctxt->cr2);
-	write_cr0(ctxt->cr0);
-
-	/*
-	 * now restore the descriptor tables to their proper values
-	 * ltr is done i fix_processor_context().
-	 */
-	load_gdt(&ctxt->gdt);
-	load_idt(&ctxt->idt);
-
-	/*
-	 * segment registers
-	 */
-	loadsegment(es, ctxt->es);
-	loadsegment(fs, ctxt->fs);
-	loadsegment(gs, ctxt->gs);
-	loadsegment(ss, ctxt->ss);
-
-	/*
-	 * sysenter MSRs
-	 */
-	if (boot_cpu_has(X86_FEATURE_SEP))
-		enable_sep_cpu();
-
-	/*
-	 * restore XCR0 for xsave capable cpu's.
-	 */
-	if (cpu_has_xsave)
-		xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
-
-	fix_processor_context();
-	do_fpu_end();
-	mtrr_ap_init();
-	mcheck_init(&boot_cpu_data);
-}
-
-/* Needed by apm.c */
-void restore_processor_state(void)
-{
-	__restore_processor_state(&saved_context);
-}
-EXPORT_SYMBOL(restore_processor_state);
diff --git a/arch/x86/power/cpu_64.c b/arch/x86/power/cpu_64.c
deleted file mode 100644
index 5343540..0000000
--- a/arch/x86/power/cpu_64.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Suspend and hibernation support for x86-64
- *
- * Distribute under GPLv2
- *
- * Copyright (c) 2007 Rafael J. Wysocki <rjw@sisk.pl>
- * Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
- * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
- */
-
-#include <linux/smp.h>
-#include <linux/suspend.h>
-#include <asm/proto.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/mtrr.h>
-#include <asm/xcr.h>
-#include <asm/suspend.h>
-
-static void fix_processor_context(void);
-
-struct saved_context saved_context;
-
-/**
- *	__save_processor_state - save CPU registers before creating a
- *		hibernation image and before restoring the memory state from it
- *	@ctxt - structure to store the registers contents in
- *
- *	NOTE: If there is a CPU register the modification of which by the
- *	boot kernel (ie. the kernel used for loading the hibernation image)
- *	might affect the operations of the restored target kernel (ie. the one
- *	saved in the hibernation image), then its contents must be saved by this
- *	function.  In other words, if kernel A is hibernated and different
- *	kernel B is used for loading the hibernation image into memory, the
- *	kernel A's __save_processor_state() function must save all registers
- *	needed by kernel A, so that it can operate correctly after the resume
- *	regardless of what kernel B does in the meantime.
- */
-static void __save_processor_state(struct saved_context *ctxt)
-{
-	kernel_fpu_begin();
-
-	/*
-	 * descriptor tables
-	 */
-	store_gdt((struct desc_ptr *)&ctxt->gdt_limit);
-	store_idt((struct desc_ptr *)&ctxt->idt_limit);
-	store_tr(ctxt->tr);
-
-	/* XMM0..XMM15 should be handled by kernel_fpu_begin(). */
-	/*
-	 * segment registers
-	 */
-	asm volatile ("movw %%ds, %0" : "=m" (ctxt->ds));
-	asm volatile ("movw %%es, %0" : "=m" (ctxt->es));
-	asm volatile ("movw %%fs, %0" : "=m" (ctxt->fs));
-	asm volatile ("movw %%gs, %0" : "=m" (ctxt->gs));
-	asm volatile ("movw %%ss, %0" : "=m" (ctxt->ss));
-
-	rdmsrl(MSR_FS_BASE, ctxt->fs_base);
-	rdmsrl(MSR_GS_BASE, ctxt->gs_base);
-	rdmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
-	mtrr_save_fixed_ranges(NULL);
-
-	/*
-	 * control registers
-	 */
-	rdmsrl(MSR_EFER, ctxt->efer);
-	ctxt->cr0 = read_cr0();
-	ctxt->cr2 = read_cr2();
-	ctxt->cr3 = read_cr3();
-	ctxt->cr4 = read_cr4();
-	ctxt->cr8 = read_cr8();
-}
-
-void save_processor_state(void)
-{
-	__save_processor_state(&saved_context);
-}
-
-static void do_fpu_end(void)
-{
-	/*
-	 * Restore FPU regs if necessary
-	 */
-	kernel_fpu_end();
-}
-
-/**
- *	__restore_processor_state - restore the contents of CPU registers saved
- *		by __save_processor_state()
- *	@ctxt - structure to load the registers contents from
- */
-static void __restore_processor_state(struct saved_context *ctxt)
-{
-	/*
-	 * control registers
-	 */
-	wrmsrl(MSR_EFER, ctxt->efer);
-	write_cr8(ctxt->cr8);
-	write_cr4(ctxt->cr4);
-	write_cr3(ctxt->cr3);
-	write_cr2(ctxt->cr2);
-	write_cr0(ctxt->cr0);
-
-	/*
-	 * now restore the descriptor tables to their proper values
-	 * ltr is done i fix_processor_context().
-	 */
-	load_gdt((const struct desc_ptr *)&ctxt->gdt_limit);
-	load_idt((const struct desc_ptr *)&ctxt->idt_limit);
-
-
-	/*
-	 * segment registers
-	 */
-	asm volatile ("movw %0, %%ds" :: "r" (ctxt->ds));
-	asm volatile ("movw %0, %%es" :: "r" (ctxt->es));
-	asm volatile ("movw %0, %%fs" :: "r" (ctxt->fs));
-	load_gs_index(ctxt->gs);
-	asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
-
-	wrmsrl(MSR_FS_BASE, ctxt->fs_base);
-	wrmsrl(MSR_GS_BASE, ctxt->gs_base);
-	wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
-
-	/*
-	 * restore XCR0 for xsave capable cpu's.
-	 */
-	if (cpu_has_xsave)
-		xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
-
-	fix_processor_context();
-
-	do_fpu_end();
-	mtrr_ap_init();
-}
-
-void restore_processor_state(void)
-{
-	__restore_processor_state(&saved_context);
-}
-
-static void fix_processor_context(void)
-{
-	int cpu = smp_processor_id();
-	struct tss_struct *t = &per_cpu(init_tss, cpu);
-
-	/*
-	 * This just modifies memory; should not be necessary. But... This
-	 * is necessary, because 386 hardware has concept of busy TSS or some
-	 * similar stupidity.
-	 */
-	set_tss_desc(cpu, t);
-
-	get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9;
-
-	syscall_init();                         /* This sets MSR_*STAR and related */
-	load_TR_desc();				/* This does ltr */
-	load_LDT(&current->active_mm->context);	/* This does lldt */
-
-	/*
-	 * Now maybe reload the debug registers
-	 */
-	if (current->thread.debugreg7){
-                loaddebug(&current->thread, 0);
-                loaddebug(&current->thread, 1);
-                loaddebug(&current->thread, 2);
-                loaddebug(&current->thread, 3);
-                /* no 4 and 5 */
-                loaddebug(&current->thread, 6);
-                loaddebug(&current->thread, 7);
-	}
-}
diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h
index 67ad67b..22d6dde 100644
--- a/arch/xtensa/include/asm/atomic.h
+++ b/arch/xtensa/include/asm/atomic.h
@@ -292,7 +292,7 @@
 #define smp_mb__before_atomic_inc()	barrier()
 #define smp_mb__after_atomic_inc()	barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* __KERNEL__ */
 
 #endif /* _XTENSA_ATOMIC_H */
diff --git a/arch/xtensa/include/asm/bitsperlong.h b/arch/xtensa/include/asm/bitsperlong.h
new file mode 100644
index 0000000..6dc0bb0
--- /dev/null
+++ b/arch/xtensa/include/asm/bitsperlong.h
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
diff --git a/arch/xtensa/include/asm/page.h b/arch/xtensa/include/asm/page.h
index 17e0c53..161bb89 100644
--- a/arch/xtensa/include/asm/page.h
+++ b/arch/xtensa/include/asm/page.h
@@ -129,7 +129,7 @@
 
 #else
 
-# include <asm-generic/page.h>
+# include <asm-generic/getorder.h>
 
 #endif
 
diff --git a/arch/xtensa/kernel/module.c b/arch/xtensa/kernel/module.c
index 3981a46..c1accea 100644
--- a/arch/xtensa/kernel/module.c
+++ b/arch/xtensa/kernel/module.c
@@ -34,8 +34,6 @@
 void module_free(struct module *mod, void *module_region)
 {
 	vfree(module_region);
-	/* FIXME: If module_region == mod->init_region, trim exception
-	   table entries. */
 }
 
 int module_frob_arch_sections(Elf32_Ehdr *hdr,
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 74d0e62..4dfdd03 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -241,6 +241,11 @@
 	  key size 256, 384 or 512 bits. This implementation currently
 	  can't handle a sectorsize which is not a multiple of 16 bytes.
 
+config CRYPTO_FPU
+	tristate
+	select CRYPTO_BLKCIPHER
+	select CRYPTO_MANAGER
+
 comment "Hash modes"
 
 config CRYPTO_HMAC
@@ -486,6 +491,7 @@
 	select CRYPTO_AES_X86_64
 	select CRYPTO_CRYPTD
 	select CRYPTO_ALGAPI
+	select CRYPTO_FPU
 	help
 	  Use Intel AES-NI instructions for AES algorithm.
 
@@ -505,6 +511,10 @@
 
 	  See <http://csrc.nist.gov/encryption/aes/> for more information.
 
+	  In addition to AES cipher algorithm support, the
+	  acceleration for some popular block cipher mode is supported
+	  too, including ECB, CBC, CTR, LRW, PCBC, XTS.
+
 config CRYPTO_ANUBIS
 	tristate "Anubis cipher algorithm"
 	select CRYPTO_ALGAPI
diff --git a/crypto/algboss.c b/crypto/algboss.c
index 6906f92..9908dd8 100644
--- a/crypto/algboss.c
+++ b/crypto/algboss.c
@@ -280,29 +280,13 @@
 
 static int __init cryptomgr_init(void)
 {
-	int err;
-
-	err = testmgr_init();
-	if (err)
-		return err;
-
-	err = crypto_register_notifier(&cryptomgr_notifier);
-	if (err)
-		goto free_testmgr;
-
-	return 0;
-
-free_testmgr:
-	testmgr_exit();
-	return err;
+	return crypto_register_notifier(&cryptomgr_notifier);
 }
 
 static void __exit cryptomgr_exit(void)
 {
 	int err = crypto_unregister_notifier(&cryptomgr_notifier);
 	BUG_ON(err);
-
-	testmgr_exit();
 }
 
 subsys_initcall(cryptomgr_init);
diff --git a/crypto/api.c b/crypto/api.c
index fd2545d..d5944f9 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -217,14 +217,11 @@
 
 	alg = crypto_alg_lookup(name, type, mask);
 	if (!alg) {
-		char tmp[CRYPTO_MAX_ALG_NAME];
-
-		request_module(name);
+		request_module("%s", name);
 
 		if (!((type ^ CRYPTO_ALG_NEED_FALLBACK) & mask &
-		      CRYPTO_ALG_NEED_FALLBACK) &&
-		    snprintf(tmp, sizeof(tmp), "%s-all", name) < sizeof(tmp))
-			request_module(tmp);
+		      CRYPTO_ALG_NEED_FALLBACK))
+			request_module("%s-all", name);
 
 		alg = crypto_alg_lookup(name, type, mask);
 	}
@@ -580,20 +577,17 @@
 void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm)
 {
 	struct crypto_alg *alg;
-	int size;
 
 	if (unlikely(!mem))
 		return;
 
 	alg = tfm->__crt_alg;
-	size = ksize(mem);
 
 	if (!tfm->exit && alg->cra_exit)
 		alg->cra_exit(tfm);
 	crypto_exit_ops(tfm);
 	crypto_mod_put(alg);
-	memset(mem, 0, size);
-	kfree(mem);
+	kzfree(mem);
 }
 EXPORT_SYMBOL_GPL(crypto_destroy_tfm);
 
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index d14b226..ae5fa99 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -586,20 +586,24 @@
 						  u32 type, u32 mask)
 {
 	char cryptd_alg_name[CRYPTO_MAX_ALG_NAME];
-	struct crypto_ablkcipher *tfm;
+	struct crypto_tfm *tfm;
 
 	if (snprintf(cryptd_alg_name, CRYPTO_MAX_ALG_NAME,
 		     "cryptd(%s)", alg_name) >= CRYPTO_MAX_ALG_NAME)
 		return ERR_PTR(-EINVAL);
-	tfm = crypto_alloc_ablkcipher(cryptd_alg_name, type, mask);
+	type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+	type |= CRYPTO_ALG_TYPE_BLKCIPHER;
+	mask &= ~CRYPTO_ALG_TYPE_MASK;
+	mask |= (CRYPTO_ALG_GENIV | CRYPTO_ALG_TYPE_BLKCIPHER_MASK);
+	tfm = crypto_alloc_base(cryptd_alg_name, type, mask);
 	if (IS_ERR(tfm))
 		return ERR_CAST(tfm);
-	if (crypto_ablkcipher_tfm(tfm)->__crt_alg->cra_module != THIS_MODULE) {
-		crypto_free_ablkcipher(tfm);
+	if (tfm->__crt_alg->cra_module != THIS_MODULE) {
+		crypto_free_tfm(tfm);
 		return ERR_PTR(-EINVAL);
 	}
 
-	return __cryptd_ablkcipher_cast(tfm);
+	return __cryptd_ablkcipher_cast(__crypto_ablkcipher_cast(tfm));
 }
 EXPORT_SYMBOL_GPL(cryptd_alloc_ablkcipher);
 
diff --git a/crypto/internal.h b/crypto/internal.h
index fc76e1f..113579a 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -121,9 +121,6 @@
 int crypto_unregister_notifier(struct notifier_block *nb);
 int crypto_probing_notify(unsigned long val, void *v);
 
-int __init testmgr_init(void);
-void testmgr_exit(void);
-
 static inline void crypto_alg_put(struct crypto_alg *alg)
 {
 	if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy)
diff --git a/crypto/pcompress.c b/crypto/pcompress.c
index ca9a4af..bcadc03 100644
--- a/crypto/pcompress.c
+++ b/crypto/pcompress.c
@@ -26,6 +26,7 @@
 #include <linux/string.h>
 
 #include <crypto/compress.h>
+#include <crypto/internal/compress.h>
 
 #include "internal.h"
 
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index c3c9124..d59ba50 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -27,6 +27,7 @@
 #include <linux/timex.h>
 #include <linux/interrupt.h>
 #include "tcrypt.h"
+#include "internal.h"
 
 /*
  * Need slab memory for testing (size in number of pages).
@@ -396,16 +397,16 @@
 	struct scatterlist sg[TVMEMSIZE];
 	struct crypto_hash *tfm;
 	struct hash_desc desc;
-	char output[1024];
+	static char output[1024];
 	int i;
 	int ret;
 
-	printk("\ntesting speed of %s\n", algo);
+	printk(KERN_INFO "\ntesting speed of %s\n", algo);
 
 	tfm = crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC);
 
 	if (IS_ERR(tfm)) {
-		printk("failed to load transform for %s: %ld\n", algo,
+		printk(KERN_ERR "failed to load transform for %s: %ld\n", algo,
 		       PTR_ERR(tfm));
 		return;
 	}
@@ -414,7 +415,7 @@
 	desc.flags = 0;
 
 	if (crypto_hash_digestsize(tfm) > sizeof(output)) {
-		printk("digestsize(%u) > outputbuffer(%zu)\n",
+		printk(KERN_ERR "digestsize(%u) > outputbuffer(%zu)\n",
 		       crypto_hash_digestsize(tfm), sizeof(output));
 		goto out;
 	}
@@ -427,12 +428,14 @@
 
 	for (i = 0; speed[i].blen != 0; i++) {
 		if (speed[i].blen > TVMEMSIZE * PAGE_SIZE) {
-			printk("template (%u) too big for tvmem (%lu)\n",
+			printk(KERN_ERR
+			       "template (%u) too big for tvmem (%lu)\n",
 			       speed[i].blen, TVMEMSIZE * PAGE_SIZE);
 			goto out;
 		}
 
-		printk("test%3u (%5u byte blocks,%5u bytes per update,%4u updates): ",
+		printk(KERN_INFO "test%3u "
+		       "(%5u byte blocks,%5u bytes per update,%4u updates): ",
 		       i, speed[i].blen, speed[i].plen, speed[i].blen / speed[i].plen);
 
 		if (sec)
@@ -443,7 +446,7 @@
 					       speed[i].plen, output);
 
 		if (ret) {
-			printk("hashing failed ret=%d\n", ret);
+			printk(KERN_ERR "hashing failed ret=%d\n", ret);
 			break;
 		}
 	}
@@ -466,239 +469,255 @@
 
 static inline int tcrypt_test(const char *alg)
 {
-	return alg_test(alg, alg, 0, 0);
+	int ret;
+
+	ret = alg_test(alg, alg, 0, 0);
+	/* non-fips algs return -EINVAL in fips mode */
+	if (fips_enabled && ret == -EINVAL)
+		ret = 0;
+	return ret;
 }
 
-static void do_test(int m)
+static int do_test(int m)
 {
 	int i;
+	int ret = 0;
 
 	switch (m) {
 	case 0:
 		for (i = 1; i < 200; i++)
-			do_test(i);
+			ret += do_test(i);
 		break;
 
 	case 1:
-		tcrypt_test("md5");
+		ret += tcrypt_test("md5");
 		break;
 
 	case 2:
-		tcrypt_test("sha1");
+		ret += tcrypt_test("sha1");
 		break;
 
 	case 3:
-		tcrypt_test("ecb(des)");
-		tcrypt_test("cbc(des)");
+		ret += tcrypt_test("ecb(des)");
+		ret += tcrypt_test("cbc(des)");
 		break;
 
 	case 4:
-		tcrypt_test("ecb(des3_ede)");
-		tcrypt_test("cbc(des3_ede)");
+		ret += tcrypt_test("ecb(des3_ede)");
+		ret += tcrypt_test("cbc(des3_ede)");
 		break;
 
 	case 5:
-		tcrypt_test("md4");
+		ret += tcrypt_test("md4");
 		break;
 
 	case 6:
-		tcrypt_test("sha256");
+		ret += tcrypt_test("sha256");
 		break;
 
 	case 7:
-		tcrypt_test("ecb(blowfish)");
-		tcrypt_test("cbc(blowfish)");
+		ret += tcrypt_test("ecb(blowfish)");
+		ret += tcrypt_test("cbc(blowfish)");
 		break;
 
 	case 8:
-		tcrypt_test("ecb(twofish)");
-		tcrypt_test("cbc(twofish)");
+		ret += tcrypt_test("ecb(twofish)");
+		ret += tcrypt_test("cbc(twofish)");
 		break;
 
 	case 9:
-		tcrypt_test("ecb(serpent)");
+		ret += tcrypt_test("ecb(serpent)");
 		break;
 
 	case 10:
-		tcrypt_test("ecb(aes)");
-		tcrypt_test("cbc(aes)");
-		tcrypt_test("lrw(aes)");
-		tcrypt_test("xts(aes)");
-		tcrypt_test("rfc3686(ctr(aes))");
+		ret += tcrypt_test("ecb(aes)");
+		ret += tcrypt_test("cbc(aes)");
+		ret += tcrypt_test("lrw(aes)");
+		ret += tcrypt_test("xts(aes)");
+		ret += tcrypt_test("ctr(aes)");
+		ret += tcrypt_test("rfc3686(ctr(aes))");
 		break;
 
 	case 11:
-		tcrypt_test("sha384");
+		ret += tcrypt_test("sha384");
 		break;
 
 	case 12:
-		tcrypt_test("sha512");
+		ret += tcrypt_test("sha512");
 		break;
 
 	case 13:
-		tcrypt_test("deflate");
+		ret += tcrypt_test("deflate");
 		break;
 
 	case 14:
-		tcrypt_test("ecb(cast5)");
+		ret += tcrypt_test("ecb(cast5)");
 		break;
 
 	case 15:
-		tcrypt_test("ecb(cast6)");
+		ret += tcrypt_test("ecb(cast6)");
 		break;
 
 	case 16:
-		tcrypt_test("ecb(arc4)");
+		ret += tcrypt_test("ecb(arc4)");
 		break;
 
 	case 17:
-		tcrypt_test("michael_mic");
+		ret += tcrypt_test("michael_mic");
 		break;
 
 	case 18:
-		tcrypt_test("crc32c");
+		ret += tcrypt_test("crc32c");
 		break;
 
 	case 19:
-		tcrypt_test("ecb(tea)");
+		ret += tcrypt_test("ecb(tea)");
 		break;
 
 	case 20:
-		tcrypt_test("ecb(xtea)");
+		ret += tcrypt_test("ecb(xtea)");
 		break;
 
 	case 21:
-		tcrypt_test("ecb(khazad)");
+		ret += tcrypt_test("ecb(khazad)");
 		break;
 
 	case 22:
-		tcrypt_test("wp512");
+		ret += tcrypt_test("wp512");
 		break;
 
 	case 23:
-		tcrypt_test("wp384");
+		ret += tcrypt_test("wp384");
 		break;
 
 	case 24:
-		tcrypt_test("wp256");
+		ret += tcrypt_test("wp256");
 		break;
 
 	case 25:
-		tcrypt_test("ecb(tnepres)");
+		ret += tcrypt_test("ecb(tnepres)");
 		break;
 
 	case 26:
-		tcrypt_test("ecb(anubis)");
-		tcrypt_test("cbc(anubis)");
+		ret += tcrypt_test("ecb(anubis)");
+		ret += tcrypt_test("cbc(anubis)");
 		break;
 
 	case 27:
-		tcrypt_test("tgr192");
+		ret += tcrypt_test("tgr192");
 		break;
 
 	case 28:
 
-		tcrypt_test("tgr160");
+		ret += tcrypt_test("tgr160");
 		break;
 
 	case 29:
-		tcrypt_test("tgr128");
+		ret += tcrypt_test("tgr128");
 		break;
 
 	case 30:
-		tcrypt_test("ecb(xeta)");
+		ret += tcrypt_test("ecb(xeta)");
 		break;
 
 	case 31:
-		tcrypt_test("pcbc(fcrypt)");
+		ret += tcrypt_test("pcbc(fcrypt)");
 		break;
 
 	case 32:
-		tcrypt_test("ecb(camellia)");
-		tcrypt_test("cbc(camellia)");
+		ret += tcrypt_test("ecb(camellia)");
+		ret += tcrypt_test("cbc(camellia)");
 		break;
 	case 33:
-		tcrypt_test("sha224");
+		ret += tcrypt_test("sha224");
 		break;
 
 	case 34:
-		tcrypt_test("salsa20");
+		ret += tcrypt_test("salsa20");
 		break;
 
 	case 35:
-		tcrypt_test("gcm(aes)");
+		ret += tcrypt_test("gcm(aes)");
 		break;
 
 	case 36:
-		tcrypt_test("lzo");
+		ret += tcrypt_test("lzo");
 		break;
 
 	case 37:
-		tcrypt_test("ccm(aes)");
+		ret += tcrypt_test("ccm(aes)");
 		break;
 
 	case 38:
-		tcrypt_test("cts(cbc(aes))");
+		ret += tcrypt_test("cts(cbc(aes))");
 		break;
 
         case 39:
-		tcrypt_test("rmd128");
+		ret += tcrypt_test("rmd128");
 		break;
 
         case 40:
-		tcrypt_test("rmd160");
+		ret += tcrypt_test("rmd160");
 		break;
 
 	case 41:
-		tcrypt_test("rmd256");
+		ret += tcrypt_test("rmd256");
 		break;
 
 	case 42:
-		tcrypt_test("rmd320");
+		ret += tcrypt_test("rmd320");
 		break;
 
 	case 43:
-		tcrypt_test("ecb(seed)");
+		ret += tcrypt_test("ecb(seed)");
 		break;
 
 	case 44:
-		tcrypt_test("zlib");
+		ret += tcrypt_test("zlib");
+		break;
+
+	case 45:
+		ret += tcrypt_test("rfc4309(ccm(aes))");
 		break;
 
 	case 100:
-		tcrypt_test("hmac(md5)");
+		ret += tcrypt_test("hmac(md5)");
 		break;
 
 	case 101:
-		tcrypt_test("hmac(sha1)");
+		ret += tcrypt_test("hmac(sha1)");
 		break;
 
 	case 102:
-		tcrypt_test("hmac(sha256)");
+		ret += tcrypt_test("hmac(sha256)");
 		break;
 
 	case 103:
-		tcrypt_test("hmac(sha384)");
+		ret += tcrypt_test("hmac(sha384)");
 		break;
 
 	case 104:
-		tcrypt_test("hmac(sha512)");
+		ret += tcrypt_test("hmac(sha512)");
 		break;
 
 	case 105:
-		tcrypt_test("hmac(sha224)");
+		ret += tcrypt_test("hmac(sha224)");
 		break;
 
 	case 106:
-		tcrypt_test("xcbc(aes)");
+		ret += tcrypt_test("xcbc(aes)");
 		break;
 
 	case 107:
-		tcrypt_test("hmac(rmd128)");
+		ret += tcrypt_test("hmac(rmd128)");
 		break;
 
 	case 108:
-		tcrypt_test("hmac(rmd160)");
+		ret += tcrypt_test("hmac(rmd160)");
+		break;
+
+	case 150:
+		ret += tcrypt_test("ansi_cprng");
 		break;
 
 	case 200:
@@ -862,6 +881,8 @@
 		test_available();
 		break;
 	}
+
+	return ret;
 }
 
 static int __init tcrypt_mod_init(void)
@@ -875,15 +896,21 @@
 			goto err_free_tv;
 	}
 
-	do_test(mode);
+	err = do_test(mode);
+	if (err) {
+		printk(KERN_ERR "tcrypt: one or more tests failed!\n");
+		goto err_free_tv;
+	}
 
-	/* We intentionaly return -EAGAIN to prevent keeping
-	 * the module. It does all its work from init()
-	 * and doesn't offer any runtime functionality 
+	/* We intentionaly return -EAGAIN to prevent keeping the module,
+	 * unless we're running in fips mode. It does all its work from
+	 * init() and doesn't offer any runtime functionality, but in
+	 * the fips case, checking for a successful load is helpful.
 	 * => we don't need it in the memory, do we?
 	 *                                        -- mludvig
 	 */
-	err = -EAGAIN;
+	if (!fips_enabled)
+		err = -EAGAIN;
 
 err_free_tv:
 	for (i = 0; i < TVMEMSIZE && tvmem[i]; i++)
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index b50c3c6..e9e9d84 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -19,6 +19,7 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <crypto/rng.h>
 
 #include "internal.h"
 #include "testmgr.h"
@@ -84,10 +85,16 @@
 	unsigned int count;
 };
 
+struct cprng_test_suite {
+	struct cprng_testvec *vecs;
+	unsigned int count;
+};
+
 struct alg_test_desc {
 	const char *alg;
 	int (*test)(const struct alg_test_desc *desc, const char *driver,
 		    u32 type, u32 mask);
+	int fips_allowed;	/* set if alg is allowed in fips mode */
 
 	union {
 		struct aead_test_suite aead;
@@ -95,14 +102,12 @@
 		struct comp_test_suite comp;
 		struct pcomp_test_suite pcomp;
 		struct hash_test_suite hash;
+		struct cprng_test_suite cprng;
 	} suite;
 };
 
 static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 };
 
-static char *xbuf[XBUFSIZE];
-static char *axbuf[XBUFSIZE];
-
 static void hexdump(unsigned char *buf, unsigned int len)
 {
 	print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
@@ -121,6 +126,33 @@
 	complete(&res->completion);
 }
 
+static int testmgr_alloc_buf(char *buf[XBUFSIZE])
+{
+	int i;
+
+	for (i = 0; i < XBUFSIZE; i++) {
+		buf[i] = (void *)__get_free_page(GFP_KERNEL);
+		if (!buf[i])
+			goto err_free_buf;
+	}
+
+	return 0;
+
+err_free_buf:
+	while (i-- > 0)
+		free_page((unsigned long)buf[i]);
+
+	return -ENOMEM;
+}
+
+static void testmgr_free_buf(char *buf[XBUFSIZE])
+{
+	int i;
+
+	for (i = 0; i < XBUFSIZE; i++)
+		free_page((unsigned long)buf[i]);
+}
+
 static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
 		     unsigned int tcount)
 {
@@ -130,8 +162,12 @@
 	char result[64];
 	struct ahash_request *req;
 	struct tcrypt_result tresult;
-	int ret;
 	void *hash_buff;
+	char *xbuf[XBUFSIZE];
+	int ret = -ENOMEM;
+
+	if (testmgr_alloc_buf(xbuf))
+		goto out_nobuf;
 
 	init_completion(&tresult.completion);
 
@@ -139,17 +175,25 @@
 	if (!req) {
 		printk(KERN_ERR "alg: hash: Failed to allocate request for "
 		       "%s\n", algo);
-		ret = -ENOMEM;
 		goto out_noreq;
 	}
 	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
 				   tcrypt_complete, &tresult);
 
+	j = 0;
 	for (i = 0; i < tcount; i++) {
+		if (template[i].np)
+			continue;
+
+		j++;
 		memset(result, 0, 64);
 
 		hash_buff = xbuf[0];
 
+		ret = -EINVAL;
+		if (WARN_ON(template[i].psize > PAGE_SIZE))
+			goto out;
+
 		memcpy(hash_buff, template[i].plaintext, template[i].psize);
 		sg_init_one(&sg[0], hash_buff, template[i].psize);
 
@@ -159,7 +203,7 @@
 						  template[i].ksize);
 			if (ret) {
 				printk(KERN_ERR "alg: hash: setkey failed on "
-				       "test %d for %s: ret=%d\n", i + 1, algo,
+				       "test %d for %s: ret=%d\n", j, algo,
 				       -ret);
 				goto out;
 			}
@@ -181,14 +225,14 @@
 			/* fall through */
 		default:
 			printk(KERN_ERR "alg: hash: digest failed on test %d "
-			       "for %s: ret=%d\n", i + 1, algo, -ret);
+			       "for %s: ret=%d\n", j, algo, -ret);
 			goto out;
 		}
 
 		if (memcmp(result, template[i].digest,
 			   crypto_ahash_digestsize(tfm))) {
 			printk(KERN_ERR "alg: hash: Test %d failed for %s\n",
-			       i + 1, algo);
+			       j, algo);
 			hexdump(result, crypto_ahash_digestsize(tfm));
 			ret = -EINVAL;
 			goto out;
@@ -203,7 +247,11 @@
 
 			temp = 0;
 			sg_init_table(sg, template[i].np);
+			ret = -EINVAL;
 			for (k = 0; k < template[i].np; k++) {
+				if (WARN_ON(offset_in_page(IDX[k]) +
+					    template[i].tap[k] > PAGE_SIZE))
+					goto out;
 				sg_set_buf(&sg[k],
 					   memcpy(xbuf[IDX[k] >> PAGE_SHIFT] +
 						  offset_in_page(IDX[k]),
@@ -265,6 +313,8 @@
 out:
 	ahash_request_free(req);
 out_noreq:
+	testmgr_free_buf(xbuf);
+out_nobuf:
 	return ret;
 }
 
@@ -273,7 +323,7 @@
 {
 	const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm));
 	unsigned int i, j, k, n, temp;
-	int ret = 0;
+	int ret = -ENOMEM;
 	char *q;
 	char *key;
 	struct aead_request *req;
@@ -285,6 +335,13 @@
 	void *input;
 	void *assoc;
 	char iv[MAX_IVLEN];
+	char *xbuf[XBUFSIZE];
+	char *axbuf[XBUFSIZE];
+
+	if (testmgr_alloc_buf(xbuf))
+		goto out_noxbuf;
+	if (testmgr_alloc_buf(axbuf))
+		goto out_noaxbuf;
 
 	if (enc == ENCRYPT)
 		e = "encryption";
@@ -297,7 +354,6 @@
 	if (!req) {
 		printk(KERN_ERR "alg: aead: Failed to allocate request for "
 		       "%s\n", algo);
-		ret = -ENOMEM;
 		goto out;
 	}
 
@@ -314,6 +370,11 @@
 			input = xbuf[0];
 			assoc = axbuf[0];
 
+			ret = -EINVAL;
+			if (WARN_ON(template[i].ilen > PAGE_SIZE ||
+				    template[i].alen > PAGE_SIZE))
+				goto out;
+
 			memcpy(input, template[i].input, template[i].ilen);
 			memcpy(assoc, template[i].assoc, template[i].alen);
 			if (template[i].iv)
@@ -363,6 +424,16 @@
 
 			switch (ret) {
 			case 0:
+				if (template[i].novrfy) {
+					/* verification was supposed to fail */
+					printk(KERN_ERR "alg: aead: %s failed "
+					       "on test %d for %s: ret was 0, "
+					       "expected -EBADMSG\n",
+					       e, j, algo);
+					/* so really, we got a bad message */
+					ret = -EBADMSG;
+					goto out;
+				}
 				break;
 			case -EINPROGRESS:
 			case -EBUSY:
@@ -372,6 +443,10 @@
 					INIT_COMPLETION(result.completion);
 					break;
 				}
+			case -EBADMSG:
+				if (template[i].novrfy)
+					/* verification failure was expected */
+					continue;
 				/* fall through */
 			default:
 				printk(KERN_ERR "alg: aead: %s failed on test "
@@ -459,7 +534,11 @@
 			}
 
 			sg_init_table(asg, template[i].anp);
+			ret = -EINVAL;
 			for (k = 0, temp = 0; k < template[i].anp; k++) {
+				if (WARN_ON(offset_in_page(IDX[k]) +
+					    template[i].atap[k] > PAGE_SIZE))
+					goto out;
 				sg_set_buf(&asg[k],
 					   memcpy(axbuf[IDX[k] >> PAGE_SHIFT] +
 						  offset_in_page(IDX[k]),
@@ -481,6 +560,16 @@
 
 			switch (ret) {
 			case 0:
+				if (template[i].novrfy) {
+					/* verification was supposed to fail */
+					printk(KERN_ERR "alg: aead: %s failed "
+					       "on chunk test %d for %s: ret "
+					       "was 0, expected -EBADMSG\n",
+					       e, j, algo);
+					/* so really, we got a bad message */
+					ret = -EBADMSG;
+					goto out;
+				}
 				break;
 			case -EINPROGRESS:
 			case -EBUSY:
@@ -490,6 +579,10 @@
 					INIT_COMPLETION(result.completion);
 					break;
 				}
+			case -EBADMSG:
+				if (template[i].novrfy)
+					/* verification failure was expected */
+					continue;
 				/* fall through */
 			default:
 				printk(KERN_ERR "alg: aead: %s failed on "
@@ -546,6 +639,10 @@
 
 out:
 	aead_request_free(req);
+	testmgr_free_buf(axbuf);
+out_noaxbuf:
+	testmgr_free_buf(xbuf);
+out_noxbuf:
 	return ret;
 }
 
@@ -554,10 +651,14 @@
 {
 	const char *algo = crypto_tfm_alg_driver_name(crypto_cipher_tfm(tfm));
 	unsigned int i, j, k;
-	int ret;
 	char *q;
 	const char *e;
 	void *data;
+	char *xbuf[XBUFSIZE];
+	int ret = -ENOMEM;
+
+	if (testmgr_alloc_buf(xbuf))
+		goto out_nobuf;
 
 	if (enc == ENCRYPT)
 	        e = "encryption";
@@ -571,6 +672,10 @@
 
 		j++;
 
+		ret = -EINVAL;
+		if (WARN_ON(template[i].ilen > PAGE_SIZE))
+			goto out;
+
 		data = xbuf[0];
 		memcpy(data, template[i].input, template[i].ilen);
 
@@ -611,6 +716,8 @@
 	ret = 0;
 
 out:
+	testmgr_free_buf(xbuf);
+out_nobuf:
 	return ret;
 }
 
@@ -620,7 +727,6 @@
 	const char *algo =
 		crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm));
 	unsigned int i, j, k, n, temp;
-	int ret;
 	char *q;
 	struct ablkcipher_request *req;
 	struct scatterlist sg[8];
@@ -628,6 +734,11 @@
 	struct tcrypt_result result;
 	void *data;
 	char iv[MAX_IVLEN];
+	char *xbuf[XBUFSIZE];
+	int ret = -ENOMEM;
+
+	if (testmgr_alloc_buf(xbuf))
+		goto out_nobuf;
 
 	if (enc == ENCRYPT)
 	        e = "encryption";
@@ -640,7 +751,6 @@
 	if (!req) {
 		printk(KERN_ERR "alg: skcipher: Failed to allocate request "
 		       "for %s\n", algo);
-		ret = -ENOMEM;
 		goto out;
 	}
 
@@ -657,6 +767,10 @@
 		if (!(template[i].np)) {
 			j++;
 
+			ret = -EINVAL;
+			if (WARN_ON(template[i].ilen > PAGE_SIZE))
+				goto out;
+
 			data = xbuf[0];
 			memcpy(data, template[i].input, template[i].ilen);
 
@@ -825,6 +939,8 @@
 
 out:
 	ablkcipher_request_free(req);
+	testmgr_free_buf(xbuf);
+out_nobuf:
 	return ret;
 }
 
@@ -837,7 +953,8 @@
 	int ret;
 
 	for (i = 0; i < ctcount; i++) {
-		int ilen, dlen = COMP_BUF_SIZE;
+		int ilen;
+		unsigned int dlen = COMP_BUF_SIZE;
 
 		memset(result, 0, sizeof (result));
 
@@ -869,7 +986,8 @@
 	}
 
 	for (i = 0; i < dtcount; i++) {
-		int ilen, dlen = COMP_BUF_SIZE;
+		int ilen;
+		unsigned int dlen = COMP_BUF_SIZE;
 
 		memset(result, 0, sizeof (result));
 
@@ -914,24 +1032,25 @@
 	const char *algo = crypto_tfm_alg_driver_name(crypto_pcomp_tfm(tfm));
 	unsigned int i;
 	char result[COMP_BUF_SIZE];
-	int error;
+	int res;
 
 	for (i = 0; i < ctcount; i++) {
 		struct comp_request req;
+		unsigned int produced = 0;
 
-		error = crypto_compress_setup(tfm, ctemplate[i].params,
-					      ctemplate[i].paramsize);
-		if (error) {
+		res = crypto_compress_setup(tfm, ctemplate[i].params,
+					    ctemplate[i].paramsize);
+		if (res) {
 			pr_err("alg: pcomp: compression setup failed on test "
-			       "%d for %s: error=%d\n", i + 1, algo, error);
-			return error;
+			       "%d for %s: error=%d\n", i + 1, algo, res);
+			return res;
 		}
 
-		error = crypto_compress_init(tfm);
-		if (error) {
+		res = crypto_compress_init(tfm);
+		if (res) {
 			pr_err("alg: pcomp: compression init failed on test "
-			       "%d for %s: error=%d\n", i + 1, algo, error);
-			return error;
+			       "%d for %s: error=%d\n", i + 1, algo, res);
+			return res;
 		}
 
 		memset(result, 0, sizeof(result));
@@ -941,32 +1060,37 @@
 		req.next_out = result;
 		req.avail_out = ctemplate[i].outlen / 2;
 
-		error = crypto_compress_update(tfm, &req);
-		if (error && (error != -EAGAIN || req.avail_in)) {
+		res = crypto_compress_update(tfm, &req);
+		if (res < 0 && (res != -EAGAIN || req.avail_in)) {
 			pr_err("alg: pcomp: compression update failed on test "
-			       "%d for %s: error=%d\n", i + 1, algo, error);
-			return error;
+			       "%d for %s: error=%d\n", i + 1, algo, res);
+			return res;
 		}
+		if (res > 0)
+			produced += res;
 
 		/* Add remaining input data */
 		req.avail_in += (ctemplate[i].inlen + 1) / 2;
 
-		error = crypto_compress_update(tfm, &req);
-		if (error && (error != -EAGAIN || req.avail_in)) {
+		res = crypto_compress_update(tfm, &req);
+		if (res < 0 && (res != -EAGAIN || req.avail_in)) {
 			pr_err("alg: pcomp: compression update failed on test "
-			       "%d for %s: error=%d\n", i + 1, algo, error);
-			return error;
+			       "%d for %s: error=%d\n", i + 1, algo, res);
+			return res;
 		}
+		if (res > 0)
+			produced += res;
 
 		/* Provide remaining output space */
 		req.avail_out += COMP_BUF_SIZE - ctemplate[i].outlen / 2;
 
-		error = crypto_compress_final(tfm, &req);
-		if (error) {
+		res = crypto_compress_final(tfm, &req);
+		if (res < 0) {
 			pr_err("alg: pcomp: compression final failed on test "
-			       "%d for %s: error=%d\n", i + 1, algo, error);
-			return error;
+			       "%d for %s: error=%d\n", i + 1, algo, res);
+			return res;
 		}
+		produced += res;
 
 		if (COMP_BUF_SIZE - req.avail_out != ctemplate[i].outlen) {
 			pr_err("alg: comp: Compression test %d failed for %s: "
@@ -976,6 +1100,13 @@
 			return -EINVAL;
 		}
 
+		if (produced != ctemplate[i].outlen) {
+			pr_err("alg: comp: Compression test %d failed for %s: "
+			       "returned len = %u (expected %d)\n", i + 1,
+			       algo, produced, ctemplate[i].outlen);
+			return -EINVAL;
+		}
+
 		if (memcmp(result, ctemplate[i].output, ctemplate[i].outlen)) {
 			pr_err("alg: pcomp: Compression test %d failed for "
 			       "%s\n", i + 1, algo);
@@ -986,21 +1117,21 @@
 
 	for (i = 0; i < dtcount; i++) {
 		struct comp_request req;
+		unsigned int produced = 0;
 
-		error = crypto_decompress_setup(tfm, dtemplate[i].params,
-						dtemplate[i].paramsize);
-		if (error) {
+		res = crypto_decompress_setup(tfm, dtemplate[i].params,
+					      dtemplate[i].paramsize);
+		if (res) {
 			pr_err("alg: pcomp: decompression setup failed on "
-			       "test %d for %s: error=%d\n", i + 1, algo,
-			       error);
-			return error;
+			       "test %d for %s: error=%d\n", i + 1, algo, res);
+			return res;
 		}
 
-		error = crypto_decompress_init(tfm);
-		if (error) {
+		res = crypto_decompress_init(tfm);
+		if (res) {
 			pr_err("alg: pcomp: decompression init failed on test "
-			       "%d for %s: error=%d\n", i + 1, algo, error);
-			return error;
+			       "%d for %s: error=%d\n", i + 1, algo, res);
+			return res;
 		}
 
 		memset(result, 0, sizeof(result));
@@ -1010,35 +1141,38 @@
 		req.next_out = result;
 		req.avail_out = dtemplate[i].outlen / 2;
 
-		error = crypto_decompress_update(tfm, &req);
-		if (error  && (error != -EAGAIN || req.avail_in)) {
+		res = crypto_decompress_update(tfm, &req);
+		if (res < 0 && (res != -EAGAIN || req.avail_in)) {
 			pr_err("alg: pcomp: decompression update failed on "
-			       "test %d for %s: error=%d\n", i + 1, algo,
-			       error);
-			return error;
+			       "test %d for %s: error=%d\n", i + 1, algo, res);
+			return res;
 		}
+		if (res > 0)
+			produced += res;
 
 		/* Add remaining input data */
 		req.avail_in += (dtemplate[i].inlen + 1) / 2;
 
-		error = crypto_decompress_update(tfm, &req);
-		if (error  && (error != -EAGAIN || req.avail_in)) {
+		res = crypto_decompress_update(tfm, &req);
+		if (res < 0 && (res != -EAGAIN || req.avail_in)) {
 			pr_err("alg: pcomp: decompression update failed on "
-			       "test %d for %s: error=%d\n", i + 1, algo,
-			       error);
-			return error;
+			       "test %d for %s: error=%d\n", i + 1, algo, res);
+			return res;
 		}
+		if (res > 0)
+			produced += res;
 
 		/* Provide remaining output space */
 		req.avail_out += COMP_BUF_SIZE - dtemplate[i].outlen / 2;
 
-		error = crypto_decompress_final(tfm, &req);
-		if (error  && (error != -EAGAIN || req.avail_in)) {
+		res = crypto_decompress_final(tfm, &req);
+		if (res < 0 && (res != -EAGAIN || req.avail_in)) {
 			pr_err("alg: pcomp: decompression final failed on "
-			       "test %d for %s: error=%d\n", i + 1, algo,
-			       error);
-			return error;
+			       "test %d for %s: error=%d\n", i + 1, algo, res);
+			return res;
 		}
+		if (res > 0)
+			produced += res;
 
 		if (COMP_BUF_SIZE - req.avail_out != dtemplate[i].outlen) {
 			pr_err("alg: comp: Decompression test %d failed for "
@@ -1048,6 +1182,13 @@
 			return -EINVAL;
 		}
 
+		if (produced != dtemplate[i].outlen) {
+			pr_err("alg: comp: Decompression test %d failed for "
+			       "%s: returned len = %u (expected %d)\n", i + 1,
+			       algo, produced, dtemplate[i].outlen);
+			return -EINVAL;
+		}
+
 		if (memcmp(result, dtemplate[i].output, dtemplate[i].outlen)) {
 			pr_err("alg: pcomp: Decompression test %d failed for "
 			       "%s\n", i + 1, algo);
@@ -1059,6 +1200,68 @@
 	return 0;
 }
 
+
+static int test_cprng(struct crypto_rng *tfm, struct cprng_testvec *template,
+		      unsigned int tcount)
+{
+	const char *algo = crypto_tfm_alg_driver_name(crypto_rng_tfm(tfm));
+	int err, i, j, seedsize;
+	u8 *seed;
+	char result[32];
+
+	seedsize = crypto_rng_seedsize(tfm);
+
+	seed = kmalloc(seedsize, GFP_KERNEL);
+	if (!seed) {
+		printk(KERN_ERR "alg: cprng: Failed to allocate seed space "
+		       "for %s\n", algo);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < tcount; i++) {
+		memset(result, 0, 32);
+
+		memcpy(seed, template[i].v, template[i].vlen);
+		memcpy(seed + template[i].vlen, template[i].key,
+		       template[i].klen);
+		memcpy(seed + template[i].vlen + template[i].klen,
+		       template[i].dt, template[i].dtlen);
+
+		err = crypto_rng_reset(tfm, seed, seedsize);
+		if (err) {
+			printk(KERN_ERR "alg: cprng: Failed to reset rng "
+			       "for %s\n", algo);
+			goto out;
+		}
+
+		for (j = 0; j < template[i].loops; j++) {
+			err = crypto_rng_get_bytes(tfm, result,
+						   template[i].rlen);
+			if (err != template[i].rlen) {
+				printk(KERN_ERR "alg: cprng: Failed to obtain "
+				       "the correct amount of random data for "
+				       "%s (requested %d, got %d)\n", algo,
+				       template[i].rlen, err);
+				goto out;
+			}
+		}
+
+		err = memcmp(result, template[i].result,
+			     template[i].rlen);
+		if (err) {
+			printk(KERN_ERR "alg: cprng: Test %d failed for %s\n",
+			       i, algo);
+			hexdump(result, template[i].rlen);
+			err = -EINVAL;
+			goto out;
+		}
+	}
+
+out:
+	kfree(seed);
+	return err;
+}
+
 static int alg_test_aead(const struct alg_test_desc *desc, const char *driver,
 			 u32 type, u32 mask)
 {
@@ -1258,11 +1461,42 @@
 	return err;
 }
 
+static int alg_test_cprng(const struct alg_test_desc *desc, const char *driver,
+			  u32 type, u32 mask)
+{
+	struct crypto_rng *rng;
+	int err;
+
+	rng = crypto_alloc_rng(driver, type, mask);
+	if (IS_ERR(rng)) {
+		printk(KERN_ERR "alg: cprng: Failed to load transform for %s: "
+		       "%ld\n", driver, PTR_ERR(rng));
+		return PTR_ERR(rng);
+	}
+
+	err = test_cprng(rng, desc->suite.cprng.vecs, desc->suite.cprng.count);
+
+	crypto_free_rng(rng);
+
+	return err;
+}
+
 /* Please keep this list sorted by algorithm name. */
 static const struct alg_test_desc alg_test_descs[] = {
 	{
+		.alg = "ansi_cprng",
+		.test = alg_test_cprng,
+		.fips_allowed = 1,
+		.suite = {
+			.cprng = {
+				.vecs = ansi_cprng_aes_tv_template,
+				.count = ANSI_CPRNG_AES_TEST_VECTORS
+			}
+		}
+	}, {
 		.alg = "cbc(aes)",
 		.test = alg_test_skcipher,
+		.fips_allowed = 1,
 		.suite = {
 			.cipher = {
 				.enc = {
@@ -1338,6 +1572,7 @@
 	}, {
 		.alg = "cbc(des3_ede)",
 		.test = alg_test_skcipher,
+		.fips_allowed = 1,
 		.suite = {
 			.cipher = {
 				.enc = {
@@ -1368,6 +1603,7 @@
 	}, {
 		.alg = "ccm(aes)",
 		.test = alg_test_aead,
+		.fips_allowed = 1,
 		.suite = {
 			.aead = {
 				.enc = {
@@ -1383,6 +1619,7 @@
 	}, {
 		.alg = "crc32c",
 		.test = alg_test_crc32c,
+		.fips_allowed = 1,
 		.suite = {
 			.hash = {
 				.vecs = crc32c_tv_template,
@@ -1390,6 +1627,22 @@
 			}
 		}
 	}, {
+		.alg = "ctr(aes)",
+		.test = alg_test_skcipher,
+		.fips_allowed = 1,
+		.suite = {
+			.cipher = {
+				.enc = {
+					.vecs = aes_ctr_enc_tv_template,
+					.count = AES_CTR_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = aes_ctr_dec_tv_template,
+					.count = AES_CTR_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
 		.alg = "cts(cbc(aes))",
 		.test = alg_test_skcipher,
 		.suite = {
@@ -1422,6 +1675,7 @@
 	}, {
 		.alg = "ecb(aes)",
 		.test = alg_test_skcipher,
+		.fips_allowed = 1,
 		.suite = {
 			.cipher = {
 				.enc = {
@@ -1527,6 +1781,7 @@
 	}, {
 		.alg = "ecb(des)",
 		.test = alg_test_skcipher,
+		.fips_allowed = 1,
 		.suite = {
 			.cipher = {
 				.enc = {
@@ -1542,6 +1797,7 @@
 	}, {
 		.alg = "ecb(des3_ede)",
 		.test = alg_test_skcipher,
+		.fips_allowed = 1,
 		.suite = {
 			.cipher = {
 				.enc = {
@@ -1677,6 +1933,7 @@
 	}, {
 		.alg = "gcm(aes)",
 		.test = alg_test_aead,
+		.fips_allowed = 1,
 		.suite = {
 			.aead = {
 				.enc = {
@@ -1719,6 +1976,7 @@
 	}, {
 		.alg = "hmac(sha1)",
 		.test = alg_test_hash,
+		.fips_allowed = 1,
 		.suite = {
 			.hash = {
 				.vecs = hmac_sha1_tv_template,
@@ -1728,6 +1986,7 @@
 	}, {
 		.alg = "hmac(sha224)",
 		.test = alg_test_hash,
+		.fips_allowed = 1,
 		.suite = {
 			.hash = {
 				.vecs = hmac_sha224_tv_template,
@@ -1737,6 +1996,7 @@
 	}, {
 		.alg = "hmac(sha256)",
 		.test = alg_test_hash,
+		.fips_allowed = 1,
 		.suite = {
 			.hash = {
 				.vecs = hmac_sha256_tv_template,
@@ -1746,6 +2006,7 @@
 	}, {
 		.alg = "hmac(sha384)",
 		.test = alg_test_hash,
+		.fips_allowed = 1,
 		.suite = {
 			.hash = {
 				.vecs = hmac_sha384_tv_template,
@@ -1755,6 +2016,7 @@
 	}, {
 		.alg = "hmac(sha512)",
 		.test = alg_test_hash,
+		.fips_allowed = 1,
 		.suite = {
 			.hash = {
 				.vecs = hmac_sha512_tv_template,
@@ -1836,15 +2098,32 @@
 	}, {
 		.alg = "rfc3686(ctr(aes))",
 		.test = alg_test_skcipher,
+		.fips_allowed = 1,
 		.suite = {
 			.cipher = {
 				.enc = {
-					.vecs = aes_ctr_enc_tv_template,
-					.count = AES_CTR_ENC_TEST_VECTORS
+					.vecs = aes_ctr_rfc3686_enc_tv_template,
+					.count = AES_CTR_3686_ENC_TEST_VECTORS
 				},
 				.dec = {
-					.vecs = aes_ctr_dec_tv_template,
-					.count = AES_CTR_DEC_TEST_VECTORS
+					.vecs = aes_ctr_rfc3686_dec_tv_template,
+					.count = AES_CTR_3686_DEC_TEST_VECTORS
+				}
+			}
+		}
+	}, {
+		.alg = "rfc4309(ccm(aes))",
+		.test = alg_test_aead,
+		.fips_allowed = 1,
+		.suite = {
+			.aead = {
+				.enc = {
+					.vecs = aes_ccm_rfc4309_enc_tv_template,
+					.count = AES_CCM_4309_ENC_TEST_VECTORS
+				},
+				.dec = {
+					.vecs = aes_ccm_rfc4309_dec_tv_template,
+					.count = AES_CCM_4309_DEC_TEST_VECTORS
 				}
 			}
 		}
@@ -1898,6 +2177,7 @@
 	}, {
 		.alg = "sha1",
 		.test = alg_test_hash,
+		.fips_allowed = 1,
 		.suite = {
 			.hash = {
 				.vecs = sha1_tv_template,
@@ -1907,6 +2187,7 @@
 	}, {
 		.alg = "sha224",
 		.test = alg_test_hash,
+		.fips_allowed = 1,
 		.suite = {
 			.hash = {
 				.vecs = sha224_tv_template,
@@ -1916,6 +2197,7 @@
 	}, {
 		.alg = "sha256",
 		.test = alg_test_hash,
+		.fips_allowed = 1,
 		.suite = {
 			.hash = {
 				.vecs = sha256_tv_template,
@@ -1925,6 +2207,7 @@
 	}, {
 		.alg = "sha384",
 		.test = alg_test_hash,
+		.fips_allowed = 1,
 		.suite = {
 			.hash = {
 				.vecs = sha384_tv_template,
@@ -1934,6 +2217,7 @@
 	}, {
 		.alg = "sha512",
 		.test = alg_test_hash,
+		.fips_allowed = 1,
 		.suite = {
 			.hash = {
 				.vecs = sha512_tv_template,
@@ -2077,60 +2361,36 @@
 		if (i < 0)
 			goto notest;
 
-		return alg_test_cipher(alg_test_descs + i, driver, type, mask);
+		if (fips_enabled && !alg_test_descs[i].fips_allowed)
+			goto non_fips_alg;
+
+		rc = alg_test_cipher(alg_test_descs + i, driver, type, mask);
+		goto test_done;
 	}
 
 	i = alg_find_test(alg);
 	if (i < 0)
 		goto notest;
 
+	if (fips_enabled && !alg_test_descs[i].fips_allowed)
+		goto non_fips_alg;
+
 	rc = alg_test_descs[i].test(alg_test_descs + i, driver,
 				      type, mask);
+test_done:
 	if (fips_enabled && rc)
 		panic("%s: %s alg self test failed in fips mode!\n", driver, alg);
 
+	if (fips_enabled && !rc)
+		printk(KERN_INFO "alg: self-tests for %s (%s) passed\n",
+		       driver, alg);
+
 	return rc;
 
 notest:
 	printk(KERN_INFO "alg: No test for %s (%s)\n", alg, driver);
 	return 0;
+non_fips_alg:
+	return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(alg_test);
-
-int __init testmgr_init(void)
-{
-	int i;
-
-	for (i = 0; i < XBUFSIZE; i++) {
-		xbuf[i] = (void *)__get_free_page(GFP_KERNEL);
-		if (!xbuf[i])
-			goto err_free_xbuf;
-	}
-
-	for (i = 0; i < XBUFSIZE; i++) {
-		axbuf[i] = (void *)__get_free_page(GFP_KERNEL);
-		if (!axbuf[i])
-			goto err_free_axbuf;
-	}
-
-	return 0;
-
-err_free_axbuf:
-	for (i = 0; i < XBUFSIZE && axbuf[i]; i++)
-		free_page((unsigned long)axbuf[i]);
-err_free_xbuf:
-	for (i = 0; i < XBUFSIZE && xbuf[i]; i++)
-		free_page((unsigned long)xbuf[i]);
-
-	return -ENOMEM;
-}
-
-void testmgr_exit(void)
-{
-	int i;
-
-	for (i = 0; i < XBUFSIZE; i++)
-		free_page((unsigned long)axbuf[i]);
-	for (i = 0; i < XBUFSIZE; i++)
-		free_page((unsigned long)xbuf[i]);
-}
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 526f00a..6931622 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -62,6 +62,7 @@
 	int np;
 	int anp;
 	unsigned char fail;
+	unsigned char novrfy;	/* ccm dec verification failure expected */
 	unsigned char wk; /* weak key flag */
 	unsigned char klen;
 	unsigned short ilen;
@@ -69,6 +70,18 @@
 	unsigned short rlen;
 };
 
+struct cprng_testvec {
+	char *key;
+	char *dt;
+	char *v;
+	char *result;
+	unsigned char klen;
+	unsigned short dtlen;
+	unsigned short vlen;
+	unsigned short rlen;
+	unsigned short loops;
+};
+
 static char zeroed_string[48];
 
 /*
@@ -2841,12 +2854,16 @@
 #define AES_LRW_DEC_TEST_VECTORS 8
 #define AES_XTS_ENC_TEST_VECTORS 4
 #define AES_XTS_DEC_TEST_VECTORS 4
-#define AES_CTR_ENC_TEST_VECTORS 7
-#define AES_CTR_DEC_TEST_VECTORS 6
+#define AES_CTR_ENC_TEST_VECTORS 3
+#define AES_CTR_DEC_TEST_VECTORS 3
+#define AES_CTR_3686_ENC_TEST_VECTORS 7
+#define AES_CTR_3686_DEC_TEST_VECTORS 6
 #define AES_GCM_ENC_TEST_VECTORS 9
 #define AES_GCM_DEC_TEST_VECTORS 8
 #define AES_CCM_ENC_TEST_VECTORS 7
 #define AES_CCM_DEC_TEST_VECTORS 7
+#define AES_CCM_4309_ENC_TEST_VECTORS 7
+#define AES_CCM_4309_DEC_TEST_VECTORS 10
 
 static struct cipher_testvec aes_enc_tv_template[] = {
 	{ /* From FIPS-197 */
@@ -3983,6 +4000,164 @@
 
 
 static struct cipher_testvec aes_ctr_enc_tv_template[] = {
+	{ /* From NIST Special Publication 800-38A, Appendix F.5 */
+		.key	= "\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
+			  "\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+		.klen	= 16,
+		.iv	= "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.input	= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+			  "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+			  "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+			  "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+			  "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+			  "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.ilen	= 64,
+		.result	= "\x87\x4d\x61\x91\xb6\x20\xe3\x26"
+			  "\x1b\xef\x68\x64\x99\x0d\xb6\xce"
+			  "\x98\x06\xf6\x6b\x79\x70\xfd\xff"
+			  "\x86\x17\x18\x7b\xb9\xff\xfd\xff"
+			  "\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e"
+			  "\x5b\x4f\x09\x02\x0d\xb0\x3e\xab"
+			  "\x1e\x03\x1d\xda\x2f\xbe\x03\xd1"
+			  "\x79\x21\x70\xa0\xf3\x00\x9c\xee",
+		.rlen	= 64,
+	}, {
+		.key	= "\x8e\x73\xb0\xf7\xda\x0e\x64\x52"
+			  "\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
+			  "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
+		.klen	= 24,
+		.iv	= "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.input	= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+			  "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+			  "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+			  "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+			  "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+			  "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.ilen	= 64,
+		.result	= "\x1a\xbc\x93\x24\x17\x52\x1c\xa2"
+			  "\x4f\x2b\x04\x59\xfe\x7e\x6e\x0b"
+			  "\x09\x03\x39\xec\x0a\xa6\xfa\xef"
+			  "\xd5\xcc\xc2\xc6\xf4\xce\x8e\x94"
+			  "\x1e\x36\xb2\x6b\xd1\xeb\xc6\x70"
+			  "\xd1\xbd\x1d\x66\x56\x20\xab\xf7"
+			  "\x4f\x78\xa7\xf6\xd2\x98\x09\x58"
+			  "\x5a\x97\xda\xec\x58\xc6\xb0\x50",
+		.rlen	= 64,
+	}, {
+		.key	= "\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+			  "\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+			  "\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+			  "\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+		.klen	= 32,
+		.iv	= "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.input	= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+			  "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+			  "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+			  "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+			  "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+			  "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.ilen	= 64,
+		.result	= "\x60\x1e\xc3\x13\x77\x57\x89\xa5"
+			  "\xb7\xa7\xf5\x04\xbb\xf3\xd2\x28"
+			  "\xf4\x43\xe3\xca\x4d\x62\xb5\x9a"
+			  "\xca\x84\xe9\x90\xca\xca\xf5\xc5"
+			  "\x2b\x09\x30\xda\xa2\x3d\xe9\x4c"
+			  "\xe8\x70\x17\xba\x2d\x84\x98\x8d"
+			  "\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6"
+			  "\x13\xc2\xdd\x08\x45\x79\x41\xa6",
+		.rlen	= 64,
+	}
+};
+
+static struct cipher_testvec aes_ctr_dec_tv_template[] = {
+	{ /* From NIST Special Publication 800-38A, Appendix F.5 */
+		.key	= "\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
+			  "\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+		.klen	= 16,
+		.iv	= "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.input	= "\x87\x4d\x61\x91\xb6\x20\xe3\x26"
+			  "\x1b\xef\x68\x64\x99\x0d\xb6\xce"
+			  "\x98\x06\xf6\x6b\x79\x70\xfd\xff"
+			  "\x86\x17\x18\x7b\xb9\xff\xfd\xff"
+			  "\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e"
+			  "\x5b\x4f\x09\x02\x0d\xb0\x3e\xab"
+			  "\x1e\x03\x1d\xda\x2f\xbe\x03\xd1"
+			  "\x79\x21\x70\xa0\xf3\x00\x9c\xee",
+		.ilen	= 64,
+		.result	= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+			  "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+			  "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+			  "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+			  "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+			  "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.rlen	= 64,
+	}, {
+		.key	= "\x8e\x73\xb0\xf7\xda\x0e\x64\x52"
+			  "\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
+			  "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
+		.klen	= 24,
+		.iv	= "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.input	= "\x1a\xbc\x93\x24\x17\x52\x1c\xa2"
+			  "\x4f\x2b\x04\x59\xfe\x7e\x6e\x0b"
+			  "\x09\x03\x39\xec\x0a\xa6\xfa\xef"
+			  "\xd5\xcc\xc2\xc6\xf4\xce\x8e\x94"
+			  "\x1e\x36\xb2\x6b\xd1\xeb\xc6\x70"
+			  "\xd1\xbd\x1d\x66\x56\x20\xab\xf7"
+			  "\x4f\x78\xa7\xf6\xd2\x98\x09\x58"
+			  "\x5a\x97\xda\xec\x58\xc6\xb0\x50",
+		.ilen	= 64,
+		.result	= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+			  "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+			  "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+			  "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+			  "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+			  "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.rlen	= 64,
+	}, {
+		.key	= "\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+			  "\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+			  "\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+			  "\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+		.klen	= 32,
+		.iv	= "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		.input	= "\x60\x1e\xc3\x13\x77\x57\x89\xa5"
+			  "\xb7\xa7\xf5\x04\xbb\xf3\xd2\x28"
+			  "\xf4\x43\xe3\xca\x4d\x62\xb5\x9a"
+			  "\xca\x84\xe9\x90\xca\xca\xf5\xc5"
+			  "\x2b\x09\x30\xda\xa2\x3d\xe9\x4c"
+			  "\xe8\x70\x17\xba\x2d\x84\x98\x8d"
+			  "\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6"
+			  "\x13\xc2\xdd\x08\x45\x79\x41\xa6",
+		.ilen	= 64,
+		.result	= "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+			  "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+			  "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+			  "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+			  "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+			  "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+		.rlen	= 64,
+	}
+};
+
+static struct cipher_testvec aes_ctr_rfc3686_enc_tv_template[] = {
 	{ /* From RFC 3686 */
 		.key	= "\xae\x68\x52\xf8\x12\x10\x67\xcc"
 			  "\x4b\xf7\xa5\x76\x55\x77\xf3\x9e"
@@ -5114,7 +5289,7 @@
 	},
 };
 
-static struct cipher_testvec aes_ctr_dec_tv_template[] = {
+static struct cipher_testvec aes_ctr_rfc3686_dec_tv_template[] = {
 	{ /* From RFC 3686 */
 		.key	= "\xae\x68\x52\xf8\x12\x10\x67\xcc"
 			  "\x4b\xf7\xa5\x76\x55\x77\xf3\x9e"
@@ -5825,6 +6000,470 @@
 	},
 };
 
+/*
+ * rfc4309 refers to section 8 of rfc3610 for test vectors, but they all
+ * use a 13-byte nonce, we only support an 11-byte nonce. Similarly, all of
+ * Special Publication 800-38C's test vectors also use nonce lengths our
+ * implementation doesn't support. The following are taken from fips cavs
+ * fax files on hand at Red Hat.
+ *
+ * nb: actual key lengths are (klen - 3), the last 3 bytes are actually
+ * part of the nonce which combine w/the iv, but need to be input this way.
+ */
+static struct aead_testvec aes_ccm_rfc4309_enc_tv_template[] = {
+	{
+		.key	= "\x83\xac\x54\x66\xc2\xeb\xe5\x05"
+			  "\x2e\x01\xd1\xfc\x5d\x82\x66\x2e"
+			  "\x96\xac\x59",
+		.klen	= 19,
+		.iv	= "\x30\x07\xa1\xe2\xa2\xc7\x55\x24",
+		.alen	= 0,
+		.input	= "\x19\xc8\x81\xf6\xe9\x86\xff\x93"
+			  "\x0b\x78\x67\xe5\xbb\xb7\xfc\x6e"
+			  "\x83\x77\xb3\xa6\x0c\x8c\x9f\x9c"
+			  "\x35\x2e\xad\xe0\x62\xf9\x91\xa1",
+		.ilen	= 32,
+		.result	= "\xab\x6f\xe1\x69\x1d\x19\x99\xa8"
+			  "\x92\xa0\xc4\x6f\x7e\xe2\x8b\xb1"
+			  "\x70\xbb\x8c\xa6\x4c\x6e\x97\x8a"
+			  "\x57\x2b\xbe\x5d\x98\xa6\xb1\x32"
+			  "\xda\x24\xea\xd9\xa1\x39\x98\xfd"
+			  "\xa4\xbe\xd9\xf2\x1a\x6d\x22\xa8",
+		.rlen	= 48,
+	}, {
+		.key	= "\x1e\x2c\x7e\x01\x41\x9a\xef\xc0"
+			  "\x0d\x58\x96\x6e\x5c\xa2\x4b\xd3"
+			  "\x4f\xa3\x19",
+		.klen	= 19,
+		.iv	= "\xd3\x01\x5a\xd8\x30\x60\x15\x56",
+		.assoc	= "\xda\xe6\x28\x9c\x45\x2d\xfd\x63"
+			  "\x5e\xda\x4c\xb6\xe6\xfc\xf9\xb7"
+			  "\x0c\x56\xcb\xe4\xe0\x05\x7a\xe1"
+			  "\x0a\x63\x09\x78\xbc\x2c\x55\xde",
+		.alen	= 32,
+		.input	= "\x87\xa3\x36\xfd\x96\xb3\x93\x78"
+			  "\xa9\x28\x63\xba\x12\xa3\x14\x85"
+			  "\x57\x1e\x06\xc9\x7b\x21\xef\x76"
+			  "\x7f\x38\x7e\x8e\x29\xa4\x3e\x7e",
+		.ilen	= 32,
+		.result	= "\x8a\x1e\x11\xf0\x02\x6b\xe2\x19"
+			  "\xfc\x70\xc4\x6d\x8e\xb7\x99\xab"
+			  "\xc5\x4b\xa2\xac\xd3\xf3\x48\xff"
+			  "\x3b\xb5\xce\x53\xef\xde\xbb\x02"
+			  "\xa9\x86\x15\x6c\x13\xfe\xda\x0a"
+			  "\x22\xb8\x29\x3d\xd8\x39\x9a\x23",
+		.rlen	= 48,
+	}, {
+		.key	= "\xf4\x6b\xc2\x75\x62\xfe\xb4\xe1"
+			  "\xa3\xf0\xff\xdd\x4e\x4b\x12\x75"
+			  "\x53\x14\x73\x66\x8d\x88\xf6\x80"
+			  "\xa0\x20\x35",
+		.klen	= 27,
+		.iv	= "\x26\xf2\x21\x8d\x50\x20\xda\xe2",
+		.assoc	= "\x5b\x9e\x13\x67\x02\x5e\xef\xc1"
+			  "\x6c\xf9\xd7\x1e\x52\x8f\x7a\x47"
+			  "\xe9\xd4\xcf\x20\x14\x6e\xf0\x2d"
+			  "\xd8\x9e\x2b\x56\x10\x23\x56\xe7",
+		.alen	= 32,
+		.ilen	= 0,
+		.result	= "\x36\xea\x7a\x70\x08\xdc\x6a\xbc"
+			  "\xad\x0c\x7a\x63\xf6\x61\xfd\x9b",
+		.rlen	= 16,
+	}, {
+		.key	= "\x56\xdf\x5c\x8f\x26\x3f\x0e\x42"
+			  "\xef\x7a\xd3\xce\xfc\x84\x60\x62"
+			  "\xca\xb4\x40\xaf\x5f\xc9\xc9\x01"
+			  "\xd6\x3c\x8c",
+		.klen	= 27,
+		.iv	= "\x86\x84\xb6\xcd\xef\x09\x2e\x94",
+		.assoc	= "\x02\x65\x78\x3c\xe9\x21\x30\x91"
+			  "\xb1\xb9\xda\x76\x9a\x78\x6d\x95"
+			  "\xf2\x88\x32\xa3\xf2\x50\xcb\x4c"
+			  "\xe3\x00\x73\x69\x84\x69\x87\x79",
+		.alen	= 32,
+		.input	= "\x9f\xd2\x02\x4b\x52\x49\x31\x3c"
+			  "\x43\x69\x3a\x2d\x8e\x70\xad\x7e"
+			  "\xe0\xe5\x46\x09\x80\x89\x13\xb2"
+			  "\x8c\x8b\xd9\x3f\x86\xfb\xb5\x6b",
+		.ilen	= 32,
+		.result	= "\x39\xdf\x7c\x3c\x5a\x29\xb9\x62"
+			  "\x5d\x51\xc2\x16\xd8\xbd\x06\x9f"
+			  "\x9b\x6a\x09\x70\xc1\x51\x83\xc2"
+			  "\x66\x88\x1d\x4f\x9a\xda\xe0\x1e"
+			  "\xc7\x79\x11\x58\xe5\x6b\x20\x40"
+			  "\x7a\xea\x46\x42\x8b\xe4\x6f\xe1",
+		.rlen	= 48,
+	}, {
+		.key	= "\xe0\x8d\x99\x71\x60\xd7\x97\x1a"
+			  "\xbd\x01\x99\xd5\x8a\xdf\x71\x3a"
+			  "\xd3\xdf\x24\x4b\x5e\x3d\x4b\x4e"
+			  "\x30\x7a\xb9\xd8\x53\x0a\x5e\x2b"
+			  "\x1e\x29\x91",
+		.klen	= 35,
+		.iv	= "\xad\x8e\xc1\x53\x0a\xcf\x2d\xbe",
+		.assoc	= "\x19\xb6\x1f\x57\xc4\xf3\xf0\x8b"
+			  "\x78\x2b\x94\x02\x29\x0f\x42\x27"
+			  "\x6b\x75\xcb\x98\x34\x08\x7e\x79"
+			  "\xe4\x3e\x49\x0d\x84\x8b\x22\x87",
+		.alen	= 32,
+		.input	= "\xe1\xd9\xd8\x13\xeb\x3a\x75\x3f"
+			  "\x9d\xbd\x5f\x66\xbe\xdc\xbb\x66"
+			  "\xbf\x17\x99\x62\x4a\x39\x27\x1f"
+			  "\x1d\xdc\x24\xae\x19\x2f\x98\x4c",
+		.ilen	= 32,
+		.result	= "\x19\xb8\x61\x33\x45\x2b\x43\x96"
+			  "\x6f\x51\xd0\x20\x30\x7d\x9b\xc6"
+			  "\x26\x3d\xf8\xc9\x65\x16\xa8\x9f"
+			  "\xf0\x62\x17\x34\xf2\x1e\x8d\x75"
+			  "\x4e\x13\xcc\xc0\xc3\x2a\x54\x2d",
+		.rlen	= 40,
+	}, {
+		.key	= "\x7c\xc8\x18\x3b\x8d\x99\xe0\x7c"
+			  "\x45\x41\xb8\xbd\x5c\xa7\xc2\x32"
+			  "\x8a\xb8\x02\x59\xa4\xfe\xa9\x2c"
+			  "\x09\x75\x9a\x9b\x3c\x9b\x27\x39"
+			  "\xf9\xd9\x4e",
+		.klen	= 35,
+		.iv	= "\x63\xb5\x3d\x9d\x43\xf6\x1e\x50",
+		.assoc	= "\x57\xf5\x6b\x8b\x57\x5c\x3d\x3b"
+			  "\x13\x02\x01\x0c\x83\x4c\x96\x35"
+			  "\x8e\xd6\x39\xcf\x7d\x14\x9b\x94"
+			  "\xb0\x39\x36\xe6\x8f\x57\xe0\x13",
+		.alen	= 32,
+		.input	= "\x3b\x6c\x29\x36\xb6\xef\x07\xa6"
+			  "\x83\x72\x07\x4f\xcf\xfa\x66\x89"
+			  "\x5f\xca\xb1\xba\xd5\x8f\x2c\x27"
+			  "\x30\xdb\x75\x09\x93\xd4\x65\xe4",
+		.ilen	= 32,
+		.result	= "\xb0\x88\x5a\x33\xaa\xe5\xc7\x1d"
+			  "\x85\x23\xc7\xc6\x2f\xf4\x1e\x3d"
+			  "\xcc\x63\x44\x25\x07\x78\x4f\x9e"
+			  "\x96\xb8\x88\xeb\xbc\x48\x1f\x06"
+			  "\x39\xaf\x39\xac\xd8\x4a\x80\x39"
+			  "\x7b\x72\x8a\xf7",
+		.rlen	= 44,
+	}, {
+		.key	= "\xab\xd0\xe9\x33\x07\x26\xe5\x83"
+			  "\x8c\x76\x95\xd4\xb6\xdc\xf3\x46"
+			  "\xf9\x8f\xad\xe3\x02\x13\x83\x77"
+			  "\x3f\xb0\xf1\xa1\xa1\x22\x0f\x2b"
+			  "\x24\xa7\x8b",
+		.klen	= 35,
+		.iv	= "\x07\xcb\xcc\x0e\xe6\x33\xbf\xf5",
+		.assoc	= "\xd4\xdb\x30\x1d\x03\xfe\xfd\x5f"
+			  "\x87\xd4\x8c\xb6\xb6\xf1\x7a\x5d"
+			  "\xab\x90\x65\x8d\x8e\xca\x4d\x4f"
+			  "\x16\x0c\x40\x90\x4b\xc7\x36\x73",
+		.alen	= 32,
+		.input	= "\xf5\xc6\x7d\x48\xc1\xb7\xe6\x92"
+			  "\x97\x5a\xca\xc4\xa9\x6d\xf9\x3d"
+			  "\x6c\xde\xbc\xf1\x90\xea\x6a\xb2"
+			  "\x35\x86\x36\xaf\x5c\xfe\x4b\x3a",
+		.ilen	= 32,
+		.result	= "\x83\x6f\x40\x87\x72\xcf\xc1\x13"
+			  "\xef\xbb\x80\x21\x04\x6c\x58\x09"
+			  "\x07\x1b\xfc\xdf\xc0\x3f\x5b\xc7"
+			  "\xe0\x79\xa8\x6e\x71\x7c\x3f\xcf"
+			  "\x5c\xda\xb2\x33\xe5\x13\xe2\x0d"
+			  "\x74\xd1\xef\xb5\x0f\x3a\xb5\xf8",
+		.rlen	= 48,
+	},
+};
+
+static struct aead_testvec aes_ccm_rfc4309_dec_tv_template[] = {
+	{
+		.key	= "\xab\x2f\x8a\x74\xb7\x1c\xd2\xb1"
+			  "\xff\x80\x2e\x48\x7d\x82\xf8\xb9"
+			  "\xc6\xfb\x7d",
+		.klen	= 19,
+		.iv	= "\x80\x0d\x13\xab\xd8\xa6\xb2\xd8",
+		.alen	= 0,
+		.input	= "\xd5\xe8\x93\x9f\xc7\x89\x2e\x2b",
+		.ilen	= 8,
+		.result	= "\x00",
+		.rlen	= 0,
+		.novrfy	= 1,
+	}, {
+		.key	= "\xab\x2f\x8a\x74\xb7\x1c\xd2\xb1"
+			  "\xff\x80\x2e\x48\x7d\x82\xf8\xb9"
+			  "\xaf\x94\x87",
+		.klen	= 19,
+		.iv	= "\x78\x35\x82\x81\x7f\x88\x94\x68",
+		.alen	= 0,
+		.input	= "\x41\x3c\xb8\x87\x73\xcb\xf3\xf3",
+		.ilen	= 8,
+		.result	= "\x00",
+		.rlen	= 0,
+	}, {
+		.key	= "\x61\x0e\x8c\xae\xe3\x23\xb6\x38"
+			  "\x76\x1c\xf6\x3a\x67\xa3\x9c\xd8"
+			  "\xc6\xfb\x7d",
+		.klen	= 19,
+		.iv	= "\x80\x0d\x13\xab\xd8\xa6\xb2\xd8",
+		.assoc	= "\xf3\x94\x87\x78\x35\x82\x81\x7f"
+			  "\x88\x94\x68\xb1\x78\x6b\x2b\xd6"
+			  "\x04\x1f\x4e\xed\x78\xd5\x33\x66"
+			  "\xd8\x94\x99\x91\x81\x54\x62\x57",
+		.alen	= 32,
+		.input	= "\xf0\x7c\x29\x02\xae\x1c\x2f\x55"
+			  "\xd0\xd1\x3d\x1a\xa3\x6d\xe4\x0a"
+			  "\x86\xb0\x87\x6b\x62\x33\x8c\x34"
+			  "\xce\xab\x57\xcc\x79\x0b\xe0\x6f"
+			  "\x5c\x3e\x48\x1f\x6c\x46\xf7\x51"
+			  "\x8b\x84\x83\x2a\xc1\x05\xb8\xc5",
+		.ilen	= 48,
+		.result	= "\x50\x82\x3e\x07\xe2\x1e\xb6\xfb"
+			  "\x33\xe4\x73\xce\xd2\xfb\x95\x79"
+			  "\xe8\xb4\xb5\x77\x11\x10\x62\x6f"
+			  "\x6a\x82\xd1\x13\xec\xf5\xd0\x48",
+		.rlen	= 32,
+		.novrfy	= 1,
+	}, {
+		.key	= "\x61\x0e\x8c\xae\xe3\x23\xb6\x38"
+			  "\x76\x1c\xf6\x3a\x67\xa3\x9c\xd8"
+			  "\x05\xe0\xc9",
+		.klen	= 19,
+		.iv	= "\x0f\xed\x34\xea\x97\xd4\x3b\xdf",
+		.assoc	= "\x49\x5c\x50\x1f\x1d\x94\xcc\x81"
+			  "\xba\xb7\xb6\x03\xaf\xa5\xc1\xa1"
+			  "\xd8\x5c\x42\x68\xe0\x6c\xda\x89"
+			  "\x05\xac\x56\xac\x1b\x2a\xd3\x86",
+		.alen	= 32,
+		.input	= "\x39\xbe\x7d\x15\x62\x77\xf3\x3c"
+			  "\xad\x83\x52\x6d\x71\x03\x25\x1c"
+			  "\xed\x81\x3a\x9a\x16\x7d\x19\x80"
+			  "\x72\x04\x72\xd0\xf6\xff\x05\x0f"
+			  "\xb7\x14\x30\x00\x32\x9e\xa0\xa6"
+			  "\x9e\x5a\x18\xa1\xb8\xfe\xdb\xd3",
+		.ilen	= 48,
+		.result	= "\x75\x05\xbe\xc2\xd9\x1e\xde\x60"
+			  "\x47\x3d\x8c\x7d\xbd\xb5\xd9\xb7"
+			  "\xf2\xae\x61\x05\x8f\x82\x24\x3f"
+			  "\x9c\x67\x91\xe1\x38\x4f\xe4\x0c",
+		.rlen	= 32,
+	}, {
+		.key	= "\x39\xbb\xa7\xbe\x59\x97\x9e\x73"
+			  "\xa2\xbc\x6b\x98\xd7\x75\x7f\xe3"
+			  "\xa4\x48\x93\x39\x26\x71\x4a\xc6"
+			  "\xee\x49\x83",
+		.klen	= 27,
+		.iv	= "\xe9\xa9\xff\xe9\x57\xba\xfd\x9e",
+		.assoc	= "\x44\xa6\x2c\x05\xe9\xe1\x43\xb1"
+			  "\x58\x7c\xf2\x5c\x6d\x39\x0a\x64"
+			  "\xa4\xf0\x13\x05\xd1\x77\x99\x67"
+			  "\x11\xc4\xc6\xdb\x00\x56\x36\x61",
+		.alen	= 32,
+		.input	= "\x71\x99\xfa\xf4\x44\x12\x68\x9b",
+		.ilen	= 8,
+		.result	= "\x00",
+		.rlen	= 0,
+	}, {
+		.key	= "\x58\x5d\xa0\x96\x65\x1a\x04\xd7"
+			  "\x96\xe5\xc5\x68\xaa\x95\x35\xe0"
+			  "\x29\xa0\xba\x9e\x48\x78\xd1\xba"
+			  "\xee\x49\x83",
+		.klen	= 27,
+		.iv	= "\xe9\xa9\xff\xe9\x57\xba\xfd\x9e",
+		.assoc	= "\x44\xa6\x2c\x05\xe9\xe1\x43\xb1"
+			  "\x58\x7c\xf2\x5c\x6d\x39\x0a\x64"
+			  "\xa4\xf0\x13\x05\xd1\x77\x99\x67"
+			  "\x11\xc4\xc6\xdb\x00\x56\x36\x61",
+		.alen	= 32,
+		.input	= "\xfb\xe5\x5d\x34\xbe\xe5\xe8\xe7"
+			  "\x5a\xef\x2f\xbf\x1f\x7f\xd4\xb2"
+			  "\x66\xca\x61\x1e\x96\x7a\x61\xb3"
+			  "\x1c\x16\x45\x52\xba\x04\x9c\x9f"
+			  "\xb1\xd2\x40\xbc\x52\x7c\x6f\xb1",
+		.ilen	= 40,
+		.result	= "\x85\x34\x66\x42\xc8\x92\x0f\x36"
+			  "\x58\xe0\x6b\x91\x3c\x98\x5c\xbb"
+			  "\x0a\x85\xcc\x02\xad\x7a\x96\xe9"
+			  "\x65\x43\xa4\xc3\x0f\xdc\x55\x81",
+		.rlen	= 32,
+	}, {
+		.key	= "\x58\x5d\xa0\x96\x65\x1a\x04\xd7"
+			  "\x96\xe5\xc5\x68\xaa\x95\x35\xe0"
+			  "\x29\xa0\xba\x9e\x48\x78\xd1\xba"
+			  "\xd1\xfc\x57",
+		.klen	= 27,
+		.iv	= "\x9c\xfe\xb8\x9c\xad\x71\xaa\x1f",
+		.assoc	= "\x86\x67\xa5\xa9\x14\x5f\x0d\xc6"
+			  "\xff\x14\xc7\x44\xbf\x6c\x3a\xc3"
+			  "\xff\xb6\x81\xbd\xe2\xd5\x06\xc7"
+			  "\x3c\xa1\x52\x13\x03\x8a\x23\x3a",
+		.alen	= 32,
+		.input	= "\x3f\x66\xb0\x9d\xe5\x4b\x38\x00"
+			  "\xc6\x0e\x6e\xe5\xd6\x98\xa6\x37"
+			  "\x8c\x26\x33\xc6\xb2\xa2\x17\xfa"
+			  "\x64\x19\xc0\x30\xd7\xfc\x14\x6b"
+			  "\xe3\x33\xc2\x04\xb0\x37\xbe\x3f"
+			  "\xa9\xb4\x2d\x68\x03\xa3\x44\xef",
+		.ilen	= 48,
+		.result	= "\x02\x87\x4d\x28\x80\x6e\xb2\xed"
+			  "\x99\x2a\xa8\xca\x04\x25\x45\x90"
+			  "\x1d\xdd\x5a\xd9\xe4\xdb\x9c\x9c"
+			  "\x49\xe9\x01\xfe\xa7\x80\x6d\x6b",
+		.rlen	= 32,
+		.novrfy	= 1,
+	}, {
+		.key	= "\xa4\x4b\x54\x29\x0a\xb8\x6d\x01"
+			  "\x5b\x80\x2a\xcf\x25\xc4\xb7\x5c"
+			  "\x20\x2c\xad\x30\xc2\x2b\x41\xfb"
+			  "\x0e\x85\xbc\x33\xad\x0f\x2b\xff"
+			  "\xee\x49\x83",
+		.klen	= 35,
+		.iv	= "\xe9\xa9\xff\xe9\x57\xba\xfd\x9e",
+		.alen	= 0,
+		.input	= "\x1f\xb8\x8f\xa3\xdd\x54\x00\xf2",
+		.ilen	= 8,
+		.result	= "\x00",
+		.rlen	= 0,
+	}, {
+		.key	= "\x39\xbb\xa7\xbe\x59\x97\x9e\x73"
+			  "\xa2\xbc\x6b\x98\xd7\x75\x7f\xe3"
+			  "\xa4\x48\x93\x39\x26\x71\x4a\xc6"
+			  "\xae\x8f\x11\x4c\xc2\x9c\x4a\xbb"
+			  "\x85\x34\x66",
+		.klen	= 35,
+		.iv	= "\x42\xc8\x92\x0f\x36\x58\xe0\x6b",
+		.alen	= 0,
+		.input	= "\x48\x01\x5e\x02\x24\x04\x66\x47"
+			  "\xa1\xea\x6f\xaf\xe8\xfc\xfb\xdd"
+			  "\xa5\xa9\x87\x8d\x84\xee\x2e\x77"
+			  "\xbb\x86\xb9\xf5\x5c\x6c\xff\xf6"
+			  "\x72\xc3\x8e\xf7\x70\xb1\xb2\x07"
+			  "\xbc\xa8\xa3\xbd\x83\x7c\x1d\x2a",
+		.ilen	= 48,
+		.result	= "\xdc\x56\xf2\x71\xb0\xb1\xa0\x6c"
+			  "\xf0\x97\x3a\xfb\x6d\xe7\x32\x99"
+			  "\x3e\xaf\x70\x5e\xb2\x4d\xea\x39"
+			  "\x89\xd4\x75\x7a\x63\xb1\xda\x93",
+		.rlen	= 32,
+		.novrfy	= 1,
+	}, {
+		.key	= "\x58\x5d\xa0\x96\x65\x1a\x04\xd7"
+			  "\x96\xe5\xc5\x68\xaa\x95\x35\xe0"
+			  "\x29\xa0\xba\x9e\x48\x78\xd1\xba"
+			  "\x0d\x1a\x53\x3b\xb5\xe3\xf8\x8b"
+			  "\xcf\x76\x3f",
+		.klen	= 35,
+		.iv	= "\xd9\x95\x75\x8f\x44\x89\x40\x7b",
+		.assoc	= "\x8f\x86\x6c\x4d\x1d\xc5\x39\x88"
+			  "\xc8\xf3\x5c\x52\x10\x63\x6f\x2b"
+			  "\x8a\x2a\xc5\x6f\x30\x23\x58\x7b"
+			  "\xfb\x36\x03\x11\xb4\xd9\xf2\xfe",
+		.alen	= 32,
+		.input	= "\x48\x58\xd6\xf3\xad\x63\x58\xbf"
+			  "\xae\xc7\x5e\xae\x83\x8f\x7b\xe4"
+			  "\x78\x5c\x4c\x67\x71\x89\x94\xbf"
+			  "\x47\xf1\x63\x7e\x1c\x59\xbd\xc5"
+			  "\x7f\x44\x0a\x0c\x01\x18\x07\x92"
+			  "\xe1\xd3\x51\xce\x32\x6d\x0c\x5b",
+		.ilen	= 48,
+		.result	= "\xc2\x54\xc8\xde\x78\x87\x77\x40"
+			  "\x49\x71\xe4\xb7\xe7\xcb\x76\x61"
+			  "\x0a\x41\xb9\xe9\xc0\x76\x54\xab"
+			  "\x04\x49\x3b\x19\x93\x57\x25\x5d",
+		.rlen	= 32,
+	},
+};
+
+/*
+ * ANSI X9.31 Continuous Pseudo-Random Number Generator (AES mode)
+ * test vectors, taken from Appendix B.2.9 and B.2.10:
+ *     http://csrc.nist.gov/groups/STM/cavp/documents/rng/RNGVS.pdf
+ * Only AES-128 is supported at this time.
+ */
+#define ANSI_CPRNG_AES_TEST_VECTORS	6
+
+static struct cprng_testvec ansi_cprng_aes_tv_template[] = {
+	{
+		.key	= "\xf3\xb1\x66\x6d\x13\x60\x72\x42"
+			  "\xed\x06\x1c\xab\xb8\xd4\x62\x02",
+		.klen	= 16,
+		.dt	= "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62"
+			  "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xf9",
+		.dtlen	= 16,
+		.v	= "\x80\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.vlen	= 16,
+		.result	= "\x59\x53\x1e\xd1\x3b\xb0\xc0\x55"
+			  "\x84\x79\x66\x85\xc1\x2f\x76\x41",
+		.rlen	= 16,
+		.loops	= 1,
+	}, {
+		.key	= "\xf3\xb1\x66\x6d\x13\x60\x72\x42"
+			  "\xed\x06\x1c\xab\xb8\xd4\x62\x02",
+		.klen	= 16,
+		.dt	= "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62"
+			  "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfa",
+		.dtlen	= 16,
+		.v	= "\xc0\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.vlen	= 16,
+		.result	= "\x7c\x22\x2c\xf4\xca\x8f\xa2\x4c"
+			  "\x1c\x9c\xb6\x41\xa9\xf3\x22\x0d",
+		.rlen	= 16,
+		.loops	= 1,
+	}, {
+		.key	= "\xf3\xb1\x66\x6d\x13\x60\x72\x42"
+			  "\xed\x06\x1c\xab\xb8\xd4\x62\x02",
+		.klen	= 16,
+		.dt	= "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62"
+			  "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfb",
+		.dtlen	= 16,
+		.v	= "\xe0\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.vlen	= 16,
+		.result	= "\x8a\xaa\x00\x39\x66\x67\x5b\xe5"
+			  "\x29\x14\x28\x81\xa9\x4d\x4e\xc7",
+		.rlen	= 16,
+		.loops	= 1,
+	}, {
+		.key	= "\xf3\xb1\x66\x6d\x13\x60\x72\x42"
+			  "\xed\x06\x1c\xab\xb8\xd4\x62\x02",
+		.klen	= 16,
+		.dt	= "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62"
+			  "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfc",
+		.dtlen	= 16,
+		.v	= "\xf0\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.vlen	= 16,
+		.result	= "\x88\xdd\xa4\x56\x30\x24\x23\xe5"
+			  "\xf6\x9d\xa5\x7e\x7b\x95\xc7\x3a",
+		.rlen	= 16,
+		.loops	= 1,
+	}, {
+		.key	= "\xf3\xb1\x66\x6d\x13\x60\x72\x42"
+			  "\xed\x06\x1c\xab\xb8\xd4\x62\x02",
+		.klen	= 16,
+		.dt	= "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62"
+			  "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfd",
+		.dtlen	= 16,
+		.v	= "\xf8\x00\x00\x00\x00\x00\x00\x00"
+			  "\x00\x00\x00\x00\x00\x00\x00\x00",
+		.vlen	= 16,
+		.result	= "\x05\x25\x92\x46\x61\x79\xd2\xcb"
+			  "\x78\xc4\x0b\x14\x0a\x5a\x9a\xc8",
+		.rlen	= 16,
+		.loops	= 1,
+	}, {	/* Monte Carlo Test */
+		.key	= "\x9f\x5b\x51\x20\x0b\xf3\x34\xb5"
+			  "\xd8\x2b\xe8\xc3\x72\x55\xc8\x48",
+		.klen	= 16,
+		.dt	= "\x63\x76\xbb\xe5\x29\x02\xba\x3b"
+			  "\x67\xc9\x25\xfa\x70\x1f\x11\xac",
+		.dtlen	= 16,
+		.v	= "\x57\x2c\x8e\x76\x87\x26\x47\x97"
+			  "\x7e\x74\xfb\xdd\xc4\x95\x01\xd1",
+		.vlen	= 16,
+		.result	= "\x48\xe9\xbd\x0d\x06\xee\x18\xfb"
+			  "\xe4\x57\x90\xd5\xc3\xfc\x9b\x73",
+		.rlen	= 16,
+		.loops	= 10000,
+	},
+};
+
 /* Cast5 test vectors from RFC 2144 */
 #define CAST5_ENC_TEST_VECTORS	3
 #define CAST5_DEC_TEST_VECTORS	3
diff --git a/crypto/zlib.c b/crypto/zlib.c
index 33609ba..c3015733 100644
--- a/crypto/zlib.c
+++ b/crypto/zlib.c
@@ -165,15 +165,15 @@
 		return -EINVAL;
 	}
 
+	ret = req->avail_out - stream->avail_out;
 	pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
 		 stream->avail_in, stream->avail_out,
-		 req->avail_in - stream->avail_in,
-		 req->avail_out - stream->avail_out);
+		 req->avail_in - stream->avail_in, ret);
 	req->next_in = stream->next_in;
 	req->avail_in = stream->avail_in;
 	req->next_out = stream->next_out;
 	req->avail_out = stream->avail_out;
-	return 0;
+	return ret;
 }
 
 static int zlib_compress_final(struct crypto_pcomp *tfm,
@@ -195,15 +195,15 @@
 		return -EINVAL;
 	}
 
+	ret = req->avail_out - stream->avail_out;
 	pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
 		 stream->avail_in, stream->avail_out,
-		 req->avail_in - stream->avail_in,
-		 req->avail_out - stream->avail_out);
+		 req->avail_in - stream->avail_in, ret);
 	req->next_in = stream->next_in;
 	req->avail_in = stream->avail_in;
 	req->next_out = stream->next_out;
 	req->avail_out = stream->avail_out;
-	return 0;
+	return ret;
 }
 
 
@@ -280,15 +280,15 @@
 		return -EINVAL;
 	}
 
+	ret = req->avail_out - stream->avail_out;
 	pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
 		 stream->avail_in, stream->avail_out,
-		 req->avail_in - stream->avail_in,
-		 req->avail_out - stream->avail_out);
+		 req->avail_in - stream->avail_in, ret);
 	req->next_in = stream->next_in;
 	req->avail_in = stream->avail_in;
 	req->next_out = stream->next_out;
 	req->avail_out = stream->avail_out;
-	return 0;
+	return ret;
 }
 
 static int zlib_decompress_final(struct crypto_pcomp *tfm,
@@ -328,15 +328,15 @@
 		return -EINVAL;
 	}
 
+	ret = req->avail_out - stream->avail_out;
 	pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
 		 stream->avail_in, stream->avail_out,
-		 req->avail_in - stream->avail_in,
-		 req->avail_out - stream->avail_out);
+		 req->avail_in - stream->avail_in, ret);
 	req->next_in = stream->next_in;
 	req->avail_in = stream->avail_in;
 	req->next_out = stream->next_out;
 	req->avail_out = stream->avail_out;
-	return 0;
+	return ret;
 }
 
 
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 9120717..2aa1908 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -535,6 +535,15 @@
 
 	  If unsure, say N.
 
+config PATA_PALMLD
+	tristate "Palm LifeDrive PATA support"
+	depends on MACH_PALMLD
+	help
+	  This option enables support for Palm LifeDrive's internal ATA
+	  port via the new ATA layer.
+
+	  If unsure, say N.
+
 config PATA_PCMCIA
 	tristate "PCMCIA PATA support"
 	depends on PCMCIA
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 7f1ecf9..1558059 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -50,6 +50,7 @@
 obj-$(CONFIG_PATA_MARVELL)	+= pata_marvell.o
 obj-$(CONFIG_PATA_MPIIX)	+= pata_mpiix.o
 obj-$(CONFIG_PATA_OLDPIIX)	+= pata_oldpiix.o
+obj-$(CONFIG_PATA_PALMLD)	+= pata_palmld.o
 obj-$(CONFIG_PATA_PCMCIA)	+= pata_pcmcia.o
 obj-$(CONFIG_PATA_PDC2027X)	+= pata_pdc2027x.o
 obj-$(CONFIG_PATA_PDC_OLD)	+= pata_pdc202xx_old.o
diff --git a/drivers/ata/pata_palmld.c b/drivers/ata/pata_palmld.c
new file mode 100644
index 0000000..11fb4cc
--- /dev/null
+++ b/drivers/ata/pata_palmld.c
@@ -0,0 +1,150 @@
+/*
+ * drivers/ata/pata_palmld.c
+ *
+ * Driver for IDE channel in Palm LifeDrive
+ *
+ * Based on research of:
+ *		Alex Osborne <ato@meshy.org>
+ *
+ * Rewrite for mainline:
+ *		Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Rewritten version based on pata_ixp4xx_cf.c:
+ * ixp4xx PATA/Compact Flash driver
+ * Copyright (C) 2006-07 Tower Technologies
+ * Author: 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/module.h>
+#include <linux/libata.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <scsi/scsi_host.h>
+#include <mach/palmld.h>
+
+#define DRV_NAME "pata_palmld"
+
+static struct scsi_host_template palmld_sht = {
+	ATA_PIO_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations palmld_port_ops = {
+	.inherits		= &ata_sff_port_ops,
+	.sff_data_xfer		= ata_sff_data_xfer_noirq,
+	.cable_detect		= ata_cable_40wire,
+};
+
+static __devinit int palmld_pata_probe(struct platform_device *pdev)
+{
+	struct ata_host *host;
+	struct ata_port *ap;
+	void __iomem *mem;
+	int ret;
+
+	/* allocate host */
+	host = ata_host_alloc(&pdev->dev, 1);
+	if (!host)
+		return -ENOMEM;
+
+	/* remap drive's physical memory address */
+	mem = devm_ioremap(&pdev->dev, PALMLD_IDE_PHYS, 0x1000);
+	if (!mem)
+		return -ENOMEM;
+
+	/* request and activate power GPIO, IRQ GPIO */
+	ret = gpio_request(GPIO_NR_PALMLD_IDE_PWEN, "HDD PWR");
+	if (ret)
+		goto err1;
+	ret = gpio_direction_output(GPIO_NR_PALMLD_IDE_PWEN, 1);
+	if (ret)
+		goto err2;
+
+	ret = gpio_request(GPIO_NR_PALMLD_IDE_RESET, "HDD RST");
+	if (ret)
+		goto err2;
+	ret = gpio_direction_output(GPIO_NR_PALMLD_IDE_RESET, 0);
+	if (ret)
+		goto err3;
+
+	/* reset the drive */
+	gpio_set_value(GPIO_NR_PALMLD_IDE_RESET, 0);
+	msleep(30);
+	gpio_set_value(GPIO_NR_PALMLD_IDE_RESET, 1);
+	msleep(30);
+
+	/* setup the ata port */
+	ap = host->ports[0];
+	ap->ops	= &palmld_port_ops;
+	ap->pio_mask = ATA_PIO4;
+	ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_PIO_POLLING;
+
+	/* memory mapping voodoo */
+	ap->ioaddr.cmd_addr = mem + 0x10;
+	ap->ioaddr.altstatus_addr = mem + 0xe;
+	ap->ioaddr.ctl_addr = mem + 0xe;
+
+	/* start the port */
+	ata_sff_std_ports(&ap->ioaddr);
+
+	/* activate host */
+	return ata_host_activate(host, 0, NULL, IRQF_TRIGGER_RISING,
+					&palmld_sht);
+
+err3:
+	gpio_free(GPIO_NR_PALMLD_IDE_RESET);
+err2:
+	gpio_free(GPIO_NR_PALMLD_IDE_PWEN);
+err1:
+	return ret;
+}
+
+static __devexit int palmld_pata_remove(struct platform_device *dev)
+{
+	struct ata_host *host = platform_get_drvdata(dev);
+
+	ata_host_detach(host);
+
+	/* power down the HDD */
+	gpio_set_value(GPIO_NR_PALMLD_IDE_PWEN, 0);
+
+	gpio_free(GPIO_NR_PALMLD_IDE_RESET);
+	gpio_free(GPIO_NR_PALMLD_IDE_PWEN);
+
+	return 0;
+}
+
+static struct platform_driver palmld_pata_platform_driver = {
+	.driver	 = {
+		.name   = DRV_NAME,
+		.owner  = THIS_MODULE,
+	},
+	.probe		= palmld_pata_probe,
+	.remove		= __devexit_p(palmld_pata_remove),
+};
+
+static int __init palmld_pata_init(void)
+{
+	return platform_driver_register(&palmld_pata_platform_driver);
+}
+
+static void __exit palmld_pata_exit(void)
+{
+	platform_driver_unregister(&palmld_pata_platform_driver);
+}
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("PalmLD PATA driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+
+module_init(palmld_pata_init);
+module_exit(palmld_pata_exit);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index d3a59c6..8a267c4 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -17,7 +17,7 @@
 #include <linux/bitops.h>
 #include <linux/mutex.h>
 #include <linux/kthread.h>
-
+#include <linux/highmem.h>
 #include <linux/firmware.h>
 #include "base.h"
 
@@ -45,7 +45,10 @@
 	struct bin_attribute attr_data;
 	struct firmware *fw;
 	unsigned long status;
-	int alloc_size;
+	struct page **pages;
+	int nr_pages;
+	int page_array_size;
+	const char *vdata;
 	struct timer_list timeout;
 };
 
@@ -122,6 +125,10 @@
 	return sprintf(buf, "%d\n", loading);
 }
 
+/* Some architectures don't have PAGE_KERNEL_RO */
+#ifndef PAGE_KERNEL_RO
+#define PAGE_KERNEL_RO PAGE_KERNEL
+#endif
 /**
  * firmware_loading_store - set value in the 'loading' control file
  * @dev: device pointer
@@ -141,6 +148,7 @@
 {
 	struct firmware_priv *fw_priv = dev_get_drvdata(dev);
 	int loading = simple_strtol(buf, NULL, 10);
+	int i;
 
 	switch (loading) {
 	case 1:
@@ -151,13 +159,30 @@
 		}
 		vfree(fw_priv->fw->data);
 		fw_priv->fw->data = NULL;
+		for (i = 0; i < fw_priv->nr_pages; i++)
+			__free_page(fw_priv->pages[i]);
+		kfree(fw_priv->pages);
+		fw_priv->pages = NULL;
+		fw_priv->page_array_size = 0;
+		fw_priv->nr_pages = 0;
 		fw_priv->fw->size = 0;
-		fw_priv->alloc_size = 0;
 		set_bit(FW_STATUS_LOADING, &fw_priv->status);
 		mutex_unlock(&fw_lock);
 		break;
 	case 0:
 		if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
+			vfree(fw_priv->fw->data);
+			fw_priv->fw->data = vmap(fw_priv->pages,
+						 fw_priv->nr_pages,
+						 0, PAGE_KERNEL_RO);
+			if (!fw_priv->fw->data) {
+				dev_err(dev, "%s: vmap() failed\n", __func__);
+				goto err;
+			}
+			/* Pages will be freed by vfree() */
+			fw_priv->pages = NULL;
+			fw_priv->page_array_size = 0;
+			fw_priv->nr_pages = 0;
 			complete(&fw_priv->completion);
 			clear_bit(FW_STATUS_LOADING, &fw_priv->status);
 			break;
@@ -167,6 +192,7 @@
 		dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading);
 		/* fallthrough */
 	case -1:
+	err:
 		fw_load_abort(fw_priv);
 		break;
 	}
@@ -191,8 +217,28 @@
 		ret_count = -ENODEV;
 		goto out;
 	}
-	ret_count = memory_read_from_buffer(buffer, count, &offset,
-						fw->data, fw->size);
+	if (offset > fw->size)
+		return 0;
+	if (count > fw->size - offset)
+		count = fw->size - offset;
+
+	ret_count = count;
+
+	while (count) {
+		void *page_data;
+		int page_nr = offset >> PAGE_SHIFT;
+		int page_ofs = offset & (PAGE_SIZE-1);
+		int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
+
+		page_data = kmap(fw_priv->pages[page_nr]);
+
+		memcpy(buffer, page_data + page_ofs, page_cnt);
+
+		kunmap(fw_priv->pages[page_nr]);
+		buffer += page_cnt;
+		offset += page_cnt;
+		count -= page_cnt;
+	}
 out:
 	mutex_unlock(&fw_lock);
 	return ret_count;
@@ -201,27 +247,39 @@
 static int
 fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
 {
-	u8 *new_data;
-	int new_size = fw_priv->alloc_size;
+	int pages_needed = ALIGN(min_size, PAGE_SIZE) >> PAGE_SHIFT;
 
-	if (min_size <= fw_priv->alloc_size)
-		return 0;
+	/* If the array of pages is too small, grow it... */
+	if (fw_priv->page_array_size < pages_needed) {
+		int new_array_size = max(pages_needed,
+					 fw_priv->page_array_size * 2);
+		struct page **new_pages;
 
-	new_size = ALIGN(min_size, PAGE_SIZE);
-	new_data = vmalloc(new_size);
-	if (!new_data) {
-		printk(KERN_ERR "%s: unable to alloc buffer\n", __func__);
-		/* Make sure that we don't keep incomplete data */
-		fw_load_abort(fw_priv);
-		return -ENOMEM;
+		new_pages = kmalloc(new_array_size * sizeof(void *),
+				    GFP_KERNEL);
+		if (!new_pages) {
+			fw_load_abort(fw_priv);
+			return -ENOMEM;
+		}
+		memcpy(new_pages, fw_priv->pages,
+		       fw_priv->page_array_size * sizeof(void *));
+		memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
+		       (new_array_size - fw_priv->page_array_size));
+		kfree(fw_priv->pages);
+		fw_priv->pages = new_pages;
+		fw_priv->page_array_size = new_array_size;
 	}
-	fw_priv->alloc_size = new_size;
-	if (fw_priv->fw->data) {
-		memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
-		vfree(fw_priv->fw->data);
+
+	while (fw_priv->nr_pages < pages_needed) {
+		fw_priv->pages[fw_priv->nr_pages] =
+			alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+
+		if (!fw_priv->pages[fw_priv->nr_pages]) {
+			fw_load_abort(fw_priv);
+			return -ENOMEM;
+		}
+		fw_priv->nr_pages++;
 	}
-	fw_priv->fw->data = new_data;
-	BUG_ON(min_size > fw_priv->alloc_size);
 	return 0;
 }
 
@@ -258,10 +316,25 @@
 	if (retval)
 		goto out;
 
-	memcpy((u8 *)fw->data + offset, buffer, count);
-
-	fw->size = max_t(size_t, offset + count, fw->size);
 	retval = count;
+
+	while (count) {
+		void *page_data;
+		int page_nr = offset >> PAGE_SHIFT;
+		int page_ofs = offset & (PAGE_SIZE - 1);
+		int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
+
+		page_data = kmap(fw_priv->pages[page_nr]);
+
+		memcpy(page_data + page_ofs, buffer, page_cnt);
+
+		kunmap(fw_priv->pages[page_nr]);
+		buffer += page_cnt;
+		offset += page_cnt;
+		count -= page_cnt;
+	}
+
+	fw->size = max_t(size_t, offset, fw->size);
 out:
 	mutex_unlock(&fw_lock);
 	return retval;
@@ -277,7 +350,11 @@
 static void fw_dev_release(struct device *dev)
 {
 	struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+	int i;
 
+	for (i = 0; i < fw_priv->nr_pages; i++)
+		__free_page(fw_priv->pages[i]);
+	kfree(fw_priv->pages);
 	kfree(fw_priv);
 	kfree(dev);
 
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 8b4708e..ead3f64 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -469,22 +469,6 @@
 	drv->shutdown(dev);
 }
 
-static int platform_drv_suspend(struct device *_dev, pm_message_t state)
-{
-	struct platform_driver *drv = to_platform_driver(_dev->driver);
-	struct platform_device *dev = to_platform_device(_dev);
-
-	return drv->suspend(dev, state);
-}
-
-static int platform_drv_resume(struct device *_dev)
-{
-	struct platform_driver *drv = to_platform_driver(_dev->driver);
-	struct platform_device *dev = to_platform_device(_dev);
-
-	return drv->resume(dev);
-}
-
 /**
  * platform_driver_register
  * @drv: platform driver structure
@@ -498,10 +482,10 @@
 		drv->driver.remove = platform_drv_remove;
 	if (drv->shutdown)
 		drv->driver.shutdown = platform_drv_shutdown;
-	if (drv->suspend)
-		drv->driver.suspend = platform_drv_suspend;
-	if (drv->resume)
-		drv->driver.resume = platform_drv_resume;
+	if (drv->suspend || drv->resume)
+		pr_warning("Platform driver '%s' needs updating - please use "
+			"dev_pm_ops\n", drv->driver.name);
+
 	return driver_register(&drv->driver);
 }
 EXPORT_SYMBOL_GPL(platform_driver_register);
@@ -633,10 +617,12 @@
 
 static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
 {
+	struct platform_driver *pdrv = to_platform_driver(dev->driver);
+	struct platform_device *pdev = to_platform_device(dev);
 	int ret = 0;
 
-	if (dev->driver && dev->driver->suspend)
-		ret = dev->driver->suspend(dev, mesg);
+	if (dev->driver && pdrv->suspend)
+		ret = pdrv->suspend(pdev, mesg);
 
 	return ret;
 }
@@ -667,10 +653,12 @@
 
 static int platform_legacy_resume(struct device *dev)
 {
+	struct platform_driver *pdrv = to_platform_driver(dev->driver);
+	struct platform_device *pdev = to_platform_device(dev);
 	int ret = 0;
 
-	if (dev->driver && dev->driver->resume)
-		ret = dev->driver->resume(dev);
+	if (dev->driver && pdrv->resume)
+		ret = pdrv->resume(pdev);
 
 	return ret;
 }
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 3e4bc69..fae7254 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -315,13 +315,13 @@
 /*------------------------- Resume routines -------------------------*/
 
 /**
- *	resume_device_noirq - Power on one device (early resume).
+ *	device_resume_noirq - Power on one device (early resume).
  *	@dev:	Device.
  *	@state: PM transition of the system being carried out.
  *
  *	Must be called with interrupts disabled.
  */
-static int resume_device_noirq(struct device *dev, pm_message_t state)
+static int device_resume_noirq(struct device *dev, pm_message_t state)
 {
 	int error = 0;
 
@@ -334,9 +334,6 @@
 	if (dev->bus->pm) {
 		pm_dev_dbg(dev, state, "EARLY ");
 		error = pm_noirq_op(dev, dev->bus->pm, state);
-	} else if (dev->bus->resume_early) {
-		pm_dev_dbg(dev, state, "legacy EARLY ");
-		error = dev->bus->resume_early(dev);
 	}
  End:
 	TRACE_RESUME(error);
@@ -344,16 +341,16 @@
 }
 
 /**
- *	dpm_power_up - Power on all regular (non-sysdev) devices.
+ *	dpm_resume_noirq - Power on all regular (non-sysdev) devices.
  *	@state: PM transition of the system being carried out.
  *
- *	Execute the appropriate "noirq resume" callback for all devices marked
- *	as DPM_OFF_IRQ.
+ *	Call the "noirq" resume handlers for all devices marked as
+ *	DPM_OFF_IRQ and enable device drivers to receive interrupts.
  *
  *	Must be called under dpm_list_mtx.  Device drivers should not receive
  *	interrupts while it's being executed.
  */
-static void dpm_power_up(pm_message_t state)
+void dpm_resume_noirq(pm_message_t state)
 {
 	struct device *dev;
 
@@ -363,33 +360,21 @@
 			int error;
 
 			dev->power.status = DPM_OFF;
-			error = resume_device_noirq(dev, state);
+			error = device_resume_noirq(dev, state);
 			if (error)
 				pm_dev_err(dev, state, " early", error);
 		}
 	mutex_unlock(&dpm_list_mtx);
-}
-
-/**
- *	device_power_up - Turn on all devices that need special attention.
- *	@state: PM transition of the system being carried out.
- *
- *	Call the "early" resume handlers and enable device drivers to receive
- *	interrupts.
- */
-void device_power_up(pm_message_t state)
-{
-	dpm_power_up(state);
 	resume_device_irqs();
 }
-EXPORT_SYMBOL_GPL(device_power_up);
+EXPORT_SYMBOL_GPL(dpm_resume_noirq);
 
 /**
- *	resume_device - Restore state for one device.
+ *	device_resume - Restore state for one device.
  *	@dev:	Device.
  *	@state: PM transition of the system being carried out.
  */
-static int resume_device(struct device *dev, pm_message_t state)
+static int device_resume(struct device *dev, pm_message_t state)
 {
 	int error = 0;
 
@@ -414,9 +399,6 @@
 		if (dev->type->pm) {
 			pm_dev_dbg(dev, state, "type ");
 			error = pm_op(dev, dev->type->pm, state);
-		} else if (dev->type->resume) {
-			pm_dev_dbg(dev, state, "legacy type ");
-			error = dev->type->resume(dev);
 		}
 		if (error)
 			goto End;
@@ -462,7 +444,7 @@
 			dev->power.status = DPM_RESUMING;
 			mutex_unlock(&dpm_list_mtx);
 
-			error = resume_device(dev, state);
+			error = device_resume(dev, state);
 
 			mutex_lock(&dpm_list_mtx);
 			if (error)
@@ -480,11 +462,11 @@
 }
 
 /**
- *	complete_device - Complete a PM transition for given device
+ *	device_complete - Complete a PM transition for given device
  *	@dev:	Device.
  *	@state: PM transition of the system being carried out.
  */
-static void complete_device(struct device *dev, pm_message_t state)
+static void device_complete(struct device *dev, pm_message_t state)
 {
 	down(&dev->sem);
 
@@ -527,7 +509,7 @@
 			dev->power.status = DPM_ON;
 			mutex_unlock(&dpm_list_mtx);
 
-			complete_device(dev, state);
+			device_complete(dev, state);
 
 			mutex_lock(&dpm_list_mtx);
 		}
@@ -540,19 +522,19 @@
 }
 
 /**
- *	device_resume - Restore state of each device in system.
+ *	dpm_resume_end - Restore state of each device in system.
  *	@state: PM transition of the system being carried out.
  *
  *	Resume all the devices, unlock them all, and allow new
  *	devices to be registered once again.
  */
-void device_resume(pm_message_t state)
+void dpm_resume_end(pm_message_t state)
 {
 	might_sleep();
 	dpm_resume(state);
 	dpm_complete(state);
 }
-EXPORT_SYMBOL_GPL(device_resume);
+EXPORT_SYMBOL_GPL(dpm_resume_end);
 
 
 /*------------------------- Suspend routines -------------------------*/
@@ -577,13 +559,13 @@
 }
 
 /**
- *	suspend_device_noirq - Shut down one device (late suspend).
+ *	device_suspend_noirq - Shut down one device (late suspend).
  *	@dev:	Device.
  *	@state: PM transition of the system being carried out.
  *
  *	This is called with interrupts off and only a single CPU running.
  */
-static int suspend_device_noirq(struct device *dev, pm_message_t state)
+static int device_suspend_noirq(struct device *dev, pm_message_t state)
 {
 	int error = 0;
 
@@ -593,24 +575,20 @@
 	if (dev->bus->pm) {
 		pm_dev_dbg(dev, state, "LATE ");
 		error = pm_noirq_op(dev, dev->bus->pm, state);
-	} else if (dev->bus->suspend_late) {
-		pm_dev_dbg(dev, state, "legacy LATE ");
-		error = dev->bus->suspend_late(dev, state);
-		suspend_report_result(dev->bus->suspend_late, error);
 	}
 	return error;
 }
 
 /**
- *	device_power_down - Shut down special devices.
+ *	dpm_suspend_noirq - Power down all regular (non-sysdev) devices.
  *	@state: PM transition of the system being carried out.
  *
- *	Prevent device drivers from receiving interrupts and call the "late"
+ *	Prevent device drivers from receiving interrupts and call the "noirq"
  *	suspend handlers.
  *
  *	Must be called under dpm_list_mtx.
  */
-int device_power_down(pm_message_t state)
+int dpm_suspend_noirq(pm_message_t state)
 {
 	struct device *dev;
 	int error = 0;
@@ -618,7 +596,7 @@
 	suspend_device_irqs();
 	mutex_lock(&dpm_list_mtx);
 	list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
-		error = suspend_device_noirq(dev, state);
+		error = device_suspend_noirq(dev, state);
 		if (error) {
 			pm_dev_err(dev, state, " late", error);
 			break;
@@ -627,17 +605,17 @@
 	}
 	mutex_unlock(&dpm_list_mtx);
 	if (error)
-		device_power_up(resume_event(state));
+		dpm_resume_noirq(resume_event(state));
 	return error;
 }
-EXPORT_SYMBOL_GPL(device_power_down);
+EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
 
 /**
- *	suspend_device - Save state of one device.
+ *	device_suspend - Save state of one device.
  *	@dev:	Device.
  *	@state: PM transition of the system being carried out.
  */
-static int suspend_device(struct device *dev, pm_message_t state)
+static int device_suspend(struct device *dev, pm_message_t state)
 {
 	int error = 0;
 
@@ -660,10 +638,6 @@
 		if (dev->type->pm) {
 			pm_dev_dbg(dev, state, "type ");
 			error = pm_op(dev, dev->type->pm, state);
-		} else if (dev->type->suspend) {
-			pm_dev_dbg(dev, state, "legacy type ");
-			error = dev->type->suspend(dev, state);
-			suspend_report_result(dev->type->suspend, error);
 		}
 		if (error)
 			goto End;
@@ -704,7 +678,7 @@
 		get_device(dev);
 		mutex_unlock(&dpm_list_mtx);
 
-		error = suspend_device(dev, state);
+		error = device_suspend(dev, state);
 
 		mutex_lock(&dpm_list_mtx);
 		if (error) {
@@ -723,11 +697,11 @@
 }
 
 /**
- *	prepare_device - Execute the ->prepare() callback(s) for given device.
+ *	device_prepare - Execute the ->prepare() callback(s) for given device.
  *	@dev:	Device.
  *	@state: PM transition of the system being carried out.
  */
-static int prepare_device(struct device *dev, pm_message_t state)
+static int device_prepare(struct device *dev, pm_message_t state)
 {
 	int error = 0;
 
@@ -781,7 +755,7 @@
 		dev->power.status = DPM_PREPARING;
 		mutex_unlock(&dpm_list_mtx);
 
-		error = prepare_device(dev, state);
+		error = device_prepare(dev, state);
 
 		mutex_lock(&dpm_list_mtx);
 		if (error) {
@@ -807,12 +781,12 @@
 }
 
 /**
- *	device_suspend - Save state and stop all devices in system.
+ *	dpm_suspend_start - Save state and stop all devices in system.
  *	@state: PM transition of the system being carried out.
  *
  *	Prepare and suspend all devices.
  */
-int device_suspend(pm_message_t state)
+int dpm_suspend_start(pm_message_t state)
 {
 	int error;
 
@@ -822,7 +796,7 @@
 		error = dpm_suspend(state);
 	return error;
 }
-EXPORT_SYMBOL_GPL(device_suspend);
+EXPORT_SYMBOL_GPL(dpm_suspend_start);
 
 void __suspend_report_result(const char *function, void *fn, int ret)
 {
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 3236b43..9742a78 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -343,11 +343,15 @@
 	/* First, call the class-specific one */
 	if (cls->resume)
 		cls->resume(dev);
+	WARN_ONCE(!irqs_disabled(),
+		"Interrupts enabled after %pF\n", cls->resume);
 
 	/* Call auxillary drivers next. */
 	list_for_each_entry(drv, &cls->drivers, entry) {
 		if (drv->resume)
 			drv->resume(dev);
+		WARN_ONCE(!irqs_disabled(),
+			"Interrupts enabled after %pF\n", drv->resume);
 	}
 }
 
@@ -377,6 +381,9 @@
 	if (ret)
 		return ret;
 
+	WARN_ONCE(!irqs_disabled(),
+		"Interrupts enabled while suspending system devices\n");
+
 	pr_debug("Suspending System Devices\n");
 
 	list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
@@ -393,6 +400,9 @@
 					if (ret)
 						goto aux_driver;
 				}
+				WARN_ONCE(!irqs_disabled(),
+					"Interrupts enabled after %pF\n",
+					drv->suspend);
 			}
 
 			/* Now call the generic one */
@@ -400,6 +410,9 @@
 				ret = cls->suspend(sysdev, state);
 				if (ret)
 					goto cls_driver;
+				WARN_ONCE(!irqs_disabled(),
+					"Interrupts enabled after %pF\n",
+					cls->suspend);
 			}
 		}
 	}
@@ -452,6 +465,9 @@
 {
 	struct sysdev_class *cls;
 
+	WARN_ONCE(!irqs_disabled(),
+		"Interrupts enabled while resuming system devices\n");
+
 	pr_debug("Resuming System Devices\n");
 
 	list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) {
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 1b98cc5..bb72ada 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -438,7 +438,7 @@
 
 config XILINX_SYSACE
 	tristate "Xilinx SystemACE support"
-	depends on 4xx
+	depends on 4xx || MICROBLAZE
 	help
 	  Include support for the Xilinx SystemACE CompactFlash interface
 
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index c0facaa..43db3ea 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -254,7 +254,7 @@
 	return index << PART_BITS;
 }
 
-static int virtblk_probe(struct virtio_device *vdev)
+static int __devinit virtblk_probe(struct virtio_device *vdev)
 {
 	struct virtio_blk *vblk;
 	int err;
@@ -288,7 +288,7 @@
 	sg_init_table(vblk->sg, vblk->sg_elems);
 
 	/* We expect one virtqueue, for output. */
-	vblk->vq = vdev->config->find_vq(vdev, 0, blk_done);
+	vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests");
 	if (IS_ERR(vblk->vq)) {
 		err = PTR_ERR(vblk->vq);
 		goto out_free_vblk;
@@ -388,14 +388,14 @@
 out_mempool:
 	mempool_destroy(vblk->pool);
 out_free_vq:
-	vdev->config->del_vq(vblk->vq);
+	vdev->config->del_vqs(vdev);
 out_free_vblk:
 	kfree(vblk);
 out:
 	return err;
 }
 
-static void virtblk_remove(struct virtio_device *vdev)
+static void __devexit virtblk_remove(struct virtio_device *vdev)
 {
 	struct virtio_blk *vblk = vdev->priv;
 
@@ -409,7 +409,7 @@
 	blk_cleanup_queue(vblk->disk->queue);
 	put_disk(vblk->disk);
 	mempool_destroy(vblk->pool);
-	vdev->config->del_vq(vblk->vq);
+	vdev->config->del_vqs(vdev);
 	kfree(vblk);
 }
 
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 067e9dc..30bae6d 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -906,7 +906,7 @@
 
 config XILINX_HWICAP
 	tristate "Xilinx HWICAP Support"
-	depends on XILINX_VIRTEX
+	depends on XILINX_VIRTEX || MICROBLAZE
 	help
 	  This option enables support for Xilinx Internal Configuration
 	  Access Port (ICAP) driver.  The ICAP is used on Xilinx Virtex
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 3686912..7a748fa 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -46,6 +46,10 @@
 #define PCI_DEVICE_ID_INTEL_G45_IG          0x2E22
 #define PCI_DEVICE_ID_INTEL_G41_HB          0x2E30
 #define PCI_DEVICE_ID_INTEL_G41_IG          0x2E32
+#define PCI_DEVICE_ID_INTEL_IGDNG_D_HB	    0x0040
+#define PCI_DEVICE_ID_INTEL_IGDNG_D_IG	    0x0042
+#define PCI_DEVICE_ID_INTEL_IGDNG_M_HB	    0x0044
+#define PCI_DEVICE_ID_INTEL_IGDNG_M_IG	    0x0046
 
 /* cover 915 and 945 variants */
 #define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
@@ -75,7 +79,9 @@
 		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \
 		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \
 		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB)
+		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \
+		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_D_HB || \
+		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_M_HB)
 
 extern int agp_memory_reserved;
 
@@ -1211,6 +1217,8 @@
 	case PCI_DEVICE_ID_INTEL_Q45_HB:
 	case PCI_DEVICE_ID_INTEL_G45_HB:
 	case PCI_DEVICE_ID_INTEL_G41_HB:
+	case PCI_DEVICE_ID_INTEL_IGDNG_D_HB:
+	case PCI_DEVICE_ID_INTEL_IGDNG_M_HB:
 		*gtt_offset = *gtt_size = MB(2);
 		break;
 	default:
@@ -2186,6 +2194,10 @@
 	    "G45/G43", NULL, &intel_i965_driver },
 	{ PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0,
 	    "G41", NULL, &intel_i965_driver },
+	{ PCI_DEVICE_ID_INTEL_IGDNG_D_HB, PCI_DEVICE_ID_INTEL_IGDNG_D_IG, 0,
+	    "IGDNG/D", NULL, &intel_i965_driver },
+	{ PCI_DEVICE_ID_INTEL_IGDNG_M_HB, PCI_DEVICE_ID_INTEL_IGDNG_M_IG, 0,
+	    "IGDNG/M", NULL, &intel_i965_driver },
 	{ 0, 0, 0, NULL, NULL, NULL }
 };
 
@@ -2387,6 +2399,8 @@
 	ID(PCI_DEVICE_ID_INTEL_Q45_HB),
 	ID(PCI_DEVICE_ID_INTEL_G45_HB),
 	ID(PCI_DEVICE_ID_INTEL_G41_HB),
+	ID(PCI_DEVICE_ID_INTEL_IGDNG_D_HB),
+	ID(PCI_DEVICE_ID_INTEL_IGDNG_M_HB),
 	{ }
 };
 
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 5fab647..f4b3f72 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -88,7 +88,7 @@
 
 config HW_RANDOM_VIA
 	tristate "VIA HW Random Number Generator support"
-	depends on HW_RANDOM && X86_32
+	depends on HW_RANDOM && X86
 	default HW_RANDOM
 	---help---
 	  This driver provides kernel-side support for the Random Number
@@ -148,3 +148,15 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called virtio-rng.  If unsure, say N.
+
+config HW_RANDOM_MXC_RNGA
+	tristate "Freescale i.MX RNGA Random Number Generator"
+	depends on HW_RANDOM && ARCH_HAS_RNGA
+	---help---
+	  This driver provides kernel-side support for the Random Number
+	  Generator hardware found on Freescale i.MX processors.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mxc-rnga.
+
+	  If unsure, say Y.
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index e81d21a..fd1ecd2 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -15,3 +15,4 @@
 obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
 obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
 obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
+obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
diff --git a/drivers/char/hw_random/mxc-rnga.c b/drivers/char/hw_random/mxc-rnga.c
new file mode 100644
index 0000000..187c6be
--- /dev/null
+++ b/drivers/char/hw_random/mxc-rnga.c
@@ -0,0 +1,247 @@
+/*
+ * RNG driver for Freescale RNGA
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Author: Alan Carvalho de Assis <acassis@gmail.com>
+ */
+
+/*
+ * 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
+ *
+ * This driver is based on other RNG drivers.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+
+/* RNGA Registers */
+#define RNGA_CONTROL			0x00
+#define RNGA_STATUS			0x04
+#define RNGA_ENTROPY			0x08
+#define RNGA_OUTPUT_FIFO		0x0c
+#define RNGA_MODE			0x10
+#define RNGA_VERIFICATION_CONTROL	0x14
+#define RNGA_OSC_CONTROL_COUNTER	0x18
+#define RNGA_OSC1_COUNTER		0x1c
+#define RNGA_OSC2_COUNTER		0x20
+#define RNGA_OSC_COUNTER_STATUS		0x24
+
+/* RNGA Registers Range */
+#define RNG_ADDR_RANGE			0x28
+
+/* RNGA Control Register */
+#define RNGA_CONTROL_SLEEP		0x00000010
+#define RNGA_CONTROL_CLEAR_INT		0x00000008
+#define RNGA_CONTROL_MASK_INTS		0x00000004
+#define RNGA_CONTROL_HIGH_ASSURANCE	0x00000002
+#define RNGA_CONTROL_GO			0x00000001
+
+#define RNGA_STATUS_LEVEL_MASK		0x0000ff00
+
+/* RNGA Status Register */
+#define RNGA_STATUS_OSC_DEAD		0x80000000
+#define RNGA_STATUS_SLEEP		0x00000010
+#define RNGA_STATUS_ERROR_INT		0x00000008
+#define RNGA_STATUS_FIFO_UNDERFLOW	0x00000004
+#define RNGA_STATUS_LAST_READ_STATUS	0x00000002
+#define RNGA_STATUS_SECURITY_VIOLATION	0x00000001
+
+static struct platform_device *rng_dev;
+
+static int mxc_rnga_data_present(struct hwrng *rng)
+{
+	int level;
+	void __iomem *rng_base = (void __iomem *)rng->priv;
+
+	/* how many random numbers is in FIFO? [0-16] */
+	level = ((__raw_readl(rng_base + RNGA_STATUS) &
+			RNGA_STATUS_LEVEL_MASK) >> 8);
+
+	return level > 0 ? 1 : 0;
+}
+
+static int mxc_rnga_data_read(struct hwrng *rng, u32 * data)
+{
+	int err;
+	u32 ctrl;
+	void __iomem *rng_base = (void __iomem *)rng->priv;
+
+	/* retrieve a random number from FIFO */
+	*data = __raw_readl(rng_base + RNGA_OUTPUT_FIFO);
+
+	/* some error while reading this random number? */
+	err = __raw_readl(rng_base + RNGA_STATUS) & RNGA_STATUS_ERROR_INT;
+
+	/* if error: clear error interrupt, but doesn't return random number */
+	if (err) {
+		dev_dbg(&rng_dev->dev, "Error while reading random number!\n");
+		ctrl = __raw_readl(rng_base + RNGA_CONTROL);
+		__raw_writel(ctrl | RNGA_CONTROL_CLEAR_INT,
+					rng_base + RNGA_CONTROL);
+		return 0;
+	} else
+		return 4;
+}
+
+static int mxc_rnga_init(struct hwrng *rng)
+{
+	u32 ctrl, osc;
+	void __iomem *rng_base = (void __iomem *)rng->priv;
+
+	/* wake up */
+	ctrl = __raw_readl(rng_base + RNGA_CONTROL);
+	__raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, rng_base + RNGA_CONTROL);
+
+	/* verify if oscillator is working */
+	osc = __raw_readl(rng_base + RNGA_STATUS);
+	if (osc & RNGA_STATUS_OSC_DEAD) {
+		dev_err(&rng_dev->dev, "RNGA Oscillator is dead!\n");
+		return -ENODEV;
+	}
+
+	/* go running */
+	ctrl = __raw_readl(rng_base + RNGA_CONTROL);
+	__raw_writel(ctrl | RNGA_CONTROL_GO, rng_base + RNGA_CONTROL);
+
+	return 0;
+}
+
+static void mxc_rnga_cleanup(struct hwrng *rng)
+{
+	u32 ctrl;
+	void __iomem *rng_base = (void __iomem *)rng->priv;
+
+	ctrl = __raw_readl(rng_base + RNGA_CONTROL);
+
+	/* stop rnga */
+	__raw_writel(ctrl & ~RNGA_CONTROL_GO, rng_base + RNGA_CONTROL);
+}
+
+static struct hwrng mxc_rnga = {
+	.name = "mxc-rnga",
+	.init = mxc_rnga_init,
+	.cleanup = mxc_rnga_cleanup,
+	.data_present = mxc_rnga_data_present,
+	.data_read = mxc_rnga_data_read
+};
+
+static int __init mxc_rnga_probe(struct platform_device *pdev)
+{
+	int err = -ENODEV;
+	struct clk *clk;
+	struct resource *res, *mem;
+	void __iomem *rng_base = NULL;
+
+	if (rng_dev)
+		return -EBUSY;
+
+	clk = clk_get(&pdev->dev, "rng");
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "Could not get rng_clk!\n");
+		err = PTR_ERR(clk);
+		goto out;
+	}
+
+	clk_enable(clk);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		err = -ENOENT;
+		goto err_region;
+	}
+
+	mem = request_mem_region(res->start, resource_size(res), pdev->name);
+	if (mem == NULL) {
+		err = -EBUSY;
+		goto err_region;
+	}
+
+	rng_base = ioremap(res->start, resource_size(res));
+	if (!rng_base) {
+		err = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	mxc_rnga.priv = (unsigned long)rng_base;
+
+	err = hwrng_register(&mxc_rnga);
+	if (err) {
+		dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err);
+		goto err_register;
+	}
+
+	rng_dev = pdev;
+
+	dev_info(&pdev->dev, "MXC RNGA Registered.\n");
+
+	return 0;
+
+err_register:
+	iounmap(rng_base);
+	rng_base = NULL;
+
+err_ioremap:
+	release_mem_region(res->start, resource_size(res));
+
+err_region:
+	clk_disable(clk);
+	clk_put(clk);
+
+out:
+	return err;
+}
+
+static int __exit mxc_rnga_remove(struct platform_device *pdev)
+{
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	void __iomem *rng_base = (void __iomem *)mxc_rnga.priv;
+	struct clk *clk = clk_get(&pdev->dev, "rng");
+
+	hwrng_unregister(&mxc_rnga);
+
+	iounmap(rng_base);
+
+	release_mem_region(res->start, resource_size(res));
+
+	clk_disable(clk);
+	clk_put(clk);
+
+	return 0;
+}
+
+static struct platform_driver mxc_rnga_driver = {
+	.driver = {
+		   .name = "mxc_rnga",
+		   .owner = THIS_MODULE,
+		   },
+	.remove = __exit_p(mxc_rnga_remove),
+};
+
+static int __init mod_init(void)
+{
+	return platform_driver_probe(&mxc_rnga_driver, mxc_rnga_probe);
+}
+
+static void __exit mod_exit(void)
+{
+	platform_driver_unregister(&mxc_rnga_driver);
+}
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("H/W RNGA driver for i.MX");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index 538313f..00dd3de 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -89,7 +89,7 @@
 	.data_read	= omap_rng_data_read,
 };
 
-static int __init omap_rng_probe(struct platform_device *pdev)
+static int __devinit omap_rng_probe(struct platform_device *pdev)
 {
 	struct resource *res, *mem;
 	int ret;
diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c
index dcd352a..a94e930 100644
--- a/drivers/char/hw_random/timeriomem-rng.c
+++ b/drivers/char/hw_random/timeriomem-rng.c
@@ -88,9 +88,9 @@
 	.priv		= 0,
 };
 
-static int __init timeriomem_rng_probe(struct platform_device *pdev)
+static int __devinit timeriomem_rng_probe(struct platform_device *pdev)
 {
-	struct resource *res, *mem;
+	struct resource *res;
 	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -98,21 +98,12 @@
 	if (!res)
 		return -ENOENT;
 
-	mem = request_mem_region(res->start, res->end - res->start + 1,
-				 pdev->name);
-	if (mem == NULL)
-		return -EBUSY;
-
-	dev_set_drvdata(&pdev->dev, mem);
-
 	timeriomem_rng_data = pdev->dev.platform_data;
 
 	timeriomem_rng_data->address = ioremap(res->start,
 						res->end - res->start + 1);
-	if (!timeriomem_rng_data->address) {
-		ret = -ENOMEM;
-		goto err_ioremap;
-	}
+	if (!timeriomem_rng_data->address)
+		return -EIO;
 
 	if (timeriomem_rng_data->period != 0
 		&& usecs_to_jiffies(timeriomem_rng_data->period) > 0) {
@@ -125,7 +116,7 @@
 
 	ret = hwrng_register(&timeriomem_rng_ops);
 	if (ret)
-		goto err_register;
+		goto failed;
 
 	dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n",
 			timeriomem_rng_data->address,
@@ -133,24 +124,19 @@
 
 	return 0;
 
-err_register:
+failed:
 	dev_err(&pdev->dev, "problem registering\n");
 	iounmap(timeriomem_rng_data->address);
-err_ioremap:
-	release_resource(mem);
 
 	return ret;
 }
 
 static int __devexit timeriomem_rng_remove(struct platform_device *pdev)
 {
-	struct resource *mem = dev_get_drvdata(&pdev->dev);
-
 	del_timer_sync(&timeriomem_rng_timer);
 	hwrng_unregister(&timeriomem_rng_ops);
 
 	iounmap(timeriomem_rng_data->address);
-	release_resource(mem);
 
 	return 0;
 }
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index 4e9573c..794aacb 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -132,6 +132,19 @@
 	struct cpuinfo_x86 *c = &cpu_data(0);
 	u32 lo, hi, old_lo;
 
+	/* VIA Nano CPUs don't have the MSR_VIA_RNG anymore.  The RNG
+	 * is always enabled if CPUID rng_en is set.  There is no
+	 * RNG configuration like it used to be the case in this
+	 * register */
+	if ((c->x86 == 6) && (c->x86_model >= 0x0f)) {
+		if (!cpu_has_xstore_enabled) {
+			printk(KERN_ERR PFX "can't enable hardware RNG "
+				"if XSTORE is not enabled\n");
+			return -ENODEV;
+		}
+		return 0;
+	}
+
 	/* Control the RNG via MSR.  Tread lightly and pay very close
 	 * close attention to values written, as the reserved fields
 	 * are documented to be "undefined and unpredictable"; but it
@@ -205,5 +218,5 @@
 module_init(mod_init);
 module_exit(mod_exit);
 
-MODULE_DESCRIPTION("H/W RNG driver for VIA chipsets");
+MODULE_DESCRIPTION("H/W RNG driver for VIA CPU with PadLock");
 MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index 86e83f8..32216b6 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -35,13 +35,13 @@
 
 static void random_recv_done(struct virtqueue *vq)
 {
-	int len;
+	unsigned int len;
 
 	/* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */
 	if (!vq->vq_ops->get_buf(vq, &len))
 		return;
 
-	data_left = len / sizeof(random_data[0]);
+	data_left += len;
 	complete(&have_data);
 }
 
@@ -49,7 +49,7 @@
 {
 	struct scatterlist sg;
 
-	sg_init_one(&sg, random_data, RANDOM_DATA_SIZE);
+	sg_init_one(&sg, random_data+data_left, RANDOM_DATA_SIZE-data_left);
 	/* There should always be room for one buffer. */
 	if (vq->vq_ops->add_buf(vq, &sg, 0, 1, random_data) != 0)
 		BUG();
@@ -59,24 +59,32 @@
 /* At least we don't udelay() in a loop like some other drivers. */
 static int virtio_data_present(struct hwrng *rng, int wait)
 {
-	if (data_left)
+	if (data_left >= sizeof(u32))
 		return 1;
 
+again:
 	if (!wait)
 		return 0;
 
 	wait_for_completion(&have_data);
+
+	/* Not enough?  Re-register. */
+	if (unlikely(data_left < sizeof(u32))) {
+		register_buffer();
+		goto again;
+	}
+
 	return 1;
 }
 
 /* virtio_data_present() must have succeeded before this is called. */
 static int virtio_data_read(struct hwrng *rng, u32 *data)
 {
-	BUG_ON(!data_left);
+	BUG_ON(data_left < sizeof(u32));
+	data_left -= sizeof(u32);
+	*data = random_data[data_left / 4];
 
-	*data = random_data[--data_left];
-
-	if (!data_left) {
+	if (data_left < sizeof(u32)) {
 		init_completion(&have_data);
 		register_buffer();
 	}
@@ -94,13 +102,13 @@
 	int err;
 
 	/* We expect a single virtqueue. */
-	vq = vdev->config->find_vq(vdev, 0, random_recv_done);
+	vq = virtio_find_single_vq(vdev, random_recv_done, "input");
 	if (IS_ERR(vq))
 		return PTR_ERR(vq);
 
 	err = hwrng_register(&virtio_hwrng);
 	if (err) {
-		vdev->config->del_vq(vq);
+		vdev->config->del_vqs(vdev);
 		return err;
 	}
 
@@ -112,7 +120,7 @@
 {
 	vdev->config->reset(vdev);
 	hwrng_unregister(&virtio_hwrng);
-	vdev->config->del_vq(vq);
+	vdev->config->del_vqs(vdev);
 }
 
 static struct virtio_device_id id_table[] = {
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index ff6f5a4..c74dacf 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -188,6 +188,9 @@
  * Finally we put our input buffer in the input queue, ready to receive. */
 static int __devinit virtcons_probe(struct virtio_device *dev)
 {
+	vq_callback_t *callbacks[] = { hvc_handle_input, NULL};
+	const char *names[] = { "input", "output" };
+	struct virtqueue *vqs[2];
 	int err;
 
 	vdev = dev;
@@ -199,20 +202,15 @@
 		goto fail;
 	}
 
-	/* Find the input queue. */
+	/* Find the queues. */
 	/* FIXME: This is why we want to wean off hvc: we do nothing
 	 * when input comes in. */
-	in_vq = vdev->config->find_vq(vdev, 0, hvc_handle_input);
-	if (IS_ERR(in_vq)) {
-		err = PTR_ERR(in_vq);
+	err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names);
+	if (err)
 		goto free;
-	}
 
-	out_vq = vdev->config->find_vq(vdev, 1, NULL);
-	if (IS_ERR(out_vq)) {
-		err = PTR_ERR(out_vq);
-		goto free_in_vq;
-	}
+	in_vq = vqs[0];
+	out_vq = vqs[1];
 
 	/* Start using the new console output. */
 	virtio_cons.get_chars = get_chars;
@@ -233,17 +231,15 @@
 	hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE);
 	if (IS_ERR(hvc)) {
 		err = PTR_ERR(hvc);
-		goto free_out_vq;
+		goto free_vqs;
 	}
 
 	/* Register the input buffer the first time. */
 	add_inbuf();
 	return 0;
 
-free_out_vq:
-	vdev->config->del_vq(out_vq);
-free_in_vq:
-	vdev->config->del_vq(in_vq);
+free_vqs:
+	vdev->config->del_vqs(vdev);
 free:
 	kfree(inbuf);
 fail:
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index de9ebee..c796a86 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -103,7 +103,6 @@
 #include <linux/io.h>
 #include <asm/system.h>
 #include <linux/uaccess.h>
-#include <linux/kmemleak.h>
 
 #define MAX_NR_CON_DRIVER 16
 
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 3e72a6a..5b27692 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -12,7 +12,7 @@
 
 config CRYPTO_DEV_PADLOCK
 	tristate "Support for VIA PadLock ACE"
-	depends on X86_32 && !UML
+	depends on X86 && !UML
 	select CRYPTO_ALGAPI
 	help
 	  Some VIA processors come with an integrated crypto engine
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index 2bef086..5f753fc 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -2564,7 +2564,7 @@
 		hifn_process_queue(dev);
 }
 
-static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int __devinit hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	int err, i;
 	struct hifn_device *dev;
@@ -2696,7 +2696,7 @@
 	return err;
 }
 
-static void hifn_remove(struct pci_dev *pdev)
+static void __devexit hifn_remove(struct pci_dev *pdev)
 {
 	int i;
 	struct hifn_device *dev;
@@ -2744,7 +2744,7 @@
 	.remove   = __devexit_p(hifn_remove),
 };
 
-static int __devinit hifn_init(void)
+static int __init hifn_init(void)
 {
 	unsigned int freq;
 	int err;
@@ -2789,7 +2789,7 @@
 	return 0;
 }
 
-static void __devexit hifn_fini(void)
+static void __exit hifn_fini(void)
 {
 	pci_unregister_driver(&hifn_pci_driver);
 
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index 856b3cc..87f92c3 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -154,7 +154,11 @@
 	int cpu = raw_smp_processor_id();
 
 	if (cword != per_cpu(last_cword, cpu))
+#ifndef CONFIG_X86_64
 		asm volatile ("pushfl; popfl");
+#else
+		asm volatile ("pushfq; popfq");
+#endif
 }
 
 static inline void padlock_store_cword(struct cword *cword)
@@ -208,10 +212,19 @@
 
 	asm volatile ("test $1, %%cl;"
 		      "je 1f;"
+#ifndef CONFIG_X86_64
 		      "lea -1(%%ecx), %%eax;"
 		      "mov $1, %%ecx;"
+#else
+		      "lea -1(%%rcx), %%rax;"
+		      "mov $1, %%rcx;"
+#endif
 		      ".byte 0xf3,0x0f,0xa7,0xc8;"	/* rep xcryptecb */
+#ifndef CONFIG_X86_64
 		      "mov %%eax, %%ecx;"
+#else
+		      "mov %%rax, %%rcx;"
+#endif
 		      "1:"
 		      ".byte 0xf3,0x0f,0xa7,0xc8"	/* rep xcryptecb */
 		      : "+S"(input), "+D"(output)
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index a3918c1..c70775f 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -44,6 +44,8 @@
 #include <crypto/sha.h>
 #include <crypto/aead.h>
 #include <crypto/authenc.h>
+#include <crypto/skcipher.h>
+#include <crypto/scatterwalk.h>
 
 #include "talitos.h"
 
@@ -339,7 +341,8 @@
 				status = error;
 
 		dma_unmap_single(dev, request->dma_desc,
-			sizeof(struct talitos_desc), DMA_BIDIRECTIONAL);
+				 sizeof(struct talitos_desc),
+				 DMA_BIDIRECTIONAL);
 
 		/* copy entries so we can call callback outside lock */
 		saved_req.desc = request->desc;
@@ -413,7 +416,8 @@
 /*
  * user diagnostics; report root cause of error based on execution unit status
  */
-static void report_eu_error(struct device *dev, int ch, struct talitos_desc *desc)
+static void report_eu_error(struct device *dev, int ch,
+			    struct talitos_desc *desc)
 {
 	struct talitos_private *priv = dev_get_drvdata(dev);
 	int i;
@@ -684,8 +688,8 @@
 	unsigned int authsize;
 };
 
-static int aead_authenc_setauthsize(struct crypto_aead *authenc,
-						 unsigned int authsize)
+static int aead_setauthsize(struct crypto_aead *authenc,
+			    unsigned int authsize)
 {
 	struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
 
@@ -694,8 +698,8 @@
 	return 0;
 }
 
-static int aead_authenc_setkey(struct crypto_aead *authenc,
-					    const u8 *key, unsigned int keylen)
+static int aead_setkey(struct crypto_aead *authenc,
+		       const u8 *key, unsigned int keylen)
 {
 	struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
 	struct rtattr *rta = (void *)key;
@@ -740,7 +744,7 @@
 }
 
 /*
- * ipsec_esp_edesc - s/w-extended ipsec_esp descriptor
+ * talitos_edesc - s/w-extended descriptor
  * @src_nents: number of segments in input scatterlist
  * @dst_nents: number of segments in output scatterlist
  * @dma_len: length of dma mapped link_tbl space
@@ -752,17 +756,67 @@
  * is greater than 1, an integrity check value is concatenated to the end
  * of link_tbl data
  */
-struct ipsec_esp_edesc {
+struct talitos_edesc {
 	int src_nents;
 	int dst_nents;
+	int src_is_chained;
+	int dst_is_chained;
 	int dma_len;
 	dma_addr_t dma_link_tbl;
 	struct talitos_desc desc;
 	struct talitos_ptr link_tbl[0];
 };
 
+static int talitos_map_sg(struct device *dev, struct scatterlist *sg,
+			  unsigned int nents, enum dma_data_direction dir,
+			  int chained)
+{
+	if (unlikely(chained))
+		while (sg) {
+			dma_map_sg(dev, sg, 1, dir);
+			sg = scatterwalk_sg_next(sg);
+		}
+	else
+		dma_map_sg(dev, sg, nents, dir);
+	return nents;
+}
+
+static void talitos_unmap_sg_chain(struct device *dev, struct scatterlist *sg,
+				   enum dma_data_direction dir)
+{
+	while (sg) {
+		dma_unmap_sg(dev, sg, 1, dir);
+		sg = scatterwalk_sg_next(sg);
+	}
+}
+
+static void talitos_sg_unmap(struct device *dev,
+			     struct talitos_edesc *edesc,
+			     struct scatterlist *src,
+			     struct scatterlist *dst)
+{
+	unsigned int src_nents = edesc->src_nents ? : 1;
+	unsigned int dst_nents = edesc->dst_nents ? : 1;
+
+	if (src != dst) {
+		if (edesc->src_is_chained)
+			talitos_unmap_sg_chain(dev, src, DMA_TO_DEVICE);
+		else
+			dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE);
+
+		if (edesc->dst_is_chained)
+			talitos_unmap_sg_chain(dev, dst, DMA_FROM_DEVICE);
+		else
+			dma_unmap_sg(dev, dst, dst_nents, DMA_FROM_DEVICE);
+	} else
+		if (edesc->src_is_chained)
+			talitos_unmap_sg_chain(dev, src, DMA_BIDIRECTIONAL);
+		else
+			dma_unmap_sg(dev, src, src_nents, DMA_BIDIRECTIONAL);
+}
+
 static void ipsec_esp_unmap(struct device *dev,
-			    struct ipsec_esp_edesc *edesc,
+			    struct talitos_edesc *edesc,
 			    struct aead_request *areq)
 {
 	unmap_single_talitos_ptr(dev, &edesc->desc.ptr[6], DMA_FROM_DEVICE);
@@ -772,15 +826,7 @@
 
 	dma_unmap_sg(dev, areq->assoc, 1, DMA_TO_DEVICE);
 
-	if (areq->src != areq->dst) {
-		dma_unmap_sg(dev, areq->src, edesc->src_nents ? : 1,
-			     DMA_TO_DEVICE);
-		dma_unmap_sg(dev, areq->dst, edesc->dst_nents ? : 1,
-			     DMA_FROM_DEVICE);
-	} else {
-		dma_unmap_sg(dev, areq->src, edesc->src_nents ? : 1,
-			     DMA_BIDIRECTIONAL);
-	}
+	talitos_sg_unmap(dev, edesc, areq->src, areq->dst);
 
 	if (edesc->dma_len)
 		dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
@@ -795,13 +841,14 @@
 				   int err)
 {
 	struct aead_request *areq = context;
-	struct ipsec_esp_edesc *edesc =
-		 container_of(desc, struct ipsec_esp_edesc, desc);
 	struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
 	struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+	struct talitos_edesc *edesc;
 	struct scatterlist *sg;
 	void *icvdata;
 
+	edesc = container_of(desc, struct talitos_edesc, desc);
+
 	ipsec_esp_unmap(dev, edesc, areq);
 
 	/* copy the generated ICV to dst */
@@ -819,17 +866,18 @@
 }
 
 static void ipsec_esp_decrypt_swauth_done(struct device *dev,
-				   struct talitos_desc *desc, void *context,
-				   int err)
+					  struct talitos_desc *desc,
+					  void *context, int err)
 {
 	struct aead_request *req = context;
-	struct ipsec_esp_edesc *edesc =
-		 container_of(desc, struct ipsec_esp_edesc, desc);
 	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 	struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+	struct talitos_edesc *edesc;
 	struct scatterlist *sg;
 	void *icvdata;
 
+	edesc = container_of(desc, struct talitos_edesc, desc);
+
 	ipsec_esp_unmap(dev, edesc, req);
 
 	if (!err) {
@@ -851,20 +899,20 @@
 }
 
 static void ipsec_esp_decrypt_hwauth_done(struct device *dev,
-				   struct talitos_desc *desc, void *context,
-				   int err)
+					  struct talitos_desc *desc,
+					  void *context, int err)
 {
 	struct aead_request *req = context;
-	struct ipsec_esp_edesc *edesc =
-		 container_of(desc, struct ipsec_esp_edesc, desc);
+	struct talitos_edesc *edesc;
+
+	edesc = container_of(desc, struct talitos_edesc, desc);
 
 	ipsec_esp_unmap(dev, edesc, req);
 
 	/* check ICV auth status */
-	if (!err)
-		if ((desc->hdr_lo & DESC_HDR_LO_ICCR1_MASK) !=
-		    DESC_HDR_LO_ICCR1_PASS)
-			err = -EBADMSG;
+	if (!err && ((desc->hdr_lo & DESC_HDR_LO_ICCR1_MASK) !=
+		     DESC_HDR_LO_ICCR1_PASS))
+		err = -EBADMSG;
 
 	kfree(edesc);
 
@@ -886,7 +934,7 @@
 		link_tbl_ptr->j_extent = 0;
 		link_tbl_ptr++;
 		cryptlen -= sg_dma_len(sg);
-		sg = sg_next(sg);
+		sg = scatterwalk_sg_next(sg);
 	}
 
 	/* adjust (decrease) last one (or two) entry's len to cryptlen */
@@ -910,7 +958,7 @@
 /*
  * fill in and submit ipsec_esp descriptor
  */
-static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq,
+static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
 		     u8 *giv, u64 seq,
 		     void (*callback) (struct device *dev,
 				       struct talitos_desc *desc,
@@ -952,32 +1000,31 @@
 	desc->ptr[4].len = cpu_to_be16(cryptlen);
 	desc->ptr[4].j_extent = authsize;
 
-	if (areq->src == areq->dst)
-		sg_count = dma_map_sg(dev, areq->src, edesc->src_nents ? : 1,
-				      DMA_BIDIRECTIONAL);
-	else
-		sg_count = dma_map_sg(dev, areq->src, edesc->src_nents ? : 1,
-				      DMA_TO_DEVICE);
+	sg_count = talitos_map_sg(dev, areq->src, edesc->src_nents ? : 1,
+				  (areq->src == areq->dst) ? DMA_BIDIRECTIONAL
+							   : DMA_TO_DEVICE,
+				  edesc->src_is_chained);
 
 	if (sg_count == 1) {
 		desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src));
 	} else {
 		sg_link_tbl_len = cryptlen;
 
-		if ((edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV) &&
-			(edesc->desc.hdr & DESC_HDR_MODE0_ENCRYPT) == 0) {
+		if (edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV)
 			sg_link_tbl_len = cryptlen + authsize;
-		}
+
 		sg_count = sg_to_link_tbl(areq->src, sg_count, sg_link_tbl_len,
 					  &edesc->link_tbl[0]);
 		if (sg_count > 1) {
 			desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP;
 			desc->ptr[4].ptr = cpu_to_be32(edesc->dma_link_tbl);
-			dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl,
-						   edesc->dma_len, DMA_BIDIRECTIONAL);
+			dma_sync_single_for_device(dev, edesc->dma_link_tbl,
+						   edesc->dma_len,
+						   DMA_BIDIRECTIONAL);
 		} else {
 			/* Only one segment now, so no link tbl needed */
-			desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src));
+			desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->
+								      src));
 		}
 	}
 
@@ -985,10 +1032,11 @@
 	desc->ptr[5].len = cpu_to_be16(cryptlen);
 	desc->ptr[5].j_extent = authsize;
 
-	if (areq->src != areq->dst) {
-		sg_count = dma_map_sg(dev, areq->dst, edesc->dst_nents ? : 1,
-				      DMA_FROM_DEVICE);
-	}
+	if (areq->src != areq->dst)
+		sg_count = talitos_map_sg(dev, areq->dst,
+					  edesc->dst_nents ? : 1,
+					  DMA_FROM_DEVICE,
+					  edesc->dst_is_chained);
 
 	if (sg_count == 1) {
 		desc->ptr[5].ptr = cpu_to_be32(sg_dma_address(areq->dst));
@@ -1033,49 +1081,55 @@
 	return ret;
 }
 
-
 /*
  * derive number of elements in scatterlist
  */
-static int sg_count(struct scatterlist *sg_list, int nbytes)
+static int sg_count(struct scatterlist *sg_list, int nbytes, int *chained)
 {
 	struct scatterlist *sg = sg_list;
 	int sg_nents = 0;
 
-	while (nbytes) {
+	*chained = 0;
+	while (nbytes > 0) {
 		sg_nents++;
 		nbytes -= sg->length;
-		sg = sg_next(sg);
+		if (!sg_is_last(sg) && (sg + 1)->length == 0)
+			*chained = 1;
+		sg = scatterwalk_sg_next(sg);
 	}
 
 	return sg_nents;
 }
 
 /*
- * allocate and map the ipsec_esp extended descriptor
+ * allocate and map the extended descriptor
  */
-static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq,
-						     int icv_stashing)
+static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
+						 struct scatterlist *src,
+						 struct scatterlist *dst,
+						 unsigned int cryptlen,
+						 unsigned int authsize,
+						 int icv_stashing,
+						 u32 cryptoflags)
 {
-	struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
-	struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
-	struct ipsec_esp_edesc *edesc;
+	struct talitos_edesc *edesc;
 	int src_nents, dst_nents, alloc_len, dma_len;
-	gfp_t flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
+	int src_chained, dst_chained = 0;
+	gfp_t flags = cryptoflags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
 		      GFP_ATOMIC;
 
-	if (areq->cryptlen + ctx->authsize > TALITOS_MAX_DATA_LEN) {
-		dev_err(ctx->dev, "cryptlen exceeds h/w max limit\n");
+	if (cryptlen + authsize > TALITOS_MAX_DATA_LEN) {
+		dev_err(dev, "length exceeds h/w max limit\n");
 		return ERR_PTR(-EINVAL);
 	}
 
-	src_nents = sg_count(areq->src, areq->cryptlen + ctx->authsize);
+	src_nents = sg_count(src, cryptlen + authsize, &src_chained);
 	src_nents = (src_nents == 1) ? 0 : src_nents;
 
-	if (areq->dst == areq->src) {
+	if (dst == src) {
 		dst_nents = src_nents;
 	} else {
-		dst_nents = sg_count(areq->dst, areq->cryptlen + ctx->authsize);
+		dst_nents = sg_count(dst, cryptlen + authsize, &dst_chained);
 		dst_nents = (dst_nents == 1) ? 0 : dst_nents;
 	}
 
@@ -1084,39 +1138,52 @@
 	 * allowing for two separate entries for ICV and generated ICV (+ 2),
 	 * and the ICV data itself
 	 */
-	alloc_len = sizeof(struct ipsec_esp_edesc);
+	alloc_len = sizeof(struct talitos_edesc);
 	if (src_nents || dst_nents) {
 		dma_len = (src_nents + dst_nents + 2) *
-				 sizeof(struct talitos_ptr) + ctx->authsize;
+				 sizeof(struct talitos_ptr) + authsize;
 		alloc_len += dma_len;
 	} else {
 		dma_len = 0;
-		alloc_len += icv_stashing ? ctx->authsize : 0;
+		alloc_len += icv_stashing ? authsize : 0;
 	}
 
 	edesc = kmalloc(alloc_len, GFP_DMA | flags);
 	if (!edesc) {
-		dev_err(ctx->dev, "could not allocate edescriptor\n");
+		dev_err(dev, "could not allocate edescriptor\n");
 		return ERR_PTR(-ENOMEM);
 	}
 
 	edesc->src_nents = src_nents;
 	edesc->dst_nents = dst_nents;
+	edesc->src_is_chained = src_chained;
+	edesc->dst_is_chained = dst_chained;
 	edesc->dma_len = dma_len;
-	edesc->dma_link_tbl = dma_map_single(ctx->dev, &edesc->link_tbl[0],
+	edesc->dma_link_tbl = dma_map_single(dev, &edesc->link_tbl[0],
 					     edesc->dma_len, DMA_BIDIRECTIONAL);
 
 	return edesc;
 }
 
-static int aead_authenc_encrypt(struct aead_request *req)
+static struct talitos_edesc *aead_edesc_alloc(struct aead_request *areq,
+					      int icv_stashing)
+{
+	struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
+	struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+
+	return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst,
+				   areq->cryptlen, ctx->authsize, icv_stashing,
+				   areq->base.flags);
+}
+
+static int aead_encrypt(struct aead_request *req)
 {
 	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 	struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
-	struct ipsec_esp_edesc *edesc;
+	struct talitos_edesc *edesc;
 
 	/* allocate extended descriptor */
-	edesc = ipsec_esp_edesc_alloc(req, 0);
+	edesc = aead_edesc_alloc(req, 0);
 	if (IS_ERR(edesc))
 		return PTR_ERR(edesc);
 
@@ -1126,70 +1193,67 @@
 	return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_encrypt_done);
 }
 
-
-
-static int aead_authenc_decrypt(struct aead_request *req)
+static int aead_decrypt(struct aead_request *req)
 {
 	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 	struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
 	unsigned int authsize = ctx->authsize;
 	struct talitos_private *priv = dev_get_drvdata(ctx->dev);
-	struct ipsec_esp_edesc *edesc;
+	struct talitos_edesc *edesc;
 	struct scatterlist *sg;
 	void *icvdata;
 
 	req->cryptlen -= authsize;
 
 	/* allocate extended descriptor */
-	edesc = ipsec_esp_edesc_alloc(req, 1);
+	edesc = aead_edesc_alloc(req, 1);
 	if (IS_ERR(edesc))
 		return PTR_ERR(edesc);
 
 	if ((priv->features & TALITOS_FTR_HW_AUTH_CHECK) &&
-	    (((!edesc->src_nents && !edesc->dst_nents) ||
-		priv->features & TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT))) {
+	    ((!edesc->src_nents && !edesc->dst_nents) ||
+	     priv->features & TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT)) {
 
 		/* decrypt and check the ICV */
-		edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND |
+		edesc->desc.hdr = ctx->desc_hdr_template |
+				  DESC_HDR_DIR_INBOUND |
 				  DESC_HDR_MODE1_MDEU_CICV;
 
 		/* reset integrity check result bits */
 		edesc->desc.hdr_lo = 0;
 
-		return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_hwauth_done);
+		return ipsec_esp(edesc, req, NULL, 0,
+				 ipsec_esp_decrypt_hwauth_done);
 
-	} else {
-
-		/* Have to check the ICV with software */
-
-		edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND;
-
-		/* stash incoming ICV for later cmp with ICV generated by the h/w */
-		if (edesc->dma_len)
-			icvdata = &edesc->link_tbl[edesc->src_nents +
-						   edesc->dst_nents + 2];
-		else
-			icvdata = &edesc->link_tbl[0];
-
-		sg = sg_last(req->src, edesc->src_nents ? : 1);
-
-		memcpy(icvdata, (char *)sg_virt(sg) + sg->length - ctx->authsize,
-		       ctx->authsize);
-
-		return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_swauth_done);
 	}
+
+	/* Have to check the ICV with software */
+	edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND;
+
+	/* stash incoming ICV for later cmp with ICV generated by the h/w */
+	if (edesc->dma_len)
+		icvdata = &edesc->link_tbl[edesc->src_nents +
+					   edesc->dst_nents + 2];
+	else
+		icvdata = &edesc->link_tbl[0];
+
+	sg = sg_last(req->src, edesc->src_nents ? : 1);
+
+	memcpy(icvdata, (char *)sg_virt(sg) + sg->length - ctx->authsize,
+	       ctx->authsize);
+
+	return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_swauth_done);
 }
 
-static int aead_authenc_givencrypt(
-	struct aead_givcrypt_request *req)
+static int aead_givencrypt(struct aead_givcrypt_request *req)
 {
 	struct aead_request *areq = &req->areq;
 	struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
 	struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
-	struct ipsec_esp_edesc *edesc;
+	struct talitos_edesc *edesc;
 
 	/* allocate extended descriptor */
-	edesc = ipsec_esp_edesc_alloc(areq, 0);
+	edesc = aead_edesc_alloc(areq, 0);
 	if (IS_ERR(edesc))
 		return PTR_ERR(edesc);
 
@@ -1204,31 +1268,228 @@
 			 ipsec_esp_encrypt_done);
 }
 
+static int ablkcipher_setkey(struct crypto_ablkcipher *cipher,
+			     const u8 *key, unsigned int keylen)
+{
+	struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+	struct ablkcipher_alg *alg = crypto_ablkcipher_alg(cipher);
+
+	if (keylen > TALITOS_MAX_KEY_SIZE)
+		goto badkey;
+
+	if (keylen < alg->min_keysize || keylen > alg->max_keysize)
+		goto badkey;
+
+	memcpy(&ctx->key, key, keylen);
+	ctx->keylen = keylen;
+
+	return 0;
+
+badkey:
+	crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+	return -EINVAL;
+}
+
+static void common_nonsnoop_unmap(struct device *dev,
+				  struct talitos_edesc *edesc,
+				  struct ablkcipher_request *areq)
+{
+	unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE);
+	unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2], DMA_TO_DEVICE);
+	unmap_single_talitos_ptr(dev, &edesc->desc.ptr[1], DMA_TO_DEVICE);
+
+	talitos_sg_unmap(dev, edesc, areq->src, areq->dst);
+
+	if (edesc->dma_len)
+		dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
+				 DMA_BIDIRECTIONAL);
+}
+
+static void ablkcipher_done(struct device *dev,
+			    struct talitos_desc *desc, void *context,
+			    int err)
+{
+	struct ablkcipher_request *areq = context;
+	struct talitos_edesc *edesc;
+
+	edesc = container_of(desc, struct talitos_edesc, desc);
+
+	common_nonsnoop_unmap(dev, edesc, areq);
+
+	kfree(edesc);
+
+	areq->base.complete(&areq->base, err);
+}
+
+static int common_nonsnoop(struct talitos_edesc *edesc,
+			   struct ablkcipher_request *areq,
+			   u8 *giv,
+			   void (*callback) (struct device *dev,
+					     struct talitos_desc *desc,
+					     void *context, int error))
+{
+	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+	struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+	struct device *dev = ctx->dev;
+	struct talitos_desc *desc = &edesc->desc;
+	unsigned int cryptlen = areq->nbytes;
+	unsigned int ivsize;
+	int sg_count, ret;
+
+	/* first DWORD empty */
+	desc->ptr[0].len = 0;
+	desc->ptr[0].ptr = 0;
+	desc->ptr[0].j_extent = 0;
+
+	/* cipher iv */
+	ivsize = crypto_ablkcipher_ivsize(cipher);
+	map_single_talitos_ptr(dev, &desc->ptr[1], ivsize, giv ?: areq->info, 0,
+			       DMA_TO_DEVICE);
+
+	/* cipher key */
+	map_single_talitos_ptr(dev, &desc->ptr[2], ctx->keylen,
+			       (char *)&ctx->key, 0, DMA_TO_DEVICE);
+
+	/*
+	 * cipher in
+	 */
+	desc->ptr[3].len = cpu_to_be16(cryptlen);
+	desc->ptr[3].j_extent = 0;
+
+	sg_count = talitos_map_sg(dev, areq->src, edesc->src_nents ? : 1,
+				  (areq->src == areq->dst) ? DMA_BIDIRECTIONAL
+							   : DMA_TO_DEVICE,
+				  edesc->src_is_chained);
+
+	if (sg_count == 1) {
+		desc->ptr[3].ptr = cpu_to_be32(sg_dma_address(areq->src));
+	} else {
+		sg_count = sg_to_link_tbl(areq->src, sg_count, cryptlen,
+					  &edesc->link_tbl[0]);
+		if (sg_count > 1) {
+			desc->ptr[3].j_extent |= DESC_PTR_LNKTBL_JUMP;
+			desc->ptr[3].ptr = cpu_to_be32(edesc->dma_link_tbl);
+			dma_sync_single_for_device(dev, edesc->dma_link_tbl,
+						   edesc->dma_len,
+						   DMA_BIDIRECTIONAL);
+		} else {
+			/* Only one segment now, so no link tbl needed */
+			desc->ptr[3].ptr = cpu_to_be32(sg_dma_address(areq->
+								      src));
+		}
+	}
+
+	/* cipher out */
+	desc->ptr[4].len = cpu_to_be16(cryptlen);
+	desc->ptr[4].j_extent = 0;
+
+	if (areq->src != areq->dst)
+		sg_count = talitos_map_sg(dev, areq->dst,
+					  edesc->dst_nents ? : 1,
+					  DMA_FROM_DEVICE,
+					  edesc->dst_is_chained);
+
+	if (sg_count == 1) {
+		desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->dst));
+	} else {
+		struct talitos_ptr *link_tbl_ptr =
+			&edesc->link_tbl[edesc->src_nents + 1];
+
+		desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP;
+		desc->ptr[4].ptr = cpu_to_be32((struct talitos_ptr *)
+					       edesc->dma_link_tbl +
+					       edesc->src_nents + 1);
+		sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen,
+					  link_tbl_ptr);
+		dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl,
+					   edesc->dma_len, DMA_BIDIRECTIONAL);
+	}
+
+	/* iv out */
+	map_single_talitos_ptr(dev, &desc->ptr[5], ivsize, ctx->iv, 0,
+			       DMA_FROM_DEVICE);
+
+	/* last DWORD empty */
+	desc->ptr[6].len = 0;
+	desc->ptr[6].ptr = 0;
+	desc->ptr[6].j_extent = 0;
+
+	ret = talitos_submit(dev, desc, callback, areq);
+	if (ret != -EINPROGRESS) {
+		common_nonsnoop_unmap(dev, edesc, areq);
+		kfree(edesc);
+	}
+	return ret;
+}
+
+static struct talitos_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request *
+						    areq)
+{
+	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+	struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+
+	return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst, areq->nbytes,
+				   0, 0, areq->base.flags);
+}
+
+static int ablkcipher_encrypt(struct ablkcipher_request *areq)
+{
+	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+	struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+	struct talitos_edesc *edesc;
+
+	/* allocate extended descriptor */
+	edesc = ablkcipher_edesc_alloc(areq);
+	if (IS_ERR(edesc))
+		return PTR_ERR(edesc);
+
+	/* set encrypt */
+	edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_MODE0_ENCRYPT;
+
+	return common_nonsnoop(edesc, areq, NULL, ablkcipher_done);
+}
+
+static int ablkcipher_decrypt(struct ablkcipher_request *areq)
+{
+	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+	struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+	struct talitos_edesc *edesc;
+
+	/* allocate extended descriptor */
+	edesc = ablkcipher_edesc_alloc(areq);
+	if (IS_ERR(edesc))
+		return PTR_ERR(edesc);
+
+	edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND;
+
+	return common_nonsnoop(edesc, areq, NULL, ablkcipher_done);
+}
+
 struct talitos_alg_template {
-	char name[CRYPTO_MAX_ALG_NAME];
-	char driver_name[CRYPTO_MAX_ALG_NAME];
-	unsigned int blocksize;
-	struct aead_alg aead;
-	struct device *dev;
+	struct crypto_alg alg;
 	__be32 desc_hdr_template;
 };
 
 static struct talitos_alg_template driver_algs[] = {
-	/* single-pass ipsec_esp descriptor */
+	/* AEAD algorithms.  These use a single-pass ipsec_esp descriptor */
 	{
-		.name = "authenc(hmac(sha1),cbc(aes))",
-		.driver_name = "authenc-hmac-sha1-cbc-aes-talitos",
-		.blocksize = AES_BLOCK_SIZE,
-		.aead = {
-			.setkey = aead_authenc_setkey,
-			.setauthsize = aead_authenc_setauthsize,
-			.encrypt = aead_authenc_encrypt,
-			.decrypt = aead_authenc_decrypt,
-			.givencrypt = aead_authenc_givencrypt,
-			.geniv = "<built-in>",
-			.ivsize = AES_BLOCK_SIZE,
-			.maxauthsize = SHA1_DIGEST_SIZE,
-			},
+		.alg = {
+			.cra_name = "authenc(hmac(sha1),cbc(aes))",
+			.cra_driver_name = "authenc-hmac-sha1-cbc-aes-talitos",
+			.cra_blocksize = AES_BLOCK_SIZE,
+			.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+			.cra_type = &crypto_aead_type,
+			.cra_aead = {
+				.setkey = aead_setkey,
+				.setauthsize = aead_setauthsize,
+				.encrypt = aead_encrypt,
+				.decrypt = aead_decrypt,
+				.givencrypt = aead_givencrypt,
+				.geniv = "<built-in>",
+				.ivsize = AES_BLOCK_SIZE,
+				.maxauthsize = SHA1_DIGEST_SIZE,
+			}
+		},
 		.desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
 			             DESC_HDR_SEL0_AESU |
 		                     DESC_HDR_MODE0_AESU_CBC |
@@ -1238,19 +1499,23 @@
 		                     DESC_HDR_MODE1_MDEU_SHA1_HMAC,
 	},
 	{
-		.name = "authenc(hmac(sha1),cbc(des3_ede))",
-		.driver_name = "authenc-hmac-sha1-cbc-3des-talitos",
-		.blocksize = DES3_EDE_BLOCK_SIZE,
-		.aead = {
-			.setkey = aead_authenc_setkey,
-			.setauthsize = aead_authenc_setauthsize,
-			.encrypt = aead_authenc_encrypt,
-			.decrypt = aead_authenc_decrypt,
-			.givencrypt = aead_authenc_givencrypt,
-			.geniv = "<built-in>",
-			.ivsize = DES3_EDE_BLOCK_SIZE,
-			.maxauthsize = SHA1_DIGEST_SIZE,
-			},
+		.alg = {
+			.cra_name = "authenc(hmac(sha1),cbc(des3_ede))",
+			.cra_driver_name = "authenc-hmac-sha1-cbc-3des-talitos",
+			.cra_blocksize = DES3_EDE_BLOCK_SIZE,
+			.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+			.cra_type = &crypto_aead_type,
+			.cra_aead = {
+				.setkey = aead_setkey,
+				.setauthsize = aead_setauthsize,
+				.encrypt = aead_encrypt,
+				.decrypt = aead_decrypt,
+				.givencrypt = aead_givencrypt,
+				.geniv = "<built-in>",
+				.ivsize = DES3_EDE_BLOCK_SIZE,
+				.maxauthsize = SHA1_DIGEST_SIZE,
+			}
+		},
 		.desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
 			             DESC_HDR_SEL0_DEU |
 		                     DESC_HDR_MODE0_DEU_CBC |
@@ -1261,19 +1526,23 @@
 		                     DESC_HDR_MODE1_MDEU_SHA1_HMAC,
 	},
 	{
-		.name = "authenc(hmac(sha256),cbc(aes))",
-		.driver_name = "authenc-hmac-sha256-cbc-aes-talitos",
-		.blocksize = AES_BLOCK_SIZE,
-		.aead = {
-			.setkey = aead_authenc_setkey,
-			.setauthsize = aead_authenc_setauthsize,
-			.encrypt = aead_authenc_encrypt,
-			.decrypt = aead_authenc_decrypt,
-			.givencrypt = aead_authenc_givencrypt,
-			.geniv = "<built-in>",
-			.ivsize = AES_BLOCK_SIZE,
-			.maxauthsize = SHA256_DIGEST_SIZE,
-			},
+		.alg = {
+			.cra_name = "authenc(hmac(sha256),cbc(aes))",
+			.cra_driver_name = "authenc-hmac-sha256-cbc-aes-talitos",
+			.cra_blocksize = AES_BLOCK_SIZE,
+			.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+			.cra_type = &crypto_aead_type,
+			.cra_aead = {
+				.setkey = aead_setkey,
+				.setauthsize = aead_setauthsize,
+				.encrypt = aead_encrypt,
+				.decrypt = aead_decrypt,
+				.givencrypt = aead_givencrypt,
+				.geniv = "<built-in>",
+				.ivsize = AES_BLOCK_SIZE,
+				.maxauthsize = SHA256_DIGEST_SIZE,
+			}
+		},
 		.desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
 			             DESC_HDR_SEL0_AESU |
 		                     DESC_HDR_MODE0_AESU_CBC |
@@ -1283,19 +1552,23 @@
 		                     DESC_HDR_MODE1_MDEU_SHA256_HMAC,
 	},
 	{
-		.name = "authenc(hmac(sha256),cbc(des3_ede))",
-		.driver_name = "authenc-hmac-sha256-cbc-3des-talitos",
-		.blocksize = DES3_EDE_BLOCK_SIZE,
-		.aead = {
-			.setkey = aead_authenc_setkey,
-			.setauthsize = aead_authenc_setauthsize,
-			.encrypt = aead_authenc_encrypt,
-			.decrypt = aead_authenc_decrypt,
-			.givencrypt = aead_authenc_givencrypt,
-			.geniv = "<built-in>",
-			.ivsize = DES3_EDE_BLOCK_SIZE,
-			.maxauthsize = SHA256_DIGEST_SIZE,
-			},
+		.alg = {
+			.cra_name = "authenc(hmac(sha256),cbc(des3_ede))",
+			.cra_driver_name = "authenc-hmac-sha256-cbc-3des-talitos",
+			.cra_blocksize = DES3_EDE_BLOCK_SIZE,
+			.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+			.cra_type = &crypto_aead_type,
+			.cra_aead = {
+				.setkey = aead_setkey,
+				.setauthsize = aead_setauthsize,
+				.encrypt = aead_encrypt,
+				.decrypt = aead_decrypt,
+				.givencrypt = aead_givencrypt,
+				.geniv = "<built-in>",
+				.ivsize = DES3_EDE_BLOCK_SIZE,
+				.maxauthsize = SHA256_DIGEST_SIZE,
+			}
+		},
 		.desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
 			             DESC_HDR_SEL0_DEU |
 		                     DESC_HDR_MODE0_DEU_CBC |
@@ -1306,19 +1579,23 @@
 		                     DESC_HDR_MODE1_MDEU_SHA256_HMAC,
 	},
 	{
-		.name = "authenc(hmac(md5),cbc(aes))",
-		.driver_name = "authenc-hmac-md5-cbc-aes-talitos",
-		.blocksize = AES_BLOCK_SIZE,
-		.aead = {
-			.setkey = aead_authenc_setkey,
-			.setauthsize = aead_authenc_setauthsize,
-			.encrypt = aead_authenc_encrypt,
-			.decrypt = aead_authenc_decrypt,
-			.givencrypt = aead_authenc_givencrypt,
-			.geniv = "<built-in>",
-			.ivsize = AES_BLOCK_SIZE,
-			.maxauthsize = MD5_DIGEST_SIZE,
-			},
+		.alg = {
+			.cra_name = "authenc(hmac(md5),cbc(aes))",
+			.cra_driver_name = "authenc-hmac-md5-cbc-aes-talitos",
+			.cra_blocksize = AES_BLOCK_SIZE,
+			.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+			.cra_type = &crypto_aead_type,
+			.cra_aead = {
+				.setkey = aead_setkey,
+				.setauthsize = aead_setauthsize,
+				.encrypt = aead_encrypt,
+				.decrypt = aead_decrypt,
+				.givencrypt = aead_givencrypt,
+				.geniv = "<built-in>",
+				.ivsize = AES_BLOCK_SIZE,
+				.maxauthsize = MD5_DIGEST_SIZE,
+			}
+		},
 		.desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
 			             DESC_HDR_SEL0_AESU |
 		                     DESC_HDR_MODE0_AESU_CBC |
@@ -1328,19 +1605,23 @@
 		                     DESC_HDR_MODE1_MDEU_MD5_HMAC,
 	},
 	{
-		.name = "authenc(hmac(md5),cbc(des3_ede))",
-		.driver_name = "authenc-hmac-md5-cbc-3des-talitos",
-		.blocksize = DES3_EDE_BLOCK_SIZE,
-		.aead = {
-			.setkey = aead_authenc_setkey,
-			.setauthsize = aead_authenc_setauthsize,
-			.encrypt = aead_authenc_encrypt,
-			.decrypt = aead_authenc_decrypt,
-			.givencrypt = aead_authenc_givencrypt,
-			.geniv = "<built-in>",
-			.ivsize = DES3_EDE_BLOCK_SIZE,
-			.maxauthsize = MD5_DIGEST_SIZE,
-			},
+		.alg = {
+			.cra_name = "authenc(hmac(md5),cbc(des3_ede))",
+			.cra_driver_name = "authenc-hmac-md5-cbc-3des-talitos",
+			.cra_blocksize = DES3_EDE_BLOCK_SIZE,
+			.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+			.cra_type = &crypto_aead_type,
+			.cra_aead = {
+				.setkey = aead_setkey,
+				.setauthsize = aead_setauthsize,
+				.encrypt = aead_encrypt,
+				.decrypt = aead_decrypt,
+				.givencrypt = aead_givencrypt,
+				.geniv = "<built-in>",
+				.ivsize = DES3_EDE_BLOCK_SIZE,
+				.maxauthsize = MD5_DIGEST_SIZE,
+			}
+		},
 		.desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
 			             DESC_HDR_SEL0_DEU |
 		                     DESC_HDR_MODE0_DEU_CBC |
@@ -1349,6 +1630,52 @@
 		                     DESC_HDR_MODE1_MDEU_INIT |
 		                     DESC_HDR_MODE1_MDEU_PAD |
 		                     DESC_HDR_MODE1_MDEU_MD5_HMAC,
+	},
+	/* ABLKCIPHER algorithms. */
+	{
+		.alg = {
+			.cra_name = "cbc(aes)",
+			.cra_driver_name = "cbc-aes-talitos",
+			.cra_blocksize = AES_BLOCK_SIZE,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                                     CRYPTO_ALG_ASYNC,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_ablkcipher = {
+				.setkey = ablkcipher_setkey,
+				.encrypt = ablkcipher_encrypt,
+				.decrypt = ablkcipher_decrypt,
+				.geniv = "eseqiv",
+				.min_keysize = AES_MIN_KEY_SIZE,
+				.max_keysize = AES_MAX_KEY_SIZE,
+				.ivsize = AES_BLOCK_SIZE,
+			}
+		},
+		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+				     DESC_HDR_SEL0_AESU |
+				     DESC_HDR_MODE0_AESU_CBC,
+	},
+	{
+		.alg = {
+			.cra_name = "cbc(des3_ede)",
+			.cra_driver_name = "cbc-3des-talitos",
+			.cra_blocksize = DES3_EDE_BLOCK_SIZE,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                                     CRYPTO_ALG_ASYNC,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_ablkcipher = {
+				.setkey = ablkcipher_setkey,
+				.encrypt = ablkcipher_encrypt,
+				.decrypt = ablkcipher_decrypt,
+				.geniv = "eseqiv",
+				.min_keysize = DES3_EDE_KEY_SIZE,
+				.max_keysize = DES3_EDE_KEY_SIZE,
+				.ivsize = DES3_EDE_BLOCK_SIZE,
+			}
+		},
+		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+			             DESC_HDR_SEL0_DEU |
+		                     DESC_HDR_MODE0_DEU_CBC |
+		                     DESC_HDR_MODE0_DEU_3DES,
 	}
 };
 
@@ -1362,12 +1689,14 @@
 static int talitos_cra_init(struct crypto_tfm *tfm)
 {
 	struct crypto_alg *alg = tfm->__crt_alg;
-	struct talitos_crypto_alg *talitos_alg =
-		 container_of(alg, struct talitos_crypto_alg, crypto_alg);
+	struct talitos_crypto_alg *talitos_alg;
 	struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
 
+	talitos_alg =  container_of(alg, struct talitos_crypto_alg, crypto_alg);
+
 	/* update context with ptr to dev */
 	ctx->dev = talitos_alg->dev;
+
 	/* copy descriptor header template value */
 	ctx->desc_hdr_template = talitos_alg->desc_hdr_template;
 
@@ -1453,19 +1782,13 @@
 		return ERR_PTR(-ENOMEM);
 
 	alg = &t_alg->crypto_alg;
+	*alg = template->alg;
 
-	snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name);
-	snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
-		 template->driver_name);
 	alg->cra_module = THIS_MODULE;
 	alg->cra_init = talitos_cra_init;
 	alg->cra_priority = TALITOS_CRA_PRIORITY;
-	alg->cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC;
-	alg->cra_blocksize = template->blocksize;
 	alg->cra_alignmask = 0;
-	alg->cra_type = &crypto_aead_type;
 	alg->cra_ctxsize = sizeof(struct talitos_ctx);
-	alg->cra_u.aead = template->aead;
 
 	t_alg->desc_hdr_template = template->desc_hdr_template;
 	t_alg->dev = dev;
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index edb0253..11f3739 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -69,7 +69,7 @@
 
 config GPIO_XILINX
 	bool "Xilinx GPIO support"
-	depends on PPC_OF
+	depends on PPC_OF || MICROBLAZE
 	help
 	  Say yes here to support the Xilinx FPGA GPIO device
 
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
index 0411d91..80a2575 100644
--- a/drivers/gpu/drm/drm_bufs.c
+++ b/drivers/gpu/drm/drm_bufs.c
@@ -371,7 +371,8 @@
 	list->user_token = list->hash.key << PAGE_SHIFT;
 	mutex_unlock(&dev->struct_mutex);
 
-	list->master = dev->primary->master;
+	if (!(map->flags & _DRM_DRIVER))
+		list->master = dev->primary->master;
 	*maplist = list;
 	return 0;
 	}
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 6f6b264..801a0d0 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -589,85 +589,13 @@
 }
 EXPORT_SYMBOL(drm_do_probe_ddc_edid);
 
-/**
- * Get EDID information.
- *
- * \param adapter : i2c device adaptor.
- * \param buf     : EDID data buffer to be filled
- * \param len     : EDID data buffer length
- * \return 0 on success or -1 on failure.
- *
- * Initialize DDC, then fetch EDID information
- * by calling drm_do_probe_ddc_edid function.
- */
-static int drm_ddc_read(struct i2c_adapter *adapter,
-			unsigned char *buf, int len)
-{
-	struct i2c_algo_bit_data *algo_data = adapter->algo_data;
-	int i, j;
-	int ret = -1;
-
-	algo_data->setscl(algo_data->data, 1);
-
-	for (i = 0; i < 1; i++) {
-		/* For some old monitors we need the
-		 * following process to initialize/stop DDC
-		 */
-		algo_data->setsda(algo_data->data, 1);
-		msleep(13);
-
-		algo_data->setscl(algo_data->data, 1);
-		for (j = 0; j < 5; j++) {
-			msleep(10);
-			if (algo_data->getscl(algo_data->data))
-				break;
-		}
-		if (j == 5)
-			continue;
-
-		algo_data->setsda(algo_data->data, 0);
-		msleep(15);
-		algo_data->setscl(algo_data->data, 0);
-		msleep(15);
-		algo_data->setsda(algo_data->data, 1);
-		msleep(15);
-
-		/* Do the real work */
-		ret = drm_do_probe_ddc_edid(adapter, buf, len);
-		algo_data->setsda(algo_data->data, 0);
-		algo_data->setscl(algo_data->data, 0);
-		msleep(15);
-
-		algo_data->setscl(algo_data->data, 1);
-		for (j = 0; j < 10; j++) {
-			msleep(10);
-			if (algo_data->getscl(algo_data->data))
-				break;
-		}
-
-		algo_data->setsda(algo_data->data, 1);
-		msleep(15);
-		algo_data->setscl(algo_data->data, 0);
-		algo_data->setsda(algo_data->data, 0);
-		if (ret == 0)
-			break;
-	}
-	/* Release the DDC lines when done or the Apple Cinema HD display
-	 * will switch off
-	 */
-	algo_data->setsda(algo_data->data, 1);
-	algo_data->setscl(algo_data->data, 1);
-
-	return ret;
-}
-
 static int drm_ddc_read_edid(struct drm_connector *connector,
 			     struct i2c_adapter *adapter,
 			     char *buf, int len)
 {
 	int ret;
 
-	ret = drm_ddc_read(adapter, buf, len);
+	ret = drm_do_probe_ddc_edid(adapter, buf, len);
 	if (ret != 0) {
 		dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n",
 			 drm_get_connector_name(connector));
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 4984aa8..ec43005 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -133,7 +133,7 @@
 
 	BUG_ON((size & (PAGE_SIZE - 1)) != 0);
 
-	obj = kcalloc(1, sizeof(*obj), GFP_KERNEL);
+	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
 
 	obj->dev = dev;
 	obj->filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
diff --git a/drivers/gpu/drm/drm_hashtab.c b/drivers/gpu/drm/drm_hashtab.c
index af539f7..ac35145 100644
--- a/drivers/gpu/drm/drm_hashtab.c
+++ b/drivers/gpu/drm/drm_hashtab.c
@@ -62,6 +62,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL(drm_ht_create);
 
 void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key)
 {
@@ -156,6 +157,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL(drm_ht_just_insert_please);
 
 int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key,
 		     struct drm_hash_item **item)
@@ -169,6 +171,7 @@
 	*item = hlist_entry(list, struct drm_hash_item, head);
 	return 0;
 }
+EXPORT_SYMBOL(drm_ht_find_item);
 
 int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key)
 {
@@ -202,3 +205,4 @@
 		ht->table = NULL;
 	}
 }
+EXPORT_SYMBOL(drm_ht_remove);
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index 367c590..7819fd9 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -42,8 +42,11 @@
  */
 
 #include "drmP.h"
+#include "drm_mm.h"
 #include <linux/slab.h>
 
+#define MM_UNUSED_TARGET 4
+
 unsigned long drm_mm_tail_space(struct drm_mm *mm)
 {
 	struct list_head *tail_node;
@@ -74,16 +77,62 @@
 	return 0;
 }
 
-
-static int drm_mm_create_tail_node(struct drm_mm *mm,
-			    unsigned long start,
-			    unsigned long size)
+static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic)
 {
 	struct drm_mm_node *child;
 
-	child = (struct drm_mm_node *)
-		drm_alloc(sizeof(*child), DRM_MEM_MM);
-	if (!child)
+	if (atomic)
+		child = kmalloc(sizeof(*child), GFP_ATOMIC);
+	else
+		child = kmalloc(sizeof(*child), GFP_KERNEL);
+
+	if (unlikely(child == NULL)) {
+		spin_lock(&mm->unused_lock);
+		if (list_empty(&mm->unused_nodes))
+			child = NULL;
+		else {
+			child =
+			    list_entry(mm->unused_nodes.next,
+				       struct drm_mm_node, fl_entry);
+			list_del(&child->fl_entry);
+			--mm->num_unused;
+		}
+		spin_unlock(&mm->unused_lock);
+	}
+	return child;
+}
+
+int drm_mm_pre_get(struct drm_mm *mm)
+{
+	struct drm_mm_node *node;
+
+	spin_lock(&mm->unused_lock);
+	while (mm->num_unused < MM_UNUSED_TARGET) {
+		spin_unlock(&mm->unused_lock);
+		node = kmalloc(sizeof(*node), GFP_KERNEL);
+		spin_lock(&mm->unused_lock);
+
+		if (unlikely(node == NULL)) {
+			int ret = (mm->num_unused < 2) ? -ENOMEM : 0;
+			spin_unlock(&mm->unused_lock);
+			return ret;
+		}
+		++mm->num_unused;
+		list_add_tail(&node->fl_entry, &mm->unused_nodes);
+	}
+	spin_unlock(&mm->unused_lock);
+	return 0;
+}
+EXPORT_SYMBOL(drm_mm_pre_get);
+
+static int drm_mm_create_tail_node(struct drm_mm *mm,
+				   unsigned long start,
+				   unsigned long size, int atomic)
+{
+	struct drm_mm_node *child;
+
+	child = drm_mm_kmalloc(mm, atomic);
+	if (unlikely(child == NULL))
 		return -ENOMEM;
 
 	child->free = 1;
@@ -97,8 +146,7 @@
 	return 0;
 }
 
-
-int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size)
+int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size, int atomic)
 {
 	struct list_head *tail_node;
 	struct drm_mm_node *entry;
@@ -106,20 +154,21 @@
 	tail_node = mm->ml_entry.prev;
 	entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
 	if (!entry->free) {
-		return drm_mm_create_tail_node(mm, entry->start + entry->size, size);
+		return drm_mm_create_tail_node(mm, entry->start + entry->size,
+					       size, atomic);
 	}
 	entry->size += size;
 	return 0;
 }
 
 static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
-					    unsigned long size)
+						 unsigned long size,
+						 int atomic)
 {
 	struct drm_mm_node *child;
 
-	child = (struct drm_mm_node *)
-		drm_alloc(sizeof(*child), DRM_MEM_MM);
-	if (!child)
+	child = drm_mm_kmalloc(parent->mm, atomic);
+	if (unlikely(child == NULL))
 		return NULL;
 
 	INIT_LIST_HEAD(&child->fl_entry);
@@ -151,8 +200,9 @@
 		tmp = parent->start % alignment;
 
 	if (tmp) {
-		align_splitoff = drm_mm_split_at_start(parent, alignment - tmp);
-		if (!align_splitoff)
+		align_splitoff =
+		    drm_mm_split_at_start(parent, alignment - tmp, 0);
+		if (unlikely(align_splitoff == NULL))
 			return NULL;
 	}
 
@@ -161,7 +211,7 @@
 		parent->free = 0;
 		return parent;
 	} else {
-		child = drm_mm_split_at_start(parent, size);
+		child = drm_mm_split_at_start(parent, size, 0);
 	}
 
 	if (align_splitoff)
@@ -169,14 +219,49 @@
 
 	return child;
 }
+
 EXPORT_SYMBOL(drm_mm_get_block);
 
+struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent,
+					    unsigned long size,
+					    unsigned alignment)
+{
+
+	struct drm_mm_node *align_splitoff = NULL;
+	struct drm_mm_node *child;
+	unsigned tmp = 0;
+
+	if (alignment)
+		tmp = parent->start % alignment;
+
+	if (tmp) {
+		align_splitoff =
+		    drm_mm_split_at_start(parent, alignment - tmp, 1);
+		if (unlikely(align_splitoff == NULL))
+			return NULL;
+	}
+
+	if (parent->size == size) {
+		list_del_init(&parent->fl_entry);
+		parent->free = 0;
+		return parent;
+	} else {
+		child = drm_mm_split_at_start(parent, size, 1);
+	}
+
+	if (align_splitoff)
+		drm_mm_put_block(align_splitoff);
+
+	return child;
+}
+EXPORT_SYMBOL(drm_mm_get_block_atomic);
+
 /*
  * Put a block. Merge with the previous and / or next block if they are free.
  * Otherwise add to the free stack.
  */
 
-void drm_mm_put_block(struct drm_mm_node * cur)
+void drm_mm_put_block(struct drm_mm_node *cur)
 {
 
 	struct drm_mm *mm = cur->mm;
@@ -188,21 +273,27 @@
 	int merged = 0;
 
 	if (cur_head->prev != root_head) {
-		prev_node = list_entry(cur_head->prev, struct drm_mm_node, ml_entry);
+		prev_node =
+		    list_entry(cur_head->prev, struct drm_mm_node, ml_entry);
 		if (prev_node->free) {
 			prev_node->size += cur->size;
 			merged = 1;
 		}
 	}
 	if (cur_head->next != root_head) {
-		next_node = list_entry(cur_head->next, struct drm_mm_node, ml_entry);
+		next_node =
+		    list_entry(cur_head->next, struct drm_mm_node, ml_entry);
 		if (next_node->free) {
 			if (merged) {
 				prev_node->size += next_node->size;
 				list_del(&next_node->ml_entry);
 				list_del(&next_node->fl_entry);
-				drm_free(next_node, sizeof(*next_node),
-					 DRM_MEM_MM);
+				if (mm->num_unused < MM_UNUSED_TARGET) {
+					list_add(&next_node->fl_entry,
+						 &mm->unused_nodes);
+					++mm->num_unused;
+				} else
+					kfree(next_node);
 			} else {
 				next_node->size += cur->size;
 				next_node->start = cur->start;
@@ -215,14 +306,19 @@
 		list_add(&cur->fl_entry, &mm->fl_entry);
 	} else {
 		list_del(&cur->ml_entry);
-		drm_free(cur, sizeof(*cur), DRM_MEM_MM);
+		if (mm->num_unused < MM_UNUSED_TARGET) {
+			list_add(&cur->fl_entry, &mm->unused_nodes);
+			++mm->num_unused;
+		} else
+			kfree(cur);
 	}
 }
+
 EXPORT_SYMBOL(drm_mm_put_block);
 
-struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
-				  unsigned long size,
-				  unsigned alignment, int best_match)
+struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
+				       unsigned long size,
+				       unsigned alignment, int best_match)
 {
 	struct list_head *list;
 	const struct list_head *free_stack = &mm->fl_entry;
@@ -247,7 +343,6 @@
 				wasted += alignment - tmp;
 		}
 
-
 		if (entry->size >= size + wasted) {
 			if (!best_match)
 				return entry;
@@ -260,6 +355,7 @@
 
 	return best;
 }
+EXPORT_SYMBOL(drm_mm_search_free);
 
 int drm_mm_clean(struct drm_mm * mm)
 {
@@ -267,14 +363,17 @@
 
 	return (head->next->next == head);
 }
-EXPORT_SYMBOL(drm_mm_search_free);
+EXPORT_SYMBOL(drm_mm_clean);
 
 int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
 {
 	INIT_LIST_HEAD(&mm->ml_entry);
 	INIT_LIST_HEAD(&mm->fl_entry);
+	INIT_LIST_HEAD(&mm->unused_nodes);
+	mm->num_unused = 0;
+	spin_lock_init(&mm->unused_lock);
 
-	return drm_mm_create_tail_node(mm, start, size);
+	return drm_mm_create_tail_node(mm, start, size, 0);
 }
 EXPORT_SYMBOL(drm_mm_init);
 
@@ -282,6 +381,7 @@
 {
 	struct list_head *bnode = mm->fl_entry.next;
 	struct drm_mm_node *entry;
+	struct drm_mm_node *next;
 
 	entry = list_entry(bnode, struct drm_mm_node, fl_entry);
 
@@ -293,7 +393,16 @@
 
 	list_del(&entry->fl_entry);
 	list_del(&entry->ml_entry);
+	kfree(entry);
 
-	drm_free(entry, sizeof(*entry), DRM_MEM_MM);
+	spin_lock(&mm->unused_lock);
+	list_for_each_entry_safe(entry, next, &mm->unused_nodes, fl_entry) {
+		list_del(&entry->fl_entry);
+		kfree(entry);
+		--mm->num_unused;
+	}
+	spin_unlock(&mm->unused_lock);
+
+	BUG_ON(mm->num_unused != 0);
 }
 EXPORT_SYMBOL(drm_mm_takedown);
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index c9b80fd..54f492a 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -38,6 +38,7 @@
 #include "drm.h"
 #include "drm_crtc.h"
 
+#define DRM_MODESET_DEBUG	"drm_mode"
 /**
  * drm_mode_debug_printmodeline - debug print a mode
  * @dev: DRM device
@@ -50,12 +51,13 @@
  */
 void drm_mode_debug_printmodeline(struct drm_display_mode *mode)
 {
-	DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
-		  mode->base.id, mode->name, mode->vrefresh, mode->clock,
-		  mode->hdisplay, mode->hsync_start,
-		  mode->hsync_end, mode->htotal,
-		  mode->vdisplay, mode->vsync_start,
-		  mode->vsync_end, mode->vtotal, mode->type, mode->flags);
+	DRM_DEBUG_MODE(DRM_MODESET_DEBUG,
+		"Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
+		mode->base.id, mode->name, mode->vrefresh, mode->clock,
+		mode->hdisplay, mode->hsync_start,
+		mode->hsync_end, mode->htotal,
+		mode->vdisplay, mode->vsync_start,
+		mode->vsync_end, mode->vtotal, mode->type, mode->flags);
 }
 EXPORT_SYMBOL(drm_mode_debug_printmodeline);
 
@@ -401,7 +403,9 @@
 			list_del(&mode->head);
 			if (verbose) {
 				drm_mode_debug_printmodeline(mode);
-				DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status);
+				DRM_DEBUG_MODE(DRM_MODESET_DEBUG,
+					"Not using %s mode %d\n",
+					mode->name, mode->status);
 			}
 			drm_mode_destroy(dev, mode);
 		}
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index b9631e3..8905068 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -51,7 +51,22 @@
 struct class *drm_class;
 struct proc_dir_entry *drm_proc_root;
 struct dentry *drm_debugfs_root;
+void drm_ut_debug_printk(unsigned int request_level,
+			 const char *prefix,
+			 const char *function_name,
+			 const char *format, ...)
+{
+	va_list args;
 
+	if (drm_debug & request_level) {
+		if (function_name)
+			printk(KERN_DEBUG "[%s:%s], ", prefix, function_name);
+		va_start(args, format);
+		vprintk(format, args);
+		va_end(args);
+	}
+}
+EXPORT_SYMBOL(drm_ut_debug_printk);
 static int drm_minor_get_id(struct drm_device *dev, int type)
 {
 	int new_id;
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 0ccb63e..1a60626 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -33,6 +33,8 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
+#define I915_DRV	"i915_drv"
+
 /* Really want an OS-independent resettable timer.  Would like to have
  * this loop run for (eg) 3 sec, but have the timer reset every time
  * the head pointer changes, so that EBUSY only happens if the ring
@@ -99,7 +101,7 @@
 	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
 
 	I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
-	DRM_DEBUG("Enabled hardware status page\n");
+	DRM_DEBUG_DRIVER(I915_DRV, "Enabled hardware status page\n");
 	return 0;
 }
 
@@ -185,7 +187,8 @@
 		master_priv->sarea_priv = (drm_i915_sarea_t *)
 			((u8 *)master_priv->sarea->handle + init->sarea_priv_offset);
 	} else {
-		DRM_DEBUG("sarea not found assuming DRI2 userspace\n");
+		DRM_DEBUG_DRIVER(I915_DRV,
+				"sarea not found assuming DRI2 userspace\n");
 	}
 
 	if (init->ring_size != 0) {
@@ -235,7 +238,7 @@
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
-	DRM_DEBUG("%s\n", __func__);
+	DRM_DEBUG_DRIVER(I915_DRV, "%s\n", __func__);
 
 	if (dev_priv->ring.map.handle == NULL) {
 		DRM_ERROR("can not ioremap virtual address for"
@@ -248,13 +251,14 @@
 		DRM_ERROR("Can not find hardware status page\n");
 		return -EINVAL;
 	}
-	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
+	DRM_DEBUG_DRIVER(I915_DRV, "hw status page @ %p\n",
+				dev_priv->hw_status_page);
 
 	if (dev_priv->status_gfx_addr != 0)
 		I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
 	else
 		I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
-	DRM_DEBUG("Enabled hardware status page\n");
+	DRM_DEBUG_DRIVER(I915_DRV, "Enabled hardware status page\n");
 
 	return 0;
 }
@@ -548,10 +552,10 @@
 	if (!master_priv->sarea_priv)
 		return -EINVAL;
 
-	DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
-		  __func__,
-		  dev_priv->current_page,
-		  master_priv->sarea_priv->pf_current_page);
+	DRM_DEBUG_DRIVER(I915_DRV, "%s: page=%d pfCurrentPage=%d\n",
+			  __func__,
+			 dev_priv->current_page,
+			 master_priv->sarea_priv->pf_current_page);
 
 	i915_kernel_lost_context(dev);
 
@@ -629,8 +633,9 @@
 		return -EINVAL;
 	}
 
-	DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
-		  batch->start, batch->used, batch->num_cliprects);
+	DRM_DEBUG_DRIVER(I915_DRV,
+			"i915 batchbuffer, start %x used %d cliprects %d\n",
+			batch->start, batch->used, batch->num_cliprects);
 
 	RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
@@ -678,8 +683,9 @@
 	void *batch_data;
 	int ret;
 
-	DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
-		  cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
+	DRM_DEBUG_DRIVER(I915_DRV,
+			"i915 cmdbuffer, buf %p sz %d cliprects %d\n",
+			cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
 
 	RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
@@ -734,7 +740,7 @@
 {
 	int ret;
 
-	DRM_DEBUG("%s\n", __func__);
+	DRM_DEBUG_DRIVER(I915_DRV, "%s\n", __func__);
 
 	RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
@@ -777,7 +783,8 @@
 		value = dev_priv->num_fence_regs - dev_priv->fence_reg_start;
 		break;
 	default:
-		DRM_DEBUG("Unknown parameter %d\n", param->param);
+		DRM_DEBUG_DRIVER(I915_DRV, "Unknown parameter %d\n",
+					param->param);
 		return -EINVAL;
 	}
 
@@ -817,7 +824,8 @@
 		dev_priv->fence_reg_start = param->value;
 		break;
 	default:
-		DRM_DEBUG("unknown parameter %d\n", param->param);
+		DRM_DEBUG_DRIVER(I915_DRV, "unknown parameter %d\n",
+					param->param);
 		return -EINVAL;
 	}
 
@@ -865,9 +873,10 @@
 
 	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
 	I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
-	DRM_DEBUG("load hws HWS_PGA with gfx mem 0x%x\n",
-			dev_priv->status_gfx_addr);
-	DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
+	DRM_DEBUG_DRIVER(I915_DRV, "load hws HWS_PGA with gfx mem 0x%x\n",
+				dev_priv->status_gfx_addr);
+	DRM_DEBUG_DRIVER(I915_DRV, "load hws at %p\n",
+				dev_priv->hw_status_page);
 	return 0;
 }
 
@@ -922,7 +931,7 @@
 	 * Some of the preallocated space is taken by the GTT
 	 * and popup.  GTT is 1K per MB of aperture size, and popup is 4K.
 	 */
-	if (IS_G4X(dev) || IS_IGD(dev))
+	if (IS_G4X(dev) || IS_IGD(dev) || IS_IGDNG(dev))
 		overhead = 4096;
 	else
 		overhead = (*aperture_size / 1024) + 4096;
@@ -1153,8 +1162,11 @@
 #endif
 
 	dev->driver->get_vblank_counter = i915_get_vblank_counter;
-	if (IS_GM45(dev))
+	dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
+	if (IS_G4X(dev) || IS_IGDNG(dev)) {
+		dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
 		dev->driver->get_vblank_counter = gm45_get_vblank_counter;
+	}
 
 	i915_gem_load(dev);
 
@@ -1198,7 +1210,9 @@
 	}
 
 	/* Must be done after probing outputs */
-	intel_opregion_init(dev, 0);
+	/* FIXME: verify on IGDNG */
+	if (!IS_IGDNG(dev))
+		intel_opregion_init(dev, 0);
 
 	return 0;
 
@@ -1232,7 +1246,8 @@
 	if (dev_priv->regs != NULL)
 		iounmap(dev_priv->regs);
 
-	intel_opregion_free(dev, 0);
+	if (!IS_IGDNG(dev))
+		intel_opregion_free(dev, 0);
 
 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
 		intel_modeset_cleanup(dev);
@@ -1256,7 +1271,7 @@
 {
 	struct drm_i915_file_private *i915_file_priv;
 
-	DRM_DEBUG("\n");
+	DRM_DEBUG_DRIVER(I915_DRV, "\n");
 	i915_file_priv = (struct drm_i915_file_private *)
 	    drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES);
 
@@ -1265,8 +1280,7 @@
 
 	file_priv->driver_priv = i915_file_priv;
 
-	i915_file_priv->mm.last_gem_seqno = 0;
-	i915_file_priv->mm.last_gem_throttle_seqno = 0;
+	INIT_LIST_HEAD(&i915_file_priv->mm.request_list);
 
 	return 0;
 }
@@ -1303,6 +1317,7 @@
 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);
 }
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index c431fa5..8ef6bce 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -126,6 +126,13 @@
 	struct drm_gem_object *obj;
 };
 
+struct sdvo_device_mapping {
+	u8 dvo_port;
+	u8 slave_addr;
+	u8 dvo_wiring;
+	u8 initialized;
+};
+
 typedef struct drm_i915_private {
 	struct drm_device *dev;
 
@@ -143,6 +150,8 @@
 	drm_local_map_t hws_map;
 	struct drm_gem_object *hws_obj;
 
+	struct resource mch_res;
+
 	unsigned int cpp;
 	int back_offset;
 	int front_offset;
@@ -158,6 +167,11 @@
 	/** Cached value of IMR to avoid reads in updating the bitfield */
 	u32 irq_mask_reg;
 	u32 pipestat[2];
+	/** splitted irq regs for graphics and display engine on IGDNG,
+	    irq_mask_reg is still used for display irq. */
+	u32 gt_irq_mask_reg;
+	u32 gt_irq_enable_reg;
+	u32 de_irq_enable_reg;
 
 	u32 hotplug_supported_mask;
 	struct work_struct hotplug_work;
@@ -285,6 +299,13 @@
 	u8 saveDACMASK;
 	u8 saveCR[37];
 	uint64_t saveFENCE[16];
+	u32 saveCURACNTR;
+	u32 saveCURAPOS;
+	u32 saveCURABASE;
+	u32 saveCURBCNTR;
+	u32 saveCURBPOS;
+	u32 saveCURBBASE;
+	u32 saveCURSIZE;
 
 	struct {
 		struct drm_mm gtt_space;
@@ -382,6 +403,7 @@
 		/* storage for physical objects */
 		struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
 	} mm;
+	struct sdvo_device_mapping sdvo_mappings[2];
 } drm_i915_private_t;
 
 /** driver private structure attached to each drm_gem_object */
@@ -491,13 +513,16 @@
 	/** Time at which this request was emitted, in jiffies. */
 	unsigned long emitted_jiffies;
 
+	/** global list entry for this request */
 	struct list_head list;
+
+	/** file_priv list entry for this request */
+	struct list_head client_list;
 };
 
 struct drm_i915_file_private {
 	struct {
-		uint32_t last_gem_seqno;
-		uint32_t last_gem_throttle_seqno;
+		struct list_head request_list;
 	} mm;
 };
 
@@ -642,6 +667,7 @@
 void i915_gem_free_all_phys_object(struct drm_device *dev);
 int i915_gem_object_get_pages(struct drm_gem_object *obj);
 void i915_gem_object_put_pages(struct drm_gem_object *obj);
+void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv);
 
 /* i915_gem_tiling.c */
 void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
@@ -785,7 +811,9 @@
 		       (dev)->pci_device == 0x2E02 || \
 		       (dev)->pci_device == 0x2E12 || \
 		       (dev)->pci_device == 0x2E22 || \
-		       (dev)->pci_device == 0x2E32)
+		       (dev)->pci_device == 0x2E32 || \
+		       (dev)->pci_device == 0x0042 || \
+		       (dev)->pci_device == 0x0046)
 
 #define IS_I965GM(dev) ((dev)->pci_device == 0x2A02 || \
 			(dev)->pci_device == 0x2A12)
@@ -807,20 +835,26 @@
 			(dev)->pci_device == 0x29D2 ||  \
 			(IS_IGD(dev)))
 
+#define IS_IGDNG_D(dev)	((dev)->pci_device == 0x0042)
+#define IS_IGDNG_M(dev)	((dev)->pci_device == 0x0046)
+#define IS_IGDNG(dev)	(IS_IGDNG_D(dev) || IS_IGDNG_M(dev))
+
 #define IS_I9XX(dev) (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) || \
-		      IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev))
+		      IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev) || \
+		      IS_IGDNG(dev))
 
 #define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \
 			IS_I945GM(dev) || IS_I965GM(dev) || IS_GM45(dev) || \
-			IS_IGD(dev))
+			IS_IGD(dev) || IS_IGDNG_M(dev))
 
-#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev))
+#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev) || \
+				IS_IGDNG(dev))
 /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
  * rows, which changed the alignment requirements and fence programming.
  */
 #define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
 						      IS_I915GM(dev)))
-#define SUPPORTS_INTEGRATED_HDMI(dev)	(IS_G4X(dev))
+#define SUPPORTS_INTEGRATED_HDMI(dev)	(IS_G4X(dev) || IS_IGDNG(dev))
 #define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
 
 #define PRIMARY_RINGBUFFER_SIZE         (128*1024)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 39f5c65..c0ae6bb 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -989,10 +989,10 @@
 		return -ENODEV;
 
 	/* Only handle setting domains to types used by the CPU. */
-	if (write_domain & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
+	if (write_domain & I915_GEM_GPU_DOMAINS)
 		return -EINVAL;
 
-	if (read_domains & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
+	if (read_domains & I915_GEM_GPU_DOMAINS)
 		return -EINVAL;
 
 	/* Having something in the write domain implies it's in the read
@@ -1481,14 +1481,19 @@
  * Returned sequence numbers are nonzero on success.
  */
 static uint32_t
-i915_add_request(struct drm_device *dev, uint32_t flush_domains)
+i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
+		 uint32_t flush_domains)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_i915_file_private *i915_file_priv = NULL;
 	struct drm_i915_gem_request *request;
 	uint32_t seqno;
 	int was_empty;
 	RING_LOCALS;
 
+	if (file_priv != NULL)
+		i915_file_priv = file_priv->driver_priv;
+
 	request = drm_calloc(1, sizeof(*request), DRM_MEM_DRIVER);
 	if (request == NULL)
 		return 0;
@@ -1515,6 +1520,12 @@
 	request->emitted_jiffies = jiffies;
 	was_empty = list_empty(&dev_priv->mm.request_list);
 	list_add_tail(&request->list, &dev_priv->mm.request_list);
+	if (i915_file_priv) {
+		list_add_tail(&request->client_list,
+			      &i915_file_priv->mm.request_list);
+	} else {
+		INIT_LIST_HEAD(&request->client_list);
+	}
 
 	/* Associate any objects on the flushing list matching the write
 	 * domain we're flushing with our flush.
@@ -1664,6 +1675,7 @@
 			i915_gem_retire_request(dev, request);
 
 			list_del(&request->list);
+			list_del(&request->client_list);
 			drm_free(request, sizeof(*request), DRM_MEM_DRIVER);
 		} else
 			break;
@@ -1702,7 +1714,10 @@
 	BUG_ON(seqno == 0);
 
 	if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) {
-		ier = I915_READ(IER);
+		if (IS_IGDNG(dev))
+			ier = I915_READ(DEIER) | I915_READ(GTIER);
+		else
+			ier = I915_READ(IER);
 		if (!ier) {
 			DRM_ERROR("something (likely vbetool) disabled "
 				  "interrupts, re-enabling\n");
@@ -1754,8 +1769,7 @@
 	if (flush_domains & I915_GEM_DOMAIN_CPU)
 		drm_agp_chipset_flush(dev);
 
-	if ((invalidate_domains | flush_domains) & ~(I915_GEM_DOMAIN_CPU |
-						     I915_GEM_DOMAIN_GTT)) {
+	if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) {
 		/*
 		 * read/write caches:
 		 *
@@ -1977,7 +1991,7 @@
 			i915_gem_flush(dev,
 				       obj->write_domain,
 				       obj->write_domain);
-			i915_add_request(dev, obj->write_domain);
+			i915_add_request(dev, NULL, obj->write_domain);
 
 			obj = NULL;
 			continue;
@@ -1991,7 +2005,7 @@
 		/* If we didn't do any of the above, there's nothing to be done
 		 * and we just can't fit it in.
 		 */
-		return -ENOMEM;
+		return -ENOSPC;
 	}
 	return ret;
 }
@@ -2006,7 +2020,7 @@
 		if (ret != 0)
 			break;
 	}
-	if (ret == -ENOMEM)
+	if (ret == -ENOSPC)
 		return 0;
 	return ret;
 }
@@ -2215,7 +2229,7 @@
 		loff_t offset;
 
 		if (avail == 0)
-			return -ENOMEM;
+			return -ENOSPC;
 
 		for (i = dev_priv->fence_reg_start;
 		     i < dev_priv->num_fence_regs; i++) {
@@ -2248,7 +2262,7 @@
 				i915_gem_flush(dev,
 					       I915_GEM_GPU_DOMAINS,
 					       I915_GEM_GPU_DOMAINS);
-				seqno = i915_add_request(dev,
+				seqno = i915_add_request(dev, NULL,
 							 I915_GEM_GPU_DOMAINS);
 				if (seqno == 0)
 					return -ENOMEM;
@@ -2364,7 +2378,7 @@
 		spin_unlock(&dev_priv->mm.active_list_lock);
 		if (lists_empty) {
 			DRM_ERROR("GTT full, but LRU list empty\n");
-			return -ENOMEM;
+			return -ENOSPC;
 		}
 
 		ret = i915_gem_evict_something(dev);
@@ -2409,8 +2423,8 @@
 	 * wasn't in the GTT, there shouldn't be any way it could have been in
 	 * a GPU cache
 	 */
-	BUG_ON(obj->read_domains & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
-	BUG_ON(obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
+	BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS);
+	BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS);
 
 	return 0;
 }
@@ -2452,7 +2466,7 @@
 
 	/* Queue the GPU write cache flushing we need. */
 	i915_gem_flush(dev, 0, obj->write_domain);
-	seqno = i915_add_request(dev, obj->write_domain);
+	seqno = i915_add_request(dev, NULL, obj->write_domain);
 	obj->write_domain = 0;
 	i915_gem_object_move_to_active(obj, seqno);
 }
@@ -3035,20 +3049,12 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	int nbox = exec->num_cliprects;
 	int i = 0, count;
-	uint32_t	exec_start, exec_len;
+	uint32_t exec_start, exec_len;
 	RING_LOCALS;
 
 	exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
 	exec_len = (uint32_t) exec->batch_len;
 
-	if ((exec_start | exec_len) & 0x7) {
-		DRM_ERROR("alignment\n");
-		return -EINVAL;
-	}
-
-	if (!exec_start)
-		return -EINVAL;
-
 	count = nbox ? nbox : 1;
 
 	for (i = 0; i < count; i++) {
@@ -3089,6 +3095,10 @@
 /* Throttle our rendering by waiting until the ring has completed our requests
  * emitted over 20 msec ago.
  *
+ * Note that if we were to use the current jiffies each time around the loop,
+ * we wouldn't escape the function with any frames outstanding if the time to
+ * render a frame was over 20ms.
+ *
  * This should get us reasonable parallelism between CPU and GPU but also
  * relatively low latency when blocking on a particular request to finish.
  */
@@ -3097,15 +3107,25 @@
 {
 	struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
 	int ret = 0;
-	uint32_t seqno;
+	unsigned long recent_enough = jiffies - msecs_to_jiffies(20);
 
 	mutex_lock(&dev->struct_mutex);
-	seqno = i915_file_priv->mm.last_gem_throttle_seqno;
-	i915_file_priv->mm.last_gem_throttle_seqno =
-		i915_file_priv->mm.last_gem_seqno;
-	if (seqno)
-		ret = i915_wait_request(dev, seqno);
+	while (!list_empty(&i915_file_priv->mm.request_list)) {
+		struct drm_i915_gem_request *request;
+
+		request = list_first_entry(&i915_file_priv->mm.request_list,
+					   struct drm_i915_gem_request,
+					   client_list);
+
+		if (time_after_eq(request->emitted_jiffies, recent_enough))
+			break;
+
+		ret = i915_wait_request(dev, request->seqno);
+		if (ret != 0)
+			break;
+	}
 	mutex_unlock(&dev->struct_mutex);
+
 	return ret;
 }
 
@@ -3182,12 +3202,29 @@
 	return ret;
 }
 
+static int
+i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer *exec,
+			   uint64_t exec_offset)
+{
+	uint32_t exec_start, exec_len;
+
+	exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
+	exec_len = (uint32_t) exec->batch_len;
+
+	if ((exec_start | exec_len) & 0x7)
+		return -EINVAL;
+
+	if (!exec_start)
+		return -EINVAL;
+
+	return 0;
+}
+
 int
 i915_gem_execbuffer(struct drm_device *dev, void *data,
 		    struct drm_file *file_priv)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
 	struct drm_i915_gem_execbuffer *args = data;
 	struct drm_i915_gem_exec_object *exec_list = NULL;
 	struct drm_gem_object **object_list = NULL;
@@ -3312,7 +3349,7 @@
 			break;
 
 		/* error other than GTT full, or we've already tried again */
-		if (ret != -ENOMEM || pin_tries >= 1) {
+		if (ret != -ENOSPC || pin_tries >= 1) {
 			if (ret != -ERESTARTSYS)
 				DRM_ERROR("Failed to pin buffers %d\n", ret);
 			goto err;
@@ -3331,8 +3368,20 @@
 
 	/* Set the pending read domains for the batch buffer to COMMAND */
 	batch_obj = object_list[args->buffer_count-1];
-	batch_obj->pending_read_domains = I915_GEM_DOMAIN_COMMAND;
-	batch_obj->pending_write_domain = 0;
+	if (batch_obj->pending_write_domain) {
+		DRM_ERROR("Attempting to use self-modifying batch buffer\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	batch_obj->pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
+
+	/* Sanity check the batch buffer, prior to moving objects */
+	exec_offset = exec_list[args->buffer_count - 1].offset;
+	ret = i915_gem_check_execbuffer (args, exec_offset);
+	if (ret != 0) {
+		DRM_ERROR("execbuf with invalid offset/length\n");
+		goto err;
+	}
 
 	i915_verify_inactive(dev, __FILE__, __LINE__);
 
@@ -3363,7 +3412,8 @@
 			       dev->invalidate_domains,
 			       dev->flush_domains);
 		if (dev->flush_domains)
-			(void)i915_add_request(dev, dev->flush_domains);
+			(void)i915_add_request(dev, file_priv,
+					       dev->flush_domains);
 	}
 
 	for (i = 0; i < args->buffer_count; i++) {
@@ -3381,8 +3431,6 @@
 	}
 #endif
 
-	exec_offset = exec_list[args->buffer_count - 1].offset;
-
 #if WATCH_EXEC
 	i915_gem_dump_object(batch_obj,
 			      args->batch_len,
@@ -3412,9 +3460,8 @@
 	 * *some* interrupts representing completion of buffers that we can
 	 * wait on when trying to clear up gtt space).
 	 */
-	seqno = i915_add_request(dev, flush_domains);
+	seqno = i915_add_request(dev, file_priv, flush_domains);
 	BUG_ON(seqno == 0);
-	i915_file_priv->mm.last_gem_seqno = seqno;
 	for (i = 0; i < args->buffer_count; i++) {
 		struct drm_gem_object *obj = object_list[i];
 
@@ -3520,8 +3567,7 @@
 		atomic_inc(&dev->pin_count);
 		atomic_add(obj->size, &dev->pin_memory);
 		if (!obj_priv->active &&
-		    (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
-					   I915_GEM_DOMAIN_GTT)) == 0 &&
+		    (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0 &&
 		    !list_empty(&obj_priv->list))
 			list_del_init(&obj_priv->list);
 	}
@@ -3548,8 +3594,7 @@
 	 */
 	if (obj_priv->pin_count == 0) {
 		if (!obj_priv->active &&
-		    (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
-					   I915_GEM_DOMAIN_GTT)) == 0)
+		    (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
 			list_move_tail(&obj_priv->list,
 				       &dev_priv->mm.inactive_list);
 		atomic_dec(&dev->pin_count);
@@ -3653,15 +3698,14 @@
 	struct drm_gem_object *obj;
 	struct drm_i915_gem_object *obj_priv;
 
-	mutex_lock(&dev->struct_mutex);
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL) {
 		DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n",
 			  args->handle);
-		mutex_unlock(&dev->struct_mutex);
 		return -EBADF;
 	}
 
+	mutex_lock(&dev->struct_mutex);
 	/* Update the active list for the hardware's current position.
 	 * Otherwise this only updates on a delayed timer or when irqs are
 	 * actually unmasked, and our working set ends up being larger than
@@ -3800,9 +3844,8 @@
 
 	/* Flush the GPU along with all non-CPU write domains
 	 */
-	i915_gem_flush(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT),
-		       ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
-	seqno = i915_add_request(dev, ~I915_GEM_DOMAIN_CPU);
+	i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+	seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS);
 
 	if (seqno == 0) {
 		mutex_unlock(&dev->struct_mutex);
@@ -4352,3 +4395,17 @@
 	drm_agp_chipset_flush(dev);
 	return 0;
 }
+
+void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv)
+{
+	struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+
+	/* Clean up our request list when the client is going away, so that
+	 * later retire_requests won't dereference our soon-to-be-gone
+	 * file_priv.
+	 */
+	mutex_lock(&dev->struct_mutex);
+	while (!list_empty(&i915_file_priv->mm.request_list))
+		list_del_init(i915_file_priv->mm.request_list.next);
+	mutex_unlock(&dev->struct_mutex);
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 540dd33..9a05cad 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -25,6 +25,8 @@
  *
  */
 
+#include <linux/acpi.h>
+#include <linux/pnp.h>
 #include "linux/string.h"
 #include "linux/bitops.h"
 #include "drmP.h"
@@ -81,6 +83,143 @@
  * to match what the GPU expects.
  */
 
+#define MCHBAR_I915 0x44
+#define MCHBAR_I965 0x48
+#define MCHBAR_SIZE (4*4096)
+
+#define DEVEN_REG 0x54
+#define   DEVEN_MCHBAR_EN (1 << 28)
+
+/* Allocate space for the MCH regs if needed, return nonzero on error */
+static int
+intel_alloc_mchbar_resource(struct drm_device *dev)
+{
+	struct pci_dev *bridge_dev;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+	u32 temp_lo, temp_hi = 0;
+	u64 mchbar_addr;
+	int ret = 0;
+
+	bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
+	if (!bridge_dev) {
+		DRM_DEBUG("no bridge dev?!\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	if (IS_I965G(dev))
+		pci_read_config_dword(bridge_dev, reg + 4, &temp_hi);
+	pci_read_config_dword(bridge_dev, reg, &temp_lo);
+	mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
+
+	/* If ACPI doesn't have it, assume we need to allocate it ourselves */
+	if (mchbar_addr &&
+	    pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
+		ret = 0;
+		goto out_put;
+	}
+
+	/* Get some space for it */
+	ret = pci_bus_alloc_resource(bridge_dev->bus, &dev_priv->mch_res,
+				     MCHBAR_SIZE, MCHBAR_SIZE,
+				     PCIBIOS_MIN_MEM,
+				     0,   pcibios_align_resource,
+				     bridge_dev);
+	if (ret) {
+		DRM_DEBUG("failed bus alloc: %d\n", ret);
+		dev_priv->mch_res.start = 0;
+		goto out_put;
+	}
+
+	if (IS_I965G(dev))
+		pci_write_config_dword(bridge_dev, reg + 4,
+				       upper_32_bits(dev_priv->mch_res.start));
+
+	pci_write_config_dword(bridge_dev, reg,
+			       lower_32_bits(dev_priv->mch_res.start));
+out_put:
+	pci_dev_put(bridge_dev);
+out:
+	return ret;
+}
+
+/* Setup MCHBAR if possible, return true if we should disable it again */
+static bool
+intel_setup_mchbar(struct drm_device *dev)
+{
+	struct pci_dev *bridge_dev;
+	int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+	u32 temp;
+	bool need_disable = false, enabled;
+
+	bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
+	if (!bridge_dev) {
+		DRM_DEBUG("no bridge dev?!\n");
+		goto out;
+	}
+
+	if (IS_I915G(dev) || IS_I915GM(dev)) {
+		pci_read_config_dword(bridge_dev, DEVEN_REG, &temp);
+		enabled = !!(temp & DEVEN_MCHBAR_EN);
+	} else {
+		pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
+		enabled = temp & 1;
+	}
+
+	/* If it's already enabled, don't have to do anything */
+	if (enabled)
+		goto out_put;
+
+	if (intel_alloc_mchbar_resource(dev))
+		goto out_put;
+
+	need_disable = true;
+
+	/* Space is allocated or reserved, so enable it. */
+	if (IS_I915G(dev) || IS_I915GM(dev)) {
+		pci_write_config_dword(bridge_dev, DEVEN_REG,
+				       temp | DEVEN_MCHBAR_EN);
+	} else {
+		pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
+		pci_write_config_dword(bridge_dev, mchbar_reg, temp | 1);
+	}
+out_put:
+	pci_dev_put(bridge_dev);
+out:
+	return need_disable;
+}
+
+static void
+intel_teardown_mchbar(struct drm_device *dev, bool disable)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct pci_dev *bridge_dev;
+	int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+	u32 temp;
+
+	bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
+	if (!bridge_dev) {
+		DRM_DEBUG("no bridge dev?!\n");
+		return;
+	}
+
+	if (disable) {
+		if (IS_I915G(dev) || IS_I915GM(dev)) {
+			pci_read_config_dword(bridge_dev, DEVEN_REG, &temp);
+			temp &= ~DEVEN_MCHBAR_EN;
+			pci_write_config_dword(bridge_dev, DEVEN_REG, temp);
+		} else {
+			pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
+			temp &= ~1;
+			pci_write_config_dword(bridge_dev, mchbar_reg, temp);
+		}
+	}
+
+	if (dev_priv->mch_res.start)
+		release_resource(&dev_priv->mch_res);
+}
+
 /**
  * Detects bit 6 swizzling of address lookup between IGD access and CPU
  * access through main memory.
@@ -91,6 +230,7 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
 	uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
+	bool need_disable;
 
 	if (!IS_I9XX(dev)) {
 		/* As far as we know, the 865 doesn't have these bit 6
@@ -101,6 +241,9 @@
 	} else if (IS_MOBILE(dev)) {
 		uint32_t dcc;
 
+		/* Try to make sure MCHBAR is enabled before poking at it */
+		need_disable = intel_setup_mchbar(dev);
+
 		/* On mobile 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,
@@ -140,6 +283,8 @@
 			swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
 			swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
 		}
+
+		intel_teardown_mchbar(dev, need_disable);
 	} else {
 		/* The 965, G33, and newer, have a very flexible memory
 		 * configuration.  It will enable dual-channel mode
@@ -170,6 +315,13 @@
 		}
 	}
 
+	/* FIXME: check with memory config on IGDNG */
+	if (IS_IGDNG(dev)) {
+		DRM_ERROR("disable tiling on IGDNG...\n");
+		swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
+		swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
+	}
+
 	dev_priv->mm.bit_6_swizzle_x = swizzle_x;
 	dev_priv->mm.bit_6_swizzle_y = swizzle_y;
 }
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 98bb4c8..b86b7b7 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -58,6 +58,47 @@
 					 DRM_I915_VBLANK_PIPE_B)
 
 void
+igdng_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+	if ((dev_priv->gt_irq_mask_reg & mask) != 0) {
+		dev_priv->gt_irq_mask_reg &= ~mask;
+		I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
+		(void) I915_READ(GTIMR);
+	}
+}
+
+static inline void
+igdng_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+	if ((dev_priv->gt_irq_mask_reg & mask) != mask) {
+		dev_priv->gt_irq_mask_reg |= mask;
+		I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
+		(void) I915_READ(GTIMR);
+	}
+}
+
+/* For display hotplug interrupt */
+void
+igdng_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+	if ((dev_priv->irq_mask_reg & mask) != 0) {
+		dev_priv->irq_mask_reg &= ~mask;
+		I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
+		(void) I915_READ(DEIMR);
+	}
+}
+
+static inline void
+igdng_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+	if ((dev_priv->irq_mask_reg & mask) != mask) {
+		dev_priv->irq_mask_reg |= mask;
+		I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
+		(void) I915_READ(DEIMR);
+	}
+}
+
+void
 i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
 	if ((dev_priv->irq_mask_reg & mask) != 0) {
@@ -196,6 +237,47 @@
 	drm_sysfs_hotplug_event(dev);
 }
 
+irqreturn_t igdng_irq_handler(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	int ret = IRQ_NONE;
+	u32 de_iir, gt_iir;
+	u32 new_de_iir, new_gt_iir;
+	struct drm_i915_master_private *master_priv;
+
+	de_iir = I915_READ(DEIIR);
+	gt_iir = I915_READ(GTIIR);
+
+	for (;;) {
+		if (de_iir == 0 && gt_iir == 0)
+			break;
+
+		ret = IRQ_HANDLED;
+
+		I915_WRITE(DEIIR, de_iir);
+		new_de_iir = I915_READ(DEIIR);
+		I915_WRITE(GTIIR, gt_iir);
+		new_gt_iir = I915_READ(GTIIR);
+
+		if (dev->primary->master) {
+			master_priv = dev->primary->master->driver_priv;
+			if (master_priv->sarea_priv)
+				master_priv->sarea_priv->last_dispatch =
+					READ_BREADCRUMB(dev_priv);
+		}
+
+		if (gt_iir & GT_USER_INTERRUPT) {
+			dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
+			DRM_WAKEUP(&dev_priv->irq_queue);
+		}
+
+		de_iir = new_de_iir;
+		gt_iir = new_gt_iir;
+	}
+
+	return ret;
+}
+
 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 {
 	struct drm_device *dev = (struct drm_device *) arg;
@@ -212,6 +294,9 @@
 
 	atomic_inc(&dev_priv->irq_received);
 
+	if (IS_IGDNG(dev))
+		return igdng_irq_handler(dev);
+
 	iir = I915_READ(IIR);
 
 	if (IS_I965G(dev)) {
@@ -349,8 +434,12 @@
 	unsigned long irqflags;
 
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
-	if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1))
-		i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
+	if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) {
+		if (IS_IGDNG(dev))
+			igdng_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
+		else
+			i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
+	}
 	spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 }
 
@@ -361,8 +450,12 @@
 
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
 	BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
-	if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0))
-		i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
+	if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
+		if (IS_IGDNG(dev))
+			igdng_disable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
+		else
+			i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
+	}
 	spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 }
 
@@ -455,6 +548,9 @@
 	if (!(pipeconf & PIPEACONF_ENABLE))
 		return -EINVAL;
 
+	if (IS_IGDNG(dev))
+		return 0;
+
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
 	if (IS_I965G(dev))
 		i915_enable_pipestat(dev_priv, pipe,
@@ -474,6 +570,9 @@
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	unsigned long irqflags;
 
+	if (IS_IGDNG(dev))
+		return;
+
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
 	i915_disable_pipestat(dev_priv, pipe,
 			      PIPE_VBLANK_INTERRUPT_ENABLE |
@@ -484,7 +583,9 @@
 void i915_enable_interrupt (struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	opregion_enable_asle(dev);
+
+	if (!IS_IGDNG(dev))
+		opregion_enable_asle(dev);
 	dev_priv->irq_enabled = 1;
 }
 
@@ -545,12 +646,65 @@
 
 /* drm_dma.h hooks
 */
+static void igdng_irq_preinstall(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+	I915_WRITE(HWSTAM, 0xeffe);
+
+	/* XXX hotplug from PCH */
+
+	I915_WRITE(DEIMR, 0xffffffff);
+	I915_WRITE(DEIER, 0x0);
+	(void) I915_READ(DEIER);
+
+	/* and GT */
+	I915_WRITE(GTIMR, 0xffffffff);
+	I915_WRITE(GTIER, 0x0);
+	(void) I915_READ(GTIER);
+}
+
+static int igdng_irq_postinstall(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	/* enable kind of interrupts always enabled */
+	u32 display_mask = DE_MASTER_IRQ_CONTROL /*| DE_PCH_EVENT */;
+	u32 render_mask = GT_USER_INTERRUPT;
+
+	dev_priv->irq_mask_reg = ~display_mask;
+	dev_priv->de_irq_enable_reg = display_mask;
+
+	/* should always can generate irq */
+	I915_WRITE(DEIIR, I915_READ(DEIIR));
+	I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
+	I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
+	(void) I915_READ(DEIER);
+
+	/* user interrupt should be enabled, but masked initial */
+	dev_priv->gt_irq_mask_reg = 0xffffffff;
+	dev_priv->gt_irq_enable_reg = render_mask;
+
+	I915_WRITE(GTIIR, I915_READ(GTIIR));
+	I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
+	I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
+	(void) I915_READ(GTIER);
+
+	return 0;
+}
+
 void i915_driver_irq_preinstall(struct drm_device * dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
 	atomic_set(&dev_priv->irq_received, 0);
 
+	INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
+
+	if (IS_IGDNG(dev)) {
+		igdng_irq_preinstall(dev);
+		return;
+	}
+
 	if (I915_HAS_HOTPLUG(dev)) {
 		I915_WRITE(PORT_HOTPLUG_EN, 0);
 		I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -562,7 +716,6 @@
 	I915_WRITE(IMR, 0xffffffff);
 	I915_WRITE(IER, 0x0);
 	(void) I915_READ(IER);
-	INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
 }
 
 int i915_driver_irq_postinstall(struct drm_device *dev)
@@ -570,9 +723,12 @@
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
 
+	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
+
 	dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
 
-	dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
+	if (IS_IGDNG(dev))
+		return igdng_irq_postinstall(dev);
 
 	/* Unmask the interrupts that we always want on. */
 	dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX;
@@ -613,11 +769,24 @@
 	(void) I915_READ(IER);
 
 	opregion_enable_asle(dev);
-	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
 
 	return 0;
 }
 
+static void igdng_irq_uninstall(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	I915_WRITE(HWSTAM, 0xffffffff);
+
+	I915_WRITE(DEIMR, 0xffffffff);
+	I915_WRITE(DEIER, 0x0);
+	I915_WRITE(DEIIR, I915_READ(DEIIR));
+
+	I915_WRITE(GTIMR, 0xffffffff);
+	I915_WRITE(GTIER, 0x0);
+	I915_WRITE(GTIIR, I915_READ(GTIIR));
+}
+
 void i915_driver_irq_uninstall(struct drm_device * dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -627,6 +796,11 @@
 
 	dev_priv->vblank_pipe = 0;
 
+	if (IS_IGDNG(dev)) {
+		igdng_irq_uninstall(dev);
+		return;
+	}
+
 	if (I915_HAS_HOTPLUG(dev)) {
 		I915_WRITE(PORT_HOTPLUG_EN, 0);
 		I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 375569d..f6237a0 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -450,6 +450,13 @@
 #define   PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13)
 #define   PLL_REF_INPUT_MASK		(3 << 13)
 #define   PLL_LOAD_PULSE_PHASE_SHIFT		9
+/* IGDNG */
+# define PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT     9
+# define PLL_REF_SDVO_HDMI_MULTIPLIER_MASK      (7 << 9)
+# define PLL_REF_SDVO_HDMI_MULTIPLIER(x)	(((x)-1) << 9)
+# define DPLL_FPA1_P1_POST_DIV_SHIFT            0
+# define DPLL_FPA1_P1_POST_DIV_MASK             0xff
+
 /*
  * Parallel to Serial Load Pulse phase selection.
  * Selects the phase for the 10X DPLL clock for the PCIe
@@ -631,8 +638,11 @@
 /* Hotplug control (945+ only) */
 #define PORT_HOTPLUG_EN		0x61110
 #define   HDMIB_HOTPLUG_INT_EN			(1 << 29)
+#define   DPB_HOTPLUG_INT_EN			(1 << 29)
 #define   HDMIC_HOTPLUG_INT_EN			(1 << 28)
+#define   DPC_HOTPLUG_INT_EN			(1 << 28)
 #define   HDMID_HOTPLUG_INT_EN			(1 << 27)
+#define   DPD_HOTPLUG_INT_EN			(1 << 27)
 #define   SDVOB_HOTPLUG_INT_EN			(1 << 26)
 #define   SDVOC_HOTPLUG_INT_EN			(1 << 25)
 #define   TV_HOTPLUG_INT_EN			(1 << 18)
@@ -665,8 +675,11 @@
 
 #define PORT_HOTPLUG_STAT	0x61114
 #define   HDMIB_HOTPLUG_INT_STATUS		(1 << 29)
+#define   DPB_HOTPLUG_INT_STATUS		(1 << 29)
 #define   HDMIC_HOTPLUG_INT_STATUS		(1 << 28)
+#define   DPC_HOTPLUG_INT_STATUS		(1 << 28)
 #define   HDMID_HOTPLUG_INT_STATUS		(1 << 27)
+#define   DPD_HOTPLUG_INT_STATUS		(1 << 27)
 #define   CRT_HOTPLUG_INT_STATUS		(1 << 11)
 #define   TV_HOTPLUG_INT_STATUS			(1 << 10)
 #define   CRT_HOTPLUG_MONITOR_MASK		(3 << 8)
@@ -951,15 +964,15 @@
 # define DAC_A_1_3_V			(0 << 4)
 # define DAC_A_1_1_V			(1 << 4)
 # define DAC_A_0_7_V			(2 << 4)
-# define DAC_A_OFF			(3 << 4)
+# define DAC_A_MASK			(3 << 4)
 # define DAC_B_1_3_V			(0 << 2)
 # define DAC_B_1_1_V			(1 << 2)
 # define DAC_B_0_7_V			(2 << 2)
-# define DAC_B_OFF			(3 << 2)
+# define DAC_B_MASK			(3 << 2)
 # define DAC_C_1_3_V			(0 << 0)
 # define DAC_C_1_1_V			(1 << 0)
 # define DAC_C_0_7_V			(2 << 0)
-# define DAC_C_OFF			(3 << 0)
+# define DAC_C_MASK			(3 << 0)
 
 /**
  * CSC coefficients are stored in a floating point format with 9 bits of
@@ -1328,6 +1341,163 @@
 #define TV_V_CHROMA_0		0x68400
 #define TV_V_CHROMA_42		0x684a8
 
+/* Display Port */
+#define DP_B				0x64100
+#define DP_C				0x64200
+#define DP_D				0x64300
+
+#define   DP_PORT_EN			(1 << 31)
+#define   DP_PIPEB_SELECT		(1 << 30)
+
+/* Link training mode - select a suitable mode for each stage */
+#define   DP_LINK_TRAIN_PAT_1		(0 << 28)
+#define   DP_LINK_TRAIN_PAT_2		(1 << 28)
+#define   DP_LINK_TRAIN_PAT_IDLE	(2 << 28)
+#define   DP_LINK_TRAIN_OFF		(3 << 28)
+#define   DP_LINK_TRAIN_MASK		(3 << 28)
+#define   DP_LINK_TRAIN_SHIFT		28
+
+/* Signal voltages. These are mostly controlled by the other end */
+#define   DP_VOLTAGE_0_4		(0 << 25)
+#define   DP_VOLTAGE_0_6		(1 << 25)
+#define   DP_VOLTAGE_0_8		(2 << 25)
+#define   DP_VOLTAGE_1_2		(3 << 25)
+#define   DP_VOLTAGE_MASK		(7 << 25)
+#define   DP_VOLTAGE_SHIFT		25
+
+/* Signal pre-emphasis levels, like voltages, the other end tells us what
+ * they want
+ */
+#define   DP_PRE_EMPHASIS_0		(0 << 22)
+#define   DP_PRE_EMPHASIS_3_5		(1 << 22)
+#define   DP_PRE_EMPHASIS_6		(2 << 22)
+#define   DP_PRE_EMPHASIS_9_5		(3 << 22)
+#define   DP_PRE_EMPHASIS_MASK		(7 << 22)
+#define   DP_PRE_EMPHASIS_SHIFT		22
+
+/* How many wires to use. I guess 3 was too hard */
+#define   DP_PORT_WIDTH_1		(0 << 19)
+#define   DP_PORT_WIDTH_2		(1 << 19)
+#define   DP_PORT_WIDTH_4		(3 << 19)
+#define   DP_PORT_WIDTH_MASK		(7 << 19)
+
+/* Mystic DPCD version 1.1 special mode */
+#define   DP_ENHANCED_FRAMING		(1 << 18)
+
+/** locked once port is enabled */
+#define   DP_PORT_REVERSAL		(1 << 15)
+
+/** sends the clock on lane 15 of the PEG for debug */
+#define   DP_CLOCK_OUTPUT_ENABLE	(1 << 13)
+
+#define   DP_SCRAMBLING_DISABLE		(1 << 12)
+
+/** limit RGB values to avoid confusing TVs */
+#define   DP_COLOR_RANGE_16_235		(1 << 8)
+
+/** Turn on the audio link */
+#define   DP_AUDIO_OUTPUT_ENABLE	(1 << 6)
+
+/** vs and hs sync polarity */
+#define   DP_SYNC_VS_HIGH		(1 << 4)
+#define   DP_SYNC_HS_HIGH		(1 << 3)
+
+/** A fantasy */
+#define   DP_DETECTED			(1 << 2)
+
+/** The aux channel provides a way to talk to the
+ * signal sink for DDC etc. Max packet size supported
+ * is 20 bytes in each direction, hence the 5 fixed
+ * data registers
+ */
+#define DPB_AUX_CH_CTL			0x64110
+#define DPB_AUX_CH_DATA1		0x64114
+#define DPB_AUX_CH_DATA2		0x64118
+#define DPB_AUX_CH_DATA3		0x6411c
+#define DPB_AUX_CH_DATA4		0x64120
+#define DPB_AUX_CH_DATA5		0x64124
+
+#define DPC_AUX_CH_CTL			0x64210
+#define DPC_AUX_CH_DATA1		0x64214
+#define DPC_AUX_CH_DATA2		0x64218
+#define DPC_AUX_CH_DATA3		0x6421c
+#define DPC_AUX_CH_DATA4		0x64220
+#define DPC_AUX_CH_DATA5		0x64224
+
+#define DPD_AUX_CH_CTL			0x64310
+#define DPD_AUX_CH_DATA1		0x64314
+#define DPD_AUX_CH_DATA2		0x64318
+#define DPD_AUX_CH_DATA3		0x6431c
+#define DPD_AUX_CH_DATA4		0x64320
+#define DPD_AUX_CH_DATA5		0x64324
+
+#define   DP_AUX_CH_CTL_SEND_BUSY	    (1 << 31)
+#define   DP_AUX_CH_CTL_DONE		    (1 << 30)
+#define   DP_AUX_CH_CTL_INTERRUPT	    (1 << 29)
+#define   DP_AUX_CH_CTL_TIME_OUT_ERROR	    (1 << 28)
+#define   DP_AUX_CH_CTL_TIME_OUT_400us	    (0 << 26)
+#define   DP_AUX_CH_CTL_TIME_OUT_600us	    (1 << 26)
+#define   DP_AUX_CH_CTL_TIME_OUT_800us	    (2 << 26)
+#define   DP_AUX_CH_CTL_TIME_OUT_1600us	    (3 << 26)
+#define   DP_AUX_CH_CTL_TIME_OUT_MASK	    (3 << 26)
+#define   DP_AUX_CH_CTL_RECEIVE_ERROR	    (1 << 25)
+#define   DP_AUX_CH_CTL_MESSAGE_SIZE_MASK    (0x1f << 20)
+#define   DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT   20
+#define   DP_AUX_CH_CTL_PRECHARGE_2US_MASK   (0xf << 16)
+#define   DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT  16
+#define   DP_AUX_CH_CTL_AUX_AKSV_SELECT	    (1 << 15)
+#define   DP_AUX_CH_CTL_MANCHESTER_TEST	    (1 << 14)
+#define   DP_AUX_CH_CTL_SYNC_TEST	    (1 << 13)
+#define   DP_AUX_CH_CTL_DEGLITCH_TEST	    (1 << 12)
+#define   DP_AUX_CH_CTL_PRECHARGE_TEST	    (1 << 11)
+#define   DP_AUX_CH_CTL_BIT_CLOCK_2X_MASK    (0x7ff)
+#define   DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT   0
+
+/*
+ * Computing GMCH M and N values for the Display Port link
+ *
+ * GMCH M/N = dot clock * bytes per pixel / ls_clk * # of lanes
+ *
+ * ls_clk (we assume) is the DP link clock (1.62 or 2.7 GHz)
+ *
+ * The GMCH value is used internally
+ *
+ * bytes_per_pixel is the number of bytes coming out of the plane,
+ * which is after the LUTs, so we want the bytes for our color format.
+ * For our current usage, this is always 3, one byte for R, G and B.
+ */
+#define PIPEA_GMCH_DATA_M			0x70050
+#define PIPEB_GMCH_DATA_M			0x71050
+
+/* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */
+#define   PIPE_GMCH_DATA_M_TU_SIZE_MASK		(0x3f << 25)
+#define   PIPE_GMCH_DATA_M_TU_SIZE_SHIFT	25
+
+#define   PIPE_GMCH_DATA_M_MASK			(0xffffff)
+
+#define PIPEA_GMCH_DATA_N			0x70054
+#define PIPEB_GMCH_DATA_N			0x71054
+#define   PIPE_GMCH_DATA_N_MASK			(0xffffff)
+
+/*
+ * Computing Link M and N values for the Display Port link
+ *
+ * Link M / N = pixel_clock / ls_clk
+ *
+ * (the DP spec calls pixel_clock the 'strm_clk')
+ *
+ * The Link value is transmitted in the Main Stream
+ * Attributes and VB-ID.
+ */
+
+#define PIPEA_DP_LINK_M				0x70060
+#define PIPEB_DP_LINK_M				0x71060
+#define   PIPEA_DP_LINK_M_MASK			(0xffffff)
+
+#define PIPEA_DP_LINK_N				0x70064
+#define PIPEB_DP_LINK_N				0x71064
+#define   PIPEA_DP_LINK_N_MASK			(0xffffff)
+
 /* Display & cursor control */
 
 /* Pipe A */
@@ -1517,4 +1687,444 @@
 # define VGA_2X_MODE				(1 << 30)
 # define VGA_PIPE_B_SELECT			(1 << 29)
 
+/* IGDNG */
+
+#define CPU_VGACNTRL	0x41000
+
+#define DIGITAL_PORT_HOTPLUG_CNTRL      0x44030
+#define  DIGITAL_PORTA_HOTPLUG_ENABLE           (1 << 4)
+#define  DIGITAL_PORTA_SHORT_PULSE_2MS          (0 << 2)
+#define  DIGITAL_PORTA_SHORT_PULSE_4_5MS        (1 << 2)
+#define  DIGITAL_PORTA_SHORT_PULSE_6MS          (2 << 2)
+#define  DIGITAL_PORTA_SHORT_PULSE_100MS        (3 << 2)
+#define  DIGITAL_PORTA_NO_DETECT                (0 << 0)
+#define  DIGITAL_PORTA_LONG_PULSE_DETECT_MASK   (1 << 1)
+#define  DIGITAL_PORTA_SHORT_PULSE_DETECT_MASK  (1 << 0)
+
+/* refresh rate hardware control */
+#define RR_HW_CTL       0x45300
+#define  RR_HW_LOW_POWER_FRAMES_MASK    0xff
+#define  RR_HW_HIGH_POWER_FRAMES_MASK   0xff00
+
+#define FDI_PLL_BIOS_0  0x46000
+#define FDI_PLL_BIOS_1  0x46004
+#define FDI_PLL_BIOS_2  0x46008
+#define DISPLAY_PORT_PLL_BIOS_0         0x4600c
+#define DISPLAY_PORT_PLL_BIOS_1         0x46010
+#define DISPLAY_PORT_PLL_BIOS_2         0x46014
+
+#define FDI_PLL_FREQ_CTL        0x46030
+#define  FDI_PLL_FREQ_CHANGE_REQUEST    (1<<24)
+#define  FDI_PLL_FREQ_LOCK_LIMIT_MASK   0xfff00
+#define  FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK  0xff
+
+
+#define PIPEA_DATA_M1           0x60030
+#define  TU_SIZE(x)             (((x)-1) << 25) /* default size 64 */
+#define  TU_SIZE_MASK           0x7e000000
+#define  PIPEA_DATA_M1_OFFSET   0
+#define PIPEA_DATA_N1           0x60034
+#define  PIPEA_DATA_N1_OFFSET   0
+
+#define PIPEA_DATA_M2           0x60038
+#define  PIPEA_DATA_M2_OFFSET   0
+#define PIPEA_DATA_N2           0x6003c
+#define  PIPEA_DATA_N2_OFFSET   0
+
+#define PIPEA_LINK_M1           0x60040
+#define  PIPEA_LINK_M1_OFFSET   0
+#define PIPEA_LINK_N1           0x60044
+#define  PIPEA_LINK_N1_OFFSET   0
+
+#define PIPEA_LINK_M2           0x60048
+#define  PIPEA_LINK_M2_OFFSET   0
+#define PIPEA_LINK_N2           0x6004c
+#define  PIPEA_LINK_N2_OFFSET   0
+
+/* PIPEB timing regs are same start from 0x61000 */
+
+#define PIPEB_DATA_M1           0x61030
+#define  PIPEB_DATA_M1_OFFSET   0
+#define PIPEB_DATA_N1           0x61034
+#define  PIPEB_DATA_N1_OFFSET   0
+
+#define PIPEB_DATA_M2           0x61038
+#define  PIPEB_DATA_M2_OFFSET   0
+#define PIPEB_DATA_N2           0x6103c
+#define  PIPEB_DATA_N2_OFFSET   0
+
+#define PIPEB_LINK_M1           0x61040
+#define  PIPEB_LINK_M1_OFFSET   0
+#define PIPEB_LINK_N1           0x61044
+#define  PIPEB_LINK_N1_OFFSET   0
+
+#define PIPEB_LINK_M2           0x61048
+#define  PIPEB_LINK_M2_OFFSET   0
+#define PIPEB_LINK_N2           0x6104c
+#define  PIPEB_LINK_N2_OFFSET   0
+
+/* CPU panel fitter */
+#define PFA_CTL_1               0x68080
+#define PFB_CTL_1               0x68880
+#define  PF_ENABLE              (1<<31)
+
+/* legacy palette */
+#define LGC_PALETTE_A           0x4a000
+#define LGC_PALETTE_B           0x4a800
+
+/* interrupts */
+#define DE_MASTER_IRQ_CONTROL   (1 << 31)
+#define DE_SPRITEB_FLIP_DONE    (1 << 29)
+#define DE_SPRITEA_FLIP_DONE    (1 << 28)
+#define DE_PLANEB_FLIP_DONE     (1 << 27)
+#define DE_PLANEA_FLIP_DONE     (1 << 26)
+#define DE_PCU_EVENT            (1 << 25)
+#define DE_GTT_FAULT            (1 << 24)
+#define DE_POISON               (1 << 23)
+#define DE_PERFORM_COUNTER      (1 << 22)
+#define DE_PCH_EVENT            (1 << 21)
+#define DE_AUX_CHANNEL_A        (1 << 20)
+#define DE_DP_A_HOTPLUG         (1 << 19)
+#define DE_GSE                  (1 << 18)
+#define DE_PIPEB_VBLANK         (1 << 15)
+#define DE_PIPEB_EVEN_FIELD     (1 << 14)
+#define DE_PIPEB_ODD_FIELD      (1 << 13)
+#define DE_PIPEB_LINE_COMPARE   (1 << 12)
+#define DE_PIPEB_VSYNC          (1 << 11)
+#define DE_PIPEB_FIFO_UNDERRUN  (1 << 8)
+#define DE_PIPEA_VBLANK         (1 << 7)
+#define DE_PIPEA_EVEN_FIELD     (1 << 6)
+#define DE_PIPEA_ODD_FIELD      (1 << 5)
+#define DE_PIPEA_LINE_COMPARE   (1 << 4)
+#define DE_PIPEA_VSYNC          (1 << 3)
+#define DE_PIPEA_FIFO_UNDERRUN  (1 << 0)
+
+#define DEISR   0x44000
+#define DEIMR   0x44004
+#define DEIIR   0x44008
+#define DEIER   0x4400c
+
+/* GT interrupt */
+#define GT_SYNC_STATUS          (1 << 2)
+#define GT_USER_INTERRUPT       (1 << 0)
+
+#define GTISR   0x44010
+#define GTIMR   0x44014
+#define GTIIR   0x44018
+#define GTIER   0x4401c
+
+/* PCH */
+
+/* south display engine interrupt */
+#define SDE_CRT_HOTPLUG         (1 << 11)
+#define SDE_PORTD_HOTPLUG       (1 << 10)
+#define SDE_PORTC_HOTPLUG       (1 << 9)
+#define SDE_PORTB_HOTPLUG       (1 << 8)
+#define SDE_SDVOB_HOTPLUG       (1 << 6)
+
+#define SDEISR  0xc4000
+#define SDEIMR  0xc4004
+#define SDEIIR  0xc4008
+#define SDEIER  0xc400c
+
+/* digital port hotplug */
+#define PCH_PORT_HOTPLUG        0xc4030
+#define PORTD_HOTPLUG_ENABLE            (1 << 20)
+#define PORTD_PULSE_DURATION_2ms        (0)
+#define PORTD_PULSE_DURATION_4_5ms      (1 << 18)
+#define PORTD_PULSE_DURATION_6ms        (2 << 18)
+#define PORTD_PULSE_DURATION_100ms      (3 << 18)
+#define PORTD_HOTPLUG_NO_DETECT         (0)
+#define PORTD_HOTPLUG_SHORT_DETECT      (1 << 16)
+#define PORTD_HOTPLUG_LONG_DETECT       (1 << 17)
+#define PORTC_HOTPLUG_ENABLE            (1 << 12)
+#define PORTC_PULSE_DURATION_2ms        (0)
+#define PORTC_PULSE_DURATION_4_5ms      (1 << 10)
+#define PORTC_PULSE_DURATION_6ms        (2 << 10)
+#define PORTC_PULSE_DURATION_100ms      (3 << 10)
+#define PORTC_HOTPLUG_NO_DETECT         (0)
+#define PORTC_HOTPLUG_SHORT_DETECT      (1 << 8)
+#define PORTC_HOTPLUG_LONG_DETECT       (1 << 9)
+#define PORTB_HOTPLUG_ENABLE            (1 << 4)
+#define PORTB_PULSE_DURATION_2ms        (0)
+#define PORTB_PULSE_DURATION_4_5ms      (1 << 2)
+#define PORTB_PULSE_DURATION_6ms        (2 << 2)
+#define PORTB_PULSE_DURATION_100ms      (3 << 2)
+#define PORTB_HOTPLUG_NO_DETECT         (0)
+#define PORTB_HOTPLUG_SHORT_DETECT      (1 << 0)
+#define PORTB_HOTPLUG_LONG_DETECT       (1 << 1)
+
+#define PCH_GPIOA               0xc5010
+#define PCH_GPIOB               0xc5014
+#define PCH_GPIOC               0xc5018
+#define PCH_GPIOD               0xc501c
+#define PCH_GPIOE               0xc5020
+#define PCH_GPIOF               0xc5024
+
+#define PCH_DPLL_A              0xc6014
+#define PCH_DPLL_B              0xc6018
+
+#define PCH_FPA0                0xc6040
+#define PCH_FPA1                0xc6044
+#define PCH_FPB0                0xc6048
+#define PCH_FPB1                0xc604c
+
+#define PCH_DPLL_TEST           0xc606c
+
+#define PCH_DREF_CONTROL        0xC6200
+#define  DREF_CONTROL_MASK      0x7fc3
+#define  DREF_CPU_SOURCE_OUTPUT_DISABLE         (0<<13)
+#define  DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD      (2<<13)
+#define  DREF_CPU_SOURCE_OUTPUT_NONSPREAD       (3<<13)
+#define  DREF_CPU_SOURCE_OUTPUT_MASK		(3<<13)
+#define  DREF_SSC_SOURCE_DISABLE                (0<<11)
+#define  DREF_SSC_SOURCE_ENABLE                 (2<<11)
+#define  DREF_SSC_SOURCE_MASK			(2<<11)
+#define  DREF_NONSPREAD_SOURCE_DISABLE          (0<<9)
+#define  DREF_NONSPREAD_CK505_ENABLE		(1<<9)
+#define  DREF_NONSPREAD_SOURCE_ENABLE           (2<<9)
+#define  DREF_NONSPREAD_SOURCE_MASK		(2<<9)
+#define  DREF_SUPERSPREAD_SOURCE_DISABLE        (0<<7)
+#define  DREF_SUPERSPREAD_SOURCE_ENABLE         (2<<7)
+#define  DREF_SSC4_DOWNSPREAD                   (0<<6)
+#define  DREF_SSC4_CENTERSPREAD                 (1<<6)
+#define  DREF_SSC1_DISABLE                      (0<<1)
+#define  DREF_SSC1_ENABLE                       (1<<1)
+#define  DREF_SSC4_DISABLE                      (0)
+#define  DREF_SSC4_ENABLE                       (1)
+
+#define PCH_RAWCLK_FREQ         0xc6204
+#define  FDL_TP1_TIMER_SHIFT    12
+#define  FDL_TP1_TIMER_MASK     (3<<12)
+#define  FDL_TP2_TIMER_SHIFT    10
+#define  FDL_TP2_TIMER_MASK     (3<<10)
+#define  RAWCLK_FREQ_MASK       0x3ff
+
+#define PCH_DPLL_TMR_CFG        0xc6208
+
+#define PCH_SSC4_PARMS          0xc6210
+#define PCH_SSC4_AUX_PARMS      0xc6214
+
+/* transcoder */
+
+#define TRANS_HTOTAL_A          0xe0000
+#define  TRANS_HTOTAL_SHIFT     16
+#define  TRANS_HACTIVE_SHIFT    0
+#define TRANS_HBLANK_A          0xe0004
+#define  TRANS_HBLANK_END_SHIFT 16
+#define  TRANS_HBLANK_START_SHIFT 0
+#define TRANS_HSYNC_A           0xe0008
+#define  TRANS_HSYNC_END_SHIFT  16
+#define  TRANS_HSYNC_START_SHIFT 0
+#define TRANS_VTOTAL_A          0xe000c
+#define  TRANS_VTOTAL_SHIFT     16
+#define  TRANS_VACTIVE_SHIFT    0
+#define TRANS_VBLANK_A          0xe0010
+#define  TRANS_VBLANK_END_SHIFT 16
+#define  TRANS_VBLANK_START_SHIFT 0
+#define TRANS_VSYNC_A           0xe0014
+#define  TRANS_VSYNC_END_SHIFT  16
+#define  TRANS_VSYNC_START_SHIFT 0
+
+#define TRANSA_DATA_M1          0xe0030
+#define TRANSA_DATA_N1          0xe0034
+#define TRANSA_DATA_M2          0xe0038
+#define TRANSA_DATA_N2          0xe003c
+#define TRANSA_DP_LINK_M1       0xe0040
+#define TRANSA_DP_LINK_N1       0xe0044
+#define TRANSA_DP_LINK_M2       0xe0048
+#define TRANSA_DP_LINK_N2       0xe004c
+
+#define TRANS_HTOTAL_B          0xe1000
+#define TRANS_HBLANK_B          0xe1004
+#define TRANS_HSYNC_B           0xe1008
+#define TRANS_VTOTAL_B          0xe100c
+#define TRANS_VBLANK_B          0xe1010
+#define TRANS_VSYNC_B           0xe1014
+
+#define TRANSB_DATA_M1          0xe1030
+#define TRANSB_DATA_N1          0xe1034
+#define TRANSB_DATA_M2          0xe1038
+#define TRANSB_DATA_N2          0xe103c
+#define TRANSB_DP_LINK_M1       0xe1040
+#define TRANSB_DP_LINK_N1       0xe1044
+#define TRANSB_DP_LINK_M2       0xe1048
+#define TRANSB_DP_LINK_N2       0xe104c
+
+#define TRANSACONF              0xf0008
+#define TRANSBCONF              0xf1008
+#define  TRANS_DISABLE          (0<<31)
+#define  TRANS_ENABLE           (1<<31)
+#define  TRANS_STATE_MASK       (1<<30)
+#define  TRANS_STATE_DISABLE    (0<<30)
+#define  TRANS_STATE_ENABLE     (1<<30)
+#define  TRANS_FSYNC_DELAY_HB1  (0<<27)
+#define  TRANS_FSYNC_DELAY_HB2  (1<<27)
+#define  TRANS_FSYNC_DELAY_HB3  (2<<27)
+#define  TRANS_FSYNC_DELAY_HB4  (3<<27)
+#define  TRANS_DP_AUDIO_ONLY    (1<<26)
+#define  TRANS_DP_VIDEO_AUDIO   (0<<26)
+#define  TRANS_PROGRESSIVE      (0<<21)
+#define  TRANS_8BPC             (0<<5)
+#define  TRANS_10BPC            (1<<5)
+#define  TRANS_6BPC             (2<<5)
+#define  TRANS_12BPC            (3<<5)
+
+#define FDI_RXA_CHICKEN         0xc200c
+#define FDI_RXB_CHICKEN         0xc2010
+#define  FDI_RX_PHASE_SYNC_POINTER_ENABLE       (1)
+
+/* CPU: FDI_TX */
+#define FDI_TXA_CTL             0x60100
+#define FDI_TXB_CTL             0x61100
+#define  FDI_TX_DISABLE         (0<<31)
+#define  FDI_TX_ENABLE          (1<<31)
+#define  FDI_LINK_TRAIN_PATTERN_1       (0<<28)
+#define  FDI_LINK_TRAIN_PATTERN_2       (1<<28)
+#define  FDI_LINK_TRAIN_PATTERN_IDLE    (2<<28)
+#define  FDI_LINK_TRAIN_NONE            (3<<28)
+#define  FDI_LINK_TRAIN_VOLTAGE_0_4V    (0<<25)
+#define  FDI_LINK_TRAIN_VOLTAGE_0_6V    (1<<25)
+#define  FDI_LINK_TRAIN_VOLTAGE_0_8V    (2<<25)
+#define  FDI_LINK_TRAIN_VOLTAGE_1_2V    (3<<25)
+#define  FDI_LINK_TRAIN_PRE_EMPHASIS_NONE (0<<22)
+#define  FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1<<22)
+#define  FDI_LINK_TRAIN_PRE_EMPHASIS_2X   (2<<22)
+#define  FDI_LINK_TRAIN_PRE_EMPHASIS_3X   (3<<22)
+#define  FDI_DP_PORT_WIDTH_X1           (0<<19)
+#define  FDI_DP_PORT_WIDTH_X2           (1<<19)
+#define  FDI_DP_PORT_WIDTH_X3           (2<<19)
+#define  FDI_DP_PORT_WIDTH_X4           (3<<19)
+#define  FDI_TX_ENHANCE_FRAME_ENABLE    (1<<18)
+/* IGDNG: hardwired to 1 */
+#define  FDI_TX_PLL_ENABLE              (1<<14)
+/* both Tx and Rx */
+#define  FDI_SCRAMBLING_ENABLE          (0<<7)
+#define  FDI_SCRAMBLING_DISABLE         (1<<7)
+
+/* FDI_RX, FDI_X is hard-wired to Transcoder_X */
+#define FDI_RXA_CTL             0xf000c
+#define FDI_RXB_CTL             0xf100c
+#define  FDI_RX_ENABLE          (1<<31)
+#define  FDI_RX_DISABLE         (0<<31)
+/* train, dp width same as FDI_TX */
+#define  FDI_DP_PORT_WIDTH_X8           (7<<19)
+#define  FDI_8BPC                       (0<<16)
+#define  FDI_10BPC                      (1<<16)
+#define  FDI_6BPC                       (2<<16)
+#define  FDI_12BPC                      (3<<16)
+#define  FDI_LINK_REVERSE_OVERWRITE     (1<<15)
+#define  FDI_DMI_LINK_REVERSE_MASK      (1<<14)
+#define  FDI_RX_PLL_ENABLE              (1<<13)
+#define  FDI_FS_ERR_CORRECT_ENABLE      (1<<11)
+#define  FDI_FE_ERR_CORRECT_ENABLE      (1<<10)
+#define  FDI_FS_ERR_REPORT_ENABLE       (1<<9)
+#define  FDI_FE_ERR_REPORT_ENABLE       (1<<8)
+#define  FDI_RX_ENHANCE_FRAME_ENABLE    (1<<6)
+#define  FDI_SEL_RAWCLK                 (0<<4)
+#define  FDI_SEL_PCDCLK                 (1<<4)
+
+#define FDI_RXA_MISC            0xf0010
+#define FDI_RXB_MISC            0xf1010
+#define FDI_RXA_TUSIZE1         0xf0030
+#define FDI_RXA_TUSIZE2         0xf0038
+#define FDI_RXB_TUSIZE1         0xf1030
+#define FDI_RXB_TUSIZE2         0xf1038
+
+/* FDI_RX interrupt register format */
+#define FDI_RX_INTER_LANE_ALIGN         (1<<10)
+#define FDI_RX_SYMBOL_LOCK              (1<<9) /* train 2 */
+#define FDI_RX_BIT_LOCK                 (1<<8) /* train 1 */
+#define FDI_RX_TRAIN_PATTERN_2_FAIL     (1<<7)
+#define FDI_RX_FS_CODE_ERR              (1<<6)
+#define FDI_RX_FE_CODE_ERR              (1<<5)
+#define FDI_RX_SYMBOL_ERR_RATE_ABOVE    (1<<4)
+#define FDI_RX_HDCP_LINK_FAIL           (1<<3)
+#define FDI_RX_PIXEL_FIFO_OVERFLOW      (1<<2)
+#define FDI_RX_CROSS_CLOCK_OVERFLOW     (1<<1)
+#define FDI_RX_SYMBOL_QUEUE_OVERFLOW    (1<<0)
+
+#define FDI_RXA_IIR             0xf0014
+#define FDI_RXA_IMR             0xf0018
+#define FDI_RXB_IIR             0xf1014
+#define FDI_RXB_IMR             0xf1018
+
+#define FDI_PLL_CTL_1           0xfe000
+#define FDI_PLL_CTL_2           0xfe004
+
+/* CRT */
+#define PCH_ADPA                0xe1100
+#define  ADPA_TRANS_SELECT_MASK (1<<30)
+#define  ADPA_TRANS_A_SELECT    0
+#define  ADPA_TRANS_B_SELECT    (1<<30)
+#define  ADPA_CRT_HOTPLUG_MASK  0x03ff0000 /* bit 25-16 */
+#define  ADPA_CRT_HOTPLUG_MONITOR_NONE  (0<<24)
+#define  ADPA_CRT_HOTPLUG_MONITOR_MASK  (3<<24)
+#define  ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24)
+#define  ADPA_CRT_HOTPLUG_MONITOR_MONO  (2<<24)
+#define  ADPA_CRT_HOTPLUG_ENABLE        (1<<23)
+#define  ADPA_CRT_HOTPLUG_PERIOD_64     (0<<22)
+#define  ADPA_CRT_HOTPLUG_PERIOD_128    (1<<22)
+#define  ADPA_CRT_HOTPLUG_WARMUP_5MS    (0<<21)
+#define  ADPA_CRT_HOTPLUG_WARMUP_10MS   (1<<21)
+#define  ADPA_CRT_HOTPLUG_SAMPLE_2S     (0<<20)
+#define  ADPA_CRT_HOTPLUG_SAMPLE_4S     (1<<20)
+#define  ADPA_CRT_HOTPLUG_VOLTAGE_40    (0<<18)
+#define  ADPA_CRT_HOTPLUG_VOLTAGE_50    (1<<18)
+#define  ADPA_CRT_HOTPLUG_VOLTAGE_60    (2<<18)
+#define  ADPA_CRT_HOTPLUG_VOLTAGE_70    (3<<18)
+#define  ADPA_CRT_HOTPLUG_VOLREF_325MV  (0<<17)
+#define  ADPA_CRT_HOTPLUG_VOLREF_475MV  (1<<17)
+#define  ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16)
+
+/* or SDVOB */
+#define HDMIB   0xe1140
+#define  PORT_ENABLE    (1 << 31)
+#define  TRANSCODER_A   (0)
+#define  TRANSCODER_B   (1 << 30)
+#define  COLOR_FORMAT_8bpc      (0)
+#define  COLOR_FORMAT_12bpc     (3 << 26)
+#define  SDVOB_HOTPLUG_ENABLE   (1 << 23)
+#define  SDVO_ENCODING          (0)
+#define  TMDS_ENCODING          (2 << 10)
+#define  NULL_PACKET_VSYNC_ENABLE       (1 << 9)
+#define  SDVOB_BORDER_ENABLE    (1 << 7)
+#define  AUDIO_ENABLE           (1 << 6)
+#define  VSYNC_ACTIVE_HIGH      (1 << 4)
+#define  HSYNC_ACTIVE_HIGH      (1 << 3)
+#define  PORT_DETECTED          (1 << 2)
+
+#define HDMIC   0xe1150
+#define HDMID   0xe1160
+
+#define PCH_LVDS	0xe1180
+#define  LVDS_DETECTED	(1 << 1)
+
+#define BLC_PWM_CPU_CTL2	0x48250
+#define  PWM_ENABLE		(1 << 31)
+#define  PWM_PIPE_A		(0 << 29)
+#define  PWM_PIPE_B		(1 << 29)
+#define BLC_PWM_CPU_CTL		0x48254
+
+#define BLC_PWM_PCH_CTL1	0xc8250
+#define  PWM_PCH_ENABLE		(1 << 31)
+#define  PWM_POLARITY_ACTIVE_LOW	(1 << 29)
+#define  PWM_POLARITY_ACTIVE_HIGH	(0 << 29)
+#define  PWM_POLARITY_ACTIVE_LOW2	(1 << 28)
+#define  PWM_POLARITY_ACTIVE_HIGH2	(0 << 28)
+
+#define BLC_PWM_PCH_CTL2	0xc8254
+
+#define PCH_PP_STATUS		0xc7200
+#define PCH_PP_CONTROL		0xc7204
+#define  EDP_FORCE_VDD		(1 << 3)
+#define  EDP_BLC_ENABLE		(1 << 2)
+#define  PANEL_POWER_RESET	(1 << 1)
+#define  PANEL_POWER_OFF	(0 << 0)
+#define  PANEL_POWER_ON		(1 << 0)
+#define PCH_PP_ON_DELAYS	0xc7208
+#define  EDP_PANEL		(1 << 30)
+#define PCH_PP_OFF_DELAYS	0xc720c
+#define PCH_PP_DIVISOR		0xc7210
+
 #endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index ce8a213..a98e283 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -295,6 +295,16 @@
 	i915_save_palette(dev, PIPE_B);
 	dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT);
 
+	/* Cursor state */
+	dev_priv->saveCURACNTR = I915_READ(CURACNTR);
+	dev_priv->saveCURAPOS = I915_READ(CURAPOS);
+	dev_priv->saveCURABASE = I915_READ(CURABASE);
+	dev_priv->saveCURBCNTR = I915_READ(CURBCNTR);
+	dev_priv->saveCURBPOS = I915_READ(CURBPOS);
+	dev_priv->saveCURBBASE = I915_READ(CURBBASE);
+	if (!IS_I9XX(dev))
+		dev_priv->saveCURSIZE = I915_READ(CURSIZE);
+
 	/* CRT state */
 	dev_priv->saveADPA = I915_READ(ADPA);
 
@@ -480,6 +490,16 @@
 	I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
 	I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
 
+	/* Cursor state */
+	I915_WRITE(CURAPOS, dev_priv->saveCURAPOS);
+	I915_WRITE(CURACNTR, dev_priv->saveCURACNTR);
+	I915_WRITE(CURABASE, dev_priv->saveCURABASE);
+	I915_WRITE(CURBPOS, dev_priv->saveCURBPOS);
+	I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR);
+	I915_WRITE(CURBBASE, dev_priv->saveCURBBASE);
+	if (!IS_I9XX(dev))
+		I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
+
 	/* CRT state */
 	I915_WRITE(ADPA, dev_priv->saveADPA);
 
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 9d78cff..754dd22 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -30,6 +30,8 @@
 #include "i915_drv.h"
 #include "intel_bios.h"
 
+#define	SLAVE_ADDR1	0x70
+#define	SLAVE_ADDR2	0x72
 
 static void *
 find_section(struct bdb_header *bdb, int section_id)
@@ -193,6 +195,88 @@
 	}
 }
 
+static void
+parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
+		       struct bdb_header *bdb)
+{
+	struct sdvo_device_mapping *p_mapping;
+	struct bdb_general_definitions *p_defs;
+	struct child_device_config *p_child;
+	int i, child_device_num, count;
+	u16	block_size, *block_ptr;
+
+	p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
+	if (!p_defs) {
+		DRM_DEBUG("No general definition block is found\n");
+		return;
+	}
+	/* judge whether the size of child device meets the requirements.
+	 * If the child device size obtained from general definition block
+	 * is different with sizeof(struct child_device_config), skip the
+	 * parsing of sdvo device info
+	 */
+	if (p_defs->child_dev_size != sizeof(*p_child)) {
+		/* different child dev size . Ignore it */
+		DRM_DEBUG("different child size is found. Invalid.\n");
+		return;
+	}
+	/* get the block size of general definitions */
+	block_ptr = (u16 *)((char *)p_defs - 2);
+	block_size = *block_ptr;
+	/* get the number of child device */
+	child_device_num = (block_size - sizeof(*p_defs)) /
+				sizeof(*p_child);
+	count = 0;
+	for (i = 0; i < child_device_num; i++) {
+		p_child = &(p_defs->devices[i]);
+		if (!p_child->device_type) {
+			/* skip the device block if device type is invalid */
+			continue;
+		}
+		if (p_child->slave_addr != SLAVE_ADDR1 &&
+			p_child->slave_addr != SLAVE_ADDR2) {
+			/*
+			 * If the slave address is neither 0x70 nor 0x72,
+			 * it is not a SDVO device. Skip it.
+			 */
+			continue;
+		}
+		if (p_child->dvo_port != DEVICE_PORT_DVOB &&
+			p_child->dvo_port != DEVICE_PORT_DVOC) {
+			/* skip the incorrect SDVO port */
+			DRM_DEBUG("Incorrect SDVO port. Skip it \n");
+			continue;
+		}
+		DRM_DEBUG("the SDVO device with slave addr %2x is found on "
+				"%s port\n",
+				p_child->slave_addr,
+				(p_child->dvo_port == DEVICE_PORT_DVOB) ?
+					"SDVOB" : "SDVOC");
+		p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]);
+		if (!p_mapping->initialized) {
+			p_mapping->dvo_port = p_child->dvo_port;
+			p_mapping->slave_addr = p_child->slave_addr;
+			p_mapping->dvo_wiring = p_child->dvo_wiring;
+			p_mapping->initialized = 1;
+		} else {
+			DRM_DEBUG("Maybe one SDVO port is shared by "
+					 "two SDVO device.\n");
+		}
+		if (p_child->slave2_addr) {
+			/* Maybe this is a SDVO device with multiple inputs */
+			/* And the mapping info is not added */
+			DRM_DEBUG("there exists the slave2_addr. Maybe this "
+				"is a SDVO device with multiple inputs.\n");
+		}
+		count++;
+	}
+
+	if (!count) {
+		/* No SDVO device info is found */
+		DRM_DEBUG("No SDVO device info is found in VBT\n");
+	}
+	return;
+}
 /**
  * intel_init_bios - initialize VBIOS settings & find VBT
  * @dev: DRM device
@@ -242,7 +326,7 @@
 	parse_general_features(dev_priv, bdb);
 	parse_lfp_panel_data(dev_priv, bdb);
 	parse_sdvo_panel_data(dev_priv, bdb);
-
+	parse_sdvo_device_mapping(dev_priv, bdb);
 	pci_unmap_rom(pdev, bios);
 
 	return 0;
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index 8ca2cde..fe72e1c 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -135,6 +135,86 @@
 	u8 rsvd11:6; /* finish byte */
 } __attribute__((packed));
 
+/* pre-915 */
+#define GPIO_PIN_DVI_LVDS	0x03 /* "DVI/LVDS DDC GPIO pins" */
+#define GPIO_PIN_ADD_I2C	0x05 /* "ADDCARD I2C GPIO pins" */
+#define GPIO_PIN_ADD_DDC	0x04 /* "ADDCARD DDC GPIO pins" */
+#define GPIO_PIN_ADD_DDC_I2C	0x06 /* "ADDCARD DDC/I2C GPIO pins" */
+
+/* Pre 915 */
+#define DEVICE_TYPE_NONE	0x00
+#define DEVICE_TYPE_CRT		0x01
+#define DEVICE_TYPE_TV		0x09
+#define DEVICE_TYPE_EFP		0x12
+#define DEVICE_TYPE_LFP		0x22
+/* On 915+ */
+#define DEVICE_TYPE_CRT_DPMS		0x6001
+#define DEVICE_TYPE_CRT_DPMS_HOTPLUG	0x4001
+#define DEVICE_TYPE_TV_COMPOSITE	0x0209
+#define DEVICE_TYPE_TV_MACROVISION	0x0289
+#define DEVICE_TYPE_TV_RF_COMPOSITE	0x020c
+#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE	0x0609
+#define DEVICE_TYPE_TV_SCART		0x0209
+#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009
+#define DEVICE_TYPE_EFP_HOTPLUG_PWR	0x6012
+#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR	0x6052
+#define DEVICE_TYPE_EFP_DVI_I		0x6053
+#define DEVICE_TYPE_EFP_DVI_D_DUAL	0x6152
+#define DEVICE_TYPE_EFP_DVI_D_HDCP	0x60d2
+#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR	0x6062
+#define DEVICE_TYPE_OPENLDI_DUALPIX	0x6162
+#define DEVICE_TYPE_LFP_PANELLINK	0x5012
+#define DEVICE_TYPE_LFP_CMOS_PWR	0x5042
+#define DEVICE_TYPE_LFP_LVDS_PWR	0x5062
+#define DEVICE_TYPE_LFP_LVDS_DUAL	0x5162
+#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP	0x51e2
+
+#define DEVICE_CFG_NONE		0x00
+#define DEVICE_CFG_12BIT_DVOB	0x01
+#define DEVICE_CFG_12BIT_DVOC	0x02
+#define DEVICE_CFG_24BIT_DVOBC	0x09
+#define DEVICE_CFG_24BIT_DVOCB	0x0a
+#define DEVICE_CFG_DUAL_DVOB	0x11
+#define DEVICE_CFG_DUAL_DVOC	0x12
+#define DEVICE_CFG_DUAL_DVOBC	0x13
+#define DEVICE_CFG_DUAL_LINK_DVOBC	0x19
+#define DEVICE_CFG_DUAL_LINK_DVOCB	0x1a
+
+#define DEVICE_WIRE_NONE	0x00
+#define DEVICE_WIRE_DVOB	0x01
+#define DEVICE_WIRE_DVOC	0x02
+#define DEVICE_WIRE_DVOBC	0x03
+#define DEVICE_WIRE_DVOBB	0x05
+#define DEVICE_WIRE_DVOCC	0x06
+#define DEVICE_WIRE_DVOB_MASTER 0x0d
+#define DEVICE_WIRE_DVOC_MASTER 0x0e
+
+#define DEVICE_PORT_DVOA	0x00 /* none on 845+ */
+#define DEVICE_PORT_DVOB	0x01
+#define DEVICE_PORT_DVOC	0x02
+
+struct child_device_config {
+	u16 handle;
+	u16 device_type;
+	u8  device_id[10]; /* See DEVICE_TYPE_* above */
+	u16 addin_offset;
+	u8  dvo_port; /* See Device_PORT_* above */
+	u8  i2c_pin;
+	u8  slave_addr;
+	u8  ddc_pin;
+	u16 edid_ptr;
+	u8  dvo_cfg; /* See DEVICE_CFG_* above */
+	u8  dvo2_port;
+	u8  i2c2_pin;
+	u8  slave2_addr;
+	u8  ddc2_pin;
+	u8  capabilities;
+	u8  dvo_wiring;/* See DEVICE_WIRE_* above */
+	u8  dvo2_wiring;
+	u16 extended_type;
+	u8  dvo_function;
+} __attribute__((packed));
+
 struct bdb_general_definitions {
 	/* DDC GPIO */
 	u8 crt_ddc_gmbus_pin;
@@ -149,14 +229,19 @@
 	u8 boot_display[2];
 	u8 child_dev_size;
 
-	/* device info */
-	u8 tv_or_lvds_info[33];
-	u8 dev1[33];
-	u8 dev2[33];
-	u8 dev3[33];
-	u8 dev4[33];
-	/* may be another device block here on some platforms */
-};
+	/*
+	 * Device info:
+	 * If TV is present, it'll be at devices[0].
+	 * LVDS will be next, either devices[0] or [1], if present.
+	 * On some platforms the number of device is 6. But could be as few as
+	 * 4 if both TV and LVDS are missing.
+	 * And the device num is related with the size of general definition
+	 * block. It is obtained by using the following formula:
+	 * number = (block_size - sizeof(bdb_general_definitions))/
+	 * 		sizeof(child_device_config);
+	 */
+	struct child_device_config devices[0];
+} __attribute__((packed));
 
 struct bdb_lvds_options {
 	u8 panel_type;
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 79acc4f..6de97fc 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -37,9 +37,14 @@
 {
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 temp;
+	u32 temp, reg;
 
-	temp = I915_READ(ADPA);
+	if (IS_IGDNG(dev))
+		reg = PCH_ADPA;
+	else
+		reg = ADPA;
+
+	temp = I915_READ(reg);
 	temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
 	temp |= ADPA_DAC_ENABLE;
 
@@ -58,7 +63,7 @@
 		break;
 	}
 
-	I915_WRITE(ADPA, temp);
+	I915_WRITE(reg, temp);
 }
 
 static int intel_crt_mode_valid(struct drm_connector *connector,
@@ -101,17 +106,23 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int dpll_md_reg;
 	u32 adpa, dpll_md;
+	u32 adpa_reg;
 
 	if (intel_crtc->pipe == 0)
 		dpll_md_reg = DPLL_A_MD;
 	else
 		dpll_md_reg = DPLL_B_MD;
 
+	if (IS_IGDNG(dev))
+		adpa_reg = PCH_ADPA;
+	else
+		adpa_reg = ADPA;
+
 	/*
 	 * Disable separate mode multiplier used when cloning SDVO to CRT
 	 * XXX this needs to be adjusted when we really are cloning
 	 */
-	if (IS_I965G(dev)) {
+	if (IS_I965G(dev) && !IS_IGDNG(dev)) {
 		dpll_md = I915_READ(dpll_md_reg);
 		I915_WRITE(dpll_md_reg,
 			   dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
@@ -125,13 +136,53 @@
 
 	if (intel_crtc->pipe == 0) {
 		adpa |= ADPA_PIPE_A_SELECT;
-		I915_WRITE(BCLRPAT_A, 0);
+		if (!IS_IGDNG(dev))
+			I915_WRITE(BCLRPAT_A, 0);
 	} else {
 		adpa |= ADPA_PIPE_B_SELECT;
-		I915_WRITE(BCLRPAT_B, 0);
+		if (!IS_IGDNG(dev))
+			I915_WRITE(BCLRPAT_B, 0);
 	}
 
-	I915_WRITE(ADPA, adpa);
+	I915_WRITE(adpa_reg, adpa);
+}
+
+static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 adpa, temp;
+	bool ret;
+
+	temp = adpa = I915_READ(PCH_ADPA);
+
+	adpa &= ~ADPA_CRT_HOTPLUG_MASK;
+
+	adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
+			ADPA_CRT_HOTPLUG_WARMUP_10MS |
+			ADPA_CRT_HOTPLUG_SAMPLE_4S |
+			ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */
+			ADPA_CRT_HOTPLUG_VOLREF_325MV |
+			ADPA_CRT_HOTPLUG_ENABLE |
+			ADPA_CRT_HOTPLUG_FORCE_TRIGGER);
+
+	DRM_DEBUG("pch crt adpa 0x%x", adpa);
+	I915_WRITE(PCH_ADPA, adpa);
+
+	/* This might not be needed as not specified in spec...*/
+	udelay(1000);
+
+	/* Check the status to see if both blue and green are on now */
+	adpa = I915_READ(PCH_ADPA);
+	if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) ==
+			ADPA_CRT_HOTPLUG_MONITOR_COLOR)
+		ret = true;
+	else
+		ret = false;
+
+	/* restore origin register */
+	I915_WRITE(PCH_ADPA, temp);
+	return ret;
 }
 
 /**
@@ -148,6 +199,10 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 hotplug_en;
 	int i, tries = 0;
+
+	if (IS_IGDNG(dev))
+		return intel_igdng_crt_detect_hotplug(connector);
+
 	/*
 	 * On 4 series desktop, CRT detect sequence need to be done twice
 	 * to get a reliable result.
@@ -423,6 +478,7 @@
 {
 	struct drm_connector *connector;
 	struct intel_output *intel_output;
+	u32 i2c_reg;
 
 	intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
 	if (!intel_output)
@@ -439,7 +495,11 @@
 					  &intel_output->enc);
 
 	/* Set up the DDC bus. */
-	intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A");
+	if (IS_IGDNG(dev))
+		i2c_reg = PCH_GPIOA;
+	else
+		i2c_reg = GPIOA;
+	intel_output->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
 	if (!intel_output->ddc_bus) {
 		dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
 			   "failed.\n");
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index c9d6f10..028f5b6 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -137,6 +137,8 @@
 #define INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS   7
 #define INTEL_LIMIT_IGD_SDVO_DAC    8
 #define INTEL_LIMIT_IGD_LVDS	    9
+#define INTEL_LIMIT_IGDNG_SDVO_DAC  10
+#define INTEL_LIMIT_IGDNG_LVDS	    11
 
 /*The parameter is for SDVO on G4x platform*/
 #define G4X_DOT_SDVO_MIN           25000
@@ -216,12 +218,43 @@
 #define G4X_P2_DUAL_CHANNEL_LVDS_FAST           7
 #define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT          0
 
+/* IGDNG */
+/* as we calculate clock using (register_value + 2) for
+   N/M1/M2, so here the range value for them is (actual_value-2).
+ */
+#define IGDNG_DOT_MIN         25000
+#define IGDNG_DOT_MAX         350000
+#define IGDNG_VCO_MIN         1760000
+#define IGDNG_VCO_MAX         3510000
+#define IGDNG_N_MIN           1
+#define IGDNG_N_MAX           5
+#define IGDNG_M_MIN           79
+#define IGDNG_M_MAX           118
+#define IGDNG_M1_MIN          12
+#define IGDNG_M1_MAX          23
+#define IGDNG_M2_MIN          5
+#define IGDNG_M2_MAX          9
+#define IGDNG_P_SDVO_DAC_MIN  5
+#define IGDNG_P_SDVO_DAC_MAX  80
+#define IGDNG_P_LVDS_MIN      28
+#define IGDNG_P_LVDS_MAX      112
+#define IGDNG_P1_MIN          1
+#define IGDNG_P1_MAX          8
+#define IGDNG_P2_SDVO_DAC_SLOW 10
+#define IGDNG_P2_SDVO_DAC_FAST 5
+#define IGDNG_P2_LVDS_SLOW    14 /* single channel */
+#define IGDNG_P2_LVDS_FAST    7  /* double channel */
+#define IGDNG_P2_DOT_LIMIT    225000 /* 225Mhz */
+
 static bool
 intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
 		    int target, int refclk, 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);
+static bool
+intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
+			int target, int refclk, intel_clock_t *best_clock);
 
 static const intel_limit_t intel_limits[] = {
     { /* INTEL_LIMIT_I8XX_DVO_DAC */
@@ -383,9 +416,47 @@
 		 .p2_slow = I9XX_P2_LVDS_SLOW,	.p2_fast = I9XX_P2_LVDS_SLOW },
 	.find_pll = intel_find_best_PLL,
     },
-
+    { /* INTEL_LIMIT_IGDNG_SDVO_DAC */
+	.dot = { .min = IGDNG_DOT_MIN,          .max = IGDNG_DOT_MAX },
+	.vco = { .min = IGDNG_VCO_MIN,          .max = IGDNG_VCO_MAX },
+	.n   = { .min = IGDNG_N_MIN,            .max = IGDNG_N_MAX },
+	.m   = { .min = IGDNG_M_MIN,            .max = IGDNG_M_MAX },
+	.m1  = { .min = IGDNG_M1_MIN,           .max = IGDNG_M1_MAX },
+	.m2  = { .min = IGDNG_M2_MIN,           .max = IGDNG_M2_MAX },
+	.p   = { .min = IGDNG_P_SDVO_DAC_MIN,   .max = IGDNG_P_SDVO_DAC_MAX },
+	.p1  = { .min = IGDNG_P1_MIN,           .max = IGDNG_P1_MAX },
+	.p2  = { .dot_limit = IGDNG_P2_DOT_LIMIT,
+		 .p2_slow = IGDNG_P2_SDVO_DAC_SLOW,
+		 .p2_fast = IGDNG_P2_SDVO_DAC_FAST },
+	.find_pll = intel_igdng_find_best_PLL,
+    },
+    { /* INTEL_LIMIT_IGDNG_LVDS */
+	.dot = { .min = IGDNG_DOT_MIN,          .max = IGDNG_DOT_MAX },
+	.vco = { .min = IGDNG_VCO_MIN,          .max = IGDNG_VCO_MAX },
+	.n   = { .min = IGDNG_N_MIN,            .max = IGDNG_N_MAX },
+	.m   = { .min = IGDNG_M_MIN,            .max = IGDNG_M_MAX },
+	.m1  = { .min = IGDNG_M1_MIN,           .max = IGDNG_M1_MAX },
+	.m2  = { .min = IGDNG_M2_MIN,           .max = IGDNG_M2_MAX },
+	.p   = { .min = IGDNG_P_LVDS_MIN,       .max = IGDNG_P_LVDS_MAX },
+	.p1  = { .min = IGDNG_P1_MIN,           .max = IGDNG_P1_MAX },
+	.p2  = { .dot_limit = IGDNG_P2_DOT_LIMIT,
+		 .p2_slow = IGDNG_P2_LVDS_SLOW,
+		 .p2_fast = IGDNG_P2_LVDS_FAST },
+	.find_pll = intel_igdng_find_best_PLL,
+    },
 };
 
+static const intel_limit_t *intel_igdng_limit(struct drm_crtc *crtc)
+{
+	const intel_limit_t *limit;
+	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+		limit = &intel_limits[INTEL_LIMIT_IGDNG_LVDS];
+	else
+		limit = &intel_limits[INTEL_LIMIT_IGDNG_SDVO_DAC];
+
+	return limit;
+}
+
 static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
@@ -418,7 +489,9 @@
 	struct drm_device *dev = crtc->dev;
 	const intel_limit_t *limit;
 
-	if (IS_G4X(dev)) {
+	if (IS_IGDNG(dev))
+		limit = intel_igdng_limit(crtc);
+	else if (IS_G4X(dev)) {
 		limit = intel_g4x_limit(crtc);
 	} else if (IS_I9XX(dev) && !IS_IGD(dev)) {
 		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
@@ -630,7 +703,64 @@
 			}
 		}
 	}
+	return found;
+}
 
+static bool
+intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
+			int target, int refclk, intel_clock_t *best_clock)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	intel_clock_t clock;
+	int max_n;
+	bool found;
+	int err_most = 47;
+	found = false;
+
+	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+		if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
+		    LVDS_CLKB_POWER_UP)
+			clock.p2 = limit->p2.p2_fast;
+		else
+			clock.p2 = limit->p2.p2_slow;
+	} else {
+		if (target < limit->p2.dot_limit)
+			clock.p2 = limit->p2.p2_slow;
+		else
+			clock.p2 = limit->p2.p2_fast;
+	}
+
+	memset(best_clock, 0, sizeof(*best_clock));
+	max_n = limit->n.max;
+	/* based on hardware requriment prefer smaller n to precision */
+	for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
+		/* based on hardware requirment prefere larger m1,m2, p1 */
+		for (clock.m1 = limit->m1.max;
+		     clock.m1 >= limit->m1.min; clock.m1--) {
+			for (clock.m2 = limit->m2.max;
+			     clock.m2 >= limit->m2.min; clock.m2--) {
+				for (clock.p1 = limit->p1.max;
+				     clock.p1 >= limit->p1.min; clock.p1--) {
+					int this_err;
+
+					intel_clock(dev, refclk, &clock);
+					if (!intel_PLL_is_valid(crtc, &clock))
+						continue;
+					this_err = abs((10000 - (target*10000/clock.dot)));
+					if (this_err < err_most) {
+						*best_clock = clock;
+						err_most = this_err;
+						max_n = clock.n;
+						found = true;
+						/* found on first matching */
+						goto out;
+					}
+				}
+			}
+		}
+	}
+out:
 	return found;
 }
 
@@ -785,18 +915,292 @@
 	return 0;
 }
 
-
-
-/**
- * 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 intel_crtc_dpms(struct drm_crtc *crtc, int mode)
+static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
 	struct drm_device *dev = crtc->dev;
-	struct drm_i915_master_private *master_priv;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int pipe = intel_crtc->pipe;
+	int plane = intel_crtc->pipe;
+	int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
+	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+	int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
+	int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
+	int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
+	int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
+	int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
+	int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
+	int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
+	int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1;
+	int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
+	int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
+	int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
+	int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
+	int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
+	int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
+	int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B;
+	int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B;
+	int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B;
+	int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B;
+	int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;
+	int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
+	u32 temp;
+	int tries = 5, j;
+
+	/* 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:
+		DRM_DEBUG("crtc %d dpms on\n", pipe);
+		/* enable PCH DPLL */
+		temp = I915_READ(pch_dpll_reg);
+		if ((temp & DPLL_VCO_ENABLE) == 0) {
+			I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
+			I915_READ(pch_dpll_reg);
+		}
+
+		/* enable PCH FDI RX PLL, wait warmup plus DMI latency */
+		temp = I915_READ(fdi_rx_reg);
+		I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE |
+				FDI_SEL_PCDCLK |
+				FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */
+		I915_READ(fdi_rx_reg);
+		udelay(200);
+
+		/* Enable CPU FDI TX PLL, always on for IGDNG */
+		temp = I915_READ(fdi_tx_reg);
+		if ((temp & FDI_TX_PLL_ENABLE) == 0) {
+			I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
+			I915_READ(fdi_tx_reg);
+			udelay(100);
+		}
+
+		/* Enable CPU pipe */
+		temp = I915_READ(pipeconf_reg);
+		if ((temp & PIPEACONF_ENABLE) == 0) {
+			I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
+			I915_READ(pipeconf_reg);
+			udelay(100);
+		}
+
+		/* configure and enable CPU plane */
+		temp = I915_READ(dspcntr_reg);
+		if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+			I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
+			/* Flush the plane changes */
+			I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+		}
+
+		/* enable CPU FDI TX and PCH FDI RX */
+		temp = I915_READ(fdi_tx_reg);
+		temp |= FDI_TX_ENABLE;
+		temp |= FDI_DP_PORT_WIDTH_X4; /* default */
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_PATTERN_1;
+		I915_WRITE(fdi_tx_reg, temp);
+		I915_READ(fdi_tx_reg);
+
+		temp = I915_READ(fdi_rx_reg);
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_PATTERN_1;
+		I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
+		I915_READ(fdi_rx_reg);
+
+		udelay(150);
+
+		/* Train FDI. */
+		/* umask FDI RX Interrupt symbol_lock and bit_lock bit
+		   for train result */
+		temp = I915_READ(fdi_rx_imr_reg);
+		temp &= ~FDI_RX_SYMBOL_LOCK;
+		temp &= ~FDI_RX_BIT_LOCK;
+		I915_WRITE(fdi_rx_imr_reg, temp);
+		I915_READ(fdi_rx_imr_reg);
+		udelay(150);
+
+		temp = I915_READ(fdi_rx_iir_reg);
+		DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+
+		if ((temp & FDI_RX_BIT_LOCK) == 0) {
+			for (j = 0; j < tries; j++) {
+				temp = I915_READ(fdi_rx_iir_reg);
+				DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+				if (temp & FDI_RX_BIT_LOCK)
+					break;
+				udelay(200);
+			}
+			if (j != tries)
+				I915_WRITE(fdi_rx_iir_reg,
+						temp | FDI_RX_BIT_LOCK);
+			else
+				DRM_DEBUG("train 1 fail\n");
+		} else {
+			I915_WRITE(fdi_rx_iir_reg,
+					temp | FDI_RX_BIT_LOCK);
+			DRM_DEBUG("train 1 ok 2!\n");
+		}
+		temp = I915_READ(fdi_tx_reg);
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_PATTERN_2;
+		I915_WRITE(fdi_tx_reg, temp);
+
+		temp = I915_READ(fdi_rx_reg);
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_PATTERN_2;
+		I915_WRITE(fdi_rx_reg, temp);
+
+		udelay(150);
+
+		temp = I915_READ(fdi_rx_iir_reg);
+		DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+
+		if ((temp & FDI_RX_SYMBOL_LOCK) == 0) {
+			for (j = 0; j < tries; j++) {
+				temp = I915_READ(fdi_rx_iir_reg);
+				DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+				if (temp & FDI_RX_SYMBOL_LOCK)
+					break;
+				udelay(200);
+			}
+			if (j != tries) {
+				I915_WRITE(fdi_rx_iir_reg,
+						temp | FDI_RX_SYMBOL_LOCK);
+				DRM_DEBUG("train 2 ok 1!\n");
+			} else
+				DRM_DEBUG("train 2 fail\n");
+		} else {
+			I915_WRITE(fdi_rx_iir_reg, temp | FDI_RX_SYMBOL_LOCK);
+			DRM_DEBUG("train 2 ok 2!\n");
+		}
+		DRM_DEBUG("train done\n");
+
+		/* set transcoder timing */
+		I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
+		I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg));
+		I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg));
+
+		I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg));
+		I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
+		I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
+
+		/* enable PCH transcoder */
+		temp = I915_READ(transconf_reg);
+		I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
+		I915_READ(transconf_reg);
+
+		while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0)
+			;
+
+		/* enable normal */
+
+		temp = I915_READ(fdi_tx_reg);
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
+				FDI_TX_ENHANCE_FRAME_ENABLE);
+		I915_READ(fdi_tx_reg);
+
+		temp = I915_READ(fdi_rx_reg);
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE |
+				FDI_RX_ENHANCE_FRAME_ENABLE);
+		I915_READ(fdi_rx_reg);
+
+		/* wait one idle pattern time */
+		udelay(100);
+
+		intel_crtc_load_lut(crtc);
+
+	break;
+	case DRM_MODE_DPMS_OFF:
+		DRM_DEBUG("crtc %d dpms off\n", pipe);
+
+		/* Disable the VGA plane that we never use */
+		I915_WRITE(CPU_VGACNTRL, VGA_DISP_DISABLE);
+
+		/* Disable display plane */
+		temp = I915_READ(dspcntr_reg);
+		if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
+			I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
+			/* Flush the plane changes */
+			I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+			I915_READ(dspbase_reg);
+		}
+
+		/* disable cpu pipe, disable after all planes disabled */
+		temp = I915_READ(pipeconf_reg);
+		if ((temp & PIPEACONF_ENABLE) != 0) {
+			I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+			I915_READ(pipeconf_reg);
+			/* wait for cpu pipe off, pipe state */
+			while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0)
+				;
+		} else
+			DRM_DEBUG("crtc %d is disabled\n", pipe);
+
+		/* IGDNG-A : disable cpu panel fitter ? */
+		temp = I915_READ(pf_ctl_reg);
+		if ((temp & PF_ENABLE) != 0) {
+			I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE);
+			I915_READ(pf_ctl_reg);
+		}
+
+		/* disable CPU FDI tx and PCH FDI rx */
+		temp = I915_READ(fdi_tx_reg);
+		I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE);
+		I915_READ(fdi_tx_reg);
+
+		temp = I915_READ(fdi_rx_reg);
+		I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE);
+		I915_READ(fdi_rx_reg);
+
+		/* still set train pattern 1 */
+		temp = I915_READ(fdi_tx_reg);
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_PATTERN_1;
+		I915_WRITE(fdi_tx_reg, temp);
+
+		temp = I915_READ(fdi_rx_reg);
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_PATTERN_1;
+		I915_WRITE(fdi_rx_reg, temp);
+
+		/* disable PCH transcoder */
+		temp = I915_READ(transconf_reg);
+		if ((temp & TRANS_ENABLE) != 0) {
+			I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
+			I915_READ(transconf_reg);
+			/* wait for PCH transcoder off, transcoder state */
+			while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0)
+				;
+		}
+
+		/* disable PCH DPLL */
+		temp = I915_READ(pch_dpll_reg);
+		if ((temp & DPLL_VCO_ENABLE) != 0) {
+			I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
+			I915_READ(pch_dpll_reg);
+		}
+
+		temp = I915_READ(fdi_rx_reg);
+		if ((temp & FDI_RX_PLL_ENABLE) != 0) {
+			temp &= ~FDI_SEL_PCDCLK;
+			temp &= ~FDI_RX_PLL_ENABLE;
+			I915_WRITE(fdi_rx_reg, temp);
+			I915_READ(fdi_rx_reg);
+		}
+
+		/* Wait for the clocks to turn off. */
+		udelay(150);
+		break;
+	}
+}
+
+static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+	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;
@@ -805,7 +1209,6 @@
 	int dspbase_reg = (pipe == 0) ? DSPAADDR : DSPBADDR;
 	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.
@@ -890,6 +1293,26 @@
 		udelay(150);
 		break;
 	}
+}
+
+/**
+ * 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 intel_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_master_private *master_priv;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int pipe = intel_crtc->pipe;
+	bool enabled;
+
+	if (IS_IGDNG(dev))
+		igdng_crtc_dpms(crtc, mode);
+	else
+		i9xx_crtc_dpms(crtc, mode);
 
 	if (!dev->primary->master)
 		return;
@@ -947,6 +1370,12 @@
 				  struct drm_display_mode *mode,
 				  struct drm_display_mode *adjusted_mode)
 {
+	struct drm_device *dev = crtc->dev;
+	if (IS_IGDNG(dev)) {
+		/* FDI link clock is fixed at 2.7G */
+		if (mode->clock * 3 > 27000 * 4)
+			return MODE_CLOCK_HIGH;
+	}
 	return true;
 }
 
@@ -1030,6 +1459,48 @@
 	return 1;
 }
 
+struct fdi_m_n {
+	u32        tu;
+	u32        gmch_m;
+	u32        gmch_n;
+	u32        link_m;
+	u32        link_n;
+};
+
+static void
+fdi_reduce_ratio(u32 *num, u32 *den)
+{
+	while (*num > 0xffffff || *den > 0xffffff) {
+		*num >>= 1;
+		*den >>= 1;
+	}
+}
+
+#define DATA_N 0x800000
+#define LINK_N 0x80000
+
+static void
+igdng_compute_m_n(int bytes_per_pixel, int nlanes,
+		int pixel_clock, int link_clock,
+		struct fdi_m_n *m_n)
+{
+	u64 temp;
+
+	m_n->tu = 64; /* default size */
+
+	temp = (u64) DATA_N * pixel_clock;
+	temp = div_u64(temp, link_clock);
+	m_n->gmch_m = (temp * bytes_per_pixel) / nlanes;
+	m_n->gmch_n = DATA_N;
+	fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
+
+	temp = (u64) LINK_N * pixel_clock;
+	m_n->link_m = div_u64(temp, link_clock);
+	m_n->link_n = LINK_N;
+	fdi_reduce_ratio(&m_n->link_m, &m_n->link_n);
+}
+
+
 static int intel_crtc_mode_set(struct drm_crtc *crtc,
 			       struct drm_display_mode *mode,
 			       struct drm_display_mode *adjusted_mode,
@@ -1063,6 +1534,17 @@
 	struct drm_connector *connector;
 	const intel_limit_t *limit;
 	int ret;
+	struct fdi_m_n m_n = {0};
+	int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1;
+	int data_n1_reg = (pipe == 0) ? PIPEA_DATA_N1 : PIPEB_DATA_N1;
+	int link_m1_reg = (pipe == 0) ? PIPEA_LINK_M1 : PIPEB_LINK_M1;
+	int link_n1_reg = (pipe == 0) ? PIPEA_LINK_N1 : PIPEB_LINK_N1;
+	int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0;
+	int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
+	int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
+	int lvds_reg = LVDS;
+	u32 temp;
+	int sdvo_pixel_multiply;
 
 	drm_vblank_pre_modeset(dev, pipe);
 
@@ -1101,6 +1583,8 @@
 		DRM_DEBUG("using SSC reference clock of %d MHz\n", refclk / 1000);
 	} else if (IS_I9XX(dev)) {
 		refclk = 96000;
+		if (IS_IGDNG(dev))
+			refclk = 120000; /* 120Mhz refclk */
 	} else {
 		refclk = 48000;
 	}
@@ -1114,6 +1598,7 @@
 	ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
 	if (!ok) {
 		DRM_ERROR("Couldn't find PLL settings for mode!\n");
+		drm_vblank_post_modeset(dev, pipe);
 		return -EINVAL;
 	}
 
@@ -1137,12 +1622,21 @@
 		}
 	}
 
+	/* FDI link */
+	if (IS_IGDNG(dev))
+		igdng_compute_m_n(3, 4, /* lane num 4 */
+				adjusted_mode->clock,
+				270000, /* lane clock */
+				&m_n);
+
 	if (IS_IGD(dev))
 		fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
 	else
 		fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
 
-	dpll = DPLL_VGA_MODE_DIS;
+	if (!IS_IGDNG(dev))
+		dpll = DPLL_VGA_MODE_DIS;
+
 	if (IS_I9XX(dev)) {
 		if (is_lvds)
 			dpll |= DPLLB_MODE_LVDS;
@@ -1150,17 +1644,22 @@
 			dpll |= DPLLB_MODE_DAC_SERIAL;
 		if (is_sdvo) {
 			dpll |= DPLL_DVO_HIGH_SPEED;
-			if (IS_I945G(dev) || IS_I945GM(dev)) {
-				int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
+			sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
+			if (IS_I945G(dev) || IS_I945GM(dev))
 				dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
-			}
+			else if (IS_IGDNG(dev))
+				dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
 		}
 
 		/* compute bitmask from p1 value */
 		if (IS_IGD(dev))
 			dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_IGD;
-		else
+		else {
 			dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+			/* also FPA1 */
+			if (IS_IGDNG(dev))
+				dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+		}
 		switch (clock.p2) {
 		case 5:
 			dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
@@ -1175,7 +1674,7 @@
 			dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
 			break;
 		}
-		if (IS_I965G(dev))
+		if (IS_I965G(dev) && !IS_IGDNG(dev))
 			dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
 	} else {
 		if (is_lvds) {
@@ -1207,10 +1706,14 @@
 	/* Set up the display plane register */
 	dspcntr = DISPPLANE_GAMMA_ENABLE;
 
-	if (pipe == 0)
-		dspcntr |= DISPPLANE_SEL_PIPE_A;
-	else
-		dspcntr |= DISPPLANE_SEL_PIPE_B;
+	/* IGDNG's plane is forced to pipe, bit 24 is to
+	   enable color space conversion */
+	if (!IS_IGDNG(dev)) {
+		if (pipe == 0)
+			dspcntr |= DISPPLANE_SEL_PIPE_A;
+		else
+			dspcntr |= DISPPLANE_SEL_PIPE_B;
+	}
 
 	if (pipe == 0 && !IS_I965G(dev)) {
 		/* Enable pixel doubling when the dot clock is > 90% of the (display)
@@ -1231,12 +1734,17 @@
 
 
 	/* Disable the panel fitter if it was on our pipe */
-	if (intel_panel_fitter_pipe(dev) == pipe)
+	if (!IS_IGDNG(dev) && intel_panel_fitter_pipe(dev) == pipe)
 		I915_WRITE(PFIT_CONTROL, 0);
 
 	DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
 	drm_mode_debug_printmodeline(mode);
 
+	/* assign to IGDNG registers */
+	if (IS_IGDNG(dev)) {
+		fp_reg = pch_fp_reg;
+		dpll_reg = pch_dpll_reg;
+	}
 
 	if (dpll & DPLL_VCO_ENABLE) {
 		I915_WRITE(fp_reg, fp);
@@ -1245,13 +1753,33 @@
 		udelay(150);
 	}
 
+	if (IS_IGDNG(dev)) {
+		/* enable PCH clock reference source */
+		/* XXX need to change the setting for other outputs */
+		u32 temp;
+		temp = I915_READ(PCH_DREF_CONTROL);
+		temp &= ~DREF_NONSPREAD_SOURCE_MASK;
+		temp |= DREF_NONSPREAD_CK505_ENABLE;
+		temp &= ~DREF_SSC_SOURCE_MASK;
+		temp |= DREF_SSC_SOURCE_ENABLE;
+		temp &= ~DREF_SSC1_ENABLE;
+		/* if no eDP, disable source output to CPU */
+		temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+		temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+		I915_WRITE(PCH_DREF_CONTROL, temp);
+	}
+
 	/* The LVDS pin pair needs to be on before the DPLLs are enabled.
 	 * This is an exception to the general rule that mode_set doesn't turn
 	 * things on.
 	 */
 	if (is_lvds) {
-		u32 lvds = I915_READ(LVDS);
+		u32 lvds;
 
+		if (IS_IGDNG(dev))
+			lvds_reg = PCH_LVDS;
+
+		lvds = I915_READ(lvds_reg);
 		lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT;
 		/* Set the B0-B3 data pairs corresponding to whether we're going to
 		 * set the DPLLs for dual-channel mode or not.
@@ -1266,8 +1794,8 @@
 		 * panels behave in the two modes.
 		 */
 
-		I915_WRITE(LVDS, lvds);
-		I915_READ(LVDS);
+		I915_WRITE(lvds_reg, lvds);
+		I915_READ(lvds_reg);
 	}
 
 	I915_WRITE(fp_reg, fp);
@@ -1276,8 +1804,8 @@
 	/* Wait for the clocks to stabilize. */
 	udelay(150);
 
-	if (IS_I965G(dev)) {
-		int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
+	if (IS_I965G(dev) && !IS_IGDNG(dev)) {
+		sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
 		I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
 			   ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
 	} else {
@@ -1303,9 +1831,25 @@
 	/* pipesrc and dspsize control the size that is scaled from, which should
 	 * always be the user's requested size.
 	 */
-	I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
-	I915_WRITE(dsppos_reg, 0);
+	if (!IS_IGDNG(dev)) {
+		I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) |
+				(mode->hdisplay - 1));
+		I915_WRITE(dsppos_reg, 0);
+	}
 	I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+
+	if (IS_IGDNG(dev)) {
+		I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m);
+		I915_WRITE(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n);
+		I915_WRITE(link_m1_reg, m_n.link_m);
+		I915_WRITE(link_n1_reg, m_n.link_n);
+
+		 /* enable FDI RX PLL too */
+		temp = I915_READ(fdi_rx_reg);
+		I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
+		udelay(200);
+	}
+
 	I915_WRITE(pipeconf_reg, pipeconf);
 	I915_READ(pipeconf_reg);
 
@@ -1315,12 +1859,9 @@
 
 	/* Flush the plane changes */
 	ret = intel_pipe_set_base(crtc, x, y, old_fb);
-	if (ret != 0)
-	    return ret;
-
 	drm_vblank_post_modeset(dev, pipe);
 
-	return 0;
+	return ret;
 }
 
 /** Loads the palette/gamma unit for the CRTC with the prepared values */
@@ -1336,6 +1877,11 @@
 	if (!crtc->enabled)
 		return;
 
+	/* use legacy palette for IGDNG */
+	if (IS_IGDNG(dev))
+		palreg = (intel_crtc->pipe == 0) ? LGC_PALETTE_A :
+						   LGC_PALETTE_B;
+
 	for (i = 0; i < 256; i++) {
 		I915_WRITE(palreg + 4 * i,
 			   (intel_crtc->lut_r[i] << 16) |
@@ -1464,16 +2010,16 @@
 	uint32_t adder;
 
 	if (x < 0) {
-		temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
+		temp |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
 		x = -x;
 	}
 	if (y < 0) {
-		temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
+		temp |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
 		y = -y;
 	}
 
-	temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
-	temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
+	temp |= x << CURSOR_X_SHIFT;
+	temp |= y << CURSOR_Y_SHIFT;
 
 	adder = intel_crtc->cursor_addr;
 	I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp);
@@ -1590,6 +2136,7 @@
 	}
 
 	encoder->crtc = crtc;
+	intel_output->base.encoder = encoder;
 	intel_output->load_detect_temp = true;
 
 	intel_crtc = to_intel_crtc(crtc);
@@ -1625,6 +2172,7 @@
 
 	if (intel_output->load_detect_temp) {
 		encoder->crtc = NULL;
+		intel_output->base.encoder = NULL;
 		intel_output->load_detect_temp = false;
 		crtc->enabled = drm_helper_crtc_in_use(crtc);
 		drm_helper_disable_unused_functions(dev);
@@ -1762,6 +2310,8 @@
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
+	if (intel_crtc->mode_set.mode)
+		drm_mode_destroy(crtc->dev, intel_crtc->mode_set.mode);
 	drm_crtc_cleanup(crtc);
 	kfree(intel_crtc);
 }
@@ -1888,7 +2438,24 @@
 	if (IS_MOBILE(dev) && !IS_I830(dev))
 		intel_lvds_init(dev);
 
-	if (IS_I9XX(dev)) {
+	if (IS_IGDNG(dev)) {
+		int found;
+
+		if (I915_READ(HDMIB) & PORT_DETECTED) {
+			/* check SDVOB */
+			/* found = intel_sdvo_init(dev, HDMIB); */
+			found = 0;
+			if (!found)
+				intel_hdmi_init(dev, HDMIB);
+		}
+
+		if (I915_READ(HDMIC) & PORT_DETECTED)
+			intel_hdmi_init(dev, HDMIC);
+
+		if (I915_READ(HDMID) & PORT_DETECTED)
+			intel_hdmi_init(dev, HDMID);
+
+	} else if (IS_I9XX(dev)) {
 		int found;
 		u32 reg;
 
@@ -1912,7 +2479,7 @@
 	} else
 		intel_dvo_init(dev);
 
-	if (IS_I9XX(dev) && IS_MOBILE(dev))
+	if (IS_I9XX(dev) && IS_MOBILE(dev) && !IS_IGDNG(dev))
 		intel_tv_init(dev);
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index e4652dc..0ecf6b7 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -207,7 +207,7 @@
 
 	if (var->pixclock != -1) {
 
-		DRM_ERROR("PIXEL CLCOK SET\n");
+		DRM_ERROR("PIXEL CLOCK SET\n");
 		return -EINVAL;
 	} else {
 		struct drm_crtc *crtc;
@@ -674,8 +674,12 @@
 	par->crtc_ids[0] = crtc->base.id;
 
 	modeset->num_connectors = conn_count;
-	if (modeset->mode != modeset->crtc->desired_mode)
-		modeset->mode = modeset->crtc->desired_mode;
+	if (modeset->crtc->desired_mode) {
+		if (modeset->mode)
+			drm_mode_destroy(dev, modeset->mode);
+		modeset->mode = drm_mode_duplicate(dev,
+						   modeset->crtc->desired_mode);
+	}
 
 	par->crtc_count = 1;
 
@@ -824,8 +828,12 @@
 		par->crtc_ids[crtc_count++] = crtc->base.id;
 
 		modeset->num_connectors = conn_count;
-		if (modeset->mode != modeset->crtc->desired_mode)
-			modeset->mode = modeset->crtc->desired_mode;
+		if (modeset->crtc->desired_mode) {
+			if (modeset->mode)
+				drm_mode_destroy(dev, modeset->mode);
+			modeset->mode = drm_mode_duplicate(dev,
+							   modeset->crtc->desired_mode);
+		}
 	}
 	par->crtc_count = crtc_count;
 
@@ -857,9 +865,15 @@
 	drm_crtc_helper_set_config(&kernelfb_mode);
 }
 
+static void intelfb_restore_work_fn(struct work_struct *ignored)
+{
+	intelfb_restore();
+}
+static DECLARE_WORK(intelfb_restore_work, intelfb_restore_work_fn);
+
 static void intelfb_sysrq(int dummy1, struct tty_struct *dummy3)
 {
-        intelfb_restore();
+        schedule_work(&intelfb_restore_work);
 }
 
 static struct sysrq_key_op sysrq_intelfb_restore_op = {
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 7d6bdd7..4ea2a65 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -56,7 +56,8 @@
 	sdvox = SDVO_ENCODING_HDMI |
 		SDVO_BORDER_ENABLE |
 		SDVO_VSYNC_ACTIVE_HIGH |
-		SDVO_HSYNC_ACTIVE_HIGH;
+		SDVO_HSYNC_ACTIVE_HIGH |
+		SDVO_NULL_PACKETS_DURING_VSYNC;
 
 	if (hdmi_priv->has_hdmi_sink)
 		sdvox |= SDVO_AUDIO_ENABLE;
@@ -145,6 +146,22 @@
 }
 
 static enum drm_connector_status
+igdng_hdmi_detect(struct drm_connector *connector)
+{
+	struct intel_output *intel_output = to_intel_output(connector);
+	struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
+
+	/* FIXME hotplug detect */
+
+	hdmi_priv->has_hdmi_sink = false;
+	intel_hdmi_sink_detect(connector);
+	if (hdmi_priv->has_hdmi_sink)
+		return connector_status_connected;
+	else
+		return connector_status_disconnected;
+}
+
+static enum drm_connector_status
 intel_hdmi_detect(struct drm_connector *connector)
 {
 	struct drm_device *dev = connector->dev;
@@ -153,6 +170,9 @@
 	struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
 	u32 temp, bit;
 
+	if (IS_IGDNG(dev))
+		return igdng_hdmi_detect(connector);
+
 	temp = I915_READ(PORT_HOTPLUG_EN);
 
 	switch (hdmi_priv->sdvox_reg) {
@@ -269,8 +289,17 @@
 	/* Set up the DDC bus. */
 	if (sdvox_reg == SDVOB)
 		intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
-	else
+	else if (sdvox_reg == SDVOC)
 		intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
+	else if (sdvox_reg == HDMIB)
+		intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
+								"HDMIB");
+	else if (sdvox_reg == HDMIC)
+		intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
+								"HDMIC");
+	else if (sdvox_reg == HDMID)
+		intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
+								"HDMID");
 
 	if (!intel_output->ddc_bus)
 		goto err_connector;
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 53cccfa..f073ed8 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -37,6 +37,8 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
+#define I915_LVDS "i915_lvds"
+
 /**
  * Sets the backlight level.
  *
@@ -45,10 +47,15 @@
 static void intel_lvds_set_backlight(struct drm_device *dev, int level)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 blc_pwm_ctl;
+	u32 blc_pwm_ctl, reg;
 
-	blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-	I915_WRITE(BLC_PWM_CTL, (blc_pwm_ctl |
+	if (IS_IGDNG(dev))
+		reg = BLC_PWM_CPU_CTL;
+	else
+		reg = BLC_PWM_CTL;
+
+	blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+	I915_WRITE(reg, (blc_pwm_ctl |
 				 (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
 }
 
@@ -58,8 +65,14 @@
 static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 reg;
 
-	return ((I915_READ(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >>
+	if (IS_IGDNG(dev))
+		reg = BLC_PWM_PCH_CTL2;
+	else
+		reg = BLC_PWM_CTL;
+
+	return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >>
 		BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
 }
 
@@ -69,23 +82,31 @@
 static void intel_lvds_set_power(struct drm_device *dev, bool on)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 pp_status;
+	u32 pp_status, ctl_reg, status_reg;
+
+	if (IS_IGDNG(dev)) {
+		ctl_reg = PCH_PP_CONTROL;
+		status_reg = PCH_PP_STATUS;
+	} else {
+		ctl_reg = PP_CONTROL;
+		status_reg = PP_STATUS;
+	}
 
 	if (on) {
-		I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) |
+		I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
 			   POWER_TARGET_ON);
 		do {
-			pp_status = I915_READ(PP_STATUS);
+			pp_status = I915_READ(status_reg);
 		} while ((pp_status & PP_ON) == 0);
 
 		intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
 	} else {
 		intel_lvds_set_backlight(dev, 0);
 
-		I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) &
+		I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
 			   ~POWER_TARGET_ON);
 		do {
-			pp_status = I915_READ(PP_STATUS);
+			pp_status = I915_READ(status_reg);
 		} while (pp_status & PP_ON);
 	}
 }
@@ -106,12 +127,28 @@
 {
 	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
+	u32 pwm_ctl_reg;
 
-	dev_priv->savePP_ON = I915_READ(PP_ON_DELAYS);
-	dev_priv->savePP_OFF = I915_READ(PP_OFF_DELAYS);
-	dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
-	dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR);
-	dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
+	if (IS_IGDNG(dev)) {
+		pp_on_reg = PCH_PP_ON_DELAYS;
+		pp_off_reg = PCH_PP_OFF_DELAYS;
+		pp_ctl_reg = PCH_PP_CONTROL;
+		pp_div_reg = PCH_PP_DIVISOR;
+		pwm_ctl_reg = BLC_PWM_CPU_CTL;
+	} else {
+		pp_on_reg = PP_ON_DELAYS;
+		pp_off_reg = PP_OFF_DELAYS;
+		pp_ctl_reg = PP_CONTROL;
+		pp_div_reg = PP_DIVISOR;
+		pwm_ctl_reg = BLC_PWM_CTL;
+	}
+
+	dev_priv->savePP_ON = I915_READ(pp_on_reg);
+	dev_priv->savePP_OFF = I915_READ(pp_off_reg);
+	dev_priv->savePP_CONTROL = I915_READ(pp_ctl_reg);
+	dev_priv->savePP_DIVISOR = I915_READ(pp_div_reg);
+	dev_priv->saveBLC_PWM_CTL = I915_READ(pwm_ctl_reg);
 	dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
 				       BACKLIGHT_DUTY_CYCLE_MASK);
 
@@ -127,12 +164,28 @@
 {
 	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
+	u32 pwm_ctl_reg;
 
-	I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
-	I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON);
-	I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF);
-	I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR);
-	I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
+	if (IS_IGDNG(dev)) {
+		pp_on_reg = PCH_PP_ON_DELAYS;
+		pp_off_reg = PCH_PP_OFF_DELAYS;
+		pp_ctl_reg = PCH_PP_CONTROL;
+		pp_div_reg = PCH_PP_DIVISOR;
+		pwm_ctl_reg = BLC_PWM_CPU_CTL;
+	} else {
+		pp_on_reg = PP_ON_DELAYS;
+		pp_off_reg = PP_OFF_DELAYS;
+		pp_ctl_reg = PP_CONTROL;
+		pp_div_reg = PP_DIVISOR;
+		pwm_ctl_reg = BLC_PWM_CTL;
+	}
+
+	I915_WRITE(pwm_ctl_reg, dev_priv->saveBLC_PWM_CTL);
+	I915_WRITE(pp_on_reg, dev_priv->savePP_ON);
+	I915_WRITE(pp_off_reg, dev_priv->savePP_OFF);
+	I915_WRITE(pp_div_reg, dev_priv->savePP_DIVISOR);
+	I915_WRITE(pp_ctl_reg, dev_priv->savePP_CONTROL);
 	if (dev_priv->savePP_CONTROL & POWER_TARGET_ON)
 		intel_lvds_set_power(dev, true);
 	else
@@ -216,8 +269,14 @@
 {
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 reg;
 
-	dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
+	if (IS_IGDNG(dev))
+		reg = BLC_PWM_CPU_CTL;
+	else
+		reg = BLC_PWM_CTL;
+
+	dev_priv->saveBLC_PWM_CTL = I915_READ(reg);
 	dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
 				       BACKLIGHT_DUTY_CYCLE_MASK);
 
@@ -251,6 +310,10 @@
 	 * settings.
 	 */
 
+	/* No panel fitting yet, fixme */
+	if (IS_IGDNG(dev))
+		return;
+
 	/*
 	 * Enable automatic panel scaling so that non-native modes fill the
 	 * screen.  Should be enabled before the pipe is enabled, according to
@@ -382,7 +445,8 @@
 
 static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
 {
-	DRM_DEBUG("Skipping LVDS initialization for %s\n", id->ident);
+	DRM_DEBUG_KMS(I915_LVDS,
+		      "Skipping LVDS initialization for %s\n", id->ident);
 	return 1;
 }
 
@@ -420,8 +484,21 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "Studio Hybrid 140g"),
 		},
 	},
-
-	/* FIXME: add a check for the Aopen Mini PC */
+	{
+		.callback = intel_no_lvds_dmi_callback,
+		.ident = "AOpen Mini PC",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "AOpen"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "i965GMx-IF"),
+		},
+	},
+	{
+		.callback = intel_no_lvds_dmi_callback,
+		.ident = "Aopen i945GTt-VFA",
+		.matches = {
+			DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"),
+		},
+	},
 
 	{ }	/* terminating entry */
 };
@@ -442,12 +519,18 @@
 	struct drm_display_mode *scan; /* *modes, *bios_mode; */
 	struct drm_crtc *crtc;
 	u32 lvds;
-	int pipe;
+	int pipe, gpio = GPIOC;
 
 	/* Skip init on machines we know falsely report LVDS */
 	if (dmi_check_system(intel_no_lvds))
 		return;
 
+	if (IS_IGDNG(dev)) {
+		if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
+			return;
+		gpio = PCH_GPIOC;
+	}
+
 	intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
 	if (!intel_output) {
 		return;
@@ -482,7 +565,7 @@
 	 */
 
 	/* Set up the DDC bus. */
-	intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C");
+	intel_output->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C");
 	if (!intel_output->ddc_bus) {
 		dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
 			   "failed.\n");
@@ -524,6 +607,11 @@
 	 * on.  If so, assume that whatever is currently programmed is the
 	 * correct mode.
 	 */
+
+	/* IGDNG: FIXME if still fail, not try pipe mode now */
+	if (IS_IGDNG(dev))
+		goto failed;
+
 	lvds = I915_READ(LVDS);
 	pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
 	crtc = intel_get_crtc_from_pipe(dev, pipe);
@@ -542,11 +630,22 @@
 		goto failed;
 
 out:
+	if (IS_IGDNG(dev)) {
+		u32 pwm;
+		/* make sure PWM is enabled */
+		pwm = I915_READ(BLC_PWM_CPU_CTL2);
+		pwm |= (PWM_ENABLE | PWM_PIPE_B);
+		I915_WRITE(BLC_PWM_CPU_CTL2, pwm);
+
+		pwm = I915_READ(BLC_PWM_PCH_CTL1);
+		pwm |= PWM_PCH_ENABLE;
+		I915_WRITE(BLC_PWM_PCH_CTL1, pwm);
+	}
 	drm_sysfs_connector_add(connector);
 	return;
 
 failed:
-	DRM_DEBUG("No LVDS modes found, disabling.\n");
+	DRM_DEBUG_KMS(I915_LVDS, "No LVDS modes found, disabling.\n");
 	if (intel_output->ddc_bus)
 		intel_i2c_destroy(intel_output->ddc_bus);
 	drm_connector_cleanup(connector);
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 3093b4d..9a00adb 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -36,7 +36,7 @@
 #include "intel_sdvo_regs.h"
 
 #undef SDVO_DEBUG
-
+#define I915_SDVO	"i915_sdvo"
 struct intel_sdvo_priv {
 	struct intel_i2c_chan *i2c_bus;
 	int slaveaddr;
@@ -277,20 +277,21 @@
 	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
 	int i;
 
-	printk(KERN_DEBUG "%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd);
+	DRM_DEBUG_KMS(I915_SDVO, "%s: W: %02X ",
+				SDVO_NAME(sdvo_priv), cmd);
 	for (i = 0; i < args_len; i++)
-		printk(KERN_DEBUG "%02X ", ((u8 *)args)[i]);
+		DRM_LOG_KMS("%02X ", ((u8 *)args)[i]);
 	for (; i < 8; i++)
-		printk(KERN_DEBUG "   ");
+		DRM_LOG_KMS("   ");
 	for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) {
 		if (cmd == sdvo_cmd_names[i].cmd) {
-			printk(KERN_DEBUG "(%s)", sdvo_cmd_names[i].name);
+			DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name);
 			break;
 		}
 	}
 	if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0]))
-		printk(KERN_DEBUG "(%02X)", cmd);
-	printk(KERN_DEBUG "\n");
+		DRM_LOG_KMS("(%02X)", cmd);
+	DRM_LOG_KMS("\n");
 }
 #else
 #define intel_sdvo_debug_write(o, c, a, l)
@@ -329,16 +330,16 @@
 	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
 	int i;
 
-	printk(KERN_DEBUG "%s: R: ", SDVO_NAME(sdvo_priv));
+	DRM_DEBUG_KMS(I915_SDVO, "%s: R: ", SDVO_NAME(sdvo_priv));
 	for (i = 0; i < response_len; i++)
-		printk(KERN_DEBUG "%02X ", ((u8 *)response)[i]);
+		DRM_LOG_KMS("%02X ", ((u8 *)response)[i]);
 	for (; i < 8; i++)
-		printk(KERN_DEBUG "   ");
+		DRM_LOG_KMS("   ");
 	if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
-		printk(KERN_DEBUG "(%s)", cmd_status_names[status]);
+		DRM_LOG_KMS("(%s)", cmd_status_names[status]);
 	else
-		printk(KERN_DEBUG "(??? %d)", status);
-	printk(KERN_DEBUG "\n");
+		DRM_LOG_KMS("(??? %d)", status);
+	DRM_LOG_KMS("\n");
 }
 #else
 #define intel_sdvo_debug_response(o, r, l, s)
@@ -1742,6 +1743,43 @@
 	.master_xfer	= intel_sdvo_master_xfer,
 };
 
+static u8
+intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct sdvo_device_mapping *my_mapping, *other_mapping;
+
+	if (output_device == SDVOB) {
+		my_mapping = &dev_priv->sdvo_mappings[0];
+		other_mapping = &dev_priv->sdvo_mappings[1];
+	} else {
+		my_mapping = &dev_priv->sdvo_mappings[1];
+		other_mapping = &dev_priv->sdvo_mappings[0];
+	}
+
+	/* If the BIOS described our SDVO device, take advantage of it. */
+	if (my_mapping->slave_addr)
+		return my_mapping->slave_addr;
+
+	/* If the BIOS only described a different SDVO device, use the
+	 * address that it isn't using.
+	 */
+	if (other_mapping->slave_addr) {
+		if (other_mapping->slave_addr == 0x70)
+			return 0x72;
+		else
+			return 0x70;
+	}
+
+	/* No SDVO device info is found for another DVO port,
+	 * so use mapping assumption we had before BIOS parsing.
+	 */
+	if (output_device == SDVOB)
+		return 0x70;
+	else
+		return 0x72;
+}
+
 bool intel_sdvo_init(struct drm_device *dev, int output_device)
 {
 	struct drm_connector *connector;
@@ -1753,6 +1791,7 @@
 	u8 ch[0x40];
 	int i;
 	int encoder_type, output_id;
+	u8 slave_addr;
 
 	intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
 	if (!intel_output) {
@@ -1771,16 +1810,15 @@
 	if (!i2cbus)
 		goto err_inteloutput;
 
+	slave_addr = intel_sdvo_get_slave_addr(dev, output_device);
 	sdvo_priv->i2c_bus = i2cbus;
 
 	if (output_device == SDVOB) {
 		output_id = 1;
-		sdvo_priv->i2c_bus->slave_addr = 0x38;
 	} else {
 		output_id = 2;
-		sdvo_priv->i2c_bus->slave_addr = 0x39;
 	}
-
+	sdvo_priv->i2c_bus->slave_addr = slave_addr >> 1;
 	sdvo_priv->output_device = output_device;
 	intel_output->i2c_bus = i2cbus;
 	intel_output->dev_priv = sdvo_priv;
@@ -1788,8 +1826,9 @@
 	/* Read the regs to test if we can talk to the device */
 	for (i = 0; i < 0x40; i++) {
 		if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) {
-			DRM_DEBUG("No SDVO device found on SDVO%c\n",
-				  output_device == SDVOB ? 'B' : 'C');
+			DRM_DEBUG_KMS(I915_SDVO,
+					"No SDVO device found on SDVO%c\n",
+					output_device == SDVOB ? 'B' : 'C');
 			goto err_i2c;
 		}
 	}
@@ -1873,9 +1912,10 @@
 
 		sdvo_priv->controlled_output = 0;
 		memcpy (bytes, &sdvo_priv->caps.output_flags, 2);
-		DRM_DEBUG("%s: Unknown SDVO output type (0x%02x%02x)\n",
-			  SDVO_NAME(sdvo_priv),
-			  bytes[0], bytes[1]);
+		DRM_DEBUG_KMS(I915_SDVO,
+				"%s: Unknown SDVO output type (0x%02x%02x)\n",
+				  SDVO_NAME(sdvo_priv),
+				  bytes[0], bytes[1]);
 		encoder_type = DRM_MODE_ENCODER_NONE;
 		connector_type = DRM_MODE_CONNECTOR_Unknown;
 		goto err_i2c;
@@ -1905,21 +1945,21 @@
 					       &sdvo_priv->pixel_clock_max);
 
 
-	DRM_DEBUG("%s device VID/DID: %02X:%02X.%02X, "
-		  "clock range %dMHz - %dMHz, "
-		  "input 1: %c, input 2: %c, "
-		  "output 1: %c, output 2: %c\n",
-		  SDVO_NAME(sdvo_priv),
-		  sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id,
-		  sdvo_priv->caps.device_rev_id,
-		  sdvo_priv->pixel_clock_min / 1000,
-		  sdvo_priv->pixel_clock_max / 1000,
-		  (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
-		  (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
-		  /* check currently supported outputs */
-		  sdvo_priv->caps.output_flags &
+	DRM_DEBUG_KMS(I915_SDVO, "%s device VID/DID: %02X:%02X.%02X, "
+			"clock range %dMHz - %dMHz, "
+			"input 1: %c, input 2: %c, "
+			"output 1: %c, output 2: %c\n",
+			SDVO_NAME(sdvo_priv),
+			sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id,
+			sdvo_priv->caps.device_rev_id,
+			sdvo_priv->pixel_clock_min / 1000,
+			sdvo_priv->pixel_clock_max / 1000,
+			(sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
+			(sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
+			/* check currently supported outputs */
+			sdvo_priv->caps.output_flags &
 			(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N',
-		  sdvo_priv->caps.output_flags &
+			sdvo_priv->caps.output_flags &
 			(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
 
 	return true;
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 98ac054..50d7ed7 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1392,6 +1392,9 @@
 		tv_ctl &= ~TV_TEST_MODE_MASK;
 		tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
 		tv_dac &= ~TVDAC_SENSE_MASK;
+		tv_dac &= ~DAC_A_MASK;
+		tv_dac &= ~DAC_B_MASK;
+		tv_dac &= ~DAC_C_MASK;
 		tv_dac |= (TVDAC_STATE_CHG_EN |
 			   TVDAC_A_SENSE_CTL |
 			   TVDAC_B_SENSE_CTL |
diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c
index bc9d09d..146f357 100644
--- a/drivers/gpu/drm/radeon/r600_cp.c
+++ b/drivers/gpu/drm/radeon/r600_cp.c
@@ -478,26 +478,27 @@
 
 	if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV770)) {
 		RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
-		DRM_INFO("Loading RV770 PFP Microcode\n");
+		DRM_INFO("Loading RV770/RV790 PFP Microcode\n");
 		for (i = 0; i < R700_PFP_UCODE_SIZE; i++)
 			RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV770_pfp_microcode[i]);
 		RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
 
 		RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
-		DRM_INFO("Loading RV770 CP Microcode\n");
+		DRM_INFO("Loading RV770/RV790 CP Microcode\n");
 		for (i = 0; i < R700_PM4_UCODE_SIZE; i++)
 			RADEON_WRITE(R600_CP_ME_RAM_DATA, RV770_cp_microcode[i]);
 		RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
 
-	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV730)) {
+	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV730) ||
+		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV740)) {
 		RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
-		DRM_INFO("Loading RV730 PFP Microcode\n");
+		DRM_INFO("Loading RV730/RV740 PFP Microcode\n");
 		for (i = 0; i < R700_PFP_UCODE_SIZE; i++)
 			RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV730_pfp_microcode[i]);
 		RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
 
 		RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
-		DRM_INFO("Loading RV730 CP Microcode\n");
+		DRM_INFO("Loading RV730/RV740 CP Microcode\n");
 		for (i = 0; i < R700_PM4_UCODE_SIZE; i++)
 			RADEON_WRITE(R600_CP_ME_RAM_DATA, RV730_cp_microcode[i]);
 		RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
@@ -1324,6 +1325,10 @@
 		dev_priv->r700_sc_prim_fifo_size = 0xf9;
 		dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
 		dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
+		if (dev_priv->r600_sx_max_export_pos_size > 16) {
+			dev_priv->r600_sx_max_export_pos_size -= 16;
+			dev_priv->r600_sx_max_export_smx_size += 16;
+		}
 		break;
 	case CHIP_RV710:
 		dev_priv->r600_max_pipes = 2;
@@ -1345,6 +1350,31 @@
 		dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
 		dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
 		break;
+	case CHIP_RV740:
+		dev_priv->r600_max_pipes = 4;
+		dev_priv->r600_max_tile_pipes = 4;
+		dev_priv->r600_max_simds = 8;
+		dev_priv->r600_max_backends = 4;
+		dev_priv->r600_max_gprs = 256;
+		dev_priv->r600_max_threads = 248;
+		dev_priv->r600_max_stack_entries = 512;
+		dev_priv->r600_max_hw_contexts = 8;
+		dev_priv->r600_max_gs_threads = 16 * 2;
+		dev_priv->r600_sx_max_export_size = 256;
+		dev_priv->r600_sx_max_export_pos_size = 32;
+		dev_priv->r600_sx_max_export_smx_size = 224;
+		dev_priv->r600_sq_num_cf_insts = 2;
+
+		dev_priv->r700_sx_num_of_sets = 7;
+		dev_priv->r700_sc_prim_fifo_size = 0x100;
+		dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
+		dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
+
+		if (dev_priv->r600_sx_max_export_pos_size > 16) {
+			dev_priv->r600_sx_max_export_pos_size -= 16;
+			dev_priv->r600_sx_max_export_smx_size += 16;
+		}
+		break;
 	default:
 		break;
 	}
@@ -1493,6 +1523,7 @@
 		break;
 	case CHIP_RV730:
 	case CHIP_RV710:
+	case CHIP_RV740:
 	default:
 		sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x4);
 		break;
@@ -1569,6 +1600,7 @@
 	switch (dev_priv->flags & RADEON_FAMILY_MASK) {
 	case CHIP_RV770:
 	case CHIP_RV730:
+	case CHIP_RV740:
 		gs_prim_buffer_depth = 384;
 		break;
 	case CHIP_RV710:
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index aff90bb..89c4c44 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -2109,7 +2109,7 @@
 
 	/* prebuild the SAREA */
 	sareapage = max_t(unsigned long, SAREA_MAX, PAGE_SIZE);
-	ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER,
+	ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK,
 			 &master_priv->sarea);
 	if (ret) {
 		DRM_ERROR("SAREA setup failed\n");
diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h
index 0c6bfc1..127d045 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.h
+++ b/drivers/gpu/drm/radeon/radeon_drv.h
@@ -146,6 +146,7 @@
 	CHIP_RV770,
 	CHIP_RV730,
 	CHIP_RV710,
+	CHIP_RV740,
 	CHIP_LAST,
 };
 
diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c
index 409e00a..3273808 100644
--- a/drivers/gpu/drm/via/via_dmablit.c
+++ b/drivers/gpu/drm/via/via_dmablit.c
@@ -195,10 +195,8 @@
 	default:
 		vsg->state = dr_via_sg_init;
 	}
-	if (vsg->bounce_buffer) {
-		vfree(vsg->bounce_buffer);
-		vsg->bounce_buffer = NULL;
-	}
+	vfree(vsg->bounce_buffer);
+	vsg->bounce_buffer = NULL;
 	vsg->free_on_sequence = 0;
 }
 
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 7e67dcb..7831a03 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -116,9 +116,16 @@
 	---help---
 	Support for cypress mouse and barcode readers.
 
-config DRAGONRISE_FF
-	tristate "DragonRise Inc. force feedback support"
+config HID_DRAGONRISE
+	tristate "DragonRise Inc. support" if EMBEDDED
 	depends on USB_HID
+	default !EMBEDDED
+	---help---
+	Say Y here if you have DragonRise Inc.game controllers.
+
+config DRAGONRISE_FF
+	bool "DragonRise Inc. force feedback support"
+	depends on HID_DRAGONRISE
 	select INPUT_FF_MEMLESS
 	---help---
 	Say Y here if you want to enable force feedback support for DragonRise Inc.
@@ -160,7 +167,7 @@
 	Support for Logitech devices that are not fully compliant with HID standard.
 
 config LOGITECH_FF
-	bool "Logitech force feedback"
+	bool "Logitech force feedback support"
 	depends on HID_LOGITECH
 	select INPUT_FF_MEMLESS
 	help
@@ -176,7 +183,7 @@
 	  force feedback.
 
 config LOGIRUMBLEPAD2_FF
-	bool "Logitech Rumblepad 2 force feedback"
+	bool "Logitech Rumblepad 2 force feedback support"
 	depends on HID_LOGITECH
 	select INPUT_FF_MEMLESS
 	help
@@ -211,11 +218,19 @@
 	---help---
 	Support for PantherLord/GreenAsia based device support.
 
+config HID_PANTHERLORD
+	tristate "Pantherlord support" if EMBEDDED
+	depends on USB_HID
+	default !EMBEDDED
+	---help---
+	  Say Y here if you have a PantherLord/GreenAsia based game controller
+	  or adapter.
+
 config PANTHERLORD_FF
 	bool "Pantherlord force feedback support"
 	depends on HID_PANTHERLORD
 	select INPUT_FF_MEMLESS
-	help
+	---help---
 	  Say Y here if you have a PantherLord/GreenAsia based game controller
 	  or adapter and want to enable force feedback support for it.
 
@@ -247,15 +262,38 @@
 	---help---
 	Support for Sunplus wireless desktop.
 
-config GREENASIA_FF
-	tristate "GreenAsia (Product ID 0x12) force feedback support"
+config HID_GREENASIA
+	tristate "GreenAsia (Product ID 0x12) support" if EMBEDDED
 	depends on USB_HID
+	default !EMBEDDED
+	---help---
+	  Say Y here if you have a GreenAsia (Product ID 0x12) based game
+	  controller or adapter.
+
+config GREENASIA_FF
+	bool "GreenAsia (Product ID 0x12) force feedback support"
+	depends on HID_GREENASIA
 	select INPUT_FF_MEMLESS
 	---help---
 	Say Y here if you have a GreenAsia (Product ID 0x12) based game controller
 	(like MANTA Warrior MM816 and SpeedLink Strike2 SL-6635) or adapter
 	and want to enable force feedback support for it.
 
+config HID_SMARTJOYPLUS
+	tristate "SmartJoy PLUS PS2/USB adapter support" if EMBEDDED
+	depends on USB_HID
+	default !EMBEDDED
+	---help---
+	Support for SmartJoy PLUS PS2/USB adapter.
+
+config SMARTJOYPLUS_FF
+	bool "SmartJoy PLUS PS2/USB adapter force feedback support"
+	depends on HID_SMARTJOYPLUS
+	select INPUT_FF_MEMLESS
+	---help---
+	Say Y here if you have a SmartJoy PLUS PS2/USB adapter and want to
+	enable force feedback support for it.
+
 config HID_TOPSEED
 	tristate "TopSeed Cyberlink remote control support" if EMBEDDED
 	depends on USB_HID
@@ -263,20 +301,44 @@
 	---help---
 	Say Y if you have a TopSeed Cyberlink remote control.
 
-config THRUSTMASTER_FF
-	tristate "ThrustMaster devices support"
+config HID_THRUSTMASTER
+	tristate "ThrustMaster devices support" if EMBEDDED
 	depends on USB_HID
-	select INPUT_FF_MEMLESS
-	help
+	default !EMBEDDED
+	---help---
 	  Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
-	  a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel.
+	  a THRUSTMASTER Ferrari GT Rumble Wheel.
+
+config THRUSTMASTER_FF
+	bool "ThrustMaster devices force feedback support"
+	depends on HID_THRUSTMASTER
+	select INPUT_FF_MEMLESS
+	---help---
+	  Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
+	  a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel and
+	  want to enable force feedback support for it.
+
+config HID_WACOM
+	tristate "Wacom Bluetooth devices support" if EMBEDDED
+	depends on BT_HIDP
+	default !EMBEDDED
+	---help---
+	Support for Wacom Graphire Bluetooth tablet.
+
+config HID_ZEROPLUS
+	tristate "Zeroplus based game controller support" if EMBEDDED
+	depends on USB_HID
+	default !EMBEDDED
+	---help---
+	  Say Y here if you have a Zeroplus based game controller.
 
 config ZEROPLUS_FF
-	tristate "Zeroplus based game controller support"
-	depends on USB_HID
+	bool "Zeroplus based game controller force feedback support"
+	depends on HID_ZEROPLUS
 	select INPUT_FF_MEMLESS
-	help
-	  Say Y here if you have a Zeroplus based game controller.
+	---help---
+	  Say Y here if you have a Zeroplus based game controller and want
+	  to have force feedback support for it.
 
 endmenu
 
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 1f7cb0f..db35151 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -22,7 +22,7 @@
 obj-$(CONFIG_HID_CHERRY)	+= hid-cherry.o
 obj-$(CONFIG_HID_CHICONY)	+= hid-chicony.o
 obj-$(CONFIG_HID_CYPRESS)	+= hid-cypress.o
-obj-$(CONFIG_DRAGONRISE_FF)	+= hid-drff.o
+obj-$(CONFIG_HID_DRAGONRISE)	+= hid-drff.o
 obj-$(CONFIG_HID_EZKEY)		+= hid-ezkey.o
 obj-$(CONFIG_HID_GYRATION)	+= hid-gyration.o
 obj-$(CONFIG_HID_KENSINGTON)	+= hid-kensington.o
@@ -34,12 +34,14 @@
 obj-$(CONFIG_HID_PANTHERLORD)	+= hid-pl.o
 obj-$(CONFIG_HID_PETALYNX)	+= hid-petalynx.o
 obj-$(CONFIG_HID_SAMSUNG)	+= hid-samsung.o
+obj-$(CONFIG_HID_SMARTJOYPLUS)	+= hid-sjoy.o
 obj-$(CONFIG_HID_SONY)		+= hid-sony.o
 obj-$(CONFIG_HID_SUNPLUS)	+= hid-sunplus.o
-obj-$(CONFIG_GREENASIA_FF)	+= hid-gaff.o
-obj-$(CONFIG_THRUSTMASTER_FF)	+= hid-tmff.o
+obj-$(CONFIG_HID_GREENASIA)	+= hid-gaff.o
+obj-$(CONFIG_HID_THRUSTMASTER)	+= hid-tmff.o
 obj-$(CONFIG_HID_TOPSEED)	+= hid-topseed.o
-obj-$(CONFIG_ZEROPLUS_FF)	+= hid-zpff.o
+obj-$(CONFIG_HID_ZEROPLUS)	+= hid-zpff.o
+obj-$(CONFIG_HID_WACOM)		+= hid-wacom.o
 
 obj-$(CONFIG_USB_HID)		+= usbhid/
 obj-$(CONFIG_USB_MOUSE)		+= usbhid/
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index acbce57..303ccce 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -436,10 +436,6 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY),
 		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
 
-	/* Apple wireless Mighty Mouse */
-	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c),
-		.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
-
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, apple_devices);
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 8551693..f2c21d5 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1312,6 +1312,8 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
 
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 47ac1a7..04359ed 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -137,6 +137,14 @@
     {0, 0x44, "BarrelSwitch"},
     {0, 0x45, "Eraser"},
     {0, 0x46, "TabletPick"},
+    {0, 0x47, "Confidence"},
+    {0, 0x48, "Width"},
+    {0, 0x49, "Height"},
+    {0, 0x51, "ContactID"},
+    {0, 0x52, "InputMode"},
+    {0, 0x53, "DeviceIndex"},
+    {0, 0x54, "ContactCount"},
+    {0, 0x55, "ContactMaximumNumber"},
   { 15, 0, "PhysicalInterfaceDevice" },
     {0, 0x00, "Undefined"},
     {0, 0x01, "Physical_Interface_Device"},
@@ -514,9 +522,11 @@
 	[EV_FF_STATUS] = "ForceFeedbackStatus",
 };
 
-static const char *syncs[2] = {
+static const char *syncs[3] = {
 	[SYN_REPORT] = "Report",		[SYN_CONFIG] = "Config",
+	[SYN_MT_REPORT] = "MT Report",
 };
+
 static const char *keys[KEY_MAX + 1] = {
 	[KEY_RESERVED] = "Reserved",		[KEY_ESC] = "Esc",
 	[KEY_1] = "1",				[KEY_2] = "2",
@@ -734,8 +744,17 @@
 	[ABS_HAT2Y] = "Hat2Y",		[ABS_HAT3X] = "Hat3X",
 	[ABS_HAT3Y] = "Hat 3Y",		[ABS_PRESSURE] = "Pressure",
 	[ABS_DISTANCE] = "Distance",	[ABS_TILT_X] = "XTilt",
-	[ABS_TILT_Y] = "YTilt",		[ABS_TOOL_WIDTH] = "Tool Width",
+	[ABS_TILT_Y] = "YTilt",		[ABS_TOOL_WIDTH] = "ToolWidth",
 	[ABS_VOLUME] = "Volume",	[ABS_MISC] = "Misc",
+	[ABS_MT_TOUCH_MAJOR] = "MTMajor",
+	[ABS_MT_TOUCH_MINOR] = "MTMinor",
+	[ABS_MT_WIDTH_MAJOR] = "MTMajorW",
+	[ABS_MT_WIDTH_MINOR] = "MTMinorW",
+	[ABS_MT_ORIENTATION] = "MTOrientation",
+	[ABS_MT_POSITION_X] = "MTPositionX",
+	[ABS_MT_POSITION_Y] = "MTPositionY",
+	[ABS_MT_TOOL_TYPE] = "MTToolType",
+	[ABS_MT_BLOB_ID] = "MTBlobID",
 };
 
 static const char *misc[MSC_MAX + 1] = {
diff --git a/drivers/hid/hid-drff.c b/drivers/hid/hid-drff.c
index 34f3eb65..a239d20 100644
--- a/drivers/hid/hid-drff.c
+++ b/drivers/hid/hid-drff.c
@@ -32,6 +32,8 @@
 #include <linux/hid.h>
 
 #include "hid-ids.h"
+
+#ifdef CONFIG_DRAGONRISE_FF
 #include "usbhid/usbhid.h"
 
 struct drff_device {
@@ -135,6 +137,12 @@
 
 	return 0;
 }
+#else
+static inline int drff_init(struct hid_device *hid)
+{
+	return 0;
+}
+#endif
 
 static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c
index 510ad3a..8a11ccd 100644
--- a/drivers/hid/hid-gaff.c
+++ b/drivers/hid/hid-gaff.c
@@ -31,6 +31,8 @@
 #include <linux/usb.h>
 #include <linux/hid.h>
 #include "hid-ids.h"
+
+#ifdef CONFIG_GREENASIA_FF
 #include "usbhid/usbhid.h"
 
 struct gaff_device {
@@ -130,6 +132,12 @@
 
 	return 0;
 }
+#else
+static inline int gaff_init(struct hid_device *hdev)
+{
+	return 0;
+}
+#endif
 
 static int ga_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 4d5ee2b..6301010 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -414,8 +414,10 @@
 #define USB_DEVICE_ID_VERNIER_LCSPEC	0x0006
 
 #define USB_VENDOR_ID_WACOM		0x056a
+#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH	0x81
 
 #define USB_VENDOR_ID_WISEGROUP		0x0925
+#define USB_DEVICE_ID_SMARTJOY_PLUS	0x0005
 #define USB_DEVICE_ID_1_PHIDGETSERVO_20	0x8101
 #define USB_DEVICE_ID_4_PHIDGETSERVO_20	0x8104
 #define USB_DEVICE_ID_8_8_4_IF_KIT	0x8201
diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c
index 51aff08..5609970 100644
--- a/drivers/hid/hid-lgff.c
+++ b/drivers/hid/hid-lgff.c
@@ -50,6 +50,12 @@
 	-1
 };
 
+static const signed short ff_joystick_ac[] = {
+	FF_CONSTANT,
+	FF_AUTOCENTER,
+	-1
+};
+
 static const signed short ff_wheel[] = {
 	FF_CONSTANT,
 	FF_AUTOCENTER,
@@ -60,8 +66,8 @@
 	{ 0x046d, 0xc211, ff_rumble },
 	{ 0x046d, 0xc219, ff_rumble },
 	{ 0x046d, 0xc283, ff_joystick },
-	{ 0x046d, 0xc286, ff_joystick },
-	{ 0x046d, 0xc294, ff_joystick },
+	{ 0x046d, 0xc286, ff_joystick_ac },
+	{ 0x046d, 0xc294, ff_wheel },
 	{ 0x046d, 0xc295, ff_joystick },
 	{ 0x046d, 0xca03, ff_wheel },
 };
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index c5b252b..75ed9d2 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -1,13 +1,8 @@
 /*
- *  HID driver for some ntrig "special" devices
+ *  HID driver for N-Trig touchscreens
  *
- *  Copyright (c) 1999 Andreas Gal
- *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
- *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
- *  Copyright (c) 2008 Jiri Slaby
  *  Copyright (c) 2008 Rafi Rubin
+ *  Copyright (c) 2009 Stephane Chatty
  *
  */
 
@@ -29,15 +24,79 @@
 #define nt_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
 					EV_KEY, (c))
 
+struct ntrig_data {
+	__s32 x, y, id, w, h;
+	char reading_a_point, found_contact_id;
+};
+
+/*
+ * this driver is aimed at two firmware versions in circulation:
+ *  - dual pen/finger single touch
+ *  - finger multitouch, pen not working
+ */
+
 static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
 		unsigned long **bit, int *max)
 {
-	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_DIGITIZER &&
-			(usage->hid & 0xff) == 0x47) {
-		nt_map_key_clear(BTN_TOOL_DOUBLETAP);
-		return 1;
+	switch (usage->hid & HID_USAGE_PAGE) {
+
+	case HID_UP_GENDESK:
+		switch (usage->hid) {
+		case HID_GD_X:
+			hid_map_usage(hi, usage, bit, max,
+					EV_ABS, ABS_MT_POSITION_X);
+			input_set_abs_params(hi->input, ABS_X,
+					field->logical_minimum,
+					field->logical_maximum, 0, 0);
+			return 1;
+		case HID_GD_Y:
+			hid_map_usage(hi, usage, bit, max,
+					EV_ABS, ABS_MT_POSITION_Y);
+			input_set_abs_params(hi->input, ABS_Y,
+					field->logical_minimum,
+					field->logical_maximum, 0, 0);
+			return 1;
+		}
+		return 0;
+
+	case HID_UP_DIGITIZER:
+		switch (usage->hid) {
+		/* we do not want to map these for now */
+		case HID_DG_INVERT: /* value is always 0 */
+		case HID_DG_ERASER: /* value is always 0 */
+		case HID_DG_CONTACTID: /* value is useless */
+		case HID_DG_BARRELSWITCH:  /* doubtful */
+		case HID_DG_INPUTMODE:
+		case HID_DG_DEVICEINDEX:
+		case HID_DG_CONTACTCOUNT:
+		case HID_DG_CONTACTMAX:
+			return -1;
+
+		/* original mapping by Rafi Rubin */
+		case HID_DG_CONFIDENCE:
+			nt_map_key_clear(BTN_TOOL_DOUBLETAP);
+			return 1;
+
+		/* width/height mapped on TouchMajor/TouchMinor/Orientation */
+		case HID_DG_WIDTH:
+			hid_map_usage(hi, usage, bit, max,
+					EV_ABS, ABS_MT_TOUCH_MAJOR);
+			return 1;
+		case HID_DG_HEIGHT:
+			hid_map_usage(hi, usage, bit, max,
+					EV_ABS, ABS_MT_TOUCH_MINOR);
+			input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
+					0, 1, 0, 0);
+			return 1;
+		}
+		return 0;
+
+	case 0xff000000:
+		/* we do not want to map these: no input-oriented meaning */
+		return -1;
 	}
+
 	return 0;
 }
 
@@ -51,6 +110,138 @@
 
 	return 0;
 }
+
+/*
+ * this function is called upon all reports
+ * so that we can filter contact point information,
+ * decide whether we are in multi or single touch mode
+ * and call input_mt_sync after each point if necessary
+ */
+static int ntrig_event (struct hid_device *hid, struct hid_field *field,
+		                        struct hid_usage *usage, __s32 value)
+{
+	struct input_dev *input = field->hidinput->input;
+	struct ntrig_data *nd = hid_get_drvdata(hid);
+
+        if (hid->claimed & HID_CLAIMED_INPUT) {
+		switch (usage->hid) {
+		case HID_GD_X:
+			nd->x = value;
+			nd->reading_a_point = 1;
+			break;
+		case HID_GD_Y:
+			nd->y = value;
+			break;
+		case HID_DG_CONTACTID:
+			nd->id = value;
+			/* we receive this only when in multitouch mode */
+			nd->found_contact_id = 1;
+			break;
+		case HID_DG_WIDTH:
+			nd->w = value;
+			break;
+		case HID_DG_HEIGHT:
+			nd->h = value;
+			/*
+			 * when in single touch mode, this is the last
+			 * report received in a finger event. We want
+			 * to emit a normal (X, Y) position
+			 */
+			if (! nd->found_contact_id) {
+				input_event(input, EV_ABS, ABS_X, nd->x);
+				input_event(input, EV_ABS, ABS_Y, nd->y);
+			}
+			break;
+		case HID_DG_TIPPRESSURE:
+			/*
+			 * when in single touch mode, this is the last
+			 * report received in a pen event. We want
+			 * to emit a normal (X, Y) position
+			 */
+			if (! nd->found_contact_id) {
+				input_event(input, EV_ABS, ABS_X, nd->x);
+				input_event(input, EV_ABS, ABS_Y, nd->y);
+				input_event(input, EV_ABS, ABS_PRESSURE, value);
+			}
+			break;
+		case 0xff000002:
+			/*
+			 * we receive this when the device is in multitouch
+			 * mode. The first of the three values tagged with
+			 * this usage tells if the contact point is real
+			 * or a placeholder
+			 */
+			if (!nd->reading_a_point || value != 1)
+				break;
+			/* emit a normal (X, Y) for the first point only */
+			if (nd->id == 0) {
+				input_event(input, EV_ABS, ABS_X, nd->x);
+				input_event(input, EV_ABS, ABS_Y, nd->y);
+			}
+			input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x);
+			input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y);
+			if (nd->w > nd->h) {
+				input_event(input, EV_ABS,
+						ABS_MT_ORIENTATION, 1);
+				input_event(input, EV_ABS,
+						ABS_MT_TOUCH_MAJOR, nd->w);
+				input_event(input, EV_ABS,
+						ABS_MT_TOUCH_MINOR, nd->h);
+			} else {
+				input_event(input, EV_ABS,
+						ABS_MT_ORIENTATION, 0);
+				input_event(input, EV_ABS,
+						ABS_MT_TOUCH_MAJOR, nd->h);
+				input_event(input, EV_ABS,
+						ABS_MT_TOUCH_MINOR, nd->w);
+			}
+			input_mt_sync(field->hidinput->input);
+			nd->reading_a_point = 0;
+			nd->found_contact_id = 0;
+			break;
+
+		default:
+			/* fallback to the generic hidinput handling */
+			return 0;
+		}
+	}
+
+	/* we have handled the hidinput part, now remains hiddev */
+        if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+                hid->hiddev_hid_event(hid, field, usage, value);
+
+	return 1;
+}
+
+static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int ret;
+	struct ntrig_data *nd;
+
+	nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL);
+	if (!nd) {
+		dev_err(&hdev->dev, "cannot allocate N-Trig data\n");
+		return -ENOMEM;
+	}
+	nd->reading_a_point = 0;
+	nd->found_contact_id = 0;
+	hid_set_drvdata(hdev, nd);
+
+	ret = hid_parse(hdev);
+	if (!ret)
+		ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+	if (ret)
+		kfree (nd);
+	return ret;
+}
+
+static void ntrig_remove(struct hid_device *hdev)
+{
+	hid_hw_stop(hdev);
+	kfree(hid_get_drvdata(hdev));
+}
+
 static const struct hid_device_id ntrig_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN),
 		.driver_data = NTRIG_DUPLICATE_USAGES },
@@ -58,11 +249,20 @@
 };
 MODULE_DEVICE_TABLE(hid, ntrig_devices);
 
+static const struct hid_usage_id ntrig_grabbed_usages[] = {
+	{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+	{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
 static struct hid_driver ntrig_driver = {
 	.name = "ntrig",
 	.id_table = ntrig_devices,
+	.probe = ntrig_probe,
+	.remove = ntrig_remove,
 	.input_mapping = ntrig_input_mapping,
 	.input_mapped = ntrig_input_mapped,
+	.usage_table = ntrig_grabbed_usages,
+	.event = ntrig_event,
 };
 
 static int ntrig_init(void)
diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c
new file mode 100644
index 0000000..eab169e
--- /dev/null
+++ b/drivers/hid/hid-sjoy.c
@@ -0,0 +1,180 @@
+/*
+ *  Force feedback support for SmartJoy PLUS PS2->USB adapter
+ *
+ *  Copyright (c) 2009 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ *  Based of hid-pl.c and hid-gaff.c
+ *   Copyright (c) 2007, 2009 Anssi Hannula <anssi.hannula@gmail.com>
+ *   Copyright (c) 2008 Lukasz Lubojanski <lukasz@lubojanski.info>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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
+ */
+
+/* #define DEBUG */
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "hid-ids.h"
+
+#ifdef CONFIG_SMARTJOYPLUS_FF
+#include "usbhid/usbhid.h"
+
+struct sjoyff_device {
+	struct hid_report *report;
+};
+
+static int hid_sjoyff_play(struct input_dev *dev, void *data,
+			 struct ff_effect *effect)
+{
+	struct hid_device *hid = input_get_drvdata(dev);
+	struct sjoyff_device *sjoyff = data;
+	u32 left, right;
+
+	left = effect->u.rumble.strong_magnitude;
+	right = effect->u.rumble.weak_magnitude;
+	dev_dbg(&dev->dev, "called with 0x%08x 0x%08x\n", left, right);
+
+	left = left * 0xff / 0xffff;
+	right = (right != 0); /* on/off only */
+
+	sjoyff->report->field[0]->value[1] = right;
+	sjoyff->report->field[0]->value[2] = left;
+	dev_dbg(&dev->dev, "running with 0x%02x 0x%02x\n", left, right);
+	usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
+
+	return 0;
+}
+
+static int sjoyff_init(struct hid_device *hid)
+{
+	struct sjoyff_device *sjoyff;
+	struct hid_report *report;
+	struct hid_input *hidinput = list_entry(hid->inputs.next,
+						struct hid_input, list);
+	struct list_head *report_list =
+			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct list_head *report_ptr = report_list;
+	struct input_dev *dev;
+	int error;
+
+	if (list_empty(report_list)) {
+		dev_err(&hid->dev, "no output reports found\n");
+		return -ENODEV;
+	}
+
+	report_ptr = report_ptr->next;
+
+	if (report_ptr == report_list) {
+		dev_err(&hid->dev, "required output report is "
+				"missing\n");
+		return -ENODEV;
+	}
+
+	report = list_entry(report_ptr, struct hid_report, list);
+	if (report->maxfield < 1) {
+		dev_err(&hid->dev, "no fields in the report\n");
+		return -ENODEV;
+	}
+
+	if (report->field[0]->report_count < 3) {
+		dev_err(&hid->dev, "not enough values in the field\n");
+		return -ENODEV;
+	}
+
+	sjoyff = kzalloc(sizeof(struct sjoyff_device), GFP_KERNEL);
+	if (!sjoyff)
+		return -ENOMEM;
+
+	dev = hidinput->input;
+
+	set_bit(FF_RUMBLE, dev->ffbit);
+
+	error = input_ff_create_memless(dev, sjoyff, hid_sjoyff_play);
+	if (error) {
+		kfree(sjoyff);
+		return error;
+	}
+
+	sjoyff->report = report;
+	sjoyff->report->field[0]->value[0] = 0x01;
+	sjoyff->report->field[0]->value[1] = 0x00;
+	sjoyff->report->field[0]->value[2] = 0x00;
+	usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
+
+	dev_info(&hid->dev,
+		"Force feedback for SmartJoy PLUS PS2/USB adapter\n");
+
+	return 0;
+}
+#else
+static inline int sjoyff_init(struct hid_device *hid)
+{
+	return 0;
+}
+#endif
+
+static int sjoy_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int ret;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err;
+	}
+
+	sjoyff_init(hdev);
+
+	return 0;
+err:
+	return ret;
+}
+
+static const struct hid_device_id sjoy_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, sjoy_devices);
+
+static struct hid_driver sjoy_driver = {
+	.name = "smartjoyplus",
+	.id_table = sjoy_devices,
+	.probe = sjoy_probe,
+};
+
+static int sjoy_init(void)
+{
+	return hid_register_driver(&sjoy_driver);
+}
+
+static void sjoy_exit(void)
+{
+	hid_unregister_driver(&sjoy_driver);
+}
+
+module_init(sjoy_init);
+module_exit(sjoy_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jussi Kivilinna");
+
diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c
index 7c1f7b5..fcd6ccd 100644
--- a/drivers/hid/hid-tmff.c
+++ b/drivers/hid/hid-tmff.c
@@ -33,11 +33,6 @@
 
 #include "hid-ids.h"
 
-#include "usbhid/usbhid.h"
-
-/* Usages for thrustmaster devices I know about */
-#define THRUSTMASTER_USAGE_FF	(HID_UP_GENDESK | 0xbb)
-
 static const signed short ff_rumble[] = {
 	FF_RUMBLE,
 	-1
@@ -48,6 +43,12 @@
 	-1
 };
 
+#ifdef CONFIG_THRUSTMASTER_FF
+#include "usbhid/usbhid.h"
+
+/* Usages for thrustmaster devices I know about */
+#define THRUSTMASTER_USAGE_FF	(HID_UP_GENDESK | 0xbb)
+
 struct tmff_device {
 	struct hid_report *report;
 	struct hid_field *ff_field;
@@ -209,6 +210,12 @@
 	kfree(tmff);
 	return error;
 }
+#else
+static inline int tmff_init(struct hid_device *hid, const signed short *ff_bits)
+{
+	return 0;
+}
+#endif
 
 static int tm_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
new file mode 100644
index 0000000..1f9237f
--- /dev/null
+++ b/drivers/hid/hid-wacom.c
@@ -0,0 +1,259 @@
+/*
+ *  Bluetooth Wacom Tablet support
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
+ *  Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
+ *  Copyright (c) 2009 Bastien Nocera <hadess@hadess.net>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+struct wacom_data {
+	__u16 tool;
+	unsigned char butstate;
+};
+
+static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
+		u8 *raw_data, int size)
+{
+	struct wacom_data *wdata = hid_get_drvdata(hdev);
+	struct hid_input *hidinput;
+	struct input_dev *input;
+	unsigned char *data = (unsigned char *) raw_data;
+	int tool, x, y, rw;
+
+	if (!(hdev->claimed & HID_CLAIMED_INPUT))
+		return 0;
+
+	tool = 0;
+	hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
+	input = hidinput->input;
+
+	/* Check if this is a tablet report */
+	if (data[0] != 0x03)
+		return 0;
+
+	/* Get X & Y positions */
+	x = le16_to_cpu(*(__le16 *) &data[2]);
+	y = le16_to_cpu(*(__le16 *) &data[4]);
+
+	/* Get current tool identifier */
+	if (data[1] & 0x90) { /* If pen is in the in/active area */
+		switch ((data[1] >> 5) & 3) {
+		case 0:	/* Pen */
+			tool = BTN_TOOL_PEN;
+			break;
+
+		case 1: /* Rubber */
+			tool = BTN_TOOL_RUBBER;
+			break;
+
+		case 2: /* Mouse with wheel */
+		case 3: /* Mouse without wheel */
+			tool = BTN_TOOL_MOUSE;
+			break;
+		}
+
+		/* Reset tool if out of active tablet area */
+		if (!(data[1] & 0x10))
+			tool = 0;
+	}
+
+	/* If tool changed, notify input subsystem */
+	if (wdata->tool != tool) {
+		if (wdata->tool) {
+			/* Completely reset old tool state */
+			if (wdata->tool == BTN_TOOL_MOUSE) {
+				input_report_key(input, BTN_LEFT, 0);
+				input_report_key(input, BTN_RIGHT, 0);
+				input_report_key(input, BTN_MIDDLE, 0);
+				input_report_abs(input, ABS_DISTANCE,
+						input->absmax[ABS_DISTANCE]);
+			} else {
+				input_report_key(input, BTN_TOUCH, 0);
+				input_report_key(input, BTN_STYLUS, 0);
+				input_report_key(input, BTN_STYLUS2, 0);
+				input_report_abs(input, ABS_PRESSURE, 0);
+			}
+			input_report_key(input, wdata->tool, 0);
+			input_sync(input);
+		}
+		wdata->tool = tool;
+		if (tool)
+			input_report_key(input, tool, 1);
+	}
+
+	if (tool) {
+		input_report_abs(input, ABS_X, x);
+		input_report_abs(input, ABS_Y, y);
+
+		switch ((data[1] >> 5) & 3) {
+		case 2: /* Mouse with wheel */
+			input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
+			rw = (data[6] & 0x01) ? -1 :
+				(data[6] & 0x02) ? 1 : 0;
+			input_report_rel(input, REL_WHEEL, rw);
+			/* fall through */
+
+		case 3: /* Mouse without wheel */
+			input_report_key(input, BTN_LEFT, data[1] & 0x01);
+			input_report_key(input, BTN_RIGHT, data[1] & 0x02);
+			/* Compute distance between mouse and tablet */
+			rw = 44 - (data[6] >> 2);
+			if (rw < 0)
+				rw = 0;
+			else if (rw > 31)
+				rw = 31;
+			input_report_abs(input, ABS_DISTANCE, rw);
+			break;
+
+		default:
+			input_report_abs(input, ABS_PRESSURE,
+					data[6] | (((__u16) (data[1] & 0x08)) << 5));
+			input_report_key(input, BTN_TOUCH, data[1] & 0x01);
+			input_report_key(input, BTN_STYLUS, data[1] & 0x02);
+			input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04);
+			break;
+		}
+
+		input_sync(input);
+	}
+
+	/* Report the state of the two buttons at the top of the tablet
+	 * as two extra fingerpad keys (buttons 4 & 5). */
+	rw = data[7] & 0x03;
+	if (rw != wdata->butstate) {
+		wdata->butstate = rw;
+		input_report_key(input, BTN_0, rw & 0x02);
+		input_report_key(input, BTN_1, rw & 0x01);
+		input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
+		input_sync(input);
+	}
+
+	return 1;
+}
+
+static int wacom_probe(struct hid_device *hdev,
+		const struct hid_device_id *id)
+{
+	struct hid_input *hidinput;
+	struct input_dev *input;
+	struct wacom_data *wdata;
+	int ret;
+
+	wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
+	if (wdata == NULL) {
+		dev_err(&hdev->dev, "can't alloc wacom descriptor\n");
+		return -ENOMEM;
+	}
+
+	hid_set_drvdata(hdev, wdata);
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto err_free;
+	}
+
+	hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
+	input = hidinput->input;
+
+	/* Basics */
+	input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
+	input->absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) |
+		BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
+	input->relbit[0] |= BIT(REL_WHEEL);
+	set_bit(BTN_TOOL_PEN, input->keybit);
+	set_bit(BTN_TOUCH, input->keybit);
+	set_bit(BTN_STYLUS, input->keybit);
+	set_bit(BTN_STYLUS2, input->keybit);
+	set_bit(BTN_LEFT, input->keybit);
+	set_bit(BTN_RIGHT, input->keybit);
+	set_bit(BTN_MIDDLE, input->keybit);
+
+	/* Pad */
+	input->evbit[0] |= BIT(EV_MSC);
+	input->mscbit[0] |= BIT(MSC_SERIAL);
+
+	/* Distance, rubber and mouse */
+	input->absbit[0] |= BIT(ABS_DISTANCE);
+	set_bit(BTN_TOOL_RUBBER, input->keybit);
+	set_bit(BTN_TOOL_MOUSE, input->keybit);
+
+	input->absmax[ABS_PRESSURE] = 511;
+	input->absmax[ABS_DISTANCE] = 32;
+
+	input->absmax[ABS_X] = 16704;
+	input->absmax[ABS_Y] = 12064;
+	input->absfuzz[ABS_X] = 4;
+	input->absfuzz[ABS_Y] = 4;
+
+	return 0;
+err_free:
+	kfree(wdata);
+	return ret;
+}
+
+static void wacom_remove(struct hid_device *hdev)
+{
+	hid_hw_stop(hdev);
+	kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id wacom_devices[] = {
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
+
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, wacom_devices);
+
+static struct hid_driver wacom_driver = {
+	.name = "wacom",
+	.id_table = wacom_devices,
+	.probe = wacom_probe,
+	.remove = wacom_remove,
+	.raw_event = wacom_raw_event,
+};
+
+static int wacom_init(void)
+{
+	int ret;
+
+	ret = hid_register_driver(&wacom_driver);
+	if (ret)
+		printk(KERN_ERR "can't register wacom driver\n");
+	printk(KERN_ERR "wacom driver registered\n");
+	return ret;
+}
+
+static void wacom_exit(void)
+{
+	hid_unregister_driver(&wacom_driver);
+}
+
+module_init(wacom_init);
+module_exit(wacom_exit);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c
index 85a198a..57f7107 100644
--- a/drivers/hid/hid-zpff.c
+++ b/drivers/hid/hid-zpff.c
@@ -27,6 +27,7 @@
 
 #include "hid-ids.h"
 
+#ifdef CONFIG_ZEROPLUS_FF
 #include "usbhid/usbhid.h"
 
 struct zpff_device {
@@ -108,6 +109,12 @@
 
 	return 0;
 }
+#else
+static inline int zpff_init(struct hid_device *hid)
+{
+	return 0;
+}
+#endif
 
 static int zp_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 00ccf4b..0c6639e 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -349,10 +349,7 @@
 	int minor, result;
 	struct hidraw *dev;
 
-	/* TODO currently we accept any HID device. This should later
-	 * probably be fixed to accept only those devices which provide
-	 * non-input applications
-	 */
+	/* we accept any HID device, no matter the applications */
 
 	dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL);
 	if (!dev)
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index ac8049b..76c4bbe 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -1234,12 +1234,11 @@
 	struct hid_device *hid = usb_get_intfdata(intf);
 	struct usbhid_device *usbhid = hid->driver_data;
 	int status;
- 
+
 	spin_lock_irq(&usbhid->lock);
 	clear_bit(HID_RESET_PENDING, &usbhid->iofl);
 	spin_unlock_irq(&usbhid->lock);
 	hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
-	/* FIXME: Any more reinitialization needed? */
 	status = hid_start_in(hid);
 	if (status < 0)
 		hid_io_error(hid);
@@ -1251,14 +1250,14 @@
 int usbhid_get_power(struct hid_device *hid)
 {
 	struct usbhid_device *usbhid = hid->driver_data;
- 
+
 	return usb_autopm_get_interface(usbhid->intf);
 }
 
 void usbhid_put_power(struct hid_device *hid)
 {
 	struct usbhid_device *usbhid = hid->driver_data;
- 
+
 	usb_autopm_put_interface(usbhid->intf);
 }
 
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index f1c6ca7..c8460fa 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -298,7 +298,7 @@
 config I2C_BLACKFIN_TWI_CLK_KHZ
 	int "Blackfin TWI I2C clock (kHz)"
 	depends on I2C_BLACKFIN_TWI
-	range 10 400
+	range 21 400
 	default 50
 	help
 	  The unit of the TWI clock is kHz.
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index fc548b3..26d8987 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -104,9 +104,14 @@
 			write_MASTER_CTL(iface,
 				read_MASTER_CTL(iface) | STOP);
 		else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
-				iface->cur_msg+1 < iface->msg_num)
-			write_MASTER_CTL(iface,
-				read_MASTER_CTL(iface) | RSTART);
+		         iface->cur_msg + 1 < iface->msg_num) {
+			if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
+				write_MASTER_CTL(iface,
+					read_MASTER_CTL(iface) | RSTART | MDIR);
+			else
+				write_MASTER_CTL(iface,
+					(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
+		}
 		SSYNC();
 		/* Clear status */
 		write_INT_STAT(iface, XMTSERV);
@@ -134,9 +139,13 @@
 				read_MASTER_CTL(iface) | STOP);
 			SSYNC();
 		} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
-				iface->cur_msg+1 < iface->msg_num) {
-			write_MASTER_CTL(iface,
-				read_MASTER_CTL(iface) | RSTART);
+		           iface->cur_msg + 1 < iface->msg_num) {
+			if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
+				write_MASTER_CTL(iface,
+					read_MASTER_CTL(iface) | RSTART | MDIR);
+			else
+				write_MASTER_CTL(iface,
+					(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
 			SSYNC();
 		}
 		/* Clear interrupt source */
@@ -196,8 +205,6 @@
 			/* remove restart bit and enable master receive */
 			write_MASTER_CTL(iface,
 				read_MASTER_CTL(iface) & ~RSTART);
-			write_MASTER_CTL(iface,
-				read_MASTER_CTL(iface) | MEN | MDIR);
 			SSYNC();
 		} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
 				iface->cur_msg+1 < iface->msg_num) {
@@ -222,18 +229,19 @@
 			}
 
 			if (iface->pmsg[iface->cur_msg].len <= 255)
-				write_MASTER_CTL(iface,
-				iface->pmsg[iface->cur_msg].len << 6);
+					write_MASTER_CTL(iface,
+					(read_MASTER_CTL(iface) &
+					(~(0xff << 6))) |
+				(iface->pmsg[iface->cur_msg].len << 6));
 			else {
-				write_MASTER_CTL(iface, 0xff << 6);
+				write_MASTER_CTL(iface,
+					(read_MASTER_CTL(iface) |
+					(0xff << 6)));
 				iface->manual_stop = 1;
 			}
 			/* remove restart bit and enable master receive */
 			write_MASTER_CTL(iface,
 				read_MASTER_CTL(iface) & ~RSTART);
-			write_MASTER_CTL(iface, read_MASTER_CTL(iface) |
-				MEN | ((iface->read_write == I2C_SMBUS_READ) ?
-				MDIR : 0));
 			SSYNC();
 		} else {
 			iface->result = 1;
@@ -441,6 +449,16 @@
 		}
 		iface->transPtr = data->block;
 		break;
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			iface->readNum = data->block[0];
+			iface->cur_mode = TWI_I2C_MODE_COMBINED;
+		} else {
+			iface->writeNum = data->block[0];
+			iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+		}
+		iface->transPtr = (u8 *)&data->block[1];
+		break;
 	default:
 		return -1;
 	}
@@ -564,7 +582,7 @@
 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
 	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
 	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
-	       I2C_FUNC_I2C;
+	       I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK;
 }
 
 static struct i2c_algorithm bfin_twi_algorithm = {
@@ -614,6 +632,7 @@
 	struct i2c_adapter *p_adap;
 	struct resource *res;
 	int rc;
+	unsigned int clkhilow;
 
 	iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL);
 	if (!iface) {
@@ -675,10 +694,14 @@
 	/* Set TWI internal clock as 10MHz */
 	write_CONTROL(iface, ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
 
+	/*
+	 * We will not end up with a CLKDIV=0 because no one will specify
+	 * 20kHz SCL or less in Kconfig now. (5 * 1024 / 20 = 0x100)
+	 */
+	clkhilow = 5 * 1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ;
+
 	/* Set Twi interface clock as specified */
-	write_CLKDIV(iface, ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ)
-			<< 8) | ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ)
-			& 0xFF));
+	write_CLKDIV(iface, (clkhilow << 8) | clkhilow);
 
 	/* Enable TWI */
 	write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index e5193bf..3542c6b 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -216,6 +216,7 @@
 	struct ocores_i2c_platform_data *pdata;
 	struct resource *res, *res2;
 	int ret;
+	int i;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -271,6 +272,10 @@
 		goto add_adapter_failed;
 	}
 
+	/* add in known devices to the bus */
+	for (i = 0; i < pdata->num_devices; i++)
+		i2c_new_device(&i2c->adap, pdata->devices + i);
+
 	return 0;
 
 add_adapter_failed:
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index ece0125..c73475d 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -333,8 +333,18 @@
 
 	if (cpu_is_omap2430() || cpu_is_omap34xx()) {
 
-		/* HSI2C controller internal clk rate should be 19.2 Mhz */
-		internal_clk = 19200;
+		/*
+		 * HSI2C controller internal clk rate should be 19.2 Mhz for
+		 * HS and for all modes on 2430. On 34xx we can use lower rate
+		 * to get longer filter period for better noise suppression.
+		 * The filter is iclk (fclk for HS) period.
+		 */
+		if (dev->speed > 400 || cpu_is_omap_2430())
+			internal_clk = 19200;
+		else if (dev->speed > 100)
+			internal_clk = 9600;
+		else
+			internal_clk = 4000;
 		fclk_rate = clk_get_rate(dev->fclk) / 1000;
 
 		/* Compute prescaler divisor */
@@ -343,17 +353,28 @@
 
 		/* If configured for High Speed */
 		if (dev->speed > 400) {
+			unsigned long scl;
+
 			/* For first phase of HS mode */
-			fsscll = internal_clk / (400 * 2) - 6;
-			fssclh = internal_clk / (400 * 2) - 6;
+			scl = internal_clk / 400;
+			fsscll = scl - (scl / 3) - 7;
+			fssclh = (scl / 3) - 5;
 
 			/* For second phase of HS mode */
-			hsscll = fclk_rate / (dev->speed * 2) - 6;
-			hssclh = fclk_rate / (dev->speed * 2) - 6;
+			scl = fclk_rate / dev->speed;
+			hsscll = scl - (scl / 3) - 7;
+			hssclh = (scl / 3) - 5;
+		} else if (dev->speed > 100) {
+			unsigned long scl;
+
+			/* Fast mode */
+			scl = internal_clk / dev->speed;
+			fsscll = scl - (scl / 3) - 7;
+			fssclh = (scl / 3) - 5;
 		} else {
-			/* To handle F/S modes */
-			fsscll = internal_clk / (dev->speed * 2) - 6;
-			fssclh = internal_clk / (dev->speed * 2) - 6;
+			/* Standard mode */
+			fsscll = internal_clk / (dev->speed * 2) - 7;
+			fssclh = internal_clk / (dev->speed * 2) - 5;
 		}
 		scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;
 		sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh;
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index acc7143..035a6c7 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -34,10 +34,24 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 
-#include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
+
+/*
+ * I2C register offsets will be shifted 0 or 1 bit left, depending on
+ * different SoCs
+ */
+#define REG_SHIFT_0	(0 << 0)
+#define REG_SHIFT_1	(1 << 0)
+#define REG_SHIFT(d)	((d) & 0x1)
+
+static const struct platform_device_id i2c_pxa_id_table[] = {
+	{ "pxa2xx-i2c",		REG_SHIFT_1 },
+	{ "pxa3xx-pwri2c",	REG_SHIFT_0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
 
 /*
  * I2C registers and bit definitions
@@ -985,6 +999,7 @@
 	struct pxa_i2c *i2c;
 	struct resource *res;
 	struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
+	struct platform_device_id *id = platform_get_device_id(dev);
 	int ret;
 	int irq;
 
@@ -1028,7 +1043,7 @@
 		ret = -EIO;
 		goto eremap;
 	}
-	i2c->reg_shift = (cpu_is_pxa3xx() && (dev->id == 1)) ? 0 : 1;
+	i2c->reg_shift = REG_SHIFT(id->driver_data);
 
 	i2c->iobase = res->start;
 	i2c->iosize = res_len(res);
@@ -1150,6 +1165,7 @@
 		.name	= "pxa2xx-i2c",
 		.owner	= THIS_MODULE,
 	},
+	.id_table	= i2c_pxa_id_table,
 };
 
 static int __init i2c_adap_pxa_init(void)
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 1691ef0..079a312 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -51,6 +51,11 @@
 	STATE_STOP
 };
 
+enum s3c24xx_i2c_type {
+	TYPE_S3C2410,
+	TYPE_S3C2440,
+};
+
 struct s3c24xx_i2c {
 	spinlock_t		lock;
 	wait_queue_head_t	wait;
@@ -88,8 +93,10 @@
 static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c)
 {
 	struct platform_device *pdev = to_platform_device(i2c->dev);
+	enum s3c24xx_i2c_type type;
 
-	return !strcmp(pdev->name, "s3c2440-i2c");
+	type = platform_get_device_id(pdev)->driver_data;
+	return type == TYPE_S3C2440;
 }
 
 /* s3c24xx_i2c_master_complete
@@ -969,52 +976,41 @@
 
 /* device driver for platform bus bits */
 
-static struct platform_driver s3c2410_i2c_driver = {
-	.probe		= s3c24xx_i2c_probe,
-	.remove		= s3c24xx_i2c_remove,
-	.suspend_late	= s3c24xx_i2c_suspend_late,
-	.resume		= s3c24xx_i2c_resume,
-	.driver		= {
-		.owner	= THIS_MODULE,
-		.name	= "s3c2410-i2c",
-	},
+static struct platform_device_id s3c24xx_driver_ids[] = {
+	{
+		.name		= "s3c2410-i2c",
+		.driver_data	= TYPE_S3C2410,
+	}, {
+		.name		= "s3c2440-i2c",
+		.driver_data	= TYPE_S3C2440,
+	}, { },
 };
+MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
 
-static struct platform_driver s3c2440_i2c_driver = {
+static struct platform_driver s3c24xx_i2c_driver = {
 	.probe		= s3c24xx_i2c_probe,
 	.remove		= s3c24xx_i2c_remove,
 	.suspend_late	= s3c24xx_i2c_suspend_late,
 	.resume		= s3c24xx_i2c_resume,
+	.id_table	= s3c24xx_driver_ids,
 	.driver		= {
 		.owner	= THIS_MODULE,
-		.name	= "s3c2440-i2c",
+		.name	= "s3c-i2c",
 	},
 };
 
 static int __init i2c_adap_s3c_init(void)
 {
-	int ret;
-
-	ret = platform_driver_register(&s3c2410_i2c_driver);
-	if (ret == 0) {
-		ret = platform_driver_register(&s3c2440_i2c_driver);
-		if (ret)
-			platform_driver_unregister(&s3c2410_i2c_driver);
-	}
-
-	return ret;
+	return platform_driver_register(&s3c24xx_i2c_driver);
 }
 subsys_initcall(i2c_adap_s3c_init);
 
 static void __exit i2c_adap_s3c_exit(void)
 {
-	platform_driver_unregister(&s3c2410_i2c_driver);
-	platform_driver_unregister(&s3c2440_i2c_driver);
+	platform_driver_unregister(&s3c24xx_i2c_driver);
 }
 module_exit(i2c_adap_s3c_exit);
 
 MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c2410-i2c");
-MODULE_ALIAS("platform:s3c2440-i2c");
diff --git a/drivers/ide/at91_ide.c b/drivers/ide/at91_ide.c
index 403d0e4..fc0949a 100644
--- a/drivers/ide/at91_ide.c
+++ b/drivers/ide/at91_ide.c
@@ -216,6 +216,7 @@
 	.host_flags 	= IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA | IDE_HFLAG_SINGLE |
 			  IDE_HFLAG_NO_IO_32BIT | IDE_HFLAG_UNMASK_IRQS,
 	.pio_mask 	= ATA_PIO6,
+	.chipset	= ide_generic,
 };
 
 /*
@@ -246,8 +247,7 @@
 static int __init at91_ide_probe(struct platform_device *pdev)
 {
 	int ret;
-	hw_regs_t hw;
-	hw_regs_t *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 	struct ide_host *host;
 	struct resource *res;
 	unsigned long tf_base = 0, ctl_base = 0;
@@ -304,10 +304,9 @@
 		ide_std_init_ports(&hw, tf_base, ctl_base + 6);
 
 	hw.irq = board->irq_pin;
-	hw.chipset = ide_generic;
 	hw.dev = &pdev->dev;
 
-	host = ide_host_alloc(&at91_ide_port_info, hws);
+	host = ide_host_alloc(&at91_ide_port_info, hws, 1);
 	if (!host) {
 		perr("failed to allocate ide host\n");
 		return -ENOMEM;
diff --git a/drivers/ide/au1xxx-ide.c b/drivers/ide/au1xxx-ide.c
index 4601364..58121bd 100644
--- a/drivers/ide/au1xxx-ide.c
+++ b/drivers/ide/au1xxx-ide.c
@@ -449,7 +449,7 @@
 }
 #endif
 
-static void auide_setup_ports(hw_regs_t *hw, _auide_hwif *ahwif)
+static void auide_setup_ports(struct ide_hw *hw, _auide_hwif *ahwif)
 {
 	int i;
 	unsigned long *ata_regs = hw->io_ports_array;
@@ -499,6 +499,7 @@
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
 	.mwdma_mask		= ATA_MWDMA2,
 #endif
+	.chipset		= ide_au1xxx,
 };
 
 static int au_ide_probe(struct platform_device *dev)
@@ -507,7 +508,7 @@
 	struct resource *res;
 	struct ide_host *host;
 	int ret = 0;
-	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 
 #if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA)
 	char *mode = "MWDMA2";
@@ -548,9 +549,8 @@
 	auide_setup_ports(&hw, ahwif);
 	hw.irq = ahwif->irq;
 	hw.dev = &dev->dev;
-	hw.chipset = ide_au1xxx;
 
-	ret = ide_host_add(&au1xxx_port_info, hws, &host);
+	ret = ide_host_add(&au1xxx_port_info, hws, 1, &host);
 	if (ret)
 		goto out;
 
diff --git a/drivers/ide/buddha.c b/drivers/ide/buddha.c
index d028f88..e3c6a59 100644
--- a/drivers/ide/buddha.c
+++ b/drivers/ide/buddha.c
@@ -121,7 +121,7 @@
     return 1;
 }
 
-static void __init buddha_setup_ports(hw_regs_t *hw, unsigned long base,
+static void __init buddha_setup_ports(struct ide_hw *hw, unsigned long base,
 				      unsigned long ctl, unsigned long irq_port,
 				      ide_ack_intr_t *ack_intr)
 {
@@ -139,13 +139,12 @@
 
 	hw->irq = IRQ_AMIGA_PORTS;
 	hw->ack_intr = ack_intr;
-
-	hw->chipset = ide_generic;
 }
 
 static const struct ide_port_info buddha_port_info = {
 	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
 	.irq_flags		= IRQF_SHARED,
+	.chipset		= ide_generic,
 };
 
     /*
@@ -161,7 +160,7 @@
 
 	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
 		unsigned long board;
-		hw_regs_t hw[MAX_NUM_HWIFS], *hws[] = { NULL, NULL, NULL, NULL };
+		struct ide_hw hw[MAX_NUM_HWIFS], *hws[MAX_NUM_HWIFS];
 
 		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
 			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
@@ -225,7 +224,7 @@
 			hws[i] = &hw[i];
 		}
 
-		ide_host_add(&buddha_port_info, hws, NULL);
+		ide_host_add(&buddha_port_info, hws, i, NULL);
 	}
 
 	return 0;
diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c
index 8890276..1683ed5 100644
--- a/drivers/ide/cmd640.c
+++ b/drivers/ide/cmd640.c
@@ -708,7 +708,7 @@
 	int second_port_cmd640 = 0, rc;
 	const char *bus_type, *port2;
 	u8 b, cfr;
-	hw_regs_t hw[2], *hws[] = { NULL, NULL, NULL, NULL };
+	struct ide_hw hw[2], *hws[2];
 
 	if (cmd640_vlb && probe_for_cmd640_vlb()) {
 		bus_type = "VLB";
@@ -762,11 +762,9 @@
 
 	ide_std_init_ports(&hw[0], 0x1f0, 0x3f6);
 	hw[0].irq = 14;
-	hw[0].chipset = ide_cmd640;
 
 	ide_std_init_ports(&hw[1], 0x170, 0x376);
 	hw[1].irq = 15;
-	hw[1].chipset = ide_cmd640;
 
 	printk(KERN_INFO "cmd640: buggy cmd640%c interface on %s, config=0x%02x"
 			 "\n", 'a' + cmd640_chip_version - 1, bus_type, cfr);
@@ -824,7 +822,8 @@
 	cmd640_dump_regs();
 #endif
 
-	return ide_host_add(&cmd640_port_info, hws, NULL);
+	return ide_host_add(&cmd640_port_info, hws, second_port_cmd640 ? 2 : 1,
+			    NULL);
 }
 
 module_param_named(probe_vlb, cmd640_vlb, bool, 0);
diff --git a/drivers/ide/cs5520.c b/drivers/ide/cs5520.c
index 87987a7..bd066bb 100644
--- a/drivers/ide/cs5520.c
+++ b/drivers/ide/cs5520.c
@@ -110,7 +110,7 @@
 static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	const struct ide_port_info *d = &cyrix_chipset;
-	hw_regs_t hw[4], *hws[] = { NULL, NULL, NULL, NULL };
+	struct ide_hw hw[2], *hws[] = { NULL, NULL };
 
 	ide_setup_pci_noise(dev, d);
 
@@ -136,7 +136,7 @@
 	ide_pci_setup_ports(dev, d, &hw[0], &hws[0]);
 	hw[0].irq = 14;
 
-	return ide_host_add(d, hws, NULL);
+	return ide_host_add(d, hws, 2, NULL);
 }
 
 static const struct pci_device_id cs5520_pci_tbl[] = {
diff --git a/drivers/ide/delkin_cb.c b/drivers/ide/delkin_cb.c
index f153b95..1e10eba 100644
--- a/drivers/ide/delkin_cb.c
+++ b/drivers/ide/delkin_cb.c
@@ -68,6 +68,7 @@
 				  IDE_HFLAG_NO_DMA,
 	.irq_flags		= IRQF_SHARED,
 	.init_chipset		= delkin_cb_init_chipset,
+	.chipset		= ide_pci,
 };
 
 static int __devinit
@@ -76,7 +77,7 @@
 	struct ide_host *host;
 	unsigned long base;
 	int rc;
-	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 
 	rc = pci_enable_device(dev);
 	if (rc) {
@@ -97,9 +98,8 @@
 	ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
 	hw.irq = dev->irq;
 	hw.dev = &dev->dev;
-	hw.chipset = ide_pci;		/* this enables IRQ sharing */
 
-	rc = ide_host_add(&delkin_cb_port_info, hws, &host);
+	rc = ide_host_add(&delkin_cb_port_info, hws, 1, &host);
 	if (rc)
 		goto out_disable;
 
diff --git a/drivers/ide/falconide.c b/drivers/ide/falconide.c
index 0e2df67..22fa273 100644
--- a/drivers/ide/falconide.c
+++ b/drivers/ide/falconide.c
@@ -111,9 +111,10 @@
 	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
 				  IDE_HFLAG_NO_DMA,
 	.irq_flags		= IRQF_SHARED,
+	.chipset		= ide_generic,
 };
 
-static void __init falconide_setup_ports(hw_regs_t *hw)
+static void __init falconide_setup_ports(struct ide_hw *hw)
 {
 	int i;
 
@@ -128,8 +129,6 @@
 
 	hw->irq = IRQ_MFP_IDE;
 	hw->ack_intr = NULL;
-
-	hw->chipset = ide_generic;
 }
 
     /*
@@ -139,7 +138,7 @@
 static int __init falconide_init(void)
 {
 	struct ide_host *host;
-	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 	int rc;
 
 	if (!MACH_IS_ATARI || !ATARIHW_PRESENT(IDE))
@@ -154,7 +153,7 @@
 
 	falconide_setup_ports(&hw);
 
-	host = ide_host_alloc(&falconide_port_info, hws);
+	host = ide_host_alloc(&falconide_port_info, hws, 1);
 	if (host == NULL) {
 		rc = -ENOMEM;
 		goto err;
diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c
index c711951..4451a6a 100644
--- a/drivers/ide/gayle.c
+++ b/drivers/ide/gayle.c
@@ -88,7 +88,7 @@
     return 1;
 }
 
-static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base,
+static void __init gayle_setup_ports(struct ide_hw *hw, unsigned long base,
 				     unsigned long ctl, unsigned long irq_port,
 				     ide_ack_intr_t *ack_intr)
 {
@@ -106,14 +106,13 @@
 
 	hw->irq = IRQ_AMIGA_PORTS;
 	hw->ack_intr = ack_intr;
-
-	hw->chipset = ide_generic;
 }
 
 static const struct ide_port_info gayle_port_info = {
 	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
 				  IDE_HFLAG_NO_DMA,
 	.irq_flags		= IRQF_SHARED,
+	.chipset		= ide_generic,
 };
 
     /*
@@ -126,7 +125,7 @@
     unsigned long base, ctrlport, irqport;
     ide_ack_intr_t *ack_intr;
     int a4000, i, rc;
-    hw_regs_t hw[GAYLE_NUM_HWIFS], *hws[] = { NULL, NULL, NULL, NULL };
+    struct ide_hw hw[GAYLE_NUM_HWIFS], *hws[GAYLE_NUM_HWIFS];
 
     if (!MACH_IS_AMIGA)
 	return -ENODEV;
@@ -171,7 +170,7 @@
 	hws[i] = &hw[i];
     }
 
-    rc = ide_host_add(&gayle_port_info, hws, NULL);
+    rc = ide_host_add(&gayle_port_info, hws, i, NULL);
     if (rc)
 	release_mem_region(res_start, res_n);
 
diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
index 0feb66c..7ce68ef 100644
--- a/drivers/ide/hpt366.c
+++ b/drivers/ide/hpt366.c
@@ -138,14 +138,6 @@
 #undef	HPT_RESET_STATE_ENGINE
 #undef	HPT_DELAY_INTERRUPT
 
-static const char *quirk_drives[] = {
-	"QUANTUM FIREBALLlct08 08",
-	"QUANTUM FIREBALLP KA6.4",
-	"QUANTUM FIREBALLP LM20.4",
-	"QUANTUM FIREBALLP LM20.5",
-	NULL
-};
-
 static const char *bad_ata100_5[] = {
 	"IBM-DTLA-307075",
 	"IBM-DTLA-307060",
@@ -729,27 +721,13 @@
 	hpt3xx_set_mode(drive, XFER_PIO_0 + pio);
 }
 
-static void hpt3xx_quirkproc(ide_drive_t *drive)
-{
-	char *m			= (char *)&drive->id[ATA_ID_PROD];
-	const  char **list	= quirk_drives;
-
-	while (*list)
-		if (strstr(m, *list++)) {
-			drive->quirk_list = 1;
-			return;
-		}
-
-	drive->quirk_list = 0;
-}
-
 static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
 {
 	ide_hwif_t *hwif	= drive->hwif;
 	struct pci_dev	*dev	= to_pci_dev(hwif->dev);
 	struct hpt_info *info	= hpt3xx_get_info(hwif->dev);
 
-	if (drive->quirk_list == 0)
+	if ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0)
 		return;
 
 	if (info->chip_type >= HPT370) {
@@ -1404,7 +1382,6 @@
 static const struct ide_port_ops hpt3xx_port_ops = {
 	.set_pio_mode		= hpt3xx_set_pio_mode,
 	.set_dma_mode		= hpt3xx_set_mode,
-	.quirkproc		= hpt3xx_quirkproc,
 	.maskproc		= hpt3xx_maskproc,
 	.mdma_filter		= hpt3xx_mdma_filter,
 	.udma_filter		= hpt3xx_udma_filter,
diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c
index 36da913..5af3d0f 100644
--- a/drivers/ide/icside.c
+++ b/drivers/ide/icside.c
@@ -65,8 +65,6 @@
 };
 
 struct icside_state {
-	unsigned int channel;
-	unsigned int enabled;
 	void __iomem *irq_port;
 	void __iomem *ioc_base;
 	unsigned int sel;
@@ -116,18 +114,11 @@
 	struct icside_state *state = ec->irq_data;
 	void __iomem *base = state->irq_port;
 
-	state->enabled = 1;
+	writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
+	readb(base + ICS_ARCIN_V6_INTROFFSET_2);
 
-	switch (state->channel) {
-	case 0:
-		writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
-		readb(base + ICS_ARCIN_V6_INTROFFSET_2);
-		break;
-	case 1:
-		writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
-		readb(base + ICS_ARCIN_V6_INTROFFSET_1);
-		break;
-	}
+	writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
+	readb(base + ICS_ARCIN_V6_INTROFFSET_1);
 }
 
 /* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
@@ -137,8 +128,6 @@
 {
 	struct icside_state *state = ec->irq_data;
 
-	state->enabled = 0;
-
 	readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
 	readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
 }
@@ -160,44 +149,6 @@
 	.irqpending	= icside_irqpending_arcin_v6,
 };
 
-/*
- * Handle routing of interrupts.  This is called before
- * we write the command to the drive.
- */
-static void icside_maskproc(ide_drive_t *drive, int mask)
-{
-	ide_hwif_t *hwif = drive->hwif;
-	struct expansion_card *ec = ECARD_DEV(hwif->dev);
-	struct icside_state *state = ecard_get_drvdata(ec);
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	state->channel = hwif->channel;
-
-	if (state->enabled && !mask) {
-		switch (hwif->channel) {
-		case 0:
-			writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-			readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-			break;
-		case 1:
-			writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-			readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-			break;
-		}
-	} else {
-		readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-		readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-	}
-
-	local_irq_restore(flags);
-}
-
-static const struct ide_port_ops icside_v6_no_dma_port_ops = {
-	.maskproc		= icside_maskproc,
-};
-
 #ifdef CONFIG_BLK_DEV_IDEDMA_ICS
 /*
  * SG-DMA support.
@@ -275,7 +226,6 @@
 
 static const struct ide_port_ops icside_v6_port_ops = {
 	.set_dma_mode		= icside_set_dma_mode,
-	.maskproc		= icside_maskproc,
 };
 
 static void icside_dma_host_set(ide_drive_t *drive, int on)
@@ -320,11 +270,6 @@
 	BUG_ON(dma_channel_active(ec->dma));
 
 	/*
-	 * Ensure that we have the right interrupt routed.
-	 */
-	icside_maskproc(drive, 0);
-
-	/*
 	 * Route the DMA signals to the correct interface.
 	 */
 	writeb(state->sel | hwif->channel, state->ioc_base);
@@ -381,7 +326,7 @@
 	return -EOPNOTSUPP;
 }
 
-static void icside_setup_ports(hw_regs_t *hw, void __iomem *base,
+static void icside_setup_ports(struct ide_hw *hw, void __iomem *base,
 			       struct cardinfo *info, struct expansion_card *ec)
 {
 	unsigned long port = (unsigned long)base + info->dataoffset;
@@ -398,11 +343,11 @@
 
 	hw->irq = ec->irq;
 	hw->dev = &ec->dev;
-	hw->chipset = ide_acorn;
 }
 
 static const struct ide_port_info icside_v5_port_info = {
 	.host_flags		= IDE_HFLAG_NO_DMA,
+	.chipset		= ide_acorn,
 };
 
 static int __devinit
@@ -410,7 +355,7 @@
 {
 	void __iomem *base;
 	struct ide_host *host;
-	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 	int ret;
 
 	base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
@@ -431,7 +376,7 @@
 
 	icside_setup_ports(&hw, base, &icside_cardinfo_v5, ec);
 
-	host = ide_host_alloc(&icside_v5_port_info, hws);
+	host = ide_host_alloc(&icside_v5_port_info, hws, 1);
 	if (host == NULL)
 		return -ENODEV;
 
@@ -452,11 +397,11 @@
 
 static const struct ide_port_info icside_v6_port_info __initdata = {
 	.init_dma		= icside_dma_off_init,
-	.port_ops		= &icside_v6_no_dma_port_ops,
 	.dma_ops		= &icside_v6_dma_ops,
 	.host_flags		= IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO,
 	.mwdma_mask		= ATA_MWDMA2,
 	.swdma_mask		= ATA_SWDMA2,
+	.chipset		= ide_acorn,
 };
 
 static int __devinit
@@ -466,7 +411,7 @@
 	struct ide_host *host;
 	unsigned int sel = 0;
 	int ret;
-	hw_regs_t hw[2], *hws[] = { &hw[0], &hw[1], NULL, NULL };
+	struct ide_hw hw[2], *hws[] = { &hw[0], &hw[1] };
 	struct ide_port_info d = icside_v6_port_info;
 
 	ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
@@ -506,7 +451,7 @@
 	icside_setup_ports(&hw[0], easi_base, &icside_cardinfo_v6_1, ec);
 	icside_setup_ports(&hw[1], easi_base, &icside_cardinfo_v6_2, ec);
 
-	host = ide_host_alloc(&d, hws);
+	host = ide_host_alloc(&d, hws, 2);
 	if (host == NULL)
 		return -ENODEV;
 
diff --git a/drivers/ide/ide-4drives.c b/drivers/ide/ide-4drives.c
index 78aca75..979d342 100644
--- a/drivers/ide/ide-4drives.c
+++ b/drivers/ide/ide-4drives.c
@@ -25,12 +25,13 @@
 	.port_ops		= &ide_4drives_port_ops,
 	.host_flags		= IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA |
 				  IDE_HFLAG_4DRIVES,
+	.chipset		= ide_4drives,
 };
 
 static int __init ide_4drives_init(void)
 {
 	unsigned long base = 0x1f0, ctl = 0x3f6;
-	hw_regs_t hw, *hws[] = { &hw, &hw, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw, &hw };
 
 	if (probe_4drives == 0)
 		return -ENODEV;
@@ -52,9 +53,8 @@
 
 	ide_std_init_ports(&hw, base, ctl);
 	hw.irq = 14;
-	hw.chipset = ide_4drives;
 
-	return ide_host_add(&ide_4drives_port_info, hws, NULL);
+	return ide_host_add(&ide_4drives_port_info, hws, 2, NULL);
 }
 
 module_init(ide_4drives_init);
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c
index ae1cae3..702ef64 100644
--- a/drivers/ide/ide-atapi.c
+++ b/drivers/ide/ide-atapi.c
@@ -259,7 +259,7 @@
 	pc->req_xfer = blk_rq_bytes(sense_rq);
 
 	if (drive->media == ide_tape)
-		set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
+		drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
 
 	/*
 	 * Push back the failed request and put request sense on top
diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
index 9e47f35..527908f 100644
--- a/drivers/ide/ide-cs.c
+++ b/drivers/ide/ide-cs.c
@@ -155,6 +155,7 @@
 	.port_ops		= &idecs_port_ops,
 	.host_flags		= IDE_HFLAG_NO_DMA,
 	.irq_flags		= IRQF_SHARED,
+	.chipset		= ide_pci,
 };
 
 static struct ide_host *idecs_register(unsigned long io, unsigned long ctl,
@@ -163,7 +164,7 @@
     struct ide_host *host;
     ide_hwif_t *hwif;
     int i, rc;
-    hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+    struct ide_hw hw, *hws[] = { &hw };
 
     if (!request_region(io, 8, DRV_NAME)) {
 	printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
@@ -181,10 +182,9 @@
     memset(&hw, 0, sizeof(hw));
     ide_std_init_ports(&hw, io, ctl);
     hw.irq = irq;
-    hw.chipset = ide_pci;
     hw.dev = &handle->dev;
 
-    rc = ide_host_add(&idecs_port_info, hws, &host);
+    rc = ide_host_add(&idecs_port_info, hws, 1, &host);
     if (rc)
 	goto out_release;
 
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index c6f7fcf..6a1de21 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -302,14 +302,12 @@
 	{ NULL,		NULL }
 };
 
-static void idedisk_check_hpa(ide_drive_t *drive)
+static u64 ide_disk_hpa_get_native_capacity(ide_drive_t *drive, int lba48)
 {
-	unsigned long long capacity, set_max;
-	int lba48 = ata_id_lba48_enabled(drive->id);
+	u64 capacity, set_max;
 
 	capacity = drive->capacity64;
-
-	set_max = idedisk_read_native_max_address(drive, lba48);
+	set_max  = idedisk_read_native_max_address(drive, lba48);
 
 	if (ide_in_drive_list(drive->id, hpa_list)) {
 		/*
@@ -320,9 +318,31 @@
 			set_max--;
 	}
 
+	return set_max;
+}
+
+static u64 ide_disk_hpa_set_capacity(ide_drive_t *drive, u64 set_max, int lba48)
+{
+	set_max = idedisk_set_max_address(drive, set_max, lba48);
+	if (set_max)
+		drive->capacity64 = set_max;
+
+	return set_max;
+}
+
+static void idedisk_check_hpa(ide_drive_t *drive)
+{
+	u64 capacity, set_max;
+	int lba48 = ata_id_lba48_enabled(drive->id);
+
+	capacity = drive->capacity64;
+	set_max  = ide_disk_hpa_get_native_capacity(drive, lba48);
+
 	if (set_max <= capacity)
 		return;
 
+	drive->probed_capacity = set_max;
+
 	printk(KERN_INFO "%s: Host Protected Area detected.\n"
 			 "\tcurrent capacity is %llu sectors (%llu MB)\n"
 			 "\tnative  capacity is %llu sectors (%llu MB)\n",
@@ -330,13 +350,13 @@
 			 capacity, sectors_to_MB(capacity),
 			 set_max, sectors_to_MB(set_max));
 
-	set_max = idedisk_set_max_address(drive, set_max, lba48);
+	if ((drive->dev_flags & IDE_DFLAG_NOHPA) == 0)
+		return;
 
-	if (set_max) {
-		drive->capacity64 = set_max;
+	set_max = ide_disk_hpa_set_capacity(drive, set_max, lba48);
+	if (set_max)
 		printk(KERN_INFO "%s: Host Protected Area disabled.\n",
 				 drive->name);
-	}
 }
 
 static int ide_disk_get_capacity(ide_drive_t *drive)
@@ -358,6 +378,8 @@
 		drive->capacity64 = drive->cyl * drive->head * drive->sect;
 	}
 
+	drive->probed_capacity = drive->capacity64;
+
 	if (lba) {
 		drive->dev_flags |= IDE_DFLAG_LBA;
 
@@ -376,7 +398,7 @@
 		       "%llu sectors (%llu MB)\n",
 		       drive->name, (unsigned long long)drive->capacity64,
 		       sectors_to_MB(drive->capacity64));
-		drive->capacity64 = 1ULL << 28;
+		drive->probed_capacity = drive->capacity64 = 1ULL << 28;
 	}
 
 	if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) &&
@@ -392,6 +414,34 @@
 	return 0;
 }
 
+static u64 ide_disk_set_capacity(ide_drive_t *drive, u64 capacity)
+{
+	u64 set = min(capacity, drive->probed_capacity);
+	u16 *id = drive->id;
+	int lba48 = ata_id_lba48_enabled(id);
+
+	if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 ||
+	    ata_id_hpa_enabled(id) == 0)
+		goto out;
+
+	/*
+	 * according to the spec the SET MAX ADDRESS command shall be
+	 * immediately preceded by a READ NATIVE MAX ADDRESS command
+	 */
+	capacity = ide_disk_hpa_get_native_capacity(drive, lba48);
+	if (capacity == 0)
+		goto out;
+
+	set = ide_disk_hpa_set_capacity(drive, set, lba48);
+	if (set) {
+		/* needed for ->resume to disable HPA */
+		drive->dev_flags |= IDE_DFLAG_NOHPA;
+		return set;
+	}
+out:
+	return drive->capacity64;
+}
+
 static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
 {
 	ide_drive_t *drive = q->queuedata;
@@ -428,14 +478,14 @@
 	if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff))
 		return -EINVAL;
 
-	if (drive->special.b.set_multmode)
+	if (drive->special_flags & IDE_SFLAG_SET_MULTMODE)
 		return -EBUSY;
 
 	rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
 	rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
 
 	drive->mult_req = arg;
-	drive->special.b.set_multmode = 1;
+	drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
 	error = blk_execute_rq(drive->queue, NULL, rq, 0);
 	blk_put_request(rq);
 
@@ -740,6 +790,7 @@
 
 const struct ide_disk_ops ide_ata_disk_ops = {
 	.check		= ide_disk_check,
+	.set_capacity	= ide_disk_set_capacity,
 	.get_capacity	= ide_disk_get_capacity,
 	.setup		= ide_disk_setup,
 	.flush		= ide_disk_flush,
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 001f68f..219e6fb 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -347,7 +347,6 @@
 
 	return mode;
 }
-EXPORT_SYMBOL_GPL(ide_find_dma_mode);
 
 static int ide_tune_dma(ide_drive_t *drive)
 {
diff --git a/drivers/ide/ide-eh.c b/drivers/ide/ide-eh.c
index 5d5fb96..2b91419 100644
--- a/drivers/ide/ide-eh.c
+++ b/drivers/ide/ide-eh.c
@@ -52,7 +52,7 @@
 	}
 
 	if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
-		drive->special.b.recalibrate = 1;
+		drive->special_flags |= IDE_SFLAG_RECALIBRATE;
 
 	++rq->errors;
 
@@ -268,9 +268,8 @@
 {
 	int legacy = (drive->id[ATA_ID_CFS_ENABLE_2] & 0x0400) ? 0 : 1;
 
-	drive->special.all = 0;
-	drive->special.b.set_geometry = legacy;
-	drive->special.b.recalibrate  = legacy;
+	drive->special_flags =
+		legacy ? (IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE) : 0;
 
 	drive->mult_count = 0;
 	drive->dev_flags &= ~IDE_DFLAG_PARKED;
@@ -280,7 +279,7 @@
 		drive->mult_req = 0;
 
 	if (drive->mult_req != drive->mult_count)
-		drive->special.b.set_multmode = 1;
+		drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
 }
 
 static void pre_reset(ide_drive_t *drive)
@@ -408,8 +407,9 @@
 	/* more than enough time */
 	udelay(10);
 	/* clear SRST, leave nIEN (unless device is on the quirk list) */
-	tp_ops->write_devctl(hwif, (drive->quirk_list == 2 ? 0 : ATA_NIEN) |
-			     ATA_DEVCTL_OBS);
+	tp_ops->write_devctl(hwif,
+		((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) ? 0 : ATA_NIEN) |
+		 ATA_DEVCTL_OBS);
 	/* more than enough time */
 	udelay(10);
 	hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c
index 4b6b71e..2141190 100644
--- a/drivers/ide/ide-gd.c
+++ b/drivers/ide/ide-gd.c
@@ -287,6 +287,19 @@
 	return ret;
 }
 
+static unsigned long long ide_gd_set_capacity(struct gendisk *disk,
+					      unsigned long long capacity)
+{
+	struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
+	ide_drive_t *drive = idkp->drive;
+	const struct ide_disk_ops *disk_ops = drive->disk_ops;
+
+	if (disk_ops->set_capacity)
+		return disk_ops->set_capacity(drive, capacity);
+
+	return drive->capacity64;
+}
+
 static int ide_gd_revalidate_disk(struct gendisk *disk)
 {
 	struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
@@ -315,6 +328,7 @@
 	.locked_ioctl		= ide_gd_ioctl,
 	.getgeo			= ide_gd_getgeo,
 	.media_changed		= ide_gd_media_changed,
+	.set_capacity		= ide_gd_set_capacity,
 	.revalidate_disk	= ide_gd_revalidate_disk
 };
 
diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
index 7812ca0..54d7c46 100644
--- a/drivers/ide/ide-generic.c
+++ b/drivers/ide/ide-generic.c
@@ -29,6 +29,7 @@
 
 static const struct ide_port_info ide_generic_port_info = {
 	.host_flags		= IDE_HFLAG_NO_DMA,
+	.chipset		= ide_generic,
 };
 
 #ifdef CONFIG_ARM
@@ -85,7 +86,7 @@
 
 static int __init ide_generic_init(void)
 {
-	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 	unsigned long io_addr;
 	int i, rc = 0, primary = 0, secondary = 0;
 
@@ -132,9 +133,7 @@
 #else
 			hw.irq = legacy_irqs[i];
 #endif
-			hw.chipset = ide_generic;
-
-			rc = ide_host_add(&ide_generic_port_info, hws, NULL);
+			rc = ide_host_add(&ide_generic_port_info, hws, 1, NULL);
 			if (rc) {
 				release_region(io_addr + 0x206, 1);
 				release_region(io_addr, 8);
diff --git a/drivers/ide/ide-h8300.c b/drivers/ide/ide-h8300.c
index c06ebdc..520f42c 100644
--- a/drivers/ide/ide-h8300.c
+++ b/drivers/ide/ide-h8300.c
@@ -64,26 +64,26 @@
 
 #define H8300_IDE_GAP (2)
 
-static inline void hw_setup(hw_regs_t *hw)
+static inline void hw_setup(struct ide_hw *hw)
 {
 	int i;
 
-	memset(hw, 0, sizeof(hw_regs_t));
+	memset(hw, 0, sizeof(*hw));
 	for (i = 0; i <= 7; i++)
 		hw->io_ports_array[i] = CONFIG_H8300_IDE_BASE + H8300_IDE_GAP*i;
 	hw->io_ports.ctl_addr = CONFIG_H8300_IDE_ALT;
 	hw->irq = EXT_IRQ0 + CONFIG_H8300_IDE_IRQ;
-	hw->chipset = ide_generic;
 }
 
 static const struct ide_port_info h8300_port_info = {
 	.tp_ops			= &h8300_tp_ops,
 	.host_flags		= IDE_HFLAG_NO_IO_32BIT | IDE_HFLAG_NO_DMA,
+	.chipset		= ide_generic,
 };
 
 static int __init h8300_ide_init(void)
 {
-	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 
 	printk(KERN_INFO DRV_NAME ": H8/300 generic IDE interface\n");
 
@@ -96,7 +96,7 @@
 
 	hw_setup(&hw);
 
-	return ide_host_add(&h8300_port_info, hws, NULL);
+	return ide_host_add(&h8300_port_info, hws, 1, NULL);
 
 out_busy:
 	printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n");
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index bba4297..272cc38 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -184,29 +184,42 @@
 	tf->command = ATA_CMD_SET_MULTI;
 }
 
-static ide_startstop_t ide_disk_special(ide_drive_t *drive)
+/**
+ *	do_special		-	issue some special commands
+ *	@drive: drive the command is for
+ *
+ *	do_special() is used to issue ATA_CMD_INIT_DEV_PARAMS,
+ *	ATA_CMD_RESTORE and ATA_CMD_SET_MULTI commands to a drive.
+ */
+
+static ide_startstop_t do_special(ide_drive_t *drive)
 {
-	special_t *s = &drive->special;
 	struct ide_cmd cmd;
 
+#ifdef DEBUG
+	printk(KERN_DEBUG "%s: %s: 0x%02x\n", drive->name, __func__,
+		drive->special_flags);
+#endif
+	if (drive->media != ide_disk) {
+		drive->special_flags = 0;
+		drive->mult_req = 0;
+		return ide_stopped;
+	}
+
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.protocol = ATA_PROT_NODATA;
 
-	if (s->b.set_geometry) {
-		s->b.set_geometry = 0;
+	if (drive->special_flags & IDE_SFLAG_SET_GEOMETRY) {
+		drive->special_flags &= ~IDE_SFLAG_SET_GEOMETRY;
 		ide_tf_set_specify_cmd(drive, &cmd.tf);
-	} else if (s->b.recalibrate) {
-		s->b.recalibrate = 0;
+	} else if (drive->special_flags & IDE_SFLAG_RECALIBRATE) {
+		drive->special_flags &= ~IDE_SFLAG_RECALIBRATE;
 		ide_tf_set_restore_cmd(drive, &cmd.tf);
-	} else if (s->b.set_multmode) {
-		s->b.set_multmode = 0;
+	} else if (drive->special_flags & IDE_SFLAG_SET_MULTMODE) {
+		drive->special_flags &= ~IDE_SFLAG_SET_MULTMODE;
 		ide_tf_set_setmult_cmd(drive, &cmd.tf);
-	} else if (s->all) {
-		int special = s->all;
-		s->all = 0;
-		printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special);
-		return ide_stopped;
-	}
+	} else
+		BUG();
 
 	cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
 	cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
@@ -217,31 +230,6 @@
 	return ide_started;
 }
 
-/**
- *	do_special		-	issue some special commands
- *	@drive: drive the command is for
- *
- *	do_special() is used to issue ATA_CMD_INIT_DEV_PARAMS,
- *	ATA_CMD_RESTORE and ATA_CMD_SET_MULTI commands to a drive.
- *
- *	It used to do much more, but has been scaled back.
- */
-
-static ide_startstop_t do_special (ide_drive_t *drive)
-{
-	special_t *s = &drive->special;
-
-#ifdef DEBUG
-	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
-#endif
-	if (drive->media == ide_disk)
-		return ide_disk_special(drive);
-
-	s->all = 0;
-	drive->mult_req = 0;
-	return ide_stopped;
-}
-
 void ide_map_sg(ide_drive_t *drive, struct ide_cmd *cmd)
 {
 	ide_hwif_t *hwif = drive->hwif;
@@ -351,7 +339,8 @@
 		printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
 		return startstop;
 	}
-	if (!drive->special.all) {
+
+	if (drive->special_flags == 0) {
 		struct ide_driver *drv;
 
 		/*
@@ -499,11 +488,15 @@
 
 		if ((hwif->host->host_flags & IDE_HFLAG_SERIALIZE) &&
 		    hwif != prev_port) {
+			ide_drive_t *cur_dev =
+				prev_port ? prev_port->cur_dev : NULL;
+
 			/*
 			 * set nIEN for previous port, drives in the
-			 * quirk_list may not like intr setups/cleanups
+			 * quirk list may not like intr setups/cleanups
 			 */
-			if (prev_port && prev_port->cur_dev->quirk_list == 0)
+			if (cur_dev &&
+			    (cur_dev->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0)
 				prev_port->tp_ops->write_devctl(prev_port,
 								ATA_NIEN |
 								ATA_DEVCTL_OBS);
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 06fe002..fa04715 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -282,6 +282,29 @@
 	return 0;
 }
 
+static const char *nien_quirk_list[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP KA9.1",
+	"QUANTUM FIREBALLP KX13.6",
+	"QUANTUM FIREBALLP KX20.5",
+	"QUANTUM FIREBALLP KX27.3",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP LM20.5",
+	NULL
+};
+
+void ide_check_nien_quirk_list(ide_drive_t *drive)
+{
+	const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
+
+	for (list = nien_quirk_list; *list != NULL; list++)
+		if (strstr(m, *list) != NULL) {
+			drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK;
+			return;
+		}
+}
+
 int ide_driveid_update(ide_drive_t *drive)
 {
 	u16 *id;
@@ -311,7 +334,6 @@
 
 	return 1;
 out_err:
-	SELECT_MASK(drive, 0);
 	if (rc == 2)
 		printk(KERN_ERR "%s: %s: bad status\n", drive->name, __func__);
 	kfree(id);
@@ -365,7 +387,7 @@
 
 	tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES);
 
-	if (drive->quirk_list == 2)
+	if (drive->dev_flags & IDE_DFLAG_NIEN_QUIRK)
 		tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
 
 	error = __ide_wait_stat(drive, drive->ready_stat,
diff --git a/drivers/ide/ide-legacy.c b/drivers/ide/ide-legacy.c
index 8c5dcbf..b9654a7 100644
--- a/drivers/ide/ide-legacy.c
+++ b/drivers/ide/ide-legacy.c
@@ -1,7 +1,7 @@
 #include <linux/kernel.h>
 #include <linux/ide.h>
 
-static void ide_legacy_init_one(hw_regs_t **hws, hw_regs_t *hw,
+static void ide_legacy_init_one(struct ide_hw **hws, struct ide_hw *hw,
 				u8 port_no, const struct ide_port_info *d,
 				unsigned long config)
 {
@@ -33,7 +33,6 @@
 
 	ide_std_init_ports(hw, base, ctl);
 	hw->irq = irq;
-	hw->chipset = d->chipset;
 	hw->config = config;
 
 	hws[port_no] = hw;
@@ -41,7 +40,7 @@
 
 int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config)
 {
-	hw_regs_t hw[2], *hws[] = { NULL, NULL, NULL, NULL };
+	struct ide_hw hw[2], *hws[] = { NULL, NULL };
 
 	memset(&hw, 0, sizeof(hw));
 
@@ -53,6 +52,6 @@
 	    (d->host_flags & IDE_HFLAG_SINGLE))
 		return -ENOENT;
 
-	return ide_host_add(d, hws, NULL);
+	return ide_host_add(d, hws, 2, NULL);
 }
 EXPORT_SYMBOL_GPL(ide_legacy_device_add);
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
index 6e80b77..017b1df 100644
--- a/drivers/ide/ide-pnp.c
+++ b/drivers/ide/ide-pnp.c
@@ -29,6 +29,7 @@
 
 static const struct ide_port_info ide_pnp_port_info = {
 	.host_flags		= IDE_HFLAG_NO_DMA,
+	.chipset		= ide_generic,
 };
 
 static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
@@ -36,7 +37,7 @@
 	struct ide_host *host;
 	unsigned long base, ctl;
 	int rc;
-	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 
 	printk(KERN_INFO DRV_NAME ": generic PnP IDE interface\n");
 
@@ -62,9 +63,8 @@
 	memset(&hw, 0, sizeof(hw));
 	ide_std_init_ports(&hw, base, ctl);
 	hw.irq = pnp_irq(dev, 0);
-	hw.chipset = ide_generic;
 
-	rc = ide_host_add(&ide_pnp_port_info, hws, &host);
+	rc = ide_host_add(&ide_pnp_port_info, hws, 1, &host);
 	if (rc)
 		goto out;
 
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index c895ed5..f371b0d 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -97,7 +97,7 @@
 		drive->mult_req = id[ATA_ID_MULTSECT] & 0xff;
 
 		if (drive->mult_req)
-			drive->special.b.set_multmode = 1;
+			drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
 	}
 }
 
@@ -465,23 +465,8 @@
 	int rc;
 	u8 cmd;
 
-	/*
-	 *	In order to keep things simple we have an id
-	 *	block for all drives at all times. If the device
-	 *	is pre ATA or refuses ATA/ATAPI identify we
-	 *	will add faked data to this.
-	 *
-	 *	Also note that 0 everywhere means "can't do X"
-	 */
- 
 	drive->dev_flags &= ~IDE_DFLAG_ID_READ;
 
-	drive->id = kzalloc(SECTOR_SIZE, GFP_KERNEL);
-	if (drive->id == NULL) {
-		printk(KERN_ERR "ide: out of memory for id data.\n");
-		return 0;
-	}
-
 	m = (char *)&drive->id[ATA_ID_PROD];
 	strcpy(m, "UNKNOWN");
 
@@ -497,7 +482,7 @@
 		}
 
 		if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
-			goto out_free;
+			return 0;
 
 		/* identification failed? */
 		if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
@@ -521,7 +506,7 @@
 	}
 
 	if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
-		goto out_free;
+		return 0;
 
 	/* The drive wasn't being helpful. Add generic info only */
 	if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
@@ -535,9 +520,6 @@
 	}
 
 	return 1;
-out_free:
-	kfree(drive->id);
-	return 0;
 }
 
 static void hwif_release_dev(struct device *dev)
@@ -702,8 +684,14 @@
 	if (irqd)
 		disable_irq(hwif->irq);
 
-	if (ide_port_wait_ready(hwif) == -EBUSY)
-		printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name);
+	rc = ide_port_wait_ready(hwif);
+	if (rc == -ENODEV) {
+		printk(KERN_INFO "%s: no devices on the port\n", hwif->name);
+		goto out;
+	} else if (rc == -EBUSY)
+		printk(KERN_ERR "%s: not ready before the probe\n", hwif->name);
+	else
+		rc = -ENODEV;
 
 	/*
 	 * Second drive should only exist if first drive was found,
@@ -714,7 +702,7 @@
 		if (drive->dev_flags & IDE_DFLAG_PRESENT)
 			rc = 0;
 	}
-
+out:
 	/*
 	 * Use cached IRQ number. It might be (and is...) changed by probe
 	 * code above
@@ -732,6 +720,8 @@
 	int i;
 
 	ide_port_for_each_present_dev(i, drive, hwif) {
+		ide_check_nien_quirk_list(drive);
+
 		if (port_ops && port_ops->quirkproc)
 			port_ops->quirkproc(drive);
 	}
@@ -817,8 +807,6 @@
 		if (ide_init_queue(drive)) {
 			printk(KERN_ERR "ide: failed to init %s\n",
 					drive->name);
-			kfree(drive->id);
-			drive->id = NULL;
 			drive->dev_flags &= ~IDE_DFLAG_PRESENT;
 			continue;
 		}
@@ -947,9 +935,6 @@
 	blk_cleanup_queue(drive->queue);
 	drive->queue = NULL;
 
-	kfree(drive->id);
-	drive->id = NULL;
-
 	drive->dev_flags &= ~IDE_DFLAG_PRESENT;
 
 	complete(&drive->gendev_rel_comp);
@@ -1035,6 +1020,15 @@
 		if (port_ops && port_ops->init_dev)
 			port_ops->init_dev(drive);
 	}
+
+	ide_port_for_each_dev(i, drive, hwif) {
+		/*
+		 * default to PIO Mode 0 before we figure out
+		 * the most suited mode for the attached device
+		 */
+		if (port_ops && port_ops->set_pio_mode)
+			port_ops->set_pio_mode(drive, 0);
+	}
 }
 
 static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
@@ -1042,8 +1036,7 @@
 {
 	hwif->channel = port;
 
-	if (d->chipset)
-		hwif->chipset = d->chipset;
+	hwif->chipset = d->chipset ? d->chipset : ide_pci;
 
 	if (d->init_iops)
 		d->init_iops(hwif);
@@ -1124,16 +1117,19 @@
 
 	ide_port_for_each_dev(i, drive, hwif) {
 		u8 j = (hwif->index * MAX_DRIVES) + i;
+		u16 *saved_id = drive->id;
 
 		memset(drive, 0, sizeof(*drive));
+		memset(saved_id, 0, SECTOR_SIZE);
+		drive->id = saved_id;
 
 		drive->media			= ide_disk;
 		drive->select			= (i << 4) | ATA_DEVICE_OBS;
 		drive->hwif			= hwif;
 		drive->ready_stat		= ATA_DRDY;
 		drive->bad_wstat		= BAD_W_STAT;
-		drive->special.b.recalibrate	= 1;
-		drive->special.b.set_geometry	= 1;
+		drive->special_flags		= IDE_SFLAG_RECALIBRATE |
+						  IDE_SFLAG_SET_GEOMETRY;
 		drive->name[0]			= 'h';
 		drive->name[1]			= 'd';
 		drive->name[2]			= 'a' + j;
@@ -1168,11 +1164,10 @@
 	ide_port_init_devices_data(hwif);
 }
 
-static void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
+static void ide_init_port_hw(ide_hwif_t *hwif, struct ide_hw *hw)
 {
 	memcpy(&hwif->io_ports, &hw->io_ports, sizeof(hwif->io_ports));
 	hwif->irq = hw->irq;
-	hwif->chipset = hw->chipset;
 	hwif->dev = hw->dev;
 	hwif->gendev.parent = hw->parent ? hw->parent : hw->dev;
 	hwif->ack_intr = hw->ack_intr;
@@ -1233,8 +1228,10 @@
 	ide_drive_t *drive;
 	int i;
 
-	ide_port_for_each_dev(i, drive, hwif)
+	ide_port_for_each_dev(i, drive, hwif) {
+		kfree(drive->id);
 		kfree(drive);
+	}
 }
 
 static int ide_port_alloc_devices(ide_hwif_t *hwif, int node)
@@ -1248,6 +1245,18 @@
 		if (drive == NULL)
 			goto out_nomem;
 
+		/*
+		 * In order to keep things simple we have an id
+		 * block for all drives at all times. If the device
+		 * is pre ATA or refuses ATA/ATAPI identify we
+		 * will add faked data to this.
+		 *
+		 * Also note that 0 everywhere means "can't do X"
+		 */
+		drive->id = kzalloc_node(SECTOR_SIZE, GFP_KERNEL, node);
+		if (drive->id == NULL)
+			goto out_nomem;
+
 		hwif->devices[i] = drive;
 	}
 	return 0;
@@ -1257,7 +1266,8 @@
 	return -ENOMEM;
 }
 
-struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws)
+struct ide_host *ide_host_alloc(const struct ide_port_info *d,
+				struct ide_hw **hws, unsigned int n_ports)
 {
 	struct ide_host *host;
 	struct device *dev = hws[0] ? hws[0]->dev : NULL;
@@ -1268,7 +1278,7 @@
 	if (host == NULL)
 		return NULL;
 
-	for (i = 0; i < MAX_HOST_PORTS; i++) {
+	for (i = 0; i < n_ports; i++) {
 		ide_hwif_t *hwif;
 		int idx;
 
@@ -1288,6 +1298,7 @@
 		if (idx < 0) {
 			printk(KERN_ERR "%s: no free slot for interface\n",
 					d ? d->name : "ide");
+			ide_port_free_devices(hwif);
 			kfree(hwif);
 			continue;
 		}
@@ -1344,7 +1355,7 @@
 }
 
 int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
-		      hw_regs_t **hws)
+		      struct ide_hw **hws)
 {
 	ide_hwif_t *hwif, *mate = NULL;
 	int i, j = 0;
@@ -1438,13 +1449,13 @@
 }
 EXPORT_SYMBOL_GPL(ide_host_register);
 
-int ide_host_add(const struct ide_port_info *d, hw_regs_t **hws,
-		 struct ide_host **hostp)
+int ide_host_add(const struct ide_port_info *d, struct ide_hw **hws,
+		 unsigned int n_ports, struct ide_host **hostp)
 {
 	struct ide_host *host;
 	int rc;
 
-	host = ide_host_alloc(d, hws);
+	host = ide_host_alloc(d, hws, n_ports);
 	if (host == NULL)
 		return -ENOMEM;
 
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index d9764f0..4b447a8 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -240,18 +240,27 @@
 
 static void ide_tape_release(struct device *);
 
-static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
+static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES];
+
+static struct ide_tape_obj *ide_tape_get(struct gendisk *disk, bool cdev,
+					 unsigned int i)
 {
 	struct ide_tape_obj *tape = NULL;
 
 	mutex_lock(&idetape_ref_mutex);
-	tape = ide_drv_g(disk, ide_tape_obj);
+
+	if (cdev)
+		tape = idetape_devs[i];
+	else
+		tape = ide_drv_g(disk, ide_tape_obj);
+
 	if (tape) {
 		if (ide_device_get(tape->drive))
 			tape = NULL;
 		else
 			get_device(&tape->dev);
 	}
+
 	mutex_unlock(&idetape_ref_mutex);
 	return tape;
 }
@@ -267,24 +276,6 @@
 }
 
 /*
- * The variables below are used for the character device interface. Additional
- * state variables are defined in our ide_drive_t structure.
- */
-static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES];
-
-static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
-{
-	struct ide_tape_obj *tape = NULL;
-
-	mutex_lock(&idetape_ref_mutex);
-	tape = idetape_devs[i];
-	if (tape)
-		get_device(&tape->dev);
-	mutex_unlock(&idetape_ref_mutex);
-	return tape;
-}
-
-/*
  * called on each failed packet command retry to analyze the request sense. We
  * currently do not utilize this information.
  */
@@ -397,7 +388,8 @@
 		if (readpos[0] & 0x4) {
 			printk(KERN_INFO "ide-tape: Block location is unknown"
 					 "to the tape\n");
-			clear_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags);
+			clear_bit(ilog2(IDE_AFLAG_ADDRESS_VALID),
+				  &drive->atapi_flags);
 			uptodate = 0;
 			err = IDE_DRV_ERROR_GENERAL;
 		} else {
@@ -406,7 +398,8 @@
 
 			tape->partition = readpos[1];
 			tape->first_frame = be32_to_cpup((__be32 *)&readpos[4]);
-			set_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags);
+			set_bit(ilog2(IDE_AFLAG_ADDRESS_VALID),
+				&drive->atapi_flags);
 		}
 	}
 
@@ -656,15 +649,15 @@
 
 	if ((drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) == 0 &&
 	    (rq->cmd[13] & REQ_IDETAPE_PC2) == 0)
-		set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
+		drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
 
 	if (drive->dev_flags & IDE_DFLAG_POST_RESET) {
-		set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
+		drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
 		drive->dev_flags &= ~IDE_DFLAG_POST_RESET;
 	}
 
-	if (!test_and_clear_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags) &&
-	    (stat & ATA_DSC) == 0) {
+	if (!(drive->atapi_flags & IDE_AFLAG_IGNORE_DSC) &&
+	    !(stat & ATA_DSC)) {
 		if (postponed_rq == NULL) {
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_poll_freq = tape->best_dsc_rw_freq;
@@ -684,7 +677,9 @@
 			tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW;
 		idetape_postpone_request(drive);
 		return ide_stopped;
-	}
+	} else
+		drive->atapi_flags &= ~IDE_AFLAG_IGNORE_DSC;
+
 	if (rq->cmd[13] & REQ_IDETAPE_READ) {
 		pc = &tape->queued_pc;
 		ide_tape_create_rw_cmd(tape, pc, rq, READ_6);
@@ -744,7 +739,7 @@
 	int load_attempted = 0;
 
 	/* Wait for the tape to become ready */
-	set_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags);
+	set_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), &drive->atapi_flags);
 	timeout += jiffies;
 	while (time_before(jiffies, timeout)) {
 		if (ide_do_test_unit_ready(drive, disk) == 0)
@@ -820,7 +815,7 @@
 	if (tape->chrdev_dir != IDETAPE_DIR_READ)
 		return;
 
-	clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags);
+	clear_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags);
 	tape->valid = 0;
 	if (tape->buf != NULL) {
 		kfree(tape->buf);
@@ -1113,7 +1108,8 @@
 
 	if (tape->chrdev_dir == IDETAPE_DIR_READ) {
 		tape->valid = 0;
-		if (test_and_clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags))
+		if (test_and_clear_bit(ilog2(IDE_AFLAG_FILEMARK),
+				       &drive->atapi_flags))
 			++count;
 		ide_tape_discard_merge_buffer(drive, 0);
 	}
@@ -1168,7 +1164,7 @@
 	debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
 
 	if (tape->chrdev_dir != IDETAPE_DIR_READ) {
-		if (test_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags))
+		if (test_bit(ilog2(IDE_AFLAG_DETECT_BS), &drive->atapi_flags))
 			if (count > tape->blk_size &&
 			    (count % tape->blk_size) == 0)
 				tape->user_bs_factor = count / tape->blk_size;
@@ -1184,7 +1180,8 @@
 		/* refill if staging buffer is empty */
 		if (!tape->valid) {
 			/* If we are at a filemark, nothing more to read */
-			if (test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags))
+			if (test_bit(ilog2(IDE_AFLAG_FILEMARK),
+				     &drive->atapi_flags))
 				break;
 			/* read */
 			if (idetape_queue_rw_tail(drive, REQ_IDETAPE_READ,
@@ -1202,7 +1199,7 @@
 		done += todo;
 	}
 
-	if (!done && test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) {
+	if (!done && test_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags)) {
 		debug_log(DBG_SENSE, "%s: spacing over filemark\n", tape->name);
 
 		idetape_space_over_filemarks(drive, MTFSF, 1);
@@ -1336,7 +1333,8 @@
 		ide_tape_discard_merge_buffer(drive, 0);
 		retval = ide_do_start_stop(drive, disk, !IDETAPE_LU_LOAD_MASK);
 		if (!retval)
-			clear_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags);
+			clear_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT),
+				  &drive->atapi_flags);
 		return retval;
 	case MTNOP:
 		ide_tape_discard_merge_buffer(drive, 0);
@@ -1358,9 +1356,11 @@
 			    mt_count % tape->blk_size)
 				return -EIO;
 			tape->user_bs_factor = mt_count / tape->blk_size;
-			clear_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags);
+			clear_bit(ilog2(IDE_AFLAG_DETECT_BS),
+				  &drive->atapi_flags);
 		} else
-			set_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags);
+			set_bit(ilog2(IDE_AFLAG_DETECT_BS),
+				&drive->atapi_flags);
 		return 0;
 	case MTSEEK:
 		ide_tape_discard_merge_buffer(drive, 0);
@@ -1486,7 +1486,7 @@
 		return -ENXIO;
 
 	lock_kernel();
-	tape = ide_tape_chrdev_get(i);
+	tape = ide_tape_get(NULL, true, i);
 	if (!tape) {
 		unlock_kernel();
 		return -ENXIO;
@@ -1505,20 +1505,20 @@
 
 	filp->private_data = tape;
 
-	if (test_and_set_bit(IDE_AFLAG_BUSY, &drive->atapi_flags)) {
+	if (test_and_set_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags)) {
 		retval = -EBUSY;
 		goto out_put_tape;
 	}
 
 	retval = idetape_wait_ready(drive, 60 * HZ);
 	if (retval) {
-		clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
+		clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
 		printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
 		goto out_put_tape;
 	}
 
 	idetape_read_position(drive);
-	if (!test_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags))
+	if (!test_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), &drive->atapi_flags))
 		(void)idetape_rewind_tape(drive);
 
 	/* Read block size and write protect status from drive. */
@@ -1534,7 +1534,7 @@
 	if (tape->write_prot) {
 		if ((filp->f_flags & O_ACCMODE) == O_WRONLY ||
 		    (filp->f_flags & O_ACCMODE) == O_RDWR) {
-			clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
+			clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
 			retval = -EROFS;
 			goto out_put_tape;
 		}
@@ -1591,15 +1591,17 @@
 			ide_tape_discard_merge_buffer(drive, 1);
 	}
 
-	if (minor < 128 && test_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags))
+	if (minor < 128 && test_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT),
+				    &drive->atapi_flags))
 		(void) idetape_rewind_tape(drive);
+
 	if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
 		if (tape->door_locked == DOOR_LOCKED) {
 			if (!ide_set_media_lock(drive, tape->disk, 0))
 				tape->door_locked = DOOR_UNLOCKED;
 		}
 	}
-	clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
+	clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
 	ide_tape_put(tape);
 	unlock_kernel();
 	return 0;
@@ -1905,7 +1907,7 @@
 
 static int idetape_open(struct block_device *bdev, fmode_t mode)
 {
-	struct ide_tape_obj *tape = ide_tape_get(bdev->bd_disk);
+	struct ide_tape_obj *tape = ide_tape_get(bdev->bd_disk, false, 0);
 
 	if (!tape)
 		return -ENXIO;
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index a0c3e1b..75b85a8 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -98,7 +98,6 @@
 	if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
 		ide_tf_dump(drive->name, cmd);
 		tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
-		SELECT_MASK(drive, 0);
 
 		if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) {
 			u8 data[2] = { cmd->tf.data, cmd->hob.data };
@@ -166,7 +165,7 @@
 	if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
 		if (custom && tf->command == ATA_CMD_SET_MULTI) {
 			drive->mult_req = drive->mult_count = 0;
-			drive->special.b.recalibrate = 1;
+			drive->special_flags |= IDE_SFLAG_RECALIBRATE;
 			(void)ide_dump_status(drive, __func__, stat);
 			return ide_stopped;
 		} else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) {
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 92c9b90..16d0569 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -211,6 +211,11 @@
 module_param_call(noflush, ide_set_dev_param_mask, NULL, &ide_noflush, 0);
 MODULE_PARM_DESC(noflush, "disable flush requests for a device");
 
+static unsigned int ide_nohpa;
+
+module_param_call(nohpa, ide_set_dev_param_mask, NULL, &ide_nohpa, 0);
+MODULE_PARM_DESC(nohpa, "disable Host Protected Area for a device");
+
 static unsigned int ide_noprobe;
 
 module_param_call(noprobe, ide_set_dev_param_mask, NULL, &ide_noprobe, 0);
@@ -281,6 +286,11 @@
 				 drive->name);
 		drive->dev_flags |= IDE_DFLAG_NOFLUSH;
 	}
+	if (ide_nohpa & (1 << i)) {
+		printk(KERN_INFO "ide: disabling Host Protected Area for %s\n",
+				 drive->name);
+		drive->dev_flags |= IDE_DFLAG_NOHPA;
+	}
 	if (ide_noprobe & (1 << i)) {
 		printk(KERN_INFO "ide: skipping probe for %s\n", drive->name);
 		drive->dev_flags |= IDE_DFLAG_NOPROBE;
diff --git a/drivers/ide/ide_platform.c b/drivers/ide/ide_platform.c
index 051b4ab..ee9b55e 100644
--- a/drivers/ide/ide_platform.c
+++ b/drivers/ide/ide_platform.c
@@ -21,7 +21,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
-static void __devinit plat_ide_setup_ports(hw_regs_t *hw,
+static void __devinit plat_ide_setup_ports(struct ide_hw *hw,
 					   void __iomem *base,
 					   void __iomem *ctrl,
 					   struct pata_platform_info *pdata,
@@ -40,12 +40,11 @@
 	hw->io_ports.ctl_addr = (unsigned long)ctrl;
 
 	hw->irq = irq;
-
-	hw->chipset = ide_generic;
 }
 
 static const struct ide_port_info platform_ide_port_info = {
 	.host_flags		= IDE_HFLAG_NO_DMA,
+	.chipset		= ide_generic,
 };
 
 static int __devinit plat_ide_probe(struct platform_device *pdev)
@@ -55,7 +54,7 @@
 	struct pata_platform_info *pdata;
 	struct ide_host *host;
 	int ret = 0, mmio = 0;
-	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 	struct ide_port_info d = platform_ide_port_info;
 
 	pdata = pdev->dev.platform_data;
@@ -99,7 +98,7 @@
 	if (mmio)
 		d.host_flags |= IDE_HFLAG_MMIO;
 
-	ret = ide_host_add(&d, hws, &host);
+	ret = ide_host_add(&d, hws, 1, &host);
 	if (ret)
 		goto out;
 
diff --git a/drivers/ide/macide.c b/drivers/ide/macide.c
index 4b1718e..1447c8c 100644
--- a/drivers/ide/macide.c
+++ b/drivers/ide/macide.c
@@ -62,7 +62,7 @@
 	return 0;
 }
 
-static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base,
+static void __init macide_setup_ports(struct ide_hw *hw, unsigned long base,
 				      int irq, ide_ack_intr_t *ack_intr)
 {
 	int i;
@@ -76,13 +76,12 @@
 
 	hw->irq = irq;
 	hw->ack_intr = ack_intr;
-
-	hw->chipset = ide_generic;
 }
 
 static const struct ide_port_info macide_port_info = {
 	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
 	.irq_flags		= IRQF_SHARED,
+	.chipset		= ide_generic,
 };
 
 static const char *mac_ide_name[] =
@@ -97,7 +96,7 @@
 	ide_ack_intr_t *ack_intr;
 	unsigned long base;
 	int irq;
-	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 
 	if (!MACH_IS_MAC)
 		return -ENODEV;
@@ -127,7 +126,7 @@
 
 	macide_setup_ports(&hw, base, irq, ack_intr);
 
-	return ide_host_add(&macide_port_info, hws, NULL);
+	return ide_host_add(&macide_port_info, hws, 1, NULL);
 }
 
 module_init(macide_init);
diff --git a/drivers/ide/palm_bk3710.c b/drivers/ide/palm_bk3710.c
index 09d813d..3c1dc01 100644
--- a/drivers/ide/palm_bk3710.c
+++ b/drivers/ide/palm_bk3710.c
@@ -306,6 +306,7 @@
 	.host_flags		= IDE_HFLAG_MMIO,
 	.pio_mask		= ATA_PIO4,
 	.mwdma_mask		= ATA_MWDMA2,
+	.chipset		= ide_palm3710,
 };
 
 static int __init palm_bk3710_probe(struct platform_device *pdev)
@@ -315,7 +316,7 @@
 	void __iomem *base;
 	unsigned long rate, mem_size;
 	int i, rc;
-	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 
 	clk = clk_get(&pdev->dev, "IDECLK");
 	if (IS_ERR(clk))
@@ -363,13 +364,12 @@
 			(base + IDE_PALM_ATA_PRI_CTL_OFFSET);
 	hw.irq = irq->start;
 	hw.dev = &pdev->dev;
-	hw.chipset = ide_palm3710;
 
 	palm_bk3710_port_info.udma_mask = rate < 100000000 ? ATA_UDMA4 :
 							     ATA_UDMA5;
 
 	/* Register the IDE interface with Linux */
-	rc = ide_host_add(&palm_bk3710_port_info, hws, NULL);
+	rc = ide_host_add(&palm_bk3710_port_info, hws, 1, NULL);
 	if (rc)
 		goto out;
 
diff --git a/drivers/ide/pdc202xx_new.c b/drivers/ide/pdc202xx_new.c
index b68906c..65ba823 100644
--- a/drivers/ide/pdc202xx_new.c
+++ b/drivers/ide/pdc202xx_new.c
@@ -40,18 +40,6 @@
 #define DBG(fmt, args...)
 #endif
 
-static const char *pdc_quirk_drives[] = {
-	"QUANTUM FIREBALLlct08 08",
-	"QUANTUM FIREBALLP KA6.4",
-	"QUANTUM FIREBALLP KA9.1",
-	"QUANTUM FIREBALLP LM20.4",
-	"QUANTUM FIREBALLP KX13.6",
-	"QUANTUM FIREBALLP KX20.5",
-	"QUANTUM FIREBALLP KX27.3",
-	"QUANTUM FIREBALLP LM20.5",
-	NULL
-};
-
 static u8 max_dma_rate(struct pci_dev *pdev)
 {
 	u8 mode;
@@ -200,19 +188,6 @@
 		return ATA_CBL_PATA80;
 }
 
-static void pdcnew_quirkproc(ide_drive_t *drive)
-{
-	const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
-
-	for (list = pdc_quirk_drives; *list != NULL; list++)
-		if (strstr(m, *list) != NULL) {
-			drive->quirk_list = 2;
-			return;
-		}
-
-	drive->quirk_list = 0;
-}
-
 static void pdcnew_reset(ide_drive_t *drive)
 {
 	/*
@@ -473,7 +448,6 @@
 static const struct ide_port_ops pdcnew_port_ops = {
 	.set_pio_mode		= pdcnew_set_pio_mode,
 	.set_dma_mode		= pdcnew_set_dma_mode,
-	.quirkproc		= pdcnew_quirkproc,
 	.resetproc		= pdcnew_reset,
 	.cable_detect		= pdcnew_cable_detect,
 };
diff --git a/drivers/ide/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c
index e24ecc8..b6abf7e 100644
--- a/drivers/ide/pdc202xx_old.c
+++ b/drivers/ide/pdc202xx_old.c
@@ -23,18 +23,6 @@
 
 #define PDC202XX_DEBUG_DRIVE_INFO	0
 
-static const char *pdc_quirk_drives[] = {
-	"QUANTUM FIREBALLlct08 08",
-	"QUANTUM FIREBALLP KA6.4",
-	"QUANTUM FIREBALLP KA9.1",
-	"QUANTUM FIREBALLP LM20.4",
-	"QUANTUM FIREBALLP KX13.6",
-	"QUANTUM FIREBALLP KX20.5",
-	"QUANTUM FIREBALLP KX27.3",
-	"QUANTUM FIREBALLP LM20.5",
-	NULL
-};
-
 static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
 
 static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
@@ -151,19 +139,6 @@
 	outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
 }
 
-static void pdc202xx_quirkproc(ide_drive_t *drive)
-{
-	const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
-
-	for (list = pdc_quirk_drives; *list != NULL; list++)
-		if (strstr(m, *list) != NULL) {
-			drive->quirk_list = 2;
-			return;
-		}
-
-	drive->quirk_list = 0;
-}
-
 static void pdc202xx_dma_start(ide_drive_t *drive)
 {
 	if (drive->current_speed > XFER_UDMA_2)
@@ -203,52 +178,6 @@
 	return ide_dma_end(drive);
 }
 
-static int pdc202xx_dma_test_irq(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= drive->hwif;
-	unsigned long high_16	= hwif->extra_base - 16;
-	u8 dma_stat		= inb(hwif->dma_base + ATA_DMA_STATUS);
-	u8 sc1d			= inb(high_16 + 0x001d);
-
-	if (hwif->channel) {
-		/* bit7: Error, bit6: Interrupting, bit5: FIFO Full, bit4: FIFO Empty */
-		if ((sc1d & 0x50) == 0x50)
-			goto somebody_else;
-		else if ((sc1d & 0x40) == 0x40)
-			return (dma_stat & 4) == 4;
-	} else {
-		/* bit3: Error, bit2: Interrupting, bit1: FIFO Full, bit0: FIFO Empty */
-		if ((sc1d & 0x05) == 0x05)
-			goto somebody_else;
-		else if ((sc1d & 0x04) == 0x04)
-			return (dma_stat & 4) == 4;
-	}
-somebody_else:
-	return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-}
-
-static void pdc202xx_reset(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= drive->hwif;
-	unsigned long high_16	= hwif->extra_base - 16;
-	u8 udma_speed_flag	= inb(high_16 | 0x001f);
-
-	printk(KERN_WARNING "PDC202xx: software reset...\n");
-
-	outb(udma_speed_flag | 0x10, high_16 | 0x001f);
-	mdelay(100);
-	outb(udma_speed_flag & ~0x10, high_16 | 0x001f);
-	mdelay(2000);	/* 2 seconds ?! */
-
-	ide_set_max_pio(drive);
-}
-
-static void pdc202xx_dma_lost_irq(ide_drive_t *drive)
-{
-	pdc202xx_reset(drive);
-	ide_dma_lost_irq(drive);
-}
-
 static int init_chipset_pdc202xx(struct pci_dev *dev)
 {
 	unsigned long dmabase = pci_resource_start(dev, 4);
@@ -302,37 +231,22 @@
 static const struct ide_port_ops pdc20246_port_ops = {
 	.set_pio_mode		= pdc202xx_set_pio_mode,
 	.set_dma_mode		= pdc202xx_set_mode,
-	.quirkproc		= pdc202xx_quirkproc,
 };
 
 static const struct ide_port_ops pdc2026x_port_ops = {
 	.set_pio_mode		= pdc202xx_set_pio_mode,
 	.set_dma_mode		= pdc202xx_set_mode,
-	.quirkproc		= pdc202xx_quirkproc,
-	.resetproc		= pdc202xx_reset,
 	.cable_detect		= pdc2026x_cable_detect,
 };
 
-static const struct ide_dma_ops pdc20246_dma_ops = {
-	.dma_host_set		= ide_dma_host_set,
-	.dma_setup		= ide_dma_setup,
-	.dma_start		= ide_dma_start,
-	.dma_end		= ide_dma_end,
-	.dma_test_irq		= pdc202xx_dma_test_irq,
-	.dma_lost_irq		= ide_dma_lost_irq,
-	.dma_timer_expiry	= ide_dma_sff_timer_expiry,
-	.dma_sff_read_status	= ide_dma_sff_read_status,
-};
-
 static const struct ide_dma_ops pdc2026x_dma_ops = {
 	.dma_host_set		= ide_dma_host_set,
 	.dma_setup		= ide_dma_setup,
 	.dma_start		= pdc202xx_dma_start,
 	.dma_end		= pdc202xx_dma_end,
-	.dma_test_irq		= pdc202xx_dma_test_irq,
-	.dma_lost_irq		= pdc202xx_dma_lost_irq,
+	.dma_test_irq		= ide_dma_test_irq,
+	.dma_lost_irq		= ide_dma_lost_irq,
 	.dma_timer_expiry	= ide_dma_sff_timer_expiry,
-	.dma_clear		= pdc202xx_reset,
 	.dma_sff_read_status	= ide_dma_sff_read_status,
 };
 
@@ -354,7 +268,7 @@
 		.name		= DRV_NAME,
 		.init_chipset	= init_chipset_pdc202xx,
 		.port_ops	= &pdc20246_port_ops,
-		.dma_ops	= &pdc20246_dma_ops,
+		.dma_ops	= &sff_dma_ops,
 		.host_flags	= IDE_HFLAGS_PDC202XX,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c
index f76e4e6..97642a7a 100644
--- a/drivers/ide/pmac.c
+++ b/drivers/ide/pmac.c
@@ -1023,13 +1023,14 @@
  * Setup, register & probe an IDE channel driven by this driver, this is
  * called by one of the 2 probe functions (macio or PCI).
  */
-static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
+static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif,
+					   struct ide_hw *hw)
 {
 	struct device_node *np = pmif->node;
 	const int *bidp;
 	struct ide_host *host;
 	ide_hwif_t *hwif;
-	hw_regs_t *hws[] = { hw, NULL, NULL, NULL };
+	struct ide_hw *hws[] = { hw };
 	struct ide_port_info d = pmac_port_info;
 	int rc;
 
@@ -1077,7 +1078,7 @@
 	/* Make sure we have sane timings */
 	sanitize_timings(pmif);
 
-	host = ide_host_alloc(&d, hws);
+	host = ide_host_alloc(&d, hws, 1);
 	if (host == NULL)
 		return -ENOMEM;
 	hwif = host->ports[0];
@@ -1124,7 +1125,7 @@
 	return 0;
 }
 
-static void __devinit pmac_ide_init_ports(hw_regs_t *hw, unsigned long base)
+static void __devinit pmac_ide_init_ports(struct ide_hw *hw, unsigned long base)
 {
 	int i;
 
@@ -1144,7 +1145,7 @@
 	unsigned long regbase;
 	pmac_ide_hwif_t *pmif;
 	int irq, rc;
-	hw_regs_t hw;
+	struct ide_hw hw;
 
 	pmif = kzalloc(sizeof(*pmif), GFP_KERNEL);
 	if (pmif == NULL)
@@ -1268,7 +1269,7 @@
 	void __iomem *base;
 	unsigned long rbase, rlen;
 	int rc;
-	hw_regs_t hw;
+	struct ide_hw hw;
 
 	np = pci_device_to_OF_node(pdev);
 	if (np == NULL) {
diff --git a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c
index c793466..ab49a97 100644
--- a/drivers/ide/q40ide.c
+++ b/drivers/ide/q40ide.c
@@ -51,11 +51,11 @@
 /*
  * Addresses are pretranslated for Q40 ISA access.
  */
-static void q40_ide_setup_ports(hw_regs_t *hw, unsigned long base,
+static void q40_ide_setup_ports(struct ide_hw *hw, unsigned long base,
 			ide_ack_intr_t *ack_intr,
 			int irq)
 {
-	memset(hw, 0, sizeof(hw_regs_t));
+	memset(hw, 0, sizeof(*hw));
 	/* BIG FAT WARNING: 
 	   assumption: only DATA port is ever used in 16 bit mode */
 	hw->io_ports.data_addr = Q40_ISA_IO_W(base);
@@ -70,8 +70,6 @@
 
 	hw->irq = irq;
 	hw->ack_intr = ack_intr;
-
-	hw->chipset = ide_generic;
 }
 
 static void q40ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
@@ -119,6 +117,7 @@
 	.tp_ops			= &q40ide_tp_ops,
 	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
 	.irq_flags		= IRQF_SHARED,
+	.chipset		= ide_generic,
 };
 
 /* 
@@ -136,7 +135,7 @@
 static int __init q40ide_init(void)
 {
     int i;
-    hw_regs_t hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL, NULL, NULL };
+    struct ide_hw hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL };
 
     if (!MACH_IS_Q40)
       return -ENODEV;
@@ -163,7 +162,7 @@
 	hws[i] = &hw[i];
     }
 
-    return ide_host_add(&q40ide_port_info, hws, NULL);
+    return ide_host_add(&q40ide_port_info, hws, Q40IDE_NUM_HWIFS, NULL);
 }
 
 module_init(q40ide_init);
diff --git a/drivers/ide/rapide.c b/drivers/ide/rapide.c
index d5003ca..00f5424 100644
--- a/drivers/ide/rapide.c
+++ b/drivers/ide/rapide.c
@@ -13,9 +13,10 @@
 
 static const struct ide_port_info rapide_port_info = {
 	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
+	.chipset		= ide_generic,
 };
 
-static void rapide_setup_ports(hw_regs_t *hw, void __iomem *base,
+static void rapide_setup_ports(struct ide_hw *hw, void __iomem *base,
 			       void __iomem *ctrl, unsigned int sz, int irq)
 {
 	unsigned long port = (unsigned long)base;
@@ -35,7 +36,7 @@
 	void __iomem *base;
 	struct ide_host *host;
 	int ret;
-	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 
 	ret = ecard_request_resources(ec);
 	if (ret)
@@ -49,10 +50,9 @@
 
 	memset(&hw, 0, sizeof(hw));
 	rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq);
-	hw.chipset = ide_generic;
 	hw.dev = &ec->dev;
 
-	ret = ide_host_add(&rapide_port_info, hws, &host);
+	ret = ide_host_add(&rapide_port_info, hws, 1, &host);
 	if (ret)
 		goto release;
 
diff --git a/drivers/ide/scc_pata.c b/drivers/ide/scc_pata.c
index 5be41f2..1104bb3 100644
--- a/drivers/ide/scc_pata.c
+++ b/drivers/ide/scc_pata.c
@@ -559,7 +559,7 @@
 {
 	struct scc_ports *ports = pci_get_drvdata(dev);
 	struct ide_host *host;
-	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 	int i, rc;
 
 	memset(&hw, 0, sizeof(hw));
@@ -567,9 +567,8 @@
 		hw.io_ports_array[i] = ports->dma + 0x20 + i * 4;
 	hw.irq = dev->irq;
 	hw.dev = &dev->dev;
-	hw.chipset = ide_pci;
 
-	rc = ide_host_add(d, hws, &host);
+	rc = ide_host_add(d, hws, 1, &host);
 	if (rc)
 		return rc;
 
@@ -823,6 +822,7 @@
 	.host_flags	= IDE_HFLAG_SINGLE,
 	.irq_flags	= IRQF_SHARED,
 	.pio_mask	= ATA_PIO4,
+	.chipset	= ide_pci,
 };
 
 /**
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index 7a3a12d..ab3db61 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -1,7 +1,7 @@
 /*
  *  Copyright (C) 1998-2000  Andre Hedrick <andre@linux-ide.org>
  *  Copyright (C) 1995-1998  Mark Lord
- *  Copyright (C)      2007  Bartlomiej Zolnierkiewicz
+ *  Copyright (C) 2007-2009  Bartlomiej Zolnierkiewicz
  *
  *  May be copied or modified under the terms of the GNU General Public License
  */
@@ -301,11 +301,11 @@
 }
 
 /**
- *	ide_hw_configure	-	configure a hw_regs_t instance
+ *	ide_hw_configure	-	configure a struct ide_hw instance
  *	@dev: PCI device holding interface
  *	@d: IDE port info
  *	@port: port number
- *	@hw: hw_regs_t instance corresponding to this port
+ *	@hw: struct ide_hw instance corresponding to this port
  *
  *	Perform the initial set up for the hardware interface structure. This
  *	is done per interface port rather than per PCI device. There may be
@@ -315,7 +315,7 @@
  */
 
 static int ide_hw_configure(struct pci_dev *dev, const struct ide_port_info *d,
-			    unsigned int port, hw_regs_t *hw)
+			    unsigned int port, struct ide_hw *hw)
 {
 	unsigned long ctl = 0, base = 0;
 
@@ -344,7 +344,6 @@
 
 	memset(hw, 0, sizeof(*hw));
 	hw->dev = &dev->dev;
-	hw->chipset = d->chipset ? d->chipset : ide_pci;
 	ide_std_init_ports(hw, base, ctl | 2);
 
 	return 0;
@@ -446,8 +445,8 @@
  *	ide_pci_setup_ports	-	configure ports/devices on PCI IDE
  *	@dev: PCI device
  *	@d: IDE port info
- *	@hw: hw_regs_t instances corresponding to this PCI IDE device
- *	@hws: hw_regs_t pointers table to update
+ *	@hw: struct ide_hw instances corresponding to this PCI IDE device
+ *	@hws: struct ide_hw pointers table to update
  *
  *	Scan the interfaces attached to this device and do any
  *	necessary per port setup. Attach the devices and ask the
@@ -459,7 +458,7 @@
  */
 
 void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d,
-			 hw_regs_t *hw, hw_regs_t **hws)
+			 struct ide_hw *hw, struct ide_hw **hws)
 {
 	int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port;
 	u8 tmp;
@@ -535,61 +534,15 @@
 	return ret;
 }
 
-int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d,
-		     void *priv)
-{
-	struct ide_host *host;
-	hw_regs_t hw[4], *hws[] = { NULL, NULL, NULL, NULL };
-	int ret;
-
-	ret = ide_setup_pci_controller(dev, d, 1);
-	if (ret < 0)
-		goto out;
-
-	ide_pci_setup_ports(dev, d, &hw[0], &hws[0]);
-
-	host = ide_host_alloc(d, hws);
-	if (host == NULL) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	host->dev[0] = &dev->dev;
-
-	host->host_priv = priv;
-
-	host->irq_flags = IRQF_SHARED;
-
-	pci_set_drvdata(dev, host);
-
-	ret = do_ide_setup_pci_device(dev, d, 1);
-	if (ret < 0)
-		goto out;
-
-	/* fixup IRQ */
-	if (ide_pci_is_in_compatibility_mode(dev)) {
-		hw[0].irq = pci_get_legacy_ide_irq(dev, 0);
-		hw[1].irq = pci_get_legacy_ide_irq(dev, 1);
-	} else
-		hw[1].irq = hw[0].irq = ret;
-
-	ret = ide_host_register(host, d, hws);
-	if (ret)
-		ide_host_free(host);
-out:
-	return ret;
-}
-EXPORT_SYMBOL_GPL(ide_pci_init_one);
-
 int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2,
 		     const struct ide_port_info *d, void *priv)
 {
 	struct pci_dev *pdev[] = { dev1, dev2 };
 	struct ide_host *host;
-	int ret, i;
-	hw_regs_t hw[4], *hws[] = { NULL, NULL, NULL, NULL };
+	int ret, i, n_ports = dev2 ? 4 : 2;
+	struct ide_hw hw[4], *hws[] = { NULL, NULL, NULL, NULL };
 
-	for (i = 0; i < 2; i++) {
+	for (i = 0; i < n_ports / 2; i++) {
 		ret = ide_setup_pci_controller(pdev[i], d, !i);
 		if (ret < 0)
 			goto out;
@@ -597,23 +550,24 @@
 		ide_pci_setup_ports(pdev[i], d, &hw[i*2], &hws[i*2]);
 	}
 
-	host = ide_host_alloc(d, hws);
+	host = ide_host_alloc(d, hws, n_ports);
 	if (host == NULL) {
 		ret = -ENOMEM;
 		goto out;
 	}
 
 	host->dev[0] = &dev1->dev;
-	host->dev[1] = &dev2->dev;
+	if (dev2)
+		host->dev[1] = &dev2->dev;
 
 	host->host_priv = priv;
-
 	host->irq_flags = IRQF_SHARED;
 
 	pci_set_drvdata(pdev[0], host);
-	pci_set_drvdata(pdev[1], host);
+	if (dev2)
+		pci_set_drvdata(pdev[1], host);
 
-	for (i = 0; i < 2; i++) {
+	for (i = 0; i < n_ports / 2; i++) {
 		ret = do_ide_setup_pci_device(pdev[i], d, !i);
 
 		/*
@@ -639,6 +593,13 @@
 }
 EXPORT_SYMBOL_GPL(ide_pci_init_two);
 
+int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d,
+		     void *priv)
+{
+	return ide_pci_init_two(dev, NULL, d, priv);
+}
+EXPORT_SYMBOL_GPL(ide_pci_init_one);
+
 void ide_pci_remove(struct pci_dev *dev)
 {
 	struct ide_host *host = pci_get_drvdata(dev);
diff --git a/drivers/ide/sgiioc4.c b/drivers/ide/sgiioc4.c
index e5d2a48..5f37f16 100644
--- a/drivers/ide/sgiioc4.c
+++ b/drivers/ide/sgiioc4.c
@@ -91,7 +91,7 @@
 
 
 static void
-sgiioc4_init_hwif_ports(hw_regs_t * hw, unsigned long data_port,
+sgiioc4_init_hwif_ports(struct ide_hw *hw, unsigned long data_port,
 			unsigned long ctrl_port, unsigned long irq_port)
 {
 	unsigned long reg = data_port;
@@ -546,7 +546,7 @@
 	unsigned long cmd_base, irqport;
 	unsigned long bar0, cmd_phys_base, ctl;
 	void __iomem *virt_base;
-	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 	int rc;
 
 	/*  Get the CmdBlk and CtrlBlk Base Registers */
@@ -575,13 +575,12 @@
 	memset(&hw, 0, sizeof(hw));
 	sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
 	hw.irq = dev->irq;
-	hw.chipset = ide_pci;
 	hw.dev = &dev->dev;
 
 	/* Initializing chipset IRQ Registers */
 	writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4));
 
-	rc = ide_host_add(&sgiioc4_port_info, hws, NULL);
+	rc = ide_host_add(&sgiioc4_port_info, hws, 1, NULL);
 	if (!rc)
 		return 0;
 
diff --git a/drivers/ide/siimage.c b/drivers/ide/siimage.c
index e4973cd..bd82d22 100644
--- a/drivers/ide/siimage.c
+++ b/drivers/ide/siimage.c
@@ -451,8 +451,8 @@
 static void sil_sata_pre_reset(ide_drive_t *drive)
 {
 	if (drive->media == ide_disk) {
-		drive->special.b.set_geometry = 0;
-		drive->special.b.recalibrate = 0;
+		drive->special_flags &=
+			~(IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE);
 	}
 }
 
diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
index b0a4606..0924abf 100644
--- a/drivers/ide/sl82c105.c
+++ b/drivers/ide/sl82c105.c
@@ -10,7 +10,7 @@
  * with the timing registers setup.
  *  -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org
  *
- * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
+ * Copyright (C) 2006-2007,2009 MontaVista Software, Inc. <source@mvista.com>
  * Copyright (C)      2007 Bartlomiej Zolnierkiewicz
  */
 
@@ -146,14 +146,15 @@
 	u32 val, mask		= hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
 	u8 dma_cmd;
 
-	printk("sl82c105: lost IRQ, resetting host\n");
+	printk(KERN_WARNING "sl82c105: lost IRQ, resetting host\n");
 
 	/*
 	 * Check the raw interrupt from the drive.
 	 */
 	pci_read_config_dword(dev, 0x40, &val);
 	if (val & mask)
-		printk("sl82c105: drive was requesting IRQ, but host lost it\n");
+		printk(KERN_INFO "sl82c105: drive was requesting IRQ, "
+		       "but host lost it\n");
 
 	/*
 	 * Was DMA enabled?  If so, disable it - we're resetting the
@@ -162,7 +163,7 @@
 	dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
 	if (dma_cmd & 1) {
 		outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
-		printk("sl82c105: DMA was enabled\n");
+		printk(KERN_INFO "sl82c105: DMA was enabled\n");
 	}
 
 	sl82c105_reset_host(dev);
diff --git a/drivers/ide/tx4938ide.c b/drivers/ide/tx4938ide.c
index e33d764..ea89fdd 100644
--- a/drivers/ide/tx4938ide.c
+++ b/drivers/ide/tx4938ide.c
@@ -130,8 +130,7 @@
 
 static int __init tx4938ide_probe(struct platform_device *pdev)
 {
-	hw_regs_t hw;
-	hw_regs_t *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 	struct ide_host *host;
 	struct resource *res;
 	struct tx4938ide_platform_info *pdata = pdev->dev.platform_data;
@@ -183,7 +182,7 @@
 		tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, 0);
 	else
 		d.port_ops = NULL;
-	ret = ide_host_add(&d, hws, &host);
+	ret = ide_host_add(&d, hws, 1, &host);
 	if (!ret)
 		platform_set_drvdata(pdev, host);
 	return ret;
diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c
index 5ca7622..64b58ec 100644
--- a/drivers/ide/tx4939ide.c
+++ b/drivers/ide/tx4939ide.c
@@ -537,8 +537,7 @@
 
 static int __init tx4939ide_probe(struct platform_device *pdev)
 {
-	hw_regs_t hw;
-	hw_regs_t *hws[] = { &hw, NULL, NULL, NULL };
+	struct ide_hw hw, *hws[] = { &hw };
 	struct ide_host *host;
 	struct resource *res;
 	int irq, ret;
@@ -581,7 +580,7 @@
 	hw.dev = &pdev->dev;
 
 	pr_info("TX4939 IDE interface (base %#lx, irq %d)\n", mapbase, irq);
-	host = ide_host_alloc(&tx4939ide_port_info, hws);
+	host = ide_host_alloc(&tx4939ide_port_info, hws, 1);
 	if (!host)
 		return -ENOMEM;
 	/* use extra_base for base address of the all registers */
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 75223f5..0ba6ec8 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -257,11 +257,8 @@
 {
 	struct iscsi_iser_task *iser_task = task->dd_data;
 
-	/*
-	 * mgmt tasks do not need special cleanup and we do not
-	 * allocate anything in the init task callout
-	 */
-	if (!task->sc || task->state == ISCSI_TASK_PENDING)
+	/* mgmt tasks do not need special cleanup */
+	if (!task->sc)
 		return;
 
 	if (iser_task->status == ISER_TASK_STATUS_STARTED) {
@@ -517,7 +514,8 @@
 }
 
 static struct iscsi_endpoint *
-iscsi_iser_ep_connect(struct sockaddr *dst_addr, int non_blocking)
+iscsi_iser_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
+		      int non_blocking)
 {
 	int err;
 	struct iser_conn *ib_conn;
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index da3c3a5..c4b3fbd 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -192,7 +192,7 @@
 
 config SERIO_XILINX_XPS_PS2
 	tristate "Xilinx XPS PS/2 Controller Support"
-	depends on PPC
+	depends on PPC || MICROBLAZE
 	help
 	  This driver supports XPS PS/2 IP from the Xilinx EDK on
 	  PowerPC platform.
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
index a28c06d..89b3941 100644
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -135,7 +135,7 @@
 	io->dev.parent	= &dev->dev;
 
 	kmi->io 	= io;
-	kmi->base	= ioremap(dev->res.start, KMI_SIZE);
+	kmi->base	= ioremap(dev->res.start, resource_size(&dev->res));
 	if (!kmi->base) {
 		ret = -ENOMEM;
 		goto out;
diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c
index 1aa46a3..173d104 100644
--- a/drivers/leds/leds-h1940.c
+++ b/drivers/leds/leds-h1940.c
@@ -16,6 +16,8 @@
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/leds.h>
+#include <linux/gpio.h>
+
 #include <mach/regs-gpio.h>
 #include <mach/hardware.h>
 #include <mach/h1940-latch.h>
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
index aa2e7ae..aa7acf3 100644
--- a/drivers/leds/leds-s3c24xx.c
+++ b/drivers/leds/leds-s3c24xx.c
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
+#include <linux/gpio.h>
 
 #include <mach/hardware.h>
 #include <mach/regs-gpio.h>
diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig
index a3d3cba..0aaa059 100644
--- a/drivers/lguest/Kconfig
+++ b/drivers/lguest/Kconfig
@@ -1,6 +1,6 @@
 config LGUEST
 	tristate "Linux hypervisor example code"
-	depends on X86_32 && EXPERIMENTAL && !X86_PAE && FUTEX
+	depends on X86_32 && EXPERIMENTAL && EVENTFD
 	select HVC_DRIVER
 	---help---
 	  This is a very simple module which allows you to run
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
index 4845fb3..a6974e9 100644
--- a/drivers/lguest/core.c
+++ b/drivers/lguest/core.c
@@ -95,7 +95,7 @@
 	 * array of struct pages.  It increments that pointer, but we don't
 	 * care. */
 	pagep = switcher_page;
-	err = map_vm_area(switcher_vma, PAGE_KERNEL, &pagep);
+	err = map_vm_area(switcher_vma, PAGE_KERNEL_EXEC, &pagep);
 	if (err) {
 		printk("lguest: map_vm_area failed: %i\n", err);
 		goto free_vma;
@@ -188,6 +188,9 @@
 {
 	/* We stop running once the Guest is dead. */
 	while (!cpu->lg->dead) {
+		unsigned int irq;
+		bool more;
+
 		/* First we run any hypercalls the Guest wants done. */
 		if (cpu->hcall)
 			do_hypercalls(cpu);
@@ -195,23 +198,23 @@
 		/* It's possible the Guest did a NOTIFY hypercall to the
 		 * Launcher, in which case we return from the read() now. */
 		if (cpu->pending_notify) {
-			if (put_user(cpu->pending_notify, user))
-				return -EFAULT;
-			return sizeof(cpu->pending_notify);
+			if (!send_notify_to_eventfd(cpu)) {
+				if (put_user(cpu->pending_notify, user))
+					return -EFAULT;
+				return sizeof(cpu->pending_notify);
+			}
 		}
 
 		/* Check for signals */
 		if (signal_pending(current))
 			return -ERESTARTSYS;
 
-		/* If Waker set break_out, return to Launcher. */
-		if (cpu->break_out)
-			return -EAGAIN;
-
 		/* Check if there are any interrupts which can be delivered now:
 		 * if so, this sets up the hander to be executed when we next
 		 * run the Guest. */
-		maybe_do_interrupt(cpu);
+		irq = interrupt_pending(cpu, &more);
+		if (irq < LGUEST_IRQS)
+			try_deliver_interrupt(cpu, irq, more);
 
 		/* All long-lived kernel loops need to check with this horrible
 		 * thing called the freezer.  If the Host is trying to suspend,
@@ -224,10 +227,15 @@
 			break;
 
 		/* If the Guest asked to be stopped, we sleep.  The Guest's
-		 * clock timer or LHREQ_BREAK from the Waker will wake us. */
+		 * clock timer will wake us. */
 		if (cpu->halted) {
 			set_current_state(TASK_INTERRUPTIBLE);
-			schedule();
+			/* Just before we sleep, make sure no interrupt snuck in
+			 * which we should be doing. */
+			if (interrupt_pending(cpu, &more) < LGUEST_IRQS)
+				set_current_state(TASK_RUNNING);
+			else
+				schedule();
 			continue;
 		}
 
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c
index 54d66f0..c29ffa1 100644
--- a/drivers/lguest/hypercalls.c
+++ b/drivers/lguest/hypercalls.c
@@ -37,6 +37,10 @@
 		/* This call does nothing, except by breaking out of the Guest
 		 * it makes us process all the asynchronous hypercalls. */
 		break;
+	case LHCALL_SEND_INTERRUPTS:
+		/* This call does nothing too, but by breaking out of the Guest
+		 * it makes us process any pending interrupts. */
+		break;
 	case LHCALL_LGUEST_INIT:
 		/* You can't get here unless you're already initialized.  Don't
 		 * do that. */
@@ -73,11 +77,21 @@
 		guest_set_stack(cpu, args->arg1, args->arg2, args->arg3);
 		break;
 	case LHCALL_SET_PTE:
+#ifdef CONFIG_X86_PAE
+		guest_set_pte(cpu, args->arg1, args->arg2,
+				__pte(args->arg3 | (u64)args->arg4 << 32));
+#else
 		guest_set_pte(cpu, args->arg1, args->arg2, __pte(args->arg3));
+#endif
 		break;
+	case LHCALL_SET_PGD:
+		guest_set_pgd(cpu->lg, args->arg1, args->arg2);
+		break;
+#ifdef CONFIG_X86_PAE
 	case LHCALL_SET_PMD:
 		guest_set_pmd(cpu->lg, args->arg1, args->arg2);
 		break;
+#endif
 	case LHCALL_SET_CLOCKEVENT:
 		guest_set_clockevent(cpu, args->arg1);
 		break;
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
index 6e99adb..0e9067b 100644
--- a/drivers/lguest/interrupts_and_traps.c
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -128,30 +128,39 @@
 /*H:205
  * Virtual Interrupts.
  *
- * maybe_do_interrupt() gets called before every entry to the Guest, to see if
- * we should divert the Guest to running an interrupt handler. */
-void maybe_do_interrupt(struct lg_cpu *cpu)
+ * interrupt_pending() returns the first pending interrupt which isn't blocked
+ * by the Guest.  It is called before every entry to the Guest, and just before
+ * we go to sleep when the Guest has halted itself. */
+unsigned int interrupt_pending(struct lg_cpu *cpu, bool *more)
 {
 	unsigned int irq;
 	DECLARE_BITMAP(blk, LGUEST_IRQS);
-	struct desc_struct *idt;
 
 	/* If the Guest hasn't even initialized yet, we can do nothing. */
 	if (!cpu->lg->lguest_data)
-		return;
+		return LGUEST_IRQS;
 
 	/* Take our "irqs_pending" array and remove any interrupts the Guest
 	 * wants blocked: the result ends up in "blk". */
 	if (copy_from_user(&blk, cpu->lg->lguest_data->blocked_interrupts,
 			   sizeof(blk)))
-		return;
+		return LGUEST_IRQS;
 	bitmap_andnot(blk, cpu->irqs_pending, blk, LGUEST_IRQS);
 
 	/* Find the first interrupt. */
 	irq = find_first_bit(blk, LGUEST_IRQS);
-	/* None?  Nothing to do */
-	if (irq >= LGUEST_IRQS)
-		return;
+	*more = find_next_bit(blk, LGUEST_IRQS, irq+1);
+
+	return irq;
+}
+
+/* This actually diverts the Guest to running an interrupt handler, once an
+ * interrupt has been identified by interrupt_pending(). */
+void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more)
+{
+	struct desc_struct *idt;
+
+	BUG_ON(irq >= LGUEST_IRQS);
 
 	/* They may be in the middle of an iret, where they asked us never to
 	 * deliver interrupts. */
@@ -170,8 +179,12 @@
 		u32 irq_enabled;
 		if (get_user(irq_enabled, &cpu->lg->lguest_data->irq_enabled))
 			irq_enabled = 0;
-		if (!irq_enabled)
+		if (!irq_enabled) {
+			/* Make sure they know an IRQ is pending. */
+			put_user(X86_EFLAGS_IF,
+				 &cpu->lg->lguest_data->irq_pending);
 			return;
+		}
 	}
 
 	/* Look at the IDT entry the Guest gave us for this interrupt.  The
@@ -194,6 +207,25 @@
 	 * here is a compromise which means at least it gets updated every
 	 * timer interrupt. */
 	write_timestamp(cpu);
+
+	/* If there are no other interrupts we want to deliver, clear
+	 * the pending flag. */
+	if (!more)
+		put_user(0, &cpu->lg->lguest_data->irq_pending);
+}
+
+/* And this is the routine when we want to set an interrupt for the Guest. */
+void set_interrupt(struct lg_cpu *cpu, unsigned int irq)
+{
+	/* Next time the Guest runs, the core code will see if it can deliver
+	 * this interrupt. */
+	set_bit(irq, cpu->irqs_pending);
+
+	/* Make sure it sees it; it might be asleep (eg. halted), or
+	 * running the Guest right now, in which case kick_process()
+	 * will knock it out. */
+	if (!wake_up_process(cpu->tsk))
+		kick_process(cpu->tsk);
 }
 /*:*/
 
@@ -510,10 +542,7 @@
 	struct lg_cpu *cpu = container_of(timer, struct lg_cpu, hrt);
 
 	/* Remember the first interrupt is the timer interrupt. */
-	set_bit(0, cpu->irqs_pending);
-	/* If the Guest is actually stopped, we need to wake it up. */
-	if (cpu->halted)
-		wake_up_process(cpu->tsk);
+	set_interrupt(cpu, 0);
 	return HRTIMER_NORESTART;
 }
 
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
index af92a17..d4e8979 100644
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -49,7 +49,7 @@
 	u32 cr2;
 	int ts;
 	u32 esp1;
-	u8 ss1;
+	u16 ss1;
 
 	/* Bitmap of what has changed: see CHANGED_* above. */
 	int changed;
@@ -71,9 +71,7 @@
 	/* Virtual clock device */
 	struct hrtimer hrt;
 
-	/* Do we need to stop what we're doing and return to userspace? */
-	int break_out;
-	wait_queue_head_t break_wq;
+	/* Did the Guest tell us to halt? */
 	int halted;
 
 	/* Pending virtual interrupts */
@@ -82,6 +80,16 @@
 	struct lg_cpu_arch arch;
 };
 
+struct lg_eventfd {
+	unsigned long addr;
+	struct file *event;
+};
+
+struct lg_eventfd_map {
+	unsigned int num;
+	struct lg_eventfd map[];
+};
+
 /* The private info the thread maintains about the guest. */
 struct lguest
 {
@@ -102,6 +110,8 @@
 	unsigned int stack_pages;
 	u32 tsc_khz;
 
+	struct lg_eventfd_map *eventfds;
+
 	/* Dead? */
 	const char *dead;
 };
@@ -137,9 +147,13 @@
  * in the kernel. */
 #define pgd_flags(x)	(pgd_val(x) & ~PAGE_MASK)
 #define pgd_pfn(x)	(pgd_val(x) >> PAGE_SHIFT)
+#define pmd_flags(x)    (pmd_val(x) & ~PAGE_MASK)
+#define pmd_pfn(x)	(pmd_val(x) >> PAGE_SHIFT)
 
 /* interrupts_and_traps.c: */
-void maybe_do_interrupt(struct lg_cpu *cpu);
+unsigned int interrupt_pending(struct lg_cpu *cpu, bool *more);
+void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more);
+void set_interrupt(struct lg_cpu *cpu, unsigned int irq);
 bool deliver_trap(struct lg_cpu *cpu, unsigned int num);
 void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int i,
 			  u32 low, u32 hi);
@@ -150,6 +164,7 @@
 void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt,
 		const unsigned long *def);
 void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta);
+bool send_notify_to_eventfd(struct lg_cpu *cpu);
 void init_clockdev(struct lg_cpu *cpu);
 bool check_syscall_vector(struct lguest *lg);
 int init_interrupts(void);
@@ -168,7 +183,10 @@
 int init_guest_pagetable(struct lguest *lg);
 void free_guest_pagetable(struct lguest *lg);
 void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable);
+void guest_set_pgd(struct lguest *lg, unsigned long gpgdir, u32 i);
+#ifdef CONFIG_X86_PAE
 void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i);
+#endif
 void guest_pagetable_clear_all(struct lg_cpu *cpu);
 void guest_pagetable_flush_user(struct lg_cpu *cpu);
 void guest_set_pte(struct lg_cpu *cpu, unsigned long gpgdir,
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
index df44d96..e082cda 100644
--- a/drivers/lguest/lguest_device.c
+++ b/drivers/lguest/lguest_device.c
@@ -228,7 +228,8 @@
  * function. */
 static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
 				    unsigned index,
-				    void (*callback)(struct virtqueue *vq))
+				    void (*callback)(struct virtqueue *vq),
+				    const char *name)
 {
 	struct lguest_device *ldev = to_lgdev(vdev);
 	struct lguest_vq_info *lvq;
@@ -263,7 +264,7 @@
 	/* OK, tell virtio_ring.c to set up a virtqueue now we know its size
 	 * and we've got a pointer to its pages. */
 	vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN,
-				 vdev, lvq->pages, lg_notify, callback);
+				 vdev, lvq->pages, lg_notify, callback, name);
 	if (!vq) {
 		err = -ENOMEM;
 		goto unmap;
@@ -312,6 +313,38 @@
 	kfree(lvq);
 }
 
+static void lg_del_vqs(struct virtio_device *vdev)
+{
+	struct virtqueue *vq, *n;
+
+	list_for_each_entry_safe(vq, n, &vdev->vqs, list)
+		lg_del_vq(vq);
+}
+
+static int lg_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+		       struct virtqueue *vqs[],
+		       vq_callback_t *callbacks[],
+		       const char *names[])
+{
+	struct lguest_device *ldev = to_lgdev(vdev);
+	int i;
+
+	/* We must have this many virtqueues. */
+	if (nvqs > ldev->desc->num_vq)
+		return -ENOENT;
+
+	for (i = 0; i < nvqs; ++i) {
+		vqs[i] = lg_find_vq(vdev, i, callbacks[i], names[i]);
+		if (IS_ERR(vqs[i]))
+			goto error;
+	}
+	return 0;
+
+error:
+	lg_del_vqs(vdev);
+	return PTR_ERR(vqs[i]);
+}
+
 /* The ops structure which hooks everything together. */
 static struct virtio_config_ops lguest_config_ops = {
 	.get_features = lg_get_features,
@@ -321,8 +354,8 @@
 	.get_status = lg_get_status,
 	.set_status = lg_set_status,
 	.reset = lg_reset,
-	.find_vq = lg_find_vq,
-	.del_vq = lg_del_vq,
+	.find_vqs = lg_find_vqs,
+	.del_vqs = lg_del_vqs,
 };
 
 /* The root device for the lguest virtio devices.  This makes them appear as
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
index b8ee103..32e2971 100644
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -7,32 +7,83 @@
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
 #include <linux/sched.h>
+#include <linux/eventfd.h>
+#include <linux/file.h>
 #include "lg.h"
 
-/*L:055 When something happens, the Waker process needs a way to stop the
- * kernel running the Guest and return to the Launcher.  So the Waker writes
- * LHREQ_BREAK and the value "1" to /dev/lguest to do this.  Once the Launcher
- * has done whatever needs attention, it writes LHREQ_BREAK and "0" to release
- * the Waker. */
-static int break_guest_out(struct lg_cpu *cpu, const unsigned long __user*input)
+bool send_notify_to_eventfd(struct lg_cpu *cpu)
 {
-	unsigned long on;
+	unsigned int i;
+	struct lg_eventfd_map *map;
 
-	/* Fetch whether they're turning break on or off. */
-	if (get_user(on, input) != 0)
+	/* lg->eventfds is RCU-protected */
+	rcu_read_lock();
+	map = rcu_dereference(cpu->lg->eventfds);
+	for (i = 0; i < map->num; i++) {
+		if (map->map[i].addr == cpu->pending_notify) {
+			eventfd_signal(map->map[i].event, 1);
+			cpu->pending_notify = 0;
+			break;
+		}
+	}
+	rcu_read_unlock();
+	return cpu->pending_notify == 0;
+}
+
+static int add_eventfd(struct lguest *lg, unsigned long addr, int fd)
+{
+	struct lg_eventfd_map *new, *old = lg->eventfds;
+
+	if (!addr)
+		return -EINVAL;
+
+	/* Replace the old array with the new one, carefully: others can
+	 * be accessing it at the same time */
+	new = kmalloc(sizeof(*new) + sizeof(new->map[0]) * (old->num + 1),
+		      GFP_KERNEL);
+	if (!new)
+		return -ENOMEM;
+
+	/* First make identical copy. */
+	memcpy(new->map, old->map, sizeof(old->map[0]) * old->num);
+	new->num = old->num;
+
+	/* Now append new entry. */
+	new->map[new->num].addr = addr;
+	new->map[new->num].event = eventfd_fget(fd);
+	if (IS_ERR(new->map[new->num].event)) {
+		kfree(new);
+		return PTR_ERR(new->map[new->num].event);
+	}
+	new->num++;
+
+	/* Now put new one in place. */
+	rcu_assign_pointer(lg->eventfds, new);
+
+	/* We're not in a big hurry.  Wait until noone's looking at old
+	 * version, then delete it. */
+	synchronize_rcu();
+	kfree(old);
+
+	return 0;
+}
+
+static int attach_eventfd(struct lguest *lg, const unsigned long __user *input)
+{
+	unsigned long addr, fd;
+	int err;
+
+	if (get_user(addr, input) != 0)
+		return -EFAULT;
+	input++;
+	if (get_user(fd, input) != 0)
 		return -EFAULT;
 
-	if (on) {
-		cpu->break_out = 1;
-		/* Pop it out of the Guest (may be running on different CPU) */
-		wake_up_process(cpu->tsk);
-		/* Wait for them to reset it */
-		return wait_event_interruptible(cpu->break_wq, !cpu->break_out);
-	} else {
-		cpu->break_out = 0;
-		wake_up(&cpu->break_wq);
-		return 0;
-	}
+	mutex_lock(&lguest_lock);
+	err = add_eventfd(lg, addr, fd);
+	mutex_unlock(&lguest_lock);
+
+	return 0;
 }
 
 /*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt
@@ -45,9 +96,8 @@
 		return -EFAULT;
 	if (irq >= LGUEST_IRQS)
 		return -EINVAL;
-	/* Next time the Guest runs, the core code will see if it can deliver
-	 * this interrupt. */
-	set_bit(irq, cpu->irqs_pending);
+
+	set_interrupt(cpu, irq);
 	return 0;
 }
 
@@ -126,9 +176,6 @@
 	 * address. */
 	lguest_arch_setup_regs(cpu, start_ip);
 
-	/* Initialize the queue for the Waker to wait on */
-	init_waitqueue_head(&cpu->break_wq);
-
 	/* We keep a pointer to the Launcher task (ie. current task) for when
 	 * other Guests want to wake this one (eg. console input). */
 	cpu->tsk = current;
@@ -185,6 +232,13 @@
 		goto unlock;
 	}
 
+	lg->eventfds = kmalloc(sizeof(*lg->eventfds), GFP_KERNEL);
+	if (!lg->eventfds) {
+		err = -ENOMEM;
+		goto free_lg;
+	}
+	lg->eventfds->num = 0;
+
 	/* Populate the easy fields of our "struct lguest" */
 	lg->mem_base = (void __user *)args[0];
 	lg->pfn_limit = args[1];
@@ -192,7 +246,7 @@
 	/* This is the first cpu (cpu 0) and it will start booting at args[2] */
 	err = lg_cpu_start(&lg->cpus[0], 0, args[2]);
 	if (err)
-		goto release_guest;
+		goto free_eventfds;
 
 	/* Initialize the Guest's shadow page tables, using the toplevel
 	 * address the Launcher gave us.  This allocates memory, so can fail. */
@@ -211,7 +265,9 @@
 free_regs:
 	/* FIXME: This should be in free_vcpu */
 	free_page(lg->cpus[0].regs_page);
-release_guest:
+free_eventfds:
+	kfree(lg->eventfds);
+free_lg:
 	kfree(lg);
 unlock:
 	mutex_unlock(&lguest_lock);
@@ -252,11 +308,6 @@
 		/* Once the Guest is dead, you can only read() why it died. */
 		if (lg->dead)
 			return -ENOENT;
-
-		/* If you're not the task which owns the Guest, all you can do
-		 * is break the Launcher out of running the Guest. */
-		if (current != cpu->tsk && req != LHREQ_BREAK)
-			return -EPERM;
 	}
 
 	switch (req) {
@@ -264,8 +315,8 @@
 		return initialize(file, input);
 	case LHREQ_IRQ:
 		return user_send_irq(cpu, input);
-	case LHREQ_BREAK:
-		return break_guest_out(cpu, input);
+	case LHREQ_EVENTFD:
+		return attach_eventfd(lg, input);
 	default:
 		return -EINVAL;
 	}
@@ -303,6 +354,12 @@
 		 * the Launcher's memory management structure. */
 		mmput(lg->cpus[i].mm);
 	}
+
+	/* Release any eventfds they registered. */
+	for (i = 0; i < lg->eventfds->num; i++)
+		fput(lg->eventfds->map[i].event);
+	kfree(lg->eventfds);
+
 	/* If lg->dead doesn't contain an error code it will be NULL or a
 	 * kmalloc()ed string, either of which is ok to hand to kfree(). */
 	if (!IS_ERR(lg->dead))
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
index a059cf9..a6fe1ab 100644
--- a/drivers/lguest/page_tables.c
+++ b/drivers/lguest/page_tables.c
@@ -53,6 +53,17 @@
  * page.  */
 #define SWITCHER_PGD_INDEX (PTRS_PER_PGD - 1)
 
+/* For PAE we need the PMD index as well. We use the last 2MB, so we
+ * will need the last pmd entry of the last pmd page.  */
+#ifdef CONFIG_X86_PAE
+#define SWITCHER_PMD_INDEX 	(PTRS_PER_PMD - 1)
+#define RESERVE_MEM 		2U
+#define CHECK_GPGD_MASK		_PAGE_PRESENT
+#else
+#define RESERVE_MEM 		4U
+#define CHECK_GPGD_MASK		_PAGE_TABLE
+#endif
+
 /* We actually need a separate PTE page for each CPU.  Remember that after the
  * Switcher code itself comes two pages for each CPU, and we don't want this
  * CPU's guest to see the pages of any other CPU. */
@@ -73,24 +84,59 @@
 {
 	unsigned int index = pgd_index(vaddr);
 
+#ifndef CONFIG_X86_PAE
 	/* We kill any Guest trying to touch the Switcher addresses. */
 	if (index >= SWITCHER_PGD_INDEX) {
 		kill_guest(cpu, "attempt to access switcher pages");
 		index = 0;
 	}
+#endif
 	/* Return a pointer index'th pgd entry for the i'th page table. */
 	return &cpu->lg->pgdirs[i].pgdir[index];
 }
 
+#ifdef CONFIG_X86_PAE
+/* This routine then takes the PGD entry given above, which contains the
+ * address of the PMD page.  It then returns a pointer to the PMD entry for the
+ * given address. */
+static pmd_t *spmd_addr(struct lg_cpu *cpu, pgd_t spgd, unsigned long vaddr)
+{
+	unsigned int index = pmd_index(vaddr);
+	pmd_t *page;
+
+	/* We kill any Guest trying to touch the Switcher addresses. */
+	if (pgd_index(vaddr) == SWITCHER_PGD_INDEX &&
+					index >= SWITCHER_PMD_INDEX) {
+		kill_guest(cpu, "attempt to access switcher pages");
+		index = 0;
+	}
+
+	/* You should never call this if the PGD entry wasn't valid */
+	BUG_ON(!(pgd_flags(spgd) & _PAGE_PRESENT));
+	page = __va(pgd_pfn(spgd) << PAGE_SHIFT);
+
+	return &page[index];
+}
+#endif
+
 /* This routine then takes the page directory entry returned above, which
  * contains the address of the page table entry (PTE) page.  It then returns a
  * pointer to the PTE entry for the given address. */
-static pte_t *spte_addr(pgd_t spgd, unsigned long vaddr)
+static pte_t *spte_addr(struct lg_cpu *cpu, pgd_t spgd, unsigned long vaddr)
 {
+#ifdef CONFIG_X86_PAE
+	pmd_t *pmd = spmd_addr(cpu, spgd, vaddr);
+	pte_t *page = __va(pmd_pfn(*pmd) << PAGE_SHIFT);
+
+	/* You should never call this if the PMD entry wasn't valid */
+	BUG_ON(!(pmd_flags(*pmd) & _PAGE_PRESENT));
+#else
 	pte_t *page = __va(pgd_pfn(spgd) << PAGE_SHIFT);
 	/* You should never call this if the PGD entry wasn't valid */
 	BUG_ON(!(pgd_flags(spgd) & _PAGE_PRESENT));
-	return &page[(vaddr >> PAGE_SHIFT) % PTRS_PER_PTE];
+#endif
+
+	return &page[pte_index(vaddr)];
 }
 
 /* These two functions just like the above two, except they access the Guest
@@ -101,12 +147,32 @@
 	return cpu->lg->pgdirs[cpu->cpu_pgd].gpgdir + index * sizeof(pgd_t);
 }
 
-static unsigned long gpte_addr(pgd_t gpgd, unsigned long vaddr)
+#ifdef CONFIG_X86_PAE
+static unsigned long gpmd_addr(pgd_t gpgd, unsigned long vaddr)
 {
 	unsigned long gpage = pgd_pfn(gpgd) << PAGE_SHIFT;
 	BUG_ON(!(pgd_flags(gpgd) & _PAGE_PRESENT));
-	return gpage + ((vaddr>>PAGE_SHIFT) % PTRS_PER_PTE) * sizeof(pte_t);
+	return gpage + pmd_index(vaddr) * sizeof(pmd_t);
 }
+
+static unsigned long gpte_addr(struct lg_cpu *cpu,
+			       pmd_t gpmd, unsigned long vaddr)
+{
+	unsigned long gpage = pmd_pfn(gpmd) << PAGE_SHIFT;
+
+	BUG_ON(!(pmd_flags(gpmd) & _PAGE_PRESENT));
+	return gpage + pte_index(vaddr) * sizeof(pte_t);
+}
+#else
+static unsigned long gpte_addr(struct lg_cpu *cpu,
+				pgd_t gpgd, unsigned long vaddr)
+{
+	unsigned long gpage = pgd_pfn(gpgd) << PAGE_SHIFT;
+
+	BUG_ON(!(pgd_flags(gpgd) & _PAGE_PRESENT));
+	return gpage + pte_index(vaddr) * sizeof(pte_t);
+}
+#endif
 /*:*/
 
 /*M:014 get_pfn is slow: we could probably try to grab batches of pages here as
@@ -171,7 +237,7 @@
 	/* Remember that get_user_pages_fast() took a reference to the page, in
 	 * get_pfn()?  We have to put it back now. */
 	if (pte_flags(pte) & _PAGE_PRESENT)
-		put_page(pfn_to_page(pte_pfn(pte)));
+		put_page(pte_page(pte));
 }
 /*:*/
 
@@ -184,11 +250,20 @@
 
 static void check_gpgd(struct lg_cpu *cpu, pgd_t gpgd)
 {
-	if ((pgd_flags(gpgd) & ~_PAGE_TABLE) ||
+	if ((pgd_flags(gpgd) & ~CHECK_GPGD_MASK) ||
 	   (pgd_pfn(gpgd) >= cpu->lg->pfn_limit))
 		kill_guest(cpu, "bad page directory entry");
 }
 
+#ifdef CONFIG_X86_PAE
+static void check_gpmd(struct lg_cpu *cpu, pmd_t gpmd)
+{
+	if ((pmd_flags(gpmd) & ~_PAGE_TABLE) ||
+	   (pmd_pfn(gpmd) >= cpu->lg->pfn_limit))
+		kill_guest(cpu, "bad page middle directory entry");
+}
+#endif
+
 /*H:330
  * (i) Looking up a page table entry when the Guest faults.
  *
@@ -207,6 +282,11 @@
 	pte_t gpte;
 	pte_t *spte;
 
+#ifdef CONFIG_X86_PAE
+	pmd_t *spmd;
+	pmd_t gpmd;
+#endif
+
 	/* First step: get the top-level Guest page table entry. */
 	gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t);
 	/* Toplevel not present?  We can't map it in. */
@@ -228,12 +308,45 @@
 		check_gpgd(cpu, gpgd);
 		/* And we copy the flags to the shadow PGD entry.  The page
 		 * number in the shadow PGD is the page we just allocated. */
-		*spgd = __pgd(__pa(ptepage) | pgd_flags(gpgd));
+		set_pgd(spgd, __pgd(__pa(ptepage) | pgd_flags(gpgd)));
+	}
+
+#ifdef CONFIG_X86_PAE
+	gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t);
+	/* middle level not present?  We can't map it in. */
+	if (!(pmd_flags(gpmd) & _PAGE_PRESENT))
+		return false;
+
+	/* Now look at the matching shadow entry. */
+	spmd = spmd_addr(cpu, *spgd, vaddr);
+
+	if (!(pmd_flags(*spmd) & _PAGE_PRESENT)) {
+		/* No shadow entry: allocate a new shadow PTE page. */
+		unsigned long ptepage = get_zeroed_page(GFP_KERNEL);
+
+		/* This is not really the Guest's fault, but killing it is
+		* simple for this corner case. */
+		if (!ptepage) {
+			kill_guest(cpu, "out of memory allocating pte page");
+			return false;
+		}
+
+		/* We check that the Guest pmd is OK. */
+		check_gpmd(cpu, gpmd);
+
+		/* And we copy the flags to the shadow PMD entry.  The page
+		 * number in the shadow PMD is the page we just allocated. */
+		native_set_pmd(spmd, __pmd(__pa(ptepage) | pmd_flags(gpmd)));
 	}
 
 	/* OK, now we look at the lower level in the Guest page table: keep its
 	 * address, because we might update it later. */
-	gpte_ptr = gpte_addr(gpgd, vaddr);
+	gpte_ptr = gpte_addr(cpu, gpmd, vaddr);
+#else
+	/* OK, now we look at the lower level in the Guest page table: keep its
+	 * address, because we might update it later. */
+	gpte_ptr = gpte_addr(cpu, gpgd, vaddr);
+#endif
 	gpte = lgread(cpu, gpte_ptr, pte_t);
 
 	/* If this page isn't in the Guest page tables, we can't page it in. */
@@ -259,7 +372,7 @@
 		gpte = pte_mkdirty(gpte);
 
 	/* Get the pointer to the shadow PTE entry we're going to set. */
-	spte = spte_addr(*spgd, vaddr);
+	spte = spte_addr(cpu, *spgd, vaddr);
 	/* If there was a valid shadow PTE entry here before, we release it.
 	 * This can happen with a write to a previously read-only entry. */
 	release_pte(*spte);
@@ -273,7 +386,7 @@
 		 * table entry, even if the Guest says it's writable.  That way
 		 * we will come back here when a write does actually occur, so
 		 * we can update the Guest's _PAGE_DIRTY flag. */
-		*spte = gpte_to_spte(cpu, pte_wrprotect(gpte), 0);
+		native_set_pte(spte, gpte_to_spte(cpu, pte_wrprotect(gpte), 0));
 
 	/* Finally, we write the Guest PTE entry back: we've set the
 	 * _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags. */
@@ -301,14 +414,23 @@
 	pgd_t *spgd;
 	unsigned long flags;
 
+#ifdef CONFIG_X86_PAE
+	pmd_t *spmd;
+#endif
 	/* Look at the current top level entry: is it present? */
 	spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr);
 	if (!(pgd_flags(*spgd) & _PAGE_PRESENT))
 		return false;
 
+#ifdef CONFIG_X86_PAE
+	spmd = spmd_addr(cpu, *spgd, vaddr);
+	if (!(pmd_flags(*spmd) & _PAGE_PRESENT))
+		return false;
+#endif
+
 	/* Check the flags on the pte entry itself: it must be present and
 	 * writable. */
-	flags = pte_flags(*(spte_addr(*spgd, vaddr)));
+	flags = pte_flags(*(spte_addr(cpu, *spgd, vaddr)));
 
 	return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW);
 }
@@ -322,8 +444,43 @@
 		kill_guest(cpu, "bad stack page %#lx", vaddr);
 }
 
+#ifdef CONFIG_X86_PAE
+static void release_pmd(pmd_t *spmd)
+{
+	/* If the entry's not present, there's nothing to release. */
+	if (pmd_flags(*spmd) & _PAGE_PRESENT) {
+		unsigned int i;
+		pte_t *ptepage = __va(pmd_pfn(*spmd) << PAGE_SHIFT);
+		/* For each entry in the page, we might need to release it. */
+		for (i = 0; i < PTRS_PER_PTE; i++)
+			release_pte(ptepage[i]);
+		/* Now we can free the page of PTEs */
+		free_page((long)ptepage);
+		/* And zero out the PMD entry so we never release it twice. */
+		native_set_pmd(spmd, __pmd(0));
+	}
+}
+
+static void release_pgd(pgd_t *spgd)
+{
+	/* If the entry's not present, there's nothing to release. */
+	if (pgd_flags(*spgd) & _PAGE_PRESENT) {
+		unsigned int i;
+		pmd_t *pmdpage = __va(pgd_pfn(*spgd) << PAGE_SHIFT);
+
+		for (i = 0; i < PTRS_PER_PMD; i++)
+			release_pmd(&pmdpage[i]);
+
+		/* Now we can free the page of PMDs */
+		free_page((long)pmdpage);
+		/* And zero out the PGD entry so we never release it twice. */
+		set_pgd(spgd, __pgd(0));
+	}
+}
+
+#else /* !CONFIG_X86_PAE */
 /*H:450 If we chase down the release_pgd() code, it looks like this: */
-static void release_pgd(struct lguest *lg, pgd_t *spgd)
+static void release_pgd(pgd_t *spgd)
 {
 	/* If the entry's not present, there's nothing to release. */
 	if (pgd_flags(*spgd) & _PAGE_PRESENT) {
@@ -341,7 +498,7 @@
 		*spgd = __pgd(0);
 	}
 }
-
+#endif
 /*H:445 We saw flush_user_mappings() twice: once from the flush_user_mappings()
  * hypercall and once in new_pgdir() when we re-used a top-level pgdir page.
  * It simply releases every PTE page from 0 up to the Guest's kernel address. */
@@ -350,7 +507,7 @@
 	unsigned int i;
 	/* Release every pgd entry up to the kernel's address. */
 	for (i = 0; i < pgd_index(lg->kernel_address); i++)
-		release_pgd(lg, lg->pgdirs[idx].pgdir + i);
+		release_pgd(lg->pgdirs[idx].pgdir + i);
 }
 
 /*H:440 (v) Flushing (throwing away) page tables,
@@ -369,7 +526,9 @@
 {
 	pgd_t gpgd;
 	pte_t gpte;
-
+#ifdef CONFIG_X86_PAE
+	pmd_t gpmd;
+#endif
 	/* First step: get the top-level Guest page table entry. */
 	gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t);
 	/* Toplevel not present?  We can't map it in. */
@@ -378,7 +537,14 @@
 		return -1UL;
 	}
 
-	gpte = lgread(cpu, gpte_addr(gpgd, vaddr), pte_t);
+#ifdef CONFIG_X86_PAE
+	gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t);
+	if (!(pmd_flags(gpmd) & _PAGE_PRESENT))
+		kill_guest(cpu, "Bad address %#lx", vaddr);
+	gpte = lgread(cpu, gpte_addr(cpu, gpmd, vaddr), pte_t);
+#else
+	gpte = lgread(cpu, gpte_addr(cpu, gpgd, vaddr), pte_t);
+#endif
 	if (!(pte_flags(gpte) & _PAGE_PRESENT))
 		kill_guest(cpu, "Bad address %#lx", vaddr);
 
@@ -405,6 +571,9 @@
 			      int *blank_pgdir)
 {
 	unsigned int next;
+#ifdef CONFIG_X86_PAE
+	pmd_t *pmd_table;
+#endif
 
 	/* We pick one entry at random to throw out.  Choosing the Least
 	 * Recently Used might be better, but this is easy. */
@@ -416,10 +585,27 @@
 		/* If the allocation fails, just keep using the one we have */
 		if (!cpu->lg->pgdirs[next].pgdir)
 			next = cpu->cpu_pgd;
-		else
-			/* This is a blank page, so there are no kernel
-			 * mappings: caller must map the stack! */
+		else {
+#ifdef CONFIG_X86_PAE
+			/* In PAE mode, allocate a pmd page and populate the
+			 * last pgd entry. */
+			pmd_table = (pmd_t *)get_zeroed_page(GFP_KERNEL);
+			if (!pmd_table) {
+				free_page((long)cpu->lg->pgdirs[next].pgdir);
+				set_pgd(cpu->lg->pgdirs[next].pgdir, __pgd(0));
+				next = cpu->cpu_pgd;
+			} else {
+				set_pgd(cpu->lg->pgdirs[next].pgdir +
+					SWITCHER_PGD_INDEX,
+					__pgd(__pa(pmd_table) | _PAGE_PRESENT));
+				/* This is a blank page, so there are no kernel
+				 * mappings: caller must map the stack! */
+				*blank_pgdir = 1;
+			}
+#else
 			*blank_pgdir = 1;
+#endif
+		}
 	}
 	/* Record which Guest toplevel this shadows. */
 	cpu->lg->pgdirs[next].gpgdir = gpgdir;
@@ -431,7 +617,7 @@
 
 /*H:430 (iv) Switching page tables
  *
- * Now we've seen all the page table setting and manipulation, let's see what
+ * Now we've seen all the page table setting and manipulation, let's see
  * what happens when the Guest changes page tables (ie. changes the top-level
  * pgdir).  This occurs on almost every context switch. */
 void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable)
@@ -460,10 +646,25 @@
 
 	/* Every shadow pagetable this Guest has */
 	for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
-		if (lg->pgdirs[i].pgdir)
+		if (lg->pgdirs[i].pgdir) {
+#ifdef CONFIG_X86_PAE
+			pgd_t *spgd;
+			pmd_t *pmdpage;
+			unsigned int k;
+
+			/* Get the last pmd page. */
+			spgd = lg->pgdirs[i].pgdir + SWITCHER_PGD_INDEX;
+			pmdpage = __va(pgd_pfn(*spgd) << PAGE_SHIFT);
+
+			/* And release the pmd entries of that pmd page,
+			 * except for the switcher pmd. */
+			for (k = 0; k < SWITCHER_PMD_INDEX; k++)
+				release_pmd(&pmdpage[k]);
+#endif
 			/* Every PGD entry except the Switcher at the top */
 			for (j = 0; j < SWITCHER_PGD_INDEX; j++)
-				release_pgd(lg, lg->pgdirs[i].pgdir + j);
+				release_pgd(lg->pgdirs[i].pgdir + j);
+		}
 }
 
 /* We also throw away everything when a Guest tells us it's changed a kernel
@@ -504,24 +705,37 @@
 {
 	/* Look up the matching shadow page directory entry. */
 	pgd_t *spgd = spgd_addr(cpu, idx, vaddr);
+#ifdef CONFIG_X86_PAE
+	pmd_t *spmd;
+#endif
 
 	/* If the top level isn't present, there's no entry to update. */
 	if (pgd_flags(*spgd) & _PAGE_PRESENT) {
-		/* Otherwise, we start by releasing the existing entry. */
-		pte_t *spte = spte_addr(*spgd, vaddr);
-		release_pte(*spte);
+#ifdef CONFIG_X86_PAE
+		spmd = spmd_addr(cpu, *spgd, vaddr);
+		if (pmd_flags(*spmd) & _PAGE_PRESENT) {
+#endif
+			/* Otherwise, we start by releasing
+			 * the existing entry. */
+			pte_t *spte = spte_addr(cpu, *spgd, vaddr);
+			release_pte(*spte);
 
-		/* If they're setting this entry as dirty or accessed, we might
-		 * as well put that entry they've given us in now.  This shaves
-		 * 10% off a copy-on-write micro-benchmark. */
-		if (pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
-			check_gpte(cpu, gpte);
-			*spte = gpte_to_spte(cpu, gpte,
-					     pte_flags(gpte) & _PAGE_DIRTY);
-		} else
-			/* Otherwise kill it and we can demand_page() it in
-			 * later. */
-			*spte = __pte(0);
+			/* If they're setting this entry as dirty or accessed,
+			 * we might as well put that entry they've given us
+			 * in now.  This shaves 10% off a
+			 * copy-on-write micro-benchmark. */
+			if (pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
+				check_gpte(cpu, gpte);
+				native_set_pte(spte,
+						gpte_to_spte(cpu, gpte,
+						pte_flags(gpte) & _PAGE_DIRTY));
+			} else
+				/* Otherwise kill it and we can demand_page()
+				 * it in later. */
+				native_set_pte(spte, __pte(0));
+#ifdef CONFIG_X86_PAE
+		}
+#endif
 	}
 }
 
@@ -568,12 +782,10 @@
  *
  * So with that in mind here's our code to to update a (top-level) PGD entry:
  */
-void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 idx)
+void guest_set_pgd(struct lguest *lg, unsigned long gpgdir, u32 idx)
 {
 	int pgdir;
 
-	/* The kernel seems to try to initialize this early on: we ignore its
-	 * attempts to map over the Switcher. */
 	if (idx >= SWITCHER_PGD_INDEX)
 		return;
 
@@ -581,8 +793,14 @@
 	pgdir = find_pgdir(lg, gpgdir);
 	if (pgdir < ARRAY_SIZE(lg->pgdirs))
 		/* ... throw it away. */
-		release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx);
+		release_pgd(lg->pgdirs[pgdir].pgdir + idx);
 }
+#ifdef CONFIG_X86_PAE
+void guest_set_pmd(struct lguest *lg, unsigned long pmdp, u32 idx)
+{
+	guest_pagetable_clear_all(&lg->cpus[0]);
+}
+#endif
 
 /* Once we know how much memory we have we can construct simple identity
  * (which set virtual == physical) and linear mappings
@@ -596,8 +814,16 @@
 {
 	pgd_t __user *pgdir;
 	pte_t __user *linear;
-	unsigned int mapped_pages, i, linear_pages, phys_linear;
 	unsigned long mem_base = (unsigned long)lg->mem_base;
+	unsigned int mapped_pages, i, linear_pages;
+#ifdef CONFIG_X86_PAE
+	pmd_t __user *pmds;
+	unsigned int j;
+	pgd_t pgd;
+	pmd_t pmd;
+#else
+	unsigned int phys_linear;
+#endif
 
 	/* We have mapped_pages frames to map, so we need
 	 * linear_pages page tables to map them. */
@@ -610,6 +836,9 @@
 	/* Now we use the next linear_pages pages as pte pages */
 	linear = (void *)pgdir - linear_pages * PAGE_SIZE;
 
+#ifdef CONFIG_X86_PAE
+	pmds = (void *)linear - PAGE_SIZE;
+#endif
 	/* Linear mapping is easy: put every page's address into the
 	 * mapping in order. */
 	for (i = 0; i < mapped_pages; i++) {
@@ -621,6 +850,22 @@
 
 	/* The top level points to the linear page table pages above.
 	 * We setup the identity and linear mappings here. */
+#ifdef CONFIG_X86_PAE
+	for (i = j = 0; i < mapped_pages && j < PTRS_PER_PMD;
+	     i += PTRS_PER_PTE, j++) {
+		native_set_pmd(&pmd, __pmd(((unsigned long)(linear + i)
+		- mem_base) | _PAGE_PRESENT | _PAGE_RW | _PAGE_USER));
+
+		if (copy_to_user(&pmds[j], &pmd, sizeof(pmd)) != 0)
+			return -EFAULT;
+	}
+
+	set_pgd(&pgd, __pgd(((u32)pmds - mem_base) | _PAGE_PRESENT));
+	if (copy_to_user(&pgdir[0], &pgd, sizeof(pgd)) != 0)
+		return -EFAULT;
+	if (copy_to_user(&pgdir[3], &pgd, sizeof(pgd)) != 0)
+		return -EFAULT;
+#else
 	phys_linear = (unsigned long)linear - mem_base;
 	for (i = 0; i < mapped_pages; i += PTRS_PER_PTE) {
 		pgd_t pgd;
@@ -633,6 +878,7 @@
 				    &pgd, sizeof(pgd)))
 			return -EFAULT;
 	}
+#endif
 
 	/* We return the top level (guest-physical) address: remember where
 	 * this is. */
@@ -648,7 +894,10 @@
 	u64 mem;
 	u32 initrd_size;
 	struct boot_params __user *boot = (struct boot_params *)lg->mem_base;
-
+#ifdef CONFIG_X86_PAE
+	pgd_t *pgd;
+	pmd_t *pmd_table;
+#endif
 	/* Get the Guest memory size and the ramdisk size from the boot header
 	 * located at lg->mem_base (Guest address 0). */
 	if (copy_from_user(&mem, &boot->e820_map[0].size, sizeof(mem))
@@ -663,6 +912,15 @@
 	lg->pgdirs[0].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL);
 	if (!lg->pgdirs[0].pgdir)
 		return -ENOMEM;
+#ifdef CONFIG_X86_PAE
+	pgd = lg->pgdirs[0].pgdir;
+	pmd_table = (pmd_t *) get_zeroed_page(GFP_KERNEL);
+	if (!pmd_table)
+		return -ENOMEM;
+
+	set_pgd(pgd + SWITCHER_PGD_INDEX,
+		__pgd(__pa(pmd_table) | _PAGE_PRESENT));
+#endif
 	lg->cpus[0].cpu_pgd = 0;
 	return 0;
 }
@@ -672,17 +930,24 @@
 {
 	/* We get the kernel address: above this is all kernel memory. */
 	if (get_user(cpu->lg->kernel_address,
-		     &cpu->lg->lguest_data->kernel_address)
-	    /* We tell the Guest that it can't use the top 4MB of virtual
-	     * addresses used by the Switcher. */
-	    || put_user(4U*1024*1024, &cpu->lg->lguest_data->reserve_mem)
-	    || put_user(cpu->lg->pgdirs[0].gpgdir, &cpu->lg->lguest_data->pgdir))
+		&cpu->lg->lguest_data->kernel_address)
+		/* We tell the Guest that it can't use the top 2 or 4 MB
+		 * of virtual addresses used by the Switcher. */
+		|| put_user(RESERVE_MEM * 1024 * 1024,
+			&cpu->lg->lguest_data->reserve_mem)
+		|| put_user(cpu->lg->pgdirs[0].gpgdir,
+			&cpu->lg->lguest_data->pgdir))
 		kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data);
 
 	/* In flush_user_mappings() we loop from 0 to
 	 * "pgd_index(lg->kernel_address)".  This assumes it won't hit the
 	 * Switcher mappings, so check that now. */
+#ifdef CONFIG_X86_PAE
+	if (pgd_index(cpu->lg->kernel_address) == SWITCHER_PGD_INDEX &&
+		pmd_index(cpu->lg->kernel_address) == SWITCHER_PMD_INDEX)
+#else
 	if (pgd_index(cpu->lg->kernel_address) >= SWITCHER_PGD_INDEX)
+#endif
 		kill_guest(cpu, "bad kernel address %#lx",
 				 cpu->lg->kernel_address);
 }
@@ -708,16 +973,30 @@
 void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages)
 {
 	pte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages);
-	pgd_t switcher_pgd;
 	pte_t regs_pte;
 	unsigned long pfn;
 
+#ifdef CONFIG_X86_PAE
+	pmd_t switcher_pmd;
+	pmd_t *pmd_table;
+
+	native_set_pmd(&switcher_pmd, pfn_pmd(__pa(switcher_pte_page) >>
+		       PAGE_SHIFT, PAGE_KERNEL_EXEC));
+
+	pmd_table = __va(pgd_pfn(cpu->lg->
+			pgdirs[cpu->cpu_pgd].pgdir[SWITCHER_PGD_INDEX])
+								<< PAGE_SHIFT);
+	native_set_pmd(&pmd_table[SWITCHER_PMD_INDEX], switcher_pmd);
+#else
+	pgd_t switcher_pgd;
+
 	/* Make the last PGD entry for this Guest point to the Switcher's PTE
 	 * page for this CPU (with appropriate flags). */
-	switcher_pgd = __pgd(__pa(switcher_pte_page) | __PAGE_KERNEL);
+	switcher_pgd = __pgd(__pa(switcher_pte_page) | __PAGE_KERNEL_EXEC);
 
 	cpu->lg->pgdirs[cpu->cpu_pgd].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd;
 
+#endif
 	/* We also change the Switcher PTE page.  When we're running the Guest,
 	 * we want the Guest's "regs" page to appear where the first Switcher
 	 * page for this CPU is.  This is an optimization: when the Switcher
@@ -726,8 +1005,9 @@
 	 * page is already mapped there, we don't have to copy them out
 	 * again. */
 	pfn = __pa(cpu->regs_page) >> PAGE_SHIFT;
-	regs_pte = pfn_pte(pfn, __pgprot(__PAGE_KERNEL));
-	switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTRS_PER_PTE] = regs_pte;
+	native_set_pte(&regs_pte, pfn_pte(pfn, PAGE_KERNEL));
+	native_set_pte(&switcher_pte_page[pte_index((unsigned long)pages)],
+			regs_pte);
 }
 /*:*/
 
@@ -752,21 +1032,21 @@
 
 	/* The first entries are easy: they map the Switcher code. */
 	for (i = 0; i < pages; i++) {
-		pte[i] = mk_pte(switcher_page[i],
-				__pgprot(_PAGE_PRESENT|_PAGE_ACCESSED));
+		native_set_pte(&pte[i], mk_pte(switcher_page[i],
+				__pgprot(_PAGE_PRESENT|_PAGE_ACCESSED)));
 	}
 
 	/* The only other thing we map is this CPU's pair of pages. */
 	i = pages + cpu*2;
 
 	/* First page (Guest registers) is writable from the Guest */
-	pte[i] = pfn_pte(page_to_pfn(switcher_page[i]),
-			 __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW));
+	native_set_pte(&pte[i], pfn_pte(page_to_pfn(switcher_page[i]),
+			 __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW)));
 
 	/* The second page contains the "struct lguest_ro_state", and is
 	 * read-only. */
-	pte[i+1] = pfn_pte(page_to_pfn(switcher_page[i+1]),
-			   __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED));
+	native_set_pte(&pte[i+1], pfn_pte(page_to_pfn(switcher_page[i+1]),
+			   __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED)));
 }
 
 /* We've made it through the page table code.  Perhaps our tired brains are
diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c
index 7ede64f..482ed5a 100644
--- a/drivers/lguest/segments.c
+++ b/drivers/lguest/segments.c
@@ -150,7 +150,7 @@
 {
 	/* We assume the Guest has the same number of GDT entries as the
 	 * Host, otherwise we'd have to dynamically allocate the Guest GDT. */
-	if (num > ARRAY_SIZE(cpu->arch.gdt))
+	if (num >= ARRAY_SIZE(cpu->arch.gdt))
 		kill_guest(cpu, "too many gdt entries %i", num);
 
 	/* Set it up, then fix it. */
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 9d48da2..57835f5 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -758,10 +758,14 @@
 	---help---
 	  This is a v4l2 driver for the i.MX1/i.MXL CMOS Sensor Interface
 
+config MX3_VIDEO
+	bool
+
 config VIDEO_MX3
 	tristate "i.MX3x Camera Sensor Interface driver"
 	depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
 	select VIDEOBUF_DMA_CONTIG
+	select MX3_VIDEO
 	---help---
 	  This is a v4l2 driver for the i.MX3x Camera Sensor Interface
 
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 5d496a9..44b9315 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -146,7 +146,6 @@
 static MPT_RESETHANDLER		 MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
 static struct mpt_pci_driver 	*MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
 
-static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
 
 /*
  *  Driver Callback Index's
@@ -159,7 +158,8 @@
  *  Forward protos...
  */
 static irqreturn_t mpt_interrupt(int irq, void *bus_id);
-static int	mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
+static int	mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
+		MPT_FRAME_HDR *reply);
 static int	mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
 			u32 *req, int replyBytes, u16 *u16reply, int maxwait,
 			int sleepFlag);
@@ -190,9 +190,9 @@
 static int	mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
 static void 	mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
 static void 	mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
-static void	mpt_timer_expired(unsigned long data);
 static void	mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
-static int	SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
+static int	SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
+	int sleepFlag);
 static int	SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
 static int	mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
 static int	mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
@@ -207,8 +207,8 @@
 #endif
 static void	mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
 
-//int		mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
-static int	ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
+static int	ProcessEventNotification(MPT_ADAPTER *ioc,
+		EventNotificationReply_t *evReply, int *evHandlers);
 static void	mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
 static void	mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
 static void	mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
@@ -277,6 +277,56 @@
 }
 
 /**
+ * mpt_is_discovery_complete - determine if discovery has completed
+ * @ioc: per adatper instance
+ *
+ * Returns 1 when discovery completed, else zero.
+ */
+static int
+mpt_is_discovery_complete(MPT_ADAPTER *ioc)
+{
+	ConfigExtendedPageHeader_t hdr;
+	CONFIGPARMS cfg;
+	SasIOUnitPage0_t *buffer;
+	dma_addr_t dma_handle;
+	int rc = 0;
+
+	memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
+	memset(&cfg, 0, sizeof(CONFIGPARMS));
+	hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
+	hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+	hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+	cfg.cfghdr.ehdr = &hdr;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+	if ((mpt_config(ioc, &cfg)))
+		goto out;
+	if (!hdr.ExtPageLength)
+		goto out;
+
+	buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+	    &dma_handle);
+	if (!buffer)
+		goto out;
+
+	cfg.physAddr = dma_handle;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+	if ((mpt_config(ioc, &cfg)))
+		goto out_free_consistent;
+
+	if (!(buffer->PhyData[0].PortFlags &
+	    MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
+		rc = 1;
+
+ out_free_consistent:
+	pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+	    buffer, dma_handle);
+ out:
+	return rc;
+}
+
+/**
  *	mpt_fault_reset_work - work performed on workq after ioc fault
  *	@work: input argument, used to derive ioc
  *
@@ -290,7 +340,7 @@
 	int		 rc;
 	unsigned long	 flags;
 
-	if (ioc->diagPending || !ioc->active)
+	if (ioc->ioc_reset_in_progress || !ioc->active)
 		goto out;
 
 	ioc_raw_state = mpt_GetIocState(ioc, 0);
@@ -307,6 +357,12 @@
 			printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
 			    "reset (%04xh)\n", ioc->name, ioc_raw_state &
 			    MPI_DOORBELL_DATA_MASK);
+	} else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
+		if ((mpt_is_discovery_complete(ioc))) {
+			devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
+			    "discovery_quiesce_io flag\n", ioc->name));
+			ioc->sas_discovery_quiesce_io = 0;
+		}
 	}
 
  out:
@@ -317,11 +373,11 @@
 		ioc = ioc->alt_ioc;
 
 	/* rearm the timer */
-	spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
 	if (ioc->reset_work_q)
 		queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
 			msecs_to_jiffies(MPT_POLLING_INTERVAL));
-	spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 }
 
 
@@ -501,9 +557,9 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *	mpt_base_reply - MPT base driver's callback routine
+ *	mptbase_reply - MPT base driver's callback routine
  *	@ioc: Pointer to MPT_ADAPTER structure
- *	@mf: Pointer to original MPT request frame
+ *	@req: Pointer to original MPT request frame
  *	@reply: Pointer to MPT reply frame (NULL if TurboReply)
  *
  *	MPT base driver's callback routine; all base driver
@@ -514,122 +570,49 @@
  *	should be freed, or 0 if it shouldn't.
  */
 static int
-mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
+mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
 {
+	EventNotificationReply_t *pEventReply;
+	u8 event;
+	int evHandlers;
 	int freereq = 1;
-	u8 func;
 
-	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
-#ifdef CONFIG_FUSION_LOGGING
-	if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
-			!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
-		dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
-		    ioc->name, mf));
-		DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
-	}
-#endif
-
-	func = reply->u.hdr.Function;
-	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
-			ioc->name, func));
-
-	if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
-		EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
-		int evHandlers = 0;
-		int results;
-
-		results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
-		if (results != evHandlers) {
-			/* CHECKME! Any special handling needed here? */
-			devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
-					ioc->name, evHandlers, results));
-		}
-
-		/*
-		 *	Hmmm...  It seems that EventNotificationReply is an exception
-		 *	to the rule of one reply per request.
-		 */
-		if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
+	switch (reply->u.hdr.Function) {
+	case MPI_FUNCTION_EVENT_NOTIFICATION:
+		pEventReply = (EventNotificationReply_t *)reply;
+		evHandlers = 0;
+		ProcessEventNotification(ioc, pEventReply, &evHandlers);
+		event = le32_to_cpu(pEventReply->Event) & 0xFF;
+		if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
 			freereq = 0;
-		} else {
-			devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
-				ioc->name, pEvReply));
+		if (event != MPI_EVENT_EVENT_CHANGE)
+			break;
+	case MPI_FUNCTION_CONFIG:
+	case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
+		ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+		if (reply) {
+			ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+			memcpy(ioc->mptbase_cmds.reply, reply,
+			    min(MPT_DEFAULT_FRAME_SIZE,
+				4 * reply->u.reply.MsgLength));
 		}
-
-#ifdef CONFIG_PROC_FS
-//		LogEvent(ioc, pEvReply);
-#endif
-
-	} else if (func == MPI_FUNCTION_EVENT_ACK) {
-		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
-				ioc->name));
-	} else if (func == MPI_FUNCTION_CONFIG) {
-		CONFIGPARMS *pCfg;
-		unsigned long flags;
-
-		dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
-				ioc->name, mf, reply));
-
-		pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
-
-		if (pCfg) {
-			/* disable timer and remove from linked list */
-			del_timer(&pCfg->timer);
-
-			spin_lock_irqsave(&ioc->FreeQlock, flags);
-			list_del(&pCfg->linkage);
-			spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-			/*
-			 *	If IOC Status is SUCCESS, save the header
-			 *	and set the status code to GOOD.
-			 */
-			pCfg->status = MPT_CONFIG_ERROR;
-			if (reply) {
-				ConfigReply_t	*pReply = (ConfigReply_t *)reply;
-				u16		 status;
-
-				status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-				dcprintk(ioc, printk(MYIOC_s_NOTE_FMT "  IOCStatus=%04xh, IOCLogInfo=%08xh\n",
-				     ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
-
-				pCfg->status = status;
-				if (status == MPI_IOCSTATUS_SUCCESS) {
-					if ((pReply->Header.PageType &
-					    MPI_CONFIG_PAGETYPE_MASK) ==
-					    MPI_CONFIG_PAGETYPE_EXTENDED) {
-						pCfg->cfghdr.ehdr->ExtPageLength =
-						    le16_to_cpu(pReply->ExtPageLength);
-						pCfg->cfghdr.ehdr->ExtPageType =
-						    pReply->ExtPageType;
-					}
-					pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
-
-					/* If this is a regular header, save PageLength. */
-					/* LMP Do this better so not using a reserved field! */
-					pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
-					pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
-					pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
-				}
-			}
-
-			/*
-			 *	Wake up the original calling thread
-			 */
-			pCfg->wait_done = 1;
-			wake_up(&mpt_waitq);
-		}
-	} else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
-		/* we should be always getting a reply frame */
-		memcpy(ioc->persist_reply_frame, reply,
-		    min(MPT_DEFAULT_FRAME_SIZE,
-		    4*reply->u.reply.MsgLength));
-		del_timer(&ioc->persist_timer);
-		ioc->persist_wait_done = 1;
-		wake_up(&mpt_waitq);
-	} else {
-		printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
-				ioc->name, func);
+		if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
+			ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+			complete(&ioc->mptbase_cmds.done);
+		} else
+			freereq = 0;
+		if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
+			freereq = 1;
+		break;
+	case MPI_FUNCTION_EVENT_ACK:
+		devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "EventAck reply received\n", ioc->name));
+		break;
+	default:
+		printk(MYIOC_s_ERR_FMT
+		    "Unexpected msg function (=%02Xh) reply received!\n",
+		    ioc->name, reply->u.hdr.Function);
+		break;
 	}
 
 	/*
@@ -988,17 +971,21 @@
 
 	/*  Put Request back on FreeQ!  */
 	spin_lock_irqsave(&ioc->FreeQlock, flags);
-	mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
+	if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
+		goto out;
+	/* signature to know if this mf is freed */
+	mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);
 	list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
 #ifdef MFCNT
 	ioc->mfcnt--;
 #endif
+ out:
 	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *	mpt_add_sge - Place a simple SGE at address pAddr.
+ *	mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
  *	@pAddr: virtual address for SGE
  *	@flagslength: SGE flags and data transfer length
  *	@dma_addr: Physical address
@@ -1006,23 +993,117 @@
  *	This routine places a MPT request frame back on the MPT adapter's
  *	FreeQ.
  */
-void
-mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
+static void
+mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
 {
-	if (sizeof(dma_addr_t) == sizeof(u64)) {
-		SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+	SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
+	pSge->FlagsLength = cpu_to_le32(flagslength);
+	pSge->Address = cpu_to_le32(dma_addr);
+}
+
+/**
+ *	mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
+ *	@pAddr: virtual address for SGE
+ *	@flagslength: SGE flags and data transfer length
+ *	@dma_addr: Physical address
+ *
+ *	This routine places a MPT request frame back on the MPT adapter's
+ *	FreeQ.
+ **/
+static void
+mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
+{
+	SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+	pSge->Address.Low = cpu_to_le32
+			(lower_32_bits((unsigned long)(dma_addr)));
+	pSge->Address.High = cpu_to_le32
+			(upper_32_bits((unsigned long)dma_addr));
+	pSge->FlagsLength = cpu_to_le32
+			((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
+}
+
+/**
+ *	mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr
+ *	(1078 workaround).
+ *	@pAddr: virtual address for SGE
+ *	@flagslength: SGE flags and data transfer length
+ *	@dma_addr: Physical address
+ *
+ *	This routine places a MPT request frame back on the MPT adapter's
+ *	FreeQ.
+ **/
+static void
+mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
+{
+	SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+	u32 tmp;
+
+	pSge->Address.Low = cpu_to_le32
+			(lower_32_bits((unsigned long)(dma_addr)));
+	tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
+
+	/*
+	 * 1078 errata workaround for the 36GB limitation
+	 */
+	if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32)  == 9) {
+		flagslength |=
+		    MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
+		tmp |= (1<<31);
+		if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
+			printk(KERN_DEBUG "1078 P0M2 addressing for "
+			    "addr = 0x%llx len = %d\n",
+			    (unsigned long long)dma_addr,
+			    MPI_SGE_LENGTH(flagslength));
+	}
+
+	pSge->Address.High = cpu_to_le32(tmp);
+	pSge->FlagsLength = cpu_to_le32(
+		(flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
+ *	@pAddr: virtual address for SGE
+ *	@next: nextChainOffset value (u32's)
+ *	@length: length of next SGL segment
+ *	@dma_addr: Physical address
+ *
+ */
+static void
+mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
+{
+		SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
+		pChain->Length = cpu_to_le16(length);
+		pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
+		pChain->NextChainOffset = next;
+		pChain->Address = cpu_to_le32(dma_addr);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
+ *	@pAddr: virtual address for SGE
+ *	@next: nextChainOffset value (u32's)
+ *	@length: length of next SGL segment
+ *	@dma_addr: Physical address
+ *
+ */
+static void
+mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
+{
+		SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
 		u32 tmp = dma_addr & 0xFFFFFFFF;
 
-		pSge->FlagsLength = cpu_to_le32(flagslength);
-		pSge->Address.Low = cpu_to_le32(tmp);
-		tmp = (u32) ((u64)dma_addr >> 32);
-		pSge->Address.High = cpu_to_le32(tmp);
+		pChain->Length = cpu_to_le16(length);
+		pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
+				 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
 
-	} else {
-		SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
-		pSge->FlagsLength = cpu_to_le32(flagslength);
-		pSge->Address = cpu_to_le32(dma_addr);
-	}
+		pChain->NextChainOffset = next;
+
+		pChain->Address.Low = cpu_to_le32(tmp);
+		tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
+		pChain->Address.High = cpu_to_le32(tmp);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1225,7 +1306,7 @@
 	}
 	flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
 	flags_length |= ioc->HostPageBuffer_sz;
-	mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
+	ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
 	ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
 
 return 0;
@@ -1534,21 +1615,42 @@
 
 	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
 
-	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
-	    && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
-		dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
-		    ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
-		    ioc->name));
-	} else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
-	    && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
-		dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
-		    ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
-		    ioc->name));
+	if (sizeof(dma_addr_t) > 4) {
+		const uint64_t required_mask = dma_get_required_mask
+		    (&pdev->dev);
+		if (required_mask > DMA_BIT_MASK(32)
+			&& !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
+			&& !pci_set_consistent_dma_mask(pdev,
+						 DMA_BIT_MASK(64))) {
+			ioc->dma_mask = DMA_BIT_MASK(64);
+			dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+				": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
+				ioc->name));
+		} else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
+			&& !pci_set_consistent_dma_mask(pdev,
+						DMA_BIT_MASK(32))) {
+			ioc->dma_mask = DMA_BIT_MASK(32);
+			dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+				": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
+				ioc->name));
+		} else {
+			printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
+			    ioc->name, pci_name(pdev));
+			return r;
+		}
 	} else {
-		printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
-		    ioc->name, pci_name(pdev));
-		pci_release_selected_regions(pdev, ioc->bars);
-		return r;
+		if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
+			&& !pci_set_consistent_dma_mask(pdev,
+						DMA_BIT_MASK(32))) {
+			ioc->dma_mask = DMA_BIT_MASK(32);
+			dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+				": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
+				ioc->name));
+		} else {
+			printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
+			    ioc->name, pci_name(pdev));
+			return r;
+		}
 	}
 
 	mem_phys = msize = 0;
@@ -1632,6 +1734,7 @@
 
 	ioc->id = mpt_ids++;
 	sprintf(ioc->name, "ioc%d", ioc->id);
+	dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
 
 	/*
 	 * set initial debug level
@@ -1650,14 +1753,36 @@
 		return r;
 	}
 
+	/*
+	 * Setting up proper handlers for scatter gather handling
+	 */
+	if (ioc->dma_mask == DMA_BIT_MASK(64)) {
+		if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
+			ioc->add_sge = &mpt_add_sge_64bit_1078;
+		else
+			ioc->add_sge = &mpt_add_sge_64bit;
+		ioc->add_chain = &mpt_add_chain_64bit;
+		ioc->sg_addr_size = 8;
+	} else {
+		ioc->add_sge = &mpt_add_sge;
+		ioc->add_chain = &mpt_add_chain;
+		ioc->sg_addr_size = 4;
+	}
+	ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
+
 	ioc->alloc_total = sizeof(MPT_ADAPTER);
 	ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;		/* avoid div by zero! */
 	ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
 
 	ioc->pcidev = pdev;
-	ioc->diagPending = 0;
-	spin_lock_init(&ioc->diagLock);
-	spin_lock_init(&ioc->initializing_hba_lock);
+
+	spin_lock_init(&ioc->taskmgmt_lock);
+	mutex_init(&ioc->internal_cmds.mutex);
+	init_completion(&ioc->internal_cmds.done);
+	mutex_init(&ioc->mptbase_cmds.mutex);
+	init_completion(&ioc->mptbase_cmds.done);
+	mutex_init(&ioc->taskmgmt_cmds.mutex);
+	init_completion(&ioc->taskmgmt_cmds.done);
 
 	/* Initialize the event logging.
 	 */
@@ -1670,16 +1795,13 @@
 	ioc->mfcnt = 0;
 #endif
 
+	ioc->sh = NULL;
 	ioc->cached_fw = NULL;
 
 	/* Initilize SCSI Config Data structure
 	 */
 	memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
 
-	/* Initialize the running configQ head.
-	 */
-	INIT_LIST_HEAD(&ioc->configQ);
-
 	/* Initialize the fc rport list head.
 	 */
 	INIT_LIST_HEAD(&ioc->fc_rports);
@@ -1690,9 +1812,8 @@
 
 	/* Initialize workqueue */
 	INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
-	spin_lock_init(&ioc->fault_reset_work_lock);
 
-	snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name),
+	snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
 		 "mpt_poll_%d", ioc->id);
 	ioc->reset_work_q =
 		create_singlethread_workqueue(ioc->reset_work_q_name);
@@ -1767,11 +1888,14 @@
 	case MPI_MANUFACTPAGE_DEVID_SAS1064:
 	case MPI_MANUFACTPAGE_DEVID_SAS1068:
 		ioc->errata_flag_1064 = 1;
+		ioc->bus_type = SAS;
+		break;
 
 	case MPI_MANUFACTPAGE_DEVID_SAS1064E:
 	case MPI_MANUFACTPAGE_DEVID_SAS1068E:
 	case MPI_MANUFACTPAGE_DEVID_SAS1078:
 		ioc->bus_type = SAS;
+		break;
 	}
 
 
@@ -1813,6 +1937,11 @@
 	 */
 	mpt_detect_bound_ports(ioc, pdev);
 
+	INIT_LIST_HEAD(&ioc->fw_event_list);
+	spin_lock_init(&ioc->fw_event_lock);
+	snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
+	ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
+
 	if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
 	    CAN_SLEEP)) != 0){
 		printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
@@ -1885,13 +2014,18 @@
 	/*
 	 * Stop polling ioc for fault condition
 	 */
-	spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
 	wq = ioc->reset_work_q;
 	ioc->reset_work_q = NULL;
-	spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 	cancel_delayed_work(&ioc->fault_reset_work);
 	destroy_workqueue(wq);
 
+	spin_lock_irqsave(&ioc->fw_event_lock, flags);
+	wq = ioc->fw_event_q;
+	ioc->fw_event_q = NULL;
+	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+	destroy_workqueue(wq);
 
 	sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
 	remove_proc_entry(pname, NULL);
@@ -1994,6 +2128,21 @@
 	if (err)
 		return err;
 
+	if (ioc->dma_mask == DMA_BIT_MASK(64)) {
+		if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
+			ioc->add_sge = &mpt_add_sge_64bit_1078;
+		else
+			ioc->add_sge = &mpt_add_sge_64bit;
+		ioc->add_chain = &mpt_add_chain_64bit;
+		ioc->sg_addr_size = 8;
+	} else {
+
+		ioc->add_sge = &mpt_add_sge;
+		ioc->add_chain = &mpt_add_chain;
+		ioc->sg_addr_size = 4;
+	}
+	ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
+
 	printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
 	    ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
 	    CHIPREG_READ32(&ioc->chip->Doorbell));
@@ -2091,12 +2240,16 @@
 	ioc->active = 0;
 
 	if (ioc->alt_ioc) {
-		if (ioc->alt_ioc->active)
+		if (ioc->alt_ioc->active ||
+		    reason == MPT_HOSTEVENT_IOC_RECOVER) {
 			reset_alt_ioc_active = 1;
-
-		/* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
-		CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
-		ioc->alt_ioc->active = 0;
+			/* Disable alt-IOC's reply interrupts
+			 *  (and FreeQ) for a bit
+			 **/
+			CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
+				0xFFFFFFFF);
+			ioc->alt_ioc->active = 0;
+		}
 	}
 
 	hard = 1;
@@ -2117,9 +2270,11 @@
 			}
 
 		} else {
-			printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
+			printk(MYIOC_s_WARN_FMT
+			    "NOT READY WARNING!\n", ioc->name);
 		}
-		return -1;
+		ret = -1;
+		goto out;
 	}
 
 	/* hard_reset_done = 0 if a soft reset was performed
@@ -2129,7 +2284,9 @@
 		if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
 			alt_ioc_ready = 1;
 		else
-			printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
+			printk(MYIOC_s_WARN_FMT
+			    ": alt-ioc Not ready WARNING!\n",
+			    ioc->alt_ioc->name);
 	}
 
 	for (ii=0; ii<5; ii++) {
@@ -2150,7 +2307,8 @@
 	if (alt_ioc_ready) {
 		if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
 			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-			    "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
+			    "Initial Alt IocFacts failed rc=%x\n",
+			    ioc->name, rc));
 			/* Retry - alt IOC was initialized once
 			 */
 			rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
@@ -2194,16 +2352,20 @@
 			    IRQF_SHARED, ioc->name, ioc);
 			if (rc < 0) {
 				printk(MYIOC_s_ERR_FMT "Unable to allocate "
-				    "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
+				    "interrupt %d!\n",
+				    ioc->name, ioc->pcidev->irq);
 				if (ioc->msi_enable)
 					pci_disable_msi(ioc->pcidev);
-				return -EBUSY;
+				ret = -EBUSY;
+				goto out;
 			}
 			irq_allocated = 1;
 			ioc->pci_irq = ioc->pcidev->irq;
 			pci_set_master(ioc->pcidev);		/* ?? */
-			dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
-			    "%d\n", ioc->name, ioc->pcidev->irq));
+			pci_set_drvdata(ioc->pcidev, ioc);
+			dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+			    "installed at interrupt %d\n", ioc->name,
+			    ioc->pcidev->irq));
 		}
 	}
 
@@ -2212,17 +2374,22 @@
 	 * init as upper addresses are needed for init.
 	 * If fails, continue with alt-ioc processing
 	 */
+	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
+	    ioc->name));
 	if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
 		ret = -3;
 
 	/* May need to check/upload firmware & data here!
 	 * If fails, continue with alt-ioc processing
 	 */
+	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
+	    ioc->name));
 	if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
 		ret = -4;
 // NEW!
 	if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
-		printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
+		printk(MYIOC_s_WARN_FMT
+		    ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
 		    ioc->alt_ioc->name, rc);
 		alt_ioc_ready = 0;
 		reset_alt_ioc_active = 0;
@@ -2232,8 +2399,9 @@
 		if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
 			alt_ioc_ready = 0;
 			reset_alt_ioc_active = 0;
-			printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
-			    ioc->alt_ioc->name, rc);
+			printk(MYIOC_s_WARN_FMT
+				": alt-ioc: (%d) init failure WARNING!\n",
+					ioc->alt_ioc->name, rc);
 		}
 	}
 
@@ -2269,28 +2437,36 @@
 		}
 	}
 
+	/*  Enable MPT base driver management of EventNotification
+	 *  and EventAck handling.
+	 */
+	if ((ret == 0) && (!ioc->facts.EventState)) {
+		dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+			"SendEventNotification\n",
+		    ioc->name));
+		ret = SendEventNotification(ioc, 1, sleepFlag);	/* 1=Enable */
+	}
+
+	if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
+		rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
+
 	if (ret == 0) {
 		/* Enable! (reply interrupt) */
 		CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
 		ioc->active = 1;
 	}
-
-	if (reset_alt_ioc_active && ioc->alt_ioc) {
-		/* (re)Enable alt-IOC! (reply interrupt) */
-		dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
-		    ioc->alt_ioc->name));
-		CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
-		ioc->alt_ioc->active = 1;
+	if (rc == 0) {	/* alt ioc */
+		if (reset_alt_ioc_active && ioc->alt_ioc) {
+			/* (re)Enable alt-IOC! (reply interrupt) */
+			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
+				"reply irq re-enabled\n",
+				ioc->alt_ioc->name));
+			CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
+				MPI_HIM_DIM);
+			ioc->alt_ioc->active = 1;
+		}
 	}
 
-	/*  Enable MPT base driver management of EventNotification
-	 *  and EventAck handling.
-	 */
-	if ((ret == 0) && (!ioc->facts.EventState))
-		(void) SendEventNotification(ioc, 1);	/* 1=Enable EventNotification */
-
-	if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
-		(void) SendEventNotification(ioc->alt_ioc, 1);	/* 1=Enable EventNotification */
 
 	/*	Add additional "reason" check before call to GetLanConfigPages
 	 *	(combined with GetIoUnitPage2 call).  This prevents a somewhat
@@ -2306,8 +2482,9 @@
 		mutex_init(&ioc->raid_data.inactive_list_mutex);
 		INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
 
-		if (ioc->bus_type == SAS) {
+		switch (ioc->bus_type) {
 
+		case SAS:
 			/* clear persistency table */
 			if(ioc->facts.IOCExceptions &
 			    MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
@@ -2321,8 +2498,15 @@
 			 */
 			mpt_findImVolumes(ioc);
 
-		} else if (ioc->bus_type == FC) {
-			if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
+			/* Check, and possibly reset, the coalescing value
+			 */
+			mpt_read_ioc_pg_1(ioc);
+
+			break;
+
+		case FC:
+			if ((ioc->pfacts[0].ProtocolFlags &
+				MPI_PORTFACTS_PROTOCOL_LAN) &&
 			    (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
 				/*
 				 *  Pre-fetch the ports LAN MAC address!
@@ -2331,11 +2515,14 @@
 				(void) GetLanConfigPages(ioc);
 				a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
 				dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-				    "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
-				    ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
-
+					"LanAddr = %02X:%02X:%02X"
+					":%02X:%02X:%02X\n",
+					ioc->name, a[5], a[4],
+					a[3], a[2], a[1], a[0]));
 			}
-		} else {
+			break;
+
+		case SPI:
 			/* Get NVRAM and adapter maximums from SPP 0 and 2
 			 */
 			mpt_GetScsiPortSettings(ioc, 0);
@@ -2354,6 +2541,8 @@
 			mpt_read_ioc_pg_1(ioc);
 
 			mpt_read_ioc_pg_4(ioc);
+
+			break;
 		}
 
 		GetIoUnitPage2(ioc);
@@ -2435,16 +2624,20 @@
 		if (_pcidev == peer) {
 			/* Paranoia checks */
 			if (ioc->alt_ioc != NULL) {
-				printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
-					ioc->name, ioc->alt_ioc->name);
+				printk(MYIOC_s_WARN_FMT
+				    "Oops, already bound (%s <==> %s)!\n",
+				    ioc->name, ioc->name, ioc->alt_ioc->name);
 				break;
 			} else if (ioc_srch->alt_ioc != NULL) {
-				printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
-					ioc_srch->name, ioc_srch->alt_ioc->name);
+				printk(MYIOC_s_WARN_FMT
+				    "Oops, already bound (%s <==> %s)!\n",
+				    ioc_srch->name, ioc_srch->name,
+				    ioc_srch->alt_ioc->name);
 				break;
 			}
-			dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
-				ioc->name, ioc_srch->name));
+			dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+				"FOUND! binding %s <==> %s\n",
+				ioc->name, ioc->name, ioc_srch->name));
 			ioc_srch->alt_ioc = ioc;
 			ioc->alt_ioc = ioc_srch;
 		}
@@ -2464,8 +2657,8 @@
 	int ret;
 
 	if (ioc->cached_fw != NULL) {
-		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
-		    "adapter\n", __func__, ioc->name));
+		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+			"%s: Pushing FW onto adapter\n", __func__, ioc->name));
 		if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
 		    ioc->cached_fw, CAN_SLEEP)) < 0) {
 			printk(MYIOC_s_WARN_FMT
@@ -2474,11 +2667,30 @@
 		}
 	}
 
+	/*
+	 * Put the controller into ready state (if its not already)
+	 */
+	if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
+		if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
+		    CAN_SLEEP)) {
+			if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
+				printk(MYIOC_s_ERR_FMT "%s:  IOC msg unit "
+				    "reset failed to put ioc in ready state!\n",
+				    ioc->name, __func__);
+		} else
+			printk(MYIOC_s_ERR_FMT "%s:  IOC msg unit reset "
+			    "failed!\n", ioc->name, __func__);
+	}
+
+
 	/* Disable adapter interrupts! */
+	synchronize_irq(ioc->pcidev->irq);
 	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
 	ioc->active = 0;
+
 	/* Clear any lingering interrupt */
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+	CHIPREG_READ32(&ioc->chip->IntStatus);
 
 	if (ioc->alloc != NULL) {
 		sz = ioc->alloc_sz;
@@ -2538,19 +2750,22 @@
 		if((ret = mpt_host_page_access_control(ioc,
 		    MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
 			printk(MYIOC_s_ERR_FMT
-			   "host page buffers free failed (%d)!\n",
-			    ioc->name, ret);
+			   ": %s: host page buffers free failed (%d)!\n",
+			    ioc->name, __func__, ret);
 		}
-		dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free  @ %p, sz=%d bytes\n",
-		 	ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
+		dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+			"HostPageBuffer free  @ %p, sz=%d bytes\n",
+			ioc->name, ioc->HostPageBuffer,
+			ioc->HostPageBuffer_sz));
 		pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
 		    ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
 		ioc->HostPageBuffer = NULL;
 		ioc->HostPageBuffer_sz = 0;
 		ioc->alloc_total -= ioc->HostPageBuffer_sz;
 	}
-}
 
+	pci_set_drvdata(ioc->pcidev, NULL);
+}
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *	mpt_adapter_dispose - Free all resources associated with an MPT adapter
@@ -2690,8 +2905,12 @@
 	}
 
 	/* Is it already READY? */
-	if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
+	if (!statefault &&
+	    ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
+		dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+		    "IOC is in READY state\n", ioc->name));
 		return 0;
+	}
 
 	/*
 	 *	Check to see if IOC is in FAULT state.
@@ -2764,8 +2983,9 @@
 
 		ii++; cntdn--;
 		if (!cntdn) {
-			printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
-					ioc->name, (int)((ii+5)/HZ));
+			printk(MYIOC_s_ERR_FMT
+				"Wait IOC_READY state (0x%x) timeout(%d)!\n",
+				ioc->name, ioc_state, (int)((ii+5)/HZ));
 			return -ETIME;
 		}
 
@@ -2778,9 +2998,8 @@
 	}
 
 	if (statefault < 3) {
-		printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
-				ioc->name,
-				statefault==1 ? "stuck handshake" : "IOC FAULT");
+		printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
+			statefault == 1 ? "stuck handshake" : "IOC FAULT");
 	}
 
 	return hard_reset_done;
@@ -2833,8 +3052,9 @@
 
 	/* IOC *must* NOT be in RESET state! */
 	if (ioc->last_state == MPI_IOC_STATE_RESET) {
-		printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
-		    ioc->name, ioc->last_state );
+		printk(KERN_ERR MYNAM
+		    ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
+		    ioc->name, ioc->last_state);
 		return -44;
 	}
 
@@ -2896,7 +3116,7 @@
 		 *	Old: u16{Major(4),Minor(4),SubMinor(8)}
 		 *	New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
 		 */
-		if (facts->MsgVersion < 0x0102) {
+		if (facts->MsgVersion < MPI_VERSION_01_02) {
 			/*
 			 *	Handle old FC f/w style, convert to new...
 			 */
@@ -2908,9 +3128,11 @@
 			facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
 
 		facts->ProductID = le16_to_cpu(facts->ProductID);
+
 		if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
 		    > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
 			ioc->ir_firmware = 1;
+
 		facts->CurrentHostMfaHighAddr =
 				le32_to_cpu(facts->CurrentHostMfaHighAddr);
 		facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
@@ -2926,7 +3148,7 @@
 		 * to 14 in MPI-1.01.0x.
 		 */
 		if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
-		    facts->MsgVersion > 0x0100) {
+		    facts->MsgVersion > MPI_VERSION_01_00) {
 			facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
 		}
 
@@ -3108,6 +3330,7 @@
 
 	ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
 	ioc_init.MaxBuses = (U8)ioc->number_of_buses;
+
 	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
 		   ioc->name, ioc->facts.MsgVersion));
 	if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
@@ -3122,7 +3345,7 @@
 	}
 	ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz);	/* in BYTES */
 
-	if (sizeof(dma_addr_t) == sizeof(u64)) {
+	if (ioc->sg_addr_size == sizeof(u64)) {
 		/* Save the upper 32-bits of the request
 		 * (reply) and sense buffers.
 		 */
@@ -3325,11 +3548,10 @@
 	FWUpload_t		*prequest;
 	FWUploadReply_t		*preply;
 	FWUploadTCSGE_t		*ptcsge;
-	int			 sgeoffset;
 	u32			 flagsLength;
 	int			 ii, sz, reply_sz;
 	int			 cmdStatus;
-
+	int			request_size;
 	/* If the image size is 0, we are done.
 	 */
 	if ((sz = ioc->facts.FWImageSize) == 0)
@@ -3364,42 +3586,41 @@
 	ptcsge->ImageSize = cpu_to_le32(sz);
 	ptcsge++;
 
-	sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
-
 	flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
-	mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
-
-	sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
-	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
-	    ioc->name, prequest, sgeoffset));
+	ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
+	request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
+	    ioc->SGE_size;
+	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
+	    " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
+	    ioc->facts.FWImageSize, request_size));
 	DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
 
-	ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
-				reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
+	ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
+	    reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
 
-	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
+	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
+	    "rc=%x \n", ioc->name, ii));
 
 	cmdStatus = -EFAULT;
 	if (ii == 0) {
 		/* Handshake transfer was complete and successful.
 		 * Check the Reply Frame.
 		 */
-		int status, transfer_sz;
-		status = le16_to_cpu(preply->IOCStatus);
-		if (status == MPI_IOCSTATUS_SUCCESS) {
-			transfer_sz = le32_to_cpu(preply->ActualImageSize);
-			if (transfer_sz == sz)
+		int status;
+		status = le16_to_cpu(preply->IOCStatus) &
+				MPI_IOCSTATUS_MASK;
+		if (status == MPI_IOCSTATUS_SUCCESS &&
+		    ioc->facts.FWImageSize ==
+		    le32_to_cpu(preply->ActualImageSize))
 				cmdStatus = 0;
-		}
 	}
 	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
 			ioc->name, cmdStatus));
 
 
 	if (cmdStatus) {
-
-		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
-			ioc->name));
+		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
+		    "freeing image \n", ioc->name));
 		mpt_free_fw_memory(ioc);
 	}
 	kfree(prequest);
@@ -3723,6 +3944,10 @@
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 
 	if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
+
+		if (!ignore)
+			return 0;
+
 		drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
 			"address=%p\n",  ioc->name, __func__,
 			&ioc->chip->Doorbell, &ioc->chip->Reset_1078));
@@ -3740,6 +3965,7 @@
 				"looking for READY STATE: doorbell=%x"
 			        " count=%d\n",
 				ioc->name, doorbell, count));
+
 			if (doorbell == MPI_IOC_STATE_READY) {
 				return 1;
 			}
@@ -3890,6 +4116,10 @@
 				doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
 				doorbell &= MPI_IOC_STATE_MASK;
 
+				drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+				    "looking for READY STATE: doorbell=%x"
+				    " count=%d\n", ioc->name, doorbell, count));
+
 				if (doorbell == MPI_IOC_STATE_READY) {
 					break;
 				}
@@ -3901,6 +4131,11 @@
 					mdelay (1000);
 				}
 			}
+
+			if (doorbell != MPI_IOC_STATE_READY)
+				printk(MYIOC_s_ERR_FMT "Failed to come READY "
+				    "after reset! IocState=%x", ioc->name,
+				    doorbell);
 		}
 	}
 
@@ -4019,8 +4254,9 @@
 			if (sleepFlag != CAN_SLEEP)
 				count *= 10;
 
-			printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
-			    ioc->name, (int)((count+5)/HZ));
+			printk(MYIOC_s_ERR_FMT
+			    "Wait IOC_READY state (0x%x) timeout(%d)!\n",
+			    ioc->name, state, (int)((count+5)/HZ));
 			return -ETIME;
 		}
 
@@ -4090,24 +4326,29 @@
 	 * num_sge = num sge in request frame + last chain buffer
 	 * scale = num sge per chain buffer if no chain element
 	 */
-	scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
-	if (sizeof(dma_addr_t) == sizeof(u64))
-		num_sge =  scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+	scale = ioc->req_sz / ioc->SGE_size;
+	if (ioc->sg_addr_size == sizeof(u64))
+		num_sge =  scale + (ioc->req_sz - 60) / ioc->SGE_size;
 	else
-		num_sge =  1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+		num_sge =  1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
 
-	if (sizeof(dma_addr_t) == sizeof(u64)) {
+	if (ioc->sg_addr_size == sizeof(u64)) {
 		numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
-			(ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+			(ioc->req_sz - 60) / ioc->SGE_size;
 	} else {
-		numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
-			(ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+		numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
+		    scale + (ioc->req_sz - 64) / ioc->SGE_size;
 	}
 	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
 		ioc->name, num_sge, numSGE));
 
-	if ( numSGE > MPT_SCSI_SG_DEPTH	)
-		numSGE = MPT_SCSI_SG_DEPTH;
+	if (ioc->bus_type == FC) {
+		if (numSGE > MPT_SCSI_FC_SG_DEPTH)
+			numSGE = MPT_SCSI_FC_SG_DEPTH;
+	} else {
+		if (numSGE > MPT_SCSI_SG_DEPTH)
+			numSGE = MPT_SCSI_SG_DEPTH;
+	}
 
 	num_chain = 1;
 	while (numSGE - num_sge > 0) {
@@ -4161,12 +4402,42 @@
 	dma_addr_t alloc_dma;
 	u8 *mem;
 	int i, reply_sz, sz, total_size, num_chain;
+	u64	dma_mask;
+
+	dma_mask = 0;
 
 	/*  Prime reply FIFO...  */
 
 	if (ioc->reply_frames == NULL) {
 		if ( (num_chain = initChainBuffers(ioc)) < 0)
 			return -1;
+		/*
+		 * 1078 errata workaround for the 36GB limitation
+		 */
+		if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
+		    ioc->dma_mask > DMA_35BIT_MASK) {
+			if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
+			    && !pci_set_consistent_dma_mask(ioc->pcidev,
+			    DMA_BIT_MASK(32))) {
+				dma_mask = DMA_35BIT_MASK;
+				d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+				    "setting 35 bit addressing for "
+				    "Request/Reply/Chain and Sense Buffers\n",
+				    ioc->name));
+			} else {
+				/*Reseting DMA mask to 64 bit*/
+				pci_set_dma_mask(ioc->pcidev,
+					DMA_BIT_MASK(64));
+				pci_set_consistent_dma_mask(ioc->pcidev,
+					DMA_BIT_MASK(64));
+
+				printk(MYIOC_s_ERR_FMT
+				    "failed setting 35 bit addressing for "
+				    "Request/Reply/Chain and Sense Buffers\n",
+				    ioc->name);
+				return -1;
+			}
+		}
 
 		total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
 		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
@@ -4305,9 +4576,16 @@
 		alloc_dma += ioc->reply_sz;
 	}
 
+	if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
+	    ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
+	    ioc->dma_mask))
+		d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "restoring 64 bit addressing\n", ioc->name));
+
 	return 0;
 
 out_fail:
+
 	if (ioc->alloc != NULL) {
 		sz = ioc->alloc_sz;
 		pci_free_consistent(ioc->pcidev,
@@ -4324,6 +4602,13 @@
 				ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
 		ioc->sense_buf_pool = NULL;
 	}
+
+	if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
+	    DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
+	    DMA_BIT_MASK(64)))
+		d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "restoring 64 bit addressing\n", ioc->name));
+
 	return -1;
 }
 
@@ -4759,7 +5044,14 @@
 	SasIoUnitControlReply_t		*sasIoUnitCntrReply;
 	MPT_FRAME_HDR			*mf = NULL;
 	MPIHeader_t			*mpi_hdr;
+	int				ret = 0;
+	unsigned long 	 		timeleft;
 
+	mutex_lock(&ioc->mptbase_cmds.mutex);
+
+	/* init the internal cmd struct */
+	memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
+	INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
 
 	/* insure garbage is not sent to fw */
 	switch(persist_opcode) {
@@ -4769,17 +5061,19 @@
 		break;
 
 	default:
-		return -1;
-		break;
+		ret = -1;
+		goto out;
 	}
 
-	printk("%s: persist_opcode=%x\n",__func__, persist_opcode);
+	printk(KERN_DEBUG  "%s: persist_opcode=%x\n",
+		__func__, persist_opcode);
 
 	/* Get a MF for this command.
 	 */
 	if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
-		printk("%s: no msg frames!\n",__func__);
-		return -1;
+		printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
+		ret = -1;
+		goto out;
         }
 
 	mpi_hdr = (MPIHeader_t *) mf;
@@ -4789,27 +5083,42 @@
 	sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
 	sasIoUnitCntrReq->Operation = persist_opcode;
 
-	init_timer(&ioc->persist_timer);
-	ioc->persist_timer.data = (unsigned long) ioc;
-	ioc->persist_timer.function = mpt_timer_expired;
-	ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
-	ioc->persist_wait_done=0;
-	add_timer(&ioc->persist_timer);
 	mpt_put_msg_frame(mpt_base_index, ioc, mf);
-	wait_event(mpt_waitq, ioc->persist_wait_done);
-
-	sasIoUnitCntrReply =
-	    (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
-	if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
-		printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
-		    __func__,
-		    sasIoUnitCntrReply->IOCStatus,
-		    sasIoUnitCntrReply->IOCLogInfo);
-		return -1;
+	timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
+	if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+		ret = -ETIME;
+		printk(KERN_DEBUG "%s: failed\n", __func__);
+		if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+			goto out;
+		if (!timeleft) {
+			printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
+			    ioc->name, __func__);
+			mpt_HardResetHandler(ioc, CAN_SLEEP);
+			mpt_free_msg_frame(ioc, mf);
+		}
+		goto out;
 	}
 
-	printk("%s: success\n",__func__);
-	return 0;
+	if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+		ret = -1;
+		goto out;
+	}
+
+	sasIoUnitCntrReply =
+	    (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
+	if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
+		printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
+		    __func__, sasIoUnitCntrReply->IOCStatus,
+		    sasIoUnitCntrReply->IOCLogInfo);
+		printk(KERN_DEBUG "%s: failed\n", __func__);
+		ret = -1;
+	} else
+		printk(KERN_DEBUG "%s: success\n", __func__);
+ out:
+
+	CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
+	mutex_unlock(&ioc->mptbase_cmds.mutex);
+	return ret;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -5394,17 +5703,20 @@
  *	-ENOMEM if pci_alloc failed
  **/
 int
-mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
+mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
+			RaidPhysDiskPage0_t *phys_disk)
 {
-	CONFIGPARMS		 	cfg;
-	ConfigPageHeader_t	 	hdr;
+	CONFIGPARMS			cfg;
+	ConfigPageHeader_t		hdr;
 	dma_addr_t			dma_handle;
 	pRaidPhysDiskPage0_t		buffer = NULL;
 	int				rc;
 
 	memset(&cfg, 0 , sizeof(CONFIGPARMS));
 	memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+	memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
 
+	hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
 	hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
 	cfg.cfghdr.hdr = &hdr;
 	cfg.physAddr = -1;
@@ -5451,6 +5763,161 @@
 }
 
 /**
+ *	mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
+ *	@ioc: Pointer to a Adapter Structure
+ *	@phys_disk_num: io unit unique phys disk num generated by the ioc
+ *
+ *	Return:
+ *	returns number paths
+ **/
+int
+mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
+{
+	CONFIGPARMS		 	cfg;
+	ConfigPageHeader_t	 	hdr;
+	dma_addr_t			dma_handle;
+	pRaidPhysDiskPage1_t		buffer = NULL;
+	int				rc;
+
+	memset(&cfg, 0 , sizeof(CONFIGPARMS));
+	memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+
+	hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
+	hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
+	hdr.PageNumber = 1;
+	cfg.cfghdr.hdr = &hdr;
+	cfg.physAddr = -1;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+	if (mpt_config(ioc, &cfg) != 0) {
+		rc = 0;
+		goto out;
+	}
+
+	if (!hdr.PageLength) {
+		rc = 0;
+		goto out;
+	}
+
+	buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+	    &dma_handle);
+
+	if (!buffer) {
+		rc = 0;
+		goto out;
+	}
+
+	cfg.physAddr = dma_handle;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+	cfg.pageAddr = phys_disk_num;
+
+	if (mpt_config(ioc, &cfg) != 0) {
+		rc = 0;
+		goto out;
+	}
+
+	rc = buffer->NumPhysDiskPaths;
+ out:
+
+	if (buffer)
+		pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+		    dma_handle);
+
+	return rc;
+}
+EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
+
+/**
+ *	mpt_raid_phys_disk_pg1 - returns phys disk page 1
+ *	@ioc: Pointer to a Adapter Structure
+ *	@phys_disk_num: io unit unique phys disk num generated by the ioc
+ *	@phys_disk: requested payload data returned
+ *
+ *	Return:
+ *	0 on success
+ *	-EFAULT if read of config page header fails or data pointer not NULL
+ *	-ENOMEM if pci_alloc failed
+ **/
+int
+mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
+		RaidPhysDiskPage1_t *phys_disk)
+{
+	CONFIGPARMS		 	cfg;
+	ConfigPageHeader_t	 	hdr;
+	dma_addr_t			dma_handle;
+	pRaidPhysDiskPage1_t		buffer = NULL;
+	int				rc;
+	int				i;
+	__le64				sas_address;
+
+	memset(&cfg, 0 , sizeof(CONFIGPARMS));
+	memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+	rc = 0;
+
+	hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
+	hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
+	hdr.PageNumber = 1;
+	cfg.cfghdr.hdr = &hdr;
+	cfg.physAddr = -1;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+	if (mpt_config(ioc, &cfg) != 0) {
+		rc = -EFAULT;
+		goto out;
+	}
+
+	if (!hdr.PageLength) {
+		rc = -EFAULT;
+		goto out;
+	}
+
+	buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+	    &dma_handle);
+
+	if (!buffer) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	cfg.physAddr = dma_handle;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+	cfg.pageAddr = phys_disk_num;
+
+	if (mpt_config(ioc, &cfg) != 0) {
+		rc = -EFAULT;
+		goto out;
+	}
+
+	phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
+	phys_disk->PhysDiskNum = phys_disk_num;
+	for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
+		phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
+		phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
+		phys_disk->Path[i].OwnerIdentifier =
+				buffer->Path[i].OwnerIdentifier;
+		phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
+		memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
+		sas_address = le64_to_cpu(sas_address);
+		memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
+		memcpy(&sas_address,
+				&buffer->Path[i].OwnerWWID, sizeof(__le64));
+		sas_address = le64_to_cpu(sas_address);
+		memcpy(&phys_disk->Path[i].OwnerWWID,
+				&sas_address, sizeof(__le64));
+	}
+
+ out:
+
+	if (buffer)
+		pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+		    dma_handle);
+
+	return rc;
+}
+EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
+
+
+/**
  *	mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
  *	@ioc: Pointer to a Adapter Strucutre
  *
@@ -5775,30 +6242,28 @@
  *	SendEventNotification - Send EventNotification (on or off) request to adapter
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@EvSwitch: Event switch flags
+ *	@sleepFlag: Specifies whether the process can sleep
  */
 static int
-SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
+SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
 {
-	EventNotification_t	*evnp;
+	EventNotification_t	evn;
+	MPIDefaultReply_t	reply_buf;
 
-	evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
-	if (evnp == NULL) {
-		devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
-				ioc->name));
-		return 0;
-	}
-	memset(evnp, 0, sizeof(*evnp));
+	memset(&evn, 0, sizeof(EventNotification_t));
+	memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
 
-	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
+	evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
+	evn.Switch = EvSwitch;
+	evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
 
-	evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
-	evnp->ChainOffset = 0;
-	evnp->MsgFlags = 0;
-	evnp->Switch = EvSwitch;
+	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+	    "Sending EventNotification (%d) request %p\n",
+	    ioc->name, EvSwitch, &evn));
 
-	mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
-
-	return 0;
+	return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
+	    (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
+	    sleepFlag);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -5814,7 +6279,7 @@
 
 	if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
-		    ioc->name,__func__));
+		    ioc->name, __func__));
 		return -1;
 	}
 
@@ -5851,12 +6316,19 @@
 mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
 {
 	Config_t	*pReq;
+	ConfigReply_t	*pReply;
 	ConfigExtendedPageHeader_t  *pExtHdr = NULL;
 	MPT_FRAME_HDR	*mf;
-	unsigned long	 flags;
-	int		 ii, rc;
+	int		 ii;
 	int		 flagsLength;
-	int		 in_isr;
+	long		 timeout;
+	int		 ret;
+	u8		 page_type = 0, extend_page;
+	unsigned long 	 timeleft;
+	unsigned long	 flags;
+    int		 in_isr;
+	u8		 issue_hard_reset = 0;
+	u8		 retry_count = 0;
 
 	/*	Prevent calling wait_event() (below), if caller happens
 	 *	to be in ISR context, because that is fatal!
@@ -5866,15 +6338,43 @@
 		dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
 				ioc->name));
 		return -EPERM;
+    }
+
+	/* don't send a config page during diag reset */
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+	if (ioc->ioc_reset_in_progress) {
+		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: busy with host reset\n", ioc->name, __func__));
+		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+		return -EBUSY;
 	}
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+	/* don't send if no chance of success */
+	if (!ioc->active ||
+	    mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
+		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: ioc not operational, %d, %xh\n",
+		    ioc->name, __func__, ioc->active,
+		    mpt_GetIocState(ioc, 0)));
+		return -EFAULT;
+	}
+
+ retry_config:
+	mutex_lock(&ioc->mptbase_cmds.mutex);
+	/* init the internal cmd struct */
+	memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
+	INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
 
 	/* Get and Populate a free Frame
 	 */
 	if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
-		dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
-				ioc->name));
-		return -EAGAIN;
+		dcprintk(ioc, printk(MYIOC_s_WARN_FMT
+		"mpt_config: no msg frames!\n", ioc->name));
+		ret = -EAGAIN;
+		goto out;
 	}
+
 	pReq = (Config_t *)mf;
 	pReq->Action = pCfg->action;
 	pReq->Reserved = 0;
@@ -5900,7 +6400,9 @@
 		pReq->ExtPageType = pExtHdr->ExtPageType;
 		pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
 
-		/* Page Length must be treated as a reserved field for the extended header. */
+		/* Page Length must be treated as a reserved field for the
+		 * extended header.
+		 */
 		pReq->Header.PageLength = 0;
 	}
 
@@ -5913,78 +6415,91 @@
 	else
 		flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
 
-	if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
+	if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
+	    MPI_CONFIG_PAGETYPE_EXTENDED) {
 		flagsLength |= pExtHdr->ExtPageLength * 4;
-
-		dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
-			ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
-	}
-	else {
+		page_type = pReq->ExtPageType;
+		extend_page = 1;
+	} else {
 		flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
-
-		dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
-			ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
+		page_type = pReq->Header.PageType;
+		extend_page = 0;
 	}
 
-	mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
+	dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+	    "Sending Config request type 0x%x, page 0x%x and action %d\n",
+	    ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
 
-	/* Append pCfg pointer to end of mf
-	 */
-	*((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) =  (void *) pCfg;
-
-	/* Initalize the timer
-	 */
-	init_timer_on_stack(&pCfg->timer);
-	pCfg->timer.data = (unsigned long) ioc;
-	pCfg->timer.function = mpt_timer_expired;
-	pCfg->wait_done = 0;
-
-	/* Set the timer; ensure 10 second minimum */
-	if (pCfg->timeout < 10)
-		pCfg->timer.expires = jiffies + HZ*10;
-	else
-		pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
-
-	/* Add to end of Q, set timer and then issue this command */
-	spin_lock_irqsave(&ioc->FreeQlock, flags);
-	list_add_tail(&pCfg->linkage, &ioc->configQ);
-	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-	add_timer(&pCfg->timer);
+	ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
+	timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
 	mpt_put_msg_frame(mpt_base_index, ioc, mf);
-	wait_event(mpt_waitq, pCfg->wait_done);
+	timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
+		timeout);
+	if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+		ret = -ETIME;
+		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "Failed Sending Config request type 0x%x, page 0x%x,"
+		    " action %d, status %xh, time left %ld\n\n",
+			ioc->name, page_type, pReq->Header.PageNumber,
+			pReq->Action, ioc->mptbase_cmds.status, timeleft));
+		if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+			goto out;
+		if (!timeleft)
+			issue_hard_reset = 1;
+		goto out;
+	}
 
-	/* mf has been freed - do not access */
+	if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+		ret = -1;
+		goto out;
+	}
+	pReply = (ConfigReply_t	*)ioc->mptbase_cmds.reply;
+	ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+	if (ret == MPI_IOCSTATUS_SUCCESS) {
+		if (extend_page) {
+			pCfg->cfghdr.ehdr->ExtPageLength =
+			    le16_to_cpu(pReply->ExtPageLength);
+			pCfg->cfghdr.ehdr->ExtPageType =
+			    pReply->ExtPageType;
+		}
+		pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
+		pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
+		pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
+		pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
 
-	rc = pCfg->status;
+	}
 
-	return rc;
-}
+	if (retry_count)
+		printk(MYIOC_s_INFO_FMT "Retry completed "
+		    "ret=0x%x timeleft=%ld\n",
+		    ioc->name, ret, timeleft);
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	mpt_timer_expired - Callback for timer process.
- *	Used only internal config functionality.
- *	@data: Pointer to MPT_SCSI_HOST recast as an unsigned long
- */
-static void
-mpt_timer_expired(unsigned long data)
-{
-	MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
+	dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+	     ret, le32_to_cpu(pReply->IOCLogInfo)));
 
-	dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
+out:
 
-	/* Perform a FW reload */
-	if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
-		printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
+	CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
+	mutex_unlock(&ioc->mptbase_cmds.mutex);
+	if (issue_hard_reset) {
+		issue_hard_reset = 0;
+		printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+		    ioc->name, __func__);
+		mpt_HardResetHandler(ioc, CAN_SLEEP);
+		mpt_free_msg_frame(ioc, mf);
+		/* attempt one retry for a timed out command */
+		if (!retry_count) {
+			printk(MYIOC_s_INFO_FMT
+			    "Attempting Retry Config request"
+			    " type 0x%x, page 0x%x,"
+			    " action %d\n", ioc->name, page_type,
+			    pCfg->cfghdr.hdr->PageNumber, pCfg->action);
+			retry_count++;
+			goto retry_config;
+		}
+	}
+	return ret;
 
-	/* No more processing.
-	 * Hard reset clean-up will wake up
-	 * process and free all resources.
-	 */
-	dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
-
-	return;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -5998,41 +6513,34 @@
 static int
 mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
-	CONFIGPARMS *pCfg;
-	unsigned long flags;
-
-	dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-	    ": IOC %s_reset routed to MPT base driver!\n",
-	    ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
-	    reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
-
-	if (reset_phase == MPT_IOC_SETUP_RESET) {
-		;
-	} else if (reset_phase == MPT_IOC_PRE_RESET) {
-		/* If the internal config Q is not empty -
-		 * delete timer. MF resources will be freed when
-		 * the FIFO's are primed.
-		 */
-		spin_lock_irqsave(&ioc->FreeQlock, flags);
-		list_for_each_entry(pCfg, &ioc->configQ, linkage)
-			del_timer(&pCfg->timer);
-		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-	} else {
-		CONFIGPARMS *pNext;
-
-		/* Search the configQ for internal commands.
-		 * Flush the Q, and wake up all suspended threads.
-		 */
-		spin_lock_irqsave(&ioc->FreeQlock, flags);
-		list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
-			list_del(&pCfg->linkage);
-
-			pCfg->status = MPT_CONFIG_ERROR;
-			pCfg->wait_done = 1;
-			wake_up(&mpt_waitq);
+	switch (reset_phase) {
+	case MPT_IOC_SETUP_RESET:
+		ioc->taskmgmt_quiesce_io = 1;
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
+		break;
+	case MPT_IOC_PRE_RESET:
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
+		break;
+	case MPT_IOC_POST_RESET:
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: MPT_IOC_POST_RESET\n",  ioc->name, __func__));
+/* wake up mptbase_cmds */
+		if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
+			ioc->mptbase_cmds.status |=
+			    MPT_MGMT_STATUS_DID_IOCRESET;
+			complete(&ioc->mptbase_cmds.done);
 		}
-		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+/* wake up taskmgmt_cmds */
+		if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
+			ioc->taskmgmt_cmds.status |=
+				MPT_MGMT_STATUS_DID_IOCRESET;
+			complete(&ioc->taskmgmt_cmds.done);
+		}
+		break;
+	default:
+		break;
 	}
 
 	return 1;		/* currently means nothing really */
@@ -6344,6 +6852,59 @@
 
 	*size = y;
 }
+/**
+ *	mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ *	Returns 0 for SUCCESS or -1 if FAILED.
+ *
+ *	If -1 is return, then it was not possible to set the flags
+ **/
+int
+mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
+{
+	unsigned long	 flags;
+	int		 retval;
+
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+	if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
+	    (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
+		retval = -1;
+		goto out;
+	}
+	retval = 0;
+	ioc->taskmgmt_in_progress = 1;
+	ioc->taskmgmt_quiesce_io = 1;
+	if (ioc->alt_ioc) {
+		ioc->alt_ioc->taskmgmt_in_progress = 1;
+		ioc->alt_ioc->taskmgmt_quiesce_io = 1;
+	}
+ out:
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+	return retval;
+}
+EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
+
+/**
+ *	mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
+void
+mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
+{
+	unsigned long	 flags;
+
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+	ioc->taskmgmt_in_progress = 0;
+	ioc->taskmgmt_quiesce_io = 0;
+	if (ioc->alt_ioc) {
+		ioc->alt_ioc->taskmgmt_in_progress = 0;
+		ioc->alt_ioc->taskmgmt_quiesce_io = 0;
+	}
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+}
+EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
 
 
 /**
@@ -6397,7 +6958,9 @@
 mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
 {
 	int		 rc;
+	u8	 cb_idx;
 	unsigned long	 flags;
+	unsigned long	 time_count;
 
 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
 #ifdef MFCNT
@@ -6410,14 +6973,15 @@
 	/* Reset the adapter. Prevent more than 1 call to
 	 * mpt_do_ioc_recovery at any instant in time.
 	 */
-	spin_lock_irqsave(&ioc->diagLock, flags);
-	if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
-		spin_unlock_irqrestore(&ioc->diagLock, flags);
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+	if (ioc->ioc_reset_in_progress) {
+		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 		return 0;
-	} else {
-		ioc->diagPending = 1;
 	}
-	spin_unlock_irqrestore(&ioc->diagLock, flags);
+	ioc->ioc_reset_in_progress = 1;
+	if (ioc->alt_ioc)
+		ioc->alt_ioc->ioc_reset_in_progress = 1;
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 
 	/* FIXME: If do_ioc_recovery fails, repeat....
 	 */
@@ -6427,47 +6991,57 @@
 	 * Prevents timeouts occurring during a diagnostic reset...very bad.
 	 * For all other protocol drivers, this is a no-op.
 	 */
-	{
-		u8	 cb_idx;
-		int	 r = 0;
-
-		for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
-			if (MptResetHandlers[cb_idx]) {
-				dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
-						ioc->name, cb_idx));
-				r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
-				if (ioc->alt_ioc) {
-					dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
-							ioc->name, ioc->alt_ioc->name, cb_idx));
-					r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
-				}
-			}
+	for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+		if (MptResetHandlers[cb_idx]) {
+			mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
+			if (ioc->alt_ioc)
+				mpt_signal_reset(cb_idx, ioc->alt_ioc,
+					MPT_IOC_SETUP_RESET);
 		}
 	}
 
-	if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
-		printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
+	time_count = jiffies;
+	rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
+	if (rc != 0) {
+		printk(KERN_WARNING MYNAM
+		    ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name);
+	} else {
+		if (ioc->hard_resets < -1)
+			ioc->hard_resets++;
 	}
-	ioc->reload_fw = 0;
-	if (ioc->alt_ioc)
-		ioc->alt_ioc->reload_fw = 0;
 
-	spin_lock_irqsave(&ioc->diagLock, flags);
-	ioc->diagPending = 0;
-	if (ioc->alt_ioc)
-		ioc->alt_ioc->diagPending = 0;
-	spin_unlock_irqrestore(&ioc->diagLock, flags);
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+	ioc->ioc_reset_in_progress = 0;
+	ioc->taskmgmt_quiesce_io = 0;
+	ioc->taskmgmt_in_progress = 0;
+	if (ioc->alt_ioc) {
+		ioc->alt_ioc->ioc_reset_in_progress = 0;
+		ioc->alt_ioc->taskmgmt_quiesce_io = 0;
+		ioc->alt_ioc->taskmgmt_in_progress = 0;
+	}
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 
-	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
+	dtmprintk(ioc,
+	    printk(MYIOC_s_DEBUG_FMT
+		"HardResetHandler: completed (%d seconds): %s\n", ioc->name,
+		jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
+		"SUCCESS" : "FAILED")));
 
 	return rc;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#ifdef CONFIG_FUSION_LOGGING
 static void
-EventDescriptionStr(u8 event, u32 evData0, char *evStr)
+mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
 {
 	char *ds = NULL;
+	u32 evData0;
+	int ii;
+	u8 event;
+	char *evStr = ioc->evStr;
+
+	event = le32_to_cpu(pEventReply->Event) & 0xFF;
+	evData0 = le32_to_cpu(pEventReply->Data[0]);
 
 	switch(event) {
 	case MPI_EVENT_NONE:
@@ -6501,9 +7075,9 @@
 		if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
 			ds = "Loop State(LIP) Change";
 		else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
-			ds = "Loop State(LPE) Change";		/* ??? */
+			ds = "Loop State(LPE) Change";
 		else
-			ds = "Loop State(LPB) Change";		/* ??? */
+			ds = "Loop State(LPB) Change";
 		break;
 	case MPI_EVENT_LOGOUT:
 		ds = "Logout";
@@ -6703,28 +7277,65 @@
 	}
 	case MPI_EVENT_IR2:
 	{
+		u8 id = (u8)(evData0);
+		u8 channel = (u8)(evData0 >> 8);
+		u8 phys_num = (u8)(evData0 >> 24);
 		u8 ReasonCode = (u8)(evData0 >> 16);
+
 		switch (ReasonCode) {
 		case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
-			ds = "IR2: LD State Changed";
+			snprintf(evStr, EVENT_DESCR_STR_SZ,
+			    "IR2: LD State Changed: "
+			    "id=%d channel=%d phys_num=%d",
+			    id, channel, phys_num);
 			break;
 		case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
-			ds = "IR2: PD State Changed";
+			snprintf(evStr, EVENT_DESCR_STR_SZ,
+			    "IR2: PD State Changed "
+			    "id=%d channel=%d phys_num=%d",
+			    id, channel, phys_num);
 			break;
 		case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
-			ds = "IR2: Bad Block Table Full";
+			snprintf(evStr, EVENT_DESCR_STR_SZ,
+			    "IR2: Bad Block Table Full: "
+			    "id=%d channel=%d phys_num=%d",
+			    id, channel, phys_num);
 			break;
 		case MPI_EVENT_IR2_RC_PD_INSERTED:
-			ds = "IR2: PD Inserted";
+			snprintf(evStr, EVENT_DESCR_STR_SZ,
+			    "IR2: PD Inserted: "
+			    "id=%d channel=%d phys_num=%d",
+			    id, channel, phys_num);
 			break;
 		case MPI_EVENT_IR2_RC_PD_REMOVED:
-			ds = "IR2: PD Removed";
+			snprintf(evStr, EVENT_DESCR_STR_SZ,
+			    "IR2: PD Removed: "
+			    "id=%d channel=%d phys_num=%d",
+			    id, channel, phys_num);
 			break;
 		case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
-			ds = "IR2: Foreign CFG Detected";
+			snprintf(evStr, EVENT_DESCR_STR_SZ,
+			    "IR2: Foreign CFG Detected: "
+			    "id=%d channel=%d phys_num=%d",
+			    id, channel, phys_num);
 			break;
 		case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
-			ds = "IR2: Rebuild Medium Error";
+			snprintf(evStr, EVENT_DESCR_STR_SZ,
+			    "IR2: Rebuild Medium Error: "
+			    "id=%d channel=%d phys_num=%d",
+			    id, channel, phys_num);
+			break;
+		case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
+			snprintf(evStr, EVENT_DESCR_STR_SZ,
+			    "IR2: Dual Port Added: "
+			    "id=%d channel=%d phys_num=%d",
+			    id, channel, phys_num);
+			break;
+		case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
+			snprintf(evStr, EVENT_DESCR_STR_SZ,
+			    "IR2: Dual Port Removed: "
+			    "id=%d channel=%d phys_num=%d",
+			    id, channel, phys_num);
 			break;
 		default:
 			ds = "IR2";
@@ -6760,13 +7371,18 @@
 	case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
 	{
 		u8 reason = (u8)(evData0);
-		u8 port_num = (u8)(evData0 >> 8);
-		u16 handle = le16_to_cpu(evData0 >> 16);
 
-		snprintf(evStr, EVENT_DESCR_STR_SZ,
-		    "SAS Initiator Device Status Change: reason=0x%02x "
-		    "port=%d handle=0x%04x",
-		    reason, port_num, handle);
+		switch (reason) {
+		case MPI_EVENT_SAS_INIT_RC_ADDED:
+			ds = "SAS Initiator Status Change: Added";
+			break;
+		case MPI_EVENT_SAS_INIT_RC_REMOVED:
+			ds = "SAS Initiator Status Change: Deleted";
+			break;
+		default:
+			ds = "SAS Initiator Status Change";
+			break;
+		}
 		break;
 	}
 
@@ -6814,6 +7430,24 @@
 		break;
 	}
 
+	case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
+	{
+		u8 reason = (u8)(evData0);
+
+		switch (reason) {
+		case MPI_EVENT_SAS_EXP_RC_ADDED:
+			ds = "Expander Status Change: Added";
+			break;
+		case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
+			ds = "Expander Status Change: Deleted";
+			break;
+		default:
+			ds = "Expander Status Change";
+			break;
+		}
+		break;
+	}
+
 	/*
 	 *  MPT base "custom" events may be added here...
 	 */
@@ -6823,8 +7457,20 @@
 	}
 	if (ds)
 		strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
-}
 
+
+	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+	    "MPT event:(%02Xh) : %s\n",
+	    ioc->name, event, evStr));
+
+	devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
+	    ": Event data:\n"));
+	for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
+		devtverboseprintk(ioc, printk(" %08x",
+		    le32_to_cpu(pEventReply->Data[ii])));
+	devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
+}
+#endif
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *	ProcessEventNotification - Route EventNotificationReply to all event handlers
@@ -6841,37 +7487,24 @@
 {
 	u16 evDataLen;
 	u32 evData0 = 0;
-//	u32 evCtx;
 	int ii;
 	u8 cb_idx;
 	int r = 0;
 	int handlers = 0;
-	char evStr[EVENT_DESCR_STR_SZ];
 	u8 event;
 
 	/*
 	 *  Do platform normalization of values
 	 */
 	event = le32_to_cpu(pEventReply->Event) & 0xFF;
-//	evCtx = le32_to_cpu(pEventReply->EventContext);
 	evDataLen = le16_to_cpu(pEventReply->EventDataLength);
 	if (evDataLen) {
 		evData0 = le32_to_cpu(pEventReply->Data[0]);
 	}
 
-	EventDescriptionStr(event, evData0, evStr);
-	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
-			ioc->name,
-			event,
-			evStr));
-
 #ifdef CONFIG_FUSION_LOGGING
-	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-	    ": Event data:\n", ioc->name));
-	for (ii = 0; ii < evDataLen; ii++)
-		devtverboseprintk(ioc, printk(" %08x",
-		    le32_to_cpu(pEventReply->Data[ii])));
-	devtverboseprintk(ioc, printk("\n"));
+	if (evDataLen)
+		mpt_display_event_info(ioc, pEventReply);
 #endif
 
 	/*
@@ -6926,8 +7559,9 @@
 	 */
 	for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
 		if (MptEvHandlers[cb_idx]) {
-			devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
-					ioc->name, cb_idx));
+			devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+			    "Routing Event to event handler #%d\n",
+			    ioc->name, cb_idx));
 			r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
 			handlers++;
 		}
@@ -7011,8 +7645,6 @@
 	switch (info) {
 	case 0x00010000:
 		desc = "bug! MID not found";
-		if (ioc->reload_fw == 0)
-			ioc->reload_fw++;
 		break;
 
 	case 0x00020000:
@@ -7613,7 +8245,6 @@
 EXPORT_SYMBOL(mpt_put_msg_frame);
 EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
 EXPORT_SYMBOL(mpt_free_msg_frame);
-EXPORT_SYMBOL(mpt_add_sge);
 EXPORT_SYMBOL(mpt_send_handshake_request);
 EXPORT_SYMBOL(mpt_verify_adapter);
 EXPORT_SYMBOL(mpt_GetIocState);
@@ -7650,7 +8281,7 @@
 	/*  Register ourselves (mptbase) in order to facilitate
 	 *  EventNotification handling.
 	 */
-	mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
+	mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
 
 	/* Register for hard reset handling callbacks.
 	 */
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index b3e981d..1c8514d 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -76,8 +76,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2008 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"3.04.07"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.04.07"
+#define MPT_LINUX_VERSION_COMMON	"3.04.10"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.04.09"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -104,6 +104,7 @@
 #endif
 
 #define MPT_NAME_LENGTH			32
+#define MPT_KOBJ_NAME_LEN		20
 
 #define MPT_PROCFS_MPTBASEDIR		"mpt"
 						/* chg it to "driver/fusion" ? */
@@ -134,6 +135,7 @@
 
 #define MPT_COALESCING_TIMEOUT		0x10
 
+
 /*
  * SCSI transfer rate defines.
  */
@@ -161,10 +163,10 @@
 /*
  * Set the MAX_SGE value based on user input.
  */
-#ifdef  CONFIG_FUSION_MAX_SGE
-#if     CONFIG_FUSION_MAX_SGE  < 16
+#ifdef CONFIG_FUSION_MAX_SGE
+#if CONFIG_FUSION_MAX_SGE  < 16
 #define MPT_SCSI_SG_DEPTH	16
-#elif   CONFIG_FUSION_MAX_SGE  > 128
+#elif CONFIG_FUSION_MAX_SGE  > 128
 #define MPT_SCSI_SG_DEPTH	128
 #else
 #define MPT_SCSI_SG_DEPTH	CONFIG_FUSION_MAX_SGE
@@ -173,6 +175,18 @@
 #define MPT_SCSI_SG_DEPTH	40
 #endif
 
+#ifdef CONFIG_FUSION_MAX_FC_SGE
+#if CONFIG_FUSION_MAX_FC_SGE  < 16
+#define MPT_SCSI_FC_SG_DEPTH	16
+#elif CONFIG_FUSION_MAX_FC_SGE  > 256
+#define MPT_SCSI_FC_SG_DEPTH	256
+#else
+#define MPT_SCSI_FC_SG_DEPTH	CONFIG_FUSION_MAX_FC_SGE
+#endif
+#else
+#define MPT_SCSI_FC_SG_DEPTH	40
+#endif
+
 /* debug print string length used for events and iocstatus */
 # define EVENT_DESCR_STR_SZ             100
 
@@ -431,38 +445,36 @@
  *	IOCTL structure and associated defines
  */
 
-#define MPT_IOCTL_STATUS_DID_IOCRESET	0x01	/* IOC Reset occurred on the current*/
-#define MPT_IOCTL_STATUS_RF_VALID	0x02	/* The Reply Frame is VALID */
-#define MPT_IOCTL_STATUS_TIMER_ACTIVE	0x04	/* The timer is running */
-#define MPT_IOCTL_STATUS_SENSE_VALID	0x08	/* Sense data is valid */
-#define MPT_IOCTL_STATUS_COMMAND_GOOD	0x10	/* Command Status GOOD */
-#define MPT_IOCTL_STATUS_TMTIMER_ACTIVE	0x20	/* The TM timer is running */
-#define MPT_IOCTL_STATUS_TM_FAILED	0x40	/* User TM request failed */
-
 #define MPTCTL_RESET_OK			0x01	/* Issue Bus Reset */
 
-typedef struct _MPT_IOCTL {
-	struct _MPT_ADAPTER	*ioc;
-	u8			 ReplyFrame[MPT_DEFAULT_FRAME_SIZE];	/* reply frame data */
-	u8			 sense[MPT_SENSE_BUFFER_ALLOC];
-	int			 wait_done;	/* wake-up value for this ioc */
-	u8			 rsvd;
-	u8			 status;	/* current command status */
-	u8			 reset;		/* 1 if bus reset allowed */
-	u8			 id;		/* target for reset */
-	struct mutex		 ioctl_mutex;
-} MPT_IOCTL;
+#define MPT_MGMT_STATUS_RF_VALID	0x01	/* The Reply Frame is VALID */
+#define MPT_MGMT_STATUS_COMMAND_GOOD	0x02	/* Command Status GOOD */
+#define MPT_MGMT_STATUS_PENDING		0x04	/* command is pending */
+#define MPT_MGMT_STATUS_DID_IOCRESET	0x08	/* IOC Reset occurred
+						   on the current*/
+#define MPT_MGMT_STATUS_SENSE_VALID	0x10	/* valid sense info */
+#define MPT_MGMT_STATUS_TIMER_ACTIVE	0x20	/* obsolete */
+#define MPT_MGMT_STATUS_FREE_MF		0x40	/* free the mf from
+						   complete routine */
 
-#define MPT_SAS_MGMT_STATUS_RF_VALID	0x02	/* The Reply Frame is VALID */
-#define MPT_SAS_MGMT_STATUS_COMMAND_GOOD	0x10	/* Command Status GOOD */
-#define MPT_SAS_MGMT_STATUS_TM_FAILED	0x40	/* User TM request failed */
+#define INITIALIZE_MGMT_STATUS(status) \
+	status = MPT_MGMT_STATUS_PENDING;
+#define CLEAR_MGMT_STATUS(status) \
+	status = 0;
+#define CLEAR_MGMT_PENDING_STATUS(status) \
+	status &= ~MPT_MGMT_STATUS_PENDING;
+#define SET_MGMT_MSG_CONTEXT(msg_context, value) \
+	msg_context = value;
 
-typedef struct _MPT_SAS_MGMT {
+typedef struct _MPT_MGMT {
 	struct mutex		 mutex;
 	struct completion	 done;
 	u8			 reply[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */
+	u8			 sense[MPT_SENSE_BUFFER_ALLOC];
 	u8			 status;	/* current command status */
-}MPT_SAS_MGMT;
+	int			 completion_code;
+	u32			 msg_context;
+} MPT_MGMT;
 
 /*
  *  Event Structure and define
@@ -564,6 +576,10 @@
 	u8		flags;
 };
 
+typedef void (*MPT_ADD_SGE)(void *pAddr, u32 flagslength, dma_addr_t dma_addr);
+typedef void (*MPT_ADD_CHAIN)(void *pAddr, u8 next, u16 length,
+		dma_addr_t dma_addr);
+
 /*
  *  Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
  */
@@ -573,6 +589,10 @@
 	int			 pci_irq;	/* This irq           */
 	char			 name[MPT_NAME_LENGTH];	/* "iocN"             */
 	char			 prod_name[MPT_NAME_LENGTH];	/* "LSIFC9x9"         */
+#ifdef CONFIG_FUSION_LOGGING
+	/* used in mpt_display_event_info */
+	char			 evStr[EVENT_DESCR_STR_SZ];
+#endif
 	char			 board_name[16];
 	char			 board_assembly[16];
 	char			 board_tracer[16];
@@ -600,6 +620,10 @@
 	int			 reply_depth;	/* Num Allocated reply frames */
 	int			 reply_sz;	/* Reply frame size */
 	int			 num_chain;	/* Number of chain buffers */
+	MPT_ADD_SGE              add_sge;       /* Pointer to add_sge
+						   function */
+	MPT_ADD_CHAIN		 add_chain;	/* Pointer to add_chain
+						   function */
 		/* Pool of buffers for chaining. ReqToChain
 		 * and ChainToChain track index of chain buffers.
 		 * ChainBuffer (DMA) virt/phys addresses.
@@ -640,11 +664,8 @@
 	RaidCfgData		raid_data;	/* Raid config. data */
 	SasCfgData		sas_data;	/* Sas config. data */
 	FcCfgData		fc_data;	/* Fc config. data */
-	MPT_IOCTL		*ioctl;		/* ioctl data pointer */
 	struct proc_dir_entry	*ioc_dentry;
 	struct _MPT_ADAPTER	*alt_ioc;	/* ptr to 929 bound adapter port */
-	spinlock_t		 diagLock;	/* diagnostic reset lock */
-	int			 diagPending;
 	u32			 biosVersion;	/* BIOS version from IO Unit Page 2 */
 	int			 eventTypes;	/* Event logging parameters */
 	int			 eventContext;	/* Next event context */
@@ -652,7 +673,6 @@
 	struct _mpt_ioctl_events *events;	/* pointer to event log */
 	u8			*cached_fw;	/* Pointer to FW */
 	dma_addr_t	 	cached_fw_dma;
-	struct list_head	 configQ;	/* linked list of config. requests */
 	int			 hs_reply_idx;
 #ifndef MFCNT
 	u32			 pad0;
@@ -665,9 +685,6 @@
 	IOCFactsReply_t		 facts;
 	PortFactsReply_t	 pfacts[2];
 	FCPortPage0_t		 fc_port_page0[2];
-	struct timer_list	 persist_timer;	/* persist table timer */
-	int			 persist_wait_done; /* persist completion flag */
-	u8			 persist_reply_frame[MPT_DEFAULT_FRAME_SIZE]; /* persist reply */
 	LANPage0_t		 lan_cnfg_page0;
 	LANPage1_t		 lan_cnfg_page1;
 
@@ -682,23 +699,44 @@
 	int			 aen_event_read_flag; /* flag to indicate event log was read*/
 	u8			 FirstWhoInit;
 	u8			 upload_fw;	/* If set, do a fw upload */
-	u8			 reload_fw;	/* Force a FW Reload on next reset */
 	u8			 NBShiftFactor;  /* NB Shift Factor based on Block Size (Facts)  */
 	u8			 pad1[4];
 	u8			 DoneCtx;
 	u8			 TaskCtx;
 	u8			 InternalCtx;
-	spinlock_t		 initializing_hba_lock;
-	int 	 		 initializing_hba_lock_flag;
 	struct list_head	 list;
 	struct net_device	*netdev;
 	struct list_head	 sas_topology;
 	struct mutex		 sas_topology_mutex;
+
+	struct workqueue_struct	*fw_event_q;
+	struct list_head	 fw_event_list;
+	spinlock_t		 fw_event_lock;
+	u8			 fw_events_off; /* if '1', then ignore events */
+	char 			 fw_event_q_name[MPT_KOBJ_NAME_LEN];
+
 	struct mutex		 sas_discovery_mutex;
 	u8			 sas_discovery_runtime;
 	u8			 sas_discovery_ignore_events;
+
+	/* port_info object for the host */
+	struct mptsas_portinfo	*hba_port_info;
+	u64			 hba_port_sas_addr;
+	u16			 hba_port_num_phy;
+	struct list_head	 sas_device_info_list;
+	struct mutex		 sas_device_info_mutex;
+	u8			 old_sas_discovery_protocal;
+	u8			 sas_discovery_quiesce_io;
 	int			 sas_index; /* index refrencing */
-	MPT_SAS_MGMT		 sas_mgmt;
+	MPT_MGMT		 sas_mgmt;
+	MPT_MGMT		 mptbase_cmds; /* for sending config pages */
+	MPT_MGMT		 internal_cmds;
+	MPT_MGMT		 taskmgmt_cmds;
+	MPT_MGMT		 ioctl_cmds;
+	spinlock_t		 taskmgmt_lock; /* diagnostic reset lock */
+	int			 taskmgmt_in_progress;
+	u8			 taskmgmt_quiesce_io;
+	u8			 ioc_reset_in_progress;
 	struct work_struct	 sas_persist_task;
 
 	struct work_struct	 fc_setup_reset_work;
@@ -707,15 +745,27 @@
 	u8			 fc_link_speed[2];
 	spinlock_t		 fc_rescan_work_lock;
 	struct work_struct	 fc_rescan_work;
-	char			 fc_rescan_work_q_name[20];
+	char			 fc_rescan_work_q_name[MPT_KOBJ_NAME_LEN];
 	struct workqueue_struct *fc_rescan_work_q;
+
+	/* driver forced bus resets count */
+	unsigned long		  hard_resets;
+	/* fw/external bus resets count */
+	unsigned long		  soft_resets;
+	/* cmd timeouts */
+	unsigned long		  timeouts;
+
 	struct scsi_cmnd	**ScsiLookup;
 	spinlock_t		  scsi_lookup_lock;
-
-	char			 reset_work_q_name[20];
+	u64			dma_mask;
+	u32			  broadcast_aen_busy;
+	char			 reset_work_q_name[MPT_KOBJ_NAME_LEN];
 	struct workqueue_struct *reset_work_q;
 	struct delayed_work	 fault_reset_work;
-	spinlock_t		 fault_reset_work_lock;
+
+	u8			sg_addr_size;
+	u8			in_rescan;
+	u8			SGE_size;
 
 } MPT_ADAPTER;
 
@@ -753,13 +803,14 @@
 	dma_addr_t	Address;
 } MptSge_t;
 
-#define mpt_addr_size() \
-	((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SGE_FLAGS_64_BIT_ADDRESSING : \
-		MPI_SGE_FLAGS_32_BIT_ADDRESSING)
 
-#define mpt_msg_flags() \
-	((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \
-		MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32)
+#define mpt_msg_flags(ioc) \
+	(ioc->sg_addr_size == sizeof(u64)) ?		\
+	MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : 		\
+	MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32
+
+#define MPT_SGE_FLAGS_64_BIT_ADDRESSING \
+	(MPI_SGE_FLAGS_64_BIT_ADDRESSING << MPI_SGE_FLAGS_SHIFT)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -835,22 +886,14 @@
 		/* Pool of memory for holding SCpnts before doing
 		 * OS callbacks. freeQ is the free pool.
 		 */
-	u8			  tmPending;
-	u8			  resetPending;
 	u8			  negoNvram;		/* DV disabled, nego NVRAM */
 	u8			  pad1;
-	u8                        tmState;
 	u8			  rsvd[2];
 	MPT_FRAME_HDR		 *cmdPtr;		/* Ptr to nonOS request */
 	struct scsi_cmnd	 *abortSCpnt;
 	MPT_LOCAL_REPLY		  localReply;		/* internal cmd reply struct */
-	unsigned long		  hard_resets;		/* driver forced bus resets count */
-	unsigned long		  soft_resets;		/* fw/external bus resets count */
-	unsigned long		  timeouts;		/* cmd timeouts */
 	ushort			  sel_timeout[MPT_MAX_FC_DEVICES];
 	char 			  *info_kbuf;
-	wait_queue_head_t	  scandv_waitq;
-	int			  scandv_wait_done;
 	long			  last_queue_full;
 	u16			  tm_iocstatus;
 	u16			  spi_pending;
@@ -870,21 +913,16 @@
  * Generic structure passed to the base mpt_config function.
  */
 typedef struct _x_config_parms {
-	struct list_head	 linkage;	/* linked list */
-	struct timer_list	 timer;		/* timer function for this request  */
 	union {
 		ConfigExtendedPageHeader_t	*ehdr;
 		ConfigPageHeader_t	*hdr;
 	} cfghdr;
 	dma_addr_t		 physAddr;
-	int			 wait_done;	/* wait for this request */
 	u32			 pageAddr;	/* properly formatted */
+	u16			 status;
 	u8			 action;
 	u8			 dir;
 	u8			 timeout;	/* seconds */
-	u8			 pad1;
-	u16			 status;
-	u16			 pad2;
 } CONFIGPARMS;
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -909,7 +947,6 @@
 extern void	 mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
 extern void	 mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
 extern void	 mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
-extern void	 mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr);
 
 extern int	 mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag);
 extern int	 mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
@@ -922,6 +959,12 @@
 extern int	 mpt_findImVolumes(MPT_ADAPTER *ioc);
 extern int	 mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
 extern int	 mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk);
+extern int	mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
+		pRaidPhysDiskPage1_t phys_disk);
+extern int	mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc,
+		u8 phys_disk_num);
+extern int	 mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
+extern void	 mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
 extern void     mpt_halt_firmware(MPT_ADAPTER *ioc);
 
 
@@ -959,7 +1002,6 @@
 #define MPT_SGE_FLAGS_END_OF_BUFFER		(0x40000000)
 #define MPT_SGE_FLAGS_LOCAL_ADDRESS		(0x08000000)
 #define MPT_SGE_FLAGS_DIRECTION			(0x04000000)
-#define MPT_SGE_FLAGS_ADDRESSING		(mpt_addr_size() << MPI_SGE_FLAGS_SHIFT)
 #define MPT_SGE_FLAGS_END_OF_LIST		(0x01000000)
 
 #define MPT_SGE_FLAGS_TRANSACTION_ELEMENT	(0x00000000)
@@ -972,14 +1014,12 @@
 	 MPT_SGE_FLAGS_END_OF_BUFFER |	\
 	 MPT_SGE_FLAGS_END_OF_LIST |	\
 	 MPT_SGE_FLAGS_SIMPLE_ELEMENT |	\
-	 MPT_SGE_FLAGS_ADDRESSING | \
 	 MPT_TRANSFER_IOC_TO_HOST)
 #define MPT_SGE_FLAGS_SSIMPLE_WRITE \
 	(MPT_SGE_FLAGS_LAST_ELEMENT |	\
 	 MPT_SGE_FLAGS_END_OF_BUFFER |	\
 	 MPT_SGE_FLAGS_END_OF_LIST |	\
 	 MPT_SGE_FLAGS_SIMPLE_ELEMENT |	\
-	 MPT_SGE_FLAGS_ADDRESSING | \
 	 MPT_TRANSFER_HOST_TO_IOC)
 
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index c638171..9b2e219 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -84,6 +84,7 @@
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptctl_taskmgmt_id = MPT_MAX_PROTOCOL_DRIVERS;
 
 static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait );
 
@@ -127,10 +128,7 @@
 		struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
 static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma,
 		struct buflist *buflist, MPT_ADAPTER *ioc);
-static void mptctl_timeout_expired (MPT_IOCTL *ioctl);
-static int  mptctl_bus_reset(MPT_IOCTL *ioctl);
-static int mptctl_set_tm_flags(MPT_SCSI_HOST *hd);
-static void mptctl_free_tm_flags(MPT_ADAPTER *ioc);
+static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function);
 
 /*
  * Reset Handler cleanup function
@@ -183,10 +181,10 @@
 	int rc = 0;
 
 	if (nonblock) {
-		if (!mutex_trylock(&ioc->ioctl->ioctl_mutex))
+		if (!mutex_trylock(&ioc->ioctl_cmds.mutex))
 			rc = -EAGAIN;
 	} else {
-		if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex))
+		if (mutex_lock_interruptible(&ioc->ioctl_cmds.mutex))
 			rc = -ERESTARTSYS;
 	}
 	return rc;
@@ -202,99 +200,78 @@
 static int
 mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
 {
-	char *sense_data;
-	int sz, req_index;
-	u16 iocStatus;
-	u8 cmd;
+	char	*sense_data;
+	int	req_index;
+	int	sz;
 
-	if (req)
-		 cmd = req->u.hdr.Function;
-	else
-		return 1;
-	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tcompleting mpi function (0x%02X), req=%p, "
-	    "reply=%p\n", ioc->name,  req->u.hdr.Function, req, reply));
+	if (!req)
+		return 0;
 
-	if (ioc->ioctl) {
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "completing mpi function "
+	    "(0x%02X), req=%p, reply=%p\n", ioc->name,  req->u.hdr.Function,
+	    req, reply));
 
-		if (reply==NULL) {
+	/*
+	 * Handling continuation of the same reply. Processing the first
+	 * reply, and eating the other replys that come later.
+	 */
+	if (ioc->ioctl_cmds.msg_context != req->u.hdr.MsgContext)
+		goto out_continuation;
 
-			dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_reply() NULL Reply "
-				"Function=%x!\n", ioc->name, cmd));
+	ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
 
-			ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
-			ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
+	if (!reply)
+		goto out;
 
-			/* We are done, issue wake up
-	 		*/
-			ioc->ioctl->wait_done = 1;
-			wake_up (&mptctl_wait);
-			return 1;
+	ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+	sz = min(ioc->reply_sz, 4*reply->u.reply.MsgLength);
+	memcpy(ioc->ioctl_cmds.reply, reply, sz);
 
-		}
+	if (reply->u.reply.IOCStatus || reply->u.reply.IOCLogInfo)
+		dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "iocstatus (0x%04X), loginfo (0x%08X)\n", ioc->name,
+		    le16_to_cpu(reply->u.reply.IOCStatus),
+		    le32_to_cpu(reply->u.reply.IOCLogInfo)));
 
-		/* Copy the reply frame (which much exist
-		 * for non-SCSI I/O) to the IOC structure.
-		 */
-		memcpy(ioc->ioctl->ReplyFrame, reply,
-			min(ioc->reply_sz, 4*reply->u.reply.MsgLength));
-		ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID;
+	if ((req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+		(req->u.hdr.Function ==
+		 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
 
-		/* Set the command status to GOOD if IOC Status is GOOD
-		 * OR if SCSI I/O cmd and data underrun or recovered error.
-		 */
-		iocStatus = le16_to_cpu(reply->u.reply.IOCStatus) & MPI_IOCSTATUS_MASK;
-		if (iocStatus  == MPI_IOCSTATUS_SUCCESS)
-			ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
+		if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState)
+			dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+			"scsi_status (0x%02x), scsi_state (0x%02x), "
+			"tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name,
+			reply->u.sreply.SCSIStatus,
+			reply->u.sreply.SCSIState,
+			le16_to_cpu(reply->u.sreply.TaskTag),
+			le32_to_cpu(reply->u.sreply.TransferCount)));
 
-		if (iocStatus || reply->u.reply.IOCLogInfo)
-			dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tiocstatus (0x%04X), "
-				"loginfo (0x%08X)\n", ioc->name,
-				iocStatus,
-				le32_to_cpu(reply->u.reply.IOCLogInfo)));
-
-		if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
-			(cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
-
-			if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState)
-				dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-					"\tscsi_status (0x%02x), scsi_state (0x%02x), "
-					"tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name,
-					reply->u.sreply.SCSIStatus,
-					reply->u.sreply.SCSIState,
-					le16_to_cpu(reply->u.sreply.TaskTag),
-					le32_to_cpu(reply->u.sreply.TransferCount)));
-
-			ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
-
-			if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) ||
-			(iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) {
-			ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
-			}
-		}
-
-		/* Copy the sense data - if present
-		 */
-		if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) &&
-			(reply->u.sreply.SCSIState &
-			 MPI_SCSI_STATE_AUTOSENSE_VALID)){
+		if (reply->u.sreply.SCSIState &
+			MPI_SCSI_STATE_AUTOSENSE_VALID) {
 			sz = req->u.scsireq.SenseBufferLength;
 			req_index =
 			    le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
-			sense_data =
-			    ((u8 *)ioc->sense_buf_pool +
+			sense_data = ((u8 *)ioc->sense_buf_pool +
 			     (req_index * MPT_SENSE_BUFFER_ALLOC));
-			memcpy(ioc->ioctl->sense, sense_data, sz);
-			ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID;
+			memcpy(ioc->ioctl_cmds.sense, sense_data, sz);
+			ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_SENSE_VALID;
 		}
-
-		if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT)
-			mptctl_free_tm_flags(ioc);
-
-		/* We are done, issue wake up
-		 */
-		ioc->ioctl->wait_done = 1;
-		wake_up (&mptctl_wait);
 	}
+
+ out:
+	/* We are done, issue wake up
+	 */
+	if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
+		if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT)
+			mpt_clear_taskmgmt_in_progress_flag(ioc);
+		ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+		complete(&ioc->ioctl_cmds.done);
+	}
+
+ out_continuation:
+	if (reply && (reply->u.reply.MsgFlags &
+	    MPI_MSGFLAGS_CONTINUATION_REPLY))
+		return 0;
 	return 1;
 }
 
@@ -304,30 +281,66 @@
  * Expecting an interrupt, however timed out.
  *
  */
-static void mptctl_timeout_expired (MPT_IOCTL *ioctl)
+static void
+mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
 {
-	int rc = 1;
+	unsigned long flags;
 
-	if (ioctl == NULL)
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
+		ioc->name, __func__));
+
+	if (mpt_fwfault_debug)
+		mpt_halt_firmware(ioc);
+
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+	if (ioc->ioc_reset_in_progress) {
+		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+		CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
+		mpt_free_msg_frame(ioc, mf);
 		return;
-	dctlprintk(ioctl->ioc,
-		   printk(MYIOC_s_DEBUG_FMT ": Timeout Expired! Host %d\n",
-		   ioctl->ioc->name, ioctl->ioc->id));
-
-	ioctl->wait_done = 0;
-	if (ioctl->reset & MPTCTL_RESET_OK)
-		rc = mptctl_bus_reset(ioctl);
-
-	if (rc) {
-		/* Issue a reset for this device.
-		 * The IOC is not responding.
-		 */
-		dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
-			 ioctl->ioc->name));
-		mpt_HardResetHandler(ioctl->ioc, CAN_SLEEP);
 	}
-	return;
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 
+
+	if (!mptctl_bus_reset(ioc, mf->u.hdr.Function))
+		return;
+
+	/* Issue a reset for this device.
+	 * The IOC is not responding.
+	 */
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
+		 ioc->name));
+	CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
+	mpt_HardResetHandler(ioc, CAN_SLEEP);
+	mpt_free_msg_frame(ioc, mf);
+}
+
+static int
+mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+{
+	if (!mf)
+		return 0;
+
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		"TaskMgmt completed (mf=%p, mr=%p)\n",
+		ioc->name, mf, mr));
+
+	ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+
+	if (!mr)
+		goto out;
+
+	ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+	memcpy(ioc->taskmgmt_cmds.reply, mr,
+	    min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
+ out:
+	if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
+		mpt_clear_taskmgmt_in_progress_flag(ioc);
+		ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+		complete(&ioc->taskmgmt_cmds.done);
+		return 1;
+	}
+	return 0;
 }
 
 /* mptctl_bus_reset
@@ -335,133 +348,150 @@
  * Bus reset code.
  *
  */
-static int mptctl_bus_reset(MPT_IOCTL *ioctl)
+static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
 {
 	MPT_FRAME_HDR	*mf;
 	SCSITaskMgmt_t	*pScsiTm;
-	MPT_SCSI_HOST	*hd;
+	SCSITaskMgmtReply_t *pScsiTmReply;
 	int		 ii;
-	int		 retval=0;
+	int		 retval;
+	unsigned long	 timeout;
+	unsigned long	 time_count;
+	u16		 iocstatus;
 
-
-	ioctl->reset &= ~MPTCTL_RESET_OK;
-
-	if (ioctl->ioc->sh == NULL)
+	/* bus reset is only good for SCSI IO, RAID PASSTHRU */
+	if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) ||
+	    (function == MPI_FUNCTION_SCSI_IO_REQUEST)) {
+		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
+			"TaskMgmt, not SCSI_IO!!\n", ioc->name));
 		return -EPERM;
+	}
 
-	hd = shost_priv(ioctl->ioc->sh);
-	if (hd == NULL)
+	mutex_lock(&ioc->taskmgmt_cmds.mutex);
+	if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+		mutex_unlock(&ioc->taskmgmt_cmds.mutex);
 		return -EPERM;
+	}
 
-	/* Single threading ....
-	 */
-	if (mptctl_set_tm_flags(hd) != 0)
-		return -EPERM;
+	retval = 0;
 
 	/* Send request
 	 */
-	if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc)) == NULL) {
-		dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt, no msg frames!!\n",
-				ioctl->ioc->name));
-
-		mptctl_free_tm_flags(ioctl->ioc);
-		return -ENOMEM;
+	mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc);
+	if (mf == NULL) {
+		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
+			"TaskMgmt, no msg frames!!\n", ioc->name));
+		mpt_clear_taskmgmt_in_progress_flag(ioc);
+		retval = -ENOMEM;
+		goto mptctl_bus_reset_done;
 	}
 
-	dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
-			ioctl->ioc->name, mf));
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
+		ioc->name, mf));
 
 	pScsiTm = (SCSITaskMgmt_t *) mf;
-	pScsiTm->TargetID = ioctl->id;
-	pScsiTm->Bus = hd->port;	/* 0 */
-	pScsiTm->ChainOffset = 0;
+	memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
 	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
-	pScsiTm->Reserved = 0;
 	pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
-	pScsiTm->Reserved1 = 0;
 	pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
-
+	pScsiTm->TargetID = 0;
+	pScsiTm->Bus = 0;
+	pScsiTm->ChainOffset = 0;
+	pScsiTm->Reserved = 0;
+	pScsiTm->Reserved1 = 0;
+	pScsiTm->TaskMsgContext = 0;
 	for (ii= 0; ii < 8; ii++)
 		pScsiTm->LUN[ii] = 0;
-
 	for (ii=0; ii < 7; ii++)
 		pScsiTm->Reserved2[ii] = 0;
 
-	pScsiTm->TaskMsgContext = 0;
-	dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT
-		"mptctl_bus_reset: issued.\n", ioctl->ioc->name));
+	switch (ioc->bus_type) {
+	case FC:
+		timeout = 40;
+		break;
+	case SAS:
+		timeout = 30;
+		break;
+	case SPI:
+	default:
+		timeout = 2;
+		break;
+	}
 
-	DBG_DUMP_TM_REQUEST_FRAME(ioctl->ioc, (u32 *)mf);
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		"TaskMgmt type=%d timeout=%ld\n",
+		ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout));
 
-	ioctl->wait_done=0;
-
-	if ((ioctl->ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
-	    (ioctl->ioc->facts.MsgVersion >= MPI_VERSION_01_05))
-		mpt_put_msg_frame_hi_pri(mptctl_id, ioctl->ioc, mf);
+	INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+	time_count = jiffies;
+	if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+	    (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+		mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf);
 	else {
-		retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
-			sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+		retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc,
+		    sizeof(SCSITaskMgmt_t), (u32 *)pScsiTm, CAN_SLEEP);
 		if (retval != 0) {
-			dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
-				" (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
-				hd->ioc, mf));
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+				"TaskMgmt send_handshake FAILED!"
+				" (ioc %p, mf %p, rc=%d) \n", ioc->name,
+				ioc, mf, retval));
+			mpt_clear_taskmgmt_in_progress_flag(ioc);
 			goto mptctl_bus_reset_done;
 		}
 	}
 
 	/* Now wait for the command to complete */
-	ii = wait_event_timeout(mptctl_wait,
-	     ioctl->wait_done == 1,
-	     HZ*5 /* 5 second timeout */);
+	ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
+	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "TaskMgmt failed\n", ioc->name));
+		mpt_free_msg_frame(ioc, mf);
+		mpt_clear_taskmgmt_in_progress_flag(ioc);
+		if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+			retval = 0;
+		else
+			retval = -1; /* return failure */
+		goto mptctl_bus_reset_done;
+	}
 
-	if(ii <=0 && (ioctl->wait_done != 1 ))  {
-		mpt_free_msg_frame(hd->ioc, mf);
-		ioctl->wait_done = 0;
+	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "TaskMgmt failed\n", ioc->name));
+		retval = -1; /* return failure */
+		goto mptctl_bus_reset_done;
+	}
+
+	pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+	    "TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, "
+	    "iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, "
+	    "term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus,
+	    pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+	    le16_to_cpu(pScsiTmReply->IOCStatus),
+	    le32_to_cpu(pScsiTmReply->IOCLogInfo),
+	    pScsiTmReply->ResponseCode,
+	    le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+	iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+	if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
+	   iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED ||
+	   iocstatus == MPI_IOCSTATUS_SUCCESS)
+		retval = 0;
+	else {
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "TaskMgmt failed\n", ioc->name));
 		retval = -1; /* return failure */
 	}
 
-mptctl_bus_reset_done:
 
-	mptctl_free_tm_flags(ioctl->ioc);
+ mptctl_bus_reset_done:
+	mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
 	return retval;
 }
 
-static int
-mptctl_set_tm_flags(MPT_SCSI_HOST *hd) {
-	unsigned long flags;
-
-	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-
-	if (hd->tmState == TM_STATE_NONE) {
-		hd->tmState = TM_STATE_IN_PROGRESS;
-		hd->tmPending = 1;
-		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-	} else {
-		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-static void
-mptctl_free_tm_flags(MPT_ADAPTER *ioc)
-{
-	MPT_SCSI_HOST * hd;
-	unsigned long flags;
-
-	hd = shost_priv(ioc->sh);
-	if (hd == NULL)
-		return;
-
-	spin_lock_irqsave(&ioc->FreeQlock, flags);
-
-	hd->tmState = TM_STATE_NONE;
-	hd->tmPending = 0;
-	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-	return;
-}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* mptctl_ioc_reset
@@ -473,22 +503,23 @@
 static int
 mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
-	MPT_IOCTL *ioctl = ioc->ioctl;
-	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC %s_reset routed to IOCTL driver!\n", ioc->name,
-		reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
-		reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
-
-	if(ioctl == NULL)
-		return 1;
-
 	switch(reset_phase) {
 	case MPT_IOC_SETUP_RESET:
-		ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET;
-		break;
-	case MPT_IOC_POST_RESET:
-		ioctl->status &= ~MPT_IOCTL_STATUS_DID_IOCRESET;
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
 		break;
 	case MPT_IOC_PRE_RESET:
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
+		break;
+	case MPT_IOC_POST_RESET:
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
+		if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
+			ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET;
+			complete(&ioc->ioctl_cmds.done);
+		}
+		break;
 	default:
 		break;
 	}
@@ -642,7 +673,7 @@
 	else
 		ret = -EINVAL;
 
-	mutex_unlock(&iocp->ioctl->ioctl_mutex);
+	mutex_unlock(&iocp->ioctl_cmds.mutex);
 
 	return ret;
 }
@@ -758,6 +789,7 @@
 	int			 sge_offset = 0;
 	u16			 iocstat;
 	pFWDownloadReply_t	 ReplyMsg = NULL;
+	unsigned long		 timeleft;
 
 	if (mpt_verify_adapter(ioc, &iocp) < 0) {
 		printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n",
@@ -841,8 +873,9 @@
 	 *	96		8
 	 *	64		4
 	 */
-	maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t))
-			/ (sizeof(dma_addr_t) + sizeof(u32));
+	maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) -
+			sizeof(FWDownloadTCSGE_t))
+			/ iocp->SGE_size;
 	if (numfrags > maxfrags) {
 		ret = -EMLINK;
 		goto fwdl_out;
@@ -870,7 +903,7 @@
 		if (nib == 0 || nib == 3) {
 			;
 		} else if (sgIn->Address) {
-			mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
+			iocp->add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
 			n++;
 			if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
 				printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - "
@@ -882,7 +915,7 @@
 		}
 		sgIn++;
 		bl++;
-		sgOut += (sizeof(dma_addr_t) + sizeof(u32));
+		sgOut += iocp->SGE_size;
 	}
 
 	DBG_DUMP_FW_DOWNLOAD(iocp, (u32 *)mf, numfrags);
@@ -891,16 +924,30 @@
 	 * Finally, perform firmware download.
 	 */
 	ReplyMsg = NULL;
+	SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, dlmsg->MsgContext);
+	INITIALIZE_MGMT_STATUS(iocp->ioctl_cmds.status)
 	mpt_put_msg_frame(mptctl_id, iocp, mf);
 
 	/* Now wait for the command to complete */
-	ret = wait_event_timeout(mptctl_wait,
-	     iocp->ioctl->wait_done == 1,
-	     HZ*60);
+retry_wait:
+	timeleft = wait_for_completion_timeout(&iocp->ioctl_cmds.done, HZ*60);
+	if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+		ret = -ETIME;
+		printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__);
+		if (iocp->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+			mpt_free_msg_frame(iocp, mf);
+			goto fwdl_out;
+		}
+		if (!timeleft)
+			mptctl_timeout_expired(iocp, mf);
+		else
+			goto retry_wait;
+		goto fwdl_out;
+	}
 
-	if(ret <=0 && (iocp->ioctl->wait_done != 1 )) {
-	/* Now we need to reset the board */
-		mptctl_timeout_expired(iocp->ioctl);
+	if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+		printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__);
+		mpt_free_msg_frame(iocp, mf);
 		ret = -ENODATA;
 		goto fwdl_out;
 	}
@@ -908,7 +955,7 @@
 	if (sgl)
 		kfree_sgl(sgl, sgl_dma, buflist, iocp);
 
-	ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame;
+	ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply;
 	iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
 	if (iocstat == MPI_IOCSTATUS_SUCCESS) {
 		printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name);
@@ -932,6 +979,9 @@
 	return 0;
 
 fwdl_out:
+
+	CLEAR_MGMT_STATUS(iocp->ioctl_cmds.status);
+	SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, 0);
         kfree_sgl(sgl, sgl_dma, buflist, iocp);
 	return ret;
 }
@@ -1003,7 +1053,7 @@
 	 *
 	 */
 	sgl = sglbuf;
-	sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1;
+	sg_spill = ((ioc->req_sz - sge_offset)/ioc->SGE_size) - 1;
 	while (bytes_allocd < bytes) {
 		this_alloc = min(alloc_sz, bytes-bytes_allocd);
 		buflist[buflist_ent].len = this_alloc;
@@ -1024,8 +1074,9 @@
 			dma_addr_t dma_addr;
 
 			bytes_allocd += this_alloc;
-			sgl->FlagsLength = (0x10000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|this_alloc);
-			dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir);
+			sgl->FlagsLength = (0x10000000|sgdir|this_alloc);
+			dma_addr = pci_map_single(ioc->pcidev,
+				buflist[buflist_ent].kptr, this_alloc, dir);
 			sgl->Address = dma_addr;
 
 			fragcnt++;
@@ -1771,7 +1822,10 @@
 	int		msgContext;
 	u16		req_idx;
 	ulong 		timeout;
+	unsigned long	timeleft;
 	struct scsi_device *sdev;
+	unsigned long	 flags;
+	u8		 function;
 
 	/* bufIn and bufOut are used for user to kernel space transfers
 	 */
@@ -1784,24 +1838,23 @@
 				__FILE__, __LINE__, iocnum);
 		return -ENODEV;
 	}
-	if (!ioc->ioctl) {
+
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+	if (ioc->ioc_reset_in_progress) {
+		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 		printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
-			"No memory available during driver init.\n",
-				__FILE__, __LINE__);
-		return -ENOMEM;
-	} else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
-		printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
-			"Busy with IOC Reset \n", __FILE__, __LINE__);
+			"Busy with diagnostic reset\n", __FILE__, __LINE__);
 		return -EBUSY;
 	}
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 
 	/* Verify that the final request frame will not be too large.
 	 */
 	sz = karg.dataSgeOffset * 4;
 	if (karg.dataInSize > 0)
-		sz += sizeof(dma_addr_t) + sizeof(u32);
+		sz += ioc->SGE_size;
 	if (karg.dataOutSize > 0)
-		sz += sizeof(dma_addr_t) + sizeof(u32);
+		sz += ioc->SGE_size;
 
 	if (sz > ioc->req_sz) {
 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
@@ -1827,10 +1880,12 @@
 		printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
 			"Unable to read MF from mpt_ioctl_command struct @ %p\n",
 			ioc->name, __FILE__, __LINE__, mfPtr);
+		function = -1;
 		rc = -EFAULT;
 		goto done_free_mem;
 	}
 	hdr->MsgContext = cpu_to_le32(msgContext);
+	function = hdr->Function;
 
 
 	/* Verify that this request is allowed.
@@ -1838,7 +1893,7 @@
 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n",
 	    ioc->name, hdr->Function, mf));
 
-	switch (hdr->Function) {
+	switch (function) {
 	case MPI_FUNCTION_IOC_FACTS:
 	case MPI_FUNCTION_PORT_FACTS:
 		karg.dataOutSize  = karg.dataInSize = 0;
@@ -1893,7 +1948,7 @@
 			}
 
 			pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
-			pScsiReq->MsgFlags |= mpt_msg_flags();
+			pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
 
 
 			/* verify that app has not requested
@@ -1935,8 +1990,6 @@
 			pScsiReq->Control = cpu_to_le32(scsidir | qtag);
 			pScsiReq->DataLength = cpu_to_le32(dataSize);
 
-			ioc->ioctl->reset = MPTCTL_RESET_OK;
-			ioc->ioctl->id = pScsiReq->TargetID;
 
 		} else {
 			printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
@@ -1979,7 +2032,7 @@
 			int dataSize;
 
 			pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
-			pScsiReq->MsgFlags |= mpt_msg_flags();
+			pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
 
 
 			/* verify that app has not requested
@@ -2014,8 +2067,6 @@
 			pScsiReq->Control = cpu_to_le32(scsidir | qtag);
 			pScsiReq->DataLength = cpu_to_le32(dataSize);
 
-			ioc->ioctl->reset = MPTCTL_RESET_OK;
-			ioc->ioctl->id = pScsiReq->TargetID;
 		} else {
 			printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
 				"SCSI driver is not loaded. \n",
@@ -2026,20 +2077,17 @@
 		break;
 
 	case MPI_FUNCTION_SCSI_TASK_MGMT:
-		{
-			MPT_SCSI_HOST *hd = NULL;
-			if ((ioc->sh == NULL) || ((hd = shost_priv(ioc->sh)) == NULL)) {
-				printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
-					"SCSI driver not loaded or SCSI host not found. \n",
-					ioc->name, __FILE__, __LINE__);
-				rc = -EFAULT;
-				goto done_free_mem;
-			} else if (mptctl_set_tm_flags(hd) != 0) {
-				rc = -EPERM;
-				goto done_free_mem;
-			}
-		}
+	{
+		SCSITaskMgmt_t	*pScsiTm;
+		pScsiTm = (SCSITaskMgmt_t *)mf;
+		dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+			"\tTaskType=0x%x MsgFlags=0x%x "
+			"TaskMsgContext=0x%x id=%d channel=%d\n",
+			ioc->name, pScsiTm->TaskType, le32_to_cpu
+			(pScsiTm->TaskMsgContext), pScsiTm->MsgFlags,
+			pScsiTm->TargetID, pScsiTm->Bus));
 		break;
+	}
 
 	case MPI_FUNCTION_IOC_INIT:
 		{
@@ -2123,8 +2171,7 @@
 			if (karg.dataInSize > 0) {
 				flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
 						MPI_SGE_FLAGS_END_OF_BUFFER |
-						MPI_SGE_FLAGS_DIRECTION |
-						mpt_addr_size() )
+						MPI_SGE_FLAGS_DIRECTION)
 						<< MPI_SGE_FLAGS_SHIFT;
 			} else {
 				flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
@@ -2141,8 +2188,8 @@
 				/* Set up this SGE.
 				 * Copy to MF and to sglbuf
 				 */
-				mpt_add_sge(psge, flagsLength, dma_addr_out);
-				psge += (sizeof(u32) + sizeof(dma_addr_t));
+				ioc->add_sge(psge, flagsLength, dma_addr_out);
+				psge += ioc->SGE_size;
 
 				/* Copy user data to kernel space.
 				 */
@@ -2175,18 +2222,25 @@
 				/* Set up this SGE
 				 * Copy to MF and to sglbuf
 				 */
-				mpt_add_sge(psge, flagsLength, dma_addr_in);
+				ioc->add_sge(psge, flagsLength, dma_addr_in);
 			}
 		}
 	} else  {
 		/* Add a NULL SGE
 		 */
-		mpt_add_sge(psge, flagsLength, (dma_addr_t) -1);
+		ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
 	}
 
-	ioc->ioctl->wait_done = 0;
+	SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, hdr->MsgContext);
+	INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
 	if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
 
+		mutex_lock(&ioc->taskmgmt_cmds.mutex);
+		if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+			mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+			goto done_free_mem;
+		}
+
 		DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
 
 		if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
@@ -2197,10 +2251,11 @@
 				sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
 			if (rc != 0) {
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-				    "_send_handshake FAILED! (ioc %p, mf %p)\n",
+				    "send_handshake FAILED! (ioc %p, mf %p)\n",
 				    ioc->name, ioc, mf));
-				mptctl_free_tm_flags(ioc);
+				mpt_clear_taskmgmt_in_progress_flag(ioc);
 				rc = -ENODATA;
+				mutex_unlock(&ioc->taskmgmt_cmds.mutex);
 				goto done_free_mem;
 			}
 		}
@@ -2210,36 +2265,47 @@
 
 	/* Now wait for the command to complete */
 	timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT;
-	timeout = wait_event_timeout(mptctl_wait,
-	     ioc->ioctl->wait_done == 1,
-	     HZ*timeout);
-
-	if(timeout <=0 && (ioc->ioctl->wait_done != 1 )) {
-	/* Now we need to reset the board */
-
-		if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT)
-			mptctl_free_tm_flags(ioc);
-
-		mptctl_timeout_expired(ioc->ioctl);
-		rc = -ENODATA;
+retry_wait:
+	timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
+				HZ*timeout);
+	if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+		rc = -ETIME;
+		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: TIMED OUT!\n",
+		    ioc->name, __func__));
+		if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+			if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
+				mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+			goto done_free_mem;
+		}
+		if (!timeleft) {
+			if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
+				mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+			mptctl_timeout_expired(ioc, mf);
+			mf = NULL;
+		} else
+			goto retry_wait;
 		goto done_free_mem;
 	}
 
+	if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
+		mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+
+
 	mf = NULL;
 
 	/* If a valid reply frame, copy to the user.
 	 * Offset 2: reply length in U32's
 	 */
-	if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) {
+	if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
 		if (karg.maxReplyBytes < ioc->reply_sz) {
-			 sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]);
+			sz = min(karg.maxReplyBytes,
+				4*ioc->ioctl_cmds.reply[2]);
 		} else {
-			 sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]);
+			 sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]);
 		}
-
 		if (sz > 0) {
 			if (copy_to_user(karg.replyFrameBufPtr,
-				 &ioc->ioctl->ReplyFrame, sz)){
+				 ioc->ioctl_cmds.reply, sz)){
 				 printk(MYIOC_s_ERR_FMT
 				     "%s@%d::mptctl_do_mpt_command - "
 				 "Unable to write out reply frame %p\n",
@@ -2252,10 +2318,11 @@
 
 	/* If valid sense data, copy to user.
 	 */
-	if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) {
+	if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_SENSE_VALID) {
 		sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
 		if (sz > 0) {
-			if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) {
+			if (copy_to_user(karg.senseDataPtr,
+				ioc->ioctl_cmds.sense, sz)) {
 				printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
 				"Unable to write sense data to user %p\n",
 				ioc->name, __FILE__, __LINE__,
@@ -2269,7 +2336,7 @@
 	/* If the overall status is _GOOD and data in, copy data
 	 * to user.
 	 */
-	if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) &&
+	if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD) &&
 				(karg.dataInSize > 0) && (bufIn.kptr)) {
 
 		if (copy_to_user(karg.dataInBufPtr,
@@ -2284,9 +2351,8 @@
 
 done_free_mem:
 
-	ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_COMMAND_GOOD |
-		MPT_IOCTL_STATUS_SENSE_VALID |
-		MPT_IOCTL_STATUS_RF_VALID );
+	CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
+	SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
 
 	/* Free the allocated memory.
 	 */
@@ -2336,6 +2402,8 @@
 	ToolboxIstwiReadWriteRequest_t	*IstwiRWRequest;
 	MPT_FRAME_HDR		*mf = NULL;
 	MPIHeader_t		*mpi_hdr;
+	unsigned long		timeleft;
+	int			retval;
 
 	/* Reset long to int. Should affect IA64 and SPARC only
 	 */
@@ -2466,9 +2534,9 @@
 		MPT_SCSI_HOST *hd =  shost_priv(ioc->sh);
 
 		if (hd && (cim_rev == 1)) {
-			karg.hard_resets = hd->hard_resets;
-			karg.soft_resets = hd->soft_resets;
-			karg.timeouts = hd->timeouts;
+			karg.hard_resets = ioc->hard_resets;
+			karg.soft_resets = ioc->soft_resets;
+			karg.timeouts = ioc->timeouts;
 		}
 	}
 
@@ -2476,8 +2544,8 @@
 	 * Gather ISTWI(Industry Standard Two Wire Interface) Data
 	 */
 	if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
-		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
-		    ioc->name,__func__));
+		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
+			"%s, no msg frames!!\n", ioc->name, __func__));
 		goto out;
 	}
 
@@ -2498,22 +2566,29 @@
 	pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma);
 	if (!pbuf)
 		goto out;
-	mpt_add_sge((char *)&IstwiRWRequest->SGL,
+	ioc->add_sge((char *)&IstwiRWRequest->SGL,
 	    (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma);
 
-	ioc->ioctl->wait_done = 0;
+	retval = 0;
+	SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
+				IstwiRWRequest->MsgContext);
+	INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
 	mpt_put_msg_frame(mptctl_id, ioc, mf);
 
-	rc = wait_event_timeout(mptctl_wait,
-	     ioc->ioctl->wait_done == 1,
-	     HZ*MPT_IOCTL_DEFAULT_TIMEOUT /* 10 sec */);
-
-	if(rc <=0 && (ioc->ioctl->wait_done != 1 )) {
-		/*
-		 * Now we need to reset the board
-		 */
-		mpt_free_msg_frame(ioc, mf);
-		mptctl_timeout_expired(ioc->ioctl);
+retry_wait:
+	timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
+			HZ*MPT_IOCTL_DEFAULT_TIMEOUT);
+	if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+		retval = -ETIME;
+		printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __func__);
+		if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+			mpt_free_msg_frame(ioc, mf);
+			goto out;
+		}
+		if (!timeleft)
+			mptctl_timeout_expired(ioc, mf);
+		else
+			goto retry_wait;
 		goto out;
 	}
 
@@ -2526,10 +2601,13 @@
 	 *   bays have drives in them
 	 * pbuf[3] = Checksum (0x100 = (byte0 + byte2 + byte3)
 	 */
-	if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID)
+	if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)
 		karg.rsvd = *(u32 *)pbuf;
 
  out:
+	CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
+	SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
+
 	if (pbuf)
 		pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma);
 
@@ -2753,7 +2831,7 @@
 
 	ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
 
-	mutex_unlock(&iocp->ioctl->ioctl_mutex);
+	mutex_unlock(&iocp->ioctl_cmds.mutex);
 
 	return ret;
 }
@@ -2807,7 +2885,7 @@
 	 */
 	ret = mptctl_do_mpt_command (karg, &uarg->MF);
 
-	mutex_unlock(&iocp->ioctl->ioctl_mutex);
+	mutex_unlock(&iocp->ioctl_cmds.mutex);
 
 	return ret;
 }
@@ -2859,21 +2937,10 @@
 static int
 mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-	MPT_IOCTL *mem;
 	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
 
-	/*
-	 * Allocate and inite a MPT_IOCTL structure
-	*/
-	mem = kzalloc(sizeof(MPT_IOCTL), GFP_KERNEL);
-	if (!mem) {
-		mptctl_remove(pdev);
-		return -ENOMEM;
-	}
-
-	ioc->ioctl = mem;
-	ioc->ioctl->ioc = ioc;
-	mutex_init(&ioc->ioctl->ioctl_mutex);
+	mutex_init(&ioc->ioctl_cmds.mutex);
+	init_completion(&ioc->ioctl_cmds.done);
 	return 0;
 }
 
@@ -2887,9 +2954,6 @@
 static void
 mptctl_remove(struct pci_dev *pdev)
 {
-	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
-
-	kfree ( ioc->ioctl );
 }
 
 static struct mpt_pci_driver mptctl_driver = {
@@ -2929,6 +2993,7 @@
 		goto out_fail;
 	}
 
+	mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER);
 	mpt_reset_register(mptctl_id, mptctl_ioc_reset);
 	mpt_event_register(mptctl_id, mptctl_event_process);
 
@@ -2953,6 +3018,7 @@
 
 	/* De-register callback handler from base module */
 	mpt_deregister(mptctl_id);
+	mpt_reset_deregister(mptctl_taskmgmt_id);
 
         mpt_device_driver_deregister(MPTCTL_DRIVER);
 
diff --git a/drivers/message/fusion/mptdebug.h b/drivers/message/fusion/mptdebug.h
index 510b9f4..28e4788 100644
--- a/drivers/message/fusion/mptdebug.h
+++ b/drivers/message/fusion/mptdebug.h
@@ -58,6 +58,7 @@
 #define MPT_DEBUG_FC			0x00080000
 #define MPT_DEBUG_SAS			0x00100000
 #define MPT_DEBUG_SAS_WIDE		0x00200000
+#define MPT_DEBUG_36GB_MEM              0x00400000
 
 /*
  * CONFIG_FUSION_LOGGING - enabled in Kconfig
@@ -135,6 +136,8 @@
 #define dsaswideprintk(IOC, CMD)		\
 	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE)
 
+#define d36memprintk(IOC, CMD)		\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_36GB_MEM)
 
 
 /*
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index c3c24fd..e61df13 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -1251,17 +1251,15 @@
 	 * A slightly different algorithm is required for
 	 * 64bit SGEs.
 	 */
-	scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
-	if (sizeof(dma_addr_t) == sizeof(u64)) {
+	scale = ioc->req_sz/ioc->SGE_size;
+	if (ioc->sg_addr_size == sizeof(u64)) {
 		numSGE = (scale - 1) *
 		  (ioc->facts.MaxChainDepth-1) + scale +
-		  (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
-		  sizeof(u32));
+		  (ioc->req_sz - 60) / ioc->SGE_size;
 	} else {
 		numSGE = 1 + (scale - 1) *
 		  (ioc->facts.MaxChainDepth-1) + scale +
-		  (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
-		  sizeof(u32));
+		  (ioc->req_sz - 64) / ioc->SGE_size;
 	}
 
 	if (numSGE < sh->sg_tablesize) {
@@ -1292,9 +1290,6 @@
 
 	/* Clear the TM flags
 	 */
-	hd->tmPending = 0;
-	hd->tmState = TM_STATE_NONE;
-	hd->resetPending = 0;
 	hd->abortSCpnt = NULL;
 
 	/* Clear the pointer used to store
@@ -1312,8 +1307,6 @@
 	hd->timer.data = (unsigned long) hd;
 	hd->timer.function = mptscsih_timer_expired;
 
-	init_waitqueue_head(&hd->scandv_waitq);
-	hd->scandv_wait_done = 0;
 	hd->last_queue_full = 0;
 
 	sh->transportt = mptfc_transport_template;
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 79f5433..20e0b44 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -93,8 +93,37 @@
 static u8	mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
 static u8	mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
 static u8	mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8	mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
 
-static void mptsas_hotplug_work(struct work_struct *work);
+static void mptsas_firmware_event_work(struct work_struct *work);
+static void mptsas_send_sas_event(struct fw_event_work *fw_event);
+static void mptsas_send_raid_event(struct fw_event_work *fw_event);
+static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
+static void mptsas_parse_device_info(struct sas_identify *identify,
+		struct mptsas_devinfo *device_info);
+static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
+		struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
+static struct mptsas_phyinfo	*mptsas_find_phyinfo_by_sas_address
+		(MPT_ADAPTER *ioc, u64 sas_address);
+static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
+	struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
+static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
+	struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
+static int mptsas_add_end_device(MPT_ADAPTER *ioc,
+	struct mptsas_phyinfo *phy_info);
+static void mptsas_del_end_device(MPT_ADAPTER *ioc,
+	struct mptsas_phyinfo *phy_info);
+static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
+static struct mptsas_portinfo	*mptsas_find_portinfo_by_sas_address
+		(MPT_ADAPTER *ioc, u64 sas_address);
+static void mptsas_expander_delete(MPT_ADAPTER *ioc,
+		struct mptsas_portinfo *port_info, u8 force);
+static void mptsas_send_expander_event(struct fw_event_work *fw_event);
+static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
+static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
+static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
+static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
+static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
 
 static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
 					MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
@@ -218,6 +247,115 @@
 	    le16_to_cpu(pg1->AttachedDevHandle)));
 }
 
+/* inhibit sas firmware event handling */
+static void
+mptsas_fw_event_off(MPT_ADAPTER *ioc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioc->fw_event_lock, flags);
+	ioc->fw_events_off = 1;
+	ioc->sas_discovery_quiesce_io = 0;
+	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+
+}
+
+/* enable sas firmware event handling */
+static void
+mptsas_fw_event_on(MPT_ADAPTER *ioc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioc->fw_event_lock, flags);
+	ioc->fw_events_off = 0;
+	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+}
+
+/* queue a sas firmware event */
+static void
+mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
+    unsigned long delay)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioc->fw_event_lock, flags);
+	list_add_tail(&fw_event->list, &ioc->fw_event_list);
+	INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
+	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
+	    ioc->name, __func__, fw_event));
+	queue_delayed_work(ioc->fw_event_q, &fw_event->work,
+	    delay);
+	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+}
+
+/* requeue a sas firmware event */
+static void
+mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
+    unsigned long delay)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&ioc->fw_event_lock, flags);
+	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
+	    "(fw_event=0x%p)\n", ioc->name, __func__, fw_event));
+	fw_event->retries++;
+	queue_delayed_work(ioc->fw_event_q, &fw_event->work,
+	    msecs_to_jiffies(delay));
+	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+}
+
+/* free memory assoicated to a sas firmware event */
+static void
+mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioc->fw_event_lock, flags);
+	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
+	    ioc->name, __func__, fw_event));
+	list_del(&fw_event->list);
+	kfree(fw_event);
+	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+}
+
+/* walk the firmware event queue, and either stop or wait for
+ * outstanding events to complete */
+static void
+mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
+{
+	struct fw_event_work *fw_event, *next;
+	struct mptsas_target_reset_event *target_reset_list, *n;
+	u8	flush_q;
+	MPT_SCSI_HOST	*hd = shost_priv(ioc->sh);
+
+	/* flush the target_reset_list */
+	if (!list_empty(&hd->target_reset_list)) {
+		list_for_each_entry_safe(target_reset_list, n,
+		    &hd->target_reset_list, list) {
+			dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+			    "%s: removing target reset for id=%d\n",
+			    ioc->name, __func__,
+			   target_reset_list->sas_event_data.TargetID));
+			list_del(&target_reset_list->list);
+			kfree(target_reset_list);
+		}
+	}
+
+	if (list_empty(&ioc->fw_event_list) ||
+	     !ioc->fw_event_q || in_interrupt())
+		return;
+
+	flush_q = 0;
+	list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
+		if (cancel_delayed_work(&fw_event->work))
+			mptsas_free_fw_event(ioc, fw_event);
+		else
+			flush_q = 1;
+	}
+	if (flush_q)
+		flush_workqueue(ioc->fw_event_q);
+}
+
+
 static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
 {
 	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
@@ -230,20 +368,6 @@
 	return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
 }
 
-static struct mptsas_portinfo *
-mptsas_get_hba_portinfo(MPT_ADAPTER *ioc)
-{
-	struct list_head	*head = &ioc->sas_topology;
-	struct mptsas_portinfo	*pi = NULL;
-
-	/* always the first entry on sas_topology list */
-
-	if (!list_empty(head))
-		pi = list_entry(head->next, struct mptsas_portinfo, list);
-
-	return pi;
-}
-
 /*
  * mptsas_find_portinfo_by_handle
  *
@@ -265,6 +389,38 @@
 	return rc;
 }
 
+/**
+ *	mptsas_find_portinfo_by_sas_address -
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@handle:
+ *
+ *	This function should be called with the sas_topology_mutex already held
+ *
+ **/
+static struct mptsas_portinfo *
+mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
+{
+	struct mptsas_portinfo *port_info, *rc = NULL;
+	int i;
+
+	if (sas_address >= ioc->hba_port_sas_addr &&
+	    sas_address < (ioc->hba_port_sas_addr +
+	    ioc->hba_port_num_phy))
+		return ioc->hba_port_info;
+
+	mutex_lock(&ioc->sas_topology_mutex);
+	list_for_each_entry(port_info, &ioc->sas_topology, list)
+		for (i = 0; i < port_info->num_phys; i++)
+			if (port_info->phy_info[i].identify.sas_address ==
+			    sas_address) {
+				rc = port_info;
+				goto out;
+			}
+ out:
+	mutex_unlock(&ioc->sas_topology_mutex);
+	return rc;
+}
+
 /*
  * Returns true if there is a scsi end device
  */
@@ -308,6 +464,7 @@
 		if(phy_info->port_details != port_details)
 			continue;
 		memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
+		mptsas_set_rphy(ioc, phy_info, NULL);
 		phy_info->port_details = NULL;
 	}
 	kfree(port_details);
@@ -379,6 +536,285 @@
 		phy_info->port_details->starget = starget;
 }
 
+/**
+ *	mptsas_add_device_component -
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@channel: fw mapped id's
+ *	@id:
+ *	@sas_address:
+ *	@device_info:
+ *
+ **/
+static void
+mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
+	u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
+{
+	struct mptsas_device_info	*sas_info, *next;
+	struct scsi_device	*sdev;
+	struct scsi_target	*starget;
+	struct sas_rphy	*rphy;
+
+	/*
+	 * Delete all matching devices out of the list
+	 */
+	mutex_lock(&ioc->sas_device_info_mutex);
+	list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
+	    list) {
+		if (!sas_info->is_logical_volume &&
+		    (sas_info->sas_address == sas_address ||
+		    (sas_info->fw.channel == channel &&
+		     sas_info->fw.id == id))) {
+			list_del(&sas_info->list);
+			kfree(sas_info);
+		}
+	}
+
+	sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
+	if (!sas_info)
+		goto out;
+
+	/*
+	 * Set Firmware mapping
+	 */
+	sas_info->fw.id = id;
+	sas_info->fw.channel = channel;
+
+	sas_info->sas_address = sas_address;
+	sas_info->device_info = device_info;
+	sas_info->slot = slot;
+	sas_info->enclosure_logical_id = enclosure_logical_id;
+	INIT_LIST_HEAD(&sas_info->list);
+	list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
+
+	/*
+	 * Set OS mapping
+	 */
+	shost_for_each_device(sdev, ioc->sh) {
+		starget = scsi_target(sdev);
+		rphy = dev_to_rphy(starget->dev.parent);
+		if (rphy->identify.sas_address == sas_address) {
+			sas_info->os.id = starget->id;
+			sas_info->os.channel = starget->channel;
+		}
+	}
+
+ out:
+	mutex_unlock(&ioc->sas_device_info_mutex);
+	return;
+}
+
+/**
+ *	mptsas_add_device_component_by_fw -
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@channel:  fw mapped id's
+ *	@id:
+ *
+ **/
+static void
+mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+	struct mptsas_devinfo sas_device;
+	struct mptsas_enclosure enclosure_info;
+	int rc;
+
+	rc = mptsas_sas_device_pg0(ioc, &sas_device,
+	    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+	     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+	    (channel << 8) + id);
+	if (rc)
+		return;
+
+	memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
+	mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
+	    (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
+	     MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
+	     sas_device.handle_enclosure);
+
+	mptsas_add_device_component(ioc, sas_device.channel,
+	    sas_device.id, sas_device.sas_address, sas_device.device_info,
+	    sas_device.slot, enclosure_info.enclosure_logical_id);
+}
+
+/**
+ *	mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@channel: fw mapped id's
+ *	@id:
+ *
+ **/
+static void
+mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
+		struct scsi_target *starget)
+{
+	CONFIGPARMS			cfg;
+	ConfigPageHeader_t		hdr;
+	dma_addr_t			dma_handle;
+	pRaidVolumePage0_t		buffer = NULL;
+	int				i;
+	RaidPhysDiskPage0_t 		phys_disk;
+	struct mptsas_device_info	*sas_info, *next;
+
+	memset(&cfg, 0 , sizeof(CONFIGPARMS));
+	memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+	hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
+	/* assumption that all volumes on channel = 0 */
+	cfg.pageAddr = starget->id;
+	cfg.cfghdr.hdr = &hdr;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.timeout = 10;
+
+	if (mpt_config(ioc, &cfg) != 0)
+		goto out;
+
+	if (!hdr.PageLength)
+		goto out;
+
+	buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+	    &dma_handle);
+
+	if (!buffer)
+		goto out;
+
+	cfg.physAddr = dma_handle;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+	if (mpt_config(ioc, &cfg) != 0)
+		goto out;
+
+	if (!buffer->NumPhysDisks)
+		goto out;
+
+	/*
+	 * Adding entry for hidden components
+	 */
+	for (i = 0; i < buffer->NumPhysDisks; i++) {
+
+		if (mpt_raid_phys_disk_pg0(ioc,
+		    buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
+			continue;
+
+		mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
+		    phys_disk.PhysDiskID);
+
+		mutex_lock(&ioc->sas_device_info_mutex);
+		list_for_each_entry(sas_info, &ioc->sas_device_info_list,
+		    list) {
+			if (!sas_info->is_logical_volume &&
+			    (sas_info->fw.channel == phys_disk.PhysDiskBus &&
+			    sas_info->fw.id == phys_disk.PhysDiskID)) {
+				sas_info->is_hidden_raid_component = 1;
+				sas_info->volume_id = starget->id;
+			}
+		}
+		mutex_unlock(&ioc->sas_device_info_mutex);
+
+	}
+
+	/*
+	 * Delete all matching devices out of the list
+	 */
+	mutex_lock(&ioc->sas_device_info_mutex);
+	list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
+	    list) {
+		if (sas_info->is_logical_volume && sas_info->fw.id ==
+		    starget->id) {
+			list_del(&sas_info->list);
+			kfree(sas_info);
+		}
+	}
+
+	sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
+	if (sas_info) {
+		sas_info->fw.id = starget->id;
+		sas_info->os.id = starget->id;
+		sas_info->os.channel = starget->channel;
+		sas_info->is_logical_volume = 1;
+		INIT_LIST_HEAD(&sas_info->list);
+		list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
+	}
+	mutex_unlock(&ioc->sas_device_info_mutex);
+
+ out:
+	if (buffer)
+		pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+		    dma_handle);
+}
+
+/**
+ *	mptsas_add_device_component_starget -
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@starget:
+ *
+ **/
+static void
+mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
+	struct scsi_target *starget)
+{
+	VirtTarget	*vtarget;
+	struct sas_rphy	*rphy;
+	struct mptsas_phyinfo	*phy_info = NULL;
+	struct mptsas_enclosure	enclosure_info;
+
+	rphy = dev_to_rphy(starget->dev.parent);
+	vtarget = starget->hostdata;
+	phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+			rphy->identify.sas_address);
+	if (!phy_info)
+		return;
+
+	memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
+	mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
+		(MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
+		MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
+		phy_info->attached.handle_enclosure);
+
+	mptsas_add_device_component(ioc, phy_info->attached.channel,
+		phy_info->attached.id, phy_info->attached.sas_address,
+		phy_info->attached.device_info,
+		phy_info->attached.slot, enclosure_info.enclosure_logical_id);
+}
+
+/**
+ *	mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@channel: os mapped id's
+ *	@id:
+ *
+ **/
+static void
+mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+	struct mptsas_device_info	*sas_info, *next;
+
+	/*
+	 * Set is_cached flag
+	 */
+	list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
+		list) {
+		if (sas_info->os.channel == channel && sas_info->os.id == id)
+			sas_info->is_cached = 1;
+	}
+}
+
+/**
+ *	mptsas_del_device_components - Cleaning the list
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
+static void
+mptsas_del_device_components(MPT_ADAPTER *ioc)
+{
+	struct mptsas_device_info	*sas_info, *next;
+
+	mutex_lock(&ioc->sas_device_info_mutex);
+	list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
+		list) {
+		list_del(&sas_info->list);
+		kfree(sas_info);
+	}
+	mutex_unlock(&ioc->sas_device_info_mutex);
+}
+
 
 /*
  * mptsas_setup_wide_ports
@@ -434,8 +870,8 @@
 		 * Forming a port
 		 */
 		if (!port_details) {
-			port_details = kzalloc(sizeof(*port_details),
-				GFP_KERNEL);
+			port_details = kzalloc(sizeof(struct
+				mptsas_portinfo_details), GFP_KERNEL);
 			if (!port_details)
 				goto out;
 			port_details->num_phys = 1;
@@ -523,15 +959,62 @@
 	VirtTarget 			*vtarget = NULL;
 
 	shost_for_each_device(sdev, ioc->sh) {
-		if ((vdevice = sdev->hostdata) == NULL)
+		vdevice = sdev->hostdata;
+		if ((vdevice == NULL) ||
+			(vdevice->vtarget == NULL))
+			continue;
+		if ((vdevice->vtarget->tflags &
+		    MPT_TARGET_FLAGS_RAID_COMPONENT ||
+		    vdevice->vtarget->raidVolume))
 			continue;
 		if (vdevice->vtarget->id == id &&
-		    vdevice->vtarget->channel == channel)
+			vdevice->vtarget->channel == channel)
 			vtarget = vdevice->vtarget;
 	}
 	return vtarget;
 }
 
+static void
+mptsas_queue_device_delete(MPT_ADAPTER *ioc,
+	MpiEventDataSasDeviceStatusChange_t *sas_event_data)
+{
+	struct fw_event_work *fw_event;
+	int sz;
+
+	sz = offsetof(struct fw_event_work, event_data) +
+	    sizeof(MpiEventDataSasDeviceStatusChange_t);
+	fw_event = kzalloc(sz, GFP_ATOMIC);
+	if (!fw_event) {
+		printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
+		    ioc->name, __func__, __LINE__);
+		return;
+	}
+	memcpy(fw_event->event_data, sas_event_data,
+	    sizeof(MpiEventDataSasDeviceStatusChange_t));
+	fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
+	fw_event->ioc = ioc;
+	mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
+}
+
+static void
+mptsas_queue_rescan(MPT_ADAPTER *ioc)
+{
+	struct fw_event_work *fw_event;
+	int sz;
+
+	sz = offsetof(struct fw_event_work, event_data);
+	fw_event = kzalloc(sz, GFP_ATOMIC);
+	if (!fw_event) {
+		printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
+		    ioc->name, __func__, __LINE__);
+		return;
+	}
+	fw_event->event = -1;
+	fw_event->ioc = ioc;
+	mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
+}
+
+
 /**
  * mptsas_target_reset
  *
@@ -550,13 +1033,21 @@
 {
 	MPT_FRAME_HDR	*mf;
 	SCSITaskMgmt_t	*pScsiTm;
-
-	if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
-		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
-		    ioc->name,__func__, __LINE__));
+	if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
 		return 0;
+
+
+	mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
+	if (mf == NULL) {
+		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
+			"%s, no msg frames @%d!!\n", ioc->name,
+			__func__, __LINE__));
+		goto out_fail;
 	}
 
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
+		ioc->name, mf));
+
 	/* Format the Request
 	 */
 	pScsiTm = (SCSITaskMgmt_t *) mf;
@@ -569,9 +1060,18 @@
 
 	DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
 
-	mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+	   "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
+	   ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
+
+	mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
 
 	return 1;
+
+ out_fail:
+
+	mpt_clear_taskmgmt_in_progress_flag(ioc);
+	return 0;
 }
 
 /**
@@ -602,11 +1102,12 @@
 
 	vtarget->deleted = 1; /* block IO */
 
-	target_reset_list = kzalloc(sizeof(*target_reset_list),
+	target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
 	    GFP_ATOMIC);
 	if (!target_reset_list) {
-		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
-		    ioc->name,__func__, __LINE__));
+		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
+			"%s, failed to allocate mem @%d..!!\n",
+			ioc->name, __func__, __LINE__));
 		return;
 	}
 
@@ -614,84 +1115,101 @@
 		sizeof(*sas_event_data));
 	list_add_tail(&target_reset_list->list, &hd->target_reset_list);
 
-	if (hd->resetPending)
-		return;
+	target_reset_list->time_count = jiffies;
 
 	if (mptsas_target_reset(ioc, channel, id)) {
 		target_reset_list->target_reset_issued = 1;
-		hd->resetPending = 1;
 	}
 }
 
 /**
- * mptsas_dev_reset_complete
+ *	mptsas_taskmgmt_complete - complete SAS task management function
+ *	@ioc: Pointer to MPT_ADAPTER structure
  *
- * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
- * enable work queue to finish off removing device from upper layers.
- * then send next TARGET_RESET in the queue.
- *
- * @ioc
- *
+ *	Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
+ *	queue to finish off removing device from upper layers. then send next
+ *	TARGET_RESET in the queue.
  **/
-static void
-mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
+static int
+mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 {
 	MPT_SCSI_HOST	*hd = shost_priv(ioc->sh);
         struct list_head *head = &hd->target_reset_list;
-	struct mptsas_target_reset_event *target_reset_list;
-	struct mptsas_hotplug_event *ev;
-	EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
 	u8		id, channel;
-	__le64		sas_address;
+	struct mptsas_target_reset_event	*target_reset_list;
+	SCSITaskMgmtReply_t *pScsiTmReply;
+
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
+	    "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
+
+	pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
+	if (pScsiTmReply) {
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
+		    "\ttask_type = 0x%02X, iocstatus = 0x%04X "
+		    "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
+		    "term_cmnds = %d\n", ioc->name,
+		    pScsiTmReply->Bus, pScsiTmReply->TargetID,
+		    pScsiTmReply->TaskType,
+		    le16_to_cpu(pScsiTmReply->IOCStatus),
+		    le32_to_cpu(pScsiTmReply->IOCLogInfo),
+		    pScsiTmReply->ResponseCode,
+		    le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+		if (pScsiTmReply->ResponseCode)
+			mptscsih_taskmgmt_response_code(ioc,
+			pScsiTmReply->ResponseCode);
+	}
+
+	if (pScsiTmReply && (pScsiTmReply->TaskType ==
+	    MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
+	     MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
+		ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+		ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+		memcpy(ioc->taskmgmt_cmds.reply, mr,
+		    min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
+		if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
+			ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+			complete(&ioc->taskmgmt_cmds.done);
+			return 1;
+		}
+		return 0;
+	}
+
+	mpt_clear_taskmgmt_in_progress_flag(ioc);
 
 	if (list_empty(head))
-		return;
+		return 1;
 
-	target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
+	target_reset_list = list_entry(head->next,
+	    struct mptsas_target_reset_event, list);
 
-	sas_event_data = &target_reset_list->sas_event_data;
-	id = sas_event_data->TargetID;
-	channel = sas_event_data->Bus;
-	hd->resetPending = 0;
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+	    "TaskMgmt: completed (%d seconds)\n",
+	    ioc->name, jiffies_to_msecs(jiffies -
+	    target_reset_list->time_count)/1000));
+
+	id = pScsiTmReply->TargetID;
+	channel = pScsiTmReply->Bus;
+	target_reset_list->time_count = jiffies;
 
 	/*
 	 * retry target reset
 	 */
 	if (!target_reset_list->target_reset_issued) {
-		if (mptsas_target_reset(ioc, channel, id)) {
+		if (mptsas_target_reset(ioc, channel, id))
 			target_reset_list->target_reset_issued = 1;
-			hd->resetPending = 1;
-		}
-		return;
+		return 1;
 	}
 
 	/*
 	 * enable work queue to remove device from upper layers
 	 */
 	list_del(&target_reset_list->list);
+	if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
+		mptsas_queue_device_delete(ioc,
+			&target_reset_list->sas_event_data);
 
-	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-	if (!ev) {
-		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
-		    ioc->name,__func__, __LINE__));
-		return;
-	}
-
-	INIT_WORK(&ev->work, mptsas_hotplug_work);
-	ev->ioc = ioc;
-	ev->handle = le16_to_cpu(sas_event_data->DevHandle);
-	ev->parent_handle =
-	    le16_to_cpu(sas_event_data->ParentDevHandle);
-	ev->channel = channel;
-	ev->id =id;
-	ev->phy_id = sas_event_data->PhyNum;
-	memcpy(&sas_address, &sas_event_data->SASAddress,
-	    sizeof(__le64));
-	ev->sas_address = le64_to_cpu(sas_address);
-	ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
-	ev->event_type = MPTSAS_DEL_DEVICE;
-	schedule_work(&ev->work);
-	kfree(target_reset_list);
 
 	/*
 	 * issue target reset to next device in the queue
@@ -699,34 +1217,19 @@
 
 	head = &hd->target_reset_list;
 	if (list_empty(head))
-		return;
+		return 1;
 
 	target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
 	    list);
 
-	sas_event_data = &target_reset_list->sas_event_data;
-	id = sas_event_data->TargetID;
-	channel = sas_event_data->Bus;
+	id = target_reset_list->sas_event_data.TargetID;
+	channel = target_reset_list->sas_event_data.Bus;
+	target_reset_list->time_count = jiffies;
 
-	if (mptsas_target_reset(ioc, channel, id)) {
+	if (mptsas_target_reset(ioc, channel, id))
 		target_reset_list->target_reset_issued = 1;
-		hd->resetPending = 1;
-	}
-}
 
-/**
- * mptsas_taskmgmt_complete
- *
- * @ioc
- * @mf
- * @mr
- *
- **/
-static int
-mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
-{
-	mptsas_dev_reset_complete(ioc);
-	return mptscsih_taskmgmt_complete(ioc, mf, mr);
+	return 1;
 }
 
 /**
@@ -740,37 +1243,59 @@
 mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
 	MPT_SCSI_HOST	*hd;
-	struct mptsas_target_reset_event *target_reset_list, *n;
 	int rc;
 
 	rc = mptscsih_ioc_reset(ioc, reset_phase);
+	if ((ioc->bus_type != SAS) || (!rc))
+		return rc;
 
-	if (ioc->bus_type != SAS)
-		goto out;
-
-	if (reset_phase != MPT_IOC_POST_RESET)
-		goto out;
-
-	if (!ioc->sh || !ioc->sh->hostdata)
-		goto out;
 	hd = shost_priv(ioc->sh);
 	if (!hd->ioc)
 		goto out;
 
-	if (list_empty(&hd->target_reset_list))
-		goto out;
-
-	/* flush the target_reset_list */
-	list_for_each_entry_safe(target_reset_list, n,
-	    &hd->target_reset_list, list) {
-		list_del(&target_reset_list->list);
-		kfree(target_reset_list);
+	switch (reset_phase) {
+	case MPT_IOC_SETUP_RESET:
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
+		mptsas_fw_event_off(ioc);
+		break;
+	case MPT_IOC_PRE_RESET:
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
+		break;
+	case MPT_IOC_POST_RESET:
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
+		if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
+			ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
+			complete(&ioc->sas_mgmt.done);
+		}
+		mptsas_cleanup_fw_event_q(ioc);
+		mptsas_queue_rescan(ioc);
+		mptsas_fw_event_on(ioc);
+		break;
+	default:
+		break;
 	}
 
  out:
 	return rc;
 }
 
+
+/**
+ * enum device_state -
+ * @DEVICE_RETRY: need to retry the TUR
+ * @DEVICE_ERROR: TUR return error, don't add device
+ * @DEVICE_READY: device can be added
+ *
+ */
+enum device_state{
+	DEVICE_RETRY,
+	DEVICE_ERROR,
+	DEVICE_READY,
+};
+
 static int
 mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
 		u32 form, u32 form_specific)
@@ -836,15 +1361,308 @@
 	return error;
 }
 
+/**
+ *	mptsas_add_end_device - report a new end device to sas transport layer
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@phy_info: decribes attached device
+ *
+ *	return (0) success (1) failure
+ *
+ **/
+static int
+mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
+{
+	struct sas_rphy *rphy;
+	struct sas_port *port;
+	struct sas_identify identify;
+	char *ds = NULL;
+	u8 fw_id;
+
+	if (!phy_info) {
+		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+			"%s: exit at line=%d\n", ioc->name,
+			 __func__, __LINE__));
+		return 1;
+	}
+
+	fw_id = phy_info->attached.id;
+
+	if (mptsas_get_rphy(phy_info)) {
+		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+			"%s: fw_id=%d exit at line=%d\n", ioc->name,
+			 __func__, fw_id, __LINE__));
+		return 2;
+	}
+
+	port = mptsas_get_port(phy_info);
+	if (!port) {
+		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+			"%s: fw_id=%d exit at line=%d\n", ioc->name,
+			 __func__, fw_id, __LINE__));
+		return 3;
+	}
+
+	if (phy_info->attached.device_info &
+	    MPI_SAS_DEVICE_INFO_SSP_TARGET)
+		ds = "ssp";
+	if (phy_info->attached.device_info &
+	    MPI_SAS_DEVICE_INFO_STP_TARGET)
+		ds = "stp";
+	if (phy_info->attached.device_info &
+	    MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+		ds = "sata";
+
+	printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
+	    " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
+	    phy_info->attached.channel, phy_info->attached.id,
+	    phy_info->attached.phy_id, (unsigned long long)
+	    phy_info->attached.sas_address);
+
+	mptsas_parse_device_info(&identify, &phy_info->attached);
+	rphy = sas_end_device_alloc(port);
+	if (!rphy) {
+		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+			"%s: fw_id=%d exit at line=%d\n", ioc->name,
+			 __func__, fw_id, __LINE__));
+		return 5; /* non-fatal: an rphy can be added later */
+	}
+
+	rphy->identify = identify;
+	if (sas_rphy_add(rphy)) {
+		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+			"%s: fw_id=%d exit at line=%d\n", ioc->name,
+			 __func__, fw_id, __LINE__));
+		sas_rphy_free(rphy);
+		return 6;
+	}
+	mptsas_set_rphy(ioc, phy_info, rphy);
+	return 0;
+}
+
+/**
+ *	mptsas_del_end_device - report a deleted end device to sas transport layer
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@phy_info: decribes attached device
+ *
+ **/
+static void
+mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
+{
+	struct sas_rphy *rphy;
+	struct sas_port *port;
+	struct mptsas_portinfo *port_info;
+	struct mptsas_phyinfo *phy_info_parent;
+	int i;
+	char *ds = NULL;
+	u8 fw_id;
+	u64 sas_address;
+
+	if (!phy_info)
+		return;
+
+	fw_id = phy_info->attached.id;
+	sas_address = phy_info->attached.sas_address;
+
+	if (!phy_info->port_details) {
+		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+			"%s: fw_id=%d exit at line=%d\n", ioc->name,
+			 __func__, fw_id, __LINE__));
+		return;
+	}
+	rphy = mptsas_get_rphy(phy_info);
+	if (!rphy) {
+		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+			"%s: fw_id=%d exit at line=%d\n", ioc->name,
+			 __func__, fw_id, __LINE__));
+		return;
+	}
+
+	if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
+		|| phy_info->attached.device_info
+			& MPI_SAS_DEVICE_INFO_SMP_INITIATOR
+		|| phy_info->attached.device_info
+			& MPI_SAS_DEVICE_INFO_STP_INITIATOR)
+		ds = "initiator";
+	if (phy_info->attached.device_info &
+	    MPI_SAS_DEVICE_INFO_SSP_TARGET)
+		ds = "ssp";
+	if (phy_info->attached.device_info &
+	    MPI_SAS_DEVICE_INFO_STP_TARGET)
+		ds = "stp";
+	if (phy_info->attached.device_info &
+	    MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+		ds = "sata";
+
+	dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
+	    "removing %s device: fw_channel %d, fw_id %d, phy %d,"
+	    "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
+	    phy_info->attached.id, phy_info->attached.phy_id,
+	    (unsigned long long) sas_address);
+
+	port = mptsas_get_port(phy_info);
+	if (!port) {
+		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+			"%s: fw_id=%d exit at line=%d\n", ioc->name,
+			 __func__, fw_id, __LINE__));
+		return;
+	}
+	port_info = phy_info->portinfo;
+	phy_info_parent = port_info->phy_info;
+	for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
+		if (!phy_info_parent->phy)
+			continue;
+		if (phy_info_parent->attached.sas_address !=
+		    sas_address)
+			continue;
+		dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
+		    MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
+		    ioc->name, phy_info_parent->phy_id,
+		    phy_info_parent->phy);
+		sas_port_delete_phy(port, phy_info_parent->phy);
+	}
+
+	dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
+	    "delete port %d, sas_addr (0x%llx)\n", ioc->name,
+	     port->port_identifier, (unsigned long long)sas_address);
+	sas_port_delete(port);
+	mptsas_set_port(ioc, phy_info, NULL);
+	mptsas_port_delete(ioc, phy_info->port_details);
+}
+
+struct mptsas_phyinfo *
+mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
+	struct mptsas_devinfo *sas_device)
+{
+	struct mptsas_phyinfo *phy_info;
+	struct mptsas_portinfo *port_info;
+	int i;
+
+	phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+	    sas_device->sas_address);
+	if (!phy_info)
+		goto out;
+	port_info = phy_info->portinfo;
+	if (!port_info)
+		goto out;
+	mutex_lock(&ioc->sas_topology_mutex);
+	for (i = 0; i < port_info->num_phys; i++) {
+		if (port_info->phy_info[i].attached.sas_address !=
+			sas_device->sas_address)
+			continue;
+		port_info->phy_info[i].attached.channel = sas_device->channel;
+		port_info->phy_info[i].attached.id = sas_device->id;
+		port_info->phy_info[i].attached.sas_address =
+		    sas_device->sas_address;
+		port_info->phy_info[i].attached.handle = sas_device->handle;
+		port_info->phy_info[i].attached.handle_parent =
+		    sas_device->handle_parent;
+		port_info->phy_info[i].attached.handle_enclosure =
+		    sas_device->handle_enclosure;
+	}
+	mutex_unlock(&ioc->sas_topology_mutex);
+ out:
+	return phy_info;
+}
+
+/**
+ * mptsas_firmware_event_work - work thread for processing fw events
+ * @work: work queue payload containing info describing the event
+ * Context: user
+ *
+ */
+static void
+mptsas_firmware_event_work(struct work_struct *work)
+{
+	struct fw_event_work *fw_event =
+		container_of(work, struct fw_event_work, work.work);
+	MPT_ADAPTER *ioc = fw_event->ioc;
+
+	/* special rescan topology handling */
+	if (fw_event->event == -1) {
+		if (ioc->in_rescan) {
+			devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+				"%s: rescan ignored as it is in progress\n",
+				ioc->name, __func__));
+			return;
+		}
+		devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
+		    "reset\n", ioc->name, __func__));
+		ioc->in_rescan = 1;
+		mptsas_not_responding_devices(ioc);
+		mptsas_scan_sas_topology(ioc);
+		ioc->in_rescan = 0;
+		mptsas_free_fw_event(ioc, fw_event);
+		return;
+	}
+
+	/* events handling turned off during host reset */
+	if (ioc->fw_events_off) {
+		mptsas_free_fw_event(ioc, fw_event);
+		return;
+	}
+
+	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
+	    "event = (0x%02x)\n", ioc->name, __func__, fw_event,
+	    (fw_event->event & 0xFF)));
+
+	switch (fw_event->event) {
+	case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
+		mptsas_send_sas_event(fw_event);
+		break;
+	case MPI_EVENT_INTEGRATED_RAID:
+		mptsas_send_raid_event(fw_event);
+		break;
+	case MPI_EVENT_IR2:
+		mptsas_send_ir2_event(fw_event);
+		break;
+	case MPI_EVENT_PERSISTENT_TABLE_FULL:
+		mptbase_sas_persist_operation(ioc,
+		    MPI_SAS_OP_CLEAR_NOT_PRESENT);
+		mptsas_free_fw_event(ioc, fw_event);
+		break;
+	case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
+		mptsas_broadcast_primative_work(fw_event);
+		break;
+	case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
+		mptsas_send_expander_event(fw_event);
+		break;
+	case MPI_EVENT_SAS_PHY_LINK_STATUS:
+		mptsas_send_link_status_event(fw_event);
+		break;
+	case MPI_EVENT_QUEUE_FULL:
+		mptsas_handle_queue_full_event(fw_event);
+		break;
+	}
+}
+
+
+
 static int
 mptsas_slave_configure(struct scsi_device *sdev)
 {
+	struct Scsi_Host	*host = sdev->host;
+	MPT_SCSI_HOST	*hd = shost_priv(host);
+	MPT_ADAPTER	*ioc = hd->ioc;
+	VirtDevice	*vdevice = sdev->hostdata;
 
-	if (sdev->channel == MPTSAS_RAID_CHANNEL)
+	if (vdevice->vtarget->deleted) {
+		sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
+		vdevice->vtarget->deleted = 0;
+	}
+
+	/*
+	 * RAID volumes placed beyond the last expected port.
+	 * Ignore sending sas mode pages in that case..
+	 */
+	if (sdev->channel == MPTSAS_RAID_CHANNEL) {
+		mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
 		goto out;
+	}
 
 	sas_read_port_mode_page(sdev);
 
+	mptsas_add_device_component_starget(ioc, scsi_target(sdev));
+
  out:
 	return mptscsih_slave_configure(sdev);
 }
@@ -875,9 +1693,18 @@
 	 * RAID volumes placed beyond the last expected port.
 	 */
 	if (starget->channel == MPTSAS_RAID_CHANNEL) {
-		for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
-			if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
-				channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
+		if (!ioc->raid_data.pIocPg2) {
+			kfree(vtarget);
+			return -ENXIO;
+		}
+		for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+			if (id == ioc->raid_data.pIocPg2->
+					RaidVolume[i].VolumeID) {
+				channel = ioc->raid_data.pIocPg2->
+					RaidVolume[i].VolumeBus;
+			}
+		}
+		vtarget->raidVolume = 1;
 		goto out;
 	}
 
@@ -926,11 +1753,18 @@
 	struct sas_rphy		*rphy;
 	struct mptsas_portinfo	*p;
 	int 			 i;
-	MPT_ADAPTER *ioc = hd->ioc;
+	MPT_ADAPTER	*ioc = hd->ioc;
+	VirtTarget	*vtarget;
 
 	if (!starget->hostdata)
 		return;
 
+	vtarget = starget->hostdata;
+
+	mptsas_del_device_component_by_os(ioc, starget->channel,
+	    starget->id);
+
+
 	if (starget->channel == MPTSAS_RAID_CHANNEL)
 		goto out;
 
@@ -940,12 +1774,21 @@
 			if (p->phy_info[i].attached.sas_address !=
 					rphy->identify.sas_address)
 				continue;
+
+			starget_printk(KERN_INFO, starget, MYIOC_s_FMT
+			"delete device: fw_channel %d, fw_id %d, phy %d, "
+			"sas_addr 0x%llx\n", ioc->name,
+			p->phy_info[i].attached.channel,
+			p->phy_info[i].attached.id,
+			p->phy_info[i].attached.phy_id, (unsigned long long)
+			p->phy_info[i].attached.sas_address);
+
 			mptsas_set_starget(&p->phy_info[i], NULL);
-			goto out;
 		}
 	}
 
  out:
+	vtarget->starget = NULL;
 	kfree(starget->hostdata);
 	starget->hostdata = NULL;
 }
@@ -1008,6 +1851,8 @@
 static int
 mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
+	MPT_SCSI_HOST	*hd;
+	MPT_ADAPTER	*ioc;
 	VirtDevice	*vdevice = SCpnt->device->hostdata;
 
 	if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
@@ -1016,6 +1861,12 @@
 		return 0;
 	}
 
+	hd = shost_priv(SCpnt->device->host);
+	ioc = hd->ioc;
+
+	if (ioc->sas_discovery_quiesce_io)
+		return SCSI_MLQUEUE_HOST_BUSY;
+
 //	scsi_print_command(SCpnt);
 
 	return mptscsih_qcmd(SCpnt,done);
@@ -1114,14 +1965,19 @@
 static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
 		MPT_FRAME_HDR *reply)
 {
-	ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
+	ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
 	if (reply != NULL) {
-		ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
+		ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
 		memcpy(ioc->sas_mgmt.reply, reply,
 		    min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
 	}
-	complete(&ioc->sas_mgmt.done);
-	return 1;
+
+	if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
+		ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
+		complete(&ioc->sas_mgmt.done);
+		return 1;
+	}
+	return 0;
 }
 
 static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
@@ -1160,6 +2016,7 @@
 		MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
 	req->PhyNum = phy->identify.phy_identifier;
 
+	INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
 	mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
 
 	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
@@ -1174,7 +2031,7 @@
 
 	/* a reply frame is expected */
 	if ((ioc->sas_mgmt.status &
-	    MPT_IOCTL_STATUS_RF_VALID) == 0) {
+	    MPT_MGMT_STATUS_RF_VALID) == 0) {
 		error = -ENXIO;
 		goto out_unlock;
 	}
@@ -1191,6 +2048,7 @@
 	error = 0;
 
  out_unlock:
+	CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
 	mutex_unlock(&ioc->sas_mgmt.mutex);
  out:
 	return error;
@@ -1304,7 +2162,7 @@
 		struct mptsas_portinfo *port_info;
 
 		mutex_lock(&ioc->sas_topology_mutex);
-		port_info = mptsas_get_hba_portinfo(ioc);
+		port_info = ioc->hba_port_info;
 		if (port_info && port_info->phy_info)
 			sas_address =
 				port_info->phy_info[0].phy->identify.sas_address;
@@ -1319,26 +2177,32 @@
 	/* request */
 	flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
 		       MPI_SGE_FLAGS_END_OF_BUFFER |
-		       MPI_SGE_FLAGS_DIRECTION |
-		       mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
+		       MPI_SGE_FLAGS_DIRECTION)
+		       << MPI_SGE_FLAGS_SHIFT;
 	flagsLength |= (blk_rq_bytes(req) - 4);
 
 	dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
 				      blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
 	if (!dma_addr_out)
 		goto put_mf;
-	mpt_add_sge(psge, flagsLength, dma_addr_out);
-	psge += (sizeof(u32) + sizeof(dma_addr_t));
+	ioc->add_sge(psge, flagsLength, dma_addr_out);
+	psge += ioc->SGE_size;
 
 	/* response */
-	flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+	flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+		MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+		MPI_SGE_FLAGS_IOC_TO_HOST |
+		MPI_SGE_FLAGS_END_OF_BUFFER;
+
+	flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
 	flagsLength |= blk_rq_bytes(rsp) + 4;
 	dma_addr_in =  pci_map_single(ioc->pcidev, bio_data(rsp->bio),
 				      blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
 	if (!dma_addr_in)
 		goto unmap;
-	mpt_add_sge(psge, flagsLength, dma_addr_in);
+	ioc->add_sge(psge, flagsLength, dma_addr_in);
 
+	INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
 	mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
 
 	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
@@ -1351,7 +2215,7 @@
 	}
 	mf = NULL;
 
-	if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) {
+	if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
 		SmpPassthroughReply_t *smprep;
 
 		smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
@@ -1360,7 +2224,8 @@
 		req->resid_len = 0;
 		rsp->resid_len -= smprep->ResponseDataLength;
 	} else {
-		printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
+		printk(MYIOC_s_ERR_FMT
+		    "%s: smp passthru reply failed to be returned\n",
 		    ioc->name, __func__);
 		ret = -ENXIO;
 	}
@@ -1375,6 +2240,7 @@
 	if (mf)
 		mpt_free_msg_frame(ioc, mf);
 out_unlock:
+	CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
 	mutex_unlock(&ioc->sas_mgmt.mutex);
 out:
 	return ret;
@@ -1438,7 +2304,7 @@
 
 	port_info->num_phys = buffer->NumPhys;
 	port_info->phy_info = kcalloc(port_info->num_phys,
-		sizeof(*port_info->phy_info),GFP_KERNEL);
+		sizeof(struct mptsas_phyinfo), GFP_KERNEL);
 	if (!port_info->phy_info) {
 		error = -ENOMEM;
 		goto out_free_consistent;
@@ -1600,10 +2466,6 @@
 	__le64 sas_address;
 	int error=0;
 
-	if (ioc->sas_discovery_runtime &&
-		mptsas_is_end_device(device_info))
-			goto out;
-
 	hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
 	hdr.ExtPageLength = 0;
 	hdr.PageNumber = 0;
@@ -1644,6 +2506,7 @@
 
 	mptsas_print_device_pg0(ioc, buffer);
 
+	memset(device_info, 0, sizeof(struct mptsas_devinfo));
 	device_info->handle = le16_to_cpu(buffer->DevHandle);
 	device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
 	device_info->handle_enclosure =
@@ -1675,7 +2538,9 @@
 	SasExpanderPage0_t *buffer;
 	dma_addr_t dma_handle;
 	int i, error;
+	__le64 sas_address;
 
+	memset(port_info, 0, sizeof(struct mptsas_portinfo));
 	hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
 	hdr.ExtPageLength = 0;
 	hdr.PageNumber = 0;
@@ -1721,18 +2586,23 @@
 	}
 
 	/* save config data */
-	port_info->num_phys = buffer->NumPhys;
+	port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
 	port_info->phy_info = kcalloc(port_info->num_phys,
-		sizeof(*port_info->phy_info),GFP_KERNEL);
+		sizeof(struct mptsas_phyinfo), GFP_KERNEL);
 	if (!port_info->phy_info) {
 		error = -ENOMEM;
 		goto out_free_consistent;
 	}
 
+	memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
 	for (i = 0; i < port_info->num_phys; i++) {
 		port_info->phy_info[i].portinfo = port_info;
 		port_info->phy_info[i].handle =
 		    le16_to_cpu(buffer->DevHandle);
+		port_info->phy_info[i].identify.sas_address =
+		    le64_to_cpu(sas_address);
+		port_info->phy_info[i].identify.handle_parent =
+		    le16_to_cpu(buffer->ParentDevHandle);
 	}
 
  out_free_consistent:
@@ -1752,11 +2622,7 @@
 	dma_addr_t dma_handle;
 	int error=0;
 
-	if (ioc->sas_discovery_runtime &&
-		mptsas_is_end_device(&phy_info->attached))
-			goto out;
-
-	hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
+	hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
 	hdr.ExtPageLength = 0;
 	hdr.PageNumber = 1;
 	hdr.Reserved1 = 0;
@@ -1791,6 +2657,12 @@
 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
 
 	error = mpt_config(ioc, &cfg);
+
+	if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
+		error = -ENODEV;
+		goto out;
+	}
+
 	if (error)
 		goto out_free_consistent;
 
@@ -2010,16 +2882,21 @@
 				goto out;
 			}
 			mptsas_set_port(ioc, phy_info, port);
-			dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-			    "sas_port_alloc: port=%p dev=%p port_id=%d\n",
-			    ioc->name, port, dev, port->port_identifier));
+			devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
+			    MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
+			    ioc->name, port->port_identifier,
+			    (unsigned long long)phy_info->
+			    attached.sas_address));
 		}
-		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
-		    ioc->name, phy_info->phy_id));
+		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+			"sas_port_add_phy: phy_id=%d\n",
+			ioc->name, phy_info->phy_id));
 		sas_port_add_phy(port, phy_info->phy);
 		phy_info->sas_port_add_phy = 0;
+		devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
+		    MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
+		     phy_info->phy_id, phy_info->phy));
 	}
-
 	if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
 
 		struct sas_rphy *rphy;
@@ -2032,18 +2909,17 @@
 		 * the adding/removing of devices that occur
 		 * after start of day.
 		 */
-		if (ioc->sas_discovery_runtime &&
-			mptsas_is_end_device(&phy_info->attached))
-				goto out;
+		if (mptsas_is_end_device(&phy_info->attached) &&
+		    phy_info->attached.handle_parent) {
+			goto out;
+		}
 
 		mptsas_parse_device_info(&identify, &phy_info->attached);
 		if (scsi_is_host_device(parent)) {
 			struct mptsas_portinfo *port_info;
 			int i;
 
-			mutex_lock(&ioc->sas_topology_mutex);
-			port_info = mptsas_get_hba_portinfo(ioc);
-			mutex_unlock(&ioc->sas_topology_mutex);
+			port_info = ioc->hba_port_info;
 
 			for (i = 0; i < port_info->num_phys; i++)
 				if (port_info->phy_info[i].identify.sas_address ==
@@ -2102,7 +2978,7 @@
 	struct mptsas_portinfo *port_info, *hba;
 	int error = -ENOMEM, i;
 
-	hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
+	hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
 	if (! hba)
 		goto out;
 
@@ -2112,9 +2988,10 @@
 
 	mptsas_sas_io_unit_pg1(ioc);
 	mutex_lock(&ioc->sas_topology_mutex);
-	port_info = mptsas_get_hba_portinfo(ioc);
+	port_info = ioc->hba_port_info;
 	if (!port_info) {
-		port_info = hba;
+		ioc->hba_port_info = port_info = hba;
+		ioc->hba_port_num_phy = port_info->num_phys;
 		list_add_tail(&port_info->list, &ioc->sas_topology);
 	} else {
 		for (i = 0; i < hba->num_phys; i++) {
@@ -2130,15 +3007,22 @@
 		hba = NULL;
 	}
 	mutex_unlock(&ioc->sas_topology_mutex);
+#if defined(CPQ_CIM)
+	ioc->num_ports = port_info->num_phys;
+#endif
 	for (i = 0; i < port_info->num_phys; i++) {
 		mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
 			(MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
 			 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
-
+		port_info->phy_info[i].identify.handle =
+		    port_info->phy_info[i].handle;
 		mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
 			(MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
 			 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
-			 port_info->phy_info[i].handle);
+			 port_info->phy_info[i].identify.handle);
+		if (!ioc->hba_port_sas_addr)
+			ioc->hba_port_sas_addr =
+			    port_info->phy_info[i].identify.sas_address;
 		port_info->phy_info[i].identify.phy_id =
 		    port_info->phy_info[i].phy_id = i;
 		if (port_info->phy_info[i].attached.handle)
@@ -2163,247 +3047,720 @@
 	return error;
 }
 
-static int
-mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
+static void
+mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
 {
-	struct mptsas_portinfo *port_info, *p, *ex;
-	struct device *parent;
-	struct sas_rphy *rphy;
-	int error = -ENOMEM, i, j;
+	struct mptsas_portinfo *parent;
+	struct device *parent_dev;
+	struct sas_rphy	*rphy;
+	int		i;
+	u64		sas_address; /* expander sas address */
+	u32		handle;
 
-	ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
-	if (!ex)
-		goto out;
-
-	error = mptsas_sas_expander_pg0(ioc, ex,
-	    (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
-	     MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
-	if (error)
-		goto out_free_port_info;
-
-	*handle = ex->phy_info[0].handle;
-
-	mutex_lock(&ioc->sas_topology_mutex);
-	port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
-	if (!port_info) {
-		port_info = ex;
-		list_add_tail(&port_info->list, &ioc->sas_topology);
-	} else {
-		for (i = 0; i < ex->num_phys; i++) {
-			port_info->phy_info[i].handle =
-				ex->phy_info[i].handle;
-			port_info->phy_info[i].port_id =
-				ex->phy_info[i].port_id;
-		}
-		kfree(ex->phy_info);
-		kfree(ex);
-		ex = NULL;
-	}
-	mutex_unlock(&ioc->sas_topology_mutex);
-
+	handle = port_info->phy_info[0].handle;
+	sas_address = port_info->phy_info[0].identify.sas_address;
 	for (i = 0; i < port_info->num_phys; i++) {
 		mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
-			(MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
-			 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
+		    (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
+		    MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
 
-		if (port_info->phy_info[i].identify.handle) {
-			mptsas_sas_device_pg0(ioc,
-				&port_info->phy_info[i].identify,
-				(MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
-				 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
-				port_info->phy_info[i].identify.handle);
-			port_info->phy_info[i].identify.phy_id =
-			    port_info->phy_info[i].phy_id;
-		}
+		mptsas_sas_device_pg0(ioc,
+		    &port_info->phy_info[i].identify,
+		    (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+		    MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+		    port_info->phy_info[i].identify.handle);
+		port_info->phy_info[i].identify.phy_id =
+		    port_info->phy_info[i].phy_id;
 
 		if (port_info->phy_info[i].attached.handle) {
 			mptsas_sas_device_pg0(ioc,
-				&port_info->phy_info[i].attached,
-				(MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
-				 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
-				port_info->phy_info[i].attached.handle);
+			    &port_info->phy_info[i].attached,
+			    (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+			     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+			    port_info->phy_info[i].attached.handle);
 			port_info->phy_info[i].attached.phy_id =
 			    port_info->phy_info[i].phy_id;
 		}
 	}
 
-	parent = &ioc->sh->shost_gendev;
-	for (i = 0; i < port_info->num_phys; i++) {
-		mutex_lock(&ioc->sas_topology_mutex);
-		list_for_each_entry(p, &ioc->sas_topology, list) {
-			for (j = 0; j < p->num_phys; j++) {
-				if (port_info->phy_info[i].identify.handle !=
-						p->phy_info[j].attached.handle)
-					continue;
-				rphy = mptsas_get_rphy(&p->phy_info[j]);
-				parent = &rphy->dev;
-			}
-		}
-		mutex_unlock(&ioc->sas_topology_mutex);
-	}
-
-	mptsas_setup_wide_ports(ioc, port_info);
-
-	for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
-		mptsas_probe_one_phy(parent, &port_info->phy_info[i],
-		    ioc->sas_index, 0);
-
-	return 0;
-
- out_free_port_info:
-	if (ex) {
-		kfree(ex->phy_info);
-		kfree(ex);
-	}
- out:
-	return error;
-}
-
-/*
- * mptsas_delete_expander_phys
- *
- *
- * This will traverse topology, and remove expanders
- * that are no longer present
- */
-static void
-mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
-{
-	struct mptsas_portinfo buffer;
-	struct mptsas_portinfo *port_info, *n, *parent;
-	struct mptsas_phyinfo *phy_info;
-	struct sas_port * port;
-	int i;
-	u64	expander_sas_address;
-
 	mutex_lock(&ioc->sas_topology_mutex);
-	list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
-
-		if (!(port_info->phy_info[0].identify.device_info &
-		    MPI_SAS_DEVICE_INFO_SMP_TARGET))
-			continue;
-
-		if (mptsas_sas_expander_pg0(ioc, &buffer,
-		     (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
-		     MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
-		     port_info->phy_info[0].handle)) {
-
-			/*
-			 * Obtain the port_info instance to the parent port
-			 */
-			parent = mptsas_find_portinfo_by_handle(ioc,
-			    port_info->phy_info[0].identify.handle_parent);
-
-			if (!parent)
-				goto next_port;
-
-			expander_sas_address =
-				port_info->phy_info[0].identify.sas_address;
-
-			/*
-			 * Delete rphys in the parent that point
-			 * to this expander.  The transport layer will
-			 * cleanup all the children.
-			 */
-			phy_info = parent->phy_info;
-			for (i = 0; i < parent->num_phys; i++, phy_info++) {
-				port = mptsas_get_port(phy_info);
-				if (!port)
-					continue;
-				if (phy_info->attached.sas_address !=
-					expander_sas_address)
-					continue;
-				dsaswideprintk(ioc,
-				    dev_printk(KERN_DEBUG, &port->dev,
-				    MYIOC_s_FMT "delete port (%d)\n", ioc->name,
-				    port->port_identifier));
-				sas_port_delete(port);
-				mptsas_port_delete(ioc, phy_info->port_details);
-			}
- next_port:
-
-			phy_info = port_info->phy_info;
-			for (i = 0; i < port_info->num_phys; i++, phy_info++)
-				mptsas_port_delete(ioc, phy_info->port_details);
-
-			list_del(&port_info->list);
-			kfree(port_info->phy_info);
-			kfree(port_info);
+	parent = mptsas_find_portinfo_by_handle(ioc,
+	    port_info->phy_info[0].identify.handle_parent);
+	if (!parent) {
+		mutex_unlock(&ioc->sas_topology_mutex);
+		return;
+	}
+	for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
+	    i++) {
+		if (parent->phy_info[i].attached.sas_address == sas_address) {
+			rphy = mptsas_get_rphy(&parent->phy_info[i]);
+			parent_dev = &rphy->dev;
 		}
-		/*
-		* Free this memory allocated from inside
-		* mptsas_sas_expander_pg0
-		*/
-		kfree(buffer.phy_info);
 	}
 	mutex_unlock(&ioc->sas_topology_mutex);
+
+	mptsas_setup_wide_ports(ioc, port_info);
+	for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
+		mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
+		    ioc->sas_index, 0);
 }
 
-/*
- * Start of day discovery
+static void
+mptsas_expander_event_add(MPT_ADAPTER *ioc,
+    MpiEventDataSasExpanderStatusChange_t *expander_data)
+{
+	struct mptsas_portinfo *port_info;
+	int i;
+	__le64 sas_address;
+
+	port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
+	if (!port_info)
+		BUG();
+	port_info->num_phys = (expander_data->NumPhys) ?
+	    expander_data->NumPhys : 1;
+	port_info->phy_info = kcalloc(port_info->num_phys,
+	    sizeof(struct mptsas_phyinfo), GFP_KERNEL);
+	if (!port_info->phy_info)
+		BUG();
+	memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
+	for (i = 0; i < port_info->num_phys; i++) {
+		port_info->phy_info[i].portinfo = port_info;
+		port_info->phy_info[i].handle =
+		    le16_to_cpu(expander_data->DevHandle);
+		port_info->phy_info[i].identify.sas_address =
+		    le64_to_cpu(sas_address);
+		port_info->phy_info[i].identify.handle_parent =
+		    le16_to_cpu(expander_data->ParentDevHandle);
+	}
+
+	mutex_lock(&ioc->sas_topology_mutex);
+	list_add_tail(&port_info->list, &ioc->sas_topology);
+	mutex_unlock(&ioc->sas_topology_mutex);
+
+	printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
+	    "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
+	    (unsigned long long)sas_address);
+
+	mptsas_expander_refresh(ioc, port_info);
+}
+
+/**
+ * mptsas_delete_expander_siblings - remove siblings attached to expander
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @parent: the parent port_info object
+ * @expander: the expander port_info object
+ **/
+static void
+mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
+    *parent, struct mptsas_portinfo *expander)
+{
+	struct mptsas_phyinfo *phy_info;
+	struct mptsas_portinfo *port_info;
+	struct sas_rphy *rphy;
+	int i;
+
+	phy_info = expander->phy_info;
+	for (i = 0; i < expander->num_phys; i++, phy_info++) {
+		rphy = mptsas_get_rphy(phy_info);
+		if (!rphy)
+			continue;
+		if (rphy->identify.device_type == SAS_END_DEVICE)
+			mptsas_del_end_device(ioc, phy_info);
+	}
+
+	phy_info = expander->phy_info;
+	for (i = 0; i < expander->num_phys; i++, phy_info++) {
+		rphy = mptsas_get_rphy(phy_info);
+		if (!rphy)
+			continue;
+		if (rphy->identify.device_type ==
+		    MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
+		    rphy->identify.device_type ==
+		    MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
+			port_info = mptsas_find_portinfo_by_sas_address(ioc,
+			    rphy->identify.sas_address);
+			if (!port_info)
+				continue;
+			if (port_info == parent) /* backlink rphy */
+				continue;
+			/*
+			Delete this expander even if the expdevpage is exists
+			because the parent expander is already deleted
+			*/
+			mptsas_expander_delete(ioc, port_info, 1);
+		}
+	}
+}
+
+
+/**
+ *	mptsas_expander_delete - remove this expander
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@port_info: expander port_info struct
+ *	@force: Flag to forcefully delete the expander
+ *
+ **/
+
+static void mptsas_expander_delete(MPT_ADAPTER *ioc,
+		struct mptsas_portinfo *port_info, u8 force)
+{
+
+	struct mptsas_portinfo *parent;
+	int		i;
+	u64		expander_sas_address;
+	struct mptsas_phyinfo *phy_info;
+	struct mptsas_portinfo buffer;
+	struct mptsas_portinfo_details *port_details;
+	struct sas_port *port;
+
+	if (!port_info)
+		return;
+
+	/* see if expander is still there before deleting */
+	mptsas_sas_expander_pg0(ioc, &buffer,
+	    (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
+	    MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
+	    port_info->phy_info[0].identify.handle);
+
+	if (buffer.num_phys) {
+		kfree(buffer.phy_info);
+		if (!force)
+			return;
+	}
+
+
+	/*
+	 * Obtain the port_info instance to the parent port
+	 */
+	port_details = NULL;
+	expander_sas_address =
+	    port_info->phy_info[0].identify.sas_address;
+	parent = mptsas_find_portinfo_by_handle(ioc,
+	    port_info->phy_info[0].identify.handle_parent);
+	mptsas_delete_expander_siblings(ioc, parent, port_info);
+	if (!parent)
+		goto out;
+
+	/*
+	 * Delete rphys in the parent that point
+	 * to this expander.
+	 */
+	phy_info = parent->phy_info;
+	port = NULL;
+	for (i = 0; i < parent->num_phys; i++, phy_info++) {
+		if (!phy_info->phy)
+			continue;
+		if (phy_info->attached.sas_address !=
+		    expander_sas_address)
+			continue;
+		if (!port) {
+			port = mptsas_get_port(phy_info);
+			port_details = phy_info->port_details;
+		}
+		dev_printk(KERN_DEBUG, &phy_info->phy->dev,
+		    MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
+		    phy_info->phy_id, phy_info->phy);
+		sas_port_delete_phy(port, phy_info->phy);
+	}
+	if (port) {
+		dev_printk(KERN_DEBUG, &port->dev,
+		    MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
+		    ioc->name, port->port_identifier,
+		    (unsigned long long)expander_sas_address);
+		sas_port_delete(port);
+		mptsas_port_delete(ioc, port_details);
+	}
+ out:
+
+	printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
+	    "sas_addr (0x%llx)\n",  ioc->name, port_info->num_phys,
+	    (unsigned long long)expander_sas_address);
+
+	/*
+	 * free link
+	 */
+	list_del(&port_info->list);
+	kfree(port_info->phy_info);
+	kfree(port_info);
+}
+
+
+/**
+ * mptsas_send_expander_event - expanders events
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @expander_data: event data
+ *
+ *
+ * This function handles adding, removing, and refreshing
+ * device handles within the expander objects.
  */
 static void
+mptsas_send_expander_event(struct fw_event_work *fw_event)
+{
+	MPT_ADAPTER *ioc;
+	MpiEventDataSasExpanderStatusChange_t *expander_data;
+	struct mptsas_portinfo *port_info;
+	__le64 sas_address;
+	int i;
+
+	ioc = fw_event->ioc;
+	expander_data = (MpiEventDataSasExpanderStatusChange_t *)
+	    fw_event->event_data;
+	memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
+	port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
+
+	if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
+		if (port_info) {
+			for (i = 0; i < port_info->num_phys; i++) {
+				port_info->phy_info[i].portinfo = port_info;
+				port_info->phy_info[i].handle =
+				    le16_to_cpu(expander_data->DevHandle);
+				port_info->phy_info[i].identify.sas_address =
+				    le64_to_cpu(sas_address);
+				port_info->phy_info[i].identify.handle_parent =
+				    le16_to_cpu(expander_data->ParentDevHandle);
+			}
+			mptsas_expander_refresh(ioc, port_info);
+		} else if (!port_info && expander_data->NumPhys)
+			mptsas_expander_event_add(ioc, expander_data);
+	} else if (expander_data->ReasonCode ==
+	    MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
+		mptsas_expander_delete(ioc, port_info, 0);
+
+	mptsas_free_fw_event(ioc, fw_event);
+}
+
+
+/**
+ * mptsas_expander_add -
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @handle:
+ *
+ */
+struct mptsas_portinfo *
+mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
+{
+	struct mptsas_portinfo buffer, *port_info;
+	int i;
+
+	if ((mptsas_sas_expander_pg0(ioc, &buffer,
+	    (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
+	    MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
+		return NULL;
+
+	port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
+	if (!port_info) {
+		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+		"%s: exit at line=%d\n", ioc->name,
+		__func__, __LINE__));
+		return NULL;
+	}
+	port_info->num_phys = buffer.num_phys;
+	port_info->phy_info = buffer.phy_info;
+	for (i = 0; i < port_info->num_phys; i++)
+		port_info->phy_info[i].portinfo = port_info;
+	mutex_lock(&ioc->sas_topology_mutex);
+	list_add_tail(&port_info->list, &ioc->sas_topology);
+	mutex_unlock(&ioc->sas_topology_mutex);
+	printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
+	    "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
+	    (unsigned long long)buffer.phy_info[0].identify.sas_address);
+	mptsas_expander_refresh(ioc, port_info);
+	return port_info;
+}
+
+static void
+mptsas_send_link_status_event(struct fw_event_work *fw_event)
+{
+	MPT_ADAPTER *ioc;
+	MpiEventDataSasPhyLinkStatus_t *link_data;
+	struct mptsas_portinfo *port_info;
+	struct mptsas_phyinfo *phy_info = NULL;
+	__le64 sas_address;
+	u8 phy_num;
+	u8 link_rate;
+
+	ioc = fw_event->ioc;
+	link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
+
+	memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
+	sas_address = le64_to_cpu(sas_address);
+	link_rate = link_data->LinkRates >> 4;
+	phy_num = link_data->PhyNum;
+
+	port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
+	if (port_info) {
+		phy_info = &port_info->phy_info[phy_num];
+		if (phy_info)
+			phy_info->negotiated_link_rate = link_rate;
+	}
+
+	if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
+	    link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
+
+		if (!port_info) {
+			if (ioc->old_sas_discovery_protocal) {
+				port_info = mptsas_expander_add(ioc,
+					le16_to_cpu(link_data->DevHandle));
+				if (port_info)
+					goto out;
+			}
+			goto out;
+		}
+
+		if (port_info == ioc->hba_port_info)
+			mptsas_probe_hba_phys(ioc);
+		else
+			mptsas_expander_refresh(ioc, port_info);
+	} else if (phy_info && phy_info->phy) {
+		if (link_rate ==  MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
+			phy_info->phy->negotiated_linkrate =
+			    SAS_PHY_DISABLED;
+		else if (link_rate ==
+		    MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
+			phy_info->phy->negotiated_linkrate =
+			    SAS_LINK_RATE_FAILED;
+		else
+			phy_info->phy->negotiated_linkrate =
+			    SAS_LINK_RATE_UNKNOWN;
+	}
+ out:
+	mptsas_free_fw_event(ioc, fw_event);
+}
+
+static void
+mptsas_not_responding_devices(MPT_ADAPTER *ioc)
+{
+	struct mptsas_portinfo buffer, *port_info;
+	struct mptsas_device_info	*sas_info;
+	struct mptsas_devinfo sas_device;
+	u32	handle;
+	VirtTarget *vtarget = NULL;
+	struct mptsas_phyinfo *phy_info;
+	u8 found_expander;
+	int retval, retry_count;
+	unsigned long flags;
+
+	mpt_findImVolumes(ioc);
+
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+	if (ioc->ioc_reset_in_progress) {
+		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		   "%s: exiting due to a parallel reset \n", ioc->name,
+		    __func__));
+		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+		return;
+	}
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+	/* devices, logical volumes */
+	mutex_lock(&ioc->sas_device_info_mutex);
+ redo_device_scan:
+	list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
+		if (sas_info->is_cached)
+			continue;
+		if (!sas_info->is_logical_volume) {
+			sas_device.handle = 0;
+			retry_count = 0;
+retry_page:
+			retval = mptsas_sas_device_pg0(ioc, &sas_device,
+				(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
+				<< MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+				(sas_info->fw.channel << 8) +
+				sas_info->fw.id);
+
+			if (sas_device.handle)
+				continue;
+			if (retval == -EBUSY) {
+				spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+				if (ioc->ioc_reset_in_progress) {
+					dfailprintk(ioc,
+					printk(MYIOC_s_DEBUG_FMT
+					"%s: exiting due to reset\n",
+					ioc->name, __func__));
+					spin_unlock_irqrestore
+					(&ioc->taskmgmt_lock, flags);
+					mutex_unlock(&ioc->
+					sas_device_info_mutex);
+					return;
+				}
+				spin_unlock_irqrestore(&ioc->taskmgmt_lock,
+				flags);
+			}
+
+			if (retval && (retval != -ENODEV)) {
+				if (retry_count < 10) {
+					retry_count++;
+					goto retry_page;
+				} else {
+					devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+					"%s: Config page retry exceeded retry "
+					"count deleting device 0x%llx\n",
+					ioc->name, __func__,
+					sas_info->sas_address));
+				}
+			}
+
+			/* delete device */
+			vtarget = mptsas_find_vtarget(ioc,
+				sas_info->fw.channel, sas_info->fw.id);
+
+			if (vtarget)
+				vtarget->deleted = 1;
+
+			phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+					sas_info->sas_address);
+
+			if (phy_info) {
+				mptsas_del_end_device(ioc, phy_info);
+				goto redo_device_scan;
+			}
+		} else
+			mptsas_volume_delete(ioc, sas_info->fw.id);
+	}
+	mutex_lock(&ioc->sas_device_info_mutex);
+
+	/* expanders */
+	mutex_lock(&ioc->sas_topology_mutex);
+ redo_expander_scan:
+	list_for_each_entry(port_info, &ioc->sas_topology, list) {
+
+		if (port_info->phy_info &&
+		    (!(port_info->phy_info[0].identify.device_info &
+		    MPI_SAS_DEVICE_INFO_SMP_TARGET)))
+			continue;
+		found_expander = 0;
+		handle = 0xFFFF;
+		while (!mptsas_sas_expander_pg0(ioc, &buffer,
+		    (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
+		     MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
+		    !found_expander) {
+
+			handle = buffer.phy_info[0].handle;
+			if (buffer.phy_info[0].identify.sas_address ==
+			    port_info->phy_info[0].identify.sas_address) {
+				found_expander = 1;
+			}
+			kfree(buffer.phy_info);
+		}
+
+		if (!found_expander) {
+			mptsas_expander_delete(ioc, port_info, 0);
+			goto redo_expander_scan;
+		}
+	}
+	mutex_lock(&ioc->sas_topology_mutex);
+}
+
+/**
+ *	mptsas_probe_expanders - adding expanders
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
+static void
+mptsas_probe_expanders(MPT_ADAPTER *ioc)
+{
+	struct mptsas_portinfo buffer, *port_info;
+	u32 			handle;
+	int i;
+
+	handle = 0xFFFF;
+	while (!mptsas_sas_expander_pg0(ioc, &buffer,
+	    (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
+	     MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
+
+		handle = buffer.phy_info[0].handle;
+		port_info = mptsas_find_portinfo_by_sas_address(ioc,
+		    buffer.phy_info[0].identify.sas_address);
+
+		if (port_info) {
+			/* refreshing handles */
+			for (i = 0; i < buffer.num_phys; i++) {
+				port_info->phy_info[i].handle = handle;
+				port_info->phy_info[i].identify.handle_parent =
+				    buffer.phy_info[0].identify.handle_parent;
+			}
+			mptsas_expander_refresh(ioc, port_info);
+			kfree(buffer.phy_info);
+			continue;
+		}
+
+		port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
+		if (!port_info) {
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+			"%s: exit at line=%d\n", ioc->name,
+			__func__, __LINE__));
+			return;
+		}
+		port_info->num_phys = buffer.num_phys;
+		port_info->phy_info = buffer.phy_info;
+		for (i = 0; i < port_info->num_phys; i++)
+			port_info->phy_info[i].portinfo = port_info;
+		mutex_lock(&ioc->sas_topology_mutex);
+		list_add_tail(&port_info->list, &ioc->sas_topology);
+		mutex_unlock(&ioc->sas_topology_mutex);
+		printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
+		    "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
+	    (unsigned long long)buffer.phy_info[0].identify.sas_address);
+		mptsas_expander_refresh(ioc, port_info);
+	}
+}
+
+static void
+mptsas_probe_devices(MPT_ADAPTER *ioc)
+{
+	u16 handle;
+	struct mptsas_devinfo sas_device;
+	struct mptsas_phyinfo *phy_info;
+
+	handle = 0xFFFF;
+	while (!(mptsas_sas_device_pg0(ioc, &sas_device,
+	    MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
+
+		handle = sas_device.handle;
+
+		if ((sas_device.device_info &
+		     (MPI_SAS_DEVICE_INFO_SSP_TARGET |
+		      MPI_SAS_DEVICE_INFO_STP_TARGET |
+		      MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
+			continue;
+
+		phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
+		if (!phy_info)
+			continue;
+
+		if (mptsas_get_rphy(phy_info))
+			continue;
+
+		mptsas_add_end_device(ioc, phy_info);
+	}
+}
+
+/**
+ *	mptsas_scan_sas_topology -
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@sas_address:
+ *
+ **/
+static void
 mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
 {
-	u32 handle = 0xFFFF;
+	struct scsi_device *sdev;
 	int i;
 
-	mutex_lock(&ioc->sas_discovery_mutex);
 	mptsas_probe_hba_phys(ioc);
-	while (!mptsas_probe_expander_phys(ioc, &handle))
-		;
+	mptsas_probe_expanders(ioc);
+	mptsas_probe_devices(ioc);
+
 	/*
 	  Reporting RAID volumes.
 	*/
-	if (!ioc->ir_firmware)
-		goto out;
-	if (!ioc->raid_data.pIocPg2)
-		goto out;
-	if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
-		goto out;
+	if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
+	    !ioc->raid_data.pIocPg2->NumActiveVolumes)
+		return;
 	for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+		sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
+		    ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
+		if (sdev) {
+			scsi_device_put(sdev);
+			continue;
+		}
+		printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
+		    "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
+		    ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
 		scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
 		    ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
 	}
+}
+
+
+static void
+mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
+{
+	MPT_ADAPTER *ioc;
+	EventDataQueueFull_t *qfull_data;
+	struct mptsas_device_info *sas_info;
+	struct scsi_device	*sdev;
+	int depth;
+	int id = -1;
+	int channel = -1;
+	int fw_id, fw_channel;
+	u16 current_depth;
+
+
+	ioc = fw_event->ioc;
+	qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
+	fw_id = qfull_data->TargetID;
+	fw_channel = qfull_data->Bus;
+	current_depth = le16_to_cpu(qfull_data->CurrentDepth);
+
+	/* if hidden raid component, look for the volume id */
+	mutex_lock(&ioc->sas_device_info_mutex);
+	if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
+		list_for_each_entry(sas_info, &ioc->sas_device_info_list,
+		    list) {
+			if (sas_info->is_cached ||
+			    sas_info->is_logical_volume)
+				continue;
+			if (sas_info->is_hidden_raid_component &&
+			    (sas_info->fw.channel == fw_channel &&
+			    sas_info->fw.id == fw_id)) {
+				id = sas_info->volume_id;
+				channel = MPTSAS_RAID_CHANNEL;
+				goto out;
+			}
+		}
+	} else {
+		list_for_each_entry(sas_info, &ioc->sas_device_info_list,
+		    list) {
+			if (sas_info->is_cached ||
+			    sas_info->is_hidden_raid_component ||
+			    sas_info->is_logical_volume)
+				continue;
+			if (sas_info->fw.channel == fw_channel &&
+			    sas_info->fw.id == fw_id) {
+				id = sas_info->os.id;
+				channel = sas_info->os.channel;
+				goto out;
+			}
+		}
+
+	}
+
  out:
-	mutex_unlock(&ioc->sas_discovery_mutex);
+	mutex_unlock(&ioc->sas_device_info_mutex);
+
+	if (id != -1) {
+		shost_for_each_device(sdev, ioc->sh) {
+			if (sdev->id == id && sdev->channel == channel) {
+				if (current_depth > sdev->queue_depth) {
+					sdev_printk(KERN_INFO, sdev,
+					    "strange observation, the queue "
+					    "depth is (%d) meanwhile fw queue "
+					    "depth (%d)\n", sdev->queue_depth,
+					    current_depth);
+					continue;
+				}
+				depth = scsi_track_queue_full(sdev,
+				    current_depth - 1);
+				if (depth > 0)
+					sdev_printk(KERN_INFO, sdev,
+					"Queue depth reduced to (%d)\n",
+					   depth);
+				else if (depth < 0)
+					sdev_printk(KERN_INFO, sdev,
+					"Tagged Command Queueing is being "
+					"disabled\n");
+				else if (depth == 0)
+					sdev_printk(KERN_INFO, sdev,
+					"Queue depth not changed yet\n");
+			}
+		}
+	}
+
+	mptsas_free_fw_event(ioc, fw_event);
 }
 
-/*
- * Work queue thread to handle Runtime discovery
- * Mere purpose is the hot add/delete of expanders
- *(Mutex UNLOCKED)
- */
-static void
-__mptsas_discovery_work(MPT_ADAPTER *ioc)
-{
-	u32 handle = 0xFFFF;
-
-	ioc->sas_discovery_runtime=1;
-	mptsas_delete_expander_phys(ioc);
-	mptsas_probe_hba_phys(ioc);
-	while (!mptsas_probe_expander_phys(ioc, &handle))
-		;
-	ioc->sas_discovery_runtime=0;
-}
-
-/*
- * Work queue thread to handle Runtime discovery
- * Mere purpose is the hot add/delete of expanders
- *(Mutex LOCKED)
- */
-static void
-mptsas_discovery_work(struct work_struct *work)
-{
-	struct mptsas_discovery_event *ev =
-		container_of(work, struct mptsas_discovery_event, work);
-	MPT_ADAPTER *ioc = ev->ioc;
-
-	mutex_lock(&ioc->sas_discovery_mutex);
-	__mptsas_discovery_work(ioc);
-	mutex_unlock(&ioc->sas_discovery_mutex);
-	kfree(ev);
-}
 
 static struct mptsas_phyinfo *
 mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
@@ -2429,69 +3786,80 @@
 	return phy_info;
 }
 
+/**
+ *	mptsas_find_phyinfo_by_phys_disk_num -
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@phys_disk_num:
+ *	@channel:
+ *	@id:
+ *
+ **/
 static struct mptsas_phyinfo *
-mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
+mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
+	u8 channel, u8 id)
 {
-	struct mptsas_portinfo *port_info;
 	struct mptsas_phyinfo *phy_info = NULL;
+	struct mptsas_portinfo *port_info;
+	RaidPhysDiskPage1_t *phys_disk = NULL;
+	int num_paths;
+	u64 sas_address = 0;
 	int i;
 
-	mutex_lock(&ioc->sas_topology_mutex);
-	list_for_each_entry(port_info, &ioc->sas_topology, list) {
-		for (i = 0; i < port_info->num_phys; i++) {
-			if (!mptsas_is_end_device(
-				&port_info->phy_info[i].attached))
-				continue;
-			if (port_info->phy_info[i].attached.id != id)
-				continue;
-			if (port_info->phy_info[i].attached.channel != channel)
-				continue;
-			phy_info = &port_info->phy_info[i];
-			break;
+	phy_info = NULL;
+	if (!ioc->raid_data.pIocPg3)
+		return NULL;
+	/* dual port support */
+	num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
+	if (!num_paths)
+		goto out;
+	phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
+	   (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
+	if (!phys_disk)
+		goto out;
+	mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
+	for (i = 0; i < num_paths; i++) {
+		if ((phys_disk->Path[i].Flags & 1) != 0)
+			/* entry no longer valid */
+			continue;
+		if ((id == phys_disk->Path[i].PhysDiskID) &&
+		    (channel == phys_disk->Path[i].PhysDiskBus)) {
+			memcpy(&sas_address, &phys_disk->Path[i].WWID,
+				sizeof(u64));
+			phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+					sas_address);
+			goto out;
 		}
 	}
-	mutex_unlock(&ioc->sas_topology_mutex);
-	return phy_info;
-}
 
-static struct mptsas_phyinfo *
-mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
-{
-	struct mptsas_portinfo *port_info;
-	struct mptsas_phyinfo *phy_info = NULL;
-	int i;
+ out:
+	kfree(phys_disk);
+	if (phy_info)
+		return phy_info;
 
+	/*
+	 * Extra code to handle RAID0 case, where the sas_address is not updated
+	 * in phys_disk_page_1 when hotswapped
+	 */
 	mutex_lock(&ioc->sas_topology_mutex);
 	list_for_each_entry(port_info, &ioc->sas_topology, list) {
-		for (i = 0; i < port_info->num_phys; i++) {
+		for (i = 0; i < port_info->num_phys && !phy_info; i++) {
 			if (!mptsas_is_end_device(
 				&port_info->phy_info[i].attached))
 				continue;
 			if (port_info->phy_info[i].attached.phys_disk_num == ~0)
 				continue;
-			if (port_info->phy_info[i].attached.phys_disk_num != id)
-				continue;
-			if (port_info->phy_info[i].attached.channel != channel)
-				continue;
-			phy_info = &port_info->phy_info[i];
-			break;
+			if ((port_info->phy_info[i].attached.phys_disk_num ==
+			    phys_disk_num) &&
+			    (port_info->phy_info[i].attached.id == id) &&
+			    (port_info->phy_info[i].attached.channel ==
+			     channel))
+				phy_info = &port_info->phy_info[i];
 		}
 	}
 	mutex_unlock(&ioc->sas_topology_mutex);
 	return phy_info;
 }
 
-/*
- * Work queue thread to clear the persitency table
- */
-static void
-mptsas_persist_clear_table(struct work_struct *work)
-{
-	MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
-
-	mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
-}
-
 static void
 mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
 {
@@ -2517,7 +3885,8 @@
 	pRaidVolumePage0_t		buffer = NULL;
 	RaidPhysDiskPage0_t 		phys_disk;
 	int				i;
-	struct mptsas_hotplug_event 	*ev;
+	struct mptsas_phyinfo	*phy_info;
+	struct mptsas_devinfo		sas_device;
 
 	memset(&cfg, 0 , sizeof(CONFIGPARMS));
 	memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
@@ -2557,20 +3926,16 @@
 		    buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
 			continue;
 
-		ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-		if (!ev) {
-			printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
-			goto out;
-		}
+		if (mptsas_sas_device_pg0(ioc, &sas_device,
+		    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+		     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+			(phys_disk.PhysDiskBus << 8) +
+			phys_disk.PhysDiskID))
+			continue;
 
-		INIT_WORK(&ev->work, mptsas_hotplug_work);
-		ev->ioc = ioc;
-		ev->id = phys_disk.PhysDiskID;
-		ev->channel = phys_disk.PhysDiskBus;
-		ev->phys_disk_num_valid = 1;
-		ev->phys_disk_num = phys_disk.PhysDiskNum;
-		ev->event_type = MPTSAS_ADD_DEVICE;
-		schedule_work(&ev->work);
+		phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+		    sas_device.sas_address);
+		mptsas_add_end_device(ioc, phy_info);
 	}
 
  out:
@@ -2582,417 +3947,386 @@
  * Work queue thread to handle SAS hotplug events
  */
 static void
-mptsas_hotplug_work(struct work_struct *work)
+mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
+    struct mptsas_hotplug_event *hot_plug_info)
 {
-	struct mptsas_hotplug_event *ev =
-		container_of(work, struct mptsas_hotplug_event, work);
-
-	MPT_ADAPTER *ioc = ev->ioc;
 	struct mptsas_phyinfo *phy_info;
-	struct sas_rphy *rphy;
-	struct sas_port *port;
-	struct scsi_device *sdev;
 	struct scsi_target * starget;
-	struct sas_identify identify;
-	char *ds = NULL;
 	struct mptsas_devinfo sas_device;
 	VirtTarget *vtarget;
-	VirtDevice *vdevice;
+	int i;
 
-	mutex_lock(&ioc->sas_discovery_mutex);
-	switch (ev->event_type) {
-	case MPTSAS_DEL_DEVICE:
+	switch (hot_plug_info->event_type) {
 
-		phy_info = NULL;
-		if (ev->phys_disk_num_valid) {
-			if (ev->hidden_raid_component){
-				if (mptsas_sas_device_pg0(ioc, &sas_device,
-				    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
-				     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
-				    (ev->channel << 8) + ev->id)) {
-					dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-					"%s: exit at line=%d\n", ioc->name,
-						__func__, __LINE__));
-					break;
-				}
-				phy_info = mptsas_find_phyinfo_by_sas_address(
-				    ioc, sas_device.sas_address);
-			}else
-				phy_info = mptsas_find_phyinfo_by_phys_disk_num(
-				    ioc, ev->channel, ev->phys_disk_num);
-		}
+	case MPTSAS_ADD_PHYSDISK:
 
-		if (!phy_info)
-			phy_info = mptsas_find_phyinfo_by_target(ioc,
-			    ev->channel, ev->id);
-
-		/*
-		 * Sanity checks, for non-existing phys and remote rphys.
-		 */
-		if (!phy_info){
-			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-				"%s: exit at line=%d\n", ioc->name,
-				__func__, __LINE__));
+		if (!ioc->raid_data.pIocPg2)
 			break;
-		}
-		if (!phy_info->port_details) {
-			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-				"%s: exit at line=%d\n", ioc->name,
-			       	__func__, __LINE__));
-			break;
-		}
-		rphy = mptsas_get_rphy(phy_info);
-		if (!rphy) {
-			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-				"%s: exit at line=%d\n", ioc->name,
-			       	__func__, __LINE__));
-			break;
-		}
 
-		port = mptsas_get_port(phy_info);
-		if (!port) {
-			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-				"%s: exit at line=%d\n", ioc->name,
-			       	__func__, __LINE__));
-			break;
-		}
-
-		starget = mptsas_get_starget(phy_info);
-		if (starget) {
-			vtarget = starget->hostdata;
-
-			if (!vtarget) {
-				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-					"%s: exit at line=%d\n", ioc->name,
-					__func__, __LINE__));
-				break;
-			}
-
-			/*
-			 * Handling  RAID components
-			 */
-			if (ev->phys_disk_num_valid &&
-			    ev->hidden_raid_component) {
-				printk(MYIOC_s_INFO_FMT
-				    "RAID Hidding: channel=%d, id=%d, "
-				    "physdsk %d \n", ioc->name, ev->channel,
-				    ev->id, ev->phys_disk_num);
-				vtarget->id = ev->phys_disk_num;
-				vtarget->tflags |=
-				    MPT_TARGET_FLAGS_RAID_COMPONENT;
-				mptsas_reprobe_target(starget, 1);
-				phy_info->attached.phys_disk_num =
-				    ev->phys_disk_num;
-			break;
+		for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+			if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
+			    hot_plug_info->id) {
+				printk(MYIOC_s_WARN_FMT "firmware bug: unable "
+				    "to add hidden disk - target_id matchs "
+				    "volume_id\n", ioc->name);
+				mptsas_free_fw_event(ioc, fw_event);
+				return;
 			}
 		}
+		mpt_findImVolumes(ioc);
 
-		if (phy_info->attached.device_info &
-		    MPI_SAS_DEVICE_INFO_SSP_TARGET)
-			ds = "ssp";
-		if (phy_info->attached.device_info &
-		    MPI_SAS_DEVICE_INFO_STP_TARGET)
-			ds = "stp";
-		if (phy_info->attached.device_info &
-		    MPI_SAS_DEVICE_INFO_SATA_DEVICE)
-			ds = "sata";
-
-		printk(MYIOC_s_INFO_FMT
-		       "removing %s device, channel %d, id %d, phy %d\n",
-		       ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
-		dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
-		    "delete port (%d)\n", ioc->name, port->port_identifier);
-		sas_port_delete(port);
-		mptsas_port_delete(ioc, phy_info->port_details);
-		break;
 	case MPTSAS_ADD_DEVICE:
+		memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
+		mptsas_sas_device_pg0(ioc, &sas_device,
+		    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+		    MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+		    (hot_plug_info->channel << 8) +
+		    hot_plug_info->id);
 
-		if (ev->phys_disk_num_valid)
-			mpt_findImVolumes(ioc);
+		if (!sas_device.handle)
+			return;
 
-		/*
-		 * Refresh sas device pg0 data
-		 */
+		phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
+		if (!phy_info)
+			break;
+
+		if (mptsas_get_rphy(phy_info))
+			break;
+
+		mptsas_add_end_device(ioc, phy_info);
+		break;
+
+	case MPTSAS_DEL_DEVICE:
+		phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+		    hot_plug_info->sas_address);
+		mptsas_del_end_device(ioc, phy_info);
+		break;
+
+	case MPTSAS_DEL_PHYSDISK:
+
+		mpt_findImVolumes(ioc);
+
+		phy_info = mptsas_find_phyinfo_by_phys_disk_num(
+				ioc, hot_plug_info->phys_disk_num,
+				hot_plug_info->channel,
+				hot_plug_info->id);
+		mptsas_del_end_device(ioc, phy_info);
+		break;
+
+	case MPTSAS_ADD_PHYSDISK_REPROBE:
+
 		if (mptsas_sas_device_pg0(ioc, &sas_device,
 		    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
 		     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
-			(ev->channel << 8) + ev->id)) {
-				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-					"%s: exit at line=%d\n", ioc->name,
-					__func__, __LINE__));
+		    (hot_plug_info->channel << 8) + hot_plug_info->id)) {
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+			"%s: fw_id=%d exit at line=%d\n", ioc->name,
+				 __func__, hot_plug_info->id, __LINE__));
 			break;
 		}
 
-		__mptsas_discovery_work(ioc);
+		phy_info = mptsas_find_phyinfo_by_sas_address(
+		    ioc, sas_device.sas_address);
 
-		phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
-				sas_device.sas_address);
-
-		if (!phy_info || !phy_info->port_details) {
+		if (!phy_info) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-				"%s: exit at line=%d\n", ioc->name,
-			       	__func__, __LINE__));
+				"%s: fw_id=%d exit at line=%d\n", ioc->name,
+				 __func__, hot_plug_info->id, __LINE__));
 			break;
 		}
 
 		starget = mptsas_get_starget(phy_info);
-		if (starget && (!ev->hidden_raid_component)){
+		if (!starget) {
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+				"%s: fw_id=%d exit at line=%d\n", ioc->name,
+				 __func__, hot_plug_info->id, __LINE__));
+			break;
+		}
 
-			vtarget = starget->hostdata;
+		vtarget = starget->hostdata;
+		if (!vtarget) {
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+				"%s: fw_id=%d exit at line=%d\n", ioc->name,
+				 __func__, hot_plug_info->id, __LINE__));
+			break;
+		}
 
-			if (!vtarget) {
+		mpt_findImVolumes(ioc);
+
+		starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
+		    "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
+		    ioc->name, hot_plug_info->channel, hot_plug_info->id,
+		    hot_plug_info->phys_disk_num, (unsigned long long)
+		    sas_device.sas_address);
+
+		vtarget->id = hot_plug_info->phys_disk_num;
+		vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
+		phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
+		mptsas_reprobe_target(starget, 1);
+		break;
+
+	case MPTSAS_DEL_PHYSDISK_REPROBE:
+
+		if (mptsas_sas_device_pg0(ioc, &sas_device,
+		    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+		     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+			(hot_plug_info->channel << 8) + hot_plug_info->id)) {
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-				    "%s: exit at line=%d\n", ioc->name,
-				    __func__, __LINE__));
-				break;
-			}
-			/*
-			 * Handling  RAID components
-			 */
-			if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
-				printk(MYIOC_s_INFO_FMT
-				    "RAID Exposing: channel=%d, id=%d, "
-				    "physdsk %d \n", ioc->name, ev->channel,
-				    ev->id, ev->phys_disk_num);
-				vtarget->tflags &=
-				    ~MPT_TARGET_FLAGS_RAID_COMPONENT;
-				vtarget->id = ev->id;
-				mptsas_reprobe_target(starget, 0);
-				phy_info->attached.phys_disk_num = ~0;
-			}
+				    "%s: fw_id=%d exit at line=%d\n",
+				    ioc->name, __func__,
+				    hot_plug_info->id, __LINE__));
 			break;
 		}
 
-		if (mptsas_get_rphy(phy_info)) {
+		phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+				sas_device.sas_address);
+		if (!phy_info) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-				"%s: exit at line=%d\n", ioc->name,
-			       	__func__, __LINE__));
-			if (ev->channel) printk("%d\n", __LINE__);
+			    "%s: fw_id=%d exit at line=%d\n", ioc->name,
+			 __func__, hot_plug_info->id, __LINE__));
 			break;
 		}
 
-		port = mptsas_get_port(phy_info);
-		if (!port) {
+		starget = mptsas_get_starget(phy_info);
+		if (!starget) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-				"%s: exit at line=%d\n", ioc->name,
-			       	__func__, __LINE__));
+			    "%s: fw_id=%d exit at line=%d\n", ioc->name,
+			 __func__, hot_plug_info->id, __LINE__));
 			break;
 		}
-		memcpy(&phy_info->attached, &sas_device,
-		    sizeof(struct mptsas_devinfo));
 
-		if (phy_info->attached.device_info &
-		    MPI_SAS_DEVICE_INFO_SSP_TARGET)
-			ds = "ssp";
-		if (phy_info->attached.device_info &
-		    MPI_SAS_DEVICE_INFO_STP_TARGET)
-			ds = "stp";
-		if (phy_info->attached.device_info &
-		    MPI_SAS_DEVICE_INFO_SATA_DEVICE)
-			ds = "sata";
-
-		printk(MYIOC_s_INFO_FMT
-		       "attaching %s device, channel %d, id %d, phy %d\n",
-		       ioc->name, ds, ev->channel, ev->id, ev->phy_id);
-
-		mptsas_parse_device_info(&identify, &phy_info->attached);
-		rphy = sas_end_device_alloc(port);
-		if (!rphy) {
+		vtarget = starget->hostdata;
+		if (!vtarget) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-				"%s: exit at line=%d\n", ioc->name,
-			       	__func__, __LINE__));
-			break; /* non-fatal: an rphy can be added later */
-		}
-
-		rphy->identify = identify;
-		if (sas_rphy_add(rphy)) {
-			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-				"%s: exit at line=%d\n", ioc->name,
-			       	__func__, __LINE__));
-			sas_rphy_free(rphy);
+			    "%s: fw_id=%d exit at line=%d\n", ioc->name,
+			 __func__, hot_plug_info->id, __LINE__));
 			break;
 		}
-		mptsas_set_rphy(ioc, phy_info, rphy);
+
+		if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+			    "%s: fw_id=%d exit at line=%d\n", ioc->name,
+			 __func__, hot_plug_info->id, __LINE__));
+			break;
+		}
+
+		mpt_findImVolumes(ioc);
+
+		starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
+		    " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
+		    ioc->name, hot_plug_info->channel, hot_plug_info->id,
+		    hot_plug_info->phys_disk_num, (unsigned long long)
+		    sas_device.sas_address);
+
+		vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
+		vtarget->id = hot_plug_info->id;
+		phy_info->attached.phys_disk_num = ~0;
+		mptsas_reprobe_target(starget, 0);
+		mptsas_add_device_component_by_fw(ioc,
+		    hot_plug_info->channel, hot_plug_info->id);
 		break;
+
 	case MPTSAS_ADD_RAID:
-		sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
-		    ev->id, 0);
-		if (sdev) {
-			scsi_device_put(sdev);
-			break;
-		}
-		printk(MYIOC_s_INFO_FMT
-		       "attaching raid volume, channel %d, id %d\n",
-		       ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
-		scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
+
 		mpt_findImVolumes(ioc);
+		printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
+		    "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
+		    hot_plug_info->id);
+		scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
+		    hot_plug_info->id, 0);
 		break;
+
 	case MPTSAS_DEL_RAID:
-		sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
-		    ev->id, 0);
-		if (!sdev)
-			break;
-		printk(MYIOC_s_INFO_FMT
-		       "removing raid volume, channel %d, id %d\n",
-		       ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
-		vdevice = sdev->hostdata;
-		scsi_remove_device(sdev);
-		scsi_device_put(sdev);
+
 		mpt_findImVolumes(ioc);
+		printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
+		    "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
+		    hot_plug_info->id);
+		scsi_remove_device(hot_plug_info->sdev);
+		scsi_device_put(hot_plug_info->sdev);
 		break;
+
 	case MPTSAS_ADD_INACTIVE_VOLUME:
+
+		mpt_findImVolumes(ioc);
 		mptsas_adding_inactive_raid_components(ioc,
-		    ev->channel, ev->id);
+		    hot_plug_info->channel, hot_plug_info->id);
 		break;
-	case MPTSAS_IGNORE_EVENT:
+
 	default:
 		break;
 	}
 
-	mutex_unlock(&ioc->sas_discovery_mutex);
-	kfree(ev);
+	mptsas_free_fw_event(ioc, fw_event);
 }
 
 static void
-mptsas_send_sas_event(MPT_ADAPTER *ioc,
-		EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
+mptsas_send_sas_event(struct fw_event_work *fw_event)
 {
-	struct mptsas_hotplug_event *ev;
-	u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
-	__le64 sas_address;
+	MPT_ADAPTER *ioc;
+	struct mptsas_hotplug_event hot_plug_info;
+	EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
+	u32 device_info;
+	u64 sas_address;
+
+	ioc = fw_event->ioc;
+	sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
+	    fw_event->event_data;
+	device_info = le32_to_cpu(sas_event_data->DeviceInfo);
 
 	if ((device_info &
-	     (MPI_SAS_DEVICE_INFO_SSP_TARGET |
-	      MPI_SAS_DEVICE_INFO_STP_TARGET |
-	      MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
+		(MPI_SAS_DEVICE_INFO_SSP_TARGET |
+		MPI_SAS_DEVICE_INFO_STP_TARGET |
+		MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
+		mptsas_free_fw_event(ioc, fw_event);
 		return;
+	}
+
+	if (sas_event_data->ReasonCode ==
+		MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
+		mptbase_sas_persist_operation(ioc,
+		MPI_SAS_OP_CLEAR_NOT_PRESENT);
+		mptsas_free_fw_event(ioc, fw_event);
+		return;
+	}
 
 	switch (sas_event_data->ReasonCode) {
 	case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
-
-		mptsas_target_reset_queue(ioc, sas_event_data);
-		break;
-
 	case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
-		ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-		if (!ev) {
-			printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
-			break;
-		}
-
-		INIT_WORK(&ev->work, mptsas_hotplug_work);
-		ev->ioc = ioc;
-		ev->handle = le16_to_cpu(sas_event_data->DevHandle);
-		ev->parent_handle =
-		    le16_to_cpu(sas_event_data->ParentDevHandle);
-		ev->channel = sas_event_data->Bus;
-		ev->id = sas_event_data->TargetID;
-		ev->phy_id = sas_event_data->PhyNum;
+		memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
+		hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
+		hot_plug_info.channel = sas_event_data->Bus;
+		hot_plug_info.id = sas_event_data->TargetID;
+		hot_plug_info.phy_id = sas_event_data->PhyNum;
 		memcpy(&sas_address, &sas_event_data->SASAddress,
-		    sizeof(__le64));
-		ev->sas_address = le64_to_cpu(sas_address);
-		ev->device_info = device_info;
-
+		    sizeof(u64));
+		hot_plug_info.sas_address = le64_to_cpu(sas_address);
+		hot_plug_info.device_info = device_info;
 		if (sas_event_data->ReasonCode &
 		    MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
-			ev->event_type = MPTSAS_ADD_DEVICE;
+			hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
 		else
-			ev->event_type = MPTSAS_DEL_DEVICE;
-		schedule_work(&ev->work);
+			hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
+		mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
 		break;
+
 	case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
-	/*
-	 * Persistent table is full.
-	 */
-		INIT_WORK(&ioc->sas_persist_task,
-		    mptsas_persist_clear_table);
-		schedule_work(&ioc->sas_persist_task);
+		mptbase_sas_persist_operation(ioc,
+		    MPI_SAS_OP_CLEAR_NOT_PRESENT);
+		mptsas_free_fw_event(ioc, fw_event);
 		break;
-	/*
-	 * TODO, handle other events
-	 */
+
 	case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
-	case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
+	/* TODO */
 	case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
-	case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
-	case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
-	case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
-	case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
+	/* TODO */
 	default:
+		mptsas_free_fw_event(ioc, fw_event);
 		break;
 	}
 }
+
 static void
-mptsas_send_raid_event(MPT_ADAPTER *ioc,
-		EVENT_DATA_RAID *raid_event_data)
+mptsas_send_raid_event(struct fw_event_work *fw_event)
 {
-	struct mptsas_hotplug_event *ev;
-	int status = le32_to_cpu(raid_event_data->SettingsStatus);
-	int state = (status >> 8) & 0xff;
+	MPT_ADAPTER *ioc;
+	EVENT_DATA_RAID *raid_event_data;
+	struct mptsas_hotplug_event hot_plug_info;
+	int status;
+	int state;
+	struct scsi_device *sdev = NULL;
+	VirtDevice *vdevice = NULL;
+	RaidPhysDiskPage0_t phys_disk;
 
-	if (ioc->bus_type != SAS)
-		return;
+	ioc = fw_event->ioc;
+	raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
+	status = le32_to_cpu(raid_event_data->SettingsStatus);
+	state = (status >> 8) & 0xff;
 
-	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-	if (!ev) {
-		printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
-		return;
+	memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
+	hot_plug_info.id = raid_event_data->VolumeID;
+	hot_plug_info.channel = raid_event_data->VolumeBus;
+	hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
+
+	if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
+	    raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
+	    raid_event_data->ReasonCode ==
+	    MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
+		sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
+		    hot_plug_info.id, 0);
+		hot_plug_info.sdev = sdev;
+		if (sdev)
+			vdevice = sdev->hostdata;
 	}
 
-	INIT_WORK(&ev->work, mptsas_hotplug_work);
-	ev->ioc = ioc;
-	ev->id = raid_event_data->VolumeID;
-	ev->channel = raid_event_data->VolumeBus;
-	ev->event_type = MPTSAS_IGNORE_EVENT;
+	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
+	    "ReasonCode=%02x\n", ioc->name, __func__,
+	    raid_event_data->ReasonCode));
 
 	switch (raid_event_data->ReasonCode) {
 	case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
-		ev->phys_disk_num_valid = 1;
-		ev->phys_disk_num = raid_event_data->PhysDiskNum;
-		ev->event_type = MPTSAS_ADD_DEVICE;
+		hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
 		break;
 	case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
-		ev->phys_disk_num_valid = 1;
-		ev->phys_disk_num = raid_event_data->PhysDiskNum;
-		ev->hidden_raid_component = 1;
-		ev->event_type = MPTSAS_DEL_DEVICE;
+		hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
 		break;
 	case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
 		switch (state) {
 		case MPI_PD_STATE_ONLINE:
 		case MPI_PD_STATE_NOT_COMPATIBLE:
-			ev->phys_disk_num_valid = 1;
-			ev->phys_disk_num = raid_event_data->PhysDiskNum;
-			ev->hidden_raid_component = 1;
-			ev->event_type = MPTSAS_ADD_DEVICE;
+			mpt_raid_phys_disk_pg0(ioc,
+			    raid_event_data->PhysDiskNum, &phys_disk);
+			hot_plug_info.id = phys_disk.PhysDiskID;
+			hot_plug_info.channel = phys_disk.PhysDiskBus;
+			hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
 			break;
+		case MPI_PD_STATE_FAILED:
 		case MPI_PD_STATE_MISSING:
 		case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
 		case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
 		case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
-			ev->phys_disk_num_valid = 1;
-			ev->phys_disk_num = raid_event_data->PhysDiskNum;
-			ev->event_type = MPTSAS_DEL_DEVICE;
+			hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
 			break;
 		default:
 			break;
 		}
 		break;
 	case MPI_EVENT_RAID_RC_VOLUME_DELETED:
-		ev->event_type = MPTSAS_DEL_RAID;
+		if (!sdev)
+			break;
+		vdevice->vtarget->deleted = 1; /* block IO */
+		hot_plug_info.event_type = MPTSAS_DEL_RAID;
 		break;
 	case MPI_EVENT_RAID_RC_VOLUME_CREATED:
-		ev->event_type = MPTSAS_ADD_RAID;
+		if (sdev) {
+			scsi_device_put(sdev);
+			break;
+		}
+		hot_plug_info.event_type = MPTSAS_ADD_RAID;
 		break;
 	case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
+		if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
+			if (!sdev)
+				break;
+			vdevice->vtarget->deleted = 1; /* block IO */
+			hot_plug_info.event_type = MPTSAS_DEL_RAID;
+			break;
+		}
 		switch (state) {
 		case MPI_RAIDVOL0_STATUS_STATE_FAILED:
 		case MPI_RAIDVOL0_STATUS_STATE_MISSING:
-			ev->event_type = MPTSAS_DEL_RAID;
+			if (!sdev)
+				break;
+			vdevice->vtarget->deleted = 1; /* block IO */
+			hot_plug_info.event_type = MPTSAS_DEL_RAID;
 			break;
 		case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
 		case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
-			ev->event_type = MPTSAS_ADD_RAID;
+			if (sdev) {
+				scsi_device_put(sdev);
+				break;
+			}
+			hot_plug_info.event_type = MPTSAS_ADD_RAID;
 			break;
 		default:
 			break;
@@ -3001,32 +4335,188 @@
 	default:
 		break;
 	}
-	schedule_work(&ev->work);
+
+	if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
+		mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
+	else
+		mptsas_free_fw_event(ioc, fw_event);
 }
 
-static void
-mptsas_send_discovery_event(MPT_ADAPTER *ioc,
-	EVENT_DATA_SAS_DISCOVERY *discovery_data)
+/**
+ *	mptsas_issue_tm - send mptsas internal tm request
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@type: Task Management type
+ *	@channel: channel number for task management
+ *	@id: Logical Target ID for reset (if appropriate)
+ *	@lun: Logical unit for reset (if appropriate)
+ *	@task_context: Context for the task to be aborted
+ *	@timeout: timeout for task management control
+ *
+ *	return 0 on success and -1 on failure:
+ *
+ */
+static int
+mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
+	int task_context, ulong timeout, u8 *issue_reset)
 {
-	struct mptsas_discovery_event *ev;
+	MPT_FRAME_HDR	*mf;
+	SCSITaskMgmt_t	*pScsiTm;
+	int		 retval;
+	unsigned long	 timeleft;
 
-	/*
-	 * DiscoveryStatus
-	 *
-	 * This flag will be non-zero when firmware
-	 * kicks off discovery, and return to zero
-	 * once its completed.
-	 */
-	if (discovery_data->DiscoveryStatus)
-		return;
+	*issue_reset = 0;
+	mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
+	if (mf == NULL) {
+		retval = -1; /* return failure */
+		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
+		    "msg frames!!\n", ioc->name));
+		goto out;
+	}
 
-	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-	if (!ev)
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
+	    "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
+	    "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
+	     type, timeout, channel, id, (unsigned long long)lun,
+	     task_context));
+
+	pScsiTm = (SCSITaskMgmt_t *) mf;
+	memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
+	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+	pScsiTm->TaskType = type;
+	pScsiTm->MsgFlags = 0;
+	pScsiTm->TargetID = id;
+	pScsiTm->Bus = channel;
+	pScsiTm->ChainOffset = 0;
+	pScsiTm->Reserved = 0;
+	pScsiTm->Reserved1 = 0;
+	pScsiTm->TaskMsgContext = task_context;
+	int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
+
+	INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+	CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
+	retval = 0;
+	mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
+
+	/* Now wait for the command to complete */
+	timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
+	    timeout*HZ);
+	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+		retval = -1; /* return failure */
+		dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
+		    "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
+		mpt_free_msg_frame(ioc, mf);
+		if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+			goto out;
+		*issue_reset = 1;
+		goto out;
+	}
+
+	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+		retval = -1; /* return failure */
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "TaskMgmt request: failed with no reply\n", ioc->name));
+		goto out;
+	}
+
+ out:
+	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+	return retval;
+}
+
+/**
+ *	mptsas_broadcast_primative_work - Handle broadcast primitives
+ *	@work: work queue payload containing info describing the event
+ *
+ *	this will be handled in workqueue context.
+ */
+static void
+mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
+{
+	MPT_ADAPTER *ioc = fw_event->ioc;
+	MPT_FRAME_HDR	*mf;
+	VirtDevice	*vdevice;
+	int			ii;
+	struct scsi_cmnd	*sc;
+	SCSITaskMgmtReply_t	*pScsiTmReply;
+	u8			issue_reset;
+	int			task_context;
+	u8			channel, id;
+	int			 lun;
+	u32			 termination_count;
+	u32			 query_count;
+
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+	    "%s - enter\n", ioc->name, __func__));
+
+	mutex_lock(&ioc->taskmgmt_cmds.mutex);
+	if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+		mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+		mptsas_requeue_fw_event(ioc, fw_event, 1000);
 		return;
-	INIT_WORK(&ev->work, mptsas_discovery_work);
-	ev->ioc = ioc;
-	schedule_work(&ev->work);
-};
+	}
+
+	issue_reset = 0;
+	termination_count = 0;
+	query_count = 0;
+	mpt_findImVolumes(ioc);
+	pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
+
+	for (ii = 0; ii < ioc->req_depth; ii++) {
+		if (ioc->fw_events_off)
+			goto out;
+		sc = mptscsih_get_scsi_lookup(ioc, ii);
+		if (!sc)
+			continue;
+		mf = MPT_INDEX_2_MFPTR(ioc, ii);
+		if (!mf)
+			continue;
+		task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
+		vdevice = sc->device->hostdata;
+		if (!vdevice || !vdevice->vtarget)
+			continue;
+		if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
+			continue; /* skip hidden raid components */
+		if (vdevice->vtarget->raidVolume)
+			continue; /* skip hidden raid components */
+		channel = vdevice->vtarget->channel;
+		id = vdevice->vtarget->id;
+		lun = vdevice->lun;
+		if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
+		    channel, id, (u64)lun, task_context, 30, &issue_reset))
+			goto out;
+		query_count++;
+		termination_count +=
+		    le32_to_cpu(pScsiTmReply->TerminationCount);
+		if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
+		    (pScsiTmReply->ResponseCode ==
+		    MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
+		    pScsiTmReply->ResponseCode ==
+		    MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
+			continue;
+		if (mptsas_issue_tm(ioc,
+		    MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
+		    channel, id, (u64)lun, 0, 30, &issue_reset))
+			goto out;
+		termination_count +=
+		    le32_to_cpu(pScsiTmReply->TerminationCount);
+	}
+
+ out:
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+	    "%s - exit, query_count = %d termination_count = %d\n",
+	    ioc->name, __func__, query_count, termination_count));
+
+	ioc->broadcast_aen_busy = 0;
+	mpt_clear_taskmgmt_in_progress_flag(ioc);
+	mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+
+	if (issue_reset) {
+		printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+		    ioc->name, __func__);
+		mpt_HardResetHandler(ioc, CAN_SLEEP);
+	}
+	mptsas_free_fw_event(ioc, fw_event);
+}
 
 /*
  * mptsas_send_ir2_event - handle exposing hidden disk when
@@ -3037,76 +4527,159 @@
  *
  */
 static void
-mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
+mptsas_send_ir2_event(struct fw_event_work *fw_event)
 {
-	struct mptsas_hotplug_event *ev;
+	MPT_ADAPTER	*ioc;
+	struct mptsas_hotplug_event hot_plug_info;
+	MPI_EVENT_DATA_IR2	*ir2_data;
+	u8 reasonCode;
+	RaidPhysDiskPage0_t phys_disk;
 
-	if (ir2_data->ReasonCode !=
-	    MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
+	ioc = fw_event->ioc;
+	ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
+	reasonCode = ir2_data->ReasonCode;
+
+	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
+	    "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
+
+	memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
+	hot_plug_info.id = ir2_data->TargetID;
+	hot_plug_info.channel = ir2_data->Bus;
+	switch (reasonCode) {
+	case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
+		hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
+		break;
+	case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
+		hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
+		hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
+		break;
+	case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
+		hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
+		mpt_raid_phys_disk_pg0(ioc,
+		    ir2_data->PhysDiskNum, &phys_disk);
+		hot_plug_info.id = phys_disk.PhysDiskID;
+		hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
+		break;
+	default:
+		mptsas_free_fw_event(ioc, fw_event);
 		return;
-
-	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-	if (!ev)
-		return;
-
-	INIT_WORK(&ev->work, mptsas_hotplug_work);
-	ev->ioc = ioc;
-	ev->id = ir2_data->TargetID;
-	ev->channel = ir2_data->Bus;
-	ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
-
-	schedule_work(&ev->work);
-};
+	}
+	mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
+}
 
 static int
 mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
 {
-	int rc=1;
-	u8 event = le32_to_cpu(reply->Event) & 0xFF;
+	u32 event = le32_to_cpu(reply->Event);
+	int sz, event_data_sz;
+	struct fw_event_work *fw_event;
+	unsigned long delay;
 
-	if (!ioc->sh)
-		goto out;
+	/* events turned off due to host reset or driver unloading */
+	if (ioc->fw_events_off)
+		return 0;
 
-	/*
-	 * sas_discovery_ignore_events
-	 *
-	 * This flag is to prevent anymore processing of
-	 * sas events once mptsas_remove function is called.
-	 */
-	if (ioc->sas_discovery_ignore_events) {
-		rc = mptscsih_event_process(ioc, reply);
-		goto out;
-	}
-
+	delay = msecs_to_jiffies(1);
 	switch (event) {
+	case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
+	{
+		EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
+		    (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
+		if (broadcast_event_data->Primitive !=
+		    MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
+			return 0;
+		if (ioc->broadcast_aen_busy)
+			return 0;
+		ioc->broadcast_aen_busy = 1;
+		break;
+	}
 	case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
-		mptsas_send_sas_event(ioc,
-			(EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
+	{
+		EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
+		    (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
+
+		if (sas_event_data->ReasonCode ==
+		    MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
+			mptsas_target_reset_queue(ioc, sas_event_data);
+			return 0;
+		}
 		break;
+	}
+	case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
+	{
+		MpiEventDataSasExpanderStatusChange_t *expander_data =
+		    (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
+
+		if (ioc->old_sas_discovery_protocal)
+			return 0;
+
+		if (expander_data->ReasonCode ==
+		    MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
+		    ioc->device_missing_delay)
+			delay = HZ * ioc->device_missing_delay;
+		break;
+	}
+	case MPI_EVENT_SAS_DISCOVERY:
+	{
+		u32 discovery_status;
+		EventDataSasDiscovery_t *discovery_data =
+		    (EventDataSasDiscovery_t *)reply->Data;
+
+		discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
+		ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
+		if (ioc->old_sas_discovery_protocal && !discovery_status)
+			mptsas_queue_rescan(ioc);
+		return 0;
+	}
 	case MPI_EVENT_INTEGRATED_RAID:
-		mptsas_send_raid_event(ioc,
-			(EVENT_DATA_RAID *)reply->Data);
-		break;
 	case MPI_EVENT_PERSISTENT_TABLE_FULL:
-		INIT_WORK(&ioc->sas_persist_task,
-		    mptsas_persist_clear_table);
-		schedule_work(&ioc->sas_persist_task);
-		break;
-	 case MPI_EVENT_SAS_DISCOVERY:
-		mptsas_send_discovery_event(ioc,
-			(EVENT_DATA_SAS_DISCOVERY *)reply->Data);
-		break;
 	case MPI_EVENT_IR2:
-		mptsas_send_ir2_event(ioc,
-		    (PTR_MPI_EVENT_DATA_IR2)reply->Data);
+	case MPI_EVENT_SAS_PHY_LINK_STATUS:
+	case MPI_EVENT_QUEUE_FULL:
 		break;
 	default:
-		rc = mptscsih_event_process(ioc, reply);
-		break;
+		return 0;
 	}
- out:
 
-	return rc;
+	event_data_sz = ((reply->MsgLength * 4) -
+	    offsetof(EventNotificationReply_t, Data));
+	sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
+	fw_event = kzalloc(sz, GFP_ATOMIC);
+	if (!fw_event) {
+		printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
+		 __func__, __LINE__);
+		return 0;
+	}
+	memcpy(fw_event->event_data, reply->Data, event_data_sz);
+	fw_event->event = event;
+	fw_event->ioc = ioc;
+	mptsas_add_fw_event(ioc, fw_event, delay);
+	return 0;
+}
+
+/* Delete a volume when no longer listed in ioc pg2
+ */
+static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
+{
+	struct scsi_device *sdev;
+	int i;
+
+	sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
+	if (!sdev)
+		return;
+	if (!ioc->raid_data.pIocPg2)
+		goto out;
+	if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
+		goto out;
+	for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
+		if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
+			goto release_sdev;
+ out:
+	printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
+	    "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
+	scsi_remove_device(sdev);
+ release_sdev:
+	scsi_device_put(sdev);
 }
 
 static int
@@ -3128,6 +4701,7 @@
 		return r;
 
 	ioc = pci_get_drvdata(pdev);
+	mptsas_fw_event_off(ioc);
 	ioc->DoneCtx = mptsasDoneCtx;
 	ioc->TaskCtx = mptsasTaskCtx;
 	ioc->InternalCtx = mptsasInternalCtx;
@@ -3211,17 +4785,15 @@
 	 * A slightly different algorithm is required for
 	 * 64bit SGEs.
 	 */
-	scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
-	if (sizeof(dma_addr_t) == sizeof(u64)) {
+	scale = ioc->req_sz/ioc->SGE_size;
+	if (ioc->sg_addr_size == sizeof(u64)) {
 		numSGE = (scale - 1) *
 		  (ioc->facts.MaxChainDepth-1) + scale +
-		  (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
-		  sizeof(u32));
+		  (ioc->req_sz - 60) / ioc->SGE_size;
 	} else {
 		numSGE = 1 + (scale - 1) *
 		  (ioc->facts.MaxChainDepth-1) + scale +
-		  (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
-		  sizeof(u32));
+		  (ioc->req_sz - 64) / ioc->SGE_size;
 	}
 
 	if (numSGE < sh->sg_tablesize) {
@@ -3251,9 +4823,6 @@
 
 	/* Clear the TM flags
 	 */
-	hd->tmPending = 0;
-	hd->tmState = TM_STATE_NONE;
-	hd->resetPending = 0;
 	hd->abortSCpnt = NULL;
 
 	/* Clear the pointer used to store
@@ -3273,10 +4842,11 @@
 
 	ioc->sas_data.ptClear = mpt_pt_clear;
 
-	init_waitqueue_head(&hd->scandv_waitq);
-	hd->scandv_wait_done = 0;
 	hd->last_queue_full = 0;
 	INIT_LIST_HEAD(&hd->target_reset_list);
+	INIT_LIST_HEAD(&ioc->sas_device_info_list);
+	mutex_init(&ioc->sas_device_info_mutex);
+
 	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 
 	if (ioc->sas_data.ptClear==1) {
@@ -3291,8 +4861,11 @@
 		goto out_mptsas_probe;
 	}
 
+	/* older firmware doesn't support expander events */
+	if ((ioc->facts.HeaderVersion >> 8) < 0xE)
+		ioc->old_sas_discovery_protocal = 1;
 	mptsas_scan_sas_topology(ioc);
-
+	mptsas_fw_event_on(ioc);
 	return 0;
 
  out_mptsas_probe:
@@ -3301,12 +4874,25 @@
 	return error;
 }
 
+void
+mptsas_shutdown(struct pci_dev *pdev)
+{
+	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+
+	mptsas_fw_event_off(ioc);
+	mptsas_cleanup_fw_event_q(ioc);
+}
+
 static void __devexit mptsas_remove(struct pci_dev *pdev)
 {
 	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
 	struct mptsas_portinfo *p, *n;
 	int i;
 
+	mptsas_shutdown(pdev);
+
+	mptsas_del_device_components(ioc);
+
 	ioc->sas_discovery_ignore_events = 1;
 	sas_remove_host(ioc->sh);
 
@@ -3315,11 +4901,12 @@
 		list_del(&p->list);
 		for (i = 0 ; i < p->num_phys ; i++)
 			mptsas_port_delete(ioc, p->phy_info[i].port_details);
+
 		kfree(p->phy_info);
 		kfree(p);
 	}
 	mutex_unlock(&ioc->sas_topology_mutex);
-
+	ioc->hba_port_info = NULL;
 	mptscsih_remove(pdev);
 }
 
@@ -3344,7 +4931,7 @@
 	.id_table	= mptsas_pci_table,
 	.probe		= mptsas_probe,
 	.remove		= __devexit_p(mptsas_remove),
-	.shutdown	= mptscsih_shutdown,
+	.shutdown	= mptsas_shutdown,
 #ifdef CONFIG_PM
 	.suspend	= mptscsih_suspend,
 	.resume		= mptscsih_resume,
@@ -3364,10 +4951,12 @@
 		return -ENODEV;
 
 	mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
-	mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
+	mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
 	mptsasInternalCtx =
 		mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
 	mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
+	mptsasDeviceResetCtx =
+		mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
 
 	mpt_event_register(mptsasDoneCtx, mptsas_event_process);
 	mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
@@ -3392,6 +4981,7 @@
 	mpt_deregister(mptsasInternalCtx);
 	mpt_deregister(mptsasTaskCtx);
 	mpt_deregister(mptsasDoneCtx);
+	mpt_deregister(mptsasDeviceResetCtx);
 }
 
 module_init(mptsas_init);
diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h
index 2b544e0..953c2bf 100644
--- a/drivers/message/fusion/mptsas.h
+++ b/drivers/message/fusion/mptsas.h
@@ -53,6 +53,7 @@
 	struct list_head 	list;
 	EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
 	u8	target_reset_issued;
+	unsigned long	 time_count;
 };
 
 enum mptsas_hotplug_action {
@@ -60,12 +61,37 @@
 	MPTSAS_DEL_DEVICE,
 	MPTSAS_ADD_RAID,
 	MPTSAS_DEL_RAID,
+	MPTSAS_ADD_PHYSDISK,
+	MPTSAS_ADD_PHYSDISK_REPROBE,
+	MPTSAS_DEL_PHYSDISK,
+	MPTSAS_DEL_PHYSDISK_REPROBE,
 	MPTSAS_ADD_INACTIVE_VOLUME,
 	MPTSAS_IGNORE_EVENT,
 };
 
+struct mptsas_mapping{
+	u8			id;
+	u8			channel;
+};
+
+struct mptsas_device_info {
+	struct list_head 	list;
+	struct mptsas_mapping	os;	/* operating system mapping*/
+	struct mptsas_mapping	fw;	/* firmware mapping */
+	u64			sas_address;
+	u32			device_info; /* specific bits for devices */
+	u16			slot;		/* enclosure slot id */
+	u64			enclosure_logical_id; /*enclosure address */
+	u8			is_logical_volume; /* is this logical volume */
+	/* this belongs to volume */
+	u8			is_hidden_raid_component;
+	/* this valid when is_hidden_raid_component set */
+	u8			volume_id;
+	/* cached data for a removed device */
+	u8			is_cached;
+};
+
 struct mptsas_hotplug_event {
-	struct work_struct	work;
 	MPT_ADAPTER		*ioc;
 	enum mptsas_hotplug_action event_type;
 	u64			sas_address;
@@ -73,11 +99,18 @@
 	u8			id;
 	u32			device_info;
 	u16			handle;
-	u16			parent_handle;
 	u8			phy_id;
-	u8			phys_disk_num_valid;	/* hrc (hidden raid component) */
 	u8			phys_disk_num;		/* hrc - unique index*/
-	u8			hidden_raid_component;	/* hrc - don't expose*/
+	struct scsi_device	*sdev;
+};
+
+struct fw_event_work {
+	struct list_head 	list;
+	struct delayed_work	 work;
+	MPT_ADAPTER	*ioc;
+	u32			event;
+	u8			retries;
+	u8			event_data[1];
 };
 
 struct mptsas_discovery_event {
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index e62c6bc..024e830 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -80,7 +80,7 @@
 /*
  *  Other private/forward protos...
  */
-static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
+struct scsi_cmnd	*mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
 static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
 static void	mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
 static int	SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
@@ -92,18 +92,24 @@
 				 SCSIIORequest_t *pReq, int req_idx);
 static void	mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
 static void	mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
-static int	mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
-static int	mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
 
-static int	mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
+int	mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id,
+		int lun, int ctx2abort, ulong timeout);
 
 int		mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
 int		mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
 
+void
+mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
+static int	mptscsih_get_completion_code(MPT_ADAPTER *ioc,
+		MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
 int		mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
 static int	mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
 static void	mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
 
+static int
+mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
+				SCSITaskMgmtReply_t *pScsiTmReply);
 void 		mptscsih_remove(struct pci_dev *);
 void 		mptscsih_shutdown(struct pci_dev *);
 #ifdef CONFIG_PM
@@ -113,69 +119,6 @@
 
 #define SNS_LEN(scp)	SCSI_SENSE_BUFFERSIZE
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	mptscsih_add_sge - Place a simple SGE at address pAddr.
- *	@pAddr: virtual address for SGE
- *	@flagslength: SGE flags and data transfer length
- *	@dma_addr: Physical address
- *
- *	This routine places a MPT request frame back on the MPT adapter's
- *	FreeQ.
- */
-static inline void
-mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
-{
-	if (sizeof(dma_addr_t) == sizeof(u64)) {
-		SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
-		u32 tmp = dma_addr & 0xFFFFFFFF;
-
-		pSge->FlagsLength = cpu_to_le32(flagslength);
-		pSge->Address.Low = cpu_to_le32(tmp);
-		tmp = (u32) ((u64)dma_addr >> 32);
-		pSge->Address.High = cpu_to_le32(tmp);
-
-	} else {
-		SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
-		pSge->FlagsLength = cpu_to_le32(flagslength);
-		pSge->Address = cpu_to_le32(dma_addr);
-	}
-} /* mptscsih_add_sge() */
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	mptscsih_add_chain - Place a chain SGE at address pAddr.
- *	@pAddr: virtual address for SGE
- *	@next: nextChainOffset value (u32's)
- *	@length: length of next SGL segment
- *	@dma_addr: Physical address
- *
- *	This routine places a MPT request frame back on the MPT adapter's
- *	FreeQ.
- */
-static inline void
-mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
-{
-	if (sizeof(dma_addr_t) == sizeof(u64)) {
-		SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
-		u32 tmp = dma_addr & 0xFFFFFFFF;
-
-		pChain->Length = cpu_to_le16(length);
-		pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
-
-		pChain->NextChainOffset = next;
-
-		pChain->Address.Low = cpu_to_le32(tmp);
-		tmp = (u32) ((u64)dma_addr >> 32);
-		pChain->Address.High = cpu_to_le32(tmp);
-	} else {
-		SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
-		pChain->Length = cpu_to_le16(length);
-		pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
-		pChain->NextChainOffset = next;
-		pChain->Address = cpu_to_le32(dma_addr);
-	}
-} /* mptscsih_add_chain() */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -281,10 +224,10 @@
 	 */
 
 nextSGEset:
-	numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
+	numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
 	numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
 
-	sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
+	sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
 
 	/* Get first (num - 1) SG elements
 	 * Skip any SG entries with a length of 0
@@ -293,17 +236,19 @@
 	for (ii=0; ii < (numSgeThisFrame-1); ii++) {
 		thisxfer = sg_dma_len(sg);
 		if (thisxfer == 0) {
-			sg = sg_next(sg); /* Get next SG element from the OS */
+			/* Get next SG element from the OS */
+			sg = sg_next(sg);
 			sg_done++;
 			continue;
 		}
 
 		v2 = sg_dma_address(sg);
-		mptscsih_add_sge(psge, sgflags | thisxfer, v2);
+		ioc->add_sge(psge, sgflags | thisxfer, v2);
 
-		sg = sg_next(sg);	/* Get next SG element from the OS */
-		psge += (sizeof(u32) + sizeof(dma_addr_t));
-		sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+		/* Get next SG element from the OS */
+		sg = sg_next(sg);
+		psge += ioc->SGE_size;
+		sgeOffset += ioc->SGE_size;
 		sg_done++;
 	}
 
@@ -320,12 +265,8 @@
 		thisxfer = sg_dma_len(sg);
 
 		v2 = sg_dma_address(sg);
-		mptscsih_add_sge(psge, sgflags | thisxfer, v2);
-		/*
-		sg = sg_next(sg);
-		psge += (sizeof(u32) + sizeof(dma_addr_t));
-		*/
-		sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+		ioc->add_sge(psge, sgflags | thisxfer, v2);
+		sgeOffset += ioc->SGE_size;
 		sg_done++;
 
 		if (chainSge) {
@@ -334,7 +275,8 @@
 			 * Update the chain element
 			 * Offset and Length fields.
 			 */
-			mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
+			ioc->add_chain((char *)chainSge, 0, sgeOffset,
+				ioc->ChainBufferDMA + chain_dma_off);
 		} else {
 			/* The current buffer is the original MF
 			 * and there is no Chain buffer.
@@ -367,7 +309,7 @@
 		 * set properly).
 		 */
 		if (sg_done) {
-			u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
+			u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
 			sgflags = le32_to_cpu(*ptmp);
 			sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
 			*ptmp = cpu_to_le32(sgflags);
@@ -381,8 +323,9 @@
 			 * Old chain element is now complete.
 			 */
 			u8 nextChain = (u8) (sgeOffset >> 2);
-			sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
-			mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
+			sgeOffset += ioc->SGE_size;
+			ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
+					 ioc->ChainBufferDMA + chain_dma_off);
 		} else {
 			/* The original MF buffer requires a chain buffer -
 			 * set the offset.
@@ -592,14 +535,15 @@
 	}
 
 	scsi_print_command(sc);
-	printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
-	    ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
+	printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n",
+	    ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun);
 	printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
 	    "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
 	    scsi_get_resid(sc));
 	printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
 	    "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
 	    le32_to_cpu(pScsiReply->TransferCount), sc->result);
+
 	printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
 	    "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
 	    ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
@@ -654,16 +598,14 @@
 	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
 	req_idx_MR = (mr != NULL) ?
 	    le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
+
+	/* Special case, where already freed message frame is received from
+	 * Firmware. It happens with Resetting IOC.
+	 * Return immediately. Do not care
+	 */
 	if ((req_idx != req_idx_MR) ||
-	    (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
-		printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
-		    ioc->name);
-		printk (MYIOC_s_ERR_FMT
-		    "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
-		    ioc->name, req_idx, req_idx_MR, mf, mr,
-		    mptscsih_get_scsi_lookup(ioc, req_idx_MR));
+	    (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf))
 		return 0;
-	}
 
 	sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
 	if (sc == NULL) {
@@ -810,12 +752,16 @@
 			 */
 
 		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
-		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
 			/* Linux handles an unsolicited DID_RESET better
 			 * than an unsolicited DID_ABORT.
 			 */
 			sc->result = DID_RESET << 16;
 
+		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
+			if (ioc->bus_type == FC)
+				sc->result = DID_ERROR << 16;
+			else
+				sc->result = DID_RESET << 16;
 			break;
 
 		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */
@@ -992,9 +938,9 @@
 		scsi_dma_unmap(sc);
 		sc->result = DID_RESET << 16;
 		sc->host_scribble = NULL;
-		sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
-		    "completing cmds: fw_channel %d, fw_id %d, sc=%p,"
-		    " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii);
+		dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
+		    "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "
+		    "idx=%x\n", ioc->name, channel, id, sc, mf, ii));
 		sc->scsi_done(sc);
 	}
 }
@@ -1053,9 +999,11 @@
 			scsi_dma_unmap(sc);
 			sc->host_scribble = NULL;
 			sc->result = DID_NO_CONNECT << 16;
-			sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d,"
-			   "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel,
-			   vdevice->vtarget->id, sc, mf, ii);
+			dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,
+			   MYIOC_s_FMT "completing cmds: fw_channel %d, "
+			   "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,
+			   vdevice->vtarget->channel, vdevice->vtarget->id,
+			   sc, mf, ii));
 			sc->scsi_done(sc);
 			spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
 		}
@@ -1346,7 +1294,6 @@
 	MPT_FRAME_HDR		*mf;
 	SCSIIORequest_t		*pScsiReq;
 	VirtDevice		*vdevice = SCpnt->device->hostdata;
-	int	 lun;
 	u32	 datalen;
 	u32	 scsictl;
 	u32	 scsidir;
@@ -1357,13 +1304,12 @@
 
 	hd = shost_priv(SCpnt->device->host);
 	ioc = hd->ioc;
-	lun = SCpnt->device->lun;
 	SCpnt->scsi_done = done;
 
 	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
 		ioc->name, SCpnt, done));
 
-	if (hd->resetPending) {
+	if (ioc->taskmgmt_quiesce_io) {
 		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
 			ioc->name, SCpnt));
 		return SCSI_MLQUEUE_HOST_BUSY;
@@ -1422,7 +1368,7 @@
 	pScsiReq->CDBLength = SCpnt->cmd_len;
 	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
 	pScsiReq->Reserved = 0;
-	pScsiReq->MsgFlags = mpt_msg_flags();
+	pScsiReq->MsgFlags = mpt_msg_flags(ioc);
 	int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
 	pScsiReq->Control = cpu_to_le32(scsictl);
 
@@ -1448,7 +1394,8 @@
 	 */
 	if (datalen == 0) {
 		/* Add a NULL SGE */
-		mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
+		ioc->add_sge((char *)&pScsiReq->SGL,
+			MPT_SGE_FLAGS_SSIMPLE_READ | 0,
 			(dma_addr_t) -1);
 	} else {
 		/* Add a 32 or 64 bit SGE */
@@ -1528,120 +1475,6 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *	mptscsih_TMHandler - Generic handler for SCSI Task Management.
- *	@hd: Pointer to MPT SCSI HOST structure
- *	@type: Task Management type
- *	@channel: channel number for task management
- *	@id: Logical Target ID for reset (if appropriate)
- *	@lun: Logical Unit for reset (if appropriate)
- *	@ctx2abort: Context for the task to be aborted (if appropriate)
- *	@timeout: timeout for task management control
- *
- *	Fall through to mpt_HardResetHandler if: not operational, too many
- *	failed TM requests or handshake failure.
- *
- *	Remark: Currently invoked from a non-interrupt thread (_bh).
- *
- *	Note: With old EH code, at most 1 SCSI TaskMgmt function per IOC
- *	will be active.
- *
- *	Returns 0 for SUCCESS, or %FAILED.
- **/
-int
-mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
-{
-	MPT_ADAPTER	*ioc;
-	int		 rc = -1;
-	u32		 ioc_raw_state;
-	unsigned long	 flags;
-
-	ioc = hd->ioc;
-	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name));
-
-	// SJR - CHECKME - Can we avoid this here?
-	// (mpt_HardResetHandler has this check...)
-	spin_lock_irqsave(&ioc->diagLock, flags);
-	if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
-		spin_unlock_irqrestore(&ioc->diagLock, flags);
-		return FAILED;
-	}
-	spin_unlock_irqrestore(&ioc->diagLock, flags);
-
-	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
-	 *  If we time out and not bus reset, then we return a FAILED status
-	 *  to the caller.
-	 *  The call to mptscsih_tm_pending_wait() will set the pending flag
-	 *  if we are
-	 *  successful. Otherwise, reload the FW.
-	 */
-	if (mptscsih_tm_pending_wait(hd) == FAILED) {
-		if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
-			dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: "
-			   "Timed out waiting for last TM (%d) to complete! \n",
-			   ioc->name, hd->tmPending));
-			return FAILED;
-		} else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
-			dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target "
-				"reset: Timed out waiting for last TM (%d) "
-				"to complete! \n", ioc->name,
-				hd->tmPending));
-			return FAILED;
-		} else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
-			dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: "
-			   "Timed out waiting for last TM (%d) to complete! \n",
-			  ioc->name, hd->tmPending));
-			return FAILED;
-		}
-	} else {
-		spin_lock_irqsave(&ioc->FreeQlock, flags);
-		hd->tmPending |=  (1 << type);
-		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-	}
-
-	ioc_raw_state = mpt_GetIocState(ioc, 0);
-
-	if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
-		printk(MYIOC_s_WARN_FMT
-			"TM Handler for type=%x: IOC Not operational (0x%x)!\n",
-			ioc->name, type, ioc_raw_state);
-		printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name);
-		if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
-			printk(MYIOC_s_WARN_FMT "TMHandler: HardReset "
-			    "FAILED!!\n", ioc->name);
-		return FAILED;
-	}
-
-	if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
-		printk(MYIOC_s_WARN_FMT
-			"TM Handler for type=%x: ioc_state: "
-			"DOORBELL_ACTIVE (0x%x)!\n",
-			ioc->name, type, ioc_raw_state);
-		return FAILED;
-	}
-
-	/* Isse the Task Mgmt request.
-	 */
-	if (hd->hard_resets < -1)
-		hd->hard_resets++;
-
-	rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
-	    ctx2abort, timeout);
-	if (rc)
-		printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
-		       ioc->name);
-	else
-		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n",
-			   ioc->name));
-
-	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-			"TMHandler rc = %d!\n", ioc->name, rc));
-
-	return rc;
-}
-
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
  *	mptscsih_IssueTaskMgmt - Generic send Task Management function.
  *	@hd: Pointer to MPT_SCSI_HOST structure
  *	@type: Task Management type
@@ -1659,23 +1492,60 @@
  *	Returns 0 for SUCCESS, or FAILED.
  *
  **/
-static int
-mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
+int
+mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
+	int ctx2abort, ulong timeout)
 {
 	MPT_FRAME_HDR	*mf;
 	SCSITaskMgmt_t	*pScsiTm;
 	int		 ii;
 	int		 retval;
 	MPT_ADAPTER 	*ioc = hd->ioc;
+	unsigned long	 timeleft;
+	u8		 issue_hard_reset;
+	u32		 ioc_raw_state;
+	unsigned long	 time_count;
+
+	issue_hard_reset = 0;
+	ioc_raw_state = mpt_GetIocState(ioc, 0);
+
+	if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
+		printk(MYIOC_s_WARN_FMT
+			"TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
+			ioc->name, type, ioc_raw_state);
+		printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
+		    ioc->name, __func__);
+		if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
+			printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
+			    "FAILED!!\n", ioc->name);
+		return 0;
+	}
+
+	if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
+		printk(MYIOC_s_WARN_FMT
+			"TaskMgmt type=%x: ioc_state: "
+			"DOORBELL_ACTIVE (0x%x)!\n",
+			ioc->name, type, ioc_raw_state);
+		return FAILED;
+	}
+
+	mutex_lock(&ioc->taskmgmt_cmds.mutex);
+	if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+		mf = NULL;
+		retval = FAILED;
+		goto out;
+	}
 
 	/* Return Fail to calling function if no message frames available.
 	 */
 	if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
-		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
-				ioc->name));
-		return FAILED;
+		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+			"TaskMgmt no msg frames!!\n", ioc->name));
+		retval = FAILED;
+		mpt_clear_taskmgmt_in_progress_flag(ioc);
+		goto out;
 	}
-	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
 			ioc->name, mf));
 
 	/* Format the Request
@@ -1699,11 +1569,14 @@
 
 	pScsiTm->TaskMsgContext = ctx2abort;
 
-	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
-		"type=%d\n", ioc->name, ctx2abort, type));
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
+		"task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
+		type, timeout));
 
 	DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
 
+	INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+	time_count = jiffies;
 	if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
 	    (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
 		mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
@@ -1711,47 +1584,50 @@
 		retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
 			sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
 		if (retval) {
-			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
-			" (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd,
-			ioc, mf, retval));
-			goto fail_out;
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+				"TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",
+				ioc->name, mf, retval));
+			mpt_free_msg_frame(ioc, mf);
+			mpt_clear_taskmgmt_in_progress_flag(ioc);
+			goto out;
 		}
 	}
 
-	if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
-		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
-			" (hd %p, ioc %p, mf %p) \n", ioc->name, hd,
-			ioc, mf));
-		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
-			 ioc->name));
-		retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
-		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
-			 ioc->name, retval));
-		goto fail_out;
+	timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
+		timeout*HZ);
+	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+		retval = FAILED;
+		dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
+		    "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
+		mpt_clear_taskmgmt_in_progress_flag(ioc);
+		if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+			goto out;
+		issue_hard_reset = 1;
+		goto out;
 	}
 
-	/*
-	 * Handle success case, see if theres a non-zero ioc_status.
-	 */
-	if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
-	   hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
-	   hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
-		retval = 0;
-	else
-		retval = FAILED;
+	retval = mptscsih_taskmgmt_reply(ioc, type,
+	    (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
 
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+	    "TaskMgmt completed (%d seconds)\n",
+	    ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
+
+ out:
+
+	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+	if (issue_hard_reset) {
+		printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+			ioc->name, __func__);
+		retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+		mpt_free_msg_frame(ioc, mf);
+	}
+
+	retval = (retval == 0) ? 0 : FAILED;
+	mutex_unlock(&ioc->taskmgmt_cmds.mutex);
 	return retval;
-
- fail_out:
-
-	/*
-	 * Free task management mf, and corresponding tm flags
-	 */
-	mpt_free_msg_frame(ioc, mf);
-	hd->tmPending = 0;
-	hd->tmState = TM_STATE_NONE;
-	return FAILED;
 }
+EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
 
 static int
 mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
@@ -1838,13 +1714,8 @@
 		goto out;
 	}
 
-	if (hd->resetPending) {
-		retval = FAILED;
-		goto out;
-	}
-
-	if (hd->timeouts < -1)
-		hd->timeouts++;
+	if (ioc->timeouts < -1)
+		ioc->timeouts++;
 
 	if (mpt_fwfault_debug)
 		mpt_halt_firmware(ioc);
@@ -1861,22 +1732,30 @@
 
 	hd->abortSCpnt = SCpnt;
 
-	retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
-	    vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
-	    ctx2abort, mptscsih_get_tm_timeout(ioc));
+	retval = mptscsih_IssueTaskMgmt(hd,
+			 MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
+			 vdevice->vtarget->channel,
+			 vdevice->vtarget->id, vdevice->lun,
+			 ctx2abort, mptscsih_get_tm_timeout(ioc));
 
 	if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
-	    SCpnt->serial_number == sn)
+	    SCpnt->serial_number == sn) {
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "task abort: command still in active list! (sc=%p)\n",
+		    ioc->name, SCpnt));
 		retval = FAILED;
+	} else {
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "task abort: command cleared from active list! (sc=%p)\n",
+		    ioc->name, SCpnt));
+		retval = SUCCESS;
+	}
 
  out:
 	printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
-	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
+	    ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), SCpnt);
 
-	if (retval == 0)
-		return SUCCESS;
-	else
-		return FAILED;
+	return retval;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1909,14 +1788,9 @@
 	       ioc->name, SCpnt);
 	scsi_print_command(SCpnt);
 
-	if (hd->resetPending) {
-		retval = FAILED;
-		goto out;
-	}
-
 	vdevice = SCpnt->device->hostdata;
 	if (!vdevice || !vdevice->vtarget) {
-		retval = 0;
+		retval = SUCCESS;
 		goto out;
 	}
 
@@ -1927,9 +1801,11 @@
 		goto out;
 	}
 
-	retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
-	    vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
-	    mptscsih_get_tm_timeout(ioc));
+	retval = mptscsih_IssueTaskMgmt(hd,
+				MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
+				vdevice->vtarget->channel,
+				vdevice->vtarget->id, 0, 0,
+				mptscsih_get_tm_timeout(ioc));
 
  out:
 	printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
@@ -1972,12 +1848,16 @@
 	       ioc->name, SCpnt);
 	scsi_print_command(SCpnt);
 
-	if (hd->timeouts < -1)
-		hd->timeouts++;
+	if (ioc->timeouts < -1)
+		ioc->timeouts++;
 
 	vdevice = SCpnt->device->hostdata;
-	retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
-	    vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
+	if (!vdevice || !vdevice->vtarget)
+		return SUCCESS;
+	retval = mptscsih_IssueTaskMgmt(hd,
+					MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+					vdevice->vtarget->channel, 0, 0, 0,
+					mptscsih_get_tm_timeout(ioc));
 
 	printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
 	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
@@ -2001,8 +1881,9 @@
 mptscsih_host_reset(struct scsi_cmnd *SCpnt)
 {
 	MPT_SCSI_HOST *  hd;
-	int              retval;
+	int              status = SUCCESS;
 	MPT_ADAPTER	*ioc;
+	int		retval;
 
 	/*  If we can't locate the host to reset, then we failed. */
 	if ((hd = shost_priv(SCpnt->device->host)) == NULL){
@@ -2021,86 +1902,71 @@
 	/*  If our attempts to reset the host failed, then return a failed
 	 *  status.  The host will be taken off line by the SCSI mid-layer.
 	 */
-	if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
-		retval = FAILED;
-	} else {
-		/*  Make sure TM pending is cleared and TM state is set to
-		 *  NONE.
-		 */
-		retval = 0;
-		hd->tmPending = 0;
-		hd->tmState = TM_STATE_NONE;
-	}
+    retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+	if (retval < 0)
+		status = FAILED;
+	else
+		status = SUCCESS;
 
 	printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
 	    ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
 
+	return status;
+}
+
+static int
+mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
+	SCSITaskMgmtReply_t *pScsiTmReply)
+{
+	u16			 iocstatus;
+	u32			 termination_count;
+	int			 retval;
+
+	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+		retval = FAILED;
+		goto out;
+	}
+
+	DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
+
+	iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+	termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
+
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+	    "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
+	    "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
+	    "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
+	    pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
+	    le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
+	    termination_count));
+
+	if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
+	    pScsiTmReply->ResponseCode)
+		mptscsih_taskmgmt_response_code(ioc,
+		    pScsiTmReply->ResponseCode);
+
+	if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
+		retval = 0;
+		goto out;
+	}
+
+	retval = FAILED;
+	if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+		if (termination_count == 1)
+			retval = 0;
+		goto out;
+	}
+
+	if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
+	   iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
+		retval = 0;
+
+ out:
 	return retval;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	mptscsih_tm_pending_wait - wait for pending task management request to complete
- *	@hd: Pointer to MPT host structure.
- *
- *	Returns {SUCCESS,FAILED}.
- */
-static int
-mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
-{
-	unsigned long  flags;
-	int            loop_count = 4 * 10;  /* Wait 10 seconds */
-	int            status = FAILED;
-	MPT_ADAPTER	*ioc = hd->ioc;
-
-	do {
-		spin_lock_irqsave(&ioc->FreeQlock, flags);
-		if (hd->tmState == TM_STATE_NONE) {
-			hd->tmState = TM_STATE_IN_PROGRESS;
-			hd->tmPending = 1;
-			spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-			status = SUCCESS;
-			break;
-		}
-		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-		msleep(250);
-	} while (--loop_count);
-
-	return status;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	mptscsih_tm_wait_for_completion - wait for completion of TM task
- *	@hd: Pointer to MPT host structure.
- *	@timeout: timeout value
- *
- *	Returns {SUCCESS,FAILED}.
- */
-static int
-mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
-{
-	unsigned long  flags;
-	int            loop_count = 4 * timeout;
-	int            status = FAILED;
-	MPT_ADAPTER	*ioc = hd->ioc;
-
-	do {
-		spin_lock_irqsave(&ioc->FreeQlock, flags);
-		if(hd->tmPending == 0) {
-			status = SUCCESS;
-			spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-			break;
-		}
-		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-		msleep(250);
-	} while (--loop_count);
-
-	return status;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static void
+void
 mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
 {
 	char *desc;
@@ -2134,6 +2000,7 @@
 	printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
 		ioc->name, response_code, desc);
 }
+EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
@@ -2150,97 +2017,28 @@
  *	Returns 1 indicating alloc'd request frame ptr should be freed.
  **/
 int
-mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
+	MPT_FRAME_HDR *mr)
 {
-	SCSITaskMgmtReply_t	*pScsiTmReply;
-	SCSITaskMgmt_t		*pScsiTmReq;
-	MPT_SCSI_HOST		*hd;
-	unsigned long		 flags;
-	u16			 iocstatus;
-	u8			 tmType;
-	u32			 termination_count;
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		"TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
 
-	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
-	    ioc->name, mf, mr));
-	if (!ioc->sh) {
-		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
-		    "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
-		return 1;
-	}
+	ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
 
-	if (mr == NULL) {
-		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
-		    "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
-		return 1;
-	}
-
-	hd = shost_priv(ioc->sh);
-	pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
-	pScsiTmReq = (SCSITaskMgmt_t*)mf;
-	tmType = pScsiTmReq->TaskType;
-	iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-	termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
-
-	if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
-	    pScsiTmReply->ResponseCode)
-		mptscsih_taskmgmt_response_code(ioc,
-		    pScsiTmReply->ResponseCode);
-	DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
-
-#ifdef CONFIG_FUSION_LOGGING
-	if ((ioc->debug_level & MPT_DEBUG_REPLY) ||
-				(ioc->debug_level & MPT_DEBUG_TM ))
-		printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
-			"iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
-			"term_cmnds=%d\n", __func__, ioc->id, pScsiTmReply->Bus,
-			 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
-			le16_to_cpu(pScsiTmReply->IOCStatus),
-			le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
-			le32_to_cpu(pScsiTmReply->TerminationCount));
-#endif
-	if (!iocstatus) {
-		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name));
-			hd->abortSCpnt = NULL;
+	if (!mr)
 		goto out;
-	}
 
-	/* Error?  (anything non-zero?) */
-
-	/* clear flags and continue.
-	 */
-	switch (tmType) {
-
-	case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
-		if (termination_count == 1)
-			iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
-		hd->abortSCpnt = NULL;
-		break;
-
-	case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
-
-		/* If an internal command is present
-		 * or the TM failed - reload the FW.
-		 * FC FW may respond FAILED to an ABORT
-		 */
-		if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
-		    hd->cmdPtr)
-			if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
-				printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name);
-		break;
-
-	case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
-	default:
-		break;
-	}
-
+	ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+	memcpy(ioc->taskmgmt_cmds.reply, mr,
+	    min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
  out:
-	spin_lock_irqsave(&ioc->FreeQlock, flags);
-	hd->tmPending = 0;
-	hd->tmState = TM_STATE_NONE;
-	hd->tm_iocstatus = iocstatus;
-	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-	return 1;
+	if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
+		mpt_clear_taskmgmt_in_progress_flag(ioc);
+		ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+		complete(&ioc->taskmgmt_cmds.done);
+		return 1;
+	}
+	return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2290,8 +2088,10 @@
 mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
 {
 	struct inactive_raid_component_info *component_info;
-	int i;
+	int i, j;
+	RaidPhysDiskPage1_t *phys_disk;
 	int rc = 0;
+	int num_paths;
 
 	if (!ioc->raid_data.pIocPg3)
 		goto out;
@@ -2303,6 +2103,45 @@
 		}
 	}
 
+	if (ioc->bus_type != SAS)
+		goto out;
+
+	/*
+	 * Check if dual path
+	 */
+	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+		num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
+		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
+		if (num_paths < 2)
+			continue;
+		phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
+		   (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
+		if (!phys_disk)
+			continue;
+		if ((mpt_raid_phys_disk_pg1(ioc,
+		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
+		    phys_disk))) {
+			kfree(phys_disk);
+			continue;
+		}
+		for (j = 0; j < num_paths; j++) {
+			if ((phys_disk->Path[j].Flags &
+			    MPI_RAID_PHYSDISK1_FLAG_INVALID))
+				continue;
+			if ((phys_disk->Path[j].Flags &
+			    MPI_RAID_PHYSDISK1_FLAG_BROKEN))
+				continue;
+			if ((id == phys_disk->Path[j].PhysDiskID) &&
+			    (channel == phys_disk->Path[j].PhysDiskBus)) {
+				rc = 1;
+				kfree(phys_disk);
+				goto out;
+			}
+		}
+		kfree(phys_disk);
+	}
+
+
 	/*
 	 * Check inactive list for matching phys disks
 	 */
@@ -2327,8 +2166,10 @@
 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
 {
 	struct inactive_raid_component_info *component_info;
-	int i;
+	int i, j;
+	RaidPhysDiskPage1_t *phys_disk;
 	int rc = -ENXIO;
+	int num_paths;
 
 	if (!ioc->raid_data.pIocPg3)
 		goto out;
@@ -2340,6 +2181,44 @@
 		}
 	}
 
+	if (ioc->bus_type != SAS)
+		goto out;
+
+	/*
+	 * Check if dual path
+	 */
+	for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+		num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
+		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
+		if (num_paths < 2)
+			continue;
+		phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
+		   (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
+		if (!phys_disk)
+			continue;
+		if ((mpt_raid_phys_disk_pg1(ioc,
+		    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
+		    phys_disk))) {
+			kfree(phys_disk);
+			continue;
+		}
+		for (j = 0; j < num_paths; j++) {
+			if ((phys_disk->Path[j].Flags &
+			    MPI_RAID_PHYSDISK1_FLAG_INVALID))
+				continue;
+			if ((phys_disk->Path[j].Flags &
+			    MPI_RAID_PHYSDISK1_FLAG_BROKEN))
+				continue;
+			if ((id == phys_disk->Path[j].PhysDiskID) &&
+			    (channel == phys_disk->Path[j].PhysDiskBus)) {
+				rc = phys_disk->PhysDiskNum;
+				kfree(phys_disk);
+				goto out;
+			}
+		}
+		kfree(phys_disk);
+	}
+
 	/*
 	 * Check inactive list for matching phys disks
 	 */
@@ -2457,7 +2336,6 @@
 		    sdev->ppr, sdev->inquiry_len));
 
 	vdevice->configured_lun = 1;
-	mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
 
 	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		"Queue depth=%d, tflags=%x\n",
@@ -2469,6 +2347,7 @@
 		    ioc->name, vtarget->negoFlags, vtarget->maxOffset,
 		    vtarget->minSyncFactor));
 
+	mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
 	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		"tagged %d, simple %d, ordered %d\n",
 		ioc->name,sdev->tagged_supported, sdev->simple_tags,
@@ -2542,15 +2421,13 @@
 }
 
 /**
- * mptscsih_get_scsi_lookup
+ * mptscsih_get_scsi_lookup - retrieves scmd entry
  * @ioc: Pointer to MPT_ADAPTER structure
  * @i: index into the array
  *
- * retrieves scmd entry from ScsiLookup[] array list
- *
  * Returns the scsi_cmd pointer
- **/
-static struct scsi_cmnd *
+ */
+struct scsi_cmnd *
 mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
 {
 	unsigned long	flags;
@@ -2562,15 +2439,15 @@
 
 	return scmd;
 }
+EXPORT_SYMBOL(mptscsih_get_scsi_lookup);
 
 /**
- * mptscsih_getclear_scsi_lookup
+ * mptscsih_getclear_scsi_lookup -  retrieves and clears scmd entry from ScsiLookup[] array list
  * @ioc: Pointer to MPT_ADAPTER structure
  * @i: index into the array
  *
- * retrieves and clears scmd entry from ScsiLookup[] array list
- *
  * Returns the scsi_cmd pointer
+ *
  **/
 static struct scsi_cmnd *
 mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
@@ -2635,94 +2512,33 @@
 mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
 	MPT_SCSI_HOST	*hd;
-	unsigned long	 flags;
 
-	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-	    ": IOC %s_reset routed to SCSI host driver!\n",
-	    ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
-	    reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
-
-	/* If a FW reload request arrives after base installed but
-	 * before all scsi hosts have been attached, then an alt_ioc
-	 * may have a NULL sh pointer.
-	 */
 	if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
 		return 0;
-	else
-		hd = shost_priv(ioc->sh);
 
-	if (reset_phase == MPT_IOC_SETUP_RESET) {
-		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
-
-		/* Clean Up:
-		 * 1. Set Hard Reset Pending Flag
-		 * All new commands go to doneQ
-		 */
-		hd->resetPending = 1;
-
-	} else if (reset_phase == MPT_IOC_PRE_RESET) {
-		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name));
-
-		/* 2. Flush running commands
-		 *	Clean ScsiLookup (and associated memory)
-		 *	AND clean mytaskQ
-		 */
-
-		/* 2b. Reply to OS all known outstanding I/O commands.
-		 */
+	hd = shost_priv(ioc->sh);
+	switch (reset_phase) {
+	case MPT_IOC_SETUP_RESET:
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
+		break;
+	case MPT_IOC_PRE_RESET:
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
 		mptscsih_flush_running_cmds(hd);
-
-		/* 2c. If there was an internal command that
-		 * has not completed, configuration or io request,
-		 * free these resources.
-		 */
-		if (hd->cmdPtr) {
-			del_timer(&hd->timer);
-			mpt_free_msg_frame(ioc, hd->cmdPtr);
+		break;
+	case MPT_IOC_POST_RESET:
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
+		if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
+			ioc->internal_cmds.status |=
+				MPT_MGMT_STATUS_DID_IOCRESET;
+			complete(&ioc->internal_cmds.done);
 		}
-
-		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name));
-
-	} else {
-		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name));
-
-		/* Once a FW reload begins, all new OS commands are
-		 * redirected to the doneQ w/ a reset status.
-		 * Init all control structures.
-		 */
-
-		/* 2. Chain Buffer initialization
-		 */
-
-		/* 4. Renegotiate to all devices, if SPI
-		 */
-
-		/* 5. Enable new commands to be posted
-		 */
-		spin_lock_irqsave(&ioc->FreeQlock, flags);
-		hd->tmPending = 0;
-		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-		hd->resetPending = 0;
-		hd->tmState = TM_STATE_NONE;
-
-		/* 6. If there was an internal command,
-		 * wake this process up.
-		 */
-		if (hd->cmdPtr) {
-			/*
-			 * Wake up the original calling thread
-			 */
-			hd->pLocal = &hd->localReply;
-			hd->pLocal->completion = MPT_SCANDV_DID_RESET;
-			hd->scandv_wait_done = 1;
-			wake_up(&hd->scandv_waitq);
-			hd->cmdPtr = NULL;
-		}
-
-		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name));
-
+		break;
+	default:
+		break;
 	}
-
 	return 1;		/* currently means nothing really */
 }
 
@@ -2730,55 +2546,16 @@
 int
 mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 {
-	MPT_SCSI_HOST *hd;
 	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
 
-	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
-			ioc->name, event));
+	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		"MPT event (=%02Xh) routed to SCSI host driver!\n",
+		ioc->name, event));
 
-	if (ioc->sh == NULL ||
-		((hd = shost_priv(ioc->sh)) == NULL))
-		return 1;
-
-	switch (event) {
-	case MPI_EVENT_UNIT_ATTENTION:			/* 03 */
-		/* FIXME! */
-		break;
-	case MPI_EVENT_IOC_BUS_RESET:			/* 04 */
-	case MPI_EVENT_EXT_BUS_RESET:			/* 05 */
-		if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
-			hd->soft_resets++;
-		break;
-	case MPI_EVENT_LOGOUT:				/* 09 */
-		/* FIXME! */
-		break;
-
-	case MPI_EVENT_RESCAN:				/* 06 */
-		break;
-
-		/*
-		 *  CHECKME! Don't think we need to do
-		 *  anything for these, but...
-		 */
-	case MPI_EVENT_LINK_STATUS_CHANGE:		/* 07 */
-	case MPI_EVENT_LOOP_STATE_CHANGE:		/* 08 */
-		/*
-		 *  CHECKME!  Falling thru...
-		 */
-		break;
-
-	case MPI_EVENT_INTEGRATED_RAID:			/* 0B */
-		break;
-
-	case MPI_EVENT_NONE:				/* 00 */
-	case MPI_EVENT_LOG_DATA:			/* 01 */
-	case MPI_EVENT_STATE_CHANGE:			/* 02 */
-	case MPI_EVENT_EVENT_CHANGE:			/* 0A */
-	default:
-		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n",
-		    ioc->name, event));
-		break;
-	}
+	if ((event == MPI_EVENT_IOC_BUS_RESET ||
+	    event == MPI_EVENT_EXT_BUS_RESET) &&
+	    (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
+			ioc->soft_resets++;
 
 	return 1;		/* currently means nothing really */
 }
@@ -2809,153 +2586,44 @@
  *	Used ONLY for DV and other internal commands.
  */
 int
-mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
+				MPT_FRAME_HDR *reply)
 {
-	MPT_SCSI_HOST	*hd;
 	SCSIIORequest_t *pReq;
-	int		 completionCode;
+	SCSIIOReply_t	*pReply;
+	u8		 cmd;
 	u16		 req_idx;
+	u8	*sense_data;
+	int		 sz;
 
-	hd = shost_priv(ioc->sh);
+	ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+	ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
+	if (!reply)
+		goto out;
 
-	if ((mf == NULL) ||
-	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
-		printk(MYIOC_s_ERR_FMT
-			"ScanDvComplete, %s req frame ptr! (=%p)\n",
-				ioc->name, mf?"BAD":"NULL", (void *) mf);
-		goto wakeup;
+	pReply = (SCSIIOReply_t *) reply;
+	pReq = (SCSIIORequest_t *) req;
+	ioc->internal_cmds.completion_code =
+	    mptscsih_get_completion_code(ioc, req, reply);
+	ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+	memcpy(ioc->internal_cmds.reply, reply,
+	    min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
+	cmd = reply->u.hdr.Function;
+	if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+	    (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
+	    (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
+		req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
+		sense_data = ((u8 *)ioc->sense_buf_pool +
+		    (req_idx * MPT_SENSE_BUFFER_ALLOC));
+		sz = min_t(int, pReq->SenseBufferLength,
+		    MPT_SENSE_BUFFER_ALLOC);
+		memcpy(ioc->internal_cmds.sense, sense_data, sz);
 	}
-
-	del_timer(&hd->timer);
-	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
-	mptscsih_set_scsi_lookup(ioc, req_idx, NULL);
-	pReq = (SCSIIORequest_t *) mf;
-
-	if (mf != hd->cmdPtr) {
-		printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
-				ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
-	}
-	hd->cmdPtr = NULL;
-
-	ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
-			ioc->name, mf, mr, req_idx));
-
-	hd->pLocal = &hd->localReply;
-	hd->pLocal->scsiStatus = 0;
-
-	/* If target struct exists, clear sense valid flag.
-	 */
-	if (mr == NULL) {
-		completionCode = MPT_SCANDV_GOOD;
-	} else {
-		SCSIIOReply_t	*pReply;
-		u16		 status;
-		u8		 scsi_status;
-
-		pReply = (SCSIIOReply_t *) mr;
-
-		status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-		scsi_status = pReply->SCSIStatus;
-
-
-		switch(status) {
-
-		case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */
-			completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
-			break;
-
-		case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */
-		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
-		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
-		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
-			completionCode = MPT_SCANDV_DID_RESET;
-			break;
-
-		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
-		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
-		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
-			if (pReply->Function == MPI_FUNCTION_CONFIG) {
-				ConfigReply_t *pr = (ConfigReply_t *)mr;
-				completionCode = MPT_SCANDV_GOOD;
-				hd->pLocal->header.PageVersion = pr->Header.PageVersion;
-				hd->pLocal->header.PageLength = pr->Header.PageLength;
-				hd->pLocal->header.PageNumber = pr->Header.PageNumber;
-				hd->pLocal->header.PageType = pr->Header.PageType;
-
-			} else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
-				/* If the RAID Volume request is successful,
-				 * return GOOD, else indicate that
-				 * some type of error occurred.
-				 */
-				MpiRaidActionReply_t	*pr = (MpiRaidActionReply_t *)mr;
-				if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
-					completionCode = MPT_SCANDV_GOOD;
-				else
-					completionCode = MPT_SCANDV_SOME_ERROR;
-				memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
-
-			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
-				u8		*sense_data;
-				int		 sz;
-
-				/* save sense data in global structure
-				 */
-				completionCode = MPT_SCANDV_SENSE;
-				hd->pLocal->scsiStatus = scsi_status;
-				sense_data = ((u8 *)ioc->sense_buf_pool +
-					(req_idx * MPT_SENSE_BUFFER_ALLOC));
-
-				sz = min_t(int, pReq->SenseBufferLength,
-							SCSI_STD_SENSE_BYTES);
-				memcpy(hd->pLocal->sense, sense_data, sz);
-
-				ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "  Check Condition, sense ptr %p\n",
-				    ioc->name, sense_data));
-			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
-				if (pReq->CDB[0] == INQUIRY)
-					completionCode = MPT_SCANDV_ISSUE_SENSE;
-				else
-					completionCode = MPT_SCANDV_DID_RESET;
-			}
-			else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
-				completionCode = MPT_SCANDV_DID_RESET;
-			else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
-				completionCode = MPT_SCANDV_DID_RESET;
-			else {
-				completionCode = MPT_SCANDV_GOOD;
-				hd->pLocal->scsiStatus = scsi_status;
-			}
-			break;
-
-		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
-			if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
-				completionCode = MPT_SCANDV_DID_RESET;
-			else
-				completionCode = MPT_SCANDV_SOME_ERROR;
-			break;
-
-		default:
-			completionCode = MPT_SCANDV_SOME_ERROR;
-			break;
-
-		}	/* switch(status) */
-
-	} /* end of address reply case */
-
-	hd->pLocal->completion = completionCode;
-
-	/* MF and RF are freed in mpt_interrupt
-	 */
-wakeup:
-	/* Free Chain buffers (will never chain) in scan or dv */
-	//mptscsih_freeChainBuffers(ioc, req_idx);
-
-	/*
-	 * Wake up the original calling thread
-	 */
-	hd->scandv_wait_done = 1;
-	wake_up(&hd->scandv_waitq);
-
+ out:
+	if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
+		return 0;
+	ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+	complete(&ioc->internal_cmds.done);
 	return 1;
 }
 
@@ -3004,6 +2672,95 @@
 	return;
 }
 
+/**
+ *	mptscsih_get_completion_code -
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@reply:
+ *	@cmd:
+ *
+ **/
+static int
+mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
+				MPT_FRAME_HDR *reply)
+{
+	SCSIIOReply_t	*pReply;
+	MpiRaidActionReply_t *pr;
+	u8		 scsi_status;
+	u16		 status;
+	int		 completion_code;
+
+	pReply = (SCSIIOReply_t *)reply;
+	status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+	scsi_status = pReply->SCSIStatus;
+
+	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+	    "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
+	    "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
+	    scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
+
+	switch (status) {
+
+	case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */
+		completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
+		break;
+
+	case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */
+	case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
+	case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
+	case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
+		completion_code = MPT_SCANDV_DID_RESET;
+		break;
+
+	case MPI_IOCSTATUS_BUSY:
+	case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
+		completion_code = MPT_SCANDV_BUSY;
+		break;
+
+	case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
+	case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
+	case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
+		if (pReply->Function == MPI_FUNCTION_CONFIG) {
+			completion_code = MPT_SCANDV_GOOD;
+		} else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
+			pr = (MpiRaidActionReply_t *)reply;
+			if (le16_to_cpu(pr->ActionStatus) ==
+				MPI_RAID_ACTION_ASTATUS_SUCCESS)
+				completion_code = MPT_SCANDV_GOOD;
+			else
+				completion_code = MPT_SCANDV_SOME_ERROR;
+		} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
+			completion_code = MPT_SCANDV_SENSE;
+		else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
+			if (req->u.scsireq.CDB[0] == INQUIRY)
+				completion_code = MPT_SCANDV_ISSUE_SENSE;
+			else
+				completion_code = MPT_SCANDV_DID_RESET;
+		} else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
+			completion_code = MPT_SCANDV_DID_RESET;
+		else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
+			completion_code = MPT_SCANDV_DID_RESET;
+		else if (scsi_status == MPI_SCSI_STATUS_BUSY)
+			completion_code = MPT_SCANDV_BUSY;
+		else
+			completion_code = MPT_SCANDV_GOOD;
+		break;
+
+	case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
+		if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
+			completion_code = MPT_SCANDV_DID_RESET;
+		else
+			completion_code = MPT_SCANDV_SOME_ERROR;
+		break;
+	default:
+		completion_code = MPT_SCANDV_SOME_ERROR;
+		break;
+
+	}	/* switch(status) */
+
+	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+	    "  completionCode set to %08xh\n", ioc->name, completion_code));
+	return completion_code;
+}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
@@ -3030,22 +2787,27 @@
 {
 	MPT_FRAME_HDR	*mf;
 	SCSIIORequest_t	*pScsiReq;
-	SCSIIORequest_t	 ReqCopy;
 	int		 my_idx, ii, dir;
-	int		 rc, cmdTimeout;
-	int		in_isr;
+	int		 timeout;
 	char		 cmdLen;
 	char		 CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-	char		 cmd = io->cmd;
-	MPT_ADAPTER 	*ioc = hd->ioc;
+	u8		 cmd = io->cmd;
+	MPT_ADAPTER *ioc = hd->ioc;
+	int		 ret = 0;
+	unsigned long	 timeleft;
+	unsigned long	 flags;
 
-	in_isr = in_interrupt();
-	if (in_isr) {
-		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
-					ioc->name));
-		return -EPERM;
+	/* don't send internal command during diag reset */
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+	if (ioc->ioc_reset_in_progress) {
+		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+			"%s: busy with host reset\n", ioc->name, __func__));
+		return MPT_SCANDV_BUSY;
 	}
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 
+	mutex_lock(&ioc->internal_cmds.mutex);
 
 	/* Set command specific information
 	 */
@@ -3055,13 +2817,13 @@
 		dir = MPI_SCSIIO_CONTROL_READ;
 		CDB[0] = cmd;
 		CDB[4] = io->size;
-		cmdTimeout = 10;
+		timeout = 10;
 		break;
 
 	case TEST_UNIT_READY:
 		cmdLen = 6;
 		dir = MPI_SCSIIO_CONTROL_READ;
-		cmdTimeout = 10;
+		timeout = 10;
 		break;
 
 	case START_STOP:
@@ -3069,7 +2831,7 @@
 		dir = MPI_SCSIIO_CONTROL_READ;
 		CDB[0] = cmd;
 		CDB[4] = 1;	/*Spin up the disk */
-		cmdTimeout = 15;
+		timeout = 15;
 		break;
 
 	case REQUEST_SENSE:
@@ -3077,7 +2839,7 @@
 		CDB[0] = cmd;
 		CDB[4] = io->size;
 		dir = MPI_SCSIIO_CONTROL_READ;
-		cmdTimeout = 10;
+		timeout = 10;
 		break;
 
 	case READ_BUFFER:
@@ -3096,7 +2858,7 @@
 		CDB[6] = (io->size >> 16) & 0xFF;
 		CDB[7] = (io->size >>  8) & 0xFF;
 		CDB[8] = io->size & 0xFF;
-		cmdTimeout = 10;
+		timeout = 10;
 		break;
 
 	case WRITE_BUFFER:
@@ -3111,21 +2873,21 @@
 		CDB[6] = (io->size >> 16) & 0xFF;
 		CDB[7] = (io->size >>  8) & 0xFF;
 		CDB[8] = io->size & 0xFF;
-		cmdTimeout = 10;
+		timeout = 10;
 		break;
 
 	case RESERVE:
 		cmdLen = 6;
 		dir = MPI_SCSIIO_CONTROL_READ;
 		CDB[0] = cmd;
-		cmdTimeout = 10;
+		timeout = 10;
 		break;
 
 	case RELEASE:
 		cmdLen = 6;
 		dir = MPI_SCSIIO_CONTROL_READ;
 		CDB[0] = cmd;
-		cmdTimeout = 10;
+		timeout = 10;
 		break;
 
 	case SYNCHRONIZE_CACHE:
@@ -3133,20 +2895,23 @@
 		dir = MPI_SCSIIO_CONTROL_READ;
 		CDB[0] = cmd;
 //		CDB[1] = 0x02;	/* set immediate bit */
-		cmdTimeout = 10;
+		timeout = 10;
 		break;
 
 	default:
 		/* Error Case */
-		return -EFAULT;
+		ret = -EFAULT;
+		goto out;
 	}
 
 	/* Get and Populate a free Frame
+	 * MsgContext set in mpt_get_msg_frame call
 	 */
 	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
-		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n",
-		    ioc->name));
-		return -EBUSY;
+		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
+		    ioc->name, __func__));
+		ret = MPT_SCANDV_BUSY;
+		goto out;
 	}
 
 	pScsiReq = (SCSIIORequest_t *) mf;
@@ -3172,7 +2937,7 @@
 
 	pScsiReq->Reserved = 0;
 
-	pScsiReq->MsgFlags = mpt_msg_flags();
+	pScsiReq->MsgFlags = mpt_msg_flags(ioc);
 	/* MsgContext set in mpt_get_msg_fram call  */
 
 	int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
@@ -3184,74 +2949,58 @@
 
 	if (cmd == REQUEST_SENSE) {
 		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
-		ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
-			ioc->name, cmd));
+		devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
 	}
 
-	for (ii=0; ii < 16; ii++)
+	for (ii = 0; ii < 16; ii++)
 		pScsiReq->CDB[ii] = CDB[ii];
 
 	pScsiReq->DataLength = cpu_to_le32(io->size);
 	pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
 					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));
 
-	ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
-			ioc->name, cmd, io->channel, io->id, io->lun));
+	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+	    "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
+	    ioc->name, __func__, cmd, io->channel, io->id, io->lun));
 
-	if (dir == MPI_SCSIIO_CONTROL_READ) {
-		mpt_add_sge((char *) &pScsiReq->SGL,
-			MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
-			io->data_dma);
-	} else {
-		mpt_add_sge((char *) &pScsiReq->SGL,
-			MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
-			io->data_dma);
-	}
+	if (dir == MPI_SCSIIO_CONTROL_READ)
+		ioc->add_sge((char *) &pScsiReq->SGL,
+		    MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
+	else
+		ioc->add_sge((char *) &pScsiReq->SGL,
+		    MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
 
-	/* The ISR will free the request frame, but we need
-	 * the information to initialize the target. Duplicate.
-	 */
-	memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
-
-	/* Issue this command after:
-	 *	finish init
-	 *	add timer
-	 * Wait until the reply has been received
-	 *  ScsiScanDvCtx callback function will
-	 *	set hd->pLocal;
-	 *	set scandv_wait_done and call wake_up
-	 */
-	hd->pLocal = NULL;
-	hd->timer.expires = jiffies + HZ*cmdTimeout;
-	hd->scandv_wait_done = 0;
-
-	/* Save cmd pointer, for resource free if timeout or
-	 * FW reload occurs
-	 */
-	hd->cmdPtr = mf;
-
-	add_timer(&hd->timer);
+	INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
 	mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
-	wait_event(hd->scandv_waitq, hd->scandv_wait_done);
-
-	if (hd->pLocal) {
-		rc = hd->pLocal->completion;
-		hd->pLocal->skip = 0;
-
-		/* Always set fatal error codes in some cases.
-		 */
-		if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
-			rc = -ENXIO;
-		else if (rc == MPT_SCANDV_SOME_ERROR)
-			rc =  -rc;
-	} else {
-		rc = -EFAULT;
-		/* This should never happen. */
-		ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
-				ioc->name));
+	timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
+	    timeout*HZ);
+	if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+		ret = MPT_SCANDV_DID_RESET;
+		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
+		    cmd));
+		if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+			mpt_free_msg_frame(ioc, mf);
+			goto out;
+		}
+		if (!timeleft) {
+			printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+			    ioc->name, __func__);
+			mpt_HardResetHandler(ioc, CAN_SLEEP);
+			mpt_free_msg_frame(ioc, mf);
+		}
+		goto out;
 	}
 
-	return rc;
+	ret = ioc->internal_cmds.completion_code;
+	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
+			ioc->name, __func__, ret));
+
+ out:
+	CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
+	mutex_unlock(&ioc->internal_cmds.mutex);
+	return ret;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -3491,6 +3240,7 @@
 	&dev_attr_debug_level,
 	NULL,
 };
+
 EXPORT_SYMBOL(mptscsih_host_attrs);
 
 EXPORT_SYMBOL(mptscsih_remove);
@@ -3516,6 +3266,5 @@
 EXPORT_SYMBOL(mptscsih_ioc_reset);
 EXPORT_SYMBOL(mptscsih_change_queue_depth);
 EXPORT_SYMBOL(mptscsih_timer_expired);
-EXPORT_SYMBOL(mptscsih_TMHandler);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index 319aa30..eb3f677 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -60,6 +60,7 @@
 #define MPT_SCANDV_SELECTION_TIMEOUT	(0x00000008)
 #define MPT_SCANDV_ISSUE_SENSE		(0x00000010)
 #define MPT_SCANDV_FALLBACK		(0x00000020)
+#define MPT_SCANDV_BUSY			(0x00000040)
 
 #define MPT_SCANDV_MAX_RETRIES		(10)
 
@@ -89,6 +90,7 @@
 
 #endif
 
+
 typedef struct _internal_cmd {
 	char		*data;		/* data pointer */
 	dma_addr_t	data_dma;	/* data dma address */
@@ -112,6 +114,8 @@
 extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func);
 extern const char * mptscsih_info(struct Scsi_Host *SChost);
 extern int mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *));
+extern int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel,
+	u8 id, int lun, int ctx2abort, ulong timeout);
 extern void mptscsih_slave_destroy(struct scsi_device *device);
 extern int mptscsih_slave_configure(struct scsi_device *device);
 extern int mptscsih_abort(struct scsi_cmnd * SCpnt);
@@ -126,7 +130,8 @@
 extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
 extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth);
 extern void mptscsih_timer_expired(unsigned long data);
-extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
 extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id);
 extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id);
 extern struct device_attribute *mptscsih_host_attrs[];
+extern struct scsi_cmnd	*mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
+extern void mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 6162014..c5b808f 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -300,7 +300,7 @@
 	flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
 		(IOCPage4Ptr->Header.PageLength + ii) * 4;
 
-	mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
+	ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
 
 	ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		"writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
@@ -614,19 +614,24 @@
 	spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0;
 }
 
-static int
+int
 mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
 {
+	MPT_ADAPTER	*ioc = hd->ioc;
 	MpiRaidActionRequest_t	*pReq;
 	MPT_FRAME_HDR		*mf;
-	MPT_ADAPTER *ioc = hd->ioc;
+	int			ret;
+	unsigned long 	 	timeleft;
+
+	mutex_lock(&ioc->internal_cmds.mutex);
 
 	/* Get and Populate a free Frame
 	 */
 	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
-		ddvprintk(ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
-					ioc->name));
-		return -EAGAIN;
+		dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT
+			"%s: no msg frames!\n", ioc->name, __func__));
+		ret = -EAGAIN;
+		goto out;
 	}
 	pReq = (MpiRaidActionRequest_t *)mf;
 	if (quiesce)
@@ -643,29 +648,36 @@
 	pReq->Reserved2 = 0;
 	pReq->ActionDataWord = 0; /* Reserved for this action */
 
-	mpt_add_sge((char *)&pReq->ActionDataSGE,
+	ioc->add_sge((char *)&pReq->ActionDataSGE,
 		MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
 
 	ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
 			ioc->name, pReq->Action, channel, id));
 
-	hd->pLocal = NULL;
-	hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
-	hd->scandv_wait_done = 0;
-
-	/* Save cmd pointer, for resource free if timeout or
-	 * FW reload occurs
-	 */
-	hd->cmdPtr = mf;
-
-	add_timer(&hd->timer);
+	INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
 	mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
-	wait_event(hd->scandv_waitq, hd->scandv_wait_done);
+	timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, 10*HZ);
+	if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+		ret = -ETIME;
+		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n",
+		    ioc->name, __func__));
+		if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+			goto out;
+		if (!timeleft) {
+			printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+			    ioc->name, __func__);
+			mpt_HardResetHandler(ioc, CAN_SLEEP);
+			mpt_free_msg_frame(ioc, mf);
+		}
+		goto out;
+	}
 
-	if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0))
-		return -1;
+	ret = ioc->internal_cmds.completion_code;
 
-	return 0;
+ out:
+	CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
+	mutex_unlock(&ioc->internal_cmds.mutex);
+	return ret;
 }
 
 static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
@@ -1423,17 +1435,15 @@
 	 * A slightly different algorithm is required for
 	 * 64bit SGEs.
 	 */
-	scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
-	if (sizeof(dma_addr_t) == sizeof(u64)) {
+	scale = ioc->req_sz/ioc->SGE_size;
+	if (ioc->sg_addr_size == sizeof(u64)) {
 		numSGE = (scale - 1) *
 		  (ioc->facts.MaxChainDepth-1) + scale +
-		  (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
-		  sizeof(u32));
+		  (ioc->req_sz - 60) / ioc->SGE_size;
 	} else {
 		numSGE = 1 + (scale - 1) *
 		  (ioc->facts.MaxChainDepth-1) + scale +
-		  (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
-		  sizeof(u32));
+		  (ioc->req_sz - 64) / ioc->SGE_size;
 	}
 
 	if (numSGE < sh->sg_tablesize) {
@@ -1464,9 +1474,6 @@
 
 	/* Clear the TM flags
 	 */
-	hd->tmPending = 0;
-	hd->tmState = TM_STATE_NONE;
-	hd->resetPending = 0;
 	hd->abortSCpnt = NULL;
 
 	/* Clear the pointer used to store
@@ -1493,8 +1500,6 @@
 		mpt_saf_te));
 	ioc->spi_data.noQas = 0;
 
-	init_waitqueue_head(&hd->scandv_waitq);
-	hd->scandv_wait_done = 0;
 	hd->last_queue_full = 0;
 	hd->spi_pending = 0;
 
@@ -1514,7 +1519,7 @@
 	 * issue internal bus reset
 	 */
 	if (ioc->spi_data.bus_reset)
-		mptscsih_TMHandler(hd,
+		mptscsih_IssueTaskMgmt(hd,
 		    MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
 		    0, 0, 0, 0, 5);
 
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index b4cf691..3eb87bd 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -155,7 +155,7 @@
 
 config MMC_IMX
 	tristate "Motorola i.MX Multimedia Card Interface support"
-	depends on ARCH_IMX
+	depends on ARCH_MX1
 	help
 	  This selects the Motorola i.MX Multimedia card Interface.
 	  If you have a i.MX platform with a Multimedia Card slot,
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index cf6a100..7b603e4 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -177,6 +177,7 @@
  *	available.
  * @wp_pin: GPIO pin used for card write protect sending, or negative
  *	if not available.
+ * @detect_is_active_high: The state of the detect pin when it is active.
  * @detect_timer: Timer used for debouncing @detect_pin interrupts.
  */
 struct atmel_mci_slot {
@@ -196,6 +197,7 @@
 
 	int			detect_pin;
 	int			wp_pin;
+	bool			detect_is_active_high;
 
 	struct timer_list	detect_timer;
 };
@@ -924,7 +926,8 @@
 	struct atmel_mci_slot	*slot = mmc_priv(mmc);
 
 	if (gpio_is_valid(slot->detect_pin)) {
-		present = !gpio_get_value(slot->detect_pin);
+		present = !(gpio_get_value(slot->detect_pin) ^
+			    slot->detect_is_active_high);
 		dev_dbg(&mmc->class_dev, "card is %spresent\n",
 				present ? "" : "not ");
 	}
@@ -1028,7 +1031,8 @@
 		return;
 
 	enable_irq(gpio_to_irq(slot->detect_pin));
-	present = !gpio_get_value(slot->detect_pin);
+	present = !(gpio_get_value(slot->detect_pin) ^
+		    slot->detect_is_active_high);
 	present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags);
 
 	dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n",
@@ -1456,6 +1460,7 @@
 	slot->host = host;
 	slot->detect_pin = slot_data->detect_pin;
 	slot->wp_pin = slot_data->wp_pin;
+	slot->detect_is_active_high = slot_data->detect_is_active_high;
 	slot->sdc_reg = sdc_reg;
 
 	mmc->ops = &atmci_ops;
@@ -1477,7 +1482,8 @@
 		if (gpio_request(slot->detect_pin, "mmc_detect")) {
 			dev_dbg(&mmc->class_dev, "no detect pin available\n");
 			slot->detect_pin = -EBUSY;
-		} else if (gpio_get_value(slot->detect_pin)) {
+		} else if (gpio_get_value(slot->detect_pin) ^
+				slot->detect_is_active_high) {
 			clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
 		}
 	}
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 7d4febd..e1aa847 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -546,7 +546,7 @@
 		host->mclk = clk_get_rate(host->clk);
 		DBG(host, "eventual mclk rate: %u Hz\n", host->mclk);
 	}
-	host->base = ioremap(dev->res.start, SZ_4K);
+	host->base = ioremap(dev->res.start, resource_size(&dev->res));
 	if (!host->base) {
 		ret = -ENOMEM;
 		goto clk_disable;
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index c40cb96..1cf9cfb 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1073,7 +1073,6 @@
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 	mmc->max_seg_size = mmc->max_req_size;
 
-	mmc->ocr_avail = mmc_slot(host).ocr_mask;
 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
 
 	if (pdata->slots[host->slot_id].wires >= 8)
@@ -1110,13 +1109,14 @@
 		goto err_irq;
 	}
 
+	/* initialize power supplies, gpios, etc */
 	if (pdata->init != NULL) {
 		if (pdata->init(&pdev->dev) != 0) {
-			dev_dbg(mmc_dev(host->mmc),
-				"Unable to configure MMC IRQs\n");
+			dev_dbg(mmc_dev(host->mmc), "late init error\n");
 			goto err_irq_cd_init;
 		}
 	}
+	mmc->ocr_avail = mmc_slot(host).ocr_mask;
 
 	/* Request IRQ for card detect */
 	if ((mmc_slot(host).card_detect_irq)) {
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index 2db166b..4eb4f37 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -17,6 +17,7 @@
 #include <linux/mmc/host.h>
 #include <linux/platform_device.h>
 #include <linux/cpufreq.h>
+#include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 
@@ -789,7 +790,7 @@
 
 	last_source = source;
 
-	s3c2410_dma_devconfig(host->dma, source, 3,
+	s3c2410_dma_devconfig(host->dma, source,
 			      host->mem->start + host->sdidata);
 
 	if (!setup_ok) {
@@ -1121,7 +1122,7 @@
 	case MMC_POWER_OFF:
 	default:
 		s3c2410_gpio_setpin(S3C2410_GPE5, 0);
-		s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_OUTP);
+		s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPIO_OUTPUT);
 
 		if (host->is2440)
 			mci_con |= S3C2440_SDICON_SDRESET;
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index f2e9de1..6391e3d 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -39,7 +39,6 @@
 #include <mach/gpmc.h>
 #include <mach/onenand.h>
 #include <mach/gpio.h>
-#include <mach/pm.h>
 
 #include <mach/dma.h>
 
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index b4683ce..3111b6c 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2264,6 +2264,17 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called bnx2.  This is recommended.
 
+config CNIC
+	tristate "Broadcom CNIC support"
+	depends on BNX2
+	depends on UIO
+	help
+	  This driver supports offload features of Broadcom NetXtremeII
+	  gigabit Ethernet cards.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called cnic.  This is recommended.
+
 config SPIDER_NET
 	tristate "Spider Gigabit Ethernet driver"
 	depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB)
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index a1c25cb..db30ebd 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -73,6 +73,7 @@
 obj-$(CONFIG_FEALNX) += fealnx.o
 obj-$(CONFIG_TIGON3) += tg3.o
 obj-$(CONFIG_BNX2) += bnx2.o
+obj-$(CONFIG_CNIC) += cnic.o
 obj-$(CONFIG_BNX2X) += bnx2x.o
 bnx2x-objs := bnx2x_main.o bnx2x_link.o
 spidernet-y += spider_net.o spider_net_ethtool.o
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
index a740053..b6d1881 100644
--- a/drivers/net/arm/ixp4xx_eth.c
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -456,7 +456,8 @@
 	debug_desc(phys, desc);
 	BUG_ON(phys & 0x1F);
 	qmgr_put_entry(queue, phys);
-	BUG_ON(qmgr_stat_overflow(queue));
+	/* Don't check for queue overflow here, we've allocated sufficient
+	   length and queues >= 32 don't support this check anyway. */
 }
 
 
@@ -512,8 +513,8 @@
 #endif
 			napi_complete(napi);
 			qmgr_enable_irq(rxq);
-			if (!qmgr_stat_empty(rxq) &&
-			    napi_reschedule(napi)) {
+			if (!qmgr_stat_below_low_watermark(rxq) &&
+			    napi_reschedule(napi)) { /* not empty again */
 #if DEBUG_RX
 				printk(KERN_DEBUG "%s: eth_poll"
 				       " napi_reschedule successed\n",
@@ -630,9 +631,9 @@
 			port->tx_buff_tab[n_desc] = NULL;
 		}
 
-		start = qmgr_stat_empty(port->plat->txreadyq);
+		start = qmgr_stat_below_low_watermark(port->plat->txreadyq);
 		queue_put_desc(port->plat->txreadyq, phys, desc);
-		if (start) {
+		if (start) { /* TX-ready queue was empty */
 #if DEBUG_TX
 			printk(KERN_DEBUG "%s: eth_txdone_irq xmit ready\n",
 			       port->netdev->name);
@@ -708,13 +709,14 @@
 	queue_put_desc(TX_QUEUE(port->id), tx_desc_phys(port, n), desc);
 	dev->trans_start = jiffies;
 
-	if (qmgr_stat_empty(txreadyq)) {
+	if (qmgr_stat_below_low_watermark(txreadyq)) { /* empty */
 #if DEBUG_TX
 		printk(KERN_DEBUG "%s: eth_xmit queue full\n", dev->name);
 #endif
 		netif_stop_queue(dev);
 		/* we could miss TX ready interrupt */
-		if (!qmgr_stat_empty(txreadyq)) {
+		/* really empty in fact */
+		if (!qmgr_stat_below_low_watermark(txreadyq)) {
 #if DEBUG_TX
 			printk(KERN_DEBUG "%s: eth_xmit ready again\n",
 			       dev->name);
@@ -814,29 +816,29 @@
 	int err;
 
 	err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0,
-			    "%s:RX-free", port->netdev->name);
+				 "%s:RX-free", port->netdev->name);
 	if (err)
 		return err;
 
 	err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0,
-			    "%s:RX", port->netdev->name);
+				 "%s:RX", port->netdev->name);
 	if (err)
 		goto rel_rxfree;
 
 	err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0,
-			    "%s:TX", port->netdev->name);
+				 "%s:TX", port->netdev->name);
 	if (err)
 		goto rel_rx;
 
 	err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0,
-			    "%s:TX-ready", port->netdev->name);
+				 "%s:TX-ready", port->netdev->name);
 	if (err)
 		goto rel_tx;
 
 	/* TX-done queue handles skbs sent out by the NPEs */
 	if (!ports_open) {
 		err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0,
-				    "%s:TX-done", DRV_NAME);
+					 "%s:TX-done", DRV_NAME);
 		if (err)
 			goto rel_txready;
 	}
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index b0cb29d..3f5fcb0 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -49,6 +49,10 @@
 #include <linux/firmware.h>
 #include <linux/log2.h>
 
+#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
+#define BCM_CNIC 1
+#include "cnic_if.h"
+#endif
 #include "bnx2.h"
 #include "bnx2_fw.h"
 
@@ -315,6 +319,158 @@
 	spin_unlock_bh(&bp->indirect_lock);
 }
 
+#ifdef BCM_CNIC
+static int
+bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info)
+{
+	struct bnx2 *bp = netdev_priv(dev);
+	struct drv_ctl_io *io = &info->data.io;
+
+	switch (info->cmd) {
+	case DRV_CTL_IO_WR_CMD:
+		bnx2_reg_wr_ind(bp, io->offset, io->data);
+		break;
+	case DRV_CTL_IO_RD_CMD:
+		io->data = bnx2_reg_rd_ind(bp, io->offset);
+		break;
+	case DRV_CTL_CTX_WR_CMD:
+		bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
+{
+	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+	int sb_id;
+
+	if (bp->flags & BNX2_FLAG_USING_MSIX) {
+		cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
+		bnapi->cnic_present = 0;
+		sb_id = bp->irq_nvecs;
+		cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
+	} else {
+		cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
+		bnapi->cnic_tag = bnapi->last_status_idx;
+		bnapi->cnic_present = 1;
+		sb_id = 0;
+		cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
+	}
+
+	cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector;
+	cp->irq_arr[0].status_blk = (void *)
+		((unsigned long) bnapi->status_blk.msi +
+		(BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
+	cp->irq_arr[0].status_blk_num = sb_id;
+	cp->num_irq = 1;
+}
+
+static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops,
+			      void *data)
+{
+	struct bnx2 *bp = netdev_priv(dev);
+	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+	if (ops == NULL)
+		return -EINVAL;
+
+	if (cp->drv_state & CNIC_DRV_STATE_REGD)
+		return -EBUSY;
+
+	bp->cnic_data = data;
+	rcu_assign_pointer(bp->cnic_ops, ops);
+
+	cp->num_irq = 0;
+	cp->drv_state = CNIC_DRV_STATE_REGD;
+
+	bnx2_setup_cnic_irq_info(bp);
+
+	return 0;
+}
+
+static int bnx2_unregister_cnic(struct net_device *dev)
+{
+	struct bnx2 *bp = netdev_priv(dev);
+	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+	cp->drv_state = 0;
+	bnapi->cnic_present = 0;
+	rcu_assign_pointer(bp->cnic_ops, NULL);
+	synchronize_rcu();
+	return 0;
+}
+
+struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
+{
+	struct bnx2 *bp = netdev_priv(dev);
+	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+	cp->drv_owner = THIS_MODULE;
+	cp->chip_id = bp->chip_id;
+	cp->pdev = bp->pdev;
+	cp->io_base = bp->regview;
+	cp->drv_ctl = bnx2_drv_ctl;
+	cp->drv_register_cnic = bnx2_register_cnic;
+	cp->drv_unregister_cnic = bnx2_unregister_cnic;
+
+	return cp;
+}
+EXPORT_SYMBOL(bnx2_cnic_probe);
+
+static void
+bnx2_cnic_stop(struct bnx2 *bp)
+{
+	struct cnic_ops *c_ops;
+	struct cnic_ctl_info info;
+
+	rcu_read_lock();
+	c_ops = rcu_dereference(bp->cnic_ops);
+	if (c_ops) {
+		info.cmd = CNIC_CTL_STOP_CMD;
+		c_ops->cnic_ctl(bp->cnic_data, &info);
+	}
+	rcu_read_unlock();
+}
+
+static void
+bnx2_cnic_start(struct bnx2 *bp)
+{
+	struct cnic_ops *c_ops;
+	struct cnic_ctl_info info;
+
+	rcu_read_lock();
+	c_ops = rcu_dereference(bp->cnic_ops);
+	if (c_ops) {
+		if (!(bp->flags & BNX2_FLAG_USING_MSIX)) {
+			struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+
+			bnapi->cnic_tag = bnapi->last_status_idx;
+		}
+		info.cmd = CNIC_CTL_START_CMD;
+		c_ops->cnic_ctl(bp->cnic_data, &info);
+	}
+	rcu_read_unlock();
+}
+
+#else
+
+static void
+bnx2_cnic_stop(struct bnx2 *bp)
+{
+}
+
+static void
+bnx2_cnic_start(struct bnx2 *bp)
+{
+}
+
+#endif
+
 static int
 bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
 {
@@ -488,6 +644,7 @@
 static void
 bnx2_netif_stop(struct bnx2 *bp)
 {
+	bnx2_cnic_stop(bp);
 	bnx2_disable_int_sync(bp);
 	if (netif_running(bp->dev)) {
 		bnx2_napi_disable(bp);
@@ -504,6 +661,7 @@
 			netif_tx_wake_all_queues(bp->dev);
 			bnx2_napi_enable(bp);
 			bnx2_enable_int(bp);
+			bnx2_cnic_start(bp);
 		}
 	}
 }
@@ -3164,6 +3322,11 @@
 	if (bnx2_has_fast_work(bnapi))
 		return 1;
 
+#ifdef BCM_CNIC
+	if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx))
+		return 1;
+#endif
+
 	if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
 	    (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
 		return 1;
@@ -3193,6 +3356,23 @@
 	bp->idle_chk_status_idx = bnapi->last_status_idx;
 }
 
+#ifdef BCM_CNIC
+static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi)
+{
+	struct cnic_ops *c_ops;
+
+	if (!bnapi->cnic_present)
+		return;
+
+	rcu_read_lock();
+	c_ops = rcu_dereference(bp->cnic_ops);
+	if (c_ops)
+		bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data,
+						      bnapi->status_blk.msi);
+	rcu_read_unlock();
+}
+#endif
+
 static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
 {
 	struct status_block *sblk = bnapi->status_blk.msi;
@@ -3267,6 +3447,10 @@
 
 		work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
 
+#ifdef BCM_CNIC
+		bnx2_poll_cnic(bp, bnapi);
+#endif
+
 		/* bnapi->last_status_idx is used below to tell the hw how
 		 * much work has been processed, so we must read it before
 		 * checking for more work.
@@ -4632,8 +4816,11 @@
 	val = REG_RD(bp, BNX2_MQ_CONFIG);
 	val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
 	val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
-	if (CHIP_ID(bp) == CHIP_ID_5709_A0 || CHIP_ID(bp) == CHIP_ID_5709_A1)
-		val |= BNX2_MQ_CONFIG_HALT_DIS;
+	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+		val |= BNX2_MQ_CONFIG_BIN_MQ_MODE;
+		if (CHIP_REV(bp) == CHIP_REV_Ax)
+			val |= BNX2_MQ_CONFIG_HALT_DIS;
+	}
 
 	REG_WR(bp, BNX2_MQ_CONFIG, val);
 
@@ -7471,7 +7658,7 @@
 	INIT_WORK(&bp->reset_task, bnx2_reset_task);
 
 	dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
-	mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS);
+	mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS + 1);
 	dev->mem_end = dev->mem_start + mem_len;
 	dev->irq = pdev->irq;
 
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 5b570e1..a1ff739 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -361,6 +361,9 @@
 #define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE	 (1<<28)
 
 #define BNX2_L2CTX_HOST_BDIDX				0x00000004
+#define BNX2_L2CTX_STATUSB_NUM_SHIFT			 16
+#define BNX2_L2CTX_STATUSB_NUM(sb_id)			 \
+	(((sb_id) > 0) ? (((sb_id) + 7) << BNX2_L2CTX_STATUSB_NUM_SHIFT) : 0)
 #define BNX2_L2CTX_HOST_BSEQ				0x00000008
 #define BNX2_L2CTX_NX_BSEQ				0x0000000c
 #define BNX2_L2CTX_NX_BDHADDR_HI			0x00000010
@@ -5900,6 +5903,7 @@
 #define BNX2_RXP_FTQ_CTL_CUR_DEPTH			 (0x3ffL<<22)
 
 #define BNX2_RXP_SCRATCH				0x000e0000
+#define BNX2_RXP_SCRATCH_RXP_FLOOD			 0x000e0024
 #define BNX2_RXP_SCRATCH_RSS_TBL_SZ			 0x000e0038
 #define BNX2_RXP_SCRATCH_RSS_TBL			 0x000e003c
 #define BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES		 128
@@ -6678,6 +6682,11 @@
 	u32 			last_status_idx;
 	u32			int_num;
 
+#ifdef BCM_CNIC
+	u32			cnic_tag;
+	int			cnic_present;
+#endif
+
 	struct bnx2_rx_ring_info	rx_ring;
 	struct bnx2_tx_ring_info	tx_ring;
 };
@@ -6727,6 +6736,11 @@
 	int		tx_ring_size;
 	u32		tx_wake_thresh;
 
+#ifdef BCM_CNIC
+	struct cnic_ops		*cnic_ops;
+	void			*cnic_data;
+#endif
+
 	/* End of fields used in the performance code paths. */
 
 	unsigned int		current_interval;
@@ -6885,6 +6899,10 @@
 
 	u32			idle_chk_status_idx;
 
+#ifdef BCM_CNIC
+	struct cnic_eth_dev	cnic_eth_dev;
+#endif
+
 	const struct firmware	*mips_firmware;
 	const struct firmware	*rv2p_firmware;
 };
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
new file mode 100644
index 0000000..44f77eb
--- /dev/null
+++ b/drivers/net/cnic.c
@@ -0,0 +1,2717 @@
+/* cnic.c: Broadcom CNIC core network driver.
+ *
+ * Copyright (c) 2006-2009 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Original skeleton written by: John(Zongxi) Chen (zongxi@broadcom.com)
+ * Modified and maintained by: Michael Chan <mchan@broadcom.com>
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/uio_driver.h>
+#include <linux/in.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/module.h>
+
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+#define BCM_VLAN 1
+#endif
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/route.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <scsi/iscsi_if.h>
+
+#include "cnic_if.h"
+#include "bnx2.h"
+#include "cnic.h"
+#include "cnic_defs.h"
+
+#define DRV_MODULE_NAME		"cnic"
+#define PFX DRV_MODULE_NAME	": "
+
+static char version[] __devinitdata =
+	"Broadcom NetXtreme II CNIC Driver " DRV_MODULE_NAME " v" CNIC_MODULE_VERSION " (" CNIC_MODULE_RELDATE ")\n";
+
+MODULE_AUTHOR("Michael Chan <mchan@broadcom.com> and John(Zongxi) "
+	      "Chen (zongxi@broadcom.com");
+MODULE_DESCRIPTION("Broadcom NetXtreme II CNIC Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CNIC_MODULE_VERSION);
+
+static LIST_HEAD(cnic_dev_list);
+static DEFINE_RWLOCK(cnic_dev_lock);
+static DEFINE_MUTEX(cnic_lock);
+
+static struct cnic_ulp_ops *cnic_ulp_tbl[MAX_CNIC_ULP_TYPE];
+
+static int cnic_service_bnx2(void *, void *);
+static int cnic_ctl(void *, struct cnic_ctl_info *);
+
+static struct cnic_ops cnic_bnx2_ops = {
+	.cnic_owner	= THIS_MODULE,
+	.cnic_handler	= cnic_service_bnx2,
+	.cnic_ctl	= cnic_ctl,
+};
+
+static void cnic_shutdown_bnx2_rx_ring(struct cnic_dev *);
+static void cnic_init_bnx2_tx_ring(struct cnic_dev *);
+static void cnic_init_bnx2_rx_ring(struct cnic_dev *);
+static int cnic_cm_set_pg(struct cnic_sock *);
+
+static int cnic_uio_open(struct uio_info *uinfo, struct inode *inode)
+{
+	struct cnic_dev *dev = uinfo->priv;
+	struct cnic_local *cp = dev->cnic_priv;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (cp->uio_dev != -1)
+		return -EBUSY;
+
+	cp->uio_dev = iminor(inode);
+
+	cnic_shutdown_bnx2_rx_ring(dev);
+
+	cnic_init_bnx2_tx_ring(dev);
+	cnic_init_bnx2_rx_ring(dev);
+
+	return 0;
+}
+
+static int cnic_uio_close(struct uio_info *uinfo, struct inode *inode)
+{
+	struct cnic_dev *dev = uinfo->priv;
+	struct cnic_local *cp = dev->cnic_priv;
+
+	cp->uio_dev = -1;
+	return 0;
+}
+
+static inline void cnic_hold(struct cnic_dev *dev)
+{
+	atomic_inc(&dev->ref_count);
+}
+
+static inline void cnic_put(struct cnic_dev *dev)
+{
+	atomic_dec(&dev->ref_count);
+}
+
+static inline void csk_hold(struct cnic_sock *csk)
+{
+	atomic_inc(&csk->ref_count);
+}
+
+static inline void csk_put(struct cnic_sock *csk)
+{
+	atomic_dec(&csk->ref_count);
+}
+
+static struct cnic_dev *cnic_from_netdev(struct net_device *netdev)
+{
+	struct cnic_dev *cdev;
+
+	read_lock(&cnic_dev_lock);
+	list_for_each_entry(cdev, &cnic_dev_list, list) {
+		if (netdev == cdev->netdev) {
+			cnic_hold(cdev);
+			read_unlock(&cnic_dev_lock);
+			return cdev;
+		}
+	}
+	read_unlock(&cnic_dev_lock);
+	return NULL;
+}
+
+static void cnic_ctx_wr(struct cnic_dev *dev, u32 cid_addr, u32 off, u32 val)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_eth_dev *ethdev = cp->ethdev;
+	struct drv_ctl_info info;
+	struct drv_ctl_io *io = &info.data.io;
+
+	info.cmd = DRV_CTL_CTX_WR_CMD;
+	io->cid_addr = cid_addr;
+	io->offset = off;
+	io->data = val;
+	ethdev->drv_ctl(dev->netdev, &info);
+}
+
+static void cnic_reg_wr_ind(struct cnic_dev *dev, u32 off, u32 val)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_eth_dev *ethdev = cp->ethdev;
+	struct drv_ctl_info info;
+	struct drv_ctl_io *io = &info.data.io;
+
+	info.cmd = DRV_CTL_IO_WR_CMD;
+	io->offset = off;
+	io->data = val;
+	ethdev->drv_ctl(dev->netdev, &info);
+}
+
+static u32 cnic_reg_rd_ind(struct cnic_dev *dev, u32 off)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_eth_dev *ethdev = cp->ethdev;
+	struct drv_ctl_info info;
+	struct drv_ctl_io *io = &info.data.io;
+
+	info.cmd = DRV_CTL_IO_RD_CMD;
+	io->offset = off;
+	ethdev->drv_ctl(dev->netdev, &info);
+	return io->data;
+}
+
+static int cnic_in_use(struct cnic_sock *csk)
+{
+	return test_bit(SK_F_INUSE, &csk->flags);
+}
+
+static void cnic_kwq_completion(struct cnic_dev *dev, u32 count)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_eth_dev *ethdev = cp->ethdev;
+	struct drv_ctl_info info;
+
+	info.cmd = DRV_CTL_COMPLETION_CMD;
+	info.data.comp.comp_count = count;
+	ethdev->drv_ctl(dev->netdev, &info);
+}
+
+static int cnic_send_nlmsg(struct cnic_local *cp, u32 type,
+			   struct cnic_sock *csk)
+{
+	struct iscsi_path path_req;
+	char *buf = NULL;
+	u16 len = 0;
+	u32 msg_type = ISCSI_KEVENT_IF_DOWN;
+	struct cnic_ulp_ops *ulp_ops;
+
+	if (cp->uio_dev == -1)
+		return -ENODEV;
+
+	if (csk) {
+		len = sizeof(path_req);
+		buf = (char *) &path_req;
+		memset(&path_req, 0, len);
+
+		msg_type = ISCSI_KEVENT_PATH_REQ;
+		path_req.handle = (u64) csk->l5_cid;
+		if (test_bit(SK_F_IPV6, &csk->flags)) {
+			memcpy(&path_req.dst.v6_addr, &csk->dst_ip[0],
+			       sizeof(struct in6_addr));
+			path_req.ip_addr_len = 16;
+		} else {
+			memcpy(&path_req.dst.v4_addr, &csk->dst_ip[0],
+			       sizeof(struct in_addr));
+			path_req.ip_addr_len = 4;
+		}
+		path_req.vlan_id = csk->vlan_id;
+		path_req.pmtu = csk->mtu;
+	}
+
+	rcu_read_lock();
+	ulp_ops = rcu_dereference(cp->ulp_ops[CNIC_ULP_ISCSI]);
+	if (ulp_ops)
+		ulp_ops->iscsi_nl_send_msg(cp->dev, msg_type, buf, len);
+	rcu_read_unlock();
+	return 0;
+}
+
+static int cnic_iscsi_nl_msg_recv(struct cnic_dev *dev, u32 msg_type,
+				  char *buf, u16 len)
+{
+	int rc = -EINVAL;
+
+	switch (msg_type) {
+	case ISCSI_UEVENT_PATH_UPDATE: {
+		struct cnic_local *cp;
+		u32 l5_cid;
+		struct cnic_sock *csk;
+		struct iscsi_path *path_resp;
+
+		if (len < sizeof(*path_resp))
+			break;
+
+		path_resp = (struct iscsi_path *) buf;
+		cp = dev->cnic_priv;
+		l5_cid = (u32) path_resp->handle;
+		if (l5_cid >= MAX_CM_SK_TBL_SZ)
+			break;
+
+		csk = &cp->csk_tbl[l5_cid];
+		csk_hold(csk);
+		if (cnic_in_use(csk)) {
+			memcpy(csk->ha, path_resp->mac_addr, 6);
+			if (test_bit(SK_F_IPV6, &csk->flags))
+				memcpy(&csk->src_ip[0], &path_resp->src.v6_addr,
+				       sizeof(struct in6_addr));
+			else
+				memcpy(&csk->src_ip[0], &path_resp->src.v4_addr,
+				       sizeof(struct in_addr));
+			if (is_valid_ether_addr(csk->ha))
+				cnic_cm_set_pg(csk);
+		}
+		csk_put(csk);
+		rc = 0;
+	}
+	}
+
+	return rc;
+}
+
+static int cnic_offld_prep(struct cnic_sock *csk)
+{
+	if (test_and_set_bit(SK_F_OFFLD_SCHED, &csk->flags))
+		return 0;
+
+	if (!test_bit(SK_F_CONNECT_START, &csk->flags)) {
+		clear_bit(SK_F_OFFLD_SCHED, &csk->flags);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int cnic_close_prep(struct cnic_sock *csk)
+{
+	clear_bit(SK_F_CONNECT_START, &csk->flags);
+	smp_mb__after_clear_bit();
+
+	if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) {
+		while (test_and_set_bit(SK_F_OFFLD_SCHED, &csk->flags))
+			msleep(1);
+
+		return 1;
+	}
+	return 0;
+}
+
+static int cnic_abort_prep(struct cnic_sock *csk)
+{
+	clear_bit(SK_F_CONNECT_START, &csk->flags);
+	smp_mb__after_clear_bit();
+
+	while (test_and_set_bit(SK_F_OFFLD_SCHED, &csk->flags))
+		msleep(1);
+
+	if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) {
+		csk->state = L4_KCQE_OPCODE_VALUE_RESET_COMP;
+		return 1;
+	}
+
+	return 0;
+}
+
+int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops)
+{
+	struct cnic_dev *dev;
+
+	if (ulp_type >= MAX_CNIC_ULP_TYPE) {
+		printk(KERN_ERR PFX "cnic_register_driver: Bad type %d\n",
+		       ulp_type);
+		return -EINVAL;
+	}
+	mutex_lock(&cnic_lock);
+	if (cnic_ulp_tbl[ulp_type]) {
+		printk(KERN_ERR PFX "cnic_register_driver: Type %d has already "
+				    "been registered\n", ulp_type);
+		mutex_unlock(&cnic_lock);
+		return -EBUSY;
+	}
+
+	read_lock(&cnic_dev_lock);
+	list_for_each_entry(dev, &cnic_dev_list, list) {
+		struct cnic_local *cp = dev->cnic_priv;
+
+		clear_bit(ULP_F_INIT, &cp->ulp_flags[ulp_type]);
+	}
+	read_unlock(&cnic_dev_lock);
+
+	rcu_assign_pointer(cnic_ulp_tbl[ulp_type], ulp_ops);
+	mutex_unlock(&cnic_lock);
+
+	/* Prevent race conditions with netdev_event */
+	rtnl_lock();
+	read_lock(&cnic_dev_lock);
+	list_for_each_entry(dev, &cnic_dev_list, list) {
+		struct cnic_local *cp = dev->cnic_priv;
+
+		if (!test_and_set_bit(ULP_F_INIT, &cp->ulp_flags[ulp_type]))
+			ulp_ops->cnic_init(dev);
+	}
+	read_unlock(&cnic_dev_lock);
+	rtnl_unlock();
+
+	return 0;
+}
+
+int cnic_unregister_driver(int ulp_type)
+{
+	struct cnic_dev *dev;
+
+	if (ulp_type >= MAX_CNIC_ULP_TYPE) {
+		printk(KERN_ERR PFX "cnic_unregister_driver: Bad type %d\n",
+		       ulp_type);
+		return -EINVAL;
+	}
+	mutex_lock(&cnic_lock);
+	if (!cnic_ulp_tbl[ulp_type]) {
+		printk(KERN_ERR PFX "cnic_unregister_driver: Type %d has not "
+				    "been registered\n", ulp_type);
+		goto out_unlock;
+	}
+	read_lock(&cnic_dev_lock);
+	list_for_each_entry(dev, &cnic_dev_list, list) {
+		struct cnic_local *cp = dev->cnic_priv;
+
+		if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+			printk(KERN_ERR PFX "cnic_unregister_driver: Type %d "
+			       "still has devices registered\n", ulp_type);
+			read_unlock(&cnic_dev_lock);
+			goto out_unlock;
+		}
+	}
+	read_unlock(&cnic_dev_lock);
+
+	rcu_assign_pointer(cnic_ulp_tbl[ulp_type], NULL);
+
+	mutex_unlock(&cnic_lock);
+	synchronize_rcu();
+	return 0;
+
+out_unlock:
+	mutex_unlock(&cnic_lock);
+	return -EINVAL;
+}
+
+static int cnic_start_hw(struct cnic_dev *);
+static void cnic_stop_hw(struct cnic_dev *);
+
+static int cnic_register_device(struct cnic_dev *dev, int ulp_type,
+				void *ulp_ctx)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_ulp_ops *ulp_ops;
+
+	if (ulp_type >= MAX_CNIC_ULP_TYPE) {
+		printk(KERN_ERR PFX "cnic_register_device: Bad type %d\n",
+		       ulp_type);
+		return -EINVAL;
+	}
+	mutex_lock(&cnic_lock);
+	if (cnic_ulp_tbl[ulp_type] == NULL) {
+		printk(KERN_ERR PFX "cnic_register_device: Driver with type %d "
+				    "has not been registered\n", ulp_type);
+		mutex_unlock(&cnic_lock);
+		return -EAGAIN;
+	}
+	if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+		printk(KERN_ERR PFX "cnic_register_device: Type %d has already "
+		       "been registered to this device\n", ulp_type);
+		mutex_unlock(&cnic_lock);
+		return -EBUSY;
+	}
+
+	clear_bit(ULP_F_START, &cp->ulp_flags[ulp_type]);
+	cp->ulp_handle[ulp_type] = ulp_ctx;
+	ulp_ops = cnic_ulp_tbl[ulp_type];
+	rcu_assign_pointer(cp->ulp_ops[ulp_type], ulp_ops);
+	cnic_hold(dev);
+
+	if (test_bit(CNIC_F_CNIC_UP, &dev->flags))
+		if (!test_and_set_bit(ULP_F_START, &cp->ulp_flags[ulp_type]))
+			ulp_ops->cnic_start(cp->ulp_handle[ulp_type]);
+
+	mutex_unlock(&cnic_lock);
+
+	return 0;
+
+}
+EXPORT_SYMBOL(cnic_register_driver);
+
+static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+
+	if (ulp_type >= MAX_CNIC_ULP_TYPE) {
+		printk(KERN_ERR PFX "cnic_unregister_device: Bad type %d\n",
+		       ulp_type);
+		return -EINVAL;
+	}
+	mutex_lock(&cnic_lock);
+	if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+		rcu_assign_pointer(cp->ulp_ops[ulp_type], NULL);
+		cnic_put(dev);
+	} else {
+		printk(KERN_ERR PFX "cnic_unregister_device: device not "
+		       "registered to this ulp type %d\n", ulp_type);
+		mutex_unlock(&cnic_lock);
+		return -EINVAL;
+	}
+	mutex_unlock(&cnic_lock);
+
+	synchronize_rcu();
+
+	return 0;
+}
+EXPORT_SYMBOL(cnic_unregister_driver);
+
+static int cnic_init_id_tbl(struct cnic_id_tbl *id_tbl, u32 size, u32 start_id)
+{
+	id_tbl->start = start_id;
+	id_tbl->max = size;
+	id_tbl->next = 0;
+	spin_lock_init(&id_tbl->lock);
+	id_tbl->table = kzalloc(DIV_ROUND_UP(size, 32) * 4, GFP_KERNEL);
+	if (!id_tbl->table)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void cnic_free_id_tbl(struct cnic_id_tbl *id_tbl)
+{
+	kfree(id_tbl->table);
+	id_tbl->table = NULL;
+}
+
+static int cnic_alloc_id(struct cnic_id_tbl *id_tbl, u32 id)
+{
+	int ret = -1;
+
+	id -= id_tbl->start;
+	if (id >= id_tbl->max)
+		return ret;
+
+	spin_lock(&id_tbl->lock);
+	if (!test_bit(id, id_tbl->table)) {
+		set_bit(id, id_tbl->table);
+		ret = 0;
+	}
+	spin_unlock(&id_tbl->lock);
+	return ret;
+}
+
+/* Returns -1 if not successful */
+static u32 cnic_alloc_new_id(struct cnic_id_tbl *id_tbl)
+{
+	u32 id;
+
+	spin_lock(&id_tbl->lock);
+	id = find_next_zero_bit(id_tbl->table, id_tbl->max, id_tbl->next);
+	if (id >= id_tbl->max) {
+		id = -1;
+		if (id_tbl->next != 0) {
+			id = find_first_zero_bit(id_tbl->table, id_tbl->next);
+			if (id >= id_tbl->next)
+				id = -1;
+		}
+	}
+
+	if (id < id_tbl->max) {
+		set_bit(id, id_tbl->table);
+		id_tbl->next = (id + 1) & (id_tbl->max - 1);
+		id += id_tbl->start;
+	}
+
+	spin_unlock(&id_tbl->lock);
+
+	return id;
+}
+
+static void cnic_free_id(struct cnic_id_tbl *id_tbl, u32 id)
+{
+	if (id == -1)
+		return;
+
+	id -= id_tbl->start;
+	if (id >= id_tbl->max)
+		return;
+
+	clear_bit(id, id_tbl->table);
+}
+
+static void cnic_free_dma(struct cnic_dev *dev, struct cnic_dma *dma)
+{
+	int i;
+
+	if (!dma->pg_arr)
+		return;
+
+	for (i = 0; i < dma->num_pages; i++) {
+		if (dma->pg_arr[i]) {
+			pci_free_consistent(dev->pcidev, BCM_PAGE_SIZE,
+					    dma->pg_arr[i], dma->pg_map_arr[i]);
+			dma->pg_arr[i] = NULL;
+		}
+	}
+	if (dma->pgtbl) {
+		pci_free_consistent(dev->pcidev, dma->pgtbl_size,
+				    dma->pgtbl, dma->pgtbl_map);
+		dma->pgtbl = NULL;
+	}
+	kfree(dma->pg_arr);
+	dma->pg_arr = NULL;
+	dma->num_pages = 0;
+}
+
+static void cnic_setup_page_tbl(struct cnic_dev *dev, struct cnic_dma *dma)
+{
+	int i;
+	u32 *page_table = dma->pgtbl;
+
+	for (i = 0; i < dma->num_pages; i++) {
+		/* Each entry needs to be in big endian format. */
+		*page_table = (u32) ((u64) dma->pg_map_arr[i] >> 32);
+		page_table++;
+		*page_table = (u32) dma->pg_map_arr[i];
+		page_table++;
+	}
+}
+
+static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma,
+			  int pages, int use_pg_tbl)
+{
+	int i, size;
+	struct cnic_local *cp = dev->cnic_priv;
+
+	size = pages * (sizeof(void *) + sizeof(dma_addr_t));
+	dma->pg_arr = kzalloc(size, GFP_ATOMIC);
+	if (dma->pg_arr == NULL)
+		return -ENOMEM;
+
+	dma->pg_map_arr = (dma_addr_t *) (dma->pg_arr + pages);
+	dma->num_pages = pages;
+
+	for (i = 0; i < pages; i++) {
+		dma->pg_arr[i] = pci_alloc_consistent(dev->pcidev,
+						      BCM_PAGE_SIZE,
+						      &dma->pg_map_arr[i]);
+		if (dma->pg_arr[i] == NULL)
+			goto error;
+	}
+	if (!use_pg_tbl)
+		return 0;
+
+	dma->pgtbl_size = ((pages * 8) + BCM_PAGE_SIZE - 1) &
+			  ~(BCM_PAGE_SIZE - 1);
+	dma->pgtbl = pci_alloc_consistent(dev->pcidev, dma->pgtbl_size,
+					  &dma->pgtbl_map);
+	if (dma->pgtbl == NULL)
+		goto error;
+
+	cp->setup_pgtbl(dev, dma);
+
+	return 0;
+
+error:
+	cnic_free_dma(dev, dma);
+	return -ENOMEM;
+}
+
+static void cnic_free_resc(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	int i = 0;
+
+	if (cp->cnic_uinfo) {
+		cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
+		while (cp->uio_dev != -1 && i < 15) {
+			msleep(100);
+			i++;
+		}
+		uio_unregister_device(cp->cnic_uinfo);
+		kfree(cp->cnic_uinfo);
+		cp->cnic_uinfo = NULL;
+	}
+
+	if (cp->l2_buf) {
+		pci_free_consistent(dev->pcidev, cp->l2_buf_size,
+				    cp->l2_buf, cp->l2_buf_map);
+		cp->l2_buf = NULL;
+	}
+
+	if (cp->l2_ring) {
+		pci_free_consistent(dev->pcidev, cp->l2_ring_size,
+				    cp->l2_ring, cp->l2_ring_map);
+		cp->l2_ring = NULL;
+	}
+
+	for (i = 0; i < cp->ctx_blks; i++) {
+		if (cp->ctx_arr[i].ctx) {
+			pci_free_consistent(dev->pcidev, cp->ctx_blk_size,
+					    cp->ctx_arr[i].ctx,
+					    cp->ctx_arr[i].mapping);
+			cp->ctx_arr[i].ctx = NULL;
+		}
+	}
+	kfree(cp->ctx_arr);
+	cp->ctx_arr = NULL;
+	cp->ctx_blks = 0;
+
+	cnic_free_dma(dev, &cp->gbl_buf_info);
+	cnic_free_dma(dev, &cp->conn_buf_info);
+	cnic_free_dma(dev, &cp->kwq_info);
+	cnic_free_dma(dev, &cp->kcq_info);
+	kfree(cp->iscsi_tbl);
+	cp->iscsi_tbl = NULL;
+	kfree(cp->ctx_tbl);
+	cp->ctx_tbl = NULL;
+
+	cnic_free_id_tbl(&cp->cid_tbl);
+}
+
+static int cnic_alloc_context(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+
+	if (CHIP_NUM(cp) == CHIP_NUM_5709) {
+		int i, k, arr_size;
+
+		cp->ctx_blk_size = BCM_PAGE_SIZE;
+		cp->cids_per_blk = BCM_PAGE_SIZE / 128;
+		arr_size = BNX2_MAX_CID / cp->cids_per_blk *
+			   sizeof(struct cnic_ctx);
+		cp->ctx_arr = kzalloc(arr_size, GFP_KERNEL);
+		if (cp->ctx_arr == NULL)
+			return -ENOMEM;
+
+		k = 0;
+		for (i = 0; i < 2; i++) {
+			u32 j, reg, off, lo, hi;
+
+			if (i == 0)
+				off = BNX2_PG_CTX_MAP;
+			else
+				off = BNX2_ISCSI_CTX_MAP;
+
+			reg = cnic_reg_rd_ind(dev, off);
+			lo = reg >> 16;
+			hi = reg & 0xffff;
+			for (j = lo; j < hi; j += cp->cids_per_blk, k++)
+				cp->ctx_arr[k].cid = j;
+		}
+
+		cp->ctx_blks = k;
+		if (cp->ctx_blks >= (BNX2_MAX_CID / cp->cids_per_blk)) {
+			cp->ctx_blks = 0;
+			return -ENOMEM;
+		}
+
+		for (i = 0; i < cp->ctx_blks; i++) {
+			cp->ctx_arr[i].ctx =
+				pci_alloc_consistent(dev->pcidev, BCM_PAGE_SIZE,
+						     &cp->ctx_arr[i].mapping);
+			if (cp->ctx_arr[i].ctx == NULL)
+				return -ENOMEM;
+		}
+	}
+	return 0;
+}
+
+static int cnic_alloc_bnx2_resc(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct uio_info *uinfo;
+	int ret;
+
+	ret = cnic_alloc_dma(dev, &cp->kwq_info, KWQ_PAGE_CNT, 1);
+	if (ret)
+		goto error;
+	cp->kwq = (struct kwqe **) cp->kwq_info.pg_arr;
+
+	ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 1);
+	if (ret)
+		goto error;
+	cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr;
+
+	ret = cnic_alloc_context(dev);
+	if (ret)
+		goto error;
+
+	cp->l2_ring_size = 2 * BCM_PAGE_SIZE;
+	cp->l2_ring = pci_alloc_consistent(dev->pcidev, cp->l2_ring_size,
+					   &cp->l2_ring_map);
+	if (!cp->l2_ring)
+		goto error;
+
+	cp->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
+	cp->l2_buf_size = PAGE_ALIGN(cp->l2_buf_size);
+	cp->l2_buf = pci_alloc_consistent(dev->pcidev, cp->l2_buf_size,
+					   &cp->l2_buf_map);
+	if (!cp->l2_buf)
+		goto error;
+
+	uinfo = kzalloc(sizeof(*uinfo), GFP_ATOMIC);
+	if (!uinfo)
+		goto error;
+
+	uinfo->mem[0].addr = dev->netdev->base_addr;
+	uinfo->mem[0].internal_addr = dev->regview;
+	uinfo->mem[0].size = dev->netdev->mem_end - dev->netdev->mem_start;
+	uinfo->mem[0].memtype = UIO_MEM_PHYS;
+
+	uinfo->mem[1].addr = (unsigned long) cp->status_blk & PAGE_MASK;
+	if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
+		uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9;
+	else
+		uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE;
+	uinfo->mem[1].memtype = UIO_MEM_LOGICAL;
+
+	uinfo->mem[2].addr = (unsigned long) cp->l2_ring;
+	uinfo->mem[2].size = cp->l2_ring_size;
+	uinfo->mem[2].memtype = UIO_MEM_LOGICAL;
+
+	uinfo->mem[3].addr = (unsigned long) cp->l2_buf;
+	uinfo->mem[3].size = cp->l2_buf_size;
+	uinfo->mem[3].memtype = UIO_MEM_LOGICAL;
+
+	uinfo->name = "bnx2_cnic";
+	uinfo->version = CNIC_MODULE_VERSION;
+	uinfo->irq = UIO_IRQ_CUSTOM;
+
+	uinfo->open = cnic_uio_open;
+	uinfo->release = cnic_uio_close;
+
+	uinfo->priv = dev;
+
+	ret = uio_register_device(&dev->pcidev->dev, uinfo);
+	if (ret) {
+		kfree(uinfo);
+		goto error;
+	}
+
+	cp->cnic_uinfo = uinfo;
+
+	return 0;
+
+error:
+	cnic_free_resc(dev);
+	return ret;
+}
+
+static inline u32 cnic_kwq_avail(struct cnic_local *cp)
+{
+	return cp->max_kwq_idx -
+		((cp->kwq_prod_idx - cp->kwq_con_idx) & cp->max_kwq_idx);
+}
+
+static int cnic_submit_bnx2_kwqes(struct cnic_dev *dev, struct kwqe *wqes[],
+				  u32 num_wqes)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct kwqe *prod_qe;
+	u16 prod, sw_prod, i;
+
+	if (!test_bit(CNIC_F_CNIC_UP, &dev->flags))
+		return -EAGAIN;		/* bnx2 is down */
+
+	spin_lock_bh(&cp->cnic_ulp_lock);
+	if (num_wqes > cnic_kwq_avail(cp) &&
+	    !(cp->cnic_local_flags & CNIC_LCL_FL_KWQ_INIT)) {
+		spin_unlock_bh(&cp->cnic_ulp_lock);
+		return -EAGAIN;
+	}
+
+	cp->cnic_local_flags &= ~CNIC_LCL_FL_KWQ_INIT;
+
+	prod = cp->kwq_prod_idx;
+	sw_prod = prod & MAX_KWQ_IDX;
+	for (i = 0; i < num_wqes; i++) {
+		prod_qe = &cp->kwq[KWQ_PG(sw_prod)][KWQ_IDX(sw_prod)];
+		memcpy(prod_qe, wqes[i], sizeof(struct kwqe));
+		prod++;
+		sw_prod = prod & MAX_KWQ_IDX;
+	}
+	cp->kwq_prod_idx = prod;
+
+	CNIC_WR16(dev, cp->kwq_io_addr, cp->kwq_prod_idx);
+
+	spin_unlock_bh(&cp->cnic_ulp_lock);
+	return 0;
+}
+
+static void service_kcqes(struct cnic_dev *dev, int num_cqes)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	int i, j;
+
+	i = 0;
+	j = 1;
+	while (num_cqes) {
+		struct cnic_ulp_ops *ulp_ops;
+		int ulp_type;
+		u32 kcqe_op_flag = cp->completed_kcq[i]->kcqe_op_flag;
+		u32 kcqe_layer = kcqe_op_flag & KCQE_FLAGS_LAYER_MASK;
+
+		if (unlikely(kcqe_op_flag & KCQE_RAMROD_COMPLETION))
+			cnic_kwq_completion(dev, 1);
+
+		while (j < num_cqes) {
+			u32 next_op = cp->completed_kcq[i + j]->kcqe_op_flag;
+
+			if ((next_op & KCQE_FLAGS_LAYER_MASK) != kcqe_layer)
+				break;
+
+			if (unlikely(next_op & KCQE_RAMROD_COMPLETION))
+				cnic_kwq_completion(dev, 1);
+			j++;
+		}
+
+		if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L5_RDMA)
+			ulp_type = CNIC_ULP_RDMA;
+		else if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L5_ISCSI)
+			ulp_type = CNIC_ULP_ISCSI;
+		else if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L4)
+			ulp_type = CNIC_ULP_L4;
+		else if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L2)
+			goto end;
+		else {
+			printk(KERN_ERR PFX "%s: Unknown type of KCQE(0x%x)\n",
+			       dev->netdev->name, kcqe_op_flag);
+			goto end;
+		}
+
+		rcu_read_lock();
+		ulp_ops = rcu_dereference(cp->ulp_ops[ulp_type]);
+		if (likely(ulp_ops)) {
+			ulp_ops->indicate_kcqes(cp->ulp_handle[ulp_type],
+						  cp->completed_kcq + i, j);
+		}
+		rcu_read_unlock();
+end:
+		num_cqes -= j;
+		i += j;
+		j = 1;
+	}
+	return;
+}
+
+static u16 cnic_bnx2_next_idx(u16 idx)
+{
+	return idx + 1;
+}
+
+static u16 cnic_bnx2_hw_idx(u16 idx)
+{
+	return idx;
+}
+
+static int cnic_get_kcqes(struct cnic_dev *dev, u16 hw_prod, u16 *sw_prod)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	u16 i, ri, last;
+	struct kcqe *kcqe;
+	int kcqe_cnt = 0, last_cnt = 0;
+
+	i = ri = last = *sw_prod;
+	ri &= MAX_KCQ_IDX;
+
+	while ((i != hw_prod) && (kcqe_cnt < MAX_COMPLETED_KCQE)) {
+		kcqe = &cp->kcq[KCQ_PG(ri)][KCQ_IDX(ri)];
+		cp->completed_kcq[kcqe_cnt++] = kcqe;
+		i = cp->next_idx(i);
+		ri = i & MAX_KCQ_IDX;
+		if (likely(!(kcqe->kcqe_op_flag & KCQE_FLAGS_NEXT))) {
+			last_cnt = kcqe_cnt;
+			last = i;
+		}
+	}
+
+	*sw_prod = last;
+	return last_cnt;
+}
+
+static void cnic_chk_bnx2_pkt_rings(struct cnic_local *cp)
+{
+	u16 rx_cons = *cp->rx_cons_ptr;
+	u16 tx_cons = *cp->tx_cons_ptr;
+
+	if (cp->tx_cons != tx_cons || cp->rx_cons != rx_cons) {
+		cp->tx_cons = tx_cons;
+		cp->rx_cons = rx_cons;
+		uio_event_notify(cp->cnic_uinfo);
+	}
+}
+
+static int cnic_service_bnx2(void *data, void *status_blk)
+{
+	struct cnic_dev *dev = data;
+	struct status_block *sblk = status_blk;
+	struct cnic_local *cp = dev->cnic_priv;
+	u32 status_idx = sblk->status_idx;
+	u16 hw_prod, sw_prod;
+	int kcqe_cnt;
+
+	if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
+		return status_idx;
+
+	cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
+
+	hw_prod = sblk->status_completion_producer_index;
+	sw_prod = cp->kcq_prod_idx;
+	while (sw_prod != hw_prod) {
+		kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod);
+		if (kcqe_cnt == 0)
+			goto done;
+
+		service_kcqes(dev, kcqe_cnt);
+
+		/* Tell compiler that status_blk fields can change. */
+		barrier();
+		if (status_idx != sblk->status_idx) {
+			status_idx = sblk->status_idx;
+			cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
+			hw_prod = sblk->status_completion_producer_index;
+		} else
+			break;
+	}
+
+done:
+	CNIC_WR16(dev, cp->kcq_io_addr, sw_prod);
+
+	cp->kcq_prod_idx = sw_prod;
+
+	cnic_chk_bnx2_pkt_rings(cp);
+	return status_idx;
+}
+
+static void cnic_service_bnx2_msix(unsigned long data)
+{
+	struct cnic_dev *dev = (struct cnic_dev *) data;
+	struct cnic_local *cp = dev->cnic_priv;
+	struct status_block_msix *status_blk = cp->bnx2_status_blk;
+	u32 status_idx = status_blk->status_idx;
+	u16 hw_prod, sw_prod;
+	int kcqe_cnt;
+
+	cp->kwq_con_idx = status_blk->status_cmd_consumer_index;
+
+	hw_prod = status_blk->status_completion_producer_index;
+	sw_prod = cp->kcq_prod_idx;
+	while (sw_prod != hw_prod) {
+		kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod);
+		if (kcqe_cnt == 0)
+			goto done;
+
+		service_kcqes(dev, kcqe_cnt);
+
+		/* Tell compiler that status_blk fields can change. */
+		barrier();
+		if (status_idx != status_blk->status_idx) {
+			status_idx = status_blk->status_idx;
+			cp->kwq_con_idx = status_blk->status_cmd_consumer_index;
+			hw_prod = status_blk->status_completion_producer_index;
+		} else
+			break;
+	}
+
+done:
+	CNIC_WR16(dev, cp->kcq_io_addr, sw_prod);
+	cp->kcq_prod_idx = sw_prod;
+
+	cnic_chk_bnx2_pkt_rings(cp);
+
+	cp->last_status_idx = status_idx;
+	CNIC_WR(dev, BNX2_PCICFG_INT_ACK_CMD, cp->int_num |
+		BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx);
+}
+
+static irqreturn_t cnic_irq(int irq, void *dev_instance)
+{
+	struct cnic_dev *dev = dev_instance;
+	struct cnic_local *cp = dev->cnic_priv;
+	u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX;
+
+	if (cp->ack_int)
+		cp->ack_int(dev);
+
+	prefetch(cp->status_blk);
+	prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
+
+	if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags)))
+		tasklet_schedule(&cp->cnic_irq_task);
+
+	return IRQ_HANDLED;
+}
+
+static void cnic_ulp_stop(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	int if_type;
+
+	rcu_read_lock();
+	for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
+		struct cnic_ulp_ops *ulp_ops;
+
+		ulp_ops = rcu_dereference(cp->ulp_ops[if_type]);
+		if (!ulp_ops)
+			continue;
+
+		if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type]))
+			ulp_ops->cnic_stop(cp->ulp_handle[if_type]);
+	}
+	rcu_read_unlock();
+}
+
+static void cnic_ulp_start(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	int if_type;
+
+	rcu_read_lock();
+	for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
+		struct cnic_ulp_ops *ulp_ops;
+
+		ulp_ops = rcu_dereference(cp->ulp_ops[if_type]);
+		if (!ulp_ops || !ulp_ops->cnic_start)
+			continue;
+
+		if (!test_and_set_bit(ULP_F_START, &cp->ulp_flags[if_type]))
+			ulp_ops->cnic_start(cp->ulp_handle[if_type]);
+	}
+	rcu_read_unlock();
+}
+
+static int cnic_ctl(void *data, struct cnic_ctl_info *info)
+{
+	struct cnic_dev *dev = data;
+
+	switch (info->cmd) {
+	case CNIC_CTL_STOP_CMD:
+		cnic_hold(dev);
+		mutex_lock(&cnic_lock);
+
+		cnic_ulp_stop(dev);
+		cnic_stop_hw(dev);
+
+		mutex_unlock(&cnic_lock);
+		cnic_put(dev);
+		break;
+	case CNIC_CTL_START_CMD:
+		cnic_hold(dev);
+		mutex_lock(&cnic_lock);
+
+		if (!cnic_start_hw(dev))
+			cnic_ulp_start(dev);
+
+		mutex_unlock(&cnic_lock);
+		cnic_put(dev);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void cnic_ulp_init(struct cnic_dev *dev)
+{
+	int i;
+	struct cnic_local *cp = dev->cnic_priv;
+
+	rcu_read_lock();
+	for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) {
+		struct cnic_ulp_ops *ulp_ops;
+
+		ulp_ops = rcu_dereference(cnic_ulp_tbl[i]);
+		if (!ulp_ops || !ulp_ops->cnic_init)
+			continue;
+
+		if (!test_and_set_bit(ULP_F_INIT, &cp->ulp_flags[i]))
+			ulp_ops->cnic_init(dev);
+
+	}
+	rcu_read_unlock();
+}
+
+static void cnic_ulp_exit(struct cnic_dev *dev)
+{
+	int i;
+	struct cnic_local *cp = dev->cnic_priv;
+
+	rcu_read_lock();
+	for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) {
+		struct cnic_ulp_ops *ulp_ops;
+
+		ulp_ops = rcu_dereference(cnic_ulp_tbl[i]);
+		if (!ulp_ops || !ulp_ops->cnic_exit)
+			continue;
+
+		if (test_and_clear_bit(ULP_F_INIT, &cp->ulp_flags[i]))
+			ulp_ops->cnic_exit(dev);
+
+	}
+	rcu_read_unlock();
+}
+
+static int cnic_cm_offload_pg(struct cnic_sock *csk)
+{
+	struct cnic_dev *dev = csk->dev;
+	struct l4_kwq_offload_pg *l4kwqe;
+	struct kwqe *wqes[1];
+
+	l4kwqe = (struct l4_kwq_offload_pg *) &csk->kwqe1;
+	memset(l4kwqe, 0, sizeof(*l4kwqe));
+	wqes[0] = (struct kwqe *) l4kwqe;
+
+	l4kwqe->op_code = L4_KWQE_OPCODE_VALUE_OFFLOAD_PG;
+	l4kwqe->flags =
+		L4_LAYER_CODE << L4_KWQ_OFFLOAD_PG_LAYER_CODE_SHIFT;
+	l4kwqe->l2hdr_nbytes = ETH_HLEN;
+
+	l4kwqe->da0 = csk->ha[0];
+	l4kwqe->da1 = csk->ha[1];
+	l4kwqe->da2 = csk->ha[2];
+	l4kwqe->da3 = csk->ha[3];
+	l4kwqe->da4 = csk->ha[4];
+	l4kwqe->da5 = csk->ha[5];
+
+	l4kwqe->sa0 = dev->mac_addr[0];
+	l4kwqe->sa1 = dev->mac_addr[1];
+	l4kwqe->sa2 = dev->mac_addr[2];
+	l4kwqe->sa3 = dev->mac_addr[3];
+	l4kwqe->sa4 = dev->mac_addr[4];
+	l4kwqe->sa5 = dev->mac_addr[5];
+
+	l4kwqe->etype = ETH_P_IP;
+	l4kwqe->ipid_count = DEF_IPID_COUNT;
+	l4kwqe->host_opaque = csk->l5_cid;
+
+	if (csk->vlan_id) {
+		l4kwqe->pg_flags |= L4_KWQ_OFFLOAD_PG_VLAN_TAGGING;
+		l4kwqe->vlan_tag = csk->vlan_id;
+		l4kwqe->l2hdr_nbytes += 4;
+	}
+
+	return dev->submit_kwqes(dev, wqes, 1);
+}
+
+static int cnic_cm_update_pg(struct cnic_sock *csk)
+{
+	struct cnic_dev *dev = csk->dev;
+	struct l4_kwq_update_pg *l4kwqe;
+	struct kwqe *wqes[1];
+
+	l4kwqe = (struct l4_kwq_update_pg *) &csk->kwqe1;
+	memset(l4kwqe, 0, sizeof(*l4kwqe));
+	wqes[0] = (struct kwqe *) l4kwqe;
+
+	l4kwqe->opcode = L4_KWQE_OPCODE_VALUE_UPDATE_PG;
+	l4kwqe->flags =
+		L4_LAYER_CODE << L4_KWQ_UPDATE_PG_LAYER_CODE_SHIFT;
+	l4kwqe->pg_cid = csk->pg_cid;
+
+	l4kwqe->da0 = csk->ha[0];
+	l4kwqe->da1 = csk->ha[1];
+	l4kwqe->da2 = csk->ha[2];
+	l4kwqe->da3 = csk->ha[3];
+	l4kwqe->da4 = csk->ha[4];
+	l4kwqe->da5 = csk->ha[5];
+
+	l4kwqe->pg_host_opaque = csk->l5_cid;
+	l4kwqe->pg_valids = L4_KWQ_UPDATE_PG_VALIDS_DA;
+
+	return dev->submit_kwqes(dev, wqes, 1);
+}
+
+static int cnic_cm_upload_pg(struct cnic_sock *csk)
+{
+	struct cnic_dev *dev = csk->dev;
+	struct l4_kwq_upload *l4kwqe;
+	struct kwqe *wqes[1];
+
+	l4kwqe = (struct l4_kwq_upload *) &csk->kwqe1;
+	memset(l4kwqe, 0, sizeof(*l4kwqe));
+	wqes[0] = (struct kwqe *) l4kwqe;
+
+	l4kwqe->opcode = L4_KWQE_OPCODE_VALUE_UPLOAD_PG;
+	l4kwqe->flags =
+		L4_LAYER_CODE << L4_KWQ_UPLOAD_LAYER_CODE_SHIFT;
+	l4kwqe->cid = csk->pg_cid;
+
+	return dev->submit_kwqes(dev, wqes, 1);
+}
+
+static int cnic_cm_conn_req(struct cnic_sock *csk)
+{
+	struct cnic_dev *dev = csk->dev;
+	struct l4_kwq_connect_req1 *l4kwqe1;
+	struct l4_kwq_connect_req2 *l4kwqe2;
+	struct l4_kwq_connect_req3 *l4kwqe3;
+	struct kwqe *wqes[3];
+	u8 tcp_flags = 0;
+	int num_wqes = 2;
+
+	l4kwqe1 = (struct l4_kwq_connect_req1 *) &csk->kwqe1;
+	l4kwqe2 = (struct l4_kwq_connect_req2 *) &csk->kwqe2;
+	l4kwqe3 = (struct l4_kwq_connect_req3 *) &csk->kwqe3;
+	memset(l4kwqe1, 0, sizeof(*l4kwqe1));
+	memset(l4kwqe2, 0, sizeof(*l4kwqe2));
+	memset(l4kwqe3, 0, sizeof(*l4kwqe3));
+
+	l4kwqe3->op_code = L4_KWQE_OPCODE_VALUE_CONNECT3;
+	l4kwqe3->flags =
+		L4_LAYER_CODE << L4_KWQ_CONNECT_REQ3_LAYER_CODE_SHIFT;
+	l4kwqe3->ka_timeout = csk->ka_timeout;
+	l4kwqe3->ka_interval = csk->ka_interval;
+	l4kwqe3->ka_max_probe_count = csk->ka_max_probe_count;
+	l4kwqe3->tos = csk->tos;
+	l4kwqe3->ttl = csk->ttl;
+	l4kwqe3->snd_seq_scale = csk->snd_seq_scale;
+	l4kwqe3->pmtu = csk->mtu;
+	l4kwqe3->rcv_buf = csk->rcv_buf;
+	l4kwqe3->snd_buf = csk->snd_buf;
+	l4kwqe3->seed = csk->seed;
+
+	wqes[0] = (struct kwqe *) l4kwqe1;
+	if (test_bit(SK_F_IPV6, &csk->flags)) {
+		wqes[1] = (struct kwqe *) l4kwqe2;
+		wqes[2] = (struct kwqe *) l4kwqe3;
+		num_wqes = 3;
+
+		l4kwqe1->conn_flags = L4_KWQ_CONNECT_REQ1_IP_V6;
+		l4kwqe2->op_code = L4_KWQE_OPCODE_VALUE_CONNECT2;
+		l4kwqe2->flags =
+			L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT |
+			L4_LAYER_CODE << L4_KWQ_CONNECT_REQ2_LAYER_CODE_SHIFT;
+		l4kwqe2->src_ip_v6_2 = be32_to_cpu(csk->src_ip[1]);
+		l4kwqe2->src_ip_v6_3 = be32_to_cpu(csk->src_ip[2]);
+		l4kwqe2->src_ip_v6_4 = be32_to_cpu(csk->src_ip[3]);
+		l4kwqe2->dst_ip_v6_2 = be32_to_cpu(csk->dst_ip[1]);
+		l4kwqe2->dst_ip_v6_3 = be32_to_cpu(csk->dst_ip[2]);
+		l4kwqe2->dst_ip_v6_4 = be32_to_cpu(csk->dst_ip[3]);
+		l4kwqe3->mss = l4kwqe3->pmtu - sizeof(struct ipv6hdr) -
+			       sizeof(struct tcphdr);
+	} else {
+		wqes[1] = (struct kwqe *) l4kwqe3;
+		l4kwqe3->mss = l4kwqe3->pmtu - sizeof(struct iphdr) -
+			       sizeof(struct tcphdr);
+	}
+
+	l4kwqe1->op_code = L4_KWQE_OPCODE_VALUE_CONNECT1;
+	l4kwqe1->flags =
+		(L4_LAYER_CODE << L4_KWQ_CONNECT_REQ1_LAYER_CODE_SHIFT) |
+		 L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT;
+	l4kwqe1->cid = csk->cid;
+	l4kwqe1->pg_cid = csk->pg_cid;
+	l4kwqe1->src_ip = be32_to_cpu(csk->src_ip[0]);
+	l4kwqe1->dst_ip = be32_to_cpu(csk->dst_ip[0]);
+	l4kwqe1->src_port = be16_to_cpu(csk->src_port);
+	l4kwqe1->dst_port = be16_to_cpu(csk->dst_port);
+	if (csk->tcp_flags & SK_TCP_NO_DELAY_ACK)
+		tcp_flags |= L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK;
+	if (csk->tcp_flags & SK_TCP_KEEP_ALIVE)
+		tcp_flags |= L4_KWQ_CONNECT_REQ1_KEEP_ALIVE;
+	if (csk->tcp_flags & SK_TCP_NAGLE)
+		tcp_flags |= L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE;
+	if (csk->tcp_flags & SK_TCP_TIMESTAMP)
+		tcp_flags |= L4_KWQ_CONNECT_REQ1_TIME_STAMP;
+	if (csk->tcp_flags & SK_TCP_SACK)
+		tcp_flags |= L4_KWQ_CONNECT_REQ1_SACK;
+	if (csk->tcp_flags & SK_TCP_SEG_SCALING)
+		tcp_flags |= L4_KWQ_CONNECT_REQ1_SEG_SCALING;
+
+	l4kwqe1->tcp_flags = tcp_flags;
+
+	return dev->submit_kwqes(dev, wqes, num_wqes);
+}
+
+static int cnic_cm_close_req(struct cnic_sock *csk)
+{
+	struct cnic_dev *dev = csk->dev;
+	struct l4_kwq_close_req *l4kwqe;
+	struct kwqe *wqes[1];
+
+	l4kwqe = (struct l4_kwq_close_req *) &csk->kwqe2;
+	memset(l4kwqe, 0, sizeof(*l4kwqe));
+	wqes[0] = (struct kwqe *) l4kwqe;
+
+	l4kwqe->op_code = L4_KWQE_OPCODE_VALUE_CLOSE;
+	l4kwqe->flags = L4_LAYER_CODE << L4_KWQ_CLOSE_REQ_LAYER_CODE_SHIFT;
+	l4kwqe->cid = csk->cid;
+
+	return dev->submit_kwqes(dev, wqes, 1);
+}
+
+static int cnic_cm_abort_req(struct cnic_sock *csk)
+{
+	struct cnic_dev *dev = csk->dev;
+	struct l4_kwq_reset_req *l4kwqe;
+	struct kwqe *wqes[1];
+
+	l4kwqe = (struct l4_kwq_reset_req *) &csk->kwqe2;
+	memset(l4kwqe, 0, sizeof(*l4kwqe));
+	wqes[0] = (struct kwqe *) l4kwqe;
+
+	l4kwqe->op_code = L4_KWQE_OPCODE_VALUE_RESET;
+	l4kwqe->flags = L4_LAYER_CODE << L4_KWQ_RESET_REQ_LAYER_CODE_SHIFT;
+	l4kwqe->cid = csk->cid;
+
+	return dev->submit_kwqes(dev, wqes, 1);
+}
+
+static int cnic_cm_create(struct cnic_dev *dev, int ulp_type, u32 cid,
+			  u32 l5_cid, struct cnic_sock **csk, void *context)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_sock *csk1;
+
+	if (l5_cid >= MAX_CM_SK_TBL_SZ)
+		return -EINVAL;
+
+	csk1 = &cp->csk_tbl[l5_cid];
+	if (atomic_read(&csk1->ref_count))
+		return -EAGAIN;
+
+	if (test_and_set_bit(SK_F_INUSE, &csk1->flags))
+		return -EBUSY;
+
+	csk1->dev = dev;
+	csk1->cid = cid;
+	csk1->l5_cid = l5_cid;
+	csk1->ulp_type = ulp_type;
+	csk1->context = context;
+
+	csk1->ka_timeout = DEF_KA_TIMEOUT;
+	csk1->ka_interval = DEF_KA_INTERVAL;
+	csk1->ka_max_probe_count = DEF_KA_MAX_PROBE_COUNT;
+	csk1->tos = DEF_TOS;
+	csk1->ttl = DEF_TTL;
+	csk1->snd_seq_scale = DEF_SND_SEQ_SCALE;
+	csk1->rcv_buf = DEF_RCV_BUF;
+	csk1->snd_buf = DEF_SND_BUF;
+	csk1->seed = DEF_SEED;
+
+	*csk = csk1;
+	return 0;
+}
+
+static void cnic_cm_cleanup(struct cnic_sock *csk)
+{
+	if (csk->src_port) {
+		struct cnic_dev *dev = csk->dev;
+		struct cnic_local *cp = dev->cnic_priv;
+
+		cnic_free_id(&cp->csk_port_tbl, csk->src_port);
+		csk->src_port = 0;
+	}
+}
+
+static void cnic_close_conn(struct cnic_sock *csk)
+{
+	if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags)) {
+		cnic_cm_upload_pg(csk);
+		clear_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags);
+	}
+	cnic_cm_cleanup(csk);
+}
+
+static int cnic_cm_destroy(struct cnic_sock *csk)
+{
+	if (!cnic_in_use(csk))
+		return -EINVAL;
+
+	csk_hold(csk);
+	clear_bit(SK_F_INUSE, &csk->flags);
+	smp_mb__after_clear_bit();
+	while (atomic_read(&csk->ref_count) != 1)
+		msleep(1);
+	cnic_cm_cleanup(csk);
+
+	csk->flags = 0;
+	csk_put(csk);
+	return 0;
+}
+
+static inline u16 cnic_get_vlan(struct net_device *dev,
+				struct net_device **vlan_dev)
+{
+	if (dev->priv_flags & IFF_802_1Q_VLAN) {
+		*vlan_dev = vlan_dev_real_dev(dev);
+		return vlan_dev_vlan_id(dev);
+	}
+	*vlan_dev = dev;
+	return 0;
+}
+
+static int cnic_get_v4_route(struct sockaddr_in *dst_addr,
+			     struct dst_entry **dst)
+{
+#if defined(CONFIG_INET)
+	struct flowi fl;
+	int err;
+	struct rtable *rt;
+
+	memset(&fl, 0, sizeof(fl));
+	fl.nl_u.ip4_u.daddr = dst_addr->sin_addr.s_addr;
+
+	err = ip_route_output_key(&init_net, &rt, &fl);
+	if (!err)
+		*dst = &rt->u.dst;
+	return err;
+#else
+	return -ENETUNREACH;
+#endif
+}
+
+static int cnic_get_v6_route(struct sockaddr_in6 *dst_addr,
+			     struct dst_entry **dst)
+{
+#if defined(CONFIG_IPV6) || (defined(CONFIG_IPV6_MODULE) && defined(MODULE))
+	struct flowi fl;
+
+	memset(&fl, 0, sizeof(fl));
+	ipv6_addr_copy(&fl.fl6_dst, &dst_addr->sin6_addr);
+	if (ipv6_addr_type(&fl.fl6_dst) & IPV6_ADDR_LINKLOCAL)
+		fl.oif = dst_addr->sin6_scope_id;
+
+	*dst = ip6_route_output(&init_net, NULL, &fl);
+	if (*dst)
+		return 0;
+#endif
+
+	return -ENETUNREACH;
+}
+
+static struct cnic_dev *cnic_cm_select_dev(struct sockaddr_in *dst_addr,
+					   int ulp_type)
+{
+	struct cnic_dev *dev = NULL;
+	struct dst_entry *dst;
+	struct net_device *netdev = NULL;
+	int err = -ENETUNREACH;
+
+	if (dst_addr->sin_family == AF_INET)
+		err = cnic_get_v4_route(dst_addr, &dst);
+	else if (dst_addr->sin_family == AF_INET6) {
+		struct sockaddr_in6 *dst_addr6 =
+			(struct sockaddr_in6 *) dst_addr;
+
+		err = cnic_get_v6_route(dst_addr6, &dst);
+	} else
+		return NULL;
+
+	if (err)
+		return NULL;
+
+	if (!dst->dev)
+		goto done;
+
+	cnic_get_vlan(dst->dev, &netdev);
+
+	dev = cnic_from_netdev(netdev);
+
+done:
+	dst_release(dst);
+	if (dev)
+		cnic_put(dev);
+	return dev;
+}
+
+static int cnic_resolve_addr(struct cnic_sock *csk, struct cnic_sockaddr *saddr)
+{
+	struct cnic_dev *dev = csk->dev;
+	struct cnic_local *cp = dev->cnic_priv;
+
+	return cnic_send_nlmsg(cp, ISCSI_KEVENT_PATH_REQ, csk);
+}
+
+static int cnic_get_route(struct cnic_sock *csk, struct cnic_sockaddr *saddr)
+{
+	struct cnic_dev *dev = csk->dev;
+	struct cnic_local *cp = dev->cnic_priv;
+	int is_v6, err, rc = -ENETUNREACH;
+	struct dst_entry *dst;
+	struct net_device *realdev;
+	u32 local_port;
+
+	if (saddr->local.v6.sin6_family == AF_INET6 &&
+	    saddr->remote.v6.sin6_family == AF_INET6)
+		is_v6 = 1;
+	else if (saddr->local.v4.sin_family == AF_INET &&
+		 saddr->remote.v4.sin_family == AF_INET)
+		is_v6 = 0;
+	else
+		return -EINVAL;
+
+	clear_bit(SK_F_IPV6, &csk->flags);
+
+	if (is_v6) {
+#if defined(CONFIG_IPV6) || (defined(CONFIG_IPV6_MODULE) && defined(MODULE))
+		set_bit(SK_F_IPV6, &csk->flags);
+		err = cnic_get_v6_route(&saddr->remote.v6, &dst);
+		if (err)
+			return err;
+
+		if (!dst || dst->error || !dst->dev)
+			goto err_out;
+
+		memcpy(&csk->dst_ip[0], &saddr->remote.v6.sin6_addr,
+		       sizeof(struct in6_addr));
+		csk->dst_port = saddr->remote.v6.sin6_port;
+		local_port = saddr->local.v6.sin6_port;
+#else
+		return rc;
+#endif
+
+	} else {
+		err = cnic_get_v4_route(&saddr->remote.v4, &dst);
+		if (err)
+			return err;
+
+		if (!dst || dst->error || !dst->dev)
+			goto err_out;
+
+		csk->dst_ip[0] = saddr->remote.v4.sin_addr.s_addr;
+		csk->dst_port = saddr->remote.v4.sin_port;
+		local_port = saddr->local.v4.sin_port;
+	}
+
+	csk->vlan_id = cnic_get_vlan(dst->dev, &realdev);
+	if (realdev != dev->netdev)
+		goto err_out;
+
+	if (local_port >= CNIC_LOCAL_PORT_MIN &&
+	    local_port < CNIC_LOCAL_PORT_MAX) {
+		if (cnic_alloc_id(&cp->csk_port_tbl, local_port))
+			local_port = 0;
+	} else
+		local_port = 0;
+
+	if (!local_port) {
+		local_port = cnic_alloc_new_id(&cp->csk_port_tbl);
+		if (local_port == -1) {
+			rc = -ENOMEM;
+			goto err_out;
+		}
+	}
+	csk->src_port = local_port;
+
+	csk->mtu = dst_mtu(dst);
+	rc = 0;
+
+err_out:
+	dst_release(dst);
+	return rc;
+}
+
+static void cnic_init_csk_state(struct cnic_sock *csk)
+{
+	csk->state = 0;
+	clear_bit(SK_F_OFFLD_SCHED, &csk->flags);
+	clear_bit(SK_F_CLOSING, &csk->flags);
+}
+
+static int cnic_cm_connect(struct cnic_sock *csk, struct cnic_sockaddr *saddr)
+{
+	int err = 0;
+
+	if (!cnic_in_use(csk))
+		return -EINVAL;
+
+	if (test_and_set_bit(SK_F_CONNECT_START, &csk->flags))
+		return -EINVAL;
+
+	cnic_init_csk_state(csk);
+
+	err = cnic_get_route(csk, saddr);
+	if (err)
+		goto err_out;
+
+	err = cnic_resolve_addr(csk, saddr);
+	if (!err)
+		return 0;
+
+err_out:
+	clear_bit(SK_F_CONNECT_START, &csk->flags);
+	return err;
+}
+
+static int cnic_cm_abort(struct cnic_sock *csk)
+{
+	struct cnic_local *cp = csk->dev->cnic_priv;
+	u32 opcode;
+
+	if (!cnic_in_use(csk))
+		return -EINVAL;
+
+	if (cnic_abort_prep(csk))
+		return cnic_cm_abort_req(csk);
+
+	/* Getting here means that we haven't started connect, or
+	 * connect was not successful.
+	 */
+
+	csk->state = L4_KCQE_OPCODE_VALUE_RESET_COMP;
+	if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
+		opcode = csk->state;
+	else
+		opcode = L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD;
+	cp->close_conn(csk, opcode);
+
+	return 0;
+}
+
+static int cnic_cm_close(struct cnic_sock *csk)
+{
+	if (!cnic_in_use(csk))
+		return -EINVAL;
+
+	if (cnic_close_prep(csk)) {
+		csk->state = L4_KCQE_OPCODE_VALUE_CLOSE_COMP;
+		return cnic_cm_close_req(csk);
+	}
+	return 0;
+}
+
+static void cnic_cm_upcall(struct cnic_local *cp, struct cnic_sock *csk,
+			   u8 opcode)
+{
+	struct cnic_ulp_ops *ulp_ops;
+	int ulp_type = csk->ulp_type;
+
+	rcu_read_lock();
+	ulp_ops = rcu_dereference(cp->ulp_ops[ulp_type]);
+	if (ulp_ops) {
+		if (opcode == L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE)
+			ulp_ops->cm_connect_complete(csk);
+		else if (opcode == L4_KCQE_OPCODE_VALUE_CLOSE_COMP)
+			ulp_ops->cm_close_complete(csk);
+		else if (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED)
+			ulp_ops->cm_remote_abort(csk);
+		else if (opcode == L4_KCQE_OPCODE_VALUE_RESET_COMP)
+			ulp_ops->cm_abort_complete(csk);
+		else if (opcode == L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED)
+			ulp_ops->cm_remote_close(csk);
+	}
+	rcu_read_unlock();
+}
+
+static int cnic_cm_set_pg(struct cnic_sock *csk)
+{
+	if (cnic_offld_prep(csk)) {
+		if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
+			cnic_cm_update_pg(csk);
+		else
+			cnic_cm_offload_pg(csk);
+	}
+	return 0;
+}
+
+static void cnic_cm_process_offld_pg(struct cnic_dev *dev, struct l4_kcq *kcqe)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	u32 l5_cid = kcqe->pg_host_opaque;
+	u8 opcode = kcqe->op_code;
+	struct cnic_sock *csk = &cp->csk_tbl[l5_cid];
+
+	csk_hold(csk);
+	if (!cnic_in_use(csk))
+		goto done;
+
+	if (opcode == L4_KCQE_OPCODE_VALUE_UPDATE_PG) {
+		clear_bit(SK_F_OFFLD_SCHED, &csk->flags);
+		goto done;
+	}
+	csk->pg_cid = kcqe->pg_cid;
+	set_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags);
+	cnic_cm_conn_req(csk);
+
+done:
+	csk_put(csk);
+}
+
+static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct l4_kcq *l4kcqe = (struct l4_kcq *) kcqe;
+	u8 opcode = l4kcqe->op_code;
+	u32 l5_cid;
+	struct cnic_sock *csk;
+
+	if (opcode == L4_KCQE_OPCODE_VALUE_OFFLOAD_PG ||
+	    opcode == L4_KCQE_OPCODE_VALUE_UPDATE_PG) {
+		cnic_cm_process_offld_pg(dev, l4kcqe);
+		return;
+	}
+
+	l5_cid = l4kcqe->conn_id;
+	if (opcode & 0x80)
+		l5_cid = l4kcqe->cid;
+	if (l5_cid >= MAX_CM_SK_TBL_SZ)
+		return;
+
+	csk = &cp->csk_tbl[l5_cid];
+	csk_hold(csk);
+
+	if (!cnic_in_use(csk)) {
+		csk_put(csk);
+		return;
+	}
+
+	switch (opcode) {
+	case L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE:
+		if (l4kcqe->status == 0)
+			set_bit(SK_F_OFFLD_COMPLETE, &csk->flags);
+
+		smp_mb__before_clear_bit();
+		clear_bit(SK_F_OFFLD_SCHED, &csk->flags);
+		cnic_cm_upcall(cp, csk, opcode);
+		break;
+
+	case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED:
+		if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags))
+			csk->state = opcode;
+		/* fall through */
+	case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
+	case L4_KCQE_OPCODE_VALUE_RESET_COMP:
+		cp->close_conn(csk, opcode);
+		break;
+
+	case L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED:
+		cnic_cm_upcall(cp, csk, opcode);
+		break;
+	}
+	csk_put(csk);
+}
+
+static void cnic_cm_indicate_kcqe(void *data, struct kcqe *kcqe[], u32 num)
+{
+	struct cnic_dev *dev = data;
+	int i;
+
+	for (i = 0; i < num; i++)
+		cnic_cm_process_kcqe(dev, kcqe[i]);
+}
+
+static struct cnic_ulp_ops cm_ulp_ops = {
+	.indicate_kcqes		= cnic_cm_indicate_kcqe,
+};
+
+static void cnic_cm_free_mem(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+
+	kfree(cp->csk_tbl);
+	cp->csk_tbl = NULL;
+	cnic_free_id_tbl(&cp->csk_port_tbl);
+}
+
+static int cnic_cm_alloc_mem(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+
+	cp->csk_tbl = kzalloc(sizeof(struct cnic_sock) * MAX_CM_SK_TBL_SZ,
+			      GFP_KERNEL);
+	if (!cp->csk_tbl)
+		return -ENOMEM;
+
+	if (cnic_init_id_tbl(&cp->csk_port_tbl, CNIC_LOCAL_PORT_RANGE,
+			     CNIC_LOCAL_PORT_MIN)) {
+		cnic_cm_free_mem(dev);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static int cnic_ready_to_close(struct cnic_sock *csk, u32 opcode)
+{
+	if ((opcode == csk->state) ||
+	    (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED &&
+	     csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP)) {
+		if (!test_and_set_bit(SK_F_CLOSING, &csk->flags))
+			return 1;
+	}
+	return 0;
+}
+
+static void cnic_close_bnx2_conn(struct cnic_sock *csk, u32 opcode)
+{
+	struct cnic_dev *dev = csk->dev;
+	struct cnic_local *cp = dev->cnic_priv;
+
+	clear_bit(SK_F_CONNECT_START, &csk->flags);
+	if (cnic_ready_to_close(csk, opcode)) {
+		cnic_close_conn(csk);
+		cnic_cm_upcall(cp, csk, opcode);
+	}
+}
+
+static void cnic_cm_stop_bnx2_hw(struct cnic_dev *dev)
+{
+}
+
+static int cnic_cm_init_bnx2_hw(struct cnic_dev *dev)
+{
+	u32 seed;
+
+	get_random_bytes(&seed, 4);
+	cnic_ctx_wr(dev, 45, 0, seed);
+	return 0;
+}
+
+static int cnic_cm_open(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	int err;
+
+	err = cnic_cm_alloc_mem(dev);
+	if (err)
+		return err;
+
+	err = cp->start_cm(dev);
+
+	if (err)
+		goto err_out;
+
+	dev->cm_create = cnic_cm_create;
+	dev->cm_destroy = cnic_cm_destroy;
+	dev->cm_connect = cnic_cm_connect;
+	dev->cm_abort = cnic_cm_abort;
+	dev->cm_close = cnic_cm_close;
+	dev->cm_select_dev = cnic_cm_select_dev;
+
+	cp->ulp_handle[CNIC_ULP_L4] = dev;
+	rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], &cm_ulp_ops);
+	return 0;
+
+err_out:
+	cnic_cm_free_mem(dev);
+	return err;
+}
+
+static int cnic_cm_shutdown(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	int i;
+
+	cp->stop_cm(dev);
+
+	if (!cp->csk_tbl)
+		return 0;
+
+	for (i = 0; i < MAX_CM_SK_TBL_SZ; i++) {
+		struct cnic_sock *csk = &cp->csk_tbl[i];
+
+		clear_bit(SK_F_INUSE, &csk->flags);
+		cnic_cm_cleanup(csk);
+	}
+	cnic_cm_free_mem(dev);
+
+	return 0;
+}
+
+static void cnic_init_context(struct cnic_dev *dev, u32 cid)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	u32 cid_addr;
+	int i;
+
+	if (CHIP_NUM(cp) == CHIP_NUM_5709)
+		return;
+
+	cid_addr = GET_CID_ADDR(cid);
+
+	for (i = 0; i < CTX_SIZE; i += 4)
+		cnic_ctx_wr(dev, cid_addr, i, 0);
+}
+
+static int cnic_setup_5709_context(struct cnic_dev *dev, int valid)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	int ret = 0, i;
+	u32 valid_bit = valid ? BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID : 0;
+
+	if (CHIP_NUM(cp) != CHIP_NUM_5709)
+		return 0;
+
+	for (i = 0; i < cp->ctx_blks; i++) {
+		int j;
+		u32 idx = cp->ctx_arr[i].cid / cp->cids_per_blk;
+		u32 val;
+
+		memset(cp->ctx_arr[i].ctx, 0, BCM_PAGE_SIZE);
+
+		CNIC_WR(dev, BNX2_CTX_HOST_PAGE_TBL_DATA0,
+			(cp->ctx_arr[i].mapping & 0xffffffff) | valid_bit);
+		CNIC_WR(dev, BNX2_CTX_HOST_PAGE_TBL_DATA1,
+			(u64) cp->ctx_arr[i].mapping >> 32);
+		CNIC_WR(dev, BNX2_CTX_HOST_PAGE_TBL_CTRL, idx |
+			BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
+		for (j = 0; j < 10; j++) {
+
+			val = CNIC_RD(dev, BNX2_CTX_HOST_PAGE_TBL_CTRL);
+			if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
+				break;
+			udelay(5);
+		}
+		if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
+			ret = -EBUSY;
+			break;
+		}
+	}
+	return ret;
+}
+
+static void cnic_free_irq(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_eth_dev *ethdev = cp->ethdev;
+
+	if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
+		cp->disable_int_sync(dev);
+		tasklet_disable(&cp->cnic_irq_task);
+		free_irq(ethdev->irq_arr[0].vector, dev);
+	}
+}
+
+static int cnic_init_bnx2_irq(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_eth_dev *ethdev = cp->ethdev;
+
+	if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
+		int err, i = 0;
+		int sblk_num = cp->status_blk_num;
+		u32 base = ((sblk_num - 1) * BNX2_HC_SB_CONFIG_SIZE) +
+			   BNX2_HC_SB_CONFIG_1;
+
+		CNIC_WR(dev, base, BNX2_HC_SB_CONFIG_1_ONE_SHOT);
+
+		CNIC_WR(dev, base + BNX2_HC_COMP_PROD_TRIP_OFF, (2 << 16) | 8);
+		CNIC_WR(dev, base + BNX2_HC_COM_TICKS_OFF, (64 << 16) | 220);
+		CNIC_WR(dev, base + BNX2_HC_CMD_TICKS_OFF, (64 << 16) | 220);
+
+		cp->bnx2_status_blk = cp->status_blk;
+		cp->last_status_idx = cp->bnx2_status_blk->status_idx;
+		tasklet_init(&cp->cnic_irq_task, &cnic_service_bnx2_msix,
+			     (unsigned long) dev);
+		err = request_irq(ethdev->irq_arr[0].vector, cnic_irq, 0,
+				  "cnic", dev);
+		if (err) {
+			tasklet_disable(&cp->cnic_irq_task);
+			return err;
+		}
+		while (cp->bnx2_status_blk->status_completion_producer_index &&
+		       i < 10) {
+			CNIC_WR(dev, BNX2_HC_COALESCE_NOW,
+				1 << (11 + sblk_num));
+			udelay(10);
+			i++;
+			barrier();
+		}
+		if (cp->bnx2_status_blk->status_completion_producer_index) {
+			cnic_free_irq(dev);
+			goto failed;
+		}
+
+	} else {
+		struct status_block *sblk = cp->status_blk;
+		u32 hc_cmd = CNIC_RD(dev, BNX2_HC_COMMAND);
+		int i = 0;
+
+		while (sblk->status_completion_producer_index && i < 10) {
+			CNIC_WR(dev, BNX2_HC_COMMAND,
+				hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
+			udelay(10);
+			i++;
+			barrier();
+		}
+		if (sblk->status_completion_producer_index)
+			goto failed;
+
+	}
+	return 0;
+
+failed:
+	printk(KERN_ERR PFX "%s: " "KCQ index not resetting to 0.\n",
+	       dev->netdev->name);
+	return -EBUSY;
+}
+
+static void cnic_enable_bnx2_int(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_eth_dev *ethdev = cp->ethdev;
+
+	if (!(ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX))
+		return;
+
+	CNIC_WR(dev, BNX2_PCICFG_INT_ACK_CMD, cp->int_num |
+		BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx);
+}
+
+static void cnic_disable_bnx2_int_sync(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_eth_dev *ethdev = cp->ethdev;
+
+	if (!(ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX))
+		return;
+
+	CNIC_WR(dev, BNX2_PCICFG_INT_ACK_CMD, cp->int_num |
+		BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
+	CNIC_RD(dev, BNX2_PCICFG_INT_ACK_CMD);
+	synchronize_irq(ethdev->irq_arr[0].vector);
+}
+
+static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_eth_dev *ethdev = cp->ethdev;
+	u32 cid_addr, tx_cid, sb_id;
+	u32 val, offset0, offset1, offset2, offset3;
+	int i;
+	struct tx_bd *txbd;
+	dma_addr_t buf_map;
+	struct status_block *s_blk = cp->status_blk;
+
+	sb_id = cp->status_blk_num;
+	tx_cid = 20;
+	cnic_init_context(dev, tx_cid);
+	cnic_init_context(dev, tx_cid + 1);
+	cp->tx_cons_ptr = &s_blk->status_tx_quick_consumer_index2;
+	if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
+		struct status_block_msix *sblk = cp->status_blk;
+
+		tx_cid = TX_TSS_CID + sb_id - 1;
+		cnic_init_context(dev, tx_cid);
+		CNIC_WR(dev, BNX2_TSCH_TSS_CFG, (sb_id << 24) |
+			(TX_TSS_CID << 7));
+		cp->tx_cons_ptr = &sblk->status_tx_quick_consumer_index;
+	}
+	cp->tx_cons = *cp->tx_cons_ptr;
+
+	cid_addr = GET_CID_ADDR(tx_cid);
+	if (CHIP_NUM(cp) == CHIP_NUM_5709) {
+		u32 cid_addr2 = GET_CID_ADDR(tx_cid + 4) + 0x40;
+
+		for (i = 0; i < PHY_CTX_SIZE; i += 4)
+			cnic_ctx_wr(dev, cid_addr2, i, 0);
+
+		offset0 = BNX2_L2CTX_TYPE_XI;
+		offset1 = BNX2_L2CTX_CMD_TYPE_XI;
+		offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
+		offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
+	} else {
+		offset0 = BNX2_L2CTX_TYPE;
+		offset1 = BNX2_L2CTX_CMD_TYPE;
+		offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
+		offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
+	}
+	val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
+	cnic_ctx_wr(dev, cid_addr, offset0, val);
+
+	val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
+	cnic_ctx_wr(dev, cid_addr, offset1, val);
+
+	txbd = (struct tx_bd *) cp->l2_ring;
+
+	buf_map = cp->l2_buf_map;
+	for (i = 0; i < MAX_TX_DESC_CNT; i++, txbd++) {
+		txbd->tx_bd_haddr_hi = (u64) buf_map >> 32;
+		txbd->tx_bd_haddr_lo = (u64) buf_map & 0xffffffff;
+	}
+	val = (u64) cp->l2_ring_map >> 32;
+	cnic_ctx_wr(dev, cid_addr, offset2, val);
+	txbd->tx_bd_haddr_hi = val;
+
+	val = (u64) cp->l2_ring_map & 0xffffffff;
+	cnic_ctx_wr(dev, cid_addr, offset3, val);
+	txbd->tx_bd_haddr_lo = val;
+}
+
+static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_eth_dev *ethdev = cp->ethdev;
+	u32 cid_addr, sb_id, val, coal_reg, coal_val;
+	int i;
+	struct rx_bd *rxbd;
+	struct status_block *s_blk = cp->status_blk;
+
+	sb_id = cp->status_blk_num;
+	cnic_init_context(dev, 2);
+	cp->rx_cons_ptr = &s_blk->status_rx_quick_consumer_index2;
+	coal_reg = BNX2_HC_COMMAND;
+	coal_val = CNIC_RD(dev, coal_reg);
+	if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
+		struct status_block_msix *sblk = cp->status_blk;
+
+		cp->rx_cons_ptr = &sblk->status_rx_quick_consumer_index;
+		coal_reg = BNX2_HC_COALESCE_NOW;
+		coal_val = 1 << (11 + sb_id);
+	}
+	i = 0;
+	while (!(*cp->rx_cons_ptr != 0) && i < 10) {
+		CNIC_WR(dev, coal_reg, coal_val);
+		udelay(10);
+		i++;
+		barrier();
+	}
+	cp->rx_cons = *cp->rx_cons_ptr;
+
+	cid_addr = GET_CID_ADDR(2);
+	val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE |
+	      BNX2_L2CTX_CTX_TYPE_SIZE_L2 | (0x02 << 8);
+	cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_CTX_TYPE, val);
+
+	if (sb_id == 0)
+		val = 2 << BNX2_L2CTX_STATUSB_NUM_SHIFT;
+	else
+		val = BNX2_L2CTX_STATUSB_NUM(sb_id);
+	cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_HOST_BDIDX, val);
+
+	rxbd = (struct rx_bd *) (cp->l2_ring + BCM_PAGE_SIZE);
+	for (i = 0; i < MAX_RX_DESC_CNT; i++, rxbd++) {
+		dma_addr_t buf_map;
+		int n = (i % cp->l2_rx_ring_size) + 1;
+
+		buf_map = cp->l2_buf_map + (n * cp->l2_single_buf_size);
+		rxbd->rx_bd_len = cp->l2_single_buf_size;
+		rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
+		rxbd->rx_bd_haddr_hi = (u64) buf_map >> 32;
+		rxbd->rx_bd_haddr_lo = (u64) buf_map & 0xffffffff;
+	}
+	val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) >> 32;
+	cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
+	rxbd->rx_bd_haddr_hi = val;
+
+	val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) & 0xffffffff;
+	cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
+	rxbd->rx_bd_haddr_lo = val;
+
+	val = cnic_reg_rd_ind(dev, BNX2_RXP_SCRATCH_RXP_FLOOD);
+	cnic_reg_wr_ind(dev, BNX2_RXP_SCRATCH_RXP_FLOOD, val | (1 << 2));
+}
+
+static void cnic_shutdown_bnx2_rx_ring(struct cnic_dev *dev)
+{
+	struct kwqe *wqes[1], l2kwqe;
+
+	memset(&l2kwqe, 0, sizeof(l2kwqe));
+	wqes[0] = &l2kwqe;
+	l2kwqe.kwqe_op_flag = (L2_LAYER_CODE << KWQE_FLAGS_LAYER_SHIFT) |
+			      (L2_KWQE_OPCODE_VALUE_FLUSH <<
+			       KWQE_OPCODE_SHIFT) | 2;
+	dev->submit_kwqes(dev, wqes, 1);
+}
+
+static void cnic_set_bnx2_mac(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	u32 val;
+
+	val = cp->func << 2;
+
+	cp->shmem_base = cnic_reg_rd_ind(dev, BNX2_SHM_HDR_ADDR_0 + val);
+
+	val = cnic_reg_rd_ind(dev, cp->shmem_base +
+			      BNX2_PORT_HW_CFG_ISCSI_MAC_UPPER);
+	dev->mac_addr[0] = (u8) (val >> 8);
+	dev->mac_addr[1] = (u8) val;
+
+	CNIC_WR(dev, BNX2_EMAC_MAC_MATCH4, val);
+
+	val = cnic_reg_rd_ind(dev, cp->shmem_base +
+			      BNX2_PORT_HW_CFG_ISCSI_MAC_LOWER);
+	dev->mac_addr[2] = (u8) (val >> 24);
+	dev->mac_addr[3] = (u8) (val >> 16);
+	dev->mac_addr[4] = (u8) (val >> 8);
+	dev->mac_addr[5] = (u8) val;
+
+	CNIC_WR(dev, BNX2_EMAC_MAC_MATCH5, val);
+
+	val = 4 | BNX2_RPM_SORT_USER2_BC_EN;
+	if (CHIP_NUM(cp) != CHIP_NUM_5709)
+		val |= BNX2_RPM_SORT_USER2_PROM_VLAN;
+
+	CNIC_WR(dev, BNX2_RPM_SORT_USER2, 0x0);
+	CNIC_WR(dev, BNX2_RPM_SORT_USER2, val);
+	CNIC_WR(dev, BNX2_RPM_SORT_USER2, val | BNX2_RPM_SORT_USER2_ENA);
+}
+
+static int cnic_start_bnx2_hw(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_eth_dev *ethdev = cp->ethdev;
+	struct status_block *sblk = cp->status_blk;
+	u32 val;
+	int err;
+
+	cnic_set_bnx2_mac(dev);
+
+	val = CNIC_RD(dev, BNX2_MQ_CONFIG);
+	val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
+	if (BCM_PAGE_BITS > 12)
+		val |= (12 - 8)  << 4;
+	else
+		val |= (BCM_PAGE_BITS - 8)  << 4;
+
+	CNIC_WR(dev, BNX2_MQ_CONFIG, val);
+
+	CNIC_WR(dev, BNX2_HC_COMP_PROD_TRIP, (2 << 16) | 8);
+	CNIC_WR(dev, BNX2_HC_COM_TICKS, (64 << 16) | 220);
+	CNIC_WR(dev, BNX2_HC_CMD_TICKS, (64 << 16) | 220);
+
+	err = cnic_setup_5709_context(dev, 1);
+	if (err)
+		return err;
+
+	cnic_init_context(dev, KWQ_CID);
+	cnic_init_context(dev, KCQ_CID);
+
+	cp->kwq_cid_addr = GET_CID_ADDR(KWQ_CID);
+	cp->kwq_io_addr = MB_GET_CID_ADDR(KWQ_CID) + L5_KRNLQ_HOST_QIDX;
+
+	cp->max_kwq_idx = MAX_KWQ_IDX;
+	cp->kwq_prod_idx = 0;
+	cp->kwq_con_idx = 0;
+	cp->cnic_local_flags |= CNIC_LCL_FL_KWQ_INIT;
+
+	if (CHIP_NUM(cp) == CHIP_NUM_5706 || CHIP_NUM(cp) == CHIP_NUM_5708)
+		cp->kwq_con_idx_ptr = &sblk->status_rx_quick_consumer_index15;
+	else
+		cp->kwq_con_idx_ptr = &sblk->status_cmd_consumer_index;
+
+	/* Initialize the kernel work queue context. */
+	val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
+	      (BCM_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
+	cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_TYPE, val);
+
+	val = (BCM_PAGE_SIZE / sizeof(struct kwqe) - 1) << 16;
+	cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
+
+	val = ((BCM_PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT;
+	cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
+
+	val = (u32) ((u64) cp->kwq_info.pgtbl_map >> 32);
+	cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val);
+
+	val = (u32) cp->kwq_info.pgtbl_map;
+	cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val);
+
+	cp->kcq_cid_addr = GET_CID_ADDR(KCQ_CID);
+	cp->kcq_io_addr = MB_GET_CID_ADDR(KCQ_CID) + L5_KRNLQ_HOST_QIDX;
+
+	cp->kcq_prod_idx = 0;
+
+	/* Initialize the kernel complete queue context. */
+	val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
+	      (BCM_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
+	cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_TYPE, val);
+
+	val = (BCM_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16;
+	cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
+
+	val = ((BCM_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT;
+	cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
+
+	val = (u32) ((u64) cp->kcq_info.pgtbl_map >> 32);
+	cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val);
+
+	val = (u32) cp->kcq_info.pgtbl_map;
+	cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val);
+
+	cp->int_num = 0;
+	if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
+		u32 sb_id = cp->status_blk_num;
+		u32 sb = BNX2_L2CTX_STATUSB_NUM(sb_id);
+
+		cp->int_num = sb_id << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT;
+		cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
+		cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
+	}
+
+	/* Enable Commnad Scheduler notification when we write to the
+	 * host producer index of the kernel contexts. */
+	CNIC_WR(dev, BNX2_MQ_KNL_CMD_MASK1, 2);
+
+	/* Enable Command Scheduler notification when we write to either
+	 * the Send Queue or Receive Queue producer indexes of the kernel
+	 * bypass contexts. */
+	CNIC_WR(dev, BNX2_MQ_KNL_BYP_CMD_MASK1, 7);
+	CNIC_WR(dev, BNX2_MQ_KNL_BYP_WRITE_MASK1, 7);
+
+	/* Notify COM when the driver post an application buffer. */
+	CNIC_WR(dev, BNX2_MQ_KNL_RX_V2P_MASK2, 0x2000);
+
+	/* Set the CP and COM doorbells.  These two processors polls the
+	 * doorbell for a non zero value before running.  This must be done
+	 * after setting up the kernel queue contexts. */
+	cnic_reg_wr_ind(dev, BNX2_CP_SCRATCH + 0x20, 1);
+	cnic_reg_wr_ind(dev, BNX2_COM_SCRATCH + 0x20, 1);
+
+	cnic_init_bnx2_tx_ring(dev);
+	cnic_init_bnx2_rx_ring(dev);
+
+	err = cnic_init_bnx2_irq(dev);
+	if (err) {
+		printk(KERN_ERR PFX "%s: cnic_init_irq failed\n",
+		       dev->netdev->name);
+		cnic_reg_wr_ind(dev, BNX2_CP_SCRATCH + 0x20, 0);
+		cnic_reg_wr_ind(dev, BNX2_COM_SCRATCH + 0x20, 0);
+		return err;
+	}
+
+	return 0;
+}
+
+static int cnic_start_hw(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_eth_dev *ethdev = cp->ethdev;
+	int err;
+
+	if (test_bit(CNIC_F_CNIC_UP, &dev->flags))
+		return -EALREADY;
+
+	err = ethdev->drv_register_cnic(dev->netdev, cp->cnic_ops, dev);
+	if (err) {
+		printk(KERN_ERR PFX "%s: register_cnic failed\n",
+		       dev->netdev->name);
+		goto err2;
+	}
+
+	dev->regview = ethdev->io_base;
+	cp->chip_id = ethdev->chip_id;
+	pci_dev_get(dev->pcidev);
+	cp->func = PCI_FUNC(dev->pcidev->devfn);
+	cp->status_blk = ethdev->irq_arr[0].status_blk;
+	cp->status_blk_num = ethdev->irq_arr[0].status_blk_num;
+
+	err = cp->alloc_resc(dev);
+	if (err) {
+		printk(KERN_ERR PFX "%s: allocate resource failure\n",
+		       dev->netdev->name);
+		goto err1;
+	}
+
+	err = cp->start_hw(dev);
+	if (err)
+		goto err1;
+
+	err = cnic_cm_open(dev);
+	if (err)
+		goto err1;
+
+	set_bit(CNIC_F_CNIC_UP, &dev->flags);
+
+	cp->enable_int(dev);
+
+	return 0;
+
+err1:
+	ethdev->drv_unregister_cnic(dev->netdev);
+	cp->free_resc(dev);
+	pci_dev_put(dev->pcidev);
+err2:
+	return err;
+}
+
+static void cnic_stop_bnx2_hw(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_eth_dev *ethdev = cp->ethdev;
+
+	cnic_disable_bnx2_int_sync(dev);
+
+	cnic_reg_wr_ind(dev, BNX2_CP_SCRATCH + 0x20, 0);
+	cnic_reg_wr_ind(dev, BNX2_COM_SCRATCH + 0x20, 0);
+
+	cnic_init_context(dev, KWQ_CID);
+	cnic_init_context(dev, KCQ_CID);
+
+	cnic_setup_5709_context(dev, 0);
+	cnic_free_irq(dev);
+
+	ethdev->drv_unregister_cnic(dev->netdev);
+
+	cnic_free_resc(dev);
+}
+
+static void cnic_stop_hw(struct cnic_dev *dev)
+{
+	if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) {
+		struct cnic_local *cp = dev->cnic_priv;
+
+		clear_bit(CNIC_F_CNIC_UP, &dev->flags);
+		rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], NULL);
+		synchronize_rcu();
+		cnic_cm_shutdown(dev);
+		cp->stop_hw(dev);
+		pci_dev_put(dev->pcidev);
+	}
+}
+
+static void cnic_free_dev(struct cnic_dev *dev)
+{
+	int i = 0;
+
+	while ((atomic_read(&dev->ref_count) != 0) && i < 10) {
+		msleep(100);
+		i++;
+	}
+	if (atomic_read(&dev->ref_count) != 0)
+		printk(KERN_ERR PFX "%s: Failed waiting for ref count to go"
+				    " to zero.\n", dev->netdev->name);
+
+	printk(KERN_INFO PFX "Removed CNIC device: %s\n", dev->netdev->name);
+	dev_put(dev->netdev);
+	kfree(dev);
+}
+
+static struct cnic_dev *cnic_alloc_dev(struct net_device *dev,
+				       struct pci_dev *pdev)
+{
+	struct cnic_dev *cdev;
+	struct cnic_local *cp;
+	int alloc_size;
+
+	alloc_size = sizeof(struct cnic_dev) + sizeof(struct cnic_local);
+
+	cdev = kzalloc(alloc_size , GFP_KERNEL);
+	if (cdev == NULL) {
+		printk(KERN_ERR PFX "%s: allocate dev struct failure\n",
+		       dev->name);
+		return NULL;
+	}
+
+	cdev->netdev = dev;
+	cdev->cnic_priv = (char *)cdev + sizeof(struct cnic_dev);
+	cdev->register_device = cnic_register_device;
+	cdev->unregister_device = cnic_unregister_device;
+	cdev->iscsi_nl_msg_recv = cnic_iscsi_nl_msg_recv;
+
+	cp = cdev->cnic_priv;
+	cp->dev = cdev;
+	cp->uio_dev = -1;
+	cp->l2_single_buf_size = 0x400;
+	cp->l2_rx_ring_size = 3;
+
+	spin_lock_init(&cp->cnic_ulp_lock);
+
+	printk(KERN_INFO PFX "Added CNIC device: %s\n", dev->name);
+
+	return cdev;
+}
+
+static struct cnic_dev *init_bnx2_cnic(struct net_device *dev)
+{
+	struct pci_dev *pdev;
+	struct cnic_dev *cdev;
+	struct cnic_local *cp;
+	struct cnic_eth_dev *ethdev = NULL;
+	struct cnic_eth_dev *(*probe)(void *) = NULL;
+
+	probe = __symbol_get("bnx2_cnic_probe");
+	if (probe) {
+		ethdev = (*probe)(dev);
+		symbol_put_addr(probe);
+	}
+	if (!ethdev)
+		return NULL;
+
+	pdev = ethdev->pdev;
+	if (!pdev)
+		return NULL;
+
+	dev_hold(dev);
+	pci_dev_get(pdev);
+	if (pdev->device == PCI_DEVICE_ID_NX2_5709 ||
+	    pdev->device == PCI_DEVICE_ID_NX2_5709S) {
+		u8 rev;
+
+		pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+		if (rev < 0x10) {
+			pci_dev_put(pdev);
+			goto cnic_err;
+		}
+	}
+	pci_dev_put(pdev);
+
+	cdev = cnic_alloc_dev(dev, pdev);
+	if (cdev == NULL)
+		goto cnic_err;
+
+	set_bit(CNIC_F_BNX2_CLASS, &cdev->flags);
+	cdev->submit_kwqes = cnic_submit_bnx2_kwqes;
+
+	cp = cdev->cnic_priv;
+	cp->ethdev = ethdev;
+	cdev->pcidev = pdev;
+
+	cp->cnic_ops = &cnic_bnx2_ops;
+	cp->start_hw = cnic_start_bnx2_hw;
+	cp->stop_hw = cnic_stop_bnx2_hw;
+	cp->setup_pgtbl = cnic_setup_page_tbl;
+	cp->alloc_resc = cnic_alloc_bnx2_resc;
+	cp->free_resc = cnic_free_resc;
+	cp->start_cm = cnic_cm_init_bnx2_hw;
+	cp->stop_cm = cnic_cm_stop_bnx2_hw;
+	cp->enable_int = cnic_enable_bnx2_int;
+	cp->disable_int_sync = cnic_disable_bnx2_int_sync;
+	cp->close_conn = cnic_close_bnx2_conn;
+	cp->next_idx = cnic_bnx2_next_idx;
+	cp->hw_idx = cnic_bnx2_hw_idx;
+	return cdev;
+
+cnic_err:
+	dev_put(dev);
+	return NULL;
+}
+
+static struct cnic_dev *is_cnic_dev(struct net_device *dev)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct cnic_dev *cdev = NULL;
+
+	if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) {
+		memset(&drvinfo, 0, sizeof(drvinfo));
+		dev->ethtool_ops->get_drvinfo(dev, &drvinfo);
+
+		if (!strcmp(drvinfo.driver, "bnx2"))
+			cdev = init_bnx2_cnic(dev);
+		if (cdev) {
+			write_lock(&cnic_dev_lock);
+			list_add(&cdev->list, &cnic_dev_list);
+			write_unlock(&cnic_dev_lock);
+		}
+	}
+	return cdev;
+}
+
+/**
+ * netdev event handler
+ */
+static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
+							 void *ptr)
+{
+	struct net_device *netdev = ptr;
+	struct cnic_dev *dev;
+	int if_type;
+	int new_dev = 0;
+
+	dev = cnic_from_netdev(netdev);
+
+	if (!dev && (event == NETDEV_REGISTER || event == NETDEV_UP)) {
+		/* Check for the hot-plug device */
+		dev = is_cnic_dev(netdev);
+		if (dev) {
+			new_dev = 1;
+			cnic_hold(dev);
+		}
+	}
+	if (dev) {
+		struct cnic_local *cp = dev->cnic_priv;
+
+		if (new_dev)
+			cnic_ulp_init(dev);
+		else if (event == NETDEV_UNREGISTER)
+			cnic_ulp_exit(dev);
+		else if (event == NETDEV_UP) {
+			mutex_lock(&cnic_lock);
+			if (!cnic_start_hw(dev))
+				cnic_ulp_start(dev);
+			mutex_unlock(&cnic_lock);
+		}
+
+		rcu_read_lock();
+		for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
+			struct cnic_ulp_ops *ulp_ops;
+			void *ctx;
+
+			ulp_ops = rcu_dereference(cp->ulp_ops[if_type]);
+			if (!ulp_ops || !ulp_ops->indicate_netevent)
+				continue;
+
+			ctx = cp->ulp_handle[if_type];
+
+			ulp_ops->indicate_netevent(ctx, event);
+		}
+		rcu_read_unlock();
+
+		if (event == NETDEV_GOING_DOWN) {
+			mutex_lock(&cnic_lock);
+			cnic_ulp_stop(dev);
+			cnic_stop_hw(dev);
+			mutex_unlock(&cnic_lock);
+		} else if (event == NETDEV_UNREGISTER) {
+			write_lock(&cnic_dev_lock);
+			list_del_init(&dev->list);
+			write_unlock(&cnic_dev_lock);
+
+			cnic_put(dev);
+			cnic_free_dev(dev);
+			goto done;
+		}
+		cnic_put(dev);
+	}
+done:
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block cnic_netdev_notifier = {
+	.notifier_call = cnic_netdev_event
+};
+
+static void cnic_release(void)
+{
+	struct cnic_dev *dev;
+
+	while (!list_empty(&cnic_dev_list)) {
+		dev = list_entry(cnic_dev_list.next, struct cnic_dev, list);
+		if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) {
+			cnic_ulp_stop(dev);
+			cnic_stop_hw(dev);
+		}
+
+		cnic_ulp_exit(dev);
+		list_del_init(&dev->list);
+		cnic_free_dev(dev);
+	}
+}
+
+static int __init cnic_init(void)
+{
+	int rc = 0;
+
+	printk(KERN_INFO "%s", version);
+
+	rc = register_netdevice_notifier(&cnic_netdev_notifier);
+	if (rc) {
+		cnic_release();
+		return rc;
+	}
+
+	return 0;
+}
+
+static void __exit cnic_exit(void)
+{
+	unregister_netdevice_notifier(&cnic_netdev_notifier);
+	cnic_release();
+	return;
+}
+
+module_init(cnic_init);
+module_exit(cnic_exit);
diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h
new file mode 100644
index 0000000..5192d4a
--- /dev/null
+++ b/drivers/net/cnic.h
@@ -0,0 +1,299 @@
+/* cnic.h: Broadcom CNIC core network driver.
+ *
+ * Copyright (c) 2006-2009 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ */
+
+
+#ifndef CNIC_H
+#define CNIC_H
+
+#define KWQ_PAGE_CNT	4
+#define KCQ_PAGE_CNT	16
+
+#define KWQ_CID 		24
+#define KCQ_CID 		25
+
+/*
+ *	krnlq_context definition
+ */
+#define L5_KRNLQ_FLAGS	0x00000000
+#define L5_KRNLQ_SIZE	0x00000000
+#define L5_KRNLQ_TYPE	0x00000000
+#define KRNLQ_FLAGS_PG_SZ					(0xf<<0)
+#define KRNLQ_FLAGS_PG_SZ_256					(0<<0)
+#define KRNLQ_FLAGS_PG_SZ_512					(1<<0)
+#define KRNLQ_FLAGS_PG_SZ_1K					(2<<0)
+#define KRNLQ_FLAGS_PG_SZ_2K					(3<<0)
+#define KRNLQ_FLAGS_PG_SZ_4K					(4<<0)
+#define KRNLQ_FLAGS_PG_SZ_8K					(5<<0)
+#define KRNLQ_FLAGS_PG_SZ_16K					(6<<0)
+#define KRNLQ_FLAGS_PG_SZ_32K					(7<<0)
+#define KRNLQ_FLAGS_PG_SZ_64K					(8<<0)
+#define KRNLQ_FLAGS_PG_SZ_128K					(9<<0)
+#define KRNLQ_FLAGS_PG_SZ_256K					(10<<0)
+#define KRNLQ_FLAGS_PG_SZ_512K					(11<<0)
+#define KRNLQ_FLAGS_PG_SZ_1M					(12<<0)
+#define KRNLQ_FLAGS_PG_SZ_2M					(13<<0)
+#define KRNLQ_FLAGS_QE_SELF_SEQ					(1<<15)
+#define KRNLQ_SIZE_TYPE_SIZE	((((0x28 + 0x1f) & ~0x1f) / 0x20) << 16)
+#define KRNLQ_TYPE_TYPE						(0xf<<28)
+#define KRNLQ_TYPE_TYPE_EMPTY					(0<<28)
+#define KRNLQ_TYPE_TYPE_KRNLQ					(6<<28)
+
+#define L5_KRNLQ_HOST_QIDX		0x00000004
+#define L5_KRNLQ_HOST_FW_QIDX		0x00000008
+#define L5_KRNLQ_NX_QE_SELF_SEQ 	0x0000000c
+#define L5_KRNLQ_QE_SELF_SEQ_MAX	0x0000000c
+#define L5_KRNLQ_NX_QE_HADDR_HI 	0x00000010
+#define L5_KRNLQ_NX_QE_HADDR_LO 	0x00000014
+#define L5_KRNLQ_PGTBL_PGIDX		0x00000018
+#define L5_KRNLQ_NX_PG_QIDX 		0x00000018
+#define L5_KRNLQ_PGTBL_NPAGES		0x0000001c
+#define L5_KRNLQ_QIDX_INCR		0x0000001c
+#define L5_KRNLQ_PGTBL_HADDR_HI 	0x00000020
+#define L5_KRNLQ_PGTBL_HADDR_LO 	0x00000024
+
+#define BNX2_PG_CTX_MAP			0x1a0034
+#define BNX2_ISCSI_CTX_MAP		0x1a0074
+
+struct cnic_redirect_entry {
+	struct dst_entry *old_dst;
+	struct dst_entry *new_dst;
+};
+
+#define MAX_COMPLETED_KCQE	64
+
+#define MAX_CNIC_L5_CONTEXT	256
+
+#define MAX_CM_SK_TBL_SZ	MAX_CNIC_L5_CONTEXT
+
+#define MAX_ISCSI_TBL_SZ	256
+
+#define CNIC_LOCAL_PORT_MIN	60000
+#define CNIC_LOCAL_PORT_MAX	61000
+#define CNIC_LOCAL_PORT_RANGE	(CNIC_LOCAL_PORT_MAX - CNIC_LOCAL_PORT_MIN)
+
+#define KWQE_CNT (BCM_PAGE_SIZE / sizeof(struct kwqe))
+#define KCQE_CNT (BCM_PAGE_SIZE / sizeof(struct kcqe))
+#define MAX_KWQE_CNT (KWQE_CNT - 1)
+#define MAX_KCQE_CNT (KCQE_CNT - 1)
+
+#define MAX_KWQ_IDX	((KWQ_PAGE_CNT * KWQE_CNT) - 1)
+#define MAX_KCQ_IDX	((KCQ_PAGE_CNT * KCQE_CNT) - 1)
+
+#define KWQ_PG(x) (((x) & ~MAX_KWQE_CNT) >> (BCM_PAGE_BITS - 5))
+#define KWQ_IDX(x) ((x) & MAX_KWQE_CNT)
+
+#define KCQ_PG(x) (((x) & ~MAX_KCQE_CNT) >> (BCM_PAGE_BITS - 5))
+#define KCQ_IDX(x) ((x) & MAX_KCQE_CNT)
+
+#define BNX2X_NEXT_KCQE(x) (((x) & (MAX_KCQE_CNT - 1)) ==		\
+		(MAX_KCQE_CNT - 1)) ?					\
+		(x) + 2 : (x) + 1
+
+#define BNX2X_KWQ_DATA_PG(cp, x) ((x) / (cp)->kwq_16_data_pp)
+#define BNX2X_KWQ_DATA_IDX(cp, x) ((x) % (cp)->kwq_16_data_pp)
+#define BNX2X_KWQ_DATA(cp, x)						\
+	&(cp)->kwq_16_data[BNX2X_KWQ_DATA_PG(cp, x)][BNX2X_KWQ_DATA_IDX(cp, x)]
+
+#define DEF_IPID_COUNT		0xc001
+
+#define DEF_KA_TIMEOUT		10000
+#define DEF_KA_INTERVAL		300000
+#define DEF_KA_MAX_PROBE_COUNT	3
+#define DEF_TOS			0
+#define DEF_TTL			0xfe
+#define DEF_SND_SEQ_SCALE	0
+#define DEF_RCV_BUF		0xffff
+#define DEF_SND_BUF		0xffff
+#define DEF_SEED		0
+#define DEF_MAX_RT_TIME		500
+#define DEF_MAX_DA_COUNT	2
+#define DEF_SWS_TIMER		1000
+#define DEF_MAX_CWND		0xffff
+
+struct cnic_ctx {
+	u32		cid;
+	void		*ctx;
+	dma_addr_t	mapping;
+};
+
+#define BNX2_MAX_CID		0x2000
+
+struct cnic_dma {
+	int		num_pages;
+	void		**pg_arr;
+	dma_addr_t	*pg_map_arr;
+	int		pgtbl_size;
+	u32		*pgtbl;
+	dma_addr_t	pgtbl_map;
+};
+
+struct cnic_id_tbl {
+	spinlock_t	lock;
+	u32		start;
+	u32		max;
+	u32		next;
+	unsigned long	*table;
+};
+
+#define CNIC_KWQ16_DATA_SIZE	128
+
+struct kwqe_16_data {
+	u8	data[CNIC_KWQ16_DATA_SIZE];
+};
+
+struct cnic_iscsi {
+	struct cnic_dma		task_array_info;
+	struct cnic_dma		r2tq_info;
+	struct cnic_dma		hq_info;
+};
+
+struct cnic_context {
+	u32			cid;
+	struct kwqe_16_data	*kwqe_data;
+	dma_addr_t		kwqe_data_mapping;
+	wait_queue_head_t	waitq;
+	int			wait_cond;
+	unsigned long		timestamp;
+	u32			ctx_flags;
+#define	CTX_FL_OFFLD_START	0x00000001
+	u8			ulp_proto_id;
+	union {
+		struct cnic_iscsi	*iscsi;
+	} proto;
+};
+
+struct cnic_local {
+
+	spinlock_t cnic_ulp_lock;
+	void *ulp_handle[MAX_CNIC_ULP_TYPE];
+	unsigned long ulp_flags[MAX_CNIC_ULP_TYPE];
+#define ULP_F_INIT	0
+#define ULP_F_START	1
+	struct cnic_ulp_ops *ulp_ops[MAX_CNIC_ULP_TYPE];
+
+	/* protected by ulp_lock */
+	u32 cnic_local_flags;
+#define	CNIC_LCL_FL_KWQ_INIT	0x00000001
+
+	struct cnic_dev *dev;
+
+	struct cnic_eth_dev *ethdev;
+
+	void		*l2_ring;
+	dma_addr_t	l2_ring_map;
+	int		l2_ring_size;
+	int		l2_rx_ring_size;
+
+	void		*l2_buf;
+	dma_addr_t	l2_buf_map;
+	int		l2_buf_size;
+	int		l2_single_buf_size;
+
+	u16		*rx_cons_ptr;
+	u16		*tx_cons_ptr;
+	u16		rx_cons;
+	u16		tx_cons;
+
+	u32 kwq_cid_addr;
+	u32 kcq_cid_addr;
+
+	struct cnic_dma		kwq_info;
+	struct kwqe		**kwq;
+
+	struct cnic_dma		kwq_16_data_info;
+
+	u16		max_kwq_idx;
+
+	u16		kwq_prod_idx;
+	u32		kwq_io_addr;
+
+	u16		*kwq_con_idx_ptr;
+	u16		kwq_con_idx;
+
+	struct cnic_dma	kcq_info;
+	struct kcqe	**kcq;
+
+	u16		kcq_prod_idx;
+	u32		kcq_io_addr;
+
+	void				*status_blk;
+	struct status_block_msix	*bnx2_status_blk;
+	struct host_status_block	*bnx2x_status_blk;
+
+	u32				status_blk_num;
+	u32				int_num;
+	u32				last_status_idx;
+	struct tasklet_struct		cnic_irq_task;
+
+	struct kcqe		*completed_kcq[MAX_COMPLETED_KCQE];
+
+	struct cnic_sock	*csk_tbl;
+	struct cnic_id_tbl	csk_port_tbl;
+
+	struct cnic_dma		conn_buf_info;
+	struct cnic_dma		gbl_buf_info;
+
+	struct cnic_iscsi	*iscsi_tbl;
+	struct cnic_context	*ctx_tbl;
+	struct cnic_id_tbl	cid_tbl;
+	int			max_iscsi_conn;
+	atomic_t		iscsi_conn;
+
+	/* per connection parameters */
+	int			num_iscsi_tasks;
+	int			num_ccells;
+	int			task_array_size;
+	int			r2tq_size;
+	int			hq_size;
+	int			num_cqs;
+
+	struct cnic_ctx		*ctx_arr;
+	int			ctx_blks;
+	int			ctx_blk_size;
+	int			cids_per_blk;
+
+	u32			chip_id;
+	int			func;
+	u32			shmem_base;
+
+	u32			uio_dev;
+	struct uio_info		*cnic_uinfo;
+
+	struct cnic_ops		*cnic_ops;
+	int			(*start_hw)(struct cnic_dev *);
+	void			(*stop_hw)(struct cnic_dev *);
+	void			(*setup_pgtbl)(struct cnic_dev *,
+					       struct cnic_dma *);
+	int			(*alloc_resc)(struct cnic_dev *);
+	void			(*free_resc)(struct cnic_dev *);
+	int			(*start_cm)(struct cnic_dev *);
+	void			(*stop_cm)(struct cnic_dev *);
+	void			(*enable_int)(struct cnic_dev *);
+	void			(*disable_int_sync)(struct cnic_dev *);
+	void			(*ack_int)(struct cnic_dev *);
+	void			(*close_conn)(struct cnic_sock *, u32 opcode);
+	u16			(*next_idx)(u16);
+	u16			(*hw_idx)(u16);
+};
+
+struct bnx2x_bd_chain_next {
+	u32	addr_lo;
+	u32	addr_hi;
+	u8	reserved[8];
+};
+
+#define ISCSI_RAMROD_CMD_ID_UPDATE_CONN		(ISCSI_KCQE_OPCODE_UPDATE_CONN)
+#define ISCSI_RAMROD_CMD_ID_INIT		(ISCSI_KCQE_OPCODE_INIT)
+
+#define CDU_REGION_NUMBER_XCM_AG 2
+#define CDU_REGION_NUMBER_UCM_AG 4
+
+#endif
+
diff --git a/drivers/net/cnic_defs.h b/drivers/net/cnic_defs.h
new file mode 100644
index 0000000..cee80f6
--- /dev/null
+++ b/drivers/net/cnic_defs.h
@@ -0,0 +1,580 @@
+
+/* cnic.c: Broadcom CNIC core network driver.
+ *
+ * Copyright (c) 2006-2009 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ */
+
+#ifndef CNIC_DEFS_H
+#define CNIC_DEFS_H
+
+/* KWQ (kernel work queue) request op codes */
+#define L2_KWQE_OPCODE_VALUE_FLUSH                  (4)
+
+#define L4_KWQE_OPCODE_VALUE_CONNECT1               (50)
+#define L4_KWQE_OPCODE_VALUE_CONNECT2               (51)
+#define L4_KWQE_OPCODE_VALUE_CONNECT3               (52)
+#define L4_KWQE_OPCODE_VALUE_RESET                  (53)
+#define L4_KWQE_OPCODE_VALUE_CLOSE                  (54)
+#define L4_KWQE_OPCODE_VALUE_UPDATE_SECRET          (60)
+#define L4_KWQE_OPCODE_VALUE_INIT_ULP               (61)
+
+#define L4_KWQE_OPCODE_VALUE_OFFLOAD_PG             (1)
+#define L4_KWQE_OPCODE_VALUE_UPDATE_PG              (9)
+#define L4_KWQE_OPCODE_VALUE_UPLOAD_PG              (14)
+
+#define L5CM_RAMROD_CMD_ID_BASE			(0x80)
+#define L5CM_RAMROD_CMD_ID_TCP_CONNECT		(L5CM_RAMROD_CMD_ID_BASE + 3)
+#define L5CM_RAMROD_CMD_ID_CLOSE		(L5CM_RAMROD_CMD_ID_BASE + 12)
+#define L5CM_RAMROD_CMD_ID_ABORT		(L5CM_RAMROD_CMD_ID_BASE + 13)
+#define L5CM_RAMROD_CMD_ID_SEARCHER_DELETE	(L5CM_RAMROD_CMD_ID_BASE + 14)
+#define L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD	(L5CM_RAMROD_CMD_ID_BASE + 15)
+
+/* KCQ (kernel completion queue) response op codes */
+#define L4_KCQE_OPCODE_VALUE_CLOSE_COMP             (53)
+#define L4_KCQE_OPCODE_VALUE_RESET_COMP             (54)
+#define L4_KCQE_OPCODE_VALUE_FW_TCP_UPDATE          (55)
+#define L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE       (56)
+#define L4_KCQE_OPCODE_VALUE_RESET_RECEIVED         (57)
+#define L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED         (58)
+#define L4_KCQE_OPCODE_VALUE_INIT_ULP               (61)
+
+#define L4_KCQE_OPCODE_VALUE_OFFLOAD_PG             (1)
+#define L4_KCQE_OPCODE_VALUE_UPDATE_PG              (9)
+#define L4_KCQE_OPCODE_VALUE_UPLOAD_PG              (14)
+
+/* KCQ (kernel completion queue) completion status */
+#define L4_KCQE_COMPLETION_STATUS_SUCCESS		    (0)
+#define L4_KCQE_COMPLETION_STATUS_TIMEOUT        (0x93)
+
+#define L4_LAYER_CODE (4)
+#define L2_LAYER_CODE (2)
+
+/*
+ * L4 KCQ CQE
+ */
+struct l4_kcq {
+	u32 cid;
+	u32 pg_cid;
+	u32 conn_id;
+	u32 pg_host_opaque;
+#if defined(__BIG_ENDIAN)
+	u16 status;
+	u16 reserved1;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved1;
+	u16 status;
+#endif
+	u32 reserved2[2];
+#if defined(__BIG_ENDIAN)
+	u8 flags;
+#define L4_KCQ_RESERVED3 (0x7<<0)
+#define L4_KCQ_RESERVED3_SHIFT 0
+#define L4_KCQ_RAMROD_COMPLETION (0x1<<3) /* Everest only */
+#define L4_KCQ_RAMROD_COMPLETION_SHIFT 3
+#define L4_KCQ_LAYER_CODE (0x7<<4)
+#define L4_KCQ_LAYER_CODE_SHIFT 4
+#define L4_KCQ_RESERVED4 (0x1<<7)
+#define L4_KCQ_RESERVED4_SHIFT 7
+	u8 op_code;
+	u16 qe_self_seq;
+#elif defined(__LITTLE_ENDIAN)
+	u16 qe_self_seq;
+	u8 op_code;
+	u8 flags;
+#define L4_KCQ_RESERVED3 (0xF<<0)
+#define L4_KCQ_RESERVED3_SHIFT 0
+#define L4_KCQ_RAMROD_COMPLETION (0x1<<3) /* Everest only */
+#define L4_KCQ_RAMROD_COMPLETION_SHIFT 3
+#define L4_KCQ_LAYER_CODE (0x7<<4)
+#define L4_KCQ_LAYER_CODE_SHIFT 4
+#define L4_KCQ_RESERVED4 (0x1<<7)
+#define L4_KCQ_RESERVED4_SHIFT 7
+#endif
+};
+
+
+/*
+ * L4 KCQ CQE PG upload
+ */
+struct l4_kcq_upload_pg {
+	u32 pg_cid;
+#if defined(__BIG_ENDIAN)
+	u16 pg_status;
+	u16 pg_ipid_count;
+#elif defined(__LITTLE_ENDIAN)
+	u16 pg_ipid_count;
+	u16 pg_status;
+#endif
+	u32 reserved1[5];
+#if defined(__BIG_ENDIAN)
+	u8 flags;
+#define L4_KCQ_UPLOAD_PG_RESERVED3 (0xF<<0)
+#define L4_KCQ_UPLOAD_PG_RESERVED3_SHIFT 0
+#define L4_KCQ_UPLOAD_PG_LAYER_CODE (0x7<<4)
+#define L4_KCQ_UPLOAD_PG_LAYER_CODE_SHIFT 4
+#define L4_KCQ_UPLOAD_PG_RESERVED4 (0x1<<7)
+#define L4_KCQ_UPLOAD_PG_RESERVED4_SHIFT 7
+	u8 op_code;
+	u16 qe_self_seq;
+#elif defined(__LITTLE_ENDIAN)
+	u16 qe_self_seq;
+	u8 op_code;
+	u8 flags;
+#define L4_KCQ_UPLOAD_PG_RESERVED3 (0xF<<0)
+#define L4_KCQ_UPLOAD_PG_RESERVED3_SHIFT 0
+#define L4_KCQ_UPLOAD_PG_LAYER_CODE (0x7<<4)
+#define L4_KCQ_UPLOAD_PG_LAYER_CODE_SHIFT 4
+#define L4_KCQ_UPLOAD_PG_RESERVED4 (0x1<<7)
+#define L4_KCQ_UPLOAD_PG_RESERVED4_SHIFT 7
+#endif
+};
+
+
+/*
+ * Gracefully close the connection request
+ */
+struct l4_kwq_close_req {
+#if defined(__BIG_ENDIAN)
+	u8 flags;
+#define L4_KWQ_CLOSE_REQ_RESERVED1 (0xF<<0)
+#define L4_KWQ_CLOSE_REQ_RESERVED1_SHIFT 0
+#define L4_KWQ_CLOSE_REQ_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CLOSE_REQ_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT_SHIFT 7
+	u8 op_code;
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	u8 op_code;
+	u8 flags;
+#define L4_KWQ_CLOSE_REQ_RESERVED1 (0xF<<0)
+#define L4_KWQ_CLOSE_REQ_RESERVED1_SHIFT 0
+#define L4_KWQ_CLOSE_REQ_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CLOSE_REQ_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT_SHIFT 7
+#endif
+	u32 cid;
+	u32 reserved2[6];
+};
+
+
+/*
+ * The first request to be passed in order to establish connection in option2
+ */
+struct l4_kwq_connect_req1 {
+#if defined(__BIG_ENDIAN)
+	u8 flags;
+#define L4_KWQ_CONNECT_REQ1_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ1_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ1_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT_SHIFT 7
+	u8 op_code;
+	u8 reserved0;
+	u8 conn_flags;
+#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE (0x1<<0)
+#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_IP_V6 (0x1<<1)
+#define L4_KWQ_CONNECT_REQ1_IP_V6_SHIFT 1
+#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG (0x1<<2)
+#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG_SHIFT 2
+#define L4_KWQ_CONNECT_REQ1_RSRV (0x1F<<3)
+#define L4_KWQ_CONNECT_REQ1_RSRV_SHIFT 3
+#elif defined(__LITTLE_ENDIAN)
+	u8 conn_flags;
+#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE (0x1<<0)
+#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_IP_V6 (0x1<<1)
+#define L4_KWQ_CONNECT_REQ1_IP_V6_SHIFT 1
+#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG (0x1<<2)
+#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG_SHIFT 2
+#define L4_KWQ_CONNECT_REQ1_RSRV (0x1F<<3)
+#define L4_KWQ_CONNECT_REQ1_RSRV_SHIFT 3
+	u8 reserved0;
+	u8 op_code;
+	u8 flags;
+#define L4_KWQ_CONNECT_REQ1_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ1_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ1_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT_SHIFT 7
+#endif
+	u32 cid;
+	u32 pg_cid;
+	u32 src_ip;
+	u32 dst_ip;
+#if defined(__BIG_ENDIAN)
+	u16 dst_port;
+	u16 src_port;
+#elif defined(__LITTLE_ENDIAN)
+	u16 src_port;
+	u16 dst_port;
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 rsrv1[3];
+	u8 tcp_flags;
+#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK (0x1<<0)
+#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE (0x1<<1)
+#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE_SHIFT 1
+#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE (0x1<<2)
+#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE_SHIFT 2
+#define L4_KWQ_CONNECT_REQ1_TIME_STAMP (0x1<<3)
+#define L4_KWQ_CONNECT_REQ1_TIME_STAMP_SHIFT 3
+#define L4_KWQ_CONNECT_REQ1_SACK (0x1<<4)
+#define L4_KWQ_CONNECT_REQ1_SACK_SHIFT 4
+#define L4_KWQ_CONNECT_REQ1_SEG_SCALING (0x1<<5)
+#define L4_KWQ_CONNECT_REQ1_SEG_SCALING_SHIFT 5
+#define L4_KWQ_CONNECT_REQ1_RESERVED2 (0x3<<6)
+#define L4_KWQ_CONNECT_REQ1_RESERVED2_SHIFT 6
+#elif defined(__LITTLE_ENDIAN)
+	u8 tcp_flags;
+#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK (0x1<<0)
+#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE (0x1<<1)
+#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE_SHIFT 1
+#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE (0x1<<2)
+#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE_SHIFT 2
+#define L4_KWQ_CONNECT_REQ1_TIME_STAMP (0x1<<3)
+#define L4_KWQ_CONNECT_REQ1_TIME_STAMP_SHIFT 3
+#define L4_KWQ_CONNECT_REQ1_SACK (0x1<<4)
+#define L4_KWQ_CONNECT_REQ1_SACK_SHIFT 4
+#define L4_KWQ_CONNECT_REQ1_SEG_SCALING (0x1<<5)
+#define L4_KWQ_CONNECT_REQ1_SEG_SCALING_SHIFT 5
+#define L4_KWQ_CONNECT_REQ1_RESERVED2 (0x3<<6)
+#define L4_KWQ_CONNECT_REQ1_RESERVED2_SHIFT 6
+	u8 rsrv1[3];
+#endif
+	u32 rsrv2;
+};
+
+
+/*
+ * The second ( optional )request to be passed in order to establish
+ * connection in option2 - for IPv6 only
+ */
+struct l4_kwq_connect_req2 {
+#if defined(__BIG_ENDIAN)
+	u8 flags;
+#define L4_KWQ_CONNECT_REQ2_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ2_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ2_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ2_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT_SHIFT 7
+	u8 op_code;
+	u8 reserved0;
+	u8 rsrv;
+#elif defined(__LITTLE_ENDIAN)
+	u8 rsrv;
+	u8 reserved0;
+	u8 op_code;
+	u8 flags;
+#define L4_KWQ_CONNECT_REQ2_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ2_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ2_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ2_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT_SHIFT 7
+#endif
+	u32 reserved2;
+	u32 src_ip_v6_2;
+	u32 src_ip_v6_3;
+	u32 src_ip_v6_4;
+	u32 dst_ip_v6_2;
+	u32 dst_ip_v6_3;
+	u32 dst_ip_v6_4;
+};
+
+
+/*
+ * The third ( and last )request to be passed in order to establish
+ * connection in option2
+ */
+struct l4_kwq_connect_req3 {
+#if defined(__BIG_ENDIAN)
+	u8 flags;
+#define L4_KWQ_CONNECT_REQ3_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ3_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ3_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ3_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT_SHIFT 7
+	u8 op_code;
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	u8 op_code;
+	u8 flags;
+#define L4_KWQ_CONNECT_REQ3_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ3_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ3_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ3_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT_SHIFT 7
+#endif
+	u32 ka_timeout;
+	u32 ka_interval ;
+#if defined(__BIG_ENDIAN)
+	u8 snd_seq_scale;
+	u8 ttl;
+	u8 tos;
+	u8 ka_max_probe_count;
+#elif defined(__LITTLE_ENDIAN)
+	u8 ka_max_probe_count;
+	u8 tos;
+	u8 ttl;
+	u8 snd_seq_scale;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 pmtu;
+	u16 mss;
+#elif defined(__LITTLE_ENDIAN)
+	u16 mss;
+	u16 pmtu;
+#endif
+	u32 rcv_buf;
+	u32 snd_buf;
+	u32 seed;
+};
+
+
+/*
+ * a KWQE request to offload a PG connection
+ */
+struct l4_kwq_offload_pg {
+#if defined(__BIG_ENDIAN)
+	u8 flags;
+#define L4_KWQ_OFFLOAD_PG_RESERVED1 (0xF<<0)
+#define L4_KWQ_OFFLOAD_PG_RESERVED1_SHIFT 0
+#define L4_KWQ_OFFLOAD_PG_LAYER_CODE (0x7<<4)
+#define L4_KWQ_OFFLOAD_PG_LAYER_CODE_SHIFT 4
+#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT_SHIFT 7
+	u8 op_code;
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	u8 op_code;
+	u8 flags;
+#define L4_KWQ_OFFLOAD_PG_RESERVED1 (0xF<<0)
+#define L4_KWQ_OFFLOAD_PG_RESERVED1_SHIFT 0
+#define L4_KWQ_OFFLOAD_PG_LAYER_CODE (0x7<<4)
+#define L4_KWQ_OFFLOAD_PG_LAYER_CODE_SHIFT 4
+#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT_SHIFT 7
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 l2hdr_nbytes;
+	u8 pg_flags;
+#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP (0x1<<0)
+#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP_SHIFT 0
+#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING (0x1<<1)
+#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING_SHIFT 1
+#define L4_KWQ_OFFLOAD_PG_RESERVED2 (0x3F<<2)
+#define L4_KWQ_OFFLOAD_PG_RESERVED2_SHIFT 2
+	u8 da0;
+	u8 da1;
+#elif defined(__LITTLE_ENDIAN)
+	u8 da1;
+	u8 da0;
+	u8 pg_flags;
+#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP (0x1<<0)
+#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP_SHIFT 0
+#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING (0x1<<1)
+#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING_SHIFT 1
+#define L4_KWQ_OFFLOAD_PG_RESERVED2 (0x3F<<2)
+#define L4_KWQ_OFFLOAD_PG_RESERVED2_SHIFT 2
+	u8 l2hdr_nbytes;
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 da2;
+	u8 da3;
+	u8 da4;
+	u8 da5;
+#elif defined(__LITTLE_ENDIAN)
+	u8 da5;
+	u8 da4;
+	u8 da3;
+	u8 da2;
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 sa0;
+	u8 sa1;
+	u8 sa2;
+	u8 sa3;
+#elif defined(__LITTLE_ENDIAN)
+	u8 sa3;
+	u8 sa2;
+	u8 sa1;
+	u8 sa0;
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 sa4;
+	u8 sa5;
+	u16 etype;
+#elif defined(__LITTLE_ENDIAN)
+	u16 etype;
+	u8 sa5;
+	u8 sa4;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 vlan_tag;
+	u16 ipid_start;
+#elif defined(__LITTLE_ENDIAN)
+	u16 ipid_start;
+	u16 vlan_tag;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 ipid_count;
+	u16 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved3;
+	u16 ipid_count;
+#endif
+	u32 host_opaque;
+};
+
+
+/*
+ * Abortively close the connection request
+ */
+struct l4_kwq_reset_req {
+#if defined(__BIG_ENDIAN)
+	u8 flags;
+#define L4_KWQ_RESET_REQ_RESERVED1 (0xF<<0)
+#define L4_KWQ_RESET_REQ_RESERVED1_SHIFT 0
+#define L4_KWQ_RESET_REQ_LAYER_CODE (0x7<<4)
+#define L4_KWQ_RESET_REQ_LAYER_CODE_SHIFT 4
+#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT_SHIFT 7
+	u8 op_code;
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	u8 op_code;
+	u8 flags;
+#define L4_KWQ_RESET_REQ_RESERVED1 (0xF<<0)
+#define L4_KWQ_RESET_REQ_RESERVED1_SHIFT 0
+#define L4_KWQ_RESET_REQ_LAYER_CODE (0x7<<4)
+#define L4_KWQ_RESET_REQ_LAYER_CODE_SHIFT 4
+#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT_SHIFT 7
+#endif
+	u32 cid;
+	u32 reserved2[6];
+};
+
+
+/*
+ * a KWQE request to update a PG connection
+ */
+struct l4_kwq_update_pg {
+#if defined(__BIG_ENDIAN)
+	u8 flags;
+#define L4_KWQ_UPDATE_PG_RESERVED1 (0xF<<0)
+#define L4_KWQ_UPDATE_PG_RESERVED1_SHIFT 0
+#define L4_KWQ_UPDATE_PG_LAYER_CODE (0x7<<4)
+#define L4_KWQ_UPDATE_PG_LAYER_CODE_SHIFT 4
+#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT_SHIFT 7
+	u8 opcode;
+	u16 oper16;
+#elif defined(__LITTLE_ENDIAN)
+	u16 oper16;
+	u8 opcode;
+	u8 flags;
+#define L4_KWQ_UPDATE_PG_RESERVED1 (0xF<<0)
+#define L4_KWQ_UPDATE_PG_RESERVED1_SHIFT 0
+#define L4_KWQ_UPDATE_PG_LAYER_CODE (0x7<<4)
+#define L4_KWQ_UPDATE_PG_LAYER_CODE_SHIFT 4
+#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT_SHIFT 7
+#endif
+	u32 pg_cid;
+	u32 pg_host_opaque;
+#if defined(__BIG_ENDIAN)
+	u8 pg_valids;
+#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT (0x1<<0)
+#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT_SHIFT 0
+#define L4_KWQ_UPDATE_PG_VALIDS_DA (0x1<<1)
+#define L4_KWQ_UPDATE_PG_VALIDS_DA_SHIFT 1
+#define L4_KWQ_UPDATE_PG_RESERVERD2 (0x3F<<2)
+#define L4_KWQ_UPDATE_PG_RESERVERD2_SHIFT 2
+	u8 pg_unused_a;
+	u16 pg_ipid_count;
+#elif defined(__LITTLE_ENDIAN)
+	u16 pg_ipid_count;
+	u8 pg_unused_a;
+	u8 pg_valids;
+#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT (0x1<<0)
+#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT_SHIFT 0
+#define L4_KWQ_UPDATE_PG_VALIDS_DA (0x1<<1)
+#define L4_KWQ_UPDATE_PG_VALIDS_DA_SHIFT 1
+#define L4_KWQ_UPDATE_PG_RESERVERD2 (0x3F<<2)
+#define L4_KWQ_UPDATE_PG_RESERVERD2_SHIFT 2
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 reserverd3;
+	u8 da0;
+	u8 da1;
+#elif defined(__LITTLE_ENDIAN)
+	u8 da1;
+	u8 da0;
+	u16 reserverd3;
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 da2;
+	u8 da3;
+	u8 da4;
+	u8 da5;
+#elif defined(__LITTLE_ENDIAN)
+	u8 da5;
+	u8 da4;
+	u8 da3;
+	u8 da2;
+#endif
+	u32 reserved4;
+	u32 reserved5;
+};
+
+
+/*
+ * a KWQE request to upload a PG or L4 context
+ */
+struct l4_kwq_upload {
+#if defined(__BIG_ENDIAN)
+	u8 flags;
+#define L4_KWQ_UPLOAD_RESERVED1 (0xF<<0)
+#define L4_KWQ_UPLOAD_RESERVED1_SHIFT 0
+#define L4_KWQ_UPLOAD_LAYER_CODE (0x7<<4)
+#define L4_KWQ_UPLOAD_LAYER_CODE_SHIFT 4
+#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT_SHIFT 7
+	u8 opcode;
+	u16 oper16;
+#elif defined(__LITTLE_ENDIAN)
+	u16 oper16;
+	u8 opcode;
+	u8 flags;
+#define L4_KWQ_UPLOAD_RESERVED1 (0xF<<0)
+#define L4_KWQ_UPLOAD_RESERVED1_SHIFT 0
+#define L4_KWQ_UPLOAD_LAYER_CODE (0x7<<4)
+#define L4_KWQ_UPLOAD_LAYER_CODE_SHIFT 4
+#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT_SHIFT 7
+#endif
+	u32 cid;
+	u32 reserved2[6];
+};
+
+#endif /* CNIC_DEFS_H */
diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h
new file mode 100644
index 0000000..0638096
--- /dev/null
+++ b/drivers/net/cnic_if.h
@@ -0,0 +1,299 @@
+/* cnic_if.h: Broadcom CNIC core network driver.
+ *
+ * Copyright (c) 2006 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ */
+
+
+#ifndef CNIC_IF_H
+#define CNIC_IF_H
+
+#define CNIC_MODULE_VERSION	"2.0.0"
+#define CNIC_MODULE_RELDATE	"May 21, 2009"
+
+#define CNIC_ULP_RDMA		0
+#define CNIC_ULP_ISCSI		1
+#define CNIC_ULP_L4		2
+#define MAX_CNIC_ULP_TYPE_EXT	2
+#define MAX_CNIC_ULP_TYPE	3
+
+struct kwqe {
+	u32 kwqe_op_flag;
+
+#define KWQE_OPCODE_MASK	0x00ff0000
+#define KWQE_OPCODE_SHIFT	16
+#define KWQE_FLAGS_LAYER_SHIFT	28
+#define KWQE_OPCODE(x)		((x & KWQE_OPCODE_MASK) >> KWQE_OPCODE_SHIFT)
+
+	u32 kwqe_info0;
+	u32 kwqe_info1;
+	u32 kwqe_info2;
+	u32 kwqe_info3;
+	u32 kwqe_info4;
+	u32 kwqe_info5;
+	u32 kwqe_info6;
+};
+
+struct kwqe_16 {
+	u32 kwqe_info0;
+	u32 kwqe_info1;
+	u32 kwqe_info2;
+	u32 kwqe_info3;
+};
+
+struct kcqe {
+	u32 kcqe_info0;
+	u32 kcqe_info1;
+	u32 kcqe_info2;
+	u32 kcqe_info3;
+	u32 kcqe_info4;
+	u32 kcqe_info5;
+	u32 kcqe_info6;
+	u32 kcqe_op_flag;
+		#define KCQE_RAMROD_COMPLETION		(0x1<<27) /* Everest */
+		#define KCQE_FLAGS_LAYER_MASK		(0x7<<28)
+		#define KCQE_FLAGS_LAYER_MASK_MISC	(0<<28)
+		#define KCQE_FLAGS_LAYER_MASK_L2	(2<<28)
+		#define KCQE_FLAGS_LAYER_MASK_L3	(3<<28)
+		#define KCQE_FLAGS_LAYER_MASK_L4	(4<<28)
+		#define KCQE_FLAGS_LAYER_MASK_L5_RDMA	(5<<28)
+		#define KCQE_FLAGS_LAYER_MASK_L5_ISCSI	(6<<28)
+		#define KCQE_FLAGS_NEXT 		(1<<31)
+		#define KCQE_FLAGS_OPCODE_MASK		(0xff<<16)
+		#define KCQE_FLAGS_OPCODE_SHIFT		(16)
+		#define KCQE_OPCODE(op)			\
+		(((op) & KCQE_FLAGS_OPCODE_MASK) >> KCQE_FLAGS_OPCODE_SHIFT)
+};
+
+#define MAX_CNIC_CTL_DATA	64
+#define MAX_DRV_CTL_DATA	64
+
+#define CNIC_CTL_STOP_CMD		1
+#define CNIC_CTL_START_CMD		2
+#define CNIC_CTL_COMPLETION_CMD		3
+
+#define DRV_CTL_IO_WR_CMD		0x101
+#define DRV_CTL_IO_RD_CMD		0x102
+#define DRV_CTL_CTX_WR_CMD		0x103
+#define DRV_CTL_CTXTBL_WR_CMD		0x104
+#define DRV_CTL_COMPLETION_CMD		0x105
+
+struct cnic_ctl_completion {
+	u32	cid;
+};
+
+struct drv_ctl_completion {
+	u32	comp_count;
+};
+
+struct cnic_ctl_info {
+	int	cmd;
+	union {
+		struct cnic_ctl_completion comp;
+		char bytes[MAX_CNIC_CTL_DATA];
+	} data;
+};
+
+struct drv_ctl_io {
+	u32		cid_addr;
+	u32		offset;
+	u32		data;
+	dma_addr_t	dma_addr;
+};
+
+struct drv_ctl_info {
+	int	cmd;
+	union {
+		struct drv_ctl_completion comp;
+		struct drv_ctl_io io;
+		char bytes[MAX_DRV_CTL_DATA];
+	} data;
+};
+
+struct cnic_ops {
+	struct module	*cnic_owner;
+	/* Calls to these functions are protected by RCU.  When
+	 * unregistering, we wait for any calls to complete before
+	 * continuing.
+	 */
+	int		(*cnic_handler)(void *, void *);
+	int		(*cnic_ctl)(void *, struct cnic_ctl_info *);
+};
+
+#define MAX_CNIC_VEC	8
+
+struct cnic_irq {
+	unsigned int	vector;
+	void		*status_blk;
+	u32		status_blk_num;
+	u32		irq_flags;
+#define CNIC_IRQ_FL_MSIX		0x00000001
+};
+
+struct cnic_eth_dev {
+	struct module	*drv_owner;
+	u32		drv_state;
+#define CNIC_DRV_STATE_REGD		0x00000001
+#define CNIC_DRV_STATE_USING_MSIX	0x00000002
+	u32		chip_id;
+	u32		max_kwqe_pending;
+	struct pci_dev	*pdev;
+	void __iomem	*io_base;
+
+	u32		ctx_tbl_offset;
+	u32		ctx_tbl_len;
+	int		ctx_blk_size;
+	u32		starting_cid;
+	u32		max_iscsi_conn;
+	u32		max_fcoe_conn;
+	u32		max_rdma_conn;
+	u32		reserved0[2];
+
+	int		num_irq;
+	struct cnic_irq	irq_arr[MAX_CNIC_VEC];
+	int		(*drv_register_cnic)(struct net_device *,
+					     struct cnic_ops *, void *);
+	int		(*drv_unregister_cnic)(struct net_device *);
+	int		(*drv_submit_kwqes_32)(struct net_device *,
+					       struct kwqe *[], u32);
+	int		(*drv_submit_kwqes_16)(struct net_device *,
+					       struct kwqe_16 *[], u32);
+	int		(*drv_ctl)(struct net_device *, struct drv_ctl_info *);
+	unsigned long	reserved1[2];
+};
+
+struct cnic_sockaddr {
+	union {
+		struct sockaddr_in	v4;
+		struct sockaddr_in6	v6;
+	} local;
+	union {
+		struct sockaddr_in	v4;
+		struct sockaddr_in6	v6;
+	} remote;
+};
+
+struct cnic_sock {
+	struct cnic_dev *dev;
+	void	*context;
+	u32	src_ip[4];
+	u32	dst_ip[4];
+	u16	src_port;
+	u16	dst_port;
+	u16	vlan_id;
+	unsigned char old_ha[6];
+	unsigned char ha[6];
+	u32	mtu;
+	u32	cid;
+	u32	l5_cid;
+	u32	pg_cid;
+	int	ulp_type;
+
+	u32	ka_timeout;
+	u32	ka_interval;
+	u8	ka_max_probe_count;
+	u8	tos;
+	u8	ttl;
+	u8	snd_seq_scale;
+	u32	rcv_buf;
+	u32	snd_buf;
+	u32	seed;
+
+	unsigned long	tcp_flags;
+#define SK_TCP_NO_DELAY_ACK	0x1
+#define SK_TCP_KEEP_ALIVE	0x2
+#define SK_TCP_NAGLE		0x4
+#define SK_TCP_TIMESTAMP	0x8
+#define SK_TCP_SACK		0x10
+#define SK_TCP_SEG_SCALING	0x20
+	unsigned long	flags;
+#define SK_F_INUSE		0
+#define SK_F_OFFLD_COMPLETE	1
+#define SK_F_OFFLD_SCHED	2
+#define SK_F_PG_OFFLD_COMPLETE	3
+#define SK_F_CONNECT_START	4
+#define SK_F_IPV6		5
+#define SK_F_CLOSING		7
+
+	atomic_t ref_count;
+	u32 state;
+	struct kwqe kwqe1;
+	struct kwqe kwqe2;
+	struct kwqe kwqe3;
+};
+
+struct cnic_dev {
+	struct net_device	*netdev;
+	struct pci_dev		*pcidev;
+	void __iomem		*regview;
+	struct list_head	list;
+
+	int (*register_device)(struct cnic_dev *dev, int ulp_type,
+			       void *ulp_ctx);
+	int (*unregister_device)(struct cnic_dev *dev, int ulp_type);
+	int (*submit_kwqes)(struct cnic_dev *dev, struct kwqe *wqes[],
+				u32 num_wqes);
+	int (*submit_kwqes_16)(struct cnic_dev *dev, struct kwqe_16 *wqes[],
+				u32 num_wqes);
+
+	int (*cm_create)(struct cnic_dev *, int, u32, u32, struct cnic_sock **,
+			 void *);
+	int (*cm_destroy)(struct cnic_sock *);
+	int (*cm_connect)(struct cnic_sock *, struct cnic_sockaddr *);
+	int (*cm_abort)(struct cnic_sock *);
+	int (*cm_close)(struct cnic_sock *);
+	struct cnic_dev *(*cm_select_dev)(struct sockaddr_in *, int ulp_type);
+	int (*iscsi_nl_msg_recv)(struct cnic_dev *dev, u32 msg_type,
+				 char *data, u16 data_size);
+	unsigned long	flags;
+#define CNIC_F_CNIC_UP		1
+#define CNIC_F_BNX2_CLASS	3
+#define CNIC_F_BNX2X_CLASS	4
+	atomic_t	ref_count;
+	u8		mac_addr[6];
+
+	int		max_iscsi_conn;
+	int		max_fcoe_conn;
+	int		max_rdma_conn;
+
+	void		*cnic_priv;
+};
+
+#define CNIC_WR(dev, off, val)		writel(val, dev->regview + off)
+#define CNIC_WR16(dev, off, val)	writew(val, dev->regview + off)
+#define CNIC_WR8(dev, off, val)		writeb(val, dev->regview + off)
+#define CNIC_RD(dev, off)		readl(dev->regview + off)
+#define CNIC_RD16(dev, off)		readw(dev->regview + off)
+
+struct cnic_ulp_ops {
+	/* Calls to these functions are protected by RCU.  When
+	 * unregistering, we wait for any calls to complete before
+	 * continuing.
+	 */
+
+	void (*cnic_init)(struct cnic_dev *dev);
+	void (*cnic_exit)(struct cnic_dev *dev);
+	void (*cnic_start)(void *ulp_ctx);
+	void (*cnic_stop)(void *ulp_ctx);
+	void (*indicate_kcqes)(void *ulp_ctx, struct kcqe *cqes[],
+				u32 num_cqes);
+	void (*indicate_netevent)(void *ulp_ctx, unsigned long event);
+	void (*cm_connect_complete)(struct cnic_sock *);
+	void (*cm_close_complete)(struct cnic_sock *);
+	void (*cm_abort_complete)(struct cnic_sock *);
+	void (*cm_remote_close)(struct cnic_sock *);
+	void (*cm_remote_abort)(struct cnic_sock *);
+	void (*iscsi_nl_send_msg)(struct cnic_dev *dev, u32 msg_type,
+				  char *data, u16 data_size);
+	struct module *owner;
+};
+
+extern int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops);
+
+extern int cnic_unregister_driver(int ulp_type);
+
+#endif
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index 329f890..f1f773b 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -45,7 +45,8 @@
     defined(CONFIG_MACH_ZYLONITE) ||\
     defined(CONFIG_MACH_LITTLETON) ||\
     defined(CONFIG_MACH_ZYLONITE2) ||\
-    defined(CONFIG_ARCH_VIPER)
+    defined(CONFIG_ARCH_VIPER) ||\
+    defined(CONFIG_MACH_STARGATE2)
 
 #include <asm/mach-types.h>
 
@@ -73,7 +74,7 @@
 /* We actually can't write halfwords properly if not word aligned */
 static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 {
-	if (machine_is_mainstone() && reg & 2) {
+	if ((machine_is_mainstone() || machine_is_stargate2()) && reg & 2) {
 		unsigned int v = val << 16;
 		v |= readl(ioaddr + (reg & ~2)) & 0xffff;
 		writel(v, ioaddr + (reg & ~2));
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 4d1d479..7fa620d 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -845,6 +845,10 @@
 	int err;
 	struct net_device *dev;
 	struct virtnet_info *vi;
+	struct virtqueue *vqs[3];
+	vq_callback_t *callbacks[] = { skb_recv_done, skb_xmit_done, NULL};
+	const char *names[] = { "input", "output", "control" };
+	int nvqs;
 
 	/* Allocate ourselves a network device with room for our info */
 	dev = alloc_etherdev(sizeof(struct virtnet_info));
@@ -905,25 +909,19 @@
 	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
 		vi->mergeable_rx_bufs = true;
 
-	/* We expect two virtqueues, receive then send. */
-	vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done);
-	if (IS_ERR(vi->rvq)) {
-		err = PTR_ERR(vi->rvq);
-		goto free;
-	}
+	/* We expect two virtqueues, receive then send,
+	 * and optionally control. */
+	nvqs = virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ? 3 : 2;
 
-	vi->svq = vdev->config->find_vq(vdev, 1, skb_xmit_done);
-	if (IS_ERR(vi->svq)) {
-		err = PTR_ERR(vi->svq);
-		goto free_recv;
-	}
+	err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
+	if (err)
+		goto free;
+
+	vi->rvq = vqs[0];
+	vi->svq = vqs[1];
 
 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) {
-		vi->cvq = vdev->config->find_vq(vdev, 2, NULL);
-		if (IS_ERR(vi->cvq)) {
-			err = PTR_ERR(vi->svq);
-			goto free_send;
-		}
+		vi->cvq = vqs[2];
 
 		if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN))
 			dev->features |= NETIF_F_HW_VLAN_FILTER;
@@ -941,7 +939,7 @@
 	err = register_netdev(dev);
 	if (err) {
 		pr_debug("virtio_net: registering device failed\n");
-		goto free_ctrl;
+		goto free_vqs;
 	}
 
 	/* Last of all, set up some receive buffers. */
@@ -962,13 +960,8 @@
 
 unregister:
 	unregister_netdev(dev);
-free_ctrl:
-	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
-		vdev->config->del_vq(vi->cvq);
-free_send:
-	vdev->config->del_vq(vi->svq);
-free_recv:
-	vdev->config->del_vq(vi->rvq);
+free_vqs:
+	vdev->config->del_vqs(vdev);
 free:
 	free_netdev(dev);
 	return err;
@@ -994,12 +987,10 @@
 
 	BUG_ON(vi->num != 0);
 
-	vdev->config->del_vq(vi->svq);
-	vdev->config->del_vq(vi->rvq);
-	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
-		vdev->config->del_vq(vi->cvq);
 	unregister_netdev(vi->dev);
 
+	vdev->config->del_vqs(vi->vdev);
+
 	while (vi->pages)
 		__free_pages(get_a_page(vi, GFP_KERNEL), 0);
 
diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c
index 765a7f5..a6dc317 100644
--- a/drivers/net/wan/ixp4xx_hss.c
+++ b/drivers/net/wan/ixp4xx_hss.c
@@ -579,7 +579,8 @@
 	debug_desc(phys, desc);
 	BUG_ON(phys & 0x1F);
 	qmgr_put_entry(queue, phys);
-	BUG_ON(qmgr_stat_overflow(queue));
+	/* Don't check for queue overflow here, we've allocated sufficient
+	   length and queues >= 32 don't support this check anyway. */
 }
 
 
@@ -789,10 +790,10 @@
 		free_buffer_irq(port->tx_buff_tab[n_desc]);
 		port->tx_buff_tab[n_desc] = NULL;
 
-		start = qmgr_stat_empty(port->plat->txreadyq);
+		start = qmgr_stat_below_low_watermark(port->plat->txreadyq);
 		queue_put_desc(port->plat->txreadyq,
 			       tx_desc_phys(port, n_desc), desc);
-		if (start) {
+		if (start) { /* TX-ready queue was empty */
 #if DEBUG_TX
 			printk(KERN_DEBUG "%s: hss_hdlc_txdone_irq xmit"
 			       " ready\n", dev->name);
@@ -867,13 +868,13 @@
 	queue_put_desc(queue_ids[port->id].tx, tx_desc_phys(port, n), desc);
 	dev->trans_start = jiffies;
 
-	if (qmgr_stat_empty(txreadyq)) {
+	if (qmgr_stat_below_low_watermark(txreadyq)) { /* empty */
 #if DEBUG_TX
 		printk(KERN_DEBUG "%s: hss_hdlc_xmit queue full\n", dev->name);
 #endif
 		netif_stop_queue(dev);
 		/* we could miss TX ready interrupt */
-		if (!qmgr_stat_empty(txreadyq)) {
+		if (!qmgr_stat_below_low_watermark(txreadyq)) {
 #if DEBUG_TX
 			printk(KERN_DEBUG "%s: hss_hdlc_xmit ready again\n",
 			       dev->name);
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index f821dbc..27f3b81 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -1,21 +1,21 @@
 config OF_DEVICE
 	def_bool y
-	depends on OF && (SPARC || PPC_OF)
+	depends on OF && (SPARC || PPC_OF || MICROBLAZE)
 
 config OF_GPIO
 	def_bool y
-	depends on OF && PPC_OF && GPIOLIB
+	depends on OF && (PPC_OF || MICROBLAZE) && GPIOLIB
 	help
 	  OpenFirmware GPIO accessors
 
 config OF_I2C
 	def_tristate I2C
-	depends on PPC_OF && I2C
+	depends on (PPC_OF || MICROBLAZE) && I2C
 	help
 	  OpenFirmware I2C accessors
 
 config OF_SPI
 	def_tristate SPI
-	depends on OF && PPC_OF && SPI
+	depends on OF && (PPC_OF || MICROBLAZE) && SPI
 	help
 	  OpenFirmware SPI accessors
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 2764735..fbf965b 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -217,7 +217,7 @@
 	depends on ARM && ARCH_PXA && PCMCIA
 	depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \
 		    || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
-		    || ARCH_VIPER || ARCH_PXA_ESERIES)
+		    || ARCH_VIPER || ARCH_PXA_ESERIES || MACH_STARGATE2)
 	help
 	  Say Y here to include support for the PXA2xx PCMCIA controller
 
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index bbac463..047394d 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -73,5 +73,6 @@
 pxa2xx-obj-$(CONFIG_MACH_PALMTX)		+= pxa2xx_palmtx.o
 pxa2xx-obj-$(CONFIG_MACH_PALMLD)		+= pxa2xx_palmld.o
 pxa2xx-obj-$(CONFIG_MACH_E740)			+= pxa2xx_e740.o
+pxa2xx-obj-$(CONFIG_MACH_STARGATE2)		+= pxa2xx_stargate2.o
 
 obj-$(CONFIG_PCMCIA_PXA2XX)			+= pxa2xx_core.o $(pxa2xx-obj-y)
diff --git a/drivers/pcmcia/pxa2xx_stargate2.c b/drivers/pcmcia/pxa2xx_stargate2.c
new file mode 100644
index 0000000..490749e
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_stargate2.c
@@ -0,0 +1,174 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_stargate2.c
+ *
+ * Stargate 2 PCMCIA specific routines.
+ *
+ * Created:	December 6, 2005
+ * Author:	Ed C. Epp
+ * Copyright:	Intel Corp 2005
+ *              Jonathan Cameron <jic23@cam.ac.uk> 2009
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <pcmcia/ss.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include "soc_common.h"
+
+#define SG2_S0_BUFF_CTL		120
+#define SG2_S0_POWER_CTL	108
+#define SG2_S0_GPIO_RESET	82
+#define SG2_S0_GPIO_DETECT	53
+#define SG2_S0_GPIO_READY	81
+
+static struct pcmcia_irqs irqs[] = {
+	{ 0, IRQ_GPIO(SG2_S0_GPIO_DETECT), "PCMCIA0 CD" },
+};
+
+static int sg2_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	skt->irq = IRQ_GPIO(SG2_S0_GPIO_READY);
+	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));
+}
+
+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,
+				       const socket_state_t *state)
+{
+	/* Enable card power */
+	switch (state->Vcc) {
+	case 0:
+		/* sets power ctl register high */
+		gpio_set_value(SG2_S0_POWER_CTL, 1);
+		break;
+	case 33:
+	case 50:
+		/* sets power control register low (clear) */
+		gpio_set_value(SG2_S0_POWER_CTL, 0);
+		msleep(100);
+		break;
+	default:
+		pr_err("%s(): bad Vcc %u\n",
+		       __func__, state->Vcc);
+		return -1;
+	}
+
+	/* reset */
+	gpio_set_value(SG2_S0_GPIO_RESET, !!(state->flags & SS_RESET));
+
+	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,
+};
+
+static struct platform_device *sg2_pcmcia_device;
+
+static int __init sg2_pcmcia_init(void)
+{
+	int ret;
+
+	if (!machine_is_stargate2())
+		return -ENODEV;
+
+	sg2_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!sg2_pcmcia_device)
+		return -ENOMEM;
+
+	ret = gpio_request(SG2_S0_BUFF_CTL, "SG2 CF buff ctl");
+	if (ret)
+		goto error_put_platform_device;
+	ret = gpio_request(SG2_S0_POWER_CTL, "SG2 CF power ctl");
+	if (ret)
+		goto error_free_gpio_buff_ctl;
+	ret = gpio_request(SG2_S0_GPIO_RESET, "SG2 CF reset");
+	if (ret)
+		goto error_free_gpio_power_ctl;
+	/* Set gpio directions */
+	gpio_direction_output(SG2_S0_BUFF_CTL, 0);
+	gpio_direction_output(SG2_S0_POWER_CTL, 1);
+	gpio_direction_output(SG2_S0_GPIO_RESET, 1);
+
+	ret = platform_device_add_data(sg2_pcmcia_device,
+				       &sg2_pcmcia_ops,
+				       sizeof(sg2_pcmcia_ops));
+	if (ret)
+		goto error_free_gpio_reset;
+
+	ret = platform_device_add(sg2_pcmcia_device);
+	if (ret)
+		goto error_free_gpio_reset;
+
+	return 0;
+error_free_gpio_reset:
+	gpio_free(SG2_S0_GPIO_RESET);
+error_free_gpio_power_ctl:
+	gpio_free(SG2_S0_POWER_CTL);
+error_free_gpio_buff_ctl:
+	gpio_free(SG2_S0_BUFF_CTL);
+error_put_platform_device:
+	platform_device_put(sg2_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit sg2_pcmcia_exit(void)
+{
+	platform_device_unregister(sg2_pcmcia_device);
+	gpio_free(SG2_S0_BUFF_CTL);
+	gpio_free(SG2_S0_POWER_CTL);
+	gpio_free(SG2_S0_GPIO_RESET);
+}
+
+fs_initcall(sg2_pcmcia_init);
+module_exit(sg2_pcmcia_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index f604061..ba97654 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -638,6 +638,24 @@
 }
 EXPORT_SYMBOL(pnp_possible_config);
 
+int pnp_range_reserved(resource_size_t start, resource_size_t end)
+{
+	struct pnp_dev *dev;
+	struct pnp_resource *pnp_res;
+	resource_size_t *dev_start, *dev_end;
+
+	pnp_for_each_dev(dev) {
+		list_for_each_entry(pnp_res, &dev->resources, list) {
+			dev_start = &pnp_res->res.start;
+			dev_end   = &pnp_res->res.end;
+			if (ranged_conflict(&start, &end, dev_start, dev_end))
+				return 1;
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(pnp_range_reserved);
+
 /* format is: pnp_reserve_irq=irq1[,irq2] .... */
 static int __init pnp_setup_reserve_irq(char *str)
 {
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c
index f7a3283..551332e 100644
--- a/drivers/rtc/rtc-ep93xx.c
+++ b/drivers/rtc/rtc-ep93xx.c
@@ -12,32 +12,56 @@
 #include <linux/module.h>
 #include <linux/rtc.h>
 #include <linux/platform_device.h>
-#include <mach/hardware.h>
+#include <linux/io.h>
 
-#define EP93XX_RTC_REG(x)	(EP93XX_RTC_BASE + (x))
-#define EP93XX_RTC_DATA		EP93XX_RTC_REG(0x0000)
-#define EP93XX_RTC_LOAD		EP93XX_RTC_REG(0x000C)
-#define EP93XX_RTC_SWCOMP	EP93XX_RTC_REG(0x0108)
+#define EP93XX_RTC_DATA			0x000
+#define EP93XX_RTC_MATCH		0x004
+#define EP93XX_RTC_STATUS		0x008
+#define  EP93XX_RTC_STATUS_INTR		 (1<<0)
+#define EP93XX_RTC_LOAD			0x00C
+#define EP93XX_RTC_CONTROL		0x010
+#define  EP93XX_RTC_CONTROL_MIE		 (1<<0)
+#define EP93XX_RTC_SWCOMP		0x108
+#define  EP93XX_RTC_SWCOMP_DEL_MASK	 0x001f0000
+#define  EP93XX_RTC_SWCOMP_DEL_SHIFT	 16
+#define  EP93XX_RTC_SWCOMP_INT_MASK	 0x0000ffff
+#define  EP93XX_RTC_SWCOMP_INT_SHIFT	 0
 
-#define DRV_VERSION "0.2"
+#define DRV_VERSION "0.3"
 
-static int ep93xx_get_swcomp(struct device *dev, unsigned short *preload,
+/*
+ * struct device dev.platform_data is used to store our private data
+ * because struct rtc_device does not have a variable to hold it.
+ */
+struct ep93xx_rtc {
+	void __iomem	*mmio_base;
+};
+
+static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,
 				unsigned short *delete)
 {
-	unsigned short comp = __raw_readl(EP93XX_RTC_SWCOMP);
+	struct ep93xx_rtc *ep93xx_rtc = dev->platform_data;
+	unsigned long comp;
+
+	comp = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP);
 
 	if (preload)
-		*preload = comp & 0xffff;
+		*preload = (comp & EP93XX_RTC_SWCOMP_INT_MASK)
+				>> EP93XX_RTC_SWCOMP_INT_SHIFT;
 
 	if (delete)
-		*delete = (comp >> 16) & 0x1f;
+		*delete = (comp & EP93XX_RTC_SWCOMP_DEL_MASK)
+				>> EP93XX_RTC_SWCOMP_DEL_SHIFT;
 
 	return 0;
 }
 
 static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
-	unsigned long time = __raw_readl(EP93XX_RTC_DATA);
+	struct ep93xx_rtc *ep93xx_rtc = dev->platform_data;
+	unsigned long time;
+
+	 time = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA);
 
 	rtc_time_to_tm(time, tm);
 	return 0;
@@ -45,7 +69,9 @@
 
 static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs)
 {
-	__raw_writel(secs + 1, EP93XX_RTC_LOAD);
+	struct ep93xx_rtc *ep93xx_rtc = dev->platform_data;
+
+	__raw_writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD);
 	return 0;
 }
 
@@ -53,7 +79,7 @@
 {
 	unsigned short preload, delete;
 
-	ep93xx_get_swcomp(dev, &preload, &delete);
+	ep93xx_rtc_get_swcomp(dev, &preload, &delete);
 
 	seq_printf(seq, "preload\t\t: %d\n", preload);
 	seq_printf(seq, "delete\t\t: %d\n", delete);
@@ -67,54 +93,104 @@
 	.proc		= ep93xx_rtc_proc,
 };
 
-static ssize_t ep93xx_sysfs_show_comp_preload(struct device *dev,
+static ssize_t ep93xx_rtc_show_comp_preload(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
 	unsigned short preload;
 
-	ep93xx_get_swcomp(dev, &preload, NULL);
+	ep93xx_rtc_get_swcomp(dev, &preload, NULL);
 
 	return sprintf(buf, "%d\n", preload);
 }
-static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_sysfs_show_comp_preload, NULL);
+static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_rtc_show_comp_preload, NULL);
 
-static ssize_t ep93xx_sysfs_show_comp_delete(struct device *dev,
+static ssize_t ep93xx_rtc_show_comp_delete(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
 	unsigned short delete;
 
-	ep93xx_get_swcomp(dev, NULL, &delete);
+	ep93xx_rtc_get_swcomp(dev, NULL, &delete);
 
 	return sprintf(buf, "%d\n", delete);
 }
-static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_sysfs_show_comp_delete, NULL);
+static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_rtc_show_comp_delete, NULL);
 
 
-static int __devinit ep93xx_rtc_probe(struct platform_device *dev)
+static int __init ep93xx_rtc_probe(struct platform_device *pdev)
 {
-	struct rtc_device *rtc = rtc_device_register("ep93xx",
-				&dev->dev, &ep93xx_rtc_ops, THIS_MODULE);
+	struct ep93xx_rtc *ep93xx_rtc;
+	struct resource *res;
+	struct rtc_device *rtc;
+	int err;
 
-	if (IS_ERR(rtc)) {
-		return PTR_ERR(rtc);
+	ep93xx_rtc = kzalloc(sizeof(struct ep93xx_rtc), GFP_KERNEL);
+	if (ep93xx_rtc == NULL)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL)
+		return -ENXIO;
+
+	res = request_mem_region(res->start, resource_size(res), pdev->name);
+	if (res == NULL)
+		return -EBUSY;
+
+	ep93xx_rtc->mmio_base = ioremap(res->start, resource_size(res));
+	if (ep93xx_rtc->mmio_base == NULL) {
+		err = -ENXIO;
+		goto fail;
 	}
 
-	platform_set_drvdata(dev, rtc);
+	pdev->dev.platform_data = ep93xx_rtc;
 
-	device_create_file(&dev->dev, &dev_attr_comp_preload);
-	device_create_file(&dev->dev, &dev_attr_comp_delete);
+	rtc = rtc_device_register(pdev->name,
+				&pdev->dev, &ep93xx_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		err = PTR_ERR(rtc);
+		goto fail;
+	}
+
+	platform_set_drvdata(pdev, rtc);
+
+	err = device_create_file(&pdev->dev, &dev_attr_comp_preload);
+	if (err)
+		goto fail;
+	err = device_create_file(&pdev->dev, &dev_attr_comp_delete);
+	if (err) {
+		device_remove_file(&pdev->dev, &dev_attr_comp_preload);
+		goto fail;
+	}
 
 	return 0;
+
+fail:
+	if (ep93xx_rtc->mmio_base) {
+		iounmap(ep93xx_rtc->mmio_base);
+		pdev->dev.platform_data = NULL;
+	}
+	release_mem_region(res->start, resource_size(res));
+	return err;
 }
 
-static int __devexit ep93xx_rtc_remove(struct platform_device *dev)
+static int __exit ep93xx_rtc_remove(struct platform_device *pdev)
 {
-	struct rtc_device *rtc = platform_get_drvdata(dev);
+	struct rtc_device *rtc = platform_get_drvdata(pdev);
+	struct ep93xx_rtc *ep93xx_rtc = pdev->dev.platform_data;
+	struct resource *res;
 
- 	if (rtc)
-		rtc_device_unregister(rtc);
+	/* cleanup sysfs */
+	device_remove_file(&pdev->dev, &dev_attr_comp_delete);
+	device_remove_file(&pdev->dev, &dev_attr_comp_preload);
 
-	platform_set_drvdata(dev, NULL);
+	rtc_device_unregister(rtc);
+
+	iounmap(ep93xx_rtc->mmio_base);
+	pdev->dev.platform_data = NULL;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, resource_size(res));
+
+	platform_set_drvdata(pdev, NULL);
 
 	return 0;
 }
@@ -122,23 +198,22 @@
 /* work with hotplug and coldplug */
 MODULE_ALIAS("platform:ep93xx-rtc");
 
-static struct platform_driver ep93xx_rtc_platform_driver = {
+static struct platform_driver ep93xx_rtc_driver = {
 	.driver		= {
 		.name	= "ep93xx-rtc",
 		.owner	= THIS_MODULE,
 	},
-	.probe		= ep93xx_rtc_probe,
-	.remove		= __devexit_p(ep93xx_rtc_remove),
+	.remove		= __exit_p(ep93xx_rtc_remove),
 };
 
 static int __init ep93xx_rtc_init(void)
 {
-	return platform_driver_register(&ep93xx_rtc_platform_driver);
+        return platform_driver_probe(&ep93xx_rtc_driver, ep93xx_rtc_probe);
 }
 
 static void __exit ep93xx_rtc_exit(void)
 {
-	platform_driver_unregister(&ep93xx_rtc_platform_driver);
+	platform_driver_unregister(&ep93xx_rtc_driver);
 }
 
 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c
index aaf1f75..457231b 100644
--- a/drivers/rtc/rtc-pl030.c
+++ b/drivers/rtc/rtc-pl030.c
@@ -117,7 +117,7 @@
 		goto err_rtc;
 	}
 
-	rtc->base = ioremap(dev->res.start, SZ_4K);
+	rtc->base = ioremap(dev->res.start, resource_size(&dev->res));
 	if (!rtc->base) {
 		ret = -ENOMEM;
 		goto err_map;
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index 451fc13..f41873f 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -142,8 +142,7 @@
 		goto out;
 	}
 
-	ldata->base = ioremap(adev->res.start,
-			      adev->res.end - adev->res.start + 1);
+	ldata->base = ioremap(adev->res.start, resource_size(&adev->res));
 	if (!ldata->base) {
 		ret = -ENOMEM;
 		goto out_no_remap;
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 27a1be0..442bb98 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -851,8 +851,10 @@
 
 	/* Check the cqr */
 	rc = dasd_check_cqr(cqr);
-	if (rc)
+	if (rc) {
+		cqr->intrc = rc;
 		return rc;
+	}
 	device = (struct dasd_device *) cqr->startdev;
 	if (cqr->retries < 0) {
 		/* internal error 14 - start_IO run out of retries */
@@ -915,6 +917,7 @@
 		BUG();
 		break;
 	}
+	cqr->intrc = rc;
 	return rc;
 }
 
@@ -1454,8 +1457,12 @@
 	dasd_add_request_tail(cqr);
 	wait_event(generic_waitq, _wait_for_wakeup(cqr));
 
-	/* Request status is either done or failed. */
-	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
+	if (cqr->status == DASD_CQR_DONE)
+		rc = 0;
+	else if (cqr->intrc)
+		rc = cqr->intrc;
+	else
+		rc = -EIO;
 	return rc;
 }
 
@@ -1477,8 +1484,15 @@
 		dasd_cancel_req(cqr);
 		/* wait (non-interruptible) for final status */
 		wait_event(generic_waitq, _wait_for_wakeup(cqr));
+		cqr->intrc = rc;
 	}
-	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
+
+	if (cqr->status == DASD_CQR_DONE)
+		rc = 0;
+	else if (cqr->intrc)
+		rc = cqr->intrc;
+	else
+		rc = -EIO;
 	return rc;
 }
 
@@ -1523,8 +1537,12 @@
 
 	wait_event(generic_waitq, _wait_for_wakeup(cqr));
 
-	/* Request status is either done or failed. */
-	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
+	if (cqr->status == DASD_CQR_DONE)
+		rc = 0;
+	else if (cqr->intrc)
+		rc = cqr->intrc;
+	else
+		rc = -EIO;
 	return rc;
 }
 
@@ -2427,12 +2445,12 @@
 
 
 int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic,
-				void **rdc_buffer, int rdc_buffer_size)
+				void *rdc_buffer, int rdc_buffer_size)
 {
 	int ret;
 	struct dasd_ccw_req *cqr;
 
-	cqr = dasd_generic_build_rdc(device, *rdc_buffer, rdc_buffer_size,
+	cqr = dasd_generic_build_rdc(device, rdc_buffer, rdc_buffer_size,
 				     magic);
 	if (IS_ERR(cqr))
 		return PTR_ERR(cqr);
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 2efaddf..644086b 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -202,6 +202,7 @@
 		rc = -EIO;
 		break;
 	}
+	cqr->intrc = rc;
 	return rc;
 }
 
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index a41c940..cf0cfdb 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1097,20 +1097,20 @@
 {
 	struct dasd_eckd_private *private;
 	struct dasd_block *block;
-	void *rdc_data;
 	int is_known, rc;
 
 	private = (struct dasd_eckd_private *) device->private;
-	if (private == NULL) {
-		private = kzalloc(sizeof(struct dasd_eckd_private),
-				  GFP_KERNEL | GFP_DMA);
-		if (private == NULL) {
+	if (!private) {
+		private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
+		if (!private) {
 			dev_warn(&device->cdev->dev,
 				 "Allocating memory for private DASD data "
 				 "failed\n");
 			return -ENOMEM;
 		}
 		device->private = (void *) private;
+	} else {
+		memset(private, 0, sizeof(*private));
 	}
 	/* Invalidate status of initial analysis. */
 	private->init_cqr_status = -1;
@@ -1161,9 +1161,8 @@
 		goto out_err3;
 
 	/* Read Device Characteristics */
-	rdc_data = (void *) &(private->rdc_data);
-	memset(rdc_data, 0, sizeof(rdc_data));
-	rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64);
+	rc = dasd_generic_read_dev_chars(device, "ECKD", &private->rdc_data,
+					 64);
 	if (rc) {
 		DBF_EVENT(DBF_WARNING,
 			  "Read device characteristics failed, rc=%d for "
@@ -1183,7 +1182,7 @@
 		 private->rdc_data.dev_model,
 		 private->rdc_data.cu_type,
 		 private->rdc_data.cu_model.model,
-		    private->real_cyl,
+		 private->real_cyl,
 		 private->rdc_data.trk_per_cyl,
 		 private->rdc_data.sec_per_trk);
 	return 0;
@@ -2336,9 +2335,10 @@
 {
 	int tpm, cmdrtd, cmdwtd;
 	int use_prefix;
-
-	struct dasd_eckd_private *private;
+#if defined(CONFIG_64BIT)
 	int fcx_in_css, fcx_in_gneq, fcx_in_features;
+#endif
+	struct dasd_eckd_private *private;
 	struct dasd_device *basedev;
 	sector_t first_rec, last_rec;
 	sector_t first_trk, last_trk;
@@ -2361,11 +2361,15 @@
 	last_offs = sector_div(last_trk, blk_per_trk);
 	cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk);
 
-	/* is transport mode supported ? */
+	/* is transport mode supported? */
+#if defined(CONFIG_64BIT)
 	fcx_in_css = css_general_characteristics.fcx;
 	fcx_in_gneq = private->gneq->reserved2[7] & 0x04;
 	fcx_in_features = private->features.feature[40] & 0x80;
 	tpm = fcx_in_css && fcx_in_gneq && fcx_in_features;
+#else
+	tpm = 0;
+#endif
 
 	/* is read track data and write track data in command mode supported? */
 	cmdrtd = private->features.feature[9] & 0x20;
@@ -3013,8 +3017,9 @@
 		      " I/O status report for device %s:\n",
 		      dev_name(&device->cdev->dev));
 	len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-		       " in req: %p CS: 0x%02X DS: 0x%02X\n", req,
-		       scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw));
+		       " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d\n",
+		       req, scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw),
+		       scsw_cc(&irb->scsw), req->intrc);
 	len += sprintf(page + len, KERN_ERR PRINTK_HEADER
 		       " device %s: Failing CCW: %p\n",
 		       dev_name(&device->cdev->dev),
@@ -3115,9 +3120,10 @@
 		      " I/O status report for device %s:\n",
 		      dev_name(&device->cdev->dev));
 	len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-		       " in req: %p CS: 0x%02X DS: 0x%02X "
+		       " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d "
 		       "fcxs: 0x%02X schxs: 0x%02X\n", req,
 		       scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw),
+		       scsw_cc(&irb->scsw), req->intrc,
 		       irb->scsw.tm.fcxs, irb->scsw.tm.schxs);
 	len += sprintf(page + len, KERN_ERR PRINTK_HEADER
 		       " device %s: Failing TCW: %p\n",
@@ -3273,8 +3279,14 @@
 static int __init
 dasd_eckd_init(void)
 {
+	int ret;
+
 	ASCEBC(dasd_eckd_discipline.ebcname, 4);
-	return ccw_driver_register(&dasd_eckd_driver);
+	ret = ccw_driver_register(&dasd_eckd_driver);
+	if (!ret)
+		wait_for_device_probe();
+
+	return ret;
 }
 
 static void __exit
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index 8912358..597c6ff 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -122,20 +122,20 @@
 	struct dasd_block *block;
 	struct dasd_fba_private *private;
 	struct ccw_device *cdev = device->cdev;
-	void *rdc_data;
 	int rc;
 
 	private = (struct dasd_fba_private *) device->private;
-	if (private == NULL) {
-		private = kzalloc(sizeof(struct dasd_fba_private),
-				  GFP_KERNEL | GFP_DMA);
-		if (private == NULL) {
+	if (!private) {
+		private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
+		if (!private) {
 			dev_warn(&device->cdev->dev,
 				 "Allocating memory for private DASD "
 				 "data failed\n");
 			return -ENOMEM;
 		}
 		device->private = (void *) private;
+	} else {
+		memset(private, 0, sizeof(*private));
 	}
 	block = dasd_alloc_block();
 	if (IS_ERR(block)) {
@@ -150,8 +150,8 @@
 	block->base = device;
 
 	/* Read Device Characteristics */
-	rdc_data = (void *) &(private->rdc_data);
-	rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32);
+	rc = dasd_generic_read_dev_chars(device, "FBA ", &private->rdc_data,
+					 32);
 	if (rc) {
 		DBF_EVENT(DBF_WARNING, "Read device characteristics returned "
 			  "error %d for device: %s",
@@ -604,8 +604,14 @@
 static int __init
 dasd_fba_init(void)
 {
+	int ret;
+
 	ASCEBC(dasd_fba_discipline.ebcname, 4);
-	return ccw_driver_register(&dasd_fba_driver);
+	ret = ccw_driver_register(&dasd_fba_driver);
+	if (!ret)
+		wait_for_device_probe();
+
+	return ret;
 }
 
 static void __exit
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index c1e487f..f97ceb7 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -173,6 +173,7 @@
 	void *data;			/* pointer to data area */
 
 	/* these are important for recovering erroneous requests          */
+	int intrc;			/* internal error, e.g. from start_IO */
 	struct irb irb;			/* device status in case of an error */
 	struct dasd_ccw_req *refers;	/* ERP-chain queueing. */
 	void *function; 		/* originating ERP action */
@@ -578,7 +579,7 @@
 int dasd_generic_notify(struct ccw_device *, int);
 void dasd_generic_handle_state_change(struct dasd_device *);
 
-int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int);
+int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int);
 char *dasd_get_sense(struct irb *);
 
 /* externals in dasd_devmap.c */
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index a4c7ffc..b21caf1 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -127,7 +127,7 @@
 		found = 0;
 		// test if minor available
 		list_for_each_entry(entry, &dcssblk_devices, lh)
-			if (minor == MINOR(disk_devt(entry->gd)))
+			if (minor == entry->gd->first_minor)
 				found++;
 		if (!found) break; // got unused minor
 	}
@@ -625,7 +625,7 @@
 	if (rc)
 		goto release_gd;
 	sprintf(dev_info->gd->disk_name, "dcssblk%d",
-		MINOR(disk_devt(dev_info->gd)));
+		dev_info->gd->first_minor);
 	list_add_tail(&dev_info->lh, &dcssblk_devices);
 
 	if (!try_module_get(THIS_MODULE)) {
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index d028d2e..ed5396d 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -64,7 +64,7 @@
 #define CON_UPDATE_ERASE	1	/* Use EWRITEA instead of WRITE. */
 #define CON_UPDATE_LIST		2	/* Update lines in tty3270->update. */
 #define CON_UPDATE_STATUS	4	/* Update status line. */
-#define CON_UPDATE_ALL		7
+#define CON_UPDATE_ALL		8	/* Recreate screen. */
 
 static void con3270_update(struct con3270 *);
 
@@ -73,18 +73,10 @@
  */
 static void con3270_set_timer(struct con3270 *cp, int expires)
 {
-	if (expires == 0) {
-		if (timer_pending(&cp->timer))
-			del_timer(&cp->timer);
-		return;
-	}
-	if (timer_pending(&cp->timer) &&
-	    mod_timer(&cp->timer, jiffies + expires))
-		return;
-	cp->timer.function = (void (*)(unsigned long)) con3270_update;
-	cp->timer.data = (unsigned long) cp;
-	cp->timer.expires = jiffies + expires;
-	add_timer(&cp->timer);
+	if (expires == 0)
+		del_timer(&cp->timer);
+	else
+		mod_timer(&cp->timer, jiffies + expires);
 }
 
 /*
@@ -225,6 +217,12 @@
 
 	spin_lock_irqsave(&cp->view.lock, flags);
 	updated = 0;
+	if (cp->update_flags & CON_UPDATE_ALL) {
+		con3270_rebuild_update(cp);
+		con3270_update_status(cp);
+		cp->update_flags = CON_UPDATE_ERASE | CON_UPDATE_LIST |
+			CON_UPDATE_STATUS;
+	}
 	if (cp->update_flags & CON_UPDATE_ERASE) {
 		/* Use erase write alternate to initialize display. */
 		raw3270_request_set_cmd(wrq, TC_EWRITEA);
@@ -302,7 +300,6 @@
 		deactivate = 1;
 		break;
 	case 0x6d:	/* clear: start from scratch. */
-		con3270_rebuild_update(cp);
 		cp->update_flags = CON_UPDATE_ALL;
 		con3270_set_timer(cp, 1);
 		break;
@@ -382,30 +379,21 @@
 static int
 con3270_activate(struct raw3270_view *view)
 {
-	unsigned long flags;
 	struct con3270 *cp;
 
 	cp = (struct con3270 *) view;
-	spin_lock_irqsave(&cp->view.lock, flags);
-	cp->nr_up = 0;
-	con3270_rebuild_update(cp);
-	con3270_update_status(cp);
 	cp->update_flags = CON_UPDATE_ALL;
 	con3270_set_timer(cp, 1);
-	spin_unlock_irqrestore(&cp->view.lock, flags);
 	return 0;
 }
 
 static void
 con3270_deactivate(struct raw3270_view *view)
 {
-	unsigned long flags;
 	struct con3270 *cp;
 
 	cp = (struct con3270 *) view;
-	spin_lock_irqsave(&cp->view.lock, flags);
 	del_timer(&cp->timer);
-	spin_unlock_irqrestore(&cp->view.lock, flags);
 }
 
 static int
@@ -504,6 +492,7 @@
 			con3270_cline_end(cp);
 	}
 	/* Setup timer to output current console buffer after 1/10 second */
+	cp->nr_up = 0;
 	if (cp->view.dev && !timer_pending(&cp->timer))
 		con3270_set_timer(cp, HZ/10);
 	spin_unlock_irqrestore(&cp->view.lock,flags);
@@ -624,7 +613,8 @@
 
 	INIT_LIST_HEAD(&condev->lines);
 	INIT_LIST_HEAD(&condev->update);
-	init_timer(&condev->timer);
+	setup_timer(&condev->timer, (void (*)(unsigned long)) con3270_update,
+		    (unsigned long) condev);
 	tasklet_init(&condev->readlet, 
 		     (void (*)(unsigned long)) con3270_read_tasklet,
 		     (unsigned long) condev->read);
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index a7fe630..3838567 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -112,7 +112,7 @@
 #define TTY_UPDATE_LIST		2	/* Update lines in tty3270->update. */
 #define TTY_UPDATE_INPUT	4	/* Update input line. */
 #define TTY_UPDATE_STATUS	8	/* Update status line. */
-#define TTY_UPDATE_ALL		15
+#define TTY_UPDATE_ALL		16	/* Recreate screen. */
 
 static void tty3270_update(struct tty3270 *);
 
@@ -121,19 +121,10 @@
  */
 static void tty3270_set_timer(struct tty3270 *tp, int expires)
 {
-	if (expires == 0) {
-		if (timer_pending(&tp->timer) && del_timer(&tp->timer))
-			raw3270_put_view(&tp->view);
-		return;
-	}
-	if (timer_pending(&tp->timer) &&
-	    mod_timer(&tp->timer, jiffies + expires))
-		return;
-	raw3270_get_view(&tp->view);
-	tp->timer.function = (void (*)(unsigned long)) tty3270_update;
-	tp->timer.data = (unsigned long) tp;
-	tp->timer.expires = jiffies + expires;
-	add_timer(&tp->timer);
+	if (expires == 0)
+		del_timer(&tp->timer);
+	else
+		mod_timer(&tp->timer, jiffies + expires);
 }
 
 /*
@@ -337,7 +328,6 @@
 	tp = (struct tty3270 *) rq->view;
 	if (rq->rc != 0) {
 		/* Write wasn't successfull. Refresh all. */
-		tty3270_rebuild_update(tp);
 		tp->update_flags = TTY_UPDATE_ALL;
 		tty3270_set_timer(tp, 1);
 	}
@@ -366,6 +356,12 @@
 
 	spin_lock(&tp->view.lock);
 	updated = 0;
+	if (tp->update_flags & TTY_UPDATE_ALL) {
+		tty3270_rebuild_update(tp);
+		tty3270_update_status(tp);
+		tp->update_flags = TTY_UPDATE_ERASE | TTY_UPDATE_LIST |
+			TTY_UPDATE_INPUT | TTY_UPDATE_STATUS;
+	}
 	if (tp->update_flags & TTY_UPDATE_ERASE) {
 		/* Use erase write alternate to erase display. */
 		raw3270_request_set_cmd(wrq, TC_EWRITEA);
@@ -425,7 +421,6 @@
 		xchg(&tp->write, wrq);
 	}
 	spin_unlock(&tp->view.lock);
-	raw3270_put_view(&tp->view);
 }
 
 /*
@@ -570,7 +565,6 @@
 		tty3270_set_timer(tp, 1);
 	} else if (tp->input->string[0] == 0x6d) {
 		/* Display has been cleared. Redraw. */
-		tty3270_rebuild_update(tp);
 		tp->update_flags = TTY_UPDATE_ALL;
 		tty3270_set_timer(tp, 1);
 	}
@@ -641,22 +635,20 @@
 tty3270_activate(struct raw3270_view *view)
 {
 	struct tty3270 *tp;
-	unsigned long flags;
 
 	tp = (struct tty3270 *) view;
-	spin_lock_irqsave(&tp->view.lock, flags);
-	tp->nr_up = 0;
-	tty3270_rebuild_update(tp);
-	tty3270_update_status(tp);
 	tp->update_flags = TTY_UPDATE_ALL;
 	tty3270_set_timer(tp, 1);
-	spin_unlock_irqrestore(&tp->view.lock, flags);
 	return 0;
 }
 
 static void
 tty3270_deactivate(struct raw3270_view *view)
 {
+	struct tty3270 *tp;
+
+	tp = (struct tty3270 *) view;
+	del_timer(&tp->timer);
 }
 
 static int
@@ -743,6 +735,7 @@
 {
 	int pages;
 
+	del_timer_sync(&tp->timer);
 	kbd_free(tp->kbd);
 	raw3270_request_free(tp->kreset);
 	raw3270_request_free(tp->read);
@@ -889,7 +882,8 @@
 	INIT_LIST_HEAD(&tp->update);
 	INIT_LIST_HEAD(&tp->rcl_lines);
 	tp->rcl_max = 20;
-	init_timer(&tp->timer);
+	setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
+		    (unsigned long) tp);
 	tasklet_init(&tp->readlet, 
 		     (void (*)(unsigned long)) tty3270_read_tasklet,
 		     (unsigned long) tp->read);
@@ -1754,14 +1748,6 @@
 	.set_termios = tty3270_set_termios
 };
 
-static void tty3270_notifier(int index, int active)
-{
-	if (active)
-		tty_register_device(tty3270_driver, index, NULL);
-	else
-		tty_unregister_device(tty3270_driver, index);
-}
-
 /*
  * 3270 tty registration code called from tty_init().
  * Most kernel services (incl. kmalloc) are available at this poimt.
@@ -1796,12 +1782,6 @@
 		return ret;
 	}
 	tty3270_driver = driver;
-	ret = raw3270_register_notifier(tty3270_notifier);
-	if (ret) {
-		put_tty_driver(driver);
-		return ret;
-
-	}
 	return 0;
 }
 
@@ -1810,7 +1790,6 @@
 {
 	struct tty_driver *driver;
 
-	raw3270_unregister_notifier(tty3270_notifier);
 	driver = tty3270_driver;
 	tty3270_driver = NULL;
 	tty_unregister_driver(driver);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 2aebb98..5ec7789 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -12,6 +12,7 @@
 #define KMSG_COMPONENT "cio"
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
+#include <linux/ftrace.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -28,7 +29,7 @@
 #include <asm/chpid.h>
 #include <asm/airq.h>
 #include <asm/isc.h>
-#include <asm/cpu.h>
+#include <asm/cputime.h>
 #include <asm/fcx.h>
 #include <asm/nmi.h>
 #include <asm/crw.h>
@@ -626,8 +627,7 @@
  *	    handlers).
  *
  */
-void
-do_IRQ (struct pt_regs *regs)
+void __irq_entry do_IRQ(struct pt_regs *regs)
 {
 	struct tpi_info *tpi_info;
 	struct subchannel *sch;
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 151754d..bf0a24a 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -114,7 +114,7 @@
 	struct subchannel *sch;
 	int ret;
 
-	if (!cdev)
+	if (!cdev || !cdev->dev.parent)
 		return -ENODEV;
 	if (cdev->private->state == DEV_STATE_NOT_OPER)
 		return -ENODEV;
@@ -122,8 +122,6 @@
 	    cdev->private->state != DEV_STATE_W4SENSE)
 		return -EINVAL;
 	sch = to_subchannel(cdev->dev.parent);
-	if (!sch)
-		return -ENODEV;
 	ret = cio_clear(sch);
 	if (ret == 0)
 		cdev->private->intparm = intparm;
@@ -161,11 +159,9 @@
 	struct subchannel *sch;
 	int ret;
 
-	if (!cdev)
+	if (!cdev || !cdev->dev.parent)
 		return -ENODEV;
 	sch = to_subchannel(cdev->dev.parent);
-	if (!sch)
-		return -ENODEV;
 	if (cdev->private->state == DEV_STATE_NOT_OPER)
 		return -ENODEV;
 	if (cdev->private->state == DEV_STATE_VERIFY ||
@@ -339,7 +335,7 @@
 	struct subchannel *sch;
 	int ret;
 
-	if (!cdev)
+	if (!cdev || !cdev->dev.parent)
 		return -ENODEV;
 	if (cdev->private->state == DEV_STATE_NOT_OPER)
 		return -ENODEV;
@@ -347,8 +343,6 @@
 	    cdev->private->state != DEV_STATE_W4SENSE)
 		return -EINVAL;
 	sch = to_subchannel(cdev->dev.parent);
-	if (!sch)
-		return -ENODEV;
 	ret = cio_halt(sch);
 	if (ret == 0)
 		cdev->private->intparm = intparm;
@@ -372,11 +366,9 @@
 {
 	struct subchannel *sch;
 
-	if (!cdev)
+	if (!cdev || !cdev->dev.parent)
 		return -ENODEV;
 	sch = to_subchannel(cdev->dev.parent);
-	if (!sch)
-		return -ENODEV;
 	if (cdev->private->state == DEV_STATE_NOT_OPER)
 		return -ENODEV;
 	if (cdev->private->state != DEV_STATE_ONLINE ||
@@ -471,11 +463,11 @@
 {
 	struct subchannel *sch;
 
-	sch = to_subchannel(cdev->dev.parent);
-	if (!sch)
+	if (!cdev->dev.parent)
 		return 0;
-	else
-		return sch->lpm;
+
+	sch = to_subchannel(cdev->dev.parent);
+	return sch->lpm;
 }
 
 /*
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index accd957..d79cf5b 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -881,42 +881,26 @@
 	qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED);
 }
 
-static int qdio_establish_check_errors(struct ccw_device *cdev, int cstat,
-				       int dstat)
-{
-	struct qdio_irq *irq_ptr = cdev->private->qdio_data;
-
-	if (cstat || (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END))) {
-		DBF_ERROR("EQ:ck con");
-		goto error;
-	}
-
-	if (!(dstat & DEV_STAT_DEV_END)) {
-		DBF_ERROR("EQ:no dev");
-		goto error;
-	}
-
-	if (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) {
-		DBF_ERROR("EQ: bad io");
-		goto error;
-	}
-	return 0;
-error:
-	DBF_ERROR("%4x EQ:error", irq_ptr->schid.sch_no);
-	DBF_ERROR("ds: %2x cs:%2x", dstat, cstat);
-
-	qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR);
-	return 1;
-}
-
 static void qdio_establish_handle_irq(struct ccw_device *cdev, int cstat,
 				      int dstat)
 {
 	struct qdio_irq *irq_ptr = cdev->private->qdio_data;
 
 	DBF_DEV_EVENT(DBF_INFO, irq_ptr, "qest irq");
-	if (!qdio_establish_check_errors(cdev, cstat, dstat))
-		qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ESTABLISHED);
+
+	if (cstat)
+		goto error;
+	if (dstat & ~(DEV_STAT_DEV_END | DEV_STAT_CHN_END))
+		goto error;
+	if (!(dstat & DEV_STAT_DEV_END))
+		goto error;
+	qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ESTABLISHED);
+	return;
+
+error:
+	DBF_ERROR("%4x EQ:error", irq_ptr->schid.sch_no);
+	DBF_ERROR("ds: %2x cs:%2x", dstat, cstat);
+	qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR);
 }
 
 /* qdio interrupt handler */
@@ -946,7 +930,6 @@
 		}
 	}
 	qdio_irq_check_sense(irq_ptr, irb);
-
 	cstat = irb->scsw.cmd.cstat;
 	dstat = irb->scsw.cmd.dstat;
 
@@ -954,22 +937,19 @@
 	case QDIO_IRQ_STATE_INACTIVE:
 		qdio_establish_handle_irq(cdev, cstat, dstat);
 		break;
-
 	case QDIO_IRQ_STATE_CLEANUP:
 		qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE);
 		break;
-
 	case QDIO_IRQ_STATE_ESTABLISHED:
 	case QDIO_IRQ_STATE_ACTIVE:
 		if (cstat & SCHN_STAT_PCI) {
 			qdio_int_handler_pci(irq_ptr);
 			return;
 		}
-		if ((cstat & ~SCHN_STAT_PCI) || dstat) {
+		if (cstat || dstat)
 			qdio_handle_activate_check(cdev, intparm, cstat,
 						   dstat);
-			break;
-		}
+		break;
 	default:
 		WARN_ON(1);
 	}
@@ -1514,7 +1494,7 @@
 
 	if ((bufnr > QDIO_MAX_BUFFERS_PER_Q) ||
 	    (count > QDIO_MAX_BUFFERS_PER_Q) ||
-	    (q_nr > QDIO_MAX_QUEUES_PER_IRQ))
+	    (q_nr >= QDIO_MAX_QUEUES_PER_IRQ))
 		return -EINVAL;
 
 	if (!count)
diff --git a/drivers/s390/cio/qdio_perf.c b/drivers/s390/cio/qdio_perf.c
index 136d0f0..eff9439 100644
--- a/drivers/s390/cio/qdio_perf.c
+++ b/drivers/s390/cio/qdio_perf.c
@@ -25,18 +25,6 @@
 static struct proc_dir_entry *qdio_perf_pde;
 #endif
 
-inline void qdio_perf_stat_inc(atomic_long_t *count)
-{
-	if (qdio_performance_stats)
-		atomic_long_inc(count);
-}
-
-inline void qdio_perf_stat_dec(atomic_long_t *count)
-{
-	if (qdio_performance_stats)
-		atomic_long_dec(count);
-}
-
 /*
  * procfs functions
  */
diff --git a/drivers/s390/cio/qdio_perf.h b/drivers/s390/cio/qdio_perf.h
index 7821ac4..ff4504c 100644
--- a/drivers/s390/cio/qdio_perf.h
+++ b/drivers/s390/cio/qdio_perf.h
@@ -9,7 +9,6 @@
 #define QDIO_PERF_H
 
 #include <linux/types.h>
-#include <linux/device.h>
 #include <asm/atomic.h>
 
 struct qdio_perf_stats {
@@ -50,10 +49,13 @@
 extern struct qdio_perf_stats perf_stats;
 extern int qdio_performance_stats;
 
+static inline void qdio_perf_stat_inc(atomic_long_t *count)
+{
+	if (qdio_performance_stats)
+		atomic_long_inc(count);
+}
+
 int qdio_setup_perf_stats(void);
 void qdio_remove_perf_stats(void);
 
-extern void qdio_perf_stat_inc(atomic_long_t *count);
-extern void qdio_perf_stat_dec(atomic_long_t *count);
-
 #endif
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index cbc8566..e38e5d3 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -173,8 +173,9 @@
  * this device and sets it up.
  */
 static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
-				    unsigned index,
-				    void (*callback)(struct virtqueue *vq))
+				     unsigned index,
+				     void (*callback)(struct virtqueue *vq),
+				     const char *name)
 {
 	struct kvm_device *kdev = to_kvmdev(vdev);
 	struct kvm_vqconfig *config;
@@ -194,7 +195,7 @@
 
 	vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN,
 				 vdev, (void *) config->address,
-				 kvm_notify, callback);
+				 kvm_notify, callback, name);
 	if (!vq) {
 		err = -ENOMEM;
 		goto unmap;
@@ -226,6 +227,38 @@
 				       KVM_S390_VIRTIO_RING_ALIGN));
 }
 
+static void kvm_del_vqs(struct virtio_device *vdev)
+{
+	struct virtqueue *vq, *n;
+
+	list_for_each_entry_safe(vq, n, &vdev->vqs, list)
+		kvm_del_vq(vq);
+}
+
+static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+			struct virtqueue *vqs[],
+			vq_callback_t *callbacks[],
+			const char *names[])
+{
+	struct kvm_device *kdev = to_kvmdev(vdev);
+	int i;
+
+	/* We must have this many virtqueues. */
+	if (nvqs > kdev->desc->num_vq)
+		return -ENOENT;
+
+	for (i = 0; i < nvqs; ++i) {
+		vqs[i] = kvm_find_vq(vdev, i, callbacks[i], names[i]);
+		if (IS_ERR(vqs[i]))
+			goto error;
+	}
+	return 0;
+
+error:
+	kvm_del_vqs(vdev);
+	return PTR_ERR(vqs[i]);
+}
+
 /*
  * The config ops structure as defined by virtio config
  */
@@ -237,8 +270,8 @@
 	.get_status = kvm_get_status,
 	.set_status = kvm_set_status,
 	.reset = kvm_reset,
-	.find_vq = kvm_find_vq,
-	.del_vq = kvm_del_vq,
+	.find_vqs = kvm_find_vqs,
+	.del_vqs = kvm_del_vqs,
 };
 
 /*
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index 733fe3b..b2fe5cd 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -11,6 +11,24 @@
 
 #include "zfcp_ext.h"
 
+#define ZFCP_MODEL_PRIV 0x4
+
+static struct ccw_device_id zfcp_ccw_device_id[] = {
+	{ CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) },
+	{ CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, ZFCP_MODEL_PRIV) },
+	{},
+};
+MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
+
+/**
+ * zfcp_ccw_priv_sch - check if subchannel is privileged
+ * @adapter: Adapter/Subchannel to check
+ */
+int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter)
+{
+	return adapter->ccw_device->id.dev_model == ZFCP_MODEL_PRIV;
+}
+
 /**
  * zfcp_ccw_probe - probe function of zfcp driver
  * @ccw_device: pointer to belonging ccw device
@@ -176,8 +194,8 @@
 					"ccnoti4", NULL);
 		break;
 	case CIO_BOXED:
-		dev_warn(&adapter->ccw_device->dev,
-			 "The ccw device did not respond in time.\n");
+		dev_warn(&adapter->ccw_device->dev, "The FCP device "
+			 "did not respond within the specified time\n");
 		zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL);
 		break;
 	}
@@ -199,14 +217,6 @@
 	up(&zfcp_data.config_sema);
 }
 
-static struct ccw_device_id zfcp_ccw_device_id[] = {
-	{ CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) },
-	{ CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x4) }, /* priv. */
-	{},
-};
-
-MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
-
 static struct ccw_driver zfcp_ccw_driver = {
 	.owner       = THIS_MODULE,
 	.name        = "zfcp",
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 0a1a5dd..b99b87c 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -163,7 +163,7 @@
 	}
 
 	response->fsf_command = fsf_req->fsf_command;
-	response->fsf_reqid = (unsigned long)fsf_req;
+	response->fsf_reqid = fsf_req->req_id;
 	response->fsf_seqno = fsf_req->seq_no;
 	response->fsf_issued = fsf_req->issued;
 	response->fsf_prot_status = qtcb->prefix.prot_status;
@@ -737,7 +737,7 @@
 	spin_lock_irqsave(&adapter->san_dbf_lock, flags);
 	memset(r, 0, sizeof(*r));
 	strncpy(r->tag, "octc", ZFCP_DBF_TAG_SIZE);
-	r->fsf_reqid = (unsigned long)fsf_req;
+	r->fsf_reqid = fsf_req->req_id;
 	r->fsf_seqno = fsf_req->seq_no;
 	r->s_id = fc_host_port_id(adapter->scsi_host);
 	r->d_id = wka_port->d_id;
@@ -773,7 +773,7 @@
 	spin_lock_irqsave(&adapter->san_dbf_lock, flags);
 	memset(r, 0, sizeof(*r));
 	strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE);
-	r->fsf_reqid = (unsigned long)fsf_req;
+	r->fsf_reqid = fsf_req->req_id;
 	r->fsf_seqno = fsf_req->seq_no;
 	r->s_id = wka_port->d_id;
 	r->d_id = fc_host_port_id(adapter->scsi_host);
@@ -803,7 +803,7 @@
 	spin_lock_irqsave(&adapter->san_dbf_lock, flags);
 	memset(rec, 0, sizeof(*rec));
 	strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE);
-	rec->fsf_reqid = (unsigned long)fsf_req;
+	rec->fsf_reqid = fsf_req->req_id;
 	rec->fsf_seqno = fsf_req->seq_no;
 	rec->s_id = s_id;
 	rec->d_id = d_id;
@@ -965,7 +965,7 @@
 						      ZFCP_DBF_SCSI_FCP_SNS_INFO);
 				}
 
-				rec->fsf_reqid = (unsigned long)fsf_req;
+				rec->fsf_reqid = fsf_req->req_id;
 				rec->fsf_seqno = fsf_req->seq_no;
 				rec->fsf_issued = fsf_req->issued;
 			}
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 4c362a9..2074d45 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -47,13 +47,6 @@
 
 /********************* CIO/QDIO SPECIFIC DEFINES *****************************/
 
-/* Adapter Identification Parameters */
-#define ZFCP_CONTROL_UNIT_TYPE  0x1731
-#define ZFCP_CONTROL_UNIT_MODEL 0x03
-#define ZFCP_DEVICE_TYPE        0x1732
-#define ZFCP_DEVICE_MODEL       0x03
-#define ZFCP_DEVICE_MODEL_PRIV	0x04
-
 /* DMQ bug workaround: don't use last SBALE */
 #define ZFCP_MAX_SBALES_PER_SBAL	(QDIO_MAX_ELEMENTS_PER_BUFFER - 1)
 
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index fdc9b43..e50ea46 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -880,6 +880,7 @@
 				zfcp_port_put(port);
 			return ZFCP_ERP_CONTINUES;
 		}
+		/* fall through */
 	case ZFCP_ERP_STEP_NAMESERVER_LOOKUP:
 		if (!port->d_id)
 			return ZFCP_ERP_FAILED;
@@ -894,8 +895,13 @@
 				act->step = ZFCP_ERP_STEP_PORT_CLOSING;
 				return ZFCP_ERP_CONTINUES;
 			}
-		/* fall through otherwise */
 		}
+		if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
+			port->d_id = 0;
+			_zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL);
+			return ZFCP_ERP_EXIT;
+		}
+		/* fall through otherwise */
 	}
 	return ZFCP_ERP_FAILED;
 }
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 2e31b53..120a9a1 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -27,6 +27,7 @@
 
 /* zfcp_ccw.c */
 extern int zfcp_ccw_register(void);
+extern int zfcp_ccw_priv_sch(struct zfcp_adapter *);
 extern struct zfcp_adapter *zfcp_get_adapter_by_busid(char *);
 
 /* zfcp_cfdc.c */
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 18fd975..35493a8 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -150,9 +150,14 @@
 	struct zfcp_port *port;
 
 	read_lock_irqsave(&zfcp_data.config_lock, flags);
-	list_for_each_entry(port, &fsf_req->adapter->port_list_head, list)
+	list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) {
 		if ((port->d_id & range) == (elem->nport_did & range))
 			zfcp_test_link(port);
+		if (!port->d_id)
+			zfcp_erp_port_reopen(port,
+					     ZFCP_STATUS_COMMON_ERP_FAILED,
+					     "fcrscn1", NULL);
+	}
 
 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 }
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 74dee32..e6dae37 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -526,6 +526,7 @@
 		break;
 	case FSF_TOPO_AL:
 		fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
+		/* fall through */
 	default:
 		dev_err(&adapter->ccw_device->dev,
 			"Unknown or unsupported arbitrated loop "
@@ -897,6 +898,7 @@
 		switch (fsq->word[0]) {
 		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
 			zfcp_test_link(unit->port);
+			/* fall through */
 		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
 			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 			break;
@@ -993,6 +995,7 @@
 		break;
 	case FSF_PORT_HANDLE_NOT_VALID:
 		zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req);
+		/* fall through */
 	case FSF_GENERIC_COMMAND_REJECTED:
 	case FSF_PAYLOAD_SIZE_MISMATCH:
 	case FSF_REQUEST_SIZE_TOO_LARGE:
@@ -1399,7 +1402,7 @@
 	struct fsf_plogi *plogi;
 
 	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
-		return;
+		goto out;
 
 	switch (header->fsf_status) {
 	case FSF_PORT_ALREADY_OPEN:
@@ -1461,6 +1464,9 @@
 		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
 	}
+
+out:
+	zfcp_port_put(port);
 }
 
 /**
@@ -1473,6 +1479,7 @@
 	struct qdio_buffer_element *sbale;
 	struct zfcp_adapter *adapter = erp_action->adapter;
 	struct zfcp_fsf_req *req;
+	struct zfcp_port *port = erp_action->port;
 	int retval = -EIO;
 
 	spin_lock_bh(&adapter->req_q_lock);
@@ -1493,16 +1500,18 @@
         sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
 
 	req->handler = zfcp_fsf_open_port_handler;
-	req->qtcb->bottom.support.d_id = erp_action->port->d_id;
-	req->data = erp_action->port;
+	req->qtcb->bottom.support.d_id = port->d_id;
+	req->data = port;
 	req->erp_action = erp_action;
 	erp_action->fsf_req = req;
+	zfcp_port_get(port);
 
 	zfcp_fsf_start_erp_timer(req);
 	retval = zfcp_fsf_req_send(req);
 	if (retval) {
 		zfcp_fsf_req_free(req);
 		erp_action->fsf_req = NULL;
+		zfcp_port_put(port);
 	}
 out:
 	spin_unlock_bh(&adapter->req_q_lock);
@@ -1590,8 +1599,10 @@
 	case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
 		dev_warn(&req->adapter->ccw_device->dev,
 			 "Opening WKA port 0x%x failed\n", wka_port->d_id);
+		/* fall through */
 	case FSF_ADAPTER_STATUS_AVAILABLE:
 		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+		/* fall through */
 	case FSF_ACCESS_DENIED:
 		wka_port->status = ZFCP_WKA_PORT_OFFLINE;
 		break;
@@ -1876,7 +1887,7 @@
 
 		if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) &&
 		    (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) &&
-		    (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) {
+		    !zfcp_ccw_priv_sch(adapter)) {
 			exclusive = (bottom->lun_access_info &
 					FSF_UNIT_ACCESS_EXCLUSIVE);
 			readwrite = (bottom->lun_access_info &
@@ -2314,7 +2325,7 @@
 {
 	struct zfcp_fsf_req *req;
 	struct fcp_cmnd_iu *fcp_cmnd_iu;
-	unsigned int sbtype;
+	unsigned int sbtype = SBAL_FLAGS0_TYPE_READ;
 	int real_bytes, retval = -EIO;
 	struct zfcp_adapter *adapter = unit->port->adapter;
 
@@ -2356,11 +2367,9 @@
 	switch (scsi_cmnd->sc_data_direction) {
 	case DMA_NONE:
 		req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
-		sbtype = SBAL_FLAGS0_TYPE_READ;
 		break;
 	case DMA_FROM_DEVICE:
 		req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
-		sbtype = SBAL_FLAGS0_TYPE_READ;
 		fcp_cmnd_iu->rddata = 1;
 		break;
 	case DMA_TO_DEVICE:
@@ -2369,8 +2378,6 @@
 		fcp_cmnd_iu->wddata = 1;
 		break;
 	case DMA_BIDIRECTIONAL:
-	default:
-		retval = -EIO;
 		goto failed_scsi_cmnd;
 	}
 
@@ -2394,9 +2401,7 @@
 					     scsi_sglist(scsi_cmnd),
 					     FSF_MAX_SBALS_PER_REQ);
 	if (unlikely(real_bytes < 0)) {
-		if (req->sbal_number < FSF_MAX_SBALS_PER_REQ)
-			retval = -EIO;
-		else {
+		if (req->sbal_number >= FSF_MAX_SBALS_PER_REQ) {
 			dev_err(&adapter->ccw_device->dev,
 				"Oversize data package, unit 0x%016Lx "
 				"on port 0x%016Lx closed\n",
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index e8fbeae..7d0da23 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -12,6 +12,10 @@
 #include "zfcp_ext.h"
 #include <asm/atomic.h>
 
+static unsigned int default_depth = 32;
+module_param_named(queue_depth, default_depth, uint, 0600);
+MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices");
+
 /* Find start of Sense Information in FCP response unit*/
 char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu)
 {
@@ -24,6 +28,12 @@
 	return fcp_sns_info_ptr;
 }
 
+static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth)
+{
+	scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
+	return sdev->queue_depth;
+}
+
 static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
 {
 	struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
@@ -34,7 +44,7 @@
 static int zfcp_scsi_slave_configure(struct scsi_device *sdp)
 {
 	if (sdp->tagged_supported)
-		scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, 32);
+		scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, default_depth);
 	else
 		scsi_adjust_queue_depth(sdp, 0, 1);
 	return 0;
@@ -647,6 +657,7 @@
 		.name			 = "zfcp",
 		.module			 = THIS_MODULE,
 		.proc_name		 = "zfcp",
+		.change_queue_depth	 = zfcp_scsi_change_queue_depth,
 		.slave_alloc		 = zfcp_scsi_slave_alloc,
 		.slave_configure	 = zfcp_scsi_slave_configure,
 		.slave_destroy		 = zfcp_scsi_slave_destroy,
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index fb27407..6a19ed9 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -191,20 +191,19 @@
 	  it has an enclosure device.  Selecting this option will just allow
 	  certain enclosure conditions to be reported and is not required.
 
-comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs"
-	depends on SCSI
-
 config SCSI_MULTI_LUN
 	bool "Probe all LUNs on each SCSI device"
 	depends on SCSI
 	help
-	  If you have a SCSI device that supports more than one LUN (Logical
-	  Unit Number), e.g. a CD jukebox, and only one LUN is detected, you
-	  can say Y here to force the SCSI driver to probe for multiple LUNs.
-	  A SCSI device with multiple LUNs acts logically like multiple SCSI
-	  devices. The vast majority of SCSI devices have only one LUN, and
-	  so most people can say N here. The max_luns boot/module parameter 
-	  allows to override this setting.
+	  Some devices support more than one LUN (Logical Unit Number) in order
+	  to allow access to several media, e.g. CD jukebox, USB card reader,
+	  mobile phone in mass storage mode. This option forces the kernel to
+	  probe for all LUNs by default. This setting can be overriden by
+	  max_luns boot/module parameter. Note that this option does not affect
+	  devices conforming to SCSI-3 or higher as they can explicitely report
+	  their number of LUNs. It is safe to say Y here unless you have one of
+	  those rare devices which reacts in an unexpected way when probed for
+	  multiple LUNs.
 
 config SCSI_CONSTANTS
 	bool "Verbose SCSI error reporting (kernel size +=12K)"
@@ -355,6 +354,7 @@
 	 http://open-iscsi.org
 
 source "drivers/scsi/cxgb3i/Kconfig"
+source "drivers/scsi/bnx2i/Kconfig"
 
 config SGIWD93_SCSI
 	tristate "SGI WD93C93 SCSI Driver"
@@ -508,6 +508,7 @@
 
 source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
 source "drivers/scsi/aic94xx/Kconfig"
+source "drivers/scsi/mvsas/Kconfig"
 
 config SCSI_DPT_I2O
 	tristate "Adaptec I2O RAID support "
@@ -1050,16 +1051,6 @@
 
 	  Generally, saying N is fine.
 
-config SCSI_MVSAS
-	tristate "Marvell 88SE6440 SAS/SATA support"
-	depends on PCI && SCSI
-	select SCSI_SAS_LIBSAS
-	help
-	  This driver supports Marvell SAS/SATA PCI devices.
-
-	  To compiler this driver as a module, choose M here: the module
-	  will be called mvsas.
-
 config SCSI_NCR53C406A
 	tristate "NCR53c406a SCSI support"
 	depends on ISA && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index a5049cf..25429ea 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -126,9 +126,10 @@
 obj-$(CONFIG_SCSI_IBMVFC)	+= ibmvscsi/
 obj-$(CONFIG_SCSI_HPTIOP)	+= hptiop.o
 obj-$(CONFIG_SCSI_STEX)		+= stex.o
-obj-$(CONFIG_SCSI_MVSAS)	+= mvsas.o
+obj-$(CONFIG_SCSI_MVSAS)	+= mvsas/
 obj-$(CONFIG_PS3_ROM)		+= ps3rom.o
 obj-$(CONFIG_SCSI_CXGB3_ISCSI)	+= libiscsi.o libiscsi_tcp.o cxgb3i/
+obj-$(CONFIG_SCSI_BNX2_ISCSI)	+= libiscsi.o bnx2i/
 
 obj-$(CONFIG_ARM)		+= arm/
 
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
index c889d84..1cdf09a 100644
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -224,7 +224,7 @@
 	return ret;
 }
 
-static int
+static irqreturn_t
 NCR_D700_intr(int irq, void *data)
 {
 	struct NCR_D700_private *p = (struct NCR_D700_private *)data;
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
new file mode 100644
index 0000000..2fceb19
--- /dev/null
+++ b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
@@ -0,0 +1,155 @@
+/* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI
+ *
+ * Copyright (c) 2006 - 2009 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ */
+#ifndef __57XX_ISCSI_CONSTANTS_H_
+#define __57XX_ISCSI_CONSTANTS_H_
+
+/**
+* This file defines HSI constants for the iSCSI flows
+*/
+
+/* iSCSI request op codes */
+#define ISCSI_OPCODE_CLEANUP_REQUEST    (7)
+
+/* iSCSI response/messages op codes */
+#define ISCSI_OPCODE_CLEANUP_RESPONSE 		(0x27)
+#define ISCSI_OPCODE_NOPOUT_LOCAL_COMPLETION    (0)
+
+/* iSCSI task types */
+#define ISCSI_TASK_TYPE_READ    (0)
+#define ISCSI_TASK_TYPE_WRITE   (1)
+#define ISCSI_TASK_TYPE_MPATH   (2)
+
+/* initial CQ sequence numbers */
+#define ISCSI_INITIAL_SN    (1)
+
+/* KWQ (kernel work queue) layer codes */
+#define ISCSI_KWQE_LAYER_CODE   (6)
+
+/* KWQ (kernel work queue) request op codes */
+#define ISCSI_KWQE_OPCODE_OFFLOAD_CONN1 (0)
+#define ISCSI_KWQE_OPCODE_OFFLOAD_CONN2 (1)
+#define ISCSI_KWQE_OPCODE_UPDATE_CONN   (2)
+#define ISCSI_KWQE_OPCODE_DESTROY_CONN  (3)
+#define ISCSI_KWQE_OPCODE_INIT1         (4)
+#define ISCSI_KWQE_OPCODE_INIT2         (5)
+
+/* KCQ (kernel completion queue) response op codes */
+#define ISCSI_KCQE_OPCODE_OFFLOAD_CONN  (0x10)
+#define ISCSI_KCQE_OPCODE_UPDATE_CONN   (0x12)
+#define ISCSI_KCQE_OPCODE_DESTROY_CONN  (0x13)
+#define ISCSI_KCQE_OPCODE_INIT          (0x14)
+#define ISCSI_KCQE_OPCODE_FW_CLEAN_TASK	(0x15)
+#define ISCSI_KCQE_OPCODE_TCP_RESET     (0x16)
+#define ISCSI_KCQE_OPCODE_TCP_SYN       (0x17)
+#define ISCSI_KCQE_OPCODE_TCP_FIN       (0X18)
+#define ISCSI_KCQE_OPCODE_TCP_ERROR     (0x19)
+#define ISCSI_KCQE_OPCODE_CQ_EVENT_NOTIFICATION (0x20)
+#define ISCSI_KCQE_OPCODE_ISCSI_ERROR   (0x21)
+
+/* KCQ (kernel completion queue) completion status */
+#define ISCSI_KCQE_COMPLETION_STATUS_SUCCESS                            (0x0)
+#define ISCSI_KCQE_COMPLETION_STATUS_INVALID_OPCODE                     (0x1)
+#define ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE                  (0x2)
+#define ISCSI_KCQE_COMPLETION_STATUS_CTX_FREE_FAILURE                   (0x3)
+#define ISCSI_KCQE_COMPLETION_STATUS_NIC_ERROR                          (0x4)
+
+#define ISCSI_KCQE_COMPLETION_STATUS_HDR_DIG_ERR                        (0x5)
+#define ISCSI_KCQE_COMPLETION_STATUS_DATA_DIG_ERR                       (0x6)
+
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_UNEXPECTED_OPCODE     (0xa)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_OPCODE                (0xb)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_AHS_LEN               (0xc)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ITT                   (0xd)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_STATSN                (0xe)
+
+/* Response */
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN            (0xf)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T              (0x10)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_IS_ZERO  (0x2c)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_TOO_BIG  (0x2d)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_0                 (0x11)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_1                 (0x12)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_2                 (0x13)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_3                 (0x14)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_4                 (0x15)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_5                 (0x16)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_6                 (0x17)
+
+/* Data-In */
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_RCV_LEN        (0x18)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_RCV_PDU_LEN       (0x19)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_F_BIT_ZERO            (0x1a)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV          (0x1b)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATASN                (0x1c)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_BURST_LEN      (0x1d)
+
+/* R2T */
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_BUFFER_OFF            (0x1f)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN                   (0x20)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_R2TSN                 (0x21)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0 (0x22)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1 (0x23)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_EXCEED       (0x24)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_IS_RSRV           (0x25)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_BURST_LEN         (0x26)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_NOT_ZERO (0x27)
+
+/* TMF */
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REJECT_PDU_LEN        (0x28)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ASYNC_PDU_LEN         (0x29)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_NOPIN_PDU_LEN         (0x2a)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_IN_CLEANUP   (0x2b)
+
+/* IP/TCP processing errors: */
+#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_FRAGMENT               (0x40)
+#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_OPTIONS                (0x41)
+#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_URGENT_FLAG               (0x42)
+#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_MAX_RTRANS                (0x43)
+
+/* iSCSI licensing errors */
+/* general iSCSI license not installed */
+#define ISCSI_KCQE_COMPLETION_STATUS_ISCSI_NOT_SUPPORTED                (0x50)
+/* additional LOM specific iSCSI license not installed */
+#define ISCSI_KCQE_COMPLETION_STATUS_LOM_ISCSI_NOT_ENABLED              (0x51)
+
+/* SQ/RQ/CQ DB structure sizes */
+#define ISCSI_SQ_DB_SIZE    (16)
+#define ISCSI_RQ_DB_SIZE    (16)
+#define ISCSI_CQ_DB_SIZE    (80)
+
+#define ISCSI_SQN_TO_NOTIFY_NOT_VALID                                   0xFFFF
+
+/* Page size codes (for flags field in connection offload request) */
+#define ISCSI_PAGE_SIZE_256     (0)
+#define ISCSI_PAGE_SIZE_512     (1)
+#define ISCSI_PAGE_SIZE_1K      (2)
+#define ISCSI_PAGE_SIZE_2K      (3)
+#define ISCSI_PAGE_SIZE_4K      (4)
+#define ISCSI_PAGE_SIZE_8K      (5)
+#define ISCSI_PAGE_SIZE_16K     (6)
+#define ISCSI_PAGE_SIZE_32K     (7)
+#define ISCSI_PAGE_SIZE_64K     (8)
+#define ISCSI_PAGE_SIZE_128K    (9)
+#define ISCSI_PAGE_SIZE_256K    (10)
+#define ISCSI_PAGE_SIZE_512K    (11)
+#define ISCSI_PAGE_SIZE_1M      (12)
+#define ISCSI_PAGE_SIZE_2M      (13)
+#define ISCSI_PAGE_SIZE_4M      (14)
+#define ISCSI_PAGE_SIZE_8M      (15)
+
+/* Iscsi PDU related defines */
+#define ISCSI_HEADER_SIZE   (48)
+#define ISCSI_DIGEST_SHIFT  (2)
+#define ISCSI_DIGEST_SIZE   (4)
+
+#define B577XX_ISCSI_CONNECTION_TYPE    3
+
+#endif /*__57XX_ISCSI_CONSTANTS_H_ */
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
new file mode 100644
index 0000000..36af1af
--- /dev/null
+++ b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
@@ -0,0 +1,1509 @@
+/* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI.
+ *
+ * Copyright (c) 2006 - 2009 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ */
+#ifndef __57XX_ISCSI_HSI_LINUX_LE__
+#define __57XX_ISCSI_HSI_LINUX_LE__
+
+/*
+ * iSCSI Async CQE
+ */
+struct bnx2i_async_msg {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 reserved1;
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	u8 reserved1;
+	u8 op_code;
+#endif
+	u32 reserved2;
+	u32 exp_cmd_sn;
+	u32 max_cmd_sn;
+	u32 reserved3[2];
+#if defined(__BIG_ENDIAN)
+	u16 reserved5;
+	u8 err_code;
+	u8 reserved4;
+#elif defined(__LITTLE_ENDIAN)
+	u8 reserved4;
+	u8 err_code;
+	u16 reserved5;
+#endif
+	u32 reserved6;
+	u32 lun[2];
+#if defined(__BIG_ENDIAN)
+	u8 async_event;
+	u8 async_vcode;
+	u16 param1;
+#elif defined(__LITTLE_ENDIAN)
+	u16 param1;
+	u8 async_vcode;
+	u8 async_event;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 param2;
+	u16 param3;
+#elif defined(__LITTLE_ENDIAN)
+	u16 param3;
+	u16 param2;
+#endif
+	u32 reserved7[3];
+	u32 cq_req_sn;
+};
+
+
+/*
+ * iSCSI Buffer Descriptor (BD)
+ */
+struct iscsi_bd {
+	u32 buffer_addr_hi;
+	u32 buffer_addr_lo;
+#if defined(__BIG_ENDIAN)
+	u16 reserved0;
+	u16 buffer_length;
+#elif defined(__LITTLE_ENDIAN)
+	u16 buffer_length;
+	u16 reserved0;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 reserved3;
+	u16 flags;
+#define ISCSI_BD_RESERVED1 (0x3F<<0)
+#define ISCSI_BD_RESERVED1_SHIFT 0
+#define ISCSI_BD_LAST_IN_BD_CHAIN (0x1<<6)
+#define ISCSI_BD_LAST_IN_BD_CHAIN_SHIFT 6
+#define ISCSI_BD_FIRST_IN_BD_CHAIN (0x1<<7)
+#define ISCSI_BD_FIRST_IN_BD_CHAIN_SHIFT 7
+#define ISCSI_BD_RESERVED2 (0xFF<<8)
+#define ISCSI_BD_RESERVED2_SHIFT 8
+#elif defined(__LITTLE_ENDIAN)
+	u16 flags;
+#define ISCSI_BD_RESERVED1 (0x3F<<0)
+#define ISCSI_BD_RESERVED1_SHIFT 0
+#define ISCSI_BD_LAST_IN_BD_CHAIN (0x1<<6)
+#define ISCSI_BD_LAST_IN_BD_CHAIN_SHIFT 6
+#define ISCSI_BD_FIRST_IN_BD_CHAIN (0x1<<7)
+#define ISCSI_BD_FIRST_IN_BD_CHAIN_SHIFT 7
+#define ISCSI_BD_RESERVED2 (0xFF<<8)
+#define ISCSI_BD_RESERVED2_SHIFT 8
+	u16 reserved3;
+#endif
+};
+
+
+/*
+ * iSCSI Cleanup SQ WQE
+ */
+struct bnx2i_cleanup_request {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 reserved1;
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	u8 reserved1;
+	u8 op_code;
+#endif
+	u32 reserved2[3];
+#if defined(__BIG_ENDIAN)
+	u16 reserved3;
+	u16 itt;
+#define ISCSI_CLEANUP_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_CLEANUP_REQUEST_INDEX_SHIFT 0
+#define ISCSI_CLEANUP_REQUEST_TYPE (0x3<<14)
+#define ISCSI_CLEANUP_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_CLEANUP_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_CLEANUP_REQUEST_INDEX_SHIFT 0
+#define ISCSI_CLEANUP_REQUEST_TYPE (0x3<<14)
+#define ISCSI_CLEANUP_REQUEST_TYPE_SHIFT 14
+	u16 reserved3;
+#endif
+	u32 reserved4[10];
+#if defined(__BIG_ENDIAN)
+	u8 cq_index;
+	u8 reserved6;
+	u16 reserved5;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved5;
+	u8 reserved6;
+	u8 cq_index;
+#endif
+};
+
+
+/*
+ * iSCSI Cleanup CQE
+ */
+struct bnx2i_cleanup_response {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 status;
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	u8 status;
+	u8 op_code;
+#endif
+	u32 reserved1[3];
+	u32 reserved2[2];
+#if defined(__BIG_ENDIAN)
+	u16 reserved4;
+	u8 err_code;
+	u8 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+	u8 reserved3;
+	u8 err_code;
+	u16 reserved4;
+#endif
+	u32 reserved5[7];
+#if defined(__BIG_ENDIAN)
+	u16 reserved6;
+	u16 itt;
+#define ISCSI_CLEANUP_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_CLEANUP_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_CLEANUP_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_CLEANUP_RESPONSE_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_CLEANUP_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_CLEANUP_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_CLEANUP_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_CLEANUP_RESPONSE_TYPE_SHIFT 14
+	u16 reserved6;
+#endif
+	u32 cq_req_sn;
+};
+
+
+/*
+ * SCSI read/write SQ WQE
+ */
+struct bnx2i_cmd_request {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 op_attr;
+#define ISCSI_CMD_REQUEST_TASK_ATTR (0x7<<0)
+#define ISCSI_CMD_REQUEST_TASK_ATTR_SHIFT 0
+#define ISCSI_CMD_REQUEST_RESERVED1 (0x3<<3)
+#define ISCSI_CMD_REQUEST_RESERVED1_SHIFT 3
+#define ISCSI_CMD_REQUEST_WRITE (0x1<<5)
+#define ISCSI_CMD_REQUEST_WRITE_SHIFT 5
+#define ISCSI_CMD_REQUEST_READ (0x1<<6)
+#define ISCSI_CMD_REQUEST_READ_SHIFT 6
+#define ISCSI_CMD_REQUEST_FINAL (0x1<<7)
+#define ISCSI_CMD_REQUEST_FINAL_SHIFT 7
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	u8 op_attr;
+#define ISCSI_CMD_REQUEST_TASK_ATTR (0x7<<0)
+#define ISCSI_CMD_REQUEST_TASK_ATTR_SHIFT 0
+#define ISCSI_CMD_REQUEST_RESERVED1 (0x3<<3)
+#define ISCSI_CMD_REQUEST_RESERVED1_SHIFT 3
+#define ISCSI_CMD_REQUEST_WRITE (0x1<<5)
+#define ISCSI_CMD_REQUEST_WRITE_SHIFT 5
+#define ISCSI_CMD_REQUEST_READ (0x1<<6)
+#define ISCSI_CMD_REQUEST_READ_SHIFT 6
+#define ISCSI_CMD_REQUEST_FINAL (0x1<<7)
+#define ISCSI_CMD_REQUEST_FINAL_SHIFT 7
+	u8 op_code;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 ud_buffer_offset;
+	u16 sd_buffer_offset;
+#elif defined(__LITTLE_ENDIAN)
+	u16 sd_buffer_offset;
+	u16 ud_buffer_offset;
+#endif
+	u32 lun[2];
+#if defined(__BIG_ENDIAN)
+	u16 reserved2;
+	u16 itt;
+#define ISCSI_CMD_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_CMD_REQUEST_INDEX_SHIFT 0
+#define ISCSI_CMD_REQUEST_TYPE (0x3<<14)
+#define ISCSI_CMD_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_CMD_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_CMD_REQUEST_INDEX_SHIFT 0
+#define ISCSI_CMD_REQUEST_TYPE (0x3<<14)
+#define ISCSI_CMD_REQUEST_TYPE_SHIFT 14
+	u16 reserved2;
+#endif
+	u32 total_data_transfer_length;
+	u32 cmd_sn;
+	u32 reserved3;
+	u32 cdb[4];
+	u32 zero_fill;
+	u32 bd_list_addr_lo;
+	u32 bd_list_addr_hi;
+#if defined(__BIG_ENDIAN)
+	u8 cq_index;
+	u8 sd_start_bd_index;
+	u8 ud_start_bd_index;
+	u8 num_bds;
+#elif defined(__LITTLE_ENDIAN)
+	u8 num_bds;
+	u8 ud_start_bd_index;
+	u8 sd_start_bd_index;
+	u8 cq_index;
+#endif
+};
+
+
+/*
+ * task statistics for write response
+ */
+struct bnx2i_write_resp_task_stat {
+	u32 num_data_ins;
+};
+
+/*
+ * task statistics for read response
+ */
+struct bnx2i_read_resp_task_stat {
+#if defined(__BIG_ENDIAN)
+	u16 num_data_outs;
+	u16 num_r2ts;
+#elif defined(__LITTLE_ENDIAN)
+	u16 num_r2ts;
+	u16 num_data_outs;
+#endif
+};
+
+/*
+ * task statistics for iSCSI cmd response
+ */
+union bnx2i_cmd_resp_task_stat {
+	struct bnx2i_write_resp_task_stat write_stat;
+	struct bnx2i_read_resp_task_stat read_stat;
+};
+
+/*
+ * SCSI Command CQE
+ */
+struct bnx2i_cmd_response {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 response_flags;
+#define ISCSI_CMD_RESPONSE_RESERVED0 (0x1<<0)
+#define ISCSI_CMD_RESPONSE_RESERVED0_SHIFT 0
+#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW (0x1<<1)
+#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW_SHIFT 1
+#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW (0x1<<2)
+#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW_SHIFT 2
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW (0x1<<3)
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW_SHIFT 3
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW (0x1<<4)
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW_SHIFT 4
+#define ISCSI_CMD_RESPONSE_RESERVED1 (0x7<<5)
+#define ISCSI_CMD_RESPONSE_RESERVED1_SHIFT 5
+	u8 response;
+	u8 status;
+#elif defined(__LITTLE_ENDIAN)
+	u8 status;
+	u8 response;
+	u8 response_flags;
+#define ISCSI_CMD_RESPONSE_RESERVED0 (0x1<<0)
+#define ISCSI_CMD_RESPONSE_RESERVED0_SHIFT 0
+#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW (0x1<<1)
+#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW_SHIFT 1
+#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW (0x1<<2)
+#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW_SHIFT 2
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW (0x1<<3)
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW_SHIFT 3
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW (0x1<<4)
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW_SHIFT 4
+#define ISCSI_CMD_RESPONSE_RESERVED1 (0x7<<5)
+#define ISCSI_CMD_RESPONSE_RESERVED1_SHIFT 5
+	u8 op_code;
+#endif
+	u32 data_length;
+	u32 exp_cmd_sn;
+	u32 max_cmd_sn;
+	u32 reserved2;
+	u32 residual_count;
+#if defined(__BIG_ENDIAN)
+	u16 reserved4;
+	u8 err_code;
+	u8 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+	u8 reserved3;
+	u8 err_code;
+	u16 reserved4;
+#endif
+	u32 reserved5[5];
+	union bnx2i_cmd_resp_task_stat task_stat;
+	u32 reserved6;
+#if defined(__BIG_ENDIAN)
+	u16 reserved7;
+	u16 itt;
+#define ISCSI_CMD_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_CMD_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_CMD_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_CMD_RESPONSE_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_CMD_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_CMD_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_CMD_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_CMD_RESPONSE_TYPE_SHIFT 14
+	u16 reserved7;
+#endif
+	u32 cq_req_sn;
+};
+
+
+
+/*
+ * firmware middle-path request SQ WQE
+ */
+struct bnx2i_fw_mp_request {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 op_attr;
+	u16 hdr_opaque1;
+#elif defined(__LITTLE_ENDIAN)
+	u16 hdr_opaque1;
+	u8 op_attr;
+	u8 op_code;
+#endif
+	u32 data_length;
+	u32 hdr_opaque2[2];
+#if defined(__BIG_ENDIAN)
+	u16 reserved0;
+	u16 itt;
+#define ISCSI_FW_MP_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_FW_MP_REQUEST_INDEX_SHIFT 0
+#define ISCSI_FW_MP_REQUEST_TYPE (0x3<<14)
+#define ISCSI_FW_MP_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_FW_MP_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_FW_MP_REQUEST_INDEX_SHIFT 0
+#define ISCSI_FW_MP_REQUEST_TYPE (0x3<<14)
+#define ISCSI_FW_MP_REQUEST_TYPE_SHIFT 14
+	u16 reserved0;
+#endif
+	u32 hdr_opaque3[4];
+	u32 resp_bd_list_addr_lo;
+	u32 resp_bd_list_addr_hi;
+	u32 resp_buffer;
+#define ISCSI_FW_MP_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0)
+#define ISCSI_FW_MP_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0
+#define ISCSI_FW_MP_REQUEST_NUM_RESP_BDS (0xFF<<24)
+#define ISCSI_FW_MP_REQUEST_NUM_RESP_BDS_SHIFT 24
+#if defined(__BIG_ENDIAN)
+	u16 reserved4;
+	u8 reserved3;
+	u8 flags;
+#define ISCSI_FW_MP_REQUEST_RESERVED1 (0x1<<0)
+#define ISCSI_FW_MP_REQUEST_RESERVED1_SHIFT 0
+#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION (0x1<<1)
+#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION_SHIFT 1
+#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2)
+#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2
+#define ISCSI_FW_MP_REQUEST_RESERVED2 (0x1F<<3)
+#define ISCSI_FW_MP_REQUEST_RESERVED2_SHIFT 3
+#elif defined(__LITTLE_ENDIAN)
+	u8 flags;
+#define ISCSI_FW_MP_REQUEST_RESERVED1 (0x1<<0)
+#define ISCSI_FW_MP_REQUEST_RESERVED1_SHIFT 0
+#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION (0x1<<1)
+#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION_SHIFT 1
+#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2)
+#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2
+#define ISCSI_FW_MP_REQUEST_RESERVED2 (0x1F<<3)
+#define ISCSI_FW_MP_REQUEST_RESERVED2_SHIFT 3
+	u8 reserved3;
+	u16 reserved4;
+#endif
+	u32 bd_list_addr_lo;
+	u32 bd_list_addr_hi;
+#if defined(__BIG_ENDIAN)
+	u8 cq_index;
+	u8 reserved6;
+	u8 reserved5;
+	u8 num_bds;
+#elif defined(__LITTLE_ENDIAN)
+	u8 num_bds;
+	u8 reserved5;
+	u8 reserved6;
+	u8 cq_index;
+#endif
+};
+
+
+/*
+ * firmware response - CQE: used only by firmware
+ */
+struct bnx2i_fw_response {
+	u32 hdr_dword1[2];
+	u32 hdr_exp_cmd_sn;
+	u32 hdr_max_cmd_sn;
+	u32 hdr_ttt;
+	u32 hdr_res_cnt;
+	u32 cqe_flags;
+#define ISCSI_FW_RESPONSE_RESERVED2 (0xFF<<0)
+#define ISCSI_FW_RESPONSE_RESERVED2_SHIFT 0
+#define ISCSI_FW_RESPONSE_ERR_CODE (0xFF<<8)
+#define ISCSI_FW_RESPONSE_ERR_CODE_SHIFT 8
+#define ISCSI_FW_RESPONSE_RESERVED3 (0xFFFF<<16)
+#define ISCSI_FW_RESPONSE_RESERVED3_SHIFT 16
+	u32 stat_sn;
+	u32 hdr_dword2[2];
+	u32 hdr_dword3[2];
+	u32 task_stat;
+	u32 reserved0;
+	u32 hdr_itt;
+	u32 cq_req_sn;
+};
+
+
+/*
+ * iSCSI KCQ CQE parameters
+ */
+union iscsi_kcqe_params {
+	u32 reserved0[4];
+};
+
+/*
+ * iSCSI KCQ CQE
+ */
+struct iscsi_kcqe {
+	u32 iscsi_conn_id;
+	u32 completion_status;
+	u32 iscsi_conn_context_id;
+	union iscsi_kcqe_params params;
+#if defined(__BIG_ENDIAN)
+	u8 flags;
+#define ISCSI_KCQE_RESERVED0 (0xF<<0)
+#define ISCSI_KCQE_RESERVED0_SHIFT 0
+#define ISCSI_KCQE_LAYER_CODE (0x7<<4)
+#define ISCSI_KCQE_LAYER_CODE_SHIFT 4
+#define ISCSI_KCQE_RESERVED1 (0x1<<7)
+#define ISCSI_KCQE_RESERVED1_SHIFT 7
+	u8 op_code;
+	u16 qe_self_seq;
+#elif defined(__LITTLE_ENDIAN)
+	u16 qe_self_seq;
+	u8 op_code;
+	u8 flags;
+#define ISCSI_KCQE_RESERVED0 (0xF<<0)
+#define ISCSI_KCQE_RESERVED0_SHIFT 0
+#define ISCSI_KCQE_LAYER_CODE (0x7<<4)
+#define ISCSI_KCQE_LAYER_CODE_SHIFT 4
+#define ISCSI_KCQE_RESERVED1 (0x1<<7)
+#define ISCSI_KCQE_RESERVED1_SHIFT 7
+#endif
+};
+
+
+
+/*
+ * iSCSI KWQE header
+ */
+struct iscsi_kwqe_header {
+#if defined(__BIG_ENDIAN)
+	u8 flags;
+#define ISCSI_KWQE_HEADER_RESERVED0 (0xF<<0)
+#define ISCSI_KWQE_HEADER_RESERVED0_SHIFT 0
+#define ISCSI_KWQE_HEADER_LAYER_CODE (0x7<<4)
+#define ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT 4
+#define ISCSI_KWQE_HEADER_RESERVED1 (0x1<<7)
+#define ISCSI_KWQE_HEADER_RESERVED1_SHIFT 7
+	u8 op_code;
+#elif defined(__LITTLE_ENDIAN)
+	u8 op_code;
+	u8 flags;
+#define ISCSI_KWQE_HEADER_RESERVED0 (0xF<<0)
+#define ISCSI_KWQE_HEADER_RESERVED0_SHIFT 0
+#define ISCSI_KWQE_HEADER_LAYER_CODE (0x7<<4)
+#define ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT 4
+#define ISCSI_KWQE_HEADER_RESERVED1 (0x1<<7)
+#define ISCSI_KWQE_HEADER_RESERVED1_SHIFT 7
+#endif
+};
+
+/*
+ * iSCSI firmware init request 1
+ */
+struct iscsi_kwqe_init1 {
+#if defined(__BIG_ENDIAN)
+	struct iscsi_kwqe_header hdr;
+	u8 reserved0;
+	u8 num_cqs;
+#elif defined(__LITTLE_ENDIAN)
+	u8 num_cqs;
+	u8 reserved0;
+	struct iscsi_kwqe_header hdr;
+#endif
+	u32 dummy_buffer_addr_lo;
+	u32 dummy_buffer_addr_hi;
+#if defined(__BIG_ENDIAN)
+	u16 num_ccells_per_conn;
+	u16 num_tasks_per_conn;
+#elif defined(__LITTLE_ENDIAN)
+	u16 num_tasks_per_conn;
+	u16 num_ccells_per_conn;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 sq_wqes_per_page;
+	u16 sq_num_wqes;
+#elif defined(__LITTLE_ENDIAN)
+	u16 sq_num_wqes;
+	u16 sq_wqes_per_page;
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 cq_log_wqes_per_page;
+	u8 flags;
+#define ISCSI_KWQE_INIT1_PAGE_SIZE (0xF<<0)
+#define ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT 0
+#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE (0x1<<4)
+#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE_SHIFT 4
+#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE (0x1<<5)
+#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE_SHIFT 5
+#define ISCSI_KWQE_INIT1_RESERVED1 (0x3<<6)
+#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 6
+	u16 cq_num_wqes;
+#elif defined(__LITTLE_ENDIAN)
+	u16 cq_num_wqes;
+	u8 flags;
+#define ISCSI_KWQE_INIT1_PAGE_SIZE (0xF<<0)
+#define ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT 0
+#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE (0x1<<4)
+#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE_SHIFT 4
+#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE (0x1<<5)
+#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE_SHIFT 5
+#define ISCSI_KWQE_INIT1_RESERVED1 (0x3<<6)
+#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 6
+	u8 cq_log_wqes_per_page;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 cq_num_pages;
+	u16 sq_num_pages;
+#elif defined(__LITTLE_ENDIAN)
+	u16 sq_num_pages;
+	u16 cq_num_pages;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 rq_buffer_size;
+	u16 rq_num_wqes;
+#elif defined(__LITTLE_ENDIAN)
+	u16 rq_num_wqes;
+	u16 rq_buffer_size;
+#endif
+};
+
+/*
+ * iSCSI firmware init request 2
+ */
+struct iscsi_kwqe_init2 {
+#if defined(__BIG_ENDIAN)
+	struct iscsi_kwqe_header hdr;
+	u16 max_cq_sqn;
+#elif defined(__LITTLE_ENDIAN)
+	u16 max_cq_sqn;
+	struct iscsi_kwqe_header hdr;
+#endif
+	u32 error_bit_map[2];
+	u32 reserved1[5];
+};
+
+/*
+ * Initial iSCSI connection offload request 1
+ */
+struct iscsi_kwqe_conn_offload1 {
+#if defined(__BIG_ENDIAN)
+	struct iscsi_kwqe_header hdr;
+	u16 iscsi_conn_id;
+#elif defined(__LITTLE_ENDIAN)
+	u16 iscsi_conn_id;
+	struct iscsi_kwqe_header hdr;
+#endif
+	u32 sq_page_table_addr_lo;
+	u32 sq_page_table_addr_hi;
+	u32 cq_page_table_addr_lo;
+	u32 cq_page_table_addr_hi;
+	u32 reserved0[3];
+};
+
+/*
+ * iSCSI Page Table Entry (PTE)
+ */
+struct iscsi_pte {
+	u32 hi;
+	u32 lo;
+};
+
+/*
+ * Initial iSCSI connection offload request 2
+ */
+struct iscsi_kwqe_conn_offload2 {
+#if defined(__BIG_ENDIAN)
+	struct iscsi_kwqe_header hdr;
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	struct iscsi_kwqe_header hdr;
+#endif
+	u32 rq_page_table_addr_lo;
+	u32 rq_page_table_addr_hi;
+	struct iscsi_pte sq_first_pte;
+	struct iscsi_pte cq_first_pte;
+	u32 num_additional_wqes;
+};
+
+
+/*
+ * Initial iSCSI connection offload request 3
+ */
+struct iscsi_kwqe_conn_offload3 {
+#if defined(__BIG_ENDIAN)
+	struct iscsi_kwqe_header hdr;
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	struct iscsi_kwqe_header hdr;
+#endif
+	u32 reserved1;
+	struct iscsi_pte qp_first_pte[3];
+};
+
+
+/*
+ * iSCSI connection update request
+ */
+struct iscsi_kwqe_conn_update {
+#if defined(__BIG_ENDIAN)
+	struct iscsi_kwqe_header hdr;
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	struct iscsi_kwqe_header hdr;
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 session_error_recovery_level;
+	u8 max_outstanding_r2ts;
+	u8 reserved2;
+	u8 conn_flags;
+#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST (0x1<<0)
+#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST_SHIFT 0
+#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST (0x1<<1)
+#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST_SHIFT 1
+#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T (0x1<<2)
+#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T_SHIFT 2
+#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA (0x1<<3)
+#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA_SHIFT 3
+#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0xF<<4)
+#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 4
+#elif defined(__LITTLE_ENDIAN)
+	u8 conn_flags;
+#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST (0x1<<0)
+#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST_SHIFT 0
+#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST (0x1<<1)
+#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST_SHIFT 1
+#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T (0x1<<2)
+#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T_SHIFT 2
+#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA (0x1<<3)
+#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA_SHIFT 3
+#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0xF<<4)
+#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 4
+	u8 reserved2;
+	u8 max_outstanding_r2ts;
+	u8 session_error_recovery_level;
+#endif
+	u32 context_id;
+	u32 max_send_pdu_length;
+	u32 max_recv_pdu_length;
+	u32 first_burst_length;
+	u32 max_burst_length;
+	u32 exp_stat_sn;
+};
+
+/*
+ * iSCSI destroy connection request
+ */
+struct iscsi_kwqe_conn_destroy {
+#if defined(__BIG_ENDIAN)
+	struct iscsi_kwqe_header hdr;
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	struct iscsi_kwqe_header hdr;
+#endif
+	u32 context_id;
+	u32 reserved1[6];
+};
+
+/*
+ * iSCSI KWQ WQE
+ */
+union iscsi_kwqe {
+	struct iscsi_kwqe_init1 init1;
+	struct iscsi_kwqe_init2 init2;
+	struct iscsi_kwqe_conn_offload1 conn_offload1;
+	struct iscsi_kwqe_conn_offload2 conn_offload2;
+	struct iscsi_kwqe_conn_update conn_update;
+	struct iscsi_kwqe_conn_destroy conn_destroy;
+};
+
+/*
+ * iSCSI Login SQ WQE
+ */
+struct bnx2i_login_request {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 op_attr;
+#define ISCSI_LOGIN_REQUEST_NEXT_STAGE (0x3<<0)
+#define ISCSI_LOGIN_REQUEST_NEXT_STAGE_SHIFT 0
+#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE (0x3<<2)
+#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE_SHIFT 2
+#define ISCSI_LOGIN_REQUEST_RESERVED0 (0x3<<4)
+#define ISCSI_LOGIN_REQUEST_RESERVED0_SHIFT 4
+#define ISCSI_LOGIN_REQUEST_CONT (0x1<<6)
+#define ISCSI_LOGIN_REQUEST_CONT_SHIFT 6
+#define ISCSI_LOGIN_REQUEST_TRANSIT (0x1<<7)
+#define ISCSI_LOGIN_REQUEST_TRANSIT_SHIFT 7
+	u8 version_max;
+	u8 version_min;
+#elif defined(__LITTLE_ENDIAN)
+	u8 version_min;
+	u8 version_max;
+	u8 op_attr;
+#define ISCSI_LOGIN_REQUEST_NEXT_STAGE (0x3<<0)
+#define ISCSI_LOGIN_REQUEST_NEXT_STAGE_SHIFT 0
+#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE (0x3<<2)
+#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE_SHIFT 2
+#define ISCSI_LOGIN_REQUEST_RESERVED0 (0x3<<4)
+#define ISCSI_LOGIN_REQUEST_RESERVED0_SHIFT 4
+#define ISCSI_LOGIN_REQUEST_CONT (0x1<<6)
+#define ISCSI_LOGIN_REQUEST_CONT_SHIFT 6
+#define ISCSI_LOGIN_REQUEST_TRANSIT (0x1<<7)
+#define ISCSI_LOGIN_REQUEST_TRANSIT_SHIFT 7
+	u8 op_code;
+#endif
+	u32 data_length;
+	u32 isid_lo;
+#if defined(__BIG_ENDIAN)
+	u16 isid_hi;
+	u16 tsih;
+#elif defined(__LITTLE_ENDIAN)
+	u16 tsih;
+	u16 isid_hi;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 reserved2;
+	u16 itt;
+#define ISCSI_LOGIN_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_LOGIN_REQUEST_INDEX_SHIFT 0
+#define ISCSI_LOGIN_REQUEST_TYPE (0x3<<14)
+#define ISCSI_LOGIN_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_LOGIN_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_LOGIN_REQUEST_INDEX_SHIFT 0
+#define ISCSI_LOGIN_REQUEST_TYPE (0x3<<14)
+#define ISCSI_LOGIN_REQUEST_TYPE_SHIFT 14
+	u16 reserved2;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 cid;
+	u16 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved3;
+	u16 cid;
+#endif
+	u32 cmd_sn;
+	u32 exp_stat_sn;
+	u32 reserved4;
+	u32 resp_bd_list_addr_lo;
+	u32 resp_bd_list_addr_hi;
+	u32 resp_buffer;
+#define ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0)
+#define ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0
+#define ISCSI_LOGIN_REQUEST_NUM_RESP_BDS (0xFF<<24)
+#define ISCSI_LOGIN_REQUEST_NUM_RESP_BDS_SHIFT 24
+#if defined(__BIG_ENDIAN)
+	u16 reserved8;
+	u8 reserved7;
+	u8 flags;
+#define ISCSI_LOGIN_REQUEST_RESERVED5 (0x3<<0)
+#define ISCSI_LOGIN_REQUEST_RESERVED5_SHIFT 0
+#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2)
+#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2
+#define ISCSI_LOGIN_REQUEST_RESERVED6 (0x1F<<3)
+#define ISCSI_LOGIN_REQUEST_RESERVED6_SHIFT 3
+#elif defined(__LITTLE_ENDIAN)
+	u8 flags;
+#define ISCSI_LOGIN_REQUEST_RESERVED5 (0x3<<0)
+#define ISCSI_LOGIN_REQUEST_RESERVED5_SHIFT 0
+#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2)
+#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2
+#define ISCSI_LOGIN_REQUEST_RESERVED6 (0x1F<<3)
+#define ISCSI_LOGIN_REQUEST_RESERVED6_SHIFT 3
+	u8 reserved7;
+	u16 reserved8;
+#endif
+	u32 bd_list_addr_lo;
+	u32 bd_list_addr_hi;
+#if defined(__BIG_ENDIAN)
+	u8 cq_index;
+	u8 reserved10;
+	u8 reserved9;
+	u8 num_bds;
+#elif defined(__LITTLE_ENDIAN)
+	u8 num_bds;
+	u8 reserved9;
+	u8 reserved10;
+	u8 cq_index;
+#endif
+};
+
+
+/*
+ * iSCSI Login CQE
+ */
+struct bnx2i_login_response {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 response_flags;
+#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE (0x3<<0)
+#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE_SHIFT 0
+#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE (0x3<<2)
+#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE_SHIFT 2
+#define ISCSI_LOGIN_RESPONSE_RESERVED0 (0x3<<4)
+#define ISCSI_LOGIN_RESPONSE_RESERVED0_SHIFT 4
+#define ISCSI_LOGIN_RESPONSE_CONT (0x1<<6)
+#define ISCSI_LOGIN_RESPONSE_CONT_SHIFT 6
+#define ISCSI_LOGIN_RESPONSE_TRANSIT (0x1<<7)
+#define ISCSI_LOGIN_RESPONSE_TRANSIT_SHIFT 7
+	u8 version_max;
+	u8 version_active;
+#elif defined(__LITTLE_ENDIAN)
+	u8 version_active;
+	u8 version_max;
+	u8 response_flags;
+#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE (0x3<<0)
+#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE_SHIFT 0
+#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE (0x3<<2)
+#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE_SHIFT 2
+#define ISCSI_LOGIN_RESPONSE_RESERVED0 (0x3<<4)
+#define ISCSI_LOGIN_RESPONSE_RESERVED0_SHIFT 4
+#define ISCSI_LOGIN_RESPONSE_CONT (0x1<<6)
+#define ISCSI_LOGIN_RESPONSE_CONT_SHIFT 6
+#define ISCSI_LOGIN_RESPONSE_TRANSIT (0x1<<7)
+#define ISCSI_LOGIN_RESPONSE_TRANSIT_SHIFT 7
+	u8 op_code;
+#endif
+	u32 data_length;
+	u32 exp_cmd_sn;
+	u32 max_cmd_sn;
+	u32 reserved1[2];
+#if defined(__BIG_ENDIAN)
+	u16 reserved3;
+	u8 err_code;
+	u8 reserved2;
+#elif defined(__LITTLE_ENDIAN)
+	u8 reserved2;
+	u8 err_code;
+	u16 reserved3;
+#endif
+	u32 stat_sn;
+	u32 isid_lo;
+#if defined(__BIG_ENDIAN)
+	u16 isid_hi;
+	u16 tsih;
+#elif defined(__LITTLE_ENDIAN)
+	u16 tsih;
+	u16 isid_hi;
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 status_class;
+	u8 status_detail;
+	u16 reserved4;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved4;
+	u8 status_detail;
+	u8 status_class;
+#endif
+	u32 reserved5[3];
+#if defined(__BIG_ENDIAN)
+	u16 reserved6;
+	u16 itt;
+#define ISCSI_LOGIN_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_LOGIN_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_LOGIN_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_LOGIN_RESPONSE_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_LOGIN_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_LOGIN_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_LOGIN_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_LOGIN_RESPONSE_TYPE_SHIFT 14
+	u16 reserved6;
+#endif
+	u32 cq_req_sn;
+};
+
+
+/*
+ * iSCSI Logout SQ WQE
+ */
+struct bnx2i_logout_request {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 op_attr;
+#define ISCSI_LOGOUT_REQUEST_REASON (0x7F<<0)
+#define ISCSI_LOGOUT_REQUEST_REASON_SHIFT 0
+#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE (0x1<<7)
+#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE_SHIFT 7
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	u8 op_attr;
+#define ISCSI_LOGOUT_REQUEST_REASON (0x7F<<0)
+#define ISCSI_LOGOUT_REQUEST_REASON_SHIFT 0
+#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE (0x1<<7)
+#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE_SHIFT 7
+	u8 op_code;
+#endif
+	u32 data_length;
+	u32 reserved1[2];
+#if defined(__BIG_ENDIAN)
+	u16 reserved2;
+	u16 itt;
+#define ISCSI_LOGOUT_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_LOGOUT_REQUEST_INDEX_SHIFT 0
+#define ISCSI_LOGOUT_REQUEST_TYPE (0x3<<14)
+#define ISCSI_LOGOUT_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_LOGOUT_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_LOGOUT_REQUEST_INDEX_SHIFT 0
+#define ISCSI_LOGOUT_REQUEST_TYPE (0x3<<14)
+#define ISCSI_LOGOUT_REQUEST_TYPE_SHIFT 14
+	u16 reserved2;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 cid;
+	u16 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved3;
+	u16 cid;
+#endif
+	u32 cmd_sn;
+	u32 reserved4[5];
+	u32 zero_fill;
+	u32 bd_list_addr_lo;
+	u32 bd_list_addr_hi;
+#if defined(__BIG_ENDIAN)
+	u8 cq_index;
+	u8 reserved6;
+	u8 reserved5;
+	u8 num_bds;
+#elif defined(__LITTLE_ENDIAN)
+	u8 num_bds;
+	u8 reserved5;
+	u8 reserved6;
+	u8 cq_index;
+#endif
+};
+
+
+/*
+ * iSCSI Logout CQE
+ */
+struct bnx2i_logout_response {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 reserved1;
+	u8 response;
+	u8 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u8 reserved0;
+	u8 response;
+	u8 reserved1;
+	u8 op_code;
+#endif
+	u32 reserved2;
+	u32 exp_cmd_sn;
+	u32 max_cmd_sn;
+	u32 reserved3[2];
+#if defined(__BIG_ENDIAN)
+	u16 reserved5;
+	u8 err_code;
+	u8 reserved4;
+#elif defined(__LITTLE_ENDIAN)
+	u8 reserved4;
+	u8 err_code;
+	u16 reserved5;
+#endif
+	u32 reserved6[3];
+#if defined(__BIG_ENDIAN)
+	u16 time_to_wait;
+	u16 time_to_retain;
+#elif defined(__LITTLE_ENDIAN)
+	u16 time_to_retain;
+	u16 time_to_wait;
+#endif
+	u32 reserved7[3];
+#if defined(__BIG_ENDIAN)
+	u16 reserved8;
+	u16 itt;
+#define ISCSI_LOGOUT_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_LOGOUT_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_LOGOUT_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_LOGOUT_RESPONSE_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_LOGOUT_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_LOGOUT_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_LOGOUT_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_LOGOUT_RESPONSE_TYPE_SHIFT 14
+	u16 reserved8;
+#endif
+	u32 cq_req_sn;
+};
+
+
+/*
+ * iSCSI Nop-In CQE
+ */
+struct bnx2i_nop_in_msg {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 reserved1;
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	u8 reserved1;
+	u8 op_code;
+#endif
+	u32 data_length;
+	u32 exp_cmd_sn;
+	u32 max_cmd_sn;
+	u32 ttt;
+	u32 reserved2;
+#if defined(__BIG_ENDIAN)
+	u16 reserved4;
+	u8 err_code;
+	u8 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+	u8 reserved3;
+	u8 err_code;
+	u16 reserved4;
+#endif
+	u32 reserved5;
+	u32 lun[2];
+	u32 reserved6[4];
+#if defined(__BIG_ENDIAN)
+	u16 reserved7;
+	u16 itt;
+#define ISCSI_NOP_IN_MSG_INDEX (0x3FFF<<0)
+#define ISCSI_NOP_IN_MSG_INDEX_SHIFT 0
+#define ISCSI_NOP_IN_MSG_TYPE (0x3<<14)
+#define ISCSI_NOP_IN_MSG_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_NOP_IN_MSG_INDEX (0x3FFF<<0)
+#define ISCSI_NOP_IN_MSG_INDEX_SHIFT 0
+#define ISCSI_NOP_IN_MSG_TYPE (0x3<<14)
+#define ISCSI_NOP_IN_MSG_TYPE_SHIFT 14
+	u16 reserved7;
+#endif
+	u32 cq_req_sn;
+};
+
+
+/*
+ * iSCSI NOP-OUT SQ WQE
+ */
+struct bnx2i_nop_out_request {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 op_attr;
+#define ISCSI_NOP_OUT_REQUEST_RESERVED1 (0x7F<<0)
+#define ISCSI_NOP_OUT_REQUEST_RESERVED1_SHIFT 0
+#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE (0x1<<7)
+#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE_SHIFT 7
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	u8 op_attr;
+#define ISCSI_NOP_OUT_REQUEST_RESERVED1 (0x7F<<0)
+#define ISCSI_NOP_OUT_REQUEST_RESERVED1_SHIFT 0
+#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE (0x1<<7)
+#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE_SHIFT 7
+	u8 op_code;
+#endif
+	u32 data_length;
+	u32 lun[2];
+#if defined(__BIG_ENDIAN)
+	u16 reserved2;
+	u16 itt;
+#define ISCSI_NOP_OUT_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_NOP_OUT_REQUEST_INDEX_SHIFT 0
+#define ISCSI_NOP_OUT_REQUEST_TYPE (0x3<<14)
+#define ISCSI_NOP_OUT_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_NOP_OUT_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_NOP_OUT_REQUEST_INDEX_SHIFT 0
+#define ISCSI_NOP_OUT_REQUEST_TYPE (0x3<<14)
+#define ISCSI_NOP_OUT_REQUEST_TYPE_SHIFT 14
+	u16 reserved2;
+#endif
+	u32 ttt;
+	u32 cmd_sn;
+	u32 reserved3[2];
+	u32 resp_bd_list_addr_lo;
+	u32 resp_bd_list_addr_hi;
+	u32 resp_buffer;
+#define ISCSI_NOP_OUT_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0)
+#define ISCSI_NOP_OUT_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0
+#define ISCSI_NOP_OUT_REQUEST_NUM_RESP_BDS (0xFF<<24)
+#define ISCSI_NOP_OUT_REQUEST_NUM_RESP_BDS_SHIFT 24
+#if defined(__BIG_ENDIAN)
+	u16 reserved7;
+	u8 reserved6;
+	u8 flags;
+#define ISCSI_NOP_OUT_REQUEST_RESERVED4 (0x1<<0)
+#define ISCSI_NOP_OUT_REQUEST_RESERVED4_SHIFT 0
+#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION (0x1<<1)
+#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION_SHIFT 1
+#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL (0x3F<<2)
+#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL_SHIFT 2
+#elif defined(__LITTLE_ENDIAN)
+	u8 flags;
+#define ISCSI_NOP_OUT_REQUEST_RESERVED4 (0x1<<0)
+#define ISCSI_NOP_OUT_REQUEST_RESERVED4_SHIFT 0
+#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION (0x1<<1)
+#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION_SHIFT 1
+#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL (0x3F<<2)
+#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL_SHIFT 2
+	u8 reserved6;
+	u16 reserved7;
+#endif
+	u32 bd_list_addr_lo;
+	u32 bd_list_addr_hi;
+#if defined(__BIG_ENDIAN)
+	u8 cq_index;
+	u8 reserved9;
+	u8 reserved8;
+	u8 num_bds;
+#elif defined(__LITTLE_ENDIAN)
+	u8 num_bds;
+	u8 reserved8;
+	u8 reserved9;
+	u8 cq_index;
+#endif
+};
+
+/*
+ * iSCSI Reject CQE
+ */
+struct bnx2i_reject_msg {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 reserved1;
+	u8 reason;
+	u8 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u8 reserved0;
+	u8 reason;
+	u8 reserved1;
+	u8 op_code;
+#endif
+	u32 data_length;
+	u32 exp_cmd_sn;
+	u32 max_cmd_sn;
+	u32 reserved2[2];
+#if defined(__BIG_ENDIAN)
+	u16 reserved4;
+	u8 err_code;
+	u8 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+	u8 reserved3;
+	u8 err_code;
+	u16 reserved4;
+#endif
+	u32 reserved5[8];
+	u32 cq_req_sn;
+};
+
+/*
+ * bnx2i iSCSI TMF SQ WQE
+ */
+struct bnx2i_tmf_request {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 op_attr;
+#define ISCSI_TMF_REQUEST_FUNCTION (0x7F<<0)
+#define ISCSI_TMF_REQUEST_FUNCTION_SHIFT 0
+#define ISCSI_TMF_REQUEST_ALWAYS_ONE (0x1<<7)
+#define ISCSI_TMF_REQUEST_ALWAYS_ONE_SHIFT 7
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	u8 op_attr;
+#define ISCSI_TMF_REQUEST_FUNCTION (0x7F<<0)
+#define ISCSI_TMF_REQUEST_FUNCTION_SHIFT 0
+#define ISCSI_TMF_REQUEST_ALWAYS_ONE (0x1<<7)
+#define ISCSI_TMF_REQUEST_ALWAYS_ONE_SHIFT 7
+	u8 op_code;
+#endif
+	u32 data_length;
+	u32 lun[2];
+#if defined(__BIG_ENDIAN)
+	u16 reserved1;
+	u16 itt;
+#define ISCSI_TMF_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_TMF_REQUEST_INDEX_SHIFT 0
+#define ISCSI_TMF_REQUEST_TYPE (0x3<<14)
+#define ISCSI_TMF_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_TMF_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_TMF_REQUEST_INDEX_SHIFT 0
+#define ISCSI_TMF_REQUEST_TYPE (0x3<<14)
+#define ISCSI_TMF_REQUEST_TYPE_SHIFT 14
+	u16 reserved1;
+#endif
+	u32 ref_itt;
+	u32 cmd_sn;
+	u32 reserved2;
+	u32 ref_cmd_sn;
+	u32 reserved3[3];
+	u32 zero_fill;
+	u32 bd_list_addr_lo;
+	u32 bd_list_addr_hi;
+#if defined(__BIG_ENDIAN)
+	u8 cq_index;
+	u8 reserved5;
+	u8 reserved4;
+	u8 num_bds;
+#elif defined(__LITTLE_ENDIAN)
+	u8 num_bds;
+	u8 reserved4;
+	u8 reserved5;
+	u8 cq_index;
+#endif
+};
+
+/*
+ * iSCSI Text SQ WQE
+ */
+struct bnx2i_text_request {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 op_attr;
+#define ISCSI_TEXT_REQUEST_RESERVED1 (0x3F<<0)
+#define ISCSI_TEXT_REQUEST_RESERVED1_SHIFT 0
+#define ISCSI_TEXT_REQUEST_CONT (0x1<<6)
+#define ISCSI_TEXT_REQUEST_CONT_SHIFT 6
+#define ISCSI_TEXT_REQUEST_FINAL (0x1<<7)
+#define ISCSI_TEXT_REQUEST_FINAL_SHIFT 7
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	u8 op_attr;
+#define ISCSI_TEXT_REQUEST_RESERVED1 (0x3F<<0)
+#define ISCSI_TEXT_REQUEST_RESERVED1_SHIFT 0
+#define ISCSI_TEXT_REQUEST_CONT (0x1<<6)
+#define ISCSI_TEXT_REQUEST_CONT_SHIFT 6
+#define ISCSI_TEXT_REQUEST_FINAL (0x1<<7)
+#define ISCSI_TEXT_REQUEST_FINAL_SHIFT 7
+	u8 op_code;
+#endif
+	u32 data_length;
+	u32 lun[2];
+#if defined(__BIG_ENDIAN)
+	u16 reserved3;
+	u16 itt;
+#define ISCSI_TEXT_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_TEXT_REQUEST_INDEX_SHIFT 0
+#define ISCSI_TEXT_REQUEST_TYPE (0x3<<14)
+#define ISCSI_TEXT_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_TEXT_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_TEXT_REQUEST_INDEX_SHIFT 0
+#define ISCSI_TEXT_REQUEST_TYPE (0x3<<14)
+#define ISCSI_TEXT_REQUEST_TYPE_SHIFT 14
+	u16 reserved3;
+#endif
+	u32 ttt;
+	u32 cmd_sn;
+	u32 reserved4[2];
+	u32 resp_bd_list_addr_lo;
+	u32 resp_bd_list_addr_hi;
+	u32 resp_buffer;
+#define ISCSI_TEXT_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0)
+#define ISCSI_TEXT_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0
+#define ISCSI_TEXT_REQUEST_NUM_RESP_BDS (0xFF<<24)
+#define ISCSI_TEXT_REQUEST_NUM_RESP_BDS_SHIFT 24
+	u32 zero_fill;
+	u32 bd_list_addr_lo;
+	u32 bd_list_addr_hi;
+#if defined(__BIG_ENDIAN)
+	u8 cq_index;
+	u8 reserved7;
+	u8 reserved6;
+	u8 num_bds;
+#elif defined(__LITTLE_ENDIAN)
+	u8 num_bds;
+	u8 reserved6;
+	u8 reserved7;
+	u8 cq_index;
+#endif
+};
+
+/*
+ * iSCSI SQ WQE
+ */
+union iscsi_request {
+	struct bnx2i_cmd_request cmd;
+	struct bnx2i_tmf_request tmf;
+	struct bnx2i_nop_out_request nop_out;
+	struct bnx2i_login_request login_req;
+	struct bnx2i_text_request text;
+	struct bnx2i_logout_request logout_req;
+	struct bnx2i_cleanup_request cleanup;
+};
+
+
+/*
+ * iSCSI TMF CQE
+ */
+struct bnx2i_tmf_response {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 reserved1;
+	u8 response;
+	u8 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u8 reserved0;
+	u8 response;
+	u8 reserved1;
+	u8 op_code;
+#endif
+	u32 reserved2;
+	u32 exp_cmd_sn;
+	u32 max_cmd_sn;
+	u32 reserved3[2];
+#if defined(__BIG_ENDIAN)
+	u16 reserved5;
+	u8 err_code;
+	u8 reserved4;
+#elif defined(__LITTLE_ENDIAN)
+	u8 reserved4;
+	u8 err_code;
+	u16 reserved5;
+#endif
+	u32 reserved6[7];
+#if defined(__BIG_ENDIAN)
+	u16 reserved7;
+	u16 itt;
+#define ISCSI_TMF_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_TMF_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_TMF_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_TMF_RESPONSE_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_TMF_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_TMF_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_TMF_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_TMF_RESPONSE_TYPE_SHIFT 14
+	u16 reserved7;
+#endif
+	u32 cq_req_sn;
+};
+
+/*
+ * iSCSI Text CQE
+ */
+struct bnx2i_text_response {
+#if defined(__BIG_ENDIAN)
+	u8 op_code;
+	u8 response_flags;
+#define ISCSI_TEXT_RESPONSE_RESERVED1 (0x3F<<0)
+#define ISCSI_TEXT_RESPONSE_RESERVED1_SHIFT 0
+#define ISCSI_TEXT_RESPONSE_CONT (0x1<<6)
+#define ISCSI_TEXT_RESPONSE_CONT_SHIFT 6
+#define ISCSI_TEXT_RESPONSE_FINAL (0x1<<7)
+#define ISCSI_TEXT_RESPONSE_FINAL_SHIFT 7
+	u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+	u16 reserved0;
+	u8 response_flags;
+#define ISCSI_TEXT_RESPONSE_RESERVED1 (0x3F<<0)
+#define ISCSI_TEXT_RESPONSE_RESERVED1_SHIFT 0
+#define ISCSI_TEXT_RESPONSE_CONT (0x1<<6)
+#define ISCSI_TEXT_RESPONSE_CONT_SHIFT 6
+#define ISCSI_TEXT_RESPONSE_FINAL (0x1<<7)
+#define ISCSI_TEXT_RESPONSE_FINAL_SHIFT 7
+	u8 op_code;
+#endif
+	u32 data_length;
+	u32 exp_cmd_sn;
+	u32 max_cmd_sn;
+	u32 ttt;
+	u32 reserved2;
+#if defined(__BIG_ENDIAN)
+	u16 reserved4;
+	u8 err_code;
+	u8 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+	u8 reserved3;
+	u8 err_code;
+	u16 reserved4;
+#endif
+	u32 reserved5;
+	u32 lun[2];
+	u32 reserved6[4];
+#if defined(__BIG_ENDIAN)
+	u16 reserved7;
+	u16 itt;
+#define ISCSI_TEXT_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_TEXT_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_TEXT_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_TEXT_RESPONSE_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+	u16 itt;
+#define ISCSI_TEXT_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_TEXT_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_TEXT_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_TEXT_RESPONSE_TYPE_SHIFT 14
+	u16 reserved7;
+#endif
+	u32 cq_req_sn;
+};
+
+/*
+ * iSCSI CQE
+ */
+union iscsi_response {
+	struct bnx2i_cmd_response cmd;
+	struct bnx2i_tmf_response tmf;
+	struct bnx2i_login_response login_resp;
+	struct bnx2i_text_response text;
+	struct bnx2i_logout_response logout_resp;
+	struct bnx2i_cleanup_response cleanup;
+	struct bnx2i_reject_msg reject;
+	struct bnx2i_async_msg async;
+	struct bnx2i_nop_in_msg nop_in;
+};
+
+#endif /* __57XX_ISCSI_HSI_LINUX_LE__ */
diff --git a/drivers/scsi/bnx2i/Kconfig b/drivers/scsi/bnx2i/Kconfig
new file mode 100644
index 0000000..820d428
--- /dev/null
+++ b/drivers/scsi/bnx2i/Kconfig
@@ -0,0 +1,7 @@
+config SCSI_BNX2_ISCSI
+	tristate "Broadcom NetXtreme II iSCSI support"
+	select SCSI_ISCSI_ATTRS
+	select CNIC
+	---help---
+	This driver supports iSCSI offload for the Broadcom NetXtreme II
+	devices.
diff --git a/drivers/scsi/bnx2i/Makefile b/drivers/scsi/bnx2i/Makefile
new file mode 100644
index 0000000..b5802bd
--- /dev/null
+++ b/drivers/scsi/bnx2i/Makefile
@@ -0,0 +1,3 @@
+bnx2i-y := bnx2i_init.o bnx2i_hwi.o bnx2i_iscsi.o bnx2i_sysfs.o
+
+obj-$(CONFIG_SCSI_BNX2_ISCSI) += bnx2i.o
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
new file mode 100644
index 0000000..d7576f2
--- /dev/null
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -0,0 +1,771 @@
+/* bnx2i.h: Broadcom NetXtreme II iSCSI driver.
+ *
+ * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
+ * Copyright (c) 2007, 2008 Mike Christie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ */
+
+#ifndef _BNX2I_H_
+#define _BNX2I_H_
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/in.h>
+#include <linux/kfifo.h>
+#include <linux/netdevice.h>
+#include <linux/completion.h>
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi.h>
+#include <scsi/iscsi_proto.h>
+#include <scsi/libiscsi.h>
+#include <scsi/scsi_transport_iscsi.h>
+
+#include "../../net/cnic_if.h"
+#include "57xx_iscsi_hsi.h"
+#include "57xx_iscsi_constants.h"
+
+#define BNX2_ISCSI_DRIVER_NAME		"bnx2i"
+
+#define BNX2I_MAX_ADAPTERS		8
+
+#define ISCSI_MAX_CONNS_PER_HBA		128
+#define ISCSI_MAX_SESS_PER_HBA		ISCSI_MAX_CONNS_PER_HBA
+#define ISCSI_MAX_CMDS_PER_SESS		128
+
+/* Total active commands across all connections supported by devices */
+#define ISCSI_MAX_CMDS_PER_HBA_5708	(28 * (ISCSI_MAX_CMDS_PER_SESS - 1))
+#define ISCSI_MAX_CMDS_PER_HBA_5709	(128 * (ISCSI_MAX_CMDS_PER_SESS - 1))
+#define ISCSI_MAX_CMDS_PER_HBA_57710	(256 * (ISCSI_MAX_CMDS_PER_SESS - 1))
+
+#define ISCSI_MAX_BDS_PER_CMD		32
+
+#define MAX_PAGES_PER_CTRL_STRUCT_POOL	8
+#define BNX2I_RESERVED_SLOW_PATH_CMD_SLOTS	4
+
+/* 5706/08 hardware has limit on maximum buffer size per BD it can handle */
+#define MAX_BD_LENGTH			65535
+#define BD_SPLIT_SIZE			32768
+
+/* min, max & default values for SQ/RQ/CQ size, configurable via' modparam */
+#define BNX2I_SQ_WQES_MIN 		16
+#define BNX2I_570X_SQ_WQES_MAX 		128
+#define BNX2I_5770X_SQ_WQES_MAX 	512
+#define BNX2I_570X_SQ_WQES_DEFAULT 	128
+#define BNX2I_5770X_SQ_WQES_DEFAULT 	256
+
+#define BNX2I_570X_CQ_WQES_MAX 		128
+#define BNX2I_5770X_CQ_WQES_MAX 	512
+
+#define BNX2I_RQ_WQES_MIN 		16
+#define BNX2I_RQ_WQES_MAX 		32
+#define BNX2I_RQ_WQES_DEFAULT 		16
+
+/* CCELLs per conn */
+#define BNX2I_CCELLS_MIN		16
+#define BNX2I_CCELLS_MAX		96
+#define BNX2I_CCELLS_DEFAULT		64
+
+#define ITT_INVALID_SIGNATURE		0xFFFF
+
+#define ISCSI_CMD_CLEANUP_TIMEOUT	100
+
+#define BNX2I_CONN_CTX_BUF_SIZE		16384
+
+#define BNX2I_SQ_WQE_SIZE		64
+#define BNX2I_RQ_WQE_SIZE		256
+#define BNX2I_CQE_SIZE			64
+
+#define MB_KERNEL_CTX_SHIFT		8
+#define MB_KERNEL_CTX_SIZE		(1 << MB_KERNEL_CTX_SHIFT)
+
+#define CTX_SHIFT			7
+#define GET_CID_NUM(cid_addr)		((cid_addr) >> CTX_SHIFT)
+
+#define CTX_OFFSET 			0x10000
+#define MAX_CID_CNT			0x4000
+
+/* 5709 context registers */
+#define BNX2_MQ_CONFIG2			0x00003d00
+#define BNX2_MQ_CONFIG2_CONT_SZ		(0x7L<<4)
+#define BNX2_MQ_CONFIG2_FIRST_L4L5	(0x1fL<<8)
+
+/* 57710's BAR2 is mapped to doorbell registers */
+#define BNX2X_DOORBELL_PCI_BAR		2
+#define BNX2X_MAX_CQS			8
+
+#define CNIC_ARM_CQE			1
+#define CNIC_DISARM_CQE			0
+
+#define REG_RD(__hba, offset)				\
+		readl(__hba->regview + offset)
+#define REG_WR(__hba, offset, val)			\
+		writel(val, __hba->regview + offset)
+
+
+/**
+ * struct generic_pdu_resc - login pdu resource structure
+ *
+ * @req_buf:            driver buffer used to stage payload associated with
+ *                      the login request
+ * @req_dma_addr:       dma address for iscsi login request payload buffer
+ * @req_buf_size:       actual login request payload length
+ * @req_wr_ptr:         pointer into login request buffer when next data is
+ *                      to be written
+ * @resp_hdr:           iscsi header where iscsi login response header is to
+ *                      be recreated
+ * @resp_buf:           buffer to stage login response payload
+ * @resp_dma_addr:      login response payload buffer dma address
+ * @resp_buf_size:      login response paylod length
+ * @resp_wr_ptr:        pointer into login response buffer when next data is
+ *                      to be written
+ * @req_bd_tbl:         iscsi login request payload BD table
+ * @req_bd_dma:         login request BD table dma address
+ * @resp_bd_tbl:        iscsi login response payload BD table
+ * @resp_bd_dma:        login request BD table dma address
+ *
+ * following structure defines buffer info for generic pdus such as iSCSI Login,
+ *	Logout and NOP
+ */
+struct generic_pdu_resc {
+	char *req_buf;
+	dma_addr_t req_dma_addr;
+	u32 req_buf_size;
+	char *req_wr_ptr;
+	struct iscsi_hdr resp_hdr;
+	char *resp_buf;
+	dma_addr_t resp_dma_addr;
+	u32 resp_buf_size;
+	char *resp_wr_ptr;
+	char *req_bd_tbl;
+	dma_addr_t req_bd_dma;
+	char *resp_bd_tbl;
+	dma_addr_t resp_bd_dma;
+};
+
+
+/**
+ * struct bd_resc_page - tracks DMA'able memory allocated for BD tables
+ *
+ * @link:               list head to link elements
+ * @max_ptrs:           maximun pointers that can be stored in this page
+ * @num_valid:          number of pointer valid in this page
+ * @page:               base addess for page pointer array
+ *
+ * structure to track DMA'able memory allocated for command BD tables
+ */
+struct bd_resc_page {
+	struct list_head link;
+	u32 max_ptrs;
+	u32 num_valid;
+	void *page[1];
+};
+
+
+/**
+ * struct io_bdt - I/O buffer destricptor table
+ *
+ * @bd_tbl:             BD table's virtual address
+ * @bd_tbl_dma:         BD table's dma address
+ * @bd_valid:           num valid BD entries
+ *
+ * IO BD table
+ */
+struct io_bdt {
+	struct iscsi_bd *bd_tbl;
+	dma_addr_t bd_tbl_dma;
+	u16 bd_valid;
+};
+
+
+/**
+ * bnx2i_cmd - iscsi command structure
+ *
+ * @scsi_cmd:           SCSI-ML task pointer corresponding to this iscsi cmd
+ * @sg:                 SG list
+ * @io_tbl:             buffer descriptor (BD) table
+ * @bd_tbl_dma:         buffer descriptor (BD) table's dma address
+ */
+struct bnx2i_cmd {
+	struct iscsi_hdr hdr;
+	struct bnx2i_conn *conn;
+	struct scsi_cmnd *scsi_cmd;
+	struct scatterlist *sg;
+	struct io_bdt io_tbl;
+	dma_addr_t bd_tbl_dma;
+	struct bnx2i_cmd_request req;
+};
+
+
+/**
+ * struct bnx2i_conn - iscsi connection structure
+ *
+ * @cls_conn:              pointer to iscsi cls conn
+ * @hba:                   adapter structure pointer
+ * @iscsi_conn_cid:        iscsi conn id
+ * @fw_cid:                firmware iscsi context id
+ * @ep:                    endpoint structure pointer
+ * @gen_pdu:               login/nopout/logout pdu resources
+ * @violation_notified:    bit mask used to track iscsi error/warning messages
+ *                         already printed out
+ *
+ * iSCSI connection structure
+ */
+struct bnx2i_conn {
+	struct iscsi_cls_conn *cls_conn;
+	struct bnx2i_hba *hba;
+	struct completion cmd_cleanup_cmpl;
+	int is_bound;
+
+	u32 iscsi_conn_cid;
+#define BNX2I_CID_RESERVED	0x5AFF
+	u32 fw_cid;
+
+	struct timer_list poll_timer;
+	/*
+	 * Queue Pair (QP) related structure elements.
+	 */
+	struct bnx2i_endpoint *ep;
+
+	/*
+	 * Buffer for login negotiation process
+	 */
+	struct generic_pdu_resc gen_pdu;
+	u64 violation_notified;
+};
+
+
+
+/**
+ * struct iscsi_cid_queue - Per adapter iscsi cid queue
+ *
+ * @cid_que_base:           queue base memory
+ * @cid_que:                queue memory pointer
+ * @cid_q_prod_idx:         produce index
+ * @cid_q_cons_idx:         consumer index
+ * @cid_q_max_idx:          max index. used to detect wrap around condition
+ * @cid_free_cnt:           queue size
+ * @conn_cid_tbl:           iscsi cid to conn structure mapping table
+ *
+ * Per adapter iSCSI CID Queue
+ */
+struct iscsi_cid_queue {
+	void *cid_que_base;
+	u32 *cid_que;
+	u32 cid_q_prod_idx;
+	u32 cid_q_cons_idx;
+	u32 cid_q_max_idx;
+	u32 cid_free_cnt;
+	struct bnx2i_conn **conn_cid_tbl;
+};
+
+/**
+ * struct bnx2i_hba - bnx2i adapter structure
+ *
+ * @link:                  list head to link elements
+ * @cnic:                  pointer to cnic device
+ * @pcidev:                pointer to pci dev
+ * @netdev:                pointer to netdev structure
+ * @regview:               mapped PCI register space
+ * @age:                   age, incremented by every recovery
+ * @cnic_dev_type:         cnic device type, 5706/5708/5709/57710
+ * @mail_queue_access:     mailbox queue access mode, applicable to 5709 only
+ * @reg_with_cnic:         indicates whether the device is register with CNIC
+ * @adapter_state:         adapter state, UP, GOING_DOWN, LINK_DOWN
+ * @mtu_supported:         Ethernet MTU supported
+ * @shost:                 scsi host pointer
+ * @max_sqes:              SQ size
+ * @max_rqes:              RQ size
+ * @max_cqes:              CQ size
+ * @num_ccell:             number of command cells per connection
+ * @ofld_conns_active:     active connection list
+ * @max_active_conns:      max offload connections supported by this device
+ * @cid_que:               iscsi cid queue
+ * @ep_rdwr_lock:          read / write lock to synchronize various ep lists
+ * @ep_ofld_list:          connection list for pending offload completion
+ * @ep_destroy_list:       connection list for pending offload completion
+ * @mp_bd_tbl:             BD table to be used with middle path requests
+ * @mp_bd_dma:             DMA address of 'mp_bd_tbl' memory buffer
+ * @dummy_buffer:          Dummy buffer to be used with zero length scsicmd reqs
+ * @dummy_buf_dma:         DMA address of 'dummy_buffer' memory buffer
+ * @lock:              	   lock to synchonize access to hba structure
+ * @pci_did:               PCI device ID
+ * @pci_vid:               PCI vendor ID
+ * @pci_sdid:              PCI subsystem device ID
+ * @pci_svid:              PCI subsystem vendor ID
+ * @pci_func:              PCI function number in system pci tree
+ * @pci_devno:             PCI device number in system pci tree
+ * @num_wqe_sent:          statistic counter, total wqe's sent
+ * @num_cqe_rcvd:          statistic counter, total cqe's received
+ * @num_intr_claimed:      statistic counter, total interrupts claimed
+ * @link_changed_count:    statistic counter, num of link change notifications
+ *                         received
+ * @ipaddr_changed_count:  statistic counter, num times IP address changed while
+ *                         at least one connection is offloaded
+ * @num_sess_opened:       statistic counter, total num sessions opened
+ * @num_conn_opened:       statistic counter, total num conns opened on this hba
+ * @ctx_ccell_tasks:       captures number of ccells and tasks supported by
+ *                         currently offloaded connection, used to decode
+ *                         context memory
+ *
+ * Adapter Data Structure
+ */
+struct bnx2i_hba {
+	struct list_head link;
+	struct cnic_dev *cnic;
+	struct pci_dev *pcidev;
+	struct net_device *netdev;
+	void __iomem *regview;
+
+	u32 age;
+	unsigned long cnic_dev_type;
+		#define BNX2I_NX2_DEV_5706		0x0
+		#define BNX2I_NX2_DEV_5708		0x1
+		#define BNX2I_NX2_DEV_5709		0x2
+		#define BNX2I_NX2_DEV_57710		0x3
+	u32 mail_queue_access;
+		#define BNX2I_MQ_KERNEL_MODE		0x0
+		#define BNX2I_MQ_KERNEL_BYPASS_MODE	0x1
+		#define BNX2I_MQ_BIN_MODE		0x2
+	unsigned long  reg_with_cnic;
+		#define BNX2I_CNIC_REGISTERED		1
+
+	unsigned long  adapter_state;
+		#define ADAPTER_STATE_UP		0
+		#define ADAPTER_STATE_GOING_DOWN	1
+		#define ADAPTER_STATE_LINK_DOWN		2
+		#define ADAPTER_STATE_INIT_FAILED	31
+	unsigned int mtu_supported;
+		#define BNX2I_MAX_MTU_SUPPORTED		1500
+
+	struct Scsi_Host *shost;
+
+	u32 max_sqes;
+	u32 max_rqes;
+	u32 max_cqes;
+	u32 num_ccell;
+
+	int ofld_conns_active;
+
+	int max_active_conns;
+	struct iscsi_cid_queue cid_que;
+
+	rwlock_t ep_rdwr_lock;
+	struct list_head ep_ofld_list;
+	struct list_head ep_destroy_list;
+
+	/*
+	 * BD table to be used with MP (Middle Path requests.
+	 */
+	char *mp_bd_tbl;
+	dma_addr_t mp_bd_dma;
+	char *dummy_buffer;
+	dma_addr_t dummy_buf_dma;
+
+	spinlock_t lock;	/* protects hba structure access */
+	struct mutex net_dev_lock;/* sync net device access */
+
+	/*
+	 * PCI related info.
+	 */
+	u16 pci_did;
+	u16 pci_vid;
+	u16 pci_sdid;
+	u16 pci_svid;
+	u16 pci_func;
+	u16 pci_devno;
+
+	/*
+	 * Following are a bunch of statistics useful during development
+	 * and later stage for score boarding.
+	 */
+	u32 num_wqe_sent;
+	u32 num_cqe_rcvd;
+	u32 num_intr_claimed;
+	u32 link_changed_count;
+	u32 ipaddr_changed_count;
+	u32 num_sess_opened;
+	u32 num_conn_opened;
+	unsigned int ctx_ccell_tasks;
+};
+
+
+/*******************************************************************************
+ * 	QP [ SQ / RQ / CQ ] info.
+ ******************************************************************************/
+
+/*
+ * SQ/RQ/CQ generic structure definition
+ */
+struct 	sqe {
+	u8 sqe_byte[BNX2I_SQ_WQE_SIZE];
+};
+
+struct 	rqe {
+	u8 rqe_byte[BNX2I_RQ_WQE_SIZE];
+};
+
+struct 	cqe {
+	u8 cqe_byte[BNX2I_CQE_SIZE];
+};
+
+
+enum {
+#if defined(__LITTLE_ENDIAN)
+	CNIC_EVENT_COAL_INDEX	= 0x0,
+	CNIC_SEND_DOORBELL	= 0x4,
+	CNIC_EVENT_CQ_ARM	= 0x7,
+	CNIC_RECV_DOORBELL	= 0x8
+#elif defined(__BIG_ENDIAN)
+	CNIC_EVENT_COAL_INDEX	= 0x2,
+	CNIC_SEND_DOORBELL	= 0x6,
+	CNIC_EVENT_CQ_ARM	= 0x4,
+	CNIC_RECV_DOORBELL	= 0xa
+#endif
+};
+
+
+/*
+ * CQ DB
+ */
+struct bnx2x_iscsi_cq_pend_cmpl {
+	/* CQ producer, updated by Ustorm */
+	u16 ustrom_prod;
+	/* CQ pending completion counter */
+	u16 pend_cntr;
+};
+
+
+struct bnx2i_5771x_cq_db {
+	struct bnx2x_iscsi_cq_pend_cmpl qp_pend_cmpl[BNX2X_MAX_CQS];
+	/* CQ pending completion ITT array */
+	u16 itt[BNX2X_MAX_CQS];
+	/* Cstorm CQ sequence to notify array, updated by driver */;
+	u16 sqn[BNX2X_MAX_CQS];
+	u32 reserved[4] /* 16 byte allignment */;
+};
+
+
+struct bnx2i_5771x_sq_rq_db {
+	u16 prod_idx;
+	u8 reserved0[14]; /* Pad structure size to 16 bytes */
+};
+
+
+struct bnx2i_5771x_dbell_hdr {
+	u8 header;
+	/* 1 for rx doorbell, 0 for tx doorbell */
+#define B577XX_DOORBELL_HDR_RX				(0x1<<0)
+#define B577XX_DOORBELL_HDR_RX_SHIFT			0
+	/* 0 for normal doorbell, 1 for advertise wnd doorbell */
+#define B577XX_DOORBELL_HDR_DB_TYPE			(0x1<<1)
+#define B577XX_DOORBELL_HDR_DB_TYPE_SHIFT		1
+	/* rdma tx only: DPM transaction size specifier (64/128/256/512B) */
+#define B577XX_DOORBELL_HDR_DPM_SIZE			(0x3<<2)
+#define B577XX_DOORBELL_HDR_DPM_SIZE_SHIFT		2
+	/* connection type */
+#define B577XX_DOORBELL_HDR_CONN_TYPE			(0xF<<4)
+#define B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT		4
+};
+
+struct bnx2i_5771x_dbell {
+	struct bnx2i_5771x_dbell_hdr dbell;
+	u8 pad[3];
+
+};
+
+/**
+ * struct qp_info - QP (share queue region) atrributes structure
+ *
+ * @ctx_base:           ioremapped pci register base to access doorbell register
+ *                      pertaining to this offloaded connection
+ * @sq_virt:            virtual address of send queue (SQ) region
+ * @sq_phys:            DMA address of SQ memory region
+ * @sq_mem_size:        SQ size
+ * @sq_prod_qe:         SQ producer entry pointer
+ * @sq_cons_qe:         SQ consumer entry pointer
+ * @sq_first_qe:        virtaul address of first entry in SQ
+ * @sq_last_qe:         virtaul address of last entry in SQ
+ * @sq_prod_idx:        SQ producer index
+ * @sq_cons_idx:        SQ consumer index
+ * @sqe_left:           number sq entry left
+ * @sq_pgtbl_virt:      page table describing buffer consituting SQ region
+ * @sq_pgtbl_phys:      dma address of 'sq_pgtbl_virt'
+ * @sq_pgtbl_size:      SQ page table size
+ * @cq_virt:            virtual address of completion queue (CQ) region
+ * @cq_phys:            DMA address of RQ memory region
+ * @cq_mem_size:        CQ size
+ * @cq_prod_qe:         CQ producer entry pointer
+ * @cq_cons_qe:         CQ consumer entry pointer
+ * @cq_first_qe:        virtaul address of first entry in CQ
+ * @cq_last_qe:         virtaul address of last entry in CQ
+ * @cq_prod_idx:        CQ producer index
+ * @cq_cons_idx:        CQ consumer index
+ * @cqe_left:           number cq entry left
+ * @cqe_size:           size of each CQ entry
+ * @cqe_exp_seq_sn:     next expected CQE sequence number
+ * @cq_pgtbl_virt:      page table describing buffer consituting CQ region
+ * @cq_pgtbl_phys:      dma address of 'cq_pgtbl_virt'
+ * @cq_pgtbl_size:    	CQ page table size
+ * @rq_virt:            virtual address of receive queue (RQ) region
+ * @rq_phys:            DMA address of RQ memory region
+ * @rq_mem_size:        RQ size
+ * @rq_prod_qe:         RQ producer entry pointer
+ * @rq_cons_qe:         RQ consumer entry pointer
+ * @rq_first_qe:        virtaul address of first entry in RQ
+ * @rq_last_qe:         virtaul address of last entry in RQ
+ * @rq_prod_idx:        RQ producer index
+ * @rq_cons_idx:        RQ consumer index
+ * @rqe_left:           number rq entry left
+ * @rq_pgtbl_virt:      page table describing buffer consituting RQ region
+ * @rq_pgtbl_phys:      dma address of 'rq_pgtbl_virt'
+ * @rq_pgtbl_size:      RQ page table size
+ *
+ * queue pair (QP) is a per connection shared data structure which is used
+ *	to send work requests (SQ), receive completion notifications (CQ)
+ *	and receive asynchoronous / scsi sense info (RQ). 'qp_info' structure
+ *	below holds queue memory, consumer/producer indexes and page table
+ *	information
+ */
+struct qp_info {
+	void __iomem *ctx_base;
+#define DPM_TRIGER_TYPE			0x40
+
+#define BNX2I_570x_QUE_DB_SIZE		0
+#define BNX2I_5771x_QUE_DB_SIZE		16
+	struct sqe *sq_virt;
+	dma_addr_t sq_phys;
+	u32 sq_mem_size;
+
+	struct sqe *sq_prod_qe;
+	struct sqe *sq_cons_qe;
+	struct sqe *sq_first_qe;
+	struct sqe *sq_last_qe;
+	u16 sq_prod_idx;
+	u16 sq_cons_idx;
+	u32 sqe_left;
+
+	void *sq_pgtbl_virt;
+	dma_addr_t sq_pgtbl_phys;
+	u32 sq_pgtbl_size;	/* set to PAGE_SIZE for 5708 & 5709 */
+
+	struct cqe *cq_virt;
+	dma_addr_t cq_phys;
+	u32 cq_mem_size;
+
+	struct cqe *cq_prod_qe;
+	struct cqe *cq_cons_qe;
+	struct cqe *cq_first_qe;
+	struct cqe *cq_last_qe;
+	u16 cq_prod_idx;
+	u16 cq_cons_idx;
+	u32 cqe_left;
+	u32 cqe_size;
+	u32 cqe_exp_seq_sn;
+
+	void *cq_pgtbl_virt;
+	dma_addr_t cq_pgtbl_phys;
+	u32 cq_pgtbl_size;	/* set to PAGE_SIZE for 5708 & 5709 */
+
+	struct rqe *rq_virt;
+	dma_addr_t rq_phys;
+	u32 rq_mem_size;
+
+	struct rqe *rq_prod_qe;
+	struct rqe *rq_cons_qe;
+	struct rqe *rq_first_qe;
+	struct rqe *rq_last_qe;
+	u16 rq_prod_idx;
+	u16 rq_cons_idx;
+	u32 rqe_left;
+
+	void *rq_pgtbl_virt;
+	dma_addr_t rq_pgtbl_phys;
+	u32 rq_pgtbl_size;	/* set to PAGE_SIZE for 5708 & 5709 */
+};
+
+
+
+/*
+ * CID handles
+ */
+struct ep_handles {
+	u32 fw_cid;
+	u32 drv_iscsi_cid;
+	u16 pg_cid;
+	u16 rsvd;
+};
+
+
+enum {
+	EP_STATE_IDLE                   = 0x0,
+	EP_STATE_PG_OFLD_START          = 0x1,
+	EP_STATE_PG_OFLD_COMPL          = 0x2,
+	EP_STATE_OFLD_START             = 0x4,
+	EP_STATE_OFLD_COMPL             = 0x8,
+	EP_STATE_CONNECT_START          = 0x10,
+	EP_STATE_CONNECT_COMPL          = 0x20,
+	EP_STATE_ULP_UPDATE_START       = 0x40,
+	EP_STATE_ULP_UPDATE_COMPL       = 0x80,
+	EP_STATE_DISCONN_START          = 0x100,
+	EP_STATE_DISCONN_COMPL          = 0x200,
+	EP_STATE_CLEANUP_START          = 0x400,
+	EP_STATE_CLEANUP_CMPL           = 0x800,
+	EP_STATE_TCP_FIN_RCVD           = 0x1000,
+	EP_STATE_TCP_RST_RCVD           = 0x2000,
+	EP_STATE_PG_OFLD_FAILED         = 0x1000000,
+	EP_STATE_ULP_UPDATE_FAILED      = 0x2000000,
+	EP_STATE_CLEANUP_FAILED         = 0x4000000,
+	EP_STATE_OFLD_FAILED            = 0x8000000,
+	EP_STATE_CONNECT_FAILED         = 0x10000000,
+	EP_STATE_DISCONN_TIMEDOUT       = 0x20000000,
+};
+
+/**
+ * struct bnx2i_endpoint - representation of tcp connection in NX2 world
+ *
+ * @link:               list head to link elements
+ * @hba:                adapter to which this connection belongs
+ * @conn:               iscsi connection this EP is linked to
+ * @sess:               iscsi session this EP is linked to
+ * @cm_sk:              cnic sock struct
+ * @hba_age:            age to detect if 'iscsid' issues ep_disconnect()
+ *                      after HBA reset is completed by bnx2i/cnic/bnx2
+ *                      modules
+ * @state:              tracks offload connection state machine
+ * @teardown_mode:      indicates if conn teardown is abortive or orderly
+ * @qp:                 QP information
+ * @ids:                contains chip allocated *context id* & driver assigned
+ *                      *iscsi cid*
+ * @ofld_timer:         offload timer to detect timeout
+ * @ofld_wait:          wait queue
+ *
+ * Endpoint Structure - equivalent of tcp socket structure
+ */
+struct bnx2i_endpoint {
+	struct list_head link;
+	struct bnx2i_hba *hba;
+	struct bnx2i_conn *conn;
+	struct cnic_sock *cm_sk;
+	u32 hba_age;
+	u32 state;
+	unsigned long timestamp;
+	int num_active_cmds;
+
+	struct qp_info qp;
+	struct ep_handles ids;
+		#define ep_iscsi_cid	ids.drv_iscsi_cid
+		#define ep_cid		ids.fw_cid
+		#define ep_pg_cid	ids.pg_cid
+	struct timer_list ofld_timer;
+	wait_queue_head_t ofld_wait;
+};
+
+
+
+/* Global variables */
+extern unsigned int error_mask1, error_mask2;
+extern u64 iscsi_error_mask;
+extern unsigned int en_tcp_dack;
+extern unsigned int event_coal_div;
+
+extern struct scsi_transport_template *bnx2i_scsi_xport_template;
+extern struct iscsi_transport bnx2i_iscsi_transport;
+extern struct cnic_ulp_ops bnx2i_cnic_cb;
+
+extern unsigned int sq_size;
+extern unsigned int rq_size;
+
+extern struct device_attribute *bnx2i_dev_attributes[];
+
+
+
+/*
+ * Function Prototypes
+ */
+extern void bnx2i_identify_device(struct bnx2i_hba *hba);
+extern void bnx2i_register_device(struct bnx2i_hba *hba);
+
+extern void bnx2i_ulp_init(struct cnic_dev *dev);
+extern void bnx2i_ulp_exit(struct cnic_dev *dev);
+extern void bnx2i_start(void *handle);
+extern void bnx2i_stop(void *handle);
+extern void bnx2i_reg_dev_all(void);
+extern void bnx2i_unreg_dev_all(void);
+extern struct bnx2i_hba *get_adapter_list_head(void);
+
+struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba,
+					  u16 iscsi_cid);
+
+int bnx2i_alloc_ep_pool(void);
+void bnx2i_release_ep_pool(void);
+struct bnx2i_endpoint *bnx2i_ep_ofld_list_next(struct bnx2i_hba *hba);
+struct bnx2i_endpoint *bnx2i_ep_destroy_list_next(struct bnx2i_hba *hba);
+
+struct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic);
+
+struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic);
+void bnx2i_free_hba(struct bnx2i_hba *hba);
+
+void bnx2i_get_rq_buf(struct bnx2i_conn *conn, char *ptr, int len);
+void bnx2i_put_rq_buf(struct bnx2i_conn *conn, int count);
+
+void bnx2i_iscsi_unmap_sg_list(struct bnx2i_cmd *cmd);
+
+void bnx2i_drop_session(struct iscsi_cls_session *session);
+
+extern int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba);
+extern int bnx2i_send_iscsi_login(struct bnx2i_conn *conn,
+				  struct iscsi_task *mtask);
+extern int bnx2i_send_iscsi_tmf(struct bnx2i_conn *conn,
+				  struct iscsi_task *mtask);
+extern int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *conn,
+				    struct bnx2i_cmd *cmnd);
+extern int bnx2i_send_iscsi_nopout(struct bnx2i_conn *conn,
+				   struct iscsi_task *mtask, u32 ttt,
+				   char *datap, int data_len, int unsol);
+extern int bnx2i_send_iscsi_logout(struct bnx2i_conn *conn,
+				   struct iscsi_task *mtask);
+extern void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba,
+				       struct bnx2i_cmd *cmd);
+extern void bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba,
+				     struct bnx2i_endpoint *ep);
+extern void bnx2i_update_iscsi_conn(struct iscsi_conn *conn);
+extern void bnx2i_send_conn_destroy(struct bnx2i_hba *hba,
+				    struct bnx2i_endpoint *ep);
+
+extern int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba,
+			       struct bnx2i_endpoint *ep);
+extern void bnx2i_free_qp_resc(struct bnx2i_hba *hba,
+			       struct bnx2i_endpoint *ep);
+extern void bnx2i_ep_ofld_timer(unsigned long data);
+extern struct bnx2i_endpoint *bnx2i_find_ep_in_ofld_list(
+		struct bnx2i_hba *hba, u32 iscsi_cid);
+extern struct bnx2i_endpoint *bnx2i_find_ep_in_destroy_list(
+		struct bnx2i_hba *hba, u32 iscsi_cid);
+
+extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep);
+extern void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action);
+
+/* Debug related function prototypes */
+extern void bnx2i_print_pend_cmd_queue(struct bnx2i_conn *conn);
+extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn);
+extern void bnx2i_print_xmit_pdu_queue(struct bnx2i_conn *conn);
+extern void bnx2i_print_recv_state(struct bnx2i_conn *conn);
+
+#endif
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
new file mode 100644
index 0000000..906cef5
--- /dev/null
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -0,0 +1,2405 @@
+/* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver.
+ *
+ * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
+ * Copyright (c) 2007, 2008 Mike Christie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ */
+
+#include <scsi/scsi_tcq.h>
+#include <scsi/libiscsi.h>
+#include "bnx2i.h"
+
+/**
+ * bnx2i_get_cid_num - get cid from ep
+ * @ep: 	endpoint pointer
+ *
+ * Only applicable to 57710 family of devices
+ */
+static u32 bnx2i_get_cid_num(struct bnx2i_endpoint *ep)
+{
+	u32 cid;
+
+	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
+		cid = ep->ep_cid;
+	else
+		cid = GET_CID_NUM(ep->ep_cid);
+	return cid;
+}
+
+
+/**
+ * bnx2i_adjust_qp_size - Adjust SQ/RQ/CQ size for 57710 device type
+ * @hba: 		Adapter for which adjustments is to be made
+ *
+ * Only applicable to 57710 family of devices
+ */
+static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
+{
+	u32 num_elements_per_pg;
+
+	if (test_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type) ||
+	    test_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type) ||
+	    test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) {
+		if (!is_power_of_2(hba->max_sqes))
+			hba->max_sqes = rounddown_pow_of_two(hba->max_sqes);
+
+		if (!is_power_of_2(hba->max_rqes))
+			hba->max_rqes = rounddown_pow_of_two(hba->max_rqes);
+	}
+
+	/* Adjust each queue size if the user selection does not
+	 * yield integral num of page buffers
+	 */
+	/* adjust SQ */
+	num_elements_per_pg = PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
+	if (hba->max_sqes < num_elements_per_pg)
+		hba->max_sqes = num_elements_per_pg;
+	else if (hba->max_sqes % num_elements_per_pg)
+		hba->max_sqes = (hba->max_sqes + num_elements_per_pg - 1) &
+				 ~(num_elements_per_pg - 1);
+
+	/* adjust CQ */
+	num_elements_per_pg = PAGE_SIZE / BNX2I_CQE_SIZE;
+	if (hba->max_cqes < num_elements_per_pg)
+		hba->max_cqes = num_elements_per_pg;
+	else if (hba->max_cqes % num_elements_per_pg)
+		hba->max_cqes = (hba->max_cqes + num_elements_per_pg - 1) &
+				 ~(num_elements_per_pg - 1);
+
+	/* adjust RQ */
+	num_elements_per_pg = PAGE_SIZE / BNX2I_RQ_WQE_SIZE;
+	if (hba->max_rqes < num_elements_per_pg)
+		hba->max_rqes = num_elements_per_pg;
+	else if (hba->max_rqes % num_elements_per_pg)
+		hba->max_rqes = (hba->max_rqes + num_elements_per_pg - 1) &
+				 ~(num_elements_per_pg - 1);
+}
+
+
+/**
+ * bnx2i_get_link_state - get network interface link state
+ * @hba:	adapter instance pointer
+ *
+ * updates adapter structure flag based on netdev state
+ */
+static void bnx2i_get_link_state(struct bnx2i_hba *hba)
+{
+	if (test_bit(__LINK_STATE_NOCARRIER, &hba->netdev->state))
+		set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
+	else
+		clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
+}
+
+
+/**
+ * bnx2i_iscsi_license_error - displays iscsi license related error message
+ * @hba:		adapter instance pointer
+ * @error_code:		error classification
+ *
+ * Puts out an error log when driver is unable to offload iscsi connection
+ *	due to license restrictions
+ */
+static void bnx2i_iscsi_license_error(struct bnx2i_hba *hba, u32 error_code)
+{
+	if (error_code == ISCSI_KCQE_COMPLETION_STATUS_ISCSI_NOT_SUPPORTED)
+		/* iSCSI offload not supported on this device */
+		printk(KERN_ERR "bnx2i: iSCSI not supported, dev=%s\n",
+				hba->netdev->name);
+	if (error_code == ISCSI_KCQE_COMPLETION_STATUS_LOM_ISCSI_NOT_ENABLED)
+		/* iSCSI offload not supported on this LOM device */
+		printk(KERN_ERR "bnx2i: LOM is not enable to "
+				"offload iSCSI connections, dev=%s\n",
+				hba->netdev->name);
+	set_bit(ADAPTER_STATE_INIT_FAILED, &hba->adapter_state);
+}
+
+
+/**
+ * bnx2i_arm_cq_event_coalescing - arms CQ to enable EQ notification
+ * @ep:		endpoint (transport indentifier) structure
+ * @action:	action, ARM or DISARM. For now only ARM_CQE is used
+ *
+ * Arm'ing CQ will enable chip to generate global EQ events inorder to interrupt
+ *	the driver. EQ event is generated CQ index is hit or at least 1 CQ is
+ *	outstanding and on chip timer expires
+ */
+void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action)
+{
+	struct bnx2i_5771x_cq_db *cq_db;
+	u16 cq_index;
+
+	if (!test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
+		return;
+
+	if (action == CNIC_ARM_CQE) {
+		cq_index = ep->qp.cqe_exp_seq_sn +
+			   ep->num_active_cmds / event_coal_div;
+		cq_index %= (ep->qp.cqe_size * 2 + 1);
+		if (!cq_index) {
+			cq_index = 1;
+			cq_db = (struct bnx2i_5771x_cq_db *)
+					ep->qp.cq_pgtbl_virt;
+			cq_db->sqn[0] = cq_index;
+		}
+	}
+}
+
+
+/**
+ * bnx2i_get_rq_buf - copy RQ buffer contents to driver buffer
+ * @conn:		iscsi connection on which RQ event occured
+ * @ptr:		driver buffer to which RQ buffer contents is to
+ *			be copied
+ * @len:		length of valid data inside RQ buf
+ *
+ * Copies RQ buffer contents from shared (DMA'able) memory region to
+ *	driver buffer. RQ is used to DMA unsolicitated iscsi pdu's and
+ *	scsi sense info
+ */
+void bnx2i_get_rq_buf(struct bnx2i_conn *bnx2i_conn, char *ptr, int len)
+{
+	if (!bnx2i_conn->ep->qp.rqe_left)
+		return;
+
+	bnx2i_conn->ep->qp.rqe_left--;
+	memcpy(ptr, (u8 *) bnx2i_conn->ep->qp.rq_cons_qe, len);
+	if (bnx2i_conn->ep->qp.rq_cons_qe == bnx2i_conn->ep->qp.rq_last_qe) {
+		bnx2i_conn->ep->qp.rq_cons_qe = bnx2i_conn->ep->qp.rq_first_qe;
+		bnx2i_conn->ep->qp.rq_cons_idx = 0;
+	} else {
+		bnx2i_conn->ep->qp.rq_cons_qe++;
+		bnx2i_conn->ep->qp.rq_cons_idx++;
+	}
+}
+
+
+static void bnx2i_ring_577xx_doorbell(struct bnx2i_conn *conn)
+{
+	struct bnx2i_5771x_dbell dbell;
+	u32 msg;
+
+	memset(&dbell, 0, sizeof(dbell));
+	dbell.dbell.header = (B577XX_ISCSI_CONNECTION_TYPE <<
+			      B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT);
+	msg = *((u32 *)&dbell);
+	/* TODO : get doorbell register mapping */
+	writel(cpu_to_le32(msg), conn->ep->qp.ctx_base);
+}
+
+
+/**
+ * bnx2i_put_rq_buf - Replenish RQ buffer, if required ring on chip doorbell
+ * @conn:	iscsi connection on which event to post
+ * @count:	number of RQ buffer being posted to chip
+ *
+ * No need to ring hardware doorbell for 57710 family of devices
+ */
+void bnx2i_put_rq_buf(struct bnx2i_conn *bnx2i_conn, int count)
+{
+	struct bnx2i_5771x_sq_rq_db *rq_db;
+	u16 hi_bit = (bnx2i_conn->ep->qp.rq_prod_idx & 0x8000);
+	struct bnx2i_endpoint *ep = bnx2i_conn->ep;
+
+	ep->qp.rqe_left += count;
+	ep->qp.rq_prod_idx &= 0x7FFF;
+	ep->qp.rq_prod_idx += count;
+
+	if (ep->qp.rq_prod_idx > bnx2i_conn->hba->max_rqes) {
+		ep->qp.rq_prod_idx %= bnx2i_conn->hba->max_rqes;
+		if (!hi_bit)
+			ep->qp.rq_prod_idx |= 0x8000;
+	} else
+		ep->qp.rq_prod_idx |= hi_bit;
+
+	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
+		rq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.rq_pgtbl_virt;
+		rq_db->prod_idx = ep->qp.rq_prod_idx;
+		/* no need to ring hardware doorbell for 57710 */
+	} else {
+		writew(ep->qp.rq_prod_idx,
+		       ep->qp.ctx_base + CNIC_RECV_DOORBELL);
+	}
+	mmiowb();
+}
+
+
+/**
+ * bnx2i_ring_sq_dbell - Ring SQ doorbell to wake-up the processing engine
+ * @conn: 		iscsi connection to which new SQ entries belong
+ * @count: 		number of SQ WQEs to post
+ *
+ * SQ DB is updated in host memory and TX Doorbell is rung for 57710 family
+ *	of devices. For 5706/5708/5709 new SQ WQE count is written into the
+ *	doorbell register
+ */
+static void bnx2i_ring_sq_dbell(struct bnx2i_conn *bnx2i_conn, int count)
+{
+	struct bnx2i_5771x_sq_rq_db *sq_db;
+	struct bnx2i_endpoint *ep = bnx2i_conn->ep;
+
+	ep->num_active_cmds++;
+	wmb();	/* flush SQ WQE memory before the doorbell is rung */
+	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
+		sq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.sq_pgtbl_virt;
+		sq_db->prod_idx = ep->qp.sq_prod_idx;
+		bnx2i_ring_577xx_doorbell(bnx2i_conn);
+	} else
+		writew(count, ep->qp.ctx_base + CNIC_SEND_DOORBELL);
+
+	mmiowb(); /* flush posted PCI writes */
+}
+
+
+/**
+ * bnx2i_ring_dbell_update_sq_params - update SQ driver parameters
+ * @conn:	iscsi connection to which new SQ entries belong
+ * @count:	number of SQ WQEs to post
+ *
+ * this routine will update SQ driver parameters and ring the doorbell
+ */
+static void bnx2i_ring_dbell_update_sq_params(struct bnx2i_conn *bnx2i_conn,
+					      int count)
+{
+	int tmp_cnt;
+
+	if (count == 1) {
+		if (bnx2i_conn->ep->qp.sq_prod_qe ==
+		    bnx2i_conn->ep->qp.sq_last_qe)
+			bnx2i_conn->ep->qp.sq_prod_qe =
+						bnx2i_conn->ep->qp.sq_first_qe;
+		else
+			bnx2i_conn->ep->qp.sq_prod_qe++;
+	} else {
+		if ((bnx2i_conn->ep->qp.sq_prod_qe + count) <=
+		    bnx2i_conn->ep->qp.sq_last_qe)
+			bnx2i_conn->ep->qp.sq_prod_qe += count;
+		else {
+			tmp_cnt = bnx2i_conn->ep->qp.sq_last_qe -
+				bnx2i_conn->ep->qp.sq_prod_qe;
+			bnx2i_conn->ep->qp.sq_prod_qe =
+				&bnx2i_conn->ep->qp.sq_first_qe[count -
+								(tmp_cnt + 1)];
+		}
+	}
+	bnx2i_conn->ep->qp.sq_prod_idx += count;
+	/* Ring the doorbell */
+	bnx2i_ring_sq_dbell(bnx2i_conn, bnx2i_conn->ep->qp.sq_prod_idx);
+}
+
+
+/**
+ * bnx2i_send_iscsi_login - post iSCSI login request MP WQE to hardware
+ * @conn:	iscsi connection
+ * @cmd:	driver command structure which is requesting
+ *		a WQE to sent to chip for further processing
+ *
+ * prepare and post an iSCSI Login request WQE to CNIC firmware
+ */
+int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn,
+			   struct iscsi_task *task)
+{
+	struct bnx2i_cmd *bnx2i_cmd;
+	struct bnx2i_login_request *login_wqe;
+	struct iscsi_login *login_hdr;
+	u32 dword;
+
+	bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data;
+	login_hdr = (struct iscsi_login *)task->hdr;
+	login_wqe = (struct bnx2i_login_request *)
+						bnx2i_conn->ep->qp.sq_prod_qe;
+
+	login_wqe->op_code = login_hdr->opcode;
+	login_wqe->op_attr = login_hdr->flags;
+	login_wqe->version_max = login_hdr->max_version;
+	login_wqe->version_min = login_hdr->min_version;
+	login_wqe->data_length = ntoh24(login_hdr->dlength);
+	login_wqe->isid_lo = *((u32 *) login_hdr->isid);
+	login_wqe->isid_hi = *((u16 *) login_hdr->isid + 2);
+	login_wqe->tsih = login_hdr->tsih;
+	login_wqe->itt = task->itt |
+		(ISCSI_TASK_TYPE_MPATH << ISCSI_LOGIN_REQUEST_TYPE_SHIFT);
+	login_wqe->cid = login_hdr->cid;
+
+	login_wqe->cmd_sn = be32_to_cpu(login_hdr->cmdsn);
+	login_wqe->exp_stat_sn = be32_to_cpu(login_hdr->exp_statsn);
+
+	login_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma;
+	login_wqe->resp_bd_list_addr_hi =
+		(u32) ((u64) bnx2i_conn->gen_pdu.resp_bd_dma >> 32);
+
+	dword = ((1 << ISCSI_LOGIN_REQUEST_NUM_RESP_BDS_SHIFT) |
+		 (bnx2i_conn->gen_pdu.resp_buf_size <<
+		  ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH_SHIFT));
+	login_wqe->resp_buffer = dword;
+	login_wqe->flags = 0;
+	login_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma;
+	login_wqe->bd_list_addr_hi =
+		(u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32);
+	login_wqe->num_bds = 1;
+	login_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
+
+	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
+	return 0;
+}
+
+/**
+ * bnx2i_send_iscsi_tmf - post iSCSI task management request MP WQE to hardware
+ * @conn:	iscsi connection
+ * @mtask:	driver command structure which is requesting
+ *		a WQE to sent to chip for further processing
+ *
+ * prepare and post an iSCSI Login request WQE to CNIC firmware
+ */
+int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn,
+			 struct iscsi_task *mtask)
+{
+	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+	struct iscsi_tm *tmfabort_hdr;
+	struct scsi_cmnd *ref_sc;
+	struct iscsi_task *ctask;
+	struct bnx2i_cmd *bnx2i_cmd;
+	struct bnx2i_tmf_request *tmfabort_wqe;
+	u32 dword;
+
+	bnx2i_cmd = (struct bnx2i_cmd *)mtask->dd_data;
+	tmfabort_hdr = (struct iscsi_tm *)mtask->hdr;
+	tmfabort_wqe = (struct bnx2i_tmf_request *)
+						bnx2i_conn->ep->qp.sq_prod_qe;
+
+	tmfabort_wqe->op_code = tmfabort_hdr->opcode;
+	tmfabort_wqe->op_attr = 0;
+	tmfabort_wqe->op_attr =
+		ISCSI_TMF_REQUEST_ALWAYS_ONE | ISCSI_TM_FUNC_ABORT_TASK;
+	tmfabort_wqe->lun[0] = be32_to_cpu(tmfabort_hdr->lun[0]);
+	tmfabort_wqe->lun[1] = be32_to_cpu(tmfabort_hdr->lun[1]);
+
+	tmfabort_wqe->itt = (mtask->itt | (ISCSI_TASK_TYPE_MPATH << 14));
+	tmfabort_wqe->reserved2 = 0;
+	tmfabort_wqe->cmd_sn = be32_to_cpu(tmfabort_hdr->cmdsn);
+
+	ctask = iscsi_itt_to_task(conn, tmfabort_hdr->rtt);
+	if (!ctask || ctask->sc)
+		/*
+		 * the iscsi layer must have completed the cmd while this
+		 * was starting up.
+		 */
+		return 0;
+	ref_sc = ctask->sc;
+
+	if (ref_sc->sc_data_direction == DMA_TO_DEVICE)
+		dword = (ISCSI_TASK_TYPE_WRITE << ISCSI_CMD_REQUEST_TYPE_SHIFT);
+	else
+		dword = (ISCSI_TASK_TYPE_READ << ISCSI_CMD_REQUEST_TYPE_SHIFT);
+	tmfabort_wqe->ref_itt = (dword | tmfabort_hdr->rtt);
+	tmfabort_wqe->ref_cmd_sn = be32_to_cpu(tmfabort_hdr->refcmdsn);
+
+	tmfabort_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma;
+	tmfabort_wqe->bd_list_addr_hi = (u32)
+				((u64) bnx2i_conn->hba->mp_bd_dma >> 32);
+	tmfabort_wqe->num_bds = 1;
+	tmfabort_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
+
+	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
+	return 0;
+}
+
+/**
+ * bnx2i_send_iscsi_scsicmd - post iSCSI scsicmd request WQE to hardware
+ * @conn:	iscsi connection
+ * @cmd:	driver command structure which is requesting
+ *		a WQE to sent to chip for further processing
+ *
+ * prepare and post an iSCSI SCSI-CMD request WQE to CNIC firmware
+ */
+int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *bnx2i_conn,
+			     struct bnx2i_cmd *cmd)
+{
+	struct bnx2i_cmd_request *scsi_cmd_wqe;
+
+	scsi_cmd_wqe = (struct bnx2i_cmd_request *)
+						bnx2i_conn->ep->qp.sq_prod_qe;
+	memcpy(scsi_cmd_wqe, &cmd->req, sizeof(struct bnx2i_cmd_request));
+	scsi_cmd_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
+
+	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
+	return 0;
+}
+
+/**
+ * bnx2i_send_iscsi_nopout - post iSCSI NOPOUT request WQE to hardware
+ * @conn:		iscsi connection
+ * @cmd:		driver command structure which is requesting
+ *			a WQE to sent to chip for further processing
+ * @ttt:		TTT to be used when building pdu header
+ * @datap:		payload buffer pointer
+ * @data_len:		payload data length
+ * @unsol:		indicated whether nopout pdu is unsolicited pdu or
+ *			in response to target's NOPIN w/ TTT != FFFFFFFF
+ *
+ * prepare and post a nopout request WQE to CNIC firmware
+ */
+int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn,
+			    struct iscsi_task *task, u32 ttt,
+			    char *datap, int data_len, int unsol)
+{
+	struct bnx2i_endpoint *ep = bnx2i_conn->ep;
+	struct bnx2i_cmd *bnx2i_cmd;
+	struct bnx2i_nop_out_request *nopout_wqe;
+	struct iscsi_nopout *nopout_hdr;
+
+	bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data;
+	nopout_hdr = (struct iscsi_nopout *)task->hdr;
+	nopout_wqe = (struct bnx2i_nop_out_request *)ep->qp.sq_prod_qe;
+	nopout_wqe->op_code = nopout_hdr->opcode;
+	nopout_wqe->op_attr = ISCSI_FLAG_CMD_FINAL;
+	memcpy(nopout_wqe->lun, nopout_hdr->lun, 8);
+
+	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
+		u32 tmp = nopout_hdr->lun[0];
+		/* 57710 requires LUN field to be swapped */
+		nopout_hdr->lun[0] = nopout_hdr->lun[1];
+		nopout_hdr->lun[1] = tmp;
+	}
+
+	nopout_wqe->itt = ((u16)task->itt |
+			   (ISCSI_TASK_TYPE_MPATH <<
+			    ISCSI_TMF_REQUEST_TYPE_SHIFT));
+	nopout_wqe->ttt = ttt;
+	nopout_wqe->flags = 0;
+	if (!unsol)
+		nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION;
+	else if (nopout_hdr->itt == RESERVED_ITT)
+		nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION;
+
+	nopout_wqe->cmd_sn = be32_to_cpu(nopout_hdr->cmdsn);
+	nopout_wqe->data_length = data_len;
+	if (data_len) {
+		/* handle payload data, not required in first release */
+		printk(KERN_ALERT "NOPOUT: WARNING!! payload len != 0\n");
+	} else {
+		nopout_wqe->bd_list_addr_lo = (u32)
+					bnx2i_conn->hba->mp_bd_dma;
+		nopout_wqe->bd_list_addr_hi =
+			(u32) ((u64) bnx2i_conn->hba->mp_bd_dma >> 32);
+		nopout_wqe->num_bds = 1;
+	}
+	nopout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
+
+	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
+	return 0;
+}
+
+
+/**
+ * bnx2i_send_iscsi_logout - post iSCSI logout request WQE to hardware
+ * @conn:	iscsi connection
+ * @cmd:	driver command structure which is requesting
+ *		a WQE to sent to chip for further processing
+ *
+ * prepare and post logout request WQE to CNIC firmware
+ */
+int bnx2i_send_iscsi_logout(struct bnx2i_conn *bnx2i_conn,
+			    struct iscsi_task *task)
+{
+	struct bnx2i_cmd *bnx2i_cmd;
+	struct bnx2i_logout_request *logout_wqe;
+	struct iscsi_logout *logout_hdr;
+
+	bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data;
+	logout_hdr = (struct iscsi_logout *)task->hdr;
+
+	logout_wqe = (struct bnx2i_logout_request *)
+						bnx2i_conn->ep->qp.sq_prod_qe;
+	memset(logout_wqe, 0x00, sizeof(struct bnx2i_logout_request));
+
+	logout_wqe->op_code = logout_hdr->opcode;
+	logout_wqe->cmd_sn = be32_to_cpu(logout_hdr->cmdsn);
+	logout_wqe->op_attr =
+			logout_hdr->flags | ISCSI_LOGOUT_REQUEST_ALWAYS_ONE;
+	logout_wqe->itt = ((u16)task->itt |
+			   (ISCSI_TASK_TYPE_MPATH <<
+			    ISCSI_LOGOUT_REQUEST_TYPE_SHIFT));
+	logout_wqe->data_length = 0;
+	logout_wqe->cid = 0;
+
+	logout_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma;
+	logout_wqe->bd_list_addr_hi = (u32)
+				((u64) bnx2i_conn->hba->mp_bd_dma >> 32);
+	logout_wqe->num_bds = 1;
+	logout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
+
+	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
+	return 0;
+}
+
+
+/**
+ * bnx2i_update_iscsi_conn - post iSCSI logout request WQE to hardware
+ * @conn:	iscsi connection which requires iscsi parameter update
+ *
+ * sends down iSCSI Conn Update request to move iSCSI conn to FFP
+ */
+void bnx2i_update_iscsi_conn(struct iscsi_conn *conn)
+{
+	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+	struct bnx2i_hba *hba = bnx2i_conn->hba;
+	struct kwqe *kwqe_arr[2];
+	struct iscsi_kwqe_conn_update *update_wqe;
+	struct iscsi_kwqe_conn_update conn_update_kwqe;
+
+	update_wqe = &conn_update_kwqe;
+
+	update_wqe->hdr.op_code = ISCSI_KWQE_OPCODE_UPDATE_CONN;
+	update_wqe->hdr.flags =
+		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+	/* 5771x requires conn context id to be passed as is */
+	if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_conn->ep->hba->cnic_dev_type))
+		update_wqe->context_id = bnx2i_conn->ep->ep_cid;
+	else
+		update_wqe->context_id = (bnx2i_conn->ep->ep_cid >> 7);
+	update_wqe->conn_flags = 0;
+	if (conn->hdrdgst_en)
+		update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST;
+	if (conn->datadgst_en)
+		update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST;
+	if (conn->session->initial_r2t_en)
+		update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T;
+	if (conn->session->imm_data_en)
+		update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA;
+
+	update_wqe->max_send_pdu_length = conn->max_xmit_dlength;
+	update_wqe->max_recv_pdu_length = conn->max_recv_dlength;
+	update_wqe->first_burst_length = conn->session->first_burst;
+	update_wqe->max_burst_length = conn->session->max_burst;
+	update_wqe->exp_stat_sn = conn->exp_statsn;
+	update_wqe->max_outstanding_r2ts = conn->session->max_r2t;
+	update_wqe->session_error_recovery_level = conn->session->erl;
+	iscsi_conn_printk(KERN_ALERT, conn,
+			  "bnx2i: conn update - MBL 0x%x FBL 0x%x"
+			  "MRDSL_I 0x%x MRDSL_T 0x%x \n",
+			  update_wqe->max_burst_length,
+			  update_wqe->first_burst_length,
+			  update_wqe->max_recv_pdu_length,
+			  update_wqe->max_send_pdu_length);
+
+	kwqe_arr[0] = (struct kwqe *) update_wqe;
+	if (hba->cnic && hba->cnic->submit_kwqes)
+		hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1);
+}
+
+
+/**
+ * bnx2i_ep_ofld_timer - post iSCSI logout request WQE to hardware
+ * @data:	endpoint (transport handle) structure pointer
+ *
+ * routine to handle connection offload/destroy request timeout
+ */
+void bnx2i_ep_ofld_timer(unsigned long data)
+{
+	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) data;
+
+	if (ep->state == EP_STATE_OFLD_START) {
+		printk(KERN_ALERT "ofld_timer: CONN_OFLD timeout\n");
+		ep->state = EP_STATE_OFLD_FAILED;
+	} else if (ep->state == EP_STATE_DISCONN_START) {
+		printk(KERN_ALERT "ofld_timer: CONN_DISCON timeout\n");
+		ep->state = EP_STATE_DISCONN_TIMEDOUT;
+	} else if (ep->state == EP_STATE_CLEANUP_START) {
+		printk(KERN_ALERT "ofld_timer: CONN_CLEANUP timeout\n");
+		ep->state = EP_STATE_CLEANUP_FAILED;
+	}
+
+	wake_up_interruptible(&ep->ofld_wait);
+}
+
+
+static int bnx2i_power_of2(u32 val)
+{
+	u32 power = 0;
+	if (val & (val - 1))
+		return power;
+	val--;
+	while (val) {
+		val = val >> 1;
+		power++;
+	}
+	return power;
+}
+
+
+/**
+ * bnx2i_send_cmd_cleanup_req - send iscsi cmd context clean-up request
+ * @hba:	adapter structure pointer
+ * @cmd:	driver command structure which is requesting
+ *		a WQE to sent to chip for further processing
+ *
+ * prepares and posts CONN_OFLD_REQ1/2 KWQE
+ */
+void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd)
+{
+	struct bnx2i_cleanup_request *cmd_cleanup;
+
+	cmd_cleanup =
+		(struct bnx2i_cleanup_request *)cmd->conn->ep->qp.sq_prod_qe;
+	memset(cmd_cleanup, 0x00, sizeof(struct bnx2i_cleanup_request));
+
+	cmd_cleanup->op_code = ISCSI_OPCODE_CLEANUP_REQUEST;
+	cmd_cleanup->itt = cmd->req.itt;
+	cmd_cleanup->cq_index = 0; /* CQ# used for completion, 5771x only */
+
+	bnx2i_ring_dbell_update_sq_params(cmd->conn, 1);
+}
+
+
+/**
+ * bnx2i_send_conn_destroy - initiates iscsi connection teardown process
+ * @hba:	adapter structure pointer
+ * @ep:		endpoint (transport indentifier) structure
+ *
+ * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE to initiate
+ * 	iscsi connection context clean-up process
+ */
+void bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
+{
+	struct kwqe *kwqe_arr[2];
+	struct iscsi_kwqe_conn_destroy conn_cleanup;
+
+	memset(&conn_cleanup, 0x00, sizeof(struct iscsi_kwqe_conn_destroy));
+
+	conn_cleanup.hdr.op_code = ISCSI_KWQE_OPCODE_DESTROY_CONN;
+	conn_cleanup.hdr.flags =
+		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+	/* 5771x requires conn context id to be passed as is */
+	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
+		conn_cleanup.context_id = ep->ep_cid;
+	else
+		conn_cleanup.context_id = (ep->ep_cid >> 7);
+
+	conn_cleanup.reserved0 = (u16)ep->ep_iscsi_cid;
+
+	kwqe_arr[0] = (struct kwqe *) &conn_cleanup;
+	if (hba->cnic && hba->cnic->submit_kwqes)
+		hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1);
+}
+
+
+/**
+ * bnx2i_570x_send_conn_ofld_req - initiates iscsi conn context setup process
+ * @hba: 		adapter structure pointer
+ * @ep: 		endpoint (transport indentifier) structure
+ *
+ * 5706/5708/5709 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE
+ */
+static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
+					  struct bnx2i_endpoint *ep)
+{
+	struct kwqe *kwqe_arr[2];
+	struct iscsi_kwqe_conn_offload1 ofld_req1;
+	struct iscsi_kwqe_conn_offload2 ofld_req2;
+	dma_addr_t dma_addr;
+	int num_kwqes = 2;
+	u32 *ptbl;
+
+	ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1;
+	ofld_req1.hdr.flags =
+		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+	ofld_req1.iscsi_conn_id = (u16) ep->ep_iscsi_cid;
+
+	dma_addr = ep->qp.sq_pgtbl_phys;
+	ofld_req1.sq_page_table_addr_lo = (u32) dma_addr;
+	ofld_req1.sq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
+
+	dma_addr = ep->qp.cq_pgtbl_phys;
+	ofld_req1.cq_page_table_addr_lo = (u32) dma_addr;
+	ofld_req1.cq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
+
+	ofld_req2.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN2;
+	ofld_req2.hdr.flags =
+		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+	dma_addr = ep->qp.rq_pgtbl_phys;
+	ofld_req2.rq_page_table_addr_lo = (u32) dma_addr;
+	ofld_req2.rq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
+
+	ptbl = (u32 *) ep->qp.sq_pgtbl_virt;
+
+	ofld_req2.sq_first_pte.hi = *ptbl++;
+	ofld_req2.sq_first_pte.lo = *ptbl;
+
+	ptbl = (u32 *) ep->qp.cq_pgtbl_virt;
+	ofld_req2.cq_first_pte.hi = *ptbl++;
+	ofld_req2.cq_first_pte.lo = *ptbl;
+
+	kwqe_arr[0] = (struct kwqe *) &ofld_req1;
+	kwqe_arr[1] = (struct kwqe *) &ofld_req2;
+	ofld_req2.num_additional_wqes = 0;
+
+	if (hba->cnic && hba->cnic->submit_kwqes)
+		hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+}
+
+
+/**
+ * bnx2i_5771x_send_conn_ofld_req - initiates iscsi connection context creation
+ * @hba: 		adapter structure pointer
+ * @ep: 		endpoint (transport indentifier) structure
+ *
+ * 57710 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE
+ */
+static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
+					   struct bnx2i_endpoint *ep)
+{
+	struct kwqe *kwqe_arr[5];
+	struct iscsi_kwqe_conn_offload1 ofld_req1;
+	struct iscsi_kwqe_conn_offload2 ofld_req2;
+	struct iscsi_kwqe_conn_offload3 ofld_req3[1];
+	dma_addr_t dma_addr;
+	int num_kwqes = 2;
+	u32 *ptbl;
+
+	ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1;
+	ofld_req1.hdr.flags =
+		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+	ofld_req1.iscsi_conn_id = (u16) ep->ep_iscsi_cid;
+
+	dma_addr = ep->qp.sq_pgtbl_phys + ISCSI_SQ_DB_SIZE;
+	ofld_req1.sq_page_table_addr_lo = (u32) dma_addr;
+	ofld_req1.sq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
+
+	dma_addr = ep->qp.cq_pgtbl_phys + ISCSI_CQ_DB_SIZE;
+	ofld_req1.cq_page_table_addr_lo = (u32) dma_addr;
+	ofld_req1.cq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
+
+	ofld_req2.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN2;
+	ofld_req2.hdr.flags =
+		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+	dma_addr = ep->qp.rq_pgtbl_phys + ISCSI_RQ_DB_SIZE;
+	ofld_req2.rq_page_table_addr_lo = (u32) dma_addr;
+	ofld_req2.rq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
+
+	ptbl = (u32 *)((u8 *)ep->qp.sq_pgtbl_virt + ISCSI_SQ_DB_SIZE);
+	ofld_req2.sq_first_pte.hi = *ptbl++;
+	ofld_req2.sq_first_pte.lo = *ptbl;
+
+	ptbl = (u32 *)((u8 *)ep->qp.cq_pgtbl_virt + ISCSI_CQ_DB_SIZE);
+	ofld_req2.cq_first_pte.hi = *ptbl++;
+	ofld_req2.cq_first_pte.lo = *ptbl;
+
+	kwqe_arr[0] = (struct kwqe *) &ofld_req1;
+	kwqe_arr[1] = (struct kwqe *) &ofld_req2;
+
+	ofld_req2.num_additional_wqes = 1;
+	memset(ofld_req3, 0x00, sizeof(ofld_req3[0]));
+	ptbl = (u32 *)((u8 *)ep->qp.rq_pgtbl_virt + ISCSI_RQ_DB_SIZE);
+	ofld_req3[0].qp_first_pte[0].hi = *ptbl++;
+	ofld_req3[0].qp_first_pte[0].lo = *ptbl;
+
+	kwqe_arr[2] = (struct kwqe *) ofld_req3;
+	/* need if we decide to go with multiple KCQE's per conn */
+	num_kwqes += 1;
+
+	if (hba->cnic && hba->cnic->submit_kwqes)
+		hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+}
+
+/**
+ * bnx2i_send_conn_ofld_req - initiates iscsi connection context setup process
+ *
+ * @hba: 		adapter structure pointer
+ * @ep: 		endpoint (transport indentifier) structure
+ *
+ * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE
+ */
+void bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
+{
+	if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
+		bnx2i_5771x_send_conn_ofld_req(hba, ep);
+	else
+		bnx2i_570x_send_conn_ofld_req(hba, ep);
+}
+
+
+/**
+ * setup_qp_page_tables - iscsi QP page table setup function
+ * @ep:		endpoint (transport indentifier) structure
+ *
+ * Sets up page tables for SQ/RQ/CQ, 1G/sec (5706/5708/5709) devices requires
+ * 	64-bit address in big endian format. Whereas 10G/sec (57710) requires
+ * 	PT in little endian format
+ */
+static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
+{
+	int num_pages;
+	u32 *ptbl;
+	dma_addr_t page;
+	int cnic_dev_10g;
+
+	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
+		cnic_dev_10g = 1;
+	else
+		cnic_dev_10g = 0;
+
+	/* SQ page table */
+	memset(ep->qp.sq_pgtbl_virt, 0, ep->qp.sq_pgtbl_size);
+	num_pages = ep->qp.sq_mem_size / PAGE_SIZE;
+	page = ep->qp.sq_phys;
+
+	if (cnic_dev_10g)
+		ptbl = (u32 *)((u8 *)ep->qp.sq_pgtbl_virt + ISCSI_SQ_DB_SIZE);
+	else
+		ptbl = (u32 *) ep->qp.sq_pgtbl_virt;
+	while (num_pages--) {
+		if (cnic_dev_10g) {
+			/* PTE is written in little endian format for 57710 */
+			*ptbl = (u32) page;
+			ptbl++;
+			*ptbl = (u32) ((u64) page >> 32);
+			ptbl++;
+			page += PAGE_SIZE;
+		} else {
+			/* PTE is written in big endian format for
+			 * 5706/5708/5709 devices */
+			*ptbl = (u32) ((u64) page >> 32);
+			ptbl++;
+			*ptbl = (u32) page;
+			ptbl++;
+			page += PAGE_SIZE;
+		}
+	}
+
+	/* RQ page table */
+	memset(ep->qp.rq_pgtbl_virt, 0, ep->qp.rq_pgtbl_size);
+	num_pages = ep->qp.rq_mem_size / PAGE_SIZE;
+	page = ep->qp.rq_phys;
+
+	if (cnic_dev_10g)
+		ptbl = (u32 *)((u8 *)ep->qp.rq_pgtbl_virt + ISCSI_RQ_DB_SIZE);
+	else
+		ptbl = (u32 *) ep->qp.rq_pgtbl_virt;
+	while (num_pages--) {
+		if (cnic_dev_10g) {
+			/* PTE is written in little endian format for 57710 */
+			*ptbl = (u32) page;
+			ptbl++;
+			*ptbl = (u32) ((u64) page >> 32);
+			ptbl++;
+			page += PAGE_SIZE;
+		} else {
+			/* PTE is written in big endian format for
+			 * 5706/5708/5709 devices */
+			*ptbl = (u32) ((u64) page >> 32);
+			ptbl++;
+			*ptbl = (u32) page;
+			ptbl++;
+			page += PAGE_SIZE;
+		}
+	}
+
+	/* CQ page table */
+	memset(ep->qp.cq_pgtbl_virt, 0, ep->qp.cq_pgtbl_size);
+	num_pages = ep->qp.cq_mem_size / PAGE_SIZE;
+	page = ep->qp.cq_phys;
+
+	if (cnic_dev_10g)
+		ptbl = (u32 *)((u8 *)ep->qp.cq_pgtbl_virt + ISCSI_CQ_DB_SIZE);
+	else
+		ptbl = (u32 *) ep->qp.cq_pgtbl_virt;
+	while (num_pages--) {
+		if (cnic_dev_10g) {
+			/* PTE is written in little endian format for 57710 */
+			*ptbl = (u32) page;
+			ptbl++;
+			*ptbl = (u32) ((u64) page >> 32);
+			ptbl++;
+			page += PAGE_SIZE;
+		} else {
+			/* PTE is written in big endian format for
+			 * 5706/5708/5709 devices */
+			*ptbl = (u32) ((u64) page >> 32);
+			ptbl++;
+			*ptbl = (u32) page;
+			ptbl++;
+			page += PAGE_SIZE;
+		}
+	}
+}
+
+
+/**
+ * bnx2i_alloc_qp_resc - allocates required resources for QP.
+ * @hba:	adapter structure pointer
+ * @ep:		endpoint (transport indentifier) structure
+ *
+ * Allocate QP (transport layer for iSCSI connection) resources, DMA'able
+ *	memory for SQ/RQ/CQ and page tables. EP structure elements such
+ *	as producer/consumer indexes/pointers, queue sizes and page table
+ *	contents are setup
+ */
+int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
+{
+	struct bnx2i_5771x_cq_db *cq_db;
+
+	ep->hba = hba;
+	ep->conn = NULL;
+	ep->ep_cid = ep->ep_iscsi_cid = ep->ep_pg_cid = 0;
+
+	/* Allocate page table memory for SQ which is page aligned */
+	ep->qp.sq_mem_size = hba->max_sqes * BNX2I_SQ_WQE_SIZE;
+	ep->qp.sq_mem_size =
+		(ep->qp.sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+	ep->qp.sq_pgtbl_size =
+		(ep->qp.sq_mem_size / PAGE_SIZE) * sizeof(void *);
+	ep->qp.sq_pgtbl_size =
+		(ep->qp.sq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+	ep->qp.sq_pgtbl_virt =
+		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size,
+				   &ep->qp.sq_pgtbl_phys, GFP_KERNEL);
+	if (!ep->qp.sq_pgtbl_virt) {
+		printk(KERN_ALERT "bnx2i: unable to alloc SQ PT mem (%d)\n",
+				  ep->qp.sq_pgtbl_size);
+		goto mem_alloc_err;
+	}
+
+	/* Allocate memory area for actual SQ element */
+	ep->qp.sq_virt =
+		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_mem_size,
+				   &ep->qp.sq_phys, GFP_KERNEL);
+	if (!ep->qp.sq_virt) {
+		printk(KERN_ALERT "bnx2i: unable to alloc SQ BD memory %d\n",
+				  ep->qp.sq_mem_size);
+		goto mem_alloc_err;
+	}
+
+	memset(ep->qp.sq_virt, 0x00, ep->qp.sq_mem_size);
+	ep->qp.sq_first_qe = ep->qp.sq_virt;
+	ep->qp.sq_prod_qe = ep->qp.sq_first_qe;
+	ep->qp.sq_cons_qe = ep->qp.sq_first_qe;
+	ep->qp.sq_last_qe = &ep->qp.sq_first_qe[hba->max_sqes - 1];
+	ep->qp.sq_prod_idx = 0;
+	ep->qp.sq_cons_idx = 0;
+	ep->qp.sqe_left = hba->max_sqes;
+
+	/* Allocate page table memory for CQ which is page aligned */
+	ep->qp.cq_mem_size = hba->max_cqes * BNX2I_CQE_SIZE;
+	ep->qp.cq_mem_size =
+		(ep->qp.cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+	ep->qp.cq_pgtbl_size =
+		(ep->qp.cq_mem_size / PAGE_SIZE) * sizeof(void *);
+	ep->qp.cq_pgtbl_size =
+		(ep->qp.cq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+	ep->qp.cq_pgtbl_virt =
+		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size,
+				   &ep->qp.cq_pgtbl_phys, GFP_KERNEL);
+	if (!ep->qp.cq_pgtbl_virt) {
+		printk(KERN_ALERT "bnx2i: unable to alloc CQ PT memory %d\n",
+				  ep->qp.cq_pgtbl_size);
+		goto mem_alloc_err;
+	}
+
+	/* Allocate memory area for actual CQ element */
+	ep->qp.cq_virt =
+		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_mem_size,
+				   &ep->qp.cq_phys, GFP_KERNEL);
+	if (!ep->qp.cq_virt) {
+		printk(KERN_ALERT "bnx2i: unable to alloc CQ BD memory %d\n",
+				  ep->qp.cq_mem_size);
+		goto mem_alloc_err;
+	}
+	memset(ep->qp.cq_virt, 0x00, ep->qp.cq_mem_size);
+
+	ep->qp.cq_first_qe = ep->qp.cq_virt;
+	ep->qp.cq_prod_qe = ep->qp.cq_first_qe;
+	ep->qp.cq_cons_qe = ep->qp.cq_first_qe;
+	ep->qp.cq_last_qe = &ep->qp.cq_first_qe[hba->max_cqes - 1];
+	ep->qp.cq_prod_idx = 0;
+	ep->qp.cq_cons_idx = 0;
+	ep->qp.cqe_left = hba->max_cqes;
+	ep->qp.cqe_exp_seq_sn = ISCSI_INITIAL_SN;
+	ep->qp.cqe_size = hba->max_cqes;
+
+	/* Invalidate all EQ CQE index, req only for 57710 */
+	cq_db = (struct bnx2i_5771x_cq_db *) ep->qp.cq_pgtbl_virt;
+	memset(cq_db->sqn, 0xFF, sizeof(cq_db->sqn[0]) * BNX2X_MAX_CQS);
+
+	/* Allocate page table memory for RQ which is page aligned */
+	ep->qp.rq_mem_size = hba->max_rqes * BNX2I_RQ_WQE_SIZE;
+	ep->qp.rq_mem_size =
+		(ep->qp.rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+	ep->qp.rq_pgtbl_size =
+		(ep->qp.rq_mem_size / PAGE_SIZE) * sizeof(void *);
+	ep->qp.rq_pgtbl_size =
+		(ep->qp.rq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+	ep->qp.rq_pgtbl_virt =
+		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size,
+				   &ep->qp.rq_pgtbl_phys, GFP_KERNEL);
+	if (!ep->qp.rq_pgtbl_virt) {
+		printk(KERN_ALERT "bnx2i: unable to alloc RQ PT mem %d\n",
+				  ep->qp.rq_pgtbl_size);
+		goto mem_alloc_err;
+	}
+
+	/* Allocate memory area for actual RQ element */
+	ep->qp.rq_virt =
+		dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_mem_size,
+				   &ep->qp.rq_phys, GFP_KERNEL);
+	if (!ep->qp.rq_virt) {
+		printk(KERN_ALERT "bnx2i: unable to alloc RQ BD memory %d\n",
+				  ep->qp.rq_mem_size);
+		goto mem_alloc_err;
+	}
+
+	ep->qp.rq_first_qe = ep->qp.rq_virt;
+	ep->qp.rq_prod_qe = ep->qp.rq_first_qe;
+	ep->qp.rq_cons_qe = ep->qp.rq_first_qe;
+	ep->qp.rq_last_qe = &ep->qp.rq_first_qe[hba->max_rqes - 1];
+	ep->qp.rq_prod_idx = 0x8000;
+	ep->qp.rq_cons_idx = 0;
+	ep->qp.rqe_left = hba->max_rqes;
+
+	setup_qp_page_tables(ep);
+
+	return 0;
+
+mem_alloc_err:
+	bnx2i_free_qp_resc(hba, ep);
+	return -ENOMEM;
+}
+
+
+
+/**
+ * bnx2i_free_qp_resc - free memory resources held by QP
+ * @hba:	adapter structure pointer
+ * @ep:	endpoint (transport indentifier) structure
+ *
+ * Free QP resources - SQ/RQ/CQ memory and page tables.
+ */
+void bnx2i_free_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
+{
+	if (ep->qp.ctx_base) {
+		iounmap(ep->qp.ctx_base);
+		ep->qp.ctx_base = NULL;
+	}
+	/* Free SQ mem */
+	if (ep->qp.sq_pgtbl_virt) {
+		dma_free_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size,
+				  ep->qp.sq_pgtbl_virt, ep->qp.sq_pgtbl_phys);
+		ep->qp.sq_pgtbl_virt = NULL;
+		ep->qp.sq_pgtbl_phys = 0;
+	}
+	if (ep->qp.sq_virt) {
+		dma_free_coherent(&hba->pcidev->dev, ep->qp.sq_mem_size,
+				  ep->qp.sq_virt, ep->qp.sq_phys);
+		ep->qp.sq_virt = NULL;
+		ep->qp.sq_phys = 0;
+	}
+
+	/* Free RQ mem */
+	if (ep->qp.rq_pgtbl_virt) {
+		dma_free_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size,
+				  ep->qp.rq_pgtbl_virt, ep->qp.rq_pgtbl_phys);
+		ep->qp.rq_pgtbl_virt = NULL;
+		ep->qp.rq_pgtbl_phys = 0;
+	}
+	if (ep->qp.rq_virt) {
+		dma_free_coherent(&hba->pcidev->dev, ep->qp.rq_mem_size,
+				  ep->qp.rq_virt, ep->qp.rq_phys);
+		ep->qp.rq_virt = NULL;
+		ep->qp.rq_phys = 0;
+	}
+
+	/* Free CQ mem */
+	if (ep->qp.cq_pgtbl_virt) {
+		dma_free_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size,
+				  ep->qp.cq_pgtbl_virt, ep->qp.cq_pgtbl_phys);
+		ep->qp.cq_pgtbl_virt = NULL;
+		ep->qp.cq_pgtbl_phys = 0;
+	}
+	if (ep->qp.cq_virt) {
+		dma_free_coherent(&hba->pcidev->dev, ep->qp.cq_mem_size,
+				  ep->qp.cq_virt, ep->qp.cq_phys);
+		ep->qp.cq_virt = NULL;
+		ep->qp.cq_phys = 0;
+	}
+}
+
+
+/**
+ * bnx2i_send_fw_iscsi_init_msg - initiates initial handshake with iscsi f/w
+ * @hba:	adapter structure pointer
+ *
+ * Send down iscsi_init KWQEs which initiates the initial handshake with the f/w
+ * 	This results in iSCSi support validation and on-chip context manager
+ * 	initialization.  Firmware completes this handshake with a CQE carrying
+ * 	the result of iscsi support validation. Parameter carried by
+ * 	iscsi init request determines the number of offloaded connection and
+ * 	tolerance level for iscsi protocol violation this hba/chip can support
+ */
+int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
+{
+	struct kwqe *kwqe_arr[3];
+	struct iscsi_kwqe_init1 iscsi_init;
+	struct iscsi_kwqe_init2 iscsi_init2;
+	int rc = 0;
+	u64 mask64;
+
+	bnx2i_adjust_qp_size(hba);
+
+	iscsi_init.flags =
+		ISCSI_PAGE_SIZE_4K << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
+	if (en_tcp_dack)
+		iscsi_init.flags |= ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE;
+	iscsi_init.reserved0 = 0;
+	iscsi_init.num_cqs = 1;
+	iscsi_init.hdr.op_code = ISCSI_KWQE_OPCODE_INIT1;
+	iscsi_init.hdr.flags =
+		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+	iscsi_init.dummy_buffer_addr_lo = (u32) hba->dummy_buf_dma;
+	iscsi_init.dummy_buffer_addr_hi =
+		(u32) ((u64) hba->dummy_buf_dma >> 32);
+
+	hba->ctx_ccell_tasks =
+			((hba->num_ccell & 0xFFFF) | (hba->max_sqes << 16));
+	iscsi_init.num_ccells_per_conn = hba->num_ccell;
+	iscsi_init.num_tasks_per_conn = hba->max_sqes;
+	iscsi_init.sq_wqes_per_page = PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
+	iscsi_init.sq_num_wqes = hba->max_sqes;
+	iscsi_init.cq_log_wqes_per_page =
+		(u8) bnx2i_power_of2(PAGE_SIZE / BNX2I_CQE_SIZE);
+	iscsi_init.cq_num_wqes = hba->max_cqes;
+	iscsi_init.cq_num_pages = (hba->max_cqes * BNX2I_CQE_SIZE +
+				   (PAGE_SIZE - 1)) / PAGE_SIZE;
+	iscsi_init.sq_num_pages = (hba->max_sqes * BNX2I_SQ_WQE_SIZE +
+				   (PAGE_SIZE - 1)) / PAGE_SIZE;
+	iscsi_init.rq_buffer_size = BNX2I_RQ_WQE_SIZE;
+	iscsi_init.rq_num_wqes = hba->max_rqes;
+
+
+	iscsi_init2.hdr.op_code = ISCSI_KWQE_OPCODE_INIT2;
+	iscsi_init2.hdr.flags =
+		(ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+	iscsi_init2.max_cq_sqn = hba->max_cqes * 2 + 1;
+	mask64 = 0x0ULL;
+	mask64 |= (
+		/* CISCO MDS */
+		(1UL <<
+		  ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV) |
+		/* HP MSA1510i */
+		(1UL <<
+		  ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN) |
+		/* EMC */
+		(1ULL << ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN));
+	if (error_mask1)
+		iscsi_init2.error_bit_map[0] = error_mask1;
+	else
+		iscsi_init2.error_bit_map[0] = (u32) mask64;
+
+	if (error_mask2)
+		iscsi_init2.error_bit_map[1] = error_mask2;
+	else
+		iscsi_init2.error_bit_map[1] = (u32) (mask64 >> 32);
+
+	iscsi_error_mask = mask64;
+
+	kwqe_arr[0] = (struct kwqe *) &iscsi_init;
+	kwqe_arr[1] = (struct kwqe *) &iscsi_init2;
+
+	if (hba->cnic && hba->cnic->submit_kwqes)
+		rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 2);
+	return rc;
+}
+
+
+/**
+ * bnx2i_process_scsi_cmd_resp - this function handles scsi cmd completion.
+ * @conn:	iscsi connection
+ * @cqe:	pointer to newly DMA'ed CQE entry for processing
+ *
+ * process SCSI CMD Response CQE & complete the request to SCSI-ML
+ */
+static int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
+				       struct bnx2i_conn *bnx2i_conn,
+				       struct cqe *cqe)
+{
+	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+	struct bnx2i_cmd_response *resp_cqe;
+	struct bnx2i_cmd *bnx2i_cmd;
+	struct iscsi_task *task;
+	struct iscsi_cmd_rsp *hdr;
+	u32 datalen = 0;
+
+	resp_cqe = (struct bnx2i_cmd_response *)cqe;
+	spin_lock(&session->lock);
+	task = iscsi_itt_to_task(conn,
+				 resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
+	if (!task)
+		goto fail;
+
+	bnx2i_cmd = task->dd_data;
+
+	if (bnx2i_cmd->req.op_attr & ISCSI_CMD_REQUEST_READ) {
+		conn->datain_pdus_cnt +=
+			resp_cqe->task_stat.read_stat.num_data_outs;
+		conn->rxdata_octets +=
+			bnx2i_cmd->req.total_data_transfer_length;
+	} else {
+		conn->dataout_pdus_cnt +=
+			resp_cqe->task_stat.read_stat.num_data_outs;
+		conn->r2t_pdus_cnt +=
+			resp_cqe->task_stat.read_stat.num_r2ts;
+		conn->txdata_octets +=
+			bnx2i_cmd->req.total_data_transfer_length;
+	}
+	bnx2i_iscsi_unmap_sg_list(bnx2i_cmd);
+
+	hdr = (struct iscsi_cmd_rsp *)task->hdr;
+	resp_cqe = (struct bnx2i_cmd_response *)cqe;
+	hdr->opcode = resp_cqe->op_code;
+	hdr->max_cmdsn = cpu_to_be32(resp_cqe->max_cmd_sn);
+	hdr->exp_cmdsn = cpu_to_be32(resp_cqe->exp_cmd_sn);
+	hdr->response = resp_cqe->response;
+	hdr->cmd_status = resp_cqe->status;
+	hdr->flags = resp_cqe->response_flags;
+	hdr->residual_count = cpu_to_be32(resp_cqe->residual_count);
+
+	if (resp_cqe->op_code == ISCSI_OP_SCSI_DATA_IN)
+		goto done;
+
+	if (resp_cqe->status == SAM_STAT_CHECK_CONDITION) {
+		datalen = resp_cqe->data_length;
+		if (datalen < 2)
+			goto done;
+
+		if (datalen > BNX2I_RQ_WQE_SIZE) {
+			iscsi_conn_printk(KERN_ERR, conn,
+					  "sense data len %d > RQ sz\n",
+					  datalen);
+			datalen = BNX2I_RQ_WQE_SIZE;
+		} else if (datalen > ISCSI_DEF_MAX_RECV_SEG_LEN) {
+			iscsi_conn_printk(KERN_ERR, conn,
+					  "sense data len %d > conn data\n",
+					  datalen);
+			datalen = ISCSI_DEF_MAX_RECV_SEG_LEN;
+		}
+
+		bnx2i_get_rq_buf(bnx2i_cmd->conn, conn->data, datalen);
+		bnx2i_put_rq_buf(bnx2i_cmd->conn, 1);
+	}
+
+done:
+	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
+			     conn->data, datalen);
+fail:
+	spin_unlock(&session->lock);
+	return 0;
+}
+
+
+/**
+ * bnx2i_process_login_resp - this function handles iscsi login response
+ * @session:		iscsi session pointer
+ * @bnx2i_conn:		iscsi connection pointer
+ * @cqe:		pointer to newly DMA'ed CQE entry for processing
+ *
+ * process Login Response CQE & complete it to open-iscsi user daemon
+ */
+static int bnx2i_process_login_resp(struct iscsi_session *session,
+				    struct bnx2i_conn *bnx2i_conn,
+				    struct cqe *cqe)
+{
+	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+	struct iscsi_task *task;
+	struct bnx2i_login_response *login;
+	struct iscsi_login_rsp *resp_hdr;
+	int pld_len;
+	int pad_len;
+
+	login = (struct bnx2i_login_response *) cqe;
+	spin_lock(&session->lock);
+	task = iscsi_itt_to_task(conn,
+				 login->itt & ISCSI_LOGIN_RESPONSE_INDEX);
+	if (!task)
+		goto done;
+
+	resp_hdr = (struct iscsi_login_rsp *) &bnx2i_conn->gen_pdu.resp_hdr;
+	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
+	resp_hdr->opcode = login->op_code;
+	resp_hdr->flags = login->response_flags;
+	resp_hdr->max_version = login->version_max;
+	resp_hdr->active_version = login->version_active;;
+	resp_hdr->hlength = 0;
+
+	hton24(resp_hdr->dlength, login->data_length);
+	memcpy(resp_hdr->isid, &login->isid_lo, 6);
+	resp_hdr->tsih = cpu_to_be16(login->tsih);
+	resp_hdr->itt = task->hdr->itt;
+	resp_hdr->statsn = cpu_to_be32(login->stat_sn);
+	resp_hdr->exp_cmdsn = cpu_to_be32(login->exp_cmd_sn);
+	resp_hdr->max_cmdsn = cpu_to_be32(login->max_cmd_sn);
+	resp_hdr->status_class = login->status_class;
+	resp_hdr->status_detail = login->status_detail;
+	pld_len = login->data_length;
+	bnx2i_conn->gen_pdu.resp_wr_ptr =
+					bnx2i_conn->gen_pdu.resp_buf + pld_len;
+
+	pad_len = 0;
+	if (pld_len & 0x3)
+		pad_len = 4 - (pld_len % 4);
+
+	if (pad_len) {
+		int i = 0;
+		for (i = 0; i < pad_len; i++) {
+			bnx2i_conn->gen_pdu.resp_wr_ptr[0] = 0;
+			bnx2i_conn->gen_pdu.resp_wr_ptr++;
+		}
+	}
+
+	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr,
+		bnx2i_conn->gen_pdu.resp_buf,
+		bnx2i_conn->gen_pdu.resp_wr_ptr - bnx2i_conn->gen_pdu.resp_buf);
+done:
+	spin_unlock(&session->lock);
+	return 0;
+}
+
+/**
+ * bnx2i_process_tmf_resp - this function handles iscsi TMF response
+ * @session:		iscsi session pointer
+ * @bnx2i_conn:		iscsi connection pointer
+ * @cqe:		pointer to newly DMA'ed CQE entry for processing
+ *
+ * process iSCSI TMF Response CQE and wake up the driver eh thread.
+ */
+static int bnx2i_process_tmf_resp(struct iscsi_session *session,
+				  struct bnx2i_conn *bnx2i_conn,
+				  struct cqe *cqe)
+{
+	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+	struct iscsi_task *task;
+	struct bnx2i_tmf_response *tmf_cqe;
+	struct iscsi_tm_rsp *resp_hdr;
+
+	tmf_cqe = (struct bnx2i_tmf_response *)cqe;
+	spin_lock(&session->lock);
+	task = iscsi_itt_to_task(conn,
+				 tmf_cqe->itt & ISCSI_TMF_RESPONSE_INDEX);
+	if (!task)
+		goto done;
+
+	resp_hdr = (struct iscsi_tm_rsp *) &bnx2i_conn->gen_pdu.resp_hdr;
+	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
+	resp_hdr->opcode = tmf_cqe->op_code;
+	resp_hdr->max_cmdsn = cpu_to_be32(tmf_cqe->max_cmd_sn);
+	resp_hdr->exp_cmdsn = cpu_to_be32(tmf_cqe->exp_cmd_sn);
+	resp_hdr->itt = task->hdr->itt;
+	resp_hdr->response = tmf_cqe->response;
+
+	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
+done:
+	spin_unlock(&session->lock);
+	return 0;
+}
+
+/**
+ * bnx2i_process_logout_resp - this function handles iscsi logout response
+ * @session:		iscsi session pointer
+ * @bnx2i_conn:		iscsi connection pointer
+ * @cqe:		pointer to newly DMA'ed CQE entry for processing
+ *
+ * process iSCSI Logout Response CQE & make function call to
+ * notify the user daemon.
+ */
+static int bnx2i_process_logout_resp(struct iscsi_session *session,
+				     struct bnx2i_conn *bnx2i_conn,
+				     struct cqe *cqe)
+{
+	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+	struct iscsi_task *task;
+	struct bnx2i_logout_response *logout;
+	struct iscsi_logout_rsp *resp_hdr;
+
+	logout = (struct bnx2i_logout_response *) cqe;
+	spin_lock(&session->lock);
+	task = iscsi_itt_to_task(conn,
+				 logout->itt & ISCSI_LOGOUT_RESPONSE_INDEX);
+	if (!task)
+		goto done;
+
+	resp_hdr = (struct iscsi_logout_rsp *) &bnx2i_conn->gen_pdu.resp_hdr;
+	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
+	resp_hdr->opcode = logout->op_code;
+	resp_hdr->flags = logout->response;
+	resp_hdr->hlength = 0;
+
+	resp_hdr->itt = task->hdr->itt;
+	resp_hdr->statsn = task->hdr->exp_statsn;
+	resp_hdr->exp_cmdsn = cpu_to_be32(logout->exp_cmd_sn);
+	resp_hdr->max_cmdsn = cpu_to_be32(logout->max_cmd_sn);
+
+	resp_hdr->t2wait = cpu_to_be32(logout->time_to_wait);
+	resp_hdr->t2retain = cpu_to_be32(logout->time_to_retain);
+
+	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
+done:
+	spin_unlock(&session->lock);
+	return 0;
+}
+
+/**
+ * bnx2i_process_nopin_local_cmpl - this function handles iscsi nopin CQE
+ * @session:		iscsi session pointer
+ * @bnx2i_conn:		iscsi connection pointer
+ * @cqe:		pointer to newly DMA'ed CQE entry for processing
+ *
+ * process iSCSI NOPIN local completion CQE, frees IIT and command structures
+ */
+static void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session,
+					   struct bnx2i_conn *bnx2i_conn,
+					   struct cqe *cqe)
+{
+	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+	struct bnx2i_nop_in_msg *nop_in;
+	struct iscsi_task *task;
+
+	nop_in = (struct bnx2i_nop_in_msg *)cqe;
+	spin_lock(&session->lock);
+	task = iscsi_itt_to_task(conn,
+				 nop_in->itt & ISCSI_NOP_IN_MSG_INDEX);
+	if (task)
+		iscsi_put_task(task);
+	spin_unlock(&session->lock);
+}
+
+/**
+ * bnx2i_unsol_pdu_adjust_rq - makes adjustments to RQ after unsol pdu is recvd
+ * @conn:	iscsi connection
+ *
+ * Firmware advances RQ producer index for every unsolicited PDU even if
+ *	payload data length is '0'. This function makes corresponding
+ *	adjustments on the driver side to match this f/w behavior
+ */
+static void bnx2i_unsol_pdu_adjust_rq(struct bnx2i_conn *bnx2i_conn)
+{
+	char dummy_rq_data[2];
+	bnx2i_get_rq_buf(bnx2i_conn, dummy_rq_data, 1);
+	bnx2i_put_rq_buf(bnx2i_conn, 1);
+}
+
+
+/**
+ * bnx2i_process_nopin_mesg - this function handles iscsi nopin CQE
+ * @session:		iscsi session pointer
+ * @bnx2i_conn:		iscsi connection pointer
+ * @cqe:		pointer to newly DMA'ed CQE entry for processing
+ *
+ * process iSCSI target's proactive iSCSI NOPIN request
+ */
+static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
+				     struct bnx2i_conn *bnx2i_conn,
+				     struct cqe *cqe)
+{
+	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+	struct iscsi_task *task;
+	struct bnx2i_nop_in_msg *nop_in;
+	struct iscsi_nopin *hdr;
+	u32 itt;
+	int tgt_async_nop = 0;
+
+	nop_in = (struct bnx2i_nop_in_msg *)cqe;
+	itt = nop_in->itt & ISCSI_NOP_IN_MSG_INDEX;
+
+	spin_lock(&session->lock);
+	hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr;
+	memset(hdr, 0, sizeof(struct iscsi_hdr));
+	hdr->opcode = nop_in->op_code;
+	hdr->max_cmdsn = cpu_to_be32(nop_in->max_cmd_sn);
+	hdr->exp_cmdsn = cpu_to_be32(nop_in->exp_cmd_sn);
+	hdr->ttt = cpu_to_be32(nop_in->ttt);
+
+	if (itt == (u16) RESERVED_ITT) {
+		bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
+		hdr->itt = RESERVED_ITT;
+		tgt_async_nop = 1;
+		goto done;
+	}
+
+	/* this is a response to one of our nop-outs */
+	task = iscsi_itt_to_task(conn, itt);
+	if (task) {
+		hdr->flags = ISCSI_FLAG_CMD_FINAL;
+		hdr->itt = task->hdr->itt;
+		hdr->ttt = cpu_to_be32(nop_in->ttt);
+		memcpy(hdr->lun, nop_in->lun, 8);
+	}
+done:
+	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
+	spin_unlock(&session->lock);
+
+	return tgt_async_nop;
+}
+
+
+/**
+ * bnx2i_process_async_mesg - this function handles iscsi async message
+ * @session:		iscsi session pointer
+ * @bnx2i_conn:		iscsi connection pointer
+ * @cqe:		pointer to newly DMA'ed CQE entry for processing
+ *
+ * process iSCSI ASYNC Message
+ */
+static void bnx2i_process_async_mesg(struct iscsi_session *session,
+				     struct bnx2i_conn *bnx2i_conn,
+				     struct cqe *cqe)
+{
+	struct bnx2i_async_msg *async_cqe;
+	struct iscsi_async *resp_hdr;
+	u8 async_event;
+
+	bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
+
+	async_cqe = (struct bnx2i_async_msg *)cqe;
+	async_event = async_cqe->async_event;
+
+	if (async_event == ISCSI_ASYNC_MSG_SCSI_EVENT) {
+		iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data,
+				  "async: scsi events not supported\n");
+		return;
+	}
+
+	spin_lock(&session->lock);
+	resp_hdr = (struct iscsi_async *) &bnx2i_conn->gen_pdu.resp_hdr;
+	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
+	resp_hdr->opcode = async_cqe->op_code;
+	resp_hdr->flags = 0x80;
+
+	memcpy(resp_hdr->lun, async_cqe->lun, 8);
+	resp_hdr->exp_cmdsn = cpu_to_be32(async_cqe->exp_cmd_sn);
+	resp_hdr->max_cmdsn = cpu_to_be32(async_cqe->max_cmd_sn);
+
+	resp_hdr->async_event = async_cqe->async_event;
+	resp_hdr->async_vcode = async_cqe->async_vcode;
+
+	resp_hdr->param1 = cpu_to_be16(async_cqe->param1);
+	resp_hdr->param2 = cpu_to_be16(async_cqe->param2);
+	resp_hdr->param3 = cpu_to_be16(async_cqe->param3);
+
+	__iscsi_complete_pdu(bnx2i_conn->cls_conn->dd_data,
+			     (struct iscsi_hdr *)resp_hdr, NULL, 0);
+	spin_unlock(&session->lock);
+}
+
+
+/**
+ * bnx2i_process_reject_mesg - process iscsi reject pdu
+ * @session:		iscsi session pointer
+ * @bnx2i_conn:		iscsi connection pointer
+ * @cqe:		pointer to newly DMA'ed CQE entry for processing
+ *
+ * process iSCSI REJECT message
+ */
+static void bnx2i_process_reject_mesg(struct iscsi_session *session,
+				      struct bnx2i_conn *bnx2i_conn,
+				      struct cqe *cqe)
+{
+	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+	struct bnx2i_reject_msg *reject;
+	struct iscsi_reject *hdr;
+
+	reject = (struct bnx2i_reject_msg *) cqe;
+	if (reject->data_length) {
+		bnx2i_get_rq_buf(bnx2i_conn, conn->data, reject->data_length);
+		bnx2i_put_rq_buf(bnx2i_conn, 1);
+	} else
+		bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
+
+	spin_lock(&session->lock);
+	hdr = (struct iscsi_reject *) &bnx2i_conn->gen_pdu.resp_hdr;
+	memset(hdr, 0, sizeof(struct iscsi_hdr));
+	hdr->opcode = reject->op_code;
+	hdr->reason = reject->reason;
+	hton24(hdr->dlength, reject->data_length);
+	hdr->max_cmdsn = cpu_to_be32(reject->max_cmd_sn);
+	hdr->exp_cmdsn = cpu_to_be32(reject->exp_cmd_sn);
+	hdr->ffffffff = cpu_to_be32(RESERVED_ITT);
+	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data,
+			     reject->data_length);
+	spin_unlock(&session->lock);
+}
+
+/**
+ * bnx2i_process_cmd_cleanup_resp - process scsi command clean-up completion
+ * @session:		iscsi session pointer
+ * @bnx2i_conn:		iscsi connection pointer
+ * @cqe:		pointer to newly DMA'ed CQE entry for processing
+ *
+ * process command cleanup response CQE during conn shutdown or error recovery
+ */
+static void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session,
+					   struct bnx2i_conn *bnx2i_conn,
+					   struct cqe *cqe)
+{
+	struct bnx2i_cleanup_response *cmd_clean_rsp;
+	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+	struct iscsi_task *task;
+
+	cmd_clean_rsp = (struct bnx2i_cleanup_response *)cqe;
+	spin_lock(&session->lock);
+	task = iscsi_itt_to_task(conn,
+			cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
+	if (!task)
+		printk(KERN_ALERT "bnx2i: cmd clean ITT %x not active\n",
+			cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
+	spin_unlock(&session->lock);
+	complete(&bnx2i_conn->cmd_cleanup_cmpl);
+}
+
+
+
+/**
+ * bnx2i_process_new_cqes - process newly DMA'ed CQE's
+ * @bnx2i_conn:		iscsi connection
+ *
+ * this function is called by generic KCQ handler to process all pending CQE's
+ */
+static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
+{
+	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+	struct iscsi_session *session = conn->session;
+	struct qp_info *qp = &bnx2i_conn->ep->qp;
+	struct bnx2i_nop_in_msg *nopin;
+	int tgt_async_msg;
+
+	while (1) {
+		nopin = (struct bnx2i_nop_in_msg *) qp->cq_cons_qe;
+		if (nopin->cq_req_sn != qp->cqe_exp_seq_sn)
+			break;
+
+		if (unlikely(test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx)))
+			break;
+
+		tgt_async_msg = 0;
+
+		switch (nopin->op_code) {
+		case ISCSI_OP_SCSI_CMD_RSP:
+		case ISCSI_OP_SCSI_DATA_IN:
+			bnx2i_process_scsi_cmd_resp(session, bnx2i_conn,
+						    qp->cq_cons_qe);
+			break;
+		case ISCSI_OP_LOGIN_RSP:
+			bnx2i_process_login_resp(session, bnx2i_conn,
+						 qp->cq_cons_qe);
+			break;
+		case ISCSI_OP_SCSI_TMFUNC_RSP:
+			bnx2i_process_tmf_resp(session, bnx2i_conn,
+					       qp->cq_cons_qe);
+			break;
+		case ISCSI_OP_LOGOUT_RSP:
+			bnx2i_process_logout_resp(session, bnx2i_conn,
+						  qp->cq_cons_qe);
+			break;
+		case ISCSI_OP_NOOP_IN:
+			if (bnx2i_process_nopin_mesg(session, bnx2i_conn,
+						     qp->cq_cons_qe))
+				tgt_async_msg = 1;
+			break;
+		case ISCSI_OPCODE_NOPOUT_LOCAL_COMPLETION:
+			bnx2i_process_nopin_local_cmpl(session, bnx2i_conn,
+						       qp->cq_cons_qe);
+			break;
+		case ISCSI_OP_ASYNC_EVENT:
+			bnx2i_process_async_mesg(session, bnx2i_conn,
+						 qp->cq_cons_qe);
+			tgt_async_msg = 1;
+			break;
+		case ISCSI_OP_REJECT:
+			bnx2i_process_reject_mesg(session, bnx2i_conn,
+						  qp->cq_cons_qe);
+			break;
+		case ISCSI_OPCODE_CLEANUP_RESPONSE:
+			bnx2i_process_cmd_cleanup_resp(session, bnx2i_conn,
+						       qp->cq_cons_qe);
+			break;
+		default:
+			printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n",
+					  nopin->op_code);
+		}
+
+		if (!tgt_async_msg)
+			bnx2i_conn->ep->num_active_cmds--;
+
+		/* clear out in production version only, till beta keep opcode
+		 * field intact, will be helpful in debugging (context dump)
+		 * nopin->op_code = 0;
+		 */
+		qp->cqe_exp_seq_sn++;
+		if (qp->cqe_exp_seq_sn == (qp->cqe_size * 2 + 1))
+			qp->cqe_exp_seq_sn = ISCSI_INITIAL_SN;
+
+		if (qp->cq_cons_qe == qp->cq_last_qe) {
+			qp->cq_cons_qe = qp->cq_first_qe;
+			qp->cq_cons_idx = 0;
+		} else {
+			qp->cq_cons_qe++;
+			qp->cq_cons_idx++;
+		}
+	}
+	bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE);
+}
+
+/**
+ * bnx2i_fastpath_notification - process global event queue (KCQ)
+ * @hba:		adapter structure pointer
+ * @new_cqe_kcqe:	pointer to newly DMA'ed KCQE entry
+ *
+ * Fast path event notification handler, KCQ entry carries context id
+ *	of the connection that has 1 or more pending CQ entries
+ */
+static void bnx2i_fastpath_notification(struct bnx2i_hba *hba,
+					struct iscsi_kcqe *new_cqe_kcqe)
+{
+	struct bnx2i_conn *conn;
+	u32 iscsi_cid;
+
+	iscsi_cid = new_cqe_kcqe->iscsi_conn_id;
+	conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
+
+	if (!conn) {
+		printk(KERN_ALERT "cid #%x not valid\n", iscsi_cid);
+		return;
+	}
+	if (!conn->ep) {
+		printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid);
+		return;
+	}
+
+	bnx2i_process_new_cqes(conn);
+}
+
+
+/**
+ * bnx2i_process_update_conn_cmpl - process iscsi conn update completion KCQE
+ * @hba:		adapter structure pointer
+ * @update_kcqe:	kcqe pointer
+ *
+ * CONN_UPDATE completion handler, this completes iSCSI connection FFP migration
+ */
+static void bnx2i_process_update_conn_cmpl(struct bnx2i_hba *hba,
+					   struct iscsi_kcqe *update_kcqe)
+{
+	struct bnx2i_conn *conn;
+	u32 iscsi_cid;
+
+	iscsi_cid = update_kcqe->iscsi_conn_id;
+	conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
+
+	if (!conn) {
+		printk(KERN_ALERT "conn_update: cid %x not valid\n", iscsi_cid);
+		return;
+	}
+	if (!conn->ep) {
+		printk(KERN_ALERT "cid %x does not have ep bound\n", iscsi_cid);
+		return;
+	}
+
+	if (update_kcqe->completion_status) {
+		printk(KERN_ALERT "request failed cid %x\n", iscsi_cid);
+		conn->ep->state = EP_STATE_ULP_UPDATE_FAILED;
+	} else
+		conn->ep->state = EP_STATE_ULP_UPDATE_COMPL;
+
+	wake_up_interruptible(&conn->ep->ofld_wait);
+}
+
+
+/**
+ * bnx2i_recovery_que_add_conn - add connection to recovery queue
+ * @hba:		adapter structure pointer
+ * @bnx2i_conn:		iscsi connection
+ *
+ * Add connection to recovery queue and schedule adapter eh worker
+ */
+static void bnx2i_recovery_que_add_conn(struct bnx2i_hba *hba,
+					struct bnx2i_conn *bnx2i_conn)
+{
+	iscsi_conn_failure(bnx2i_conn->cls_conn->dd_data,
+			   ISCSI_ERR_CONN_FAILED);
+}
+
+
+/**
+ * bnx2i_process_tcp_error - process error notification on a given connection
+ *
+ * @hba: 		adapter structure pointer
+ * @tcp_err: 		tcp error kcqe pointer
+ *
+ * handles tcp level error notifications from FW.
+ */
+static void bnx2i_process_tcp_error(struct bnx2i_hba *hba,
+				    struct iscsi_kcqe *tcp_err)
+{
+	struct bnx2i_conn *bnx2i_conn;
+	u32 iscsi_cid;
+
+	iscsi_cid = tcp_err->iscsi_conn_id;
+	bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
+
+	if (!bnx2i_conn) {
+		printk(KERN_ALERT "bnx2i - cid 0x%x not valid\n", iscsi_cid);
+		return;
+	}
+
+	printk(KERN_ALERT "bnx2i - cid 0x%x had TCP errors, error code 0x%x\n",
+			  iscsi_cid, tcp_err->completion_status);
+	bnx2i_recovery_que_add_conn(bnx2i_conn->hba, bnx2i_conn);
+}
+
+
+/**
+ * bnx2i_process_iscsi_error - process error notification on a given connection
+ * @hba:		adapter structure pointer
+ * @iscsi_err:		iscsi error kcqe pointer
+ *
+ * handles iscsi error notifications from the FW. Firmware based in initial
+ *	handshake classifies iscsi protocol / TCP rfc violation into either
+ *	warning or error indications. If indication is of "Error" type, driver
+ *	will initiate session recovery for that connection/session. For
+ *	"Warning" type indication, driver will put out a system log message
+ *	(there will be only one message for each type for the life of the
+ *	session, this is to avoid un-necessarily overloading the system)
+ */
+static void bnx2i_process_iscsi_error(struct bnx2i_hba *hba,
+				      struct iscsi_kcqe *iscsi_err)
+{
+	struct bnx2i_conn *bnx2i_conn;
+	u32 iscsi_cid;
+	char warn_notice[] = "iscsi_warning";
+	char error_notice[] = "iscsi_error";
+	char additional_notice[64];
+	char *message;
+	int need_recovery;
+	u64 err_mask64;
+
+	iscsi_cid = iscsi_err->iscsi_conn_id;
+	bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
+	if (!bnx2i_conn) {
+		printk(KERN_ALERT "bnx2i - cid 0x%x not valid\n", iscsi_cid);
+		return;
+	}
+
+	err_mask64 = (0x1ULL << iscsi_err->completion_status);
+
+	if (err_mask64 & iscsi_error_mask) {
+		need_recovery = 0;
+		message = warn_notice;
+	} else {
+		need_recovery = 1;
+		message = error_notice;
+	}
+
+	switch (iscsi_err->completion_status) {
+	case ISCSI_KCQE_COMPLETION_STATUS_HDR_DIG_ERR:
+		strcpy(additional_notice, "hdr digest err");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_DATA_DIG_ERR:
+		strcpy(additional_notice, "data digest err");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_OPCODE:
+		strcpy(additional_notice, "wrong opcode rcvd");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_AHS_LEN:
+		strcpy(additional_notice, "AHS len > 0 rcvd");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ITT:
+		strcpy(additional_notice, "invalid ITT rcvd");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_STATSN:
+		strcpy(additional_notice, "wrong StatSN rcvd");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN:
+		strcpy(additional_notice, "wrong DataSN rcvd");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T:
+		strcpy(additional_notice, "pend R2T violation");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_0:
+		strcpy(additional_notice, "ERL0, UO");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_1:
+		strcpy(additional_notice, "ERL0, U1");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_2:
+		strcpy(additional_notice, "ERL0, U2");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_3:
+		strcpy(additional_notice, "ERL0, U3");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_4:
+		strcpy(additional_notice, "ERL0, U4");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_5:
+		strcpy(additional_notice, "ERL0, U5");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_6:
+		strcpy(additional_notice, "ERL0, U6");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_RCV_LEN:
+		strcpy(additional_notice, "invalid resi len");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_RCV_PDU_LEN:
+		strcpy(additional_notice, "MRDSL violation");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_F_BIT_ZERO:
+		strcpy(additional_notice, "F-bit not set");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV:
+		strcpy(additional_notice, "invalid TTT");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATASN:
+		strcpy(additional_notice, "invalid DataSN");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_BURST_LEN:
+		strcpy(additional_notice, "burst len violation");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_BUFFER_OFF:
+		strcpy(additional_notice, "buf offset violation");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN:
+		strcpy(additional_notice, "invalid LUN field");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_R2TSN:
+		strcpy(additional_notice, "invalid R2TSN field");
+		break;
+#define BNX2I_ERR_DESIRED_DATA_TRNS_LEN_0 	\
+	ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0
+	case BNX2I_ERR_DESIRED_DATA_TRNS_LEN_0:
+		strcpy(additional_notice, "invalid cmd len1");
+		break;
+#define BNX2I_ERR_DESIRED_DATA_TRNS_LEN_1 	\
+	ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1
+	case BNX2I_ERR_DESIRED_DATA_TRNS_LEN_1:
+		strcpy(additional_notice, "invalid cmd len2");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_EXCEED:
+		strcpy(additional_notice,
+		       "pend r2t exceeds MaxOutstandingR2T value");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_IS_RSRV:
+		strcpy(additional_notice, "TTT is rsvd");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_BURST_LEN:
+		strcpy(additional_notice, "MBL violation");
+		break;
+#define BNX2I_ERR_DATA_SEG_LEN_NOT_ZERO 	\
+	ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_NOT_ZERO
+	case BNX2I_ERR_DATA_SEG_LEN_NOT_ZERO:
+		strcpy(additional_notice, "data seg len != 0");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REJECT_PDU_LEN:
+		strcpy(additional_notice, "reject pdu len error");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ASYNC_PDU_LEN:
+		strcpy(additional_notice, "async pdu len error");
+		break;
+	case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_NOPIN_PDU_LEN:
+		strcpy(additional_notice, "nopin pdu len error");
+		break;
+#define BNX2_ERR_PEND_R2T_IN_CLEANUP			\
+	ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_IN_CLEANUP
+	case BNX2_ERR_PEND_R2T_IN_CLEANUP:
+		strcpy(additional_notice, "pend r2t in cleanup");
+		break;
+
+	case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_FRAGMENT:
+		strcpy(additional_notice, "IP fragments rcvd");
+		break;
+	case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_OPTIONS:
+		strcpy(additional_notice, "IP options error");
+		break;
+	case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_URGENT_FLAG:
+		strcpy(additional_notice, "urgent flag error");
+		break;
+	default:
+		printk(KERN_ALERT "iscsi_err - unknown err %x\n",
+				  iscsi_err->completion_status);
+	}
+
+	if (need_recovery) {
+		iscsi_conn_printk(KERN_ALERT,
+				  bnx2i_conn->cls_conn->dd_data,
+				  "bnx2i: %s - %s\n",
+				  message, additional_notice);
+
+		iscsi_conn_printk(KERN_ALERT,
+				  bnx2i_conn->cls_conn->dd_data,
+				  "conn_err - hostno %d conn %p, "
+				  "iscsi_cid %x cid %x\n",
+				  bnx2i_conn->hba->shost->host_no,
+				  bnx2i_conn, bnx2i_conn->ep->ep_iscsi_cid,
+				  bnx2i_conn->ep->ep_cid);
+		bnx2i_recovery_que_add_conn(bnx2i_conn->hba, bnx2i_conn);
+	} else
+		if (!test_and_set_bit(iscsi_err->completion_status,
+				      (void *) &bnx2i_conn->violation_notified))
+			iscsi_conn_printk(KERN_ALERT,
+					  bnx2i_conn->cls_conn->dd_data,
+					  "bnx2i: %s - %s\n",
+					  message, additional_notice);
+}
+
+
+/**
+ * bnx2i_process_conn_destroy_cmpl - process iscsi conn destroy completion
+ * @hba:		adapter structure pointer
+ * @conn_destroy:	conn destroy kcqe pointer
+ *
+ * handles connection destroy completion request.
+ */
+static void bnx2i_process_conn_destroy_cmpl(struct bnx2i_hba *hba,
+					    struct iscsi_kcqe *conn_destroy)
+{
+	struct bnx2i_endpoint *ep;
+
+	ep = bnx2i_find_ep_in_destroy_list(hba, conn_destroy->iscsi_conn_id);
+	if (!ep) {
+		printk(KERN_ALERT "bnx2i_conn_destroy_cmpl: no pending "
+				  "offload request, unexpected complection\n");
+		return;
+	}
+
+	if (hba != ep->hba) {
+		printk(KERN_ALERT "conn destroy- error hba mis-match\n");
+		return;
+	}
+
+	if (conn_destroy->completion_status) {
+		printk(KERN_ALERT "conn_destroy_cmpl: op failed\n");
+		ep->state = EP_STATE_CLEANUP_FAILED;
+	} else
+		ep->state = EP_STATE_CLEANUP_CMPL;
+	wake_up_interruptible(&ep->ofld_wait);
+}
+
+
+/**
+ * bnx2i_process_ofld_cmpl - process initial iscsi conn offload completion
+ * @hba:		adapter structure pointer
+ * @ofld_kcqe:		conn offload kcqe pointer
+ *
+ * handles initial connection offload completion, ep_connect() thread is
+ *	woken-up to continue with LLP connect process
+ */
+static void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba,
+				    struct iscsi_kcqe *ofld_kcqe)
+{
+	u32 cid_addr;
+	struct bnx2i_endpoint *ep;
+	u32 cid_num;
+
+	ep = bnx2i_find_ep_in_ofld_list(hba, ofld_kcqe->iscsi_conn_id);
+	if (!ep) {
+		printk(KERN_ALERT "ofld_cmpl: no pend offload request\n");
+		return;
+	}
+
+	if (hba != ep->hba) {
+		printk(KERN_ALERT "ofld_cmpl: error hba mis-match\n");
+		return;
+	}
+
+	if (ofld_kcqe->completion_status) {
+		if (ofld_kcqe->completion_status ==
+		    ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE)
+			printk(KERN_ALERT "bnx2i: unable to allocate"
+					  " iSCSI context resources\n");
+		ep->state = EP_STATE_OFLD_FAILED;
+	} else {
+		ep->state = EP_STATE_OFLD_COMPL;
+		cid_addr = ofld_kcqe->iscsi_conn_context_id;
+		cid_num = bnx2i_get_cid_num(ep);
+		ep->ep_cid = cid_addr;
+		ep->qp.ctx_base = NULL;
+	}
+	wake_up_interruptible(&ep->ofld_wait);
+}
+
+/**
+ * bnx2i_indicate_kcqe - process iscsi conn update completion KCQE
+ * @hba:		adapter structure pointer
+ * @update_kcqe:	kcqe pointer
+ *
+ * Generic KCQ event handler/dispatcher
+ */
+static void bnx2i_indicate_kcqe(void *context, struct kcqe *kcqe[],
+				u32 num_cqe)
+{
+	struct bnx2i_hba *hba = context;
+	int i = 0;
+	struct iscsi_kcqe *ikcqe = NULL;
+
+	while (i < num_cqe) {
+		ikcqe = (struct iscsi_kcqe *) kcqe[i++];
+
+		if (ikcqe->op_code ==
+		    ISCSI_KCQE_OPCODE_CQ_EVENT_NOTIFICATION)
+			bnx2i_fastpath_notification(hba, ikcqe);
+		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_OFFLOAD_CONN)
+			bnx2i_process_ofld_cmpl(hba, ikcqe);
+		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_UPDATE_CONN)
+			bnx2i_process_update_conn_cmpl(hba, ikcqe);
+		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_INIT) {
+			if (ikcqe->completion_status !=
+			    ISCSI_KCQE_COMPLETION_STATUS_SUCCESS)
+				bnx2i_iscsi_license_error(hba, ikcqe->\
+							  completion_status);
+			else {
+				set_bit(ADAPTER_STATE_UP, &hba->adapter_state);
+				bnx2i_get_link_state(hba);
+				printk(KERN_INFO "bnx2i [%.2x:%.2x.%.2x]: "
+						 "ISCSI_INIT passed\n",
+						 (u8)hba->pcidev->bus->number,
+						 hba->pci_devno,
+						 (u8)hba->pci_func);
+
+
+			}
+		} else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_DESTROY_CONN)
+			bnx2i_process_conn_destroy_cmpl(hba, ikcqe);
+		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_ISCSI_ERROR)
+			bnx2i_process_iscsi_error(hba, ikcqe);
+		else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_TCP_ERROR)
+			bnx2i_process_tcp_error(hba, ikcqe);
+		else
+			printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n",
+					  ikcqe->op_code);
+	}
+}
+
+
+/**
+ * bnx2i_indicate_netevent - Generic netdev event handler
+ * @context:	adapter structure pointer
+ * @event:	event type
+ *
+ * Handles four netdev events, NETDEV_UP, NETDEV_DOWN,
+ *	NETDEV_GOING_DOWN and NETDEV_CHANGE
+ */
+static void bnx2i_indicate_netevent(void *context, unsigned long event)
+{
+	struct bnx2i_hba *hba = context;
+
+	switch (event) {
+	case NETDEV_UP:
+		if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
+			bnx2i_send_fw_iscsi_init_msg(hba);
+		break;
+	case NETDEV_DOWN:
+		clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
+		clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
+		break;
+	case NETDEV_GOING_DOWN:
+		set_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
+		iscsi_host_for_each_session(hba->shost,
+					    bnx2i_drop_session);
+		break;
+	case NETDEV_CHANGE:
+		bnx2i_get_link_state(hba);
+		break;
+	default:
+		;
+	}
+}
+
+
+/**
+ * bnx2i_cm_connect_cmpl - process iscsi conn establishment completion
+ * @cm_sk: 		cnic sock structure pointer
+ *
+ * function callback exported via bnx2i - cnic driver interface to
+ *	indicate completion of option-2 TCP connect request.
+ */
+static void bnx2i_cm_connect_cmpl(struct cnic_sock *cm_sk)
+{
+	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
+
+	if (test_bit(ADAPTER_STATE_GOING_DOWN, &ep->hba->adapter_state))
+		ep->state = EP_STATE_CONNECT_FAILED;
+	else if (test_bit(SK_F_OFFLD_COMPLETE, &cm_sk->flags))
+		ep->state = EP_STATE_CONNECT_COMPL;
+	else
+		ep->state = EP_STATE_CONNECT_FAILED;
+
+	wake_up_interruptible(&ep->ofld_wait);
+}
+
+
+/**
+ * bnx2i_cm_close_cmpl - process tcp conn close completion
+ * @cm_sk:	cnic sock structure pointer
+ *
+ * function callback exported via bnx2i - cnic driver interface to
+ *	indicate completion of option-2 graceful TCP connect shutdown
+ */
+static void bnx2i_cm_close_cmpl(struct cnic_sock *cm_sk)
+{
+	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
+
+	ep->state = EP_STATE_DISCONN_COMPL;
+	wake_up_interruptible(&ep->ofld_wait);
+}
+
+
+/**
+ * bnx2i_cm_abort_cmpl - process abortive tcp conn teardown completion
+ * @cm_sk:	cnic sock structure pointer
+ *
+ * function callback exported via bnx2i - cnic driver interface to
+ *	indicate completion of option-2 abortive TCP connect termination
+ */
+static void bnx2i_cm_abort_cmpl(struct cnic_sock *cm_sk)
+{
+	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
+
+	ep->state = EP_STATE_DISCONN_COMPL;
+	wake_up_interruptible(&ep->ofld_wait);
+}
+
+
+/**
+ * bnx2i_cm_remote_close - process received TCP FIN
+ * @hba:		adapter structure pointer
+ * @update_kcqe:	kcqe pointer
+ *
+ * function callback exported via bnx2i - cnic driver interface to indicate
+ *	async TCP events such as FIN
+ */
+static void bnx2i_cm_remote_close(struct cnic_sock *cm_sk)
+{
+	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
+
+	ep->state = EP_STATE_TCP_FIN_RCVD;
+	if (ep->conn)
+		bnx2i_recovery_que_add_conn(ep->hba, ep->conn);
+}
+
+/**
+ * bnx2i_cm_remote_abort - process TCP RST and start conn cleanup
+ * @hba:		adapter structure pointer
+ * @update_kcqe:	kcqe pointer
+ *
+ * function callback exported via bnx2i - cnic driver interface to
+ *	indicate async TCP events (RST) sent by the peer.
+ */
+static void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk)
+{
+	struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
+
+	ep->state = EP_STATE_TCP_RST_RCVD;
+	if (ep->conn)
+		bnx2i_recovery_que_add_conn(ep->hba, ep->conn);
+}
+
+
+static void bnx2i_send_nl_mesg(struct cnic_dev *dev, u32 msg_type,
+			       char *buf, u16 buflen)
+{
+	struct bnx2i_hba *hba;
+
+	hba = bnx2i_find_hba_for_cnic(dev);
+	if (!hba)
+		return;
+
+	if (iscsi_offload_mesg(hba->shost, &bnx2i_iscsi_transport,
+				   msg_type, buf, buflen))
+		printk(KERN_ALERT "bnx2i: private nl message send error\n");
+
+}
+
+
+/**
+ * bnx2i_cnic_cb - global template of bnx2i - cnic driver interface structure
+ *			carrying callback function pointers
+ *
+ */
+struct cnic_ulp_ops bnx2i_cnic_cb = {
+	.cnic_init = bnx2i_ulp_init,
+	.cnic_exit = bnx2i_ulp_exit,
+	.cnic_start = bnx2i_start,
+	.cnic_stop = bnx2i_stop,
+	.indicate_kcqes = bnx2i_indicate_kcqe,
+	.indicate_netevent = bnx2i_indicate_netevent,
+	.cm_connect_complete = bnx2i_cm_connect_cmpl,
+	.cm_close_complete = bnx2i_cm_close_cmpl,
+	.cm_abort_complete = bnx2i_cm_abort_cmpl,
+	.cm_remote_close = bnx2i_cm_remote_close,
+	.cm_remote_abort = bnx2i_cm_remote_abort,
+	.iscsi_nl_send_msg = bnx2i_send_nl_mesg,
+	.owner = THIS_MODULE
+};
+
+
+/**
+ * bnx2i_map_ep_dbell_regs - map connection doorbell registers
+ * @ep: bnx2i endpoint
+ *
+ * maps connection's SQ and RQ doorbell registers, 5706/5708/5709 hosts these
+ *	register in BAR #0. Whereas in 57710 these register are accessed by
+ *	mapping BAR #1
+ */
+int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
+{
+	u32 cid_num;
+	u32 reg_off;
+	u32 first_l4l5;
+	u32 ctx_sz;
+	u32 config2;
+	resource_size_t reg_base;
+
+	cid_num = bnx2i_get_cid_num(ep);
+
+	if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
+		reg_base = pci_resource_start(ep->hba->pcidev,
+					      BNX2X_DOORBELL_PCI_BAR);
+		reg_off = PAGE_SIZE * (cid_num & 0x1FFFF) + DPM_TRIGER_TYPE;
+		ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off, 4);
+		goto arm_cq;
+	}
+
+	reg_base = ep->hba->netdev->base_addr;
+	if ((test_bit(BNX2I_NX2_DEV_5709, &ep->hba->cnic_dev_type)) &&
+	    (ep->hba->mail_queue_access == BNX2I_MQ_BIN_MODE)) {
+		config2 = REG_RD(ep->hba, BNX2_MQ_CONFIG2);
+		first_l4l5 = config2 & BNX2_MQ_CONFIG2_FIRST_L4L5;
+		ctx_sz = (config2 & BNX2_MQ_CONFIG2_CONT_SZ) >> 3;
+		if (ctx_sz)
+			reg_off = CTX_OFFSET + MAX_CID_CNT * MB_KERNEL_CTX_SIZE
+				  + PAGE_SIZE *
+				  (((cid_num - first_l4l5) / ctx_sz) + 256);
+		else
+			reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
+	} else
+		/* 5709 device in normal node and 5706/5708 devices */
+		reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
+
+	ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off,
+					  MB_KERNEL_CTX_SIZE);
+	if (!ep->qp.ctx_base)
+		return -ENOMEM;
+
+arm_cq:
+	bnx2i_arm_cq_event_coalescing(ep, CNIC_ARM_CQE);
+	return 0;
+}
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
new file mode 100644
index 0000000..ae4b2d5
--- /dev/null
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -0,0 +1,438 @@
+/* bnx2i.c: Broadcom NetXtreme II iSCSI driver.
+ *
+ * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
+ * Copyright (c) 2007, 2008 Mike Christie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ */
+
+#include "bnx2i.h"
+
+static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
+static u32 adapter_count;
+static int bnx2i_reg_device;
+
+#define DRV_MODULE_NAME		"bnx2i"
+#define DRV_MODULE_VERSION	"2.0.1d"
+#define DRV_MODULE_RELDATE	"Mar 25, 2009"
+
+static char version[] __devinitdata =
+		"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
+		" v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+
+MODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 iSCSI Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+static DEFINE_RWLOCK(bnx2i_dev_lock);
+
+unsigned int event_coal_div = 1;
+module_param(event_coal_div, int, 0664);
+MODULE_PARM_DESC(event_coal_div, "Event Coalescing Divide Factor");
+
+unsigned int en_tcp_dack = 1;
+module_param(en_tcp_dack, int, 0664);
+MODULE_PARM_DESC(en_tcp_dack, "Enable TCP Delayed ACK");
+
+unsigned int error_mask1 = 0x00;
+module_param(error_mask1, int, 0664);
+MODULE_PARM_DESC(error_mask1, "Config FW iSCSI Error Mask #1");
+
+unsigned int error_mask2 = 0x00;
+module_param(error_mask2, int, 0664);
+MODULE_PARM_DESC(error_mask2, "Config FW iSCSI Error Mask #2");
+
+unsigned int sq_size;
+module_param(sq_size, int, 0664);
+MODULE_PARM_DESC(sq_size, "Configure SQ size");
+
+unsigned int rq_size = BNX2I_RQ_WQES_DEFAULT;
+module_param(rq_size, int, 0664);
+MODULE_PARM_DESC(rq_size, "Configure RQ size");
+
+u64 iscsi_error_mask = 0x00;
+
+static void bnx2i_unreg_one_device(struct bnx2i_hba *hba) ;
+
+
+/**
+ * bnx2i_identify_device - identifies NetXtreme II device type
+ * @hba: 		Adapter structure pointer
+ *
+ * This function identifies the NX2 device type and sets appropriate
+ *	queue mailbox register access method, 5709 requires driver to
+ *	access MBOX regs using *bin* mode
+ */
+void bnx2i_identify_device(struct bnx2i_hba *hba)
+{
+	hba->cnic_dev_type = 0;
+	if ((hba->pci_did == PCI_DEVICE_ID_NX2_5706) ||
+	    (hba->pci_did == PCI_DEVICE_ID_NX2_5706S))
+		set_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type);
+	else if ((hba->pci_did == PCI_DEVICE_ID_NX2_5708) ||
+	    (hba->pci_did == PCI_DEVICE_ID_NX2_5708S))
+		set_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type);
+	else if ((hba->pci_did == PCI_DEVICE_ID_NX2_5709) ||
+	    (hba->pci_did == PCI_DEVICE_ID_NX2_5709S)) {
+		set_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type);
+		hba->mail_queue_access = BNX2I_MQ_BIN_MODE;
+	} else if (hba->pci_did == PCI_DEVICE_ID_NX2_57710 ||
+		   hba->pci_did == PCI_DEVICE_ID_NX2_57711)
+		set_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type);
+}
+
+
+/**
+ * get_adapter_list_head - returns head of adapter list
+ */
+struct bnx2i_hba *get_adapter_list_head(void)
+{
+	struct bnx2i_hba *hba = NULL;
+	struct bnx2i_hba *tmp_hba;
+
+	if (!adapter_count)
+		goto hba_not_found;
+
+	read_lock(&bnx2i_dev_lock);
+	list_for_each_entry(tmp_hba, &adapter_list, link) {
+		if (tmp_hba->cnic && tmp_hba->cnic->cm_select_dev) {
+			hba = tmp_hba;
+			break;
+		}
+	}
+	read_unlock(&bnx2i_dev_lock);
+hba_not_found:
+	return hba;
+}
+
+
+/**
+ * bnx2i_find_hba_for_cnic - maps cnic device instance to bnx2i adapter instance
+ * @cnic:	pointer to cnic device instance
+ *
+ */
+struct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic)
+{
+	struct bnx2i_hba *hba, *temp;
+
+	read_lock(&bnx2i_dev_lock);
+	list_for_each_entry_safe(hba, temp, &adapter_list, link) {
+		if (hba->cnic == cnic) {
+			read_unlock(&bnx2i_dev_lock);
+			return hba;
+		}
+	}
+	read_unlock(&bnx2i_dev_lock);
+	return NULL;
+}
+
+
+/**
+ * bnx2i_start - cnic callback to initialize & start adapter instance
+ * @handle:	transparent handle pointing to adapter structure
+ *
+ * This function maps adapter structure to pcidev structure and initiates
+ *	firmware handshake to enable/initialize on chip iscsi components
+ * 	This bnx2i - cnic interface api callback is issued after following
+ *	2 conditions are met -
+ *	  a) underlying network interface is up (marked by event 'NETDEV_UP'
+ *		from netdev
+ *	  b) bnx2i adapter instance is registered
+ */
+void bnx2i_start(void *handle)
+{
+#define BNX2I_INIT_POLL_TIME	(1000 / HZ)
+	struct bnx2i_hba *hba = handle;
+	int i = HZ;
+
+	bnx2i_send_fw_iscsi_init_msg(hba);
+	while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--)
+		msleep(BNX2I_INIT_POLL_TIME);
+}
+
+
+/**
+ * bnx2i_stop - cnic callback to shutdown adapter instance
+ * @handle:	transparent handle pointing to adapter structure
+ *
+ * driver checks if adapter is already in shutdown mode, if not start
+ *	the shutdown process
+ */
+void bnx2i_stop(void *handle)
+{
+	struct bnx2i_hba *hba = handle;
+
+	/* check if cleanup happened in GOING_DOWN context */
+	clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
+	if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN,
+				&hba->adapter_state))
+		iscsi_host_for_each_session(hba->shost,
+					    bnx2i_drop_session);
+}
+
+/**
+ * bnx2i_register_device - register bnx2i adapter instance with the cnic driver
+ * @hba:	Adapter instance to register
+ *
+ * registers bnx2i adapter instance with the cnic driver while holding the
+ *	adapter structure lock
+ */
+void bnx2i_register_device(struct bnx2i_hba *hba)
+{
+	if (test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) ||
+	    test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
+		return;
+	}
+
+	hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba);
+
+	spin_lock(&hba->lock);
+	bnx2i_reg_device++;
+	spin_unlock(&hba->lock);
+
+	set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+}
+
+
+/**
+ * bnx2i_reg_dev_all - registers all adapter instances with the cnic driver
+ *
+ * registers all bnx2i adapter instances with the cnic driver while holding
+ *	the global resource lock
+ */
+void bnx2i_reg_dev_all(void)
+{
+	struct bnx2i_hba *hba, *temp;
+
+	read_lock(&bnx2i_dev_lock);
+	list_for_each_entry_safe(hba, temp, &adapter_list, link)
+		bnx2i_register_device(hba);
+	read_unlock(&bnx2i_dev_lock);
+}
+
+
+/**
+ * bnx2i_unreg_one_device - unregister adapter instance with the cnic driver
+ * @hba:	Adapter instance to unregister
+ *
+ * registers bnx2i adapter instance with the cnic driver while holding
+ *	the adapter structure lock
+ */
+static void bnx2i_unreg_one_device(struct bnx2i_hba *hba)
+{
+	if (hba->ofld_conns_active ||
+	    !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) ||
+	    test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state))
+		return;
+
+	hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
+
+	spin_lock(&hba->lock);
+	bnx2i_reg_device--;
+	spin_unlock(&hba->lock);
+
+	/* ep_disconnect could come before NETDEV_DOWN, driver won't
+	 * see NETDEV_DOWN as it already unregistered itself.
+	 */
+	hba->adapter_state = 0;
+	clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+}
+
+/**
+ * bnx2i_unreg_dev_all - unregisters all bnx2i instances with the cnic driver
+ *
+ * unregisters all bnx2i adapter instances with the cnic driver while holding
+ *	the global resource lock
+ */
+void bnx2i_unreg_dev_all(void)
+{
+	struct bnx2i_hba *hba, *temp;
+
+	read_lock(&bnx2i_dev_lock);
+	list_for_each_entry_safe(hba, temp, &adapter_list, link)
+		bnx2i_unreg_one_device(hba);
+	read_unlock(&bnx2i_dev_lock);
+}
+
+
+/**
+ * bnx2i_init_one - initialize an adapter instance and allocate memory resources
+ * @hba:	bnx2i adapter instance
+ * @cnic:	cnic device handle
+ *
+ * Global resource lock and host adapter lock is held during critical sections
+ *	below. This routine is called from cnic_register_driver() context and
+ *	work horse thread which does majority of device specific initialization
+ */
+static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)
+{
+	int rc;
+
+	read_lock(&bnx2i_dev_lock);
+	if (bnx2i_reg_device &&
+	    !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
+		rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
+		if (rc)		/* duplicate registration */
+			printk(KERN_ERR "bnx2i- dev reg failed\n");
+
+		spin_lock(&hba->lock);
+		bnx2i_reg_device++;
+		hba->age++;
+		spin_unlock(&hba->lock);
+
+		set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+	}
+	read_unlock(&bnx2i_dev_lock);
+
+	write_lock(&bnx2i_dev_lock);
+	list_add_tail(&hba->link, &adapter_list);
+	adapter_count++;
+	write_unlock(&bnx2i_dev_lock);
+	return 0;
+}
+
+
+/**
+ * bnx2i_ulp_init - initialize an adapter instance
+ * @dev:	cnic device handle
+ *
+ * Called from cnic_register_driver() context to initialize all enumerated
+ *	cnic devices. This routine allocate adapter structure and other
+ *	device specific resources.
+ */
+void bnx2i_ulp_init(struct cnic_dev *dev)
+{
+	struct bnx2i_hba *hba;
+
+	/* Allocate a HBA structure for this device */
+	hba = bnx2i_alloc_hba(dev);
+	if (!hba) {
+		printk(KERN_ERR "bnx2i init: hba initialization failed\n");
+		return;
+	}
+
+	/* Get PCI related information and update hba struct members */
+	clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+	if (bnx2i_init_one(hba, dev)) {
+		printk(KERN_ERR "bnx2i - hba %p init failed\n", hba);
+		bnx2i_free_hba(hba);
+	} else
+		hba->cnic = dev;
+}
+
+
+/**
+ * bnx2i_ulp_exit - shuts down adapter instance and frees all resources
+ * @dev:	cnic device handle
+ *
+ */
+void bnx2i_ulp_exit(struct cnic_dev *dev)
+{
+	struct bnx2i_hba *hba;
+
+	hba = bnx2i_find_hba_for_cnic(dev);
+	if (!hba) {
+		printk(KERN_INFO "bnx2i_ulp_exit: hba not "
+				 "found, dev 0x%p\n", dev);
+		return;
+	}
+	write_lock(&bnx2i_dev_lock);
+	list_del_init(&hba->link);
+	adapter_count--;
+
+	if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
+		hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
+		clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+
+		spin_lock(&hba->lock);
+		bnx2i_reg_device--;
+		spin_unlock(&hba->lock);
+	}
+	write_unlock(&bnx2i_dev_lock);
+
+	bnx2i_free_hba(hba);
+}
+
+
+/**
+ * bnx2i_mod_init - module init entry point
+ *
+ * initialize any driver wide global data structures such as endpoint pool,
+ *	tcp port manager/queue, sysfs. finally driver will register itself
+ *	with the cnic module
+ */
+static int __init bnx2i_mod_init(void)
+{
+	int err;
+
+	printk(KERN_INFO "%s", version);
+
+	if (!is_power_of_2(sq_size))
+		sq_size = roundup_pow_of_two(sq_size);
+
+	bnx2i_scsi_xport_template =
+			iscsi_register_transport(&bnx2i_iscsi_transport);
+	if (!bnx2i_scsi_xport_template) {
+		printk(KERN_ERR "Could not register bnx2i transport.\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = cnic_register_driver(CNIC_ULP_ISCSI, &bnx2i_cnic_cb);
+	if (err) {
+		printk(KERN_ERR "Could not register bnx2i cnic driver.\n");
+		goto unreg_xport;
+	}
+
+	return 0;
+
+unreg_xport:
+	iscsi_unregister_transport(&bnx2i_iscsi_transport);
+out:
+	return err;
+}
+
+
+/**
+ * bnx2i_mod_exit - module cleanup/exit entry point
+ *
+ * Global resource lock and host adapter lock is held during critical sections
+ *	in this function. Driver will browse through the adapter list, cleans-up
+ *	each instance, unregisters iscsi transport name and finally driver will
+ *	unregister itself with the cnic module
+ */
+static void __exit bnx2i_mod_exit(void)
+{
+	struct bnx2i_hba *hba;
+
+	write_lock(&bnx2i_dev_lock);
+	while (!list_empty(&adapter_list)) {
+		hba = list_entry(adapter_list.next, struct bnx2i_hba, link);
+		list_del(&hba->link);
+		adapter_count--;
+
+		if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
+			hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
+			clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+			bnx2i_reg_device--;
+		}
+
+		write_unlock(&bnx2i_dev_lock);
+		bnx2i_free_hba(hba);
+		write_lock(&bnx2i_dev_lock);
+	}
+	write_unlock(&bnx2i_dev_lock);
+
+	iscsi_unregister_transport(&bnx2i_iscsi_transport);
+	cnic_unregister_driver(CNIC_ULP_ISCSI);
+}
+
+module_init(bnx2i_mod_init);
+module_exit(bnx2i_mod_exit);
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
new file mode 100644
index 0000000..f741219
--- /dev/null
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -0,0 +1,2064 @@
+/*
+ * bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver.
+ *
+ * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
+ * Copyright (c) 2007, 2008 Mike Christie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ */
+
+#include <scsi/scsi_tcq.h>
+#include <scsi/libiscsi.h>
+#include "bnx2i.h"
+
+struct scsi_transport_template *bnx2i_scsi_xport_template;
+struct iscsi_transport bnx2i_iscsi_transport;
+static struct scsi_host_template bnx2i_host_template;
+
+/*
+ * Global endpoint resource info
+ */
+static DEFINE_SPINLOCK(bnx2i_resc_lock); /* protects global resources */
+
+
+static int bnx2i_adapter_ready(struct bnx2i_hba *hba)
+{
+	int retval = 0;
+
+	if (!hba || !test_bit(ADAPTER_STATE_UP, &hba->adapter_state) ||
+	    test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) ||
+	    test_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state))
+		retval = -EPERM;
+	return retval;
+}
+
+/**
+ * bnx2i_get_write_cmd_bd_idx - identifies various BD bookmarks
+ * @cmd:		iscsi cmd struct pointer
+ * @buf_off:		absolute buffer offset
+ * @start_bd_off:	u32 pointer to return the offset within the BD
+ *			indicated by 'start_bd_idx' on which 'buf_off' falls
+ * @start_bd_idx:	index of the BD on which 'buf_off' falls
+ *
+ * identifies & marks various bd info for scsi command's imm data,
+ * unsolicited data and the first solicited data seq.
+ */
+static void bnx2i_get_write_cmd_bd_idx(struct bnx2i_cmd *cmd, u32 buf_off,
+				       u32 *start_bd_off, u32 *start_bd_idx)
+{
+	struct iscsi_bd *bd_tbl = cmd->io_tbl.bd_tbl;
+	u32 cur_offset = 0;
+	u32 cur_bd_idx = 0;
+
+	if (buf_off) {
+		while (buf_off >= (cur_offset + bd_tbl->buffer_length)) {
+			cur_offset += bd_tbl->buffer_length;
+			cur_bd_idx++;
+			bd_tbl++;
+		}
+	}
+
+	*start_bd_off = buf_off - cur_offset;
+	*start_bd_idx = cur_bd_idx;
+}
+
+/**
+ * bnx2i_setup_write_cmd_bd_info - sets up BD various information
+ * @task:	transport layer's cmd struct pointer
+ *
+ * identifies & marks various bd info for scsi command's immediate data,
+ * unsolicited data and first solicited data seq which includes BD start
+ * index & BD buf off. his function takes into account iscsi parameter such
+ * as immediate data and unsolicited data is support on this connection.
+ */
+static void bnx2i_setup_write_cmd_bd_info(struct iscsi_task *task)
+{
+	struct bnx2i_cmd *cmd = task->dd_data;
+	u32 start_bd_offset;
+	u32 start_bd_idx;
+	u32 buffer_offset = 0;
+	u32 cmd_len = cmd->req.total_data_transfer_length;
+
+	/* if ImmediateData is turned off & IntialR2T is turned on,
+	 * there will be no immediate or unsolicited data, just return.
+	 */
+	if (!iscsi_task_has_unsol_data(task) && !task->imm_count)
+		return;
+
+	/* Immediate data */
+	buffer_offset += task->imm_count;
+	if (task->imm_count == cmd_len)
+		return;
+
+	if (iscsi_task_has_unsol_data(task)) {
+		bnx2i_get_write_cmd_bd_idx(cmd, buffer_offset,
+					   &start_bd_offset, &start_bd_idx);
+		cmd->req.ud_buffer_offset = start_bd_offset;
+		cmd->req.ud_start_bd_index = start_bd_idx;
+		buffer_offset += task->unsol_r2t.data_length;
+	}
+
+	if (buffer_offset != cmd_len) {
+		bnx2i_get_write_cmd_bd_idx(cmd, buffer_offset,
+					   &start_bd_offset, &start_bd_idx);
+		if ((start_bd_offset > task->conn->session->first_burst) ||
+		    (start_bd_idx > scsi_sg_count(cmd->scsi_cmd))) {
+			int i = 0;
+
+			iscsi_conn_printk(KERN_ALERT, task->conn,
+					  "bnx2i- error, buf offset 0x%x "
+					  "bd_valid %d use_sg %d\n",
+					  buffer_offset, cmd->io_tbl.bd_valid,
+					  scsi_sg_count(cmd->scsi_cmd));
+			for (i = 0; i < cmd->io_tbl.bd_valid; i++)
+				iscsi_conn_printk(KERN_ALERT, task->conn,
+						  "bnx2i err, bd[%d]: len %x\n",
+						  i, cmd->io_tbl.bd_tbl[i].\
+						  buffer_length);
+		}
+		cmd->req.sd_buffer_offset = start_bd_offset;
+		cmd->req.sd_start_bd_index = start_bd_idx;
+	}
+}
+
+
+
+/**
+ * bnx2i_map_scsi_sg - maps IO buffer and prepares the BD table
+ * @hba:	adapter instance
+ * @cmd:	iscsi cmd struct pointer
+ *
+ * map SG list
+ */
+static int bnx2i_map_scsi_sg(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd)
+{
+	struct scsi_cmnd *sc = cmd->scsi_cmd;
+	struct iscsi_bd *bd = cmd->io_tbl.bd_tbl;
+	struct scatterlist *sg;
+	int byte_count = 0;
+	int bd_count = 0;
+	int sg_count;
+	int sg_len;
+	u64 addr;
+	int i;
+
+	BUG_ON(scsi_sg_count(sc) > ISCSI_MAX_BDS_PER_CMD);
+
+	sg_count = scsi_dma_map(sc);
+
+	scsi_for_each_sg(sc, sg, sg_count, i) {
+		sg_len = sg_dma_len(sg);
+		addr = (u64) sg_dma_address(sg);
+		bd[bd_count].buffer_addr_lo = addr & 0xffffffff;
+		bd[bd_count].buffer_addr_hi = addr >> 32;
+		bd[bd_count].buffer_length = sg_len;
+		bd[bd_count].flags = 0;
+		if (bd_count == 0)
+			bd[bd_count].flags = ISCSI_BD_FIRST_IN_BD_CHAIN;
+
+		byte_count += sg_len;
+		bd_count++;
+	}
+
+	if (bd_count)
+		bd[bd_count - 1].flags |= ISCSI_BD_LAST_IN_BD_CHAIN;
+
+	BUG_ON(byte_count != scsi_bufflen(sc));
+	return bd_count;
+}
+
+/**
+ * bnx2i_iscsi_map_sg_list - maps SG list
+ * @cmd:	iscsi cmd struct pointer
+ *
+ * creates BD list table for the command
+ */
+static void bnx2i_iscsi_map_sg_list(struct bnx2i_cmd *cmd)
+{
+	int bd_count;
+
+	bd_count  = bnx2i_map_scsi_sg(cmd->conn->hba, cmd);
+	if (!bd_count) {
+		struct iscsi_bd *bd = cmd->io_tbl.bd_tbl;
+
+		bd[0].buffer_addr_lo = bd[0].buffer_addr_hi = 0;
+		bd[0].buffer_length = bd[0].flags = 0;
+	}
+	cmd->io_tbl.bd_valid = bd_count;
+}
+
+
+/**
+ * bnx2i_iscsi_unmap_sg_list - unmaps SG list
+ * @cmd:	iscsi cmd struct pointer
+ *
+ * unmap IO buffers and invalidate the BD table
+ */
+void bnx2i_iscsi_unmap_sg_list(struct bnx2i_cmd *cmd)
+{
+	struct scsi_cmnd *sc = cmd->scsi_cmd;
+
+	if (cmd->io_tbl.bd_valid && sc) {
+		scsi_dma_unmap(sc);
+		cmd->io_tbl.bd_valid = 0;
+	}
+}
+
+static void bnx2i_setup_cmd_wqe_template(struct bnx2i_cmd *cmd)
+{
+	memset(&cmd->req, 0x00, sizeof(cmd->req));
+	cmd->req.op_code = 0xFF;
+	cmd->req.bd_list_addr_lo = (u32) cmd->io_tbl.bd_tbl_dma;
+	cmd->req.bd_list_addr_hi =
+		(u32) ((u64) cmd->io_tbl.bd_tbl_dma >> 32);
+
+}
+
+
+/**
+ * bnx2i_bind_conn_to_iscsi_cid - bind conn structure to 'iscsi_cid'
+ * @hba:	pointer to adapter instance
+ * @conn:	pointer to iscsi connection
+ * @iscsi_cid:	iscsi context ID, range 0 - (MAX_CONN - 1)
+ *
+ * update iscsi cid table entry with connection pointer. This enables
+ *	driver to quickly get hold of connection structure pointer in
+ *	completion/interrupt thread using iscsi context ID
+ */
+static int bnx2i_bind_conn_to_iscsi_cid(struct bnx2i_hba *hba,
+					struct bnx2i_conn *bnx2i_conn,
+					u32 iscsi_cid)
+{
+	if (hba && hba->cid_que.conn_cid_tbl[iscsi_cid]) {
+		iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data,
+				 "conn bind - entry #%d not free\n", iscsi_cid);
+		return -EBUSY;
+	}
+
+	hba->cid_que.conn_cid_tbl[iscsi_cid] = bnx2i_conn;
+	return 0;
+}
+
+
+/**
+ * bnx2i_get_conn_from_id - maps an iscsi cid to corresponding conn ptr
+ * @hba:	pointer to adapter instance
+ * @iscsi_cid:	iscsi context ID, range 0 - (MAX_CONN - 1)
+ */
+struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba,
+					  u16 iscsi_cid)
+{
+	if (!hba->cid_que.conn_cid_tbl) {
+		printk(KERN_ERR "bnx2i: ERROR - missing conn<->cid table\n");
+		return NULL;
+
+	} else if (iscsi_cid >= hba->max_active_conns) {
+		printk(KERN_ERR "bnx2i: wrong cid #%d\n", iscsi_cid);
+		return NULL;
+	}
+	return hba->cid_que.conn_cid_tbl[iscsi_cid];
+}
+
+
+/**
+ * bnx2i_alloc_iscsi_cid - allocates a iscsi_cid from free pool
+ * @hba:	pointer to adapter instance
+ */
+static u32 bnx2i_alloc_iscsi_cid(struct bnx2i_hba *hba)
+{
+	int idx;
+
+	if (!hba->cid_que.cid_free_cnt)
+		return -1;
+
+	idx = hba->cid_que.cid_q_cons_idx;
+	hba->cid_que.cid_q_cons_idx++;
+	if (hba->cid_que.cid_q_cons_idx == hba->cid_que.cid_q_max_idx)
+		hba->cid_que.cid_q_cons_idx = 0;
+
+	hba->cid_que.cid_free_cnt--;
+	return hba->cid_que.cid_que[idx];
+}
+
+
+/**
+ * bnx2i_free_iscsi_cid - returns tcp port to free list
+ * @hba: 		pointer to adapter instance
+ * @iscsi_cid:		iscsi context ID to free
+ */
+static void bnx2i_free_iscsi_cid(struct bnx2i_hba *hba, u16 iscsi_cid)
+{
+	int idx;
+
+	if (iscsi_cid == (u16) -1)
+		return;
+
+	hba->cid_que.cid_free_cnt++;
+
+	idx = hba->cid_que.cid_q_prod_idx;
+	hba->cid_que.cid_que[idx] = iscsi_cid;
+	hba->cid_que.conn_cid_tbl[iscsi_cid] = NULL;
+	hba->cid_que.cid_q_prod_idx++;
+	if (hba->cid_que.cid_q_prod_idx == hba->cid_que.cid_q_max_idx)
+		hba->cid_que.cid_q_prod_idx = 0;
+}
+
+
+/**
+ * bnx2i_setup_free_cid_que - sets up free iscsi cid queue
+ * @hba:	pointer to adapter instance
+ *
+ * allocates memory for iscsi cid queue & 'cid - conn ptr' mapping table,
+ * 	and initialize table attributes
+ */
+static int bnx2i_setup_free_cid_que(struct bnx2i_hba *hba)
+{
+	int mem_size;
+	int i;
+
+	mem_size = hba->max_active_conns * sizeof(u32);
+	mem_size = (mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+	hba->cid_que.cid_que_base = kmalloc(mem_size, GFP_KERNEL);
+	if (!hba->cid_que.cid_que_base)
+		return -ENOMEM;
+
+	mem_size = hba->max_active_conns * sizeof(struct bnx2i_conn *);
+	mem_size = (mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+	hba->cid_que.conn_cid_tbl = kmalloc(mem_size, GFP_KERNEL);
+	if (!hba->cid_que.conn_cid_tbl) {
+		kfree(hba->cid_que.cid_que_base);
+		hba->cid_que.cid_que_base = NULL;
+		return -ENOMEM;
+	}
+
+	hba->cid_que.cid_que = (u32 *)hba->cid_que.cid_que_base;
+	hba->cid_que.cid_q_prod_idx = 0;
+	hba->cid_que.cid_q_cons_idx = 0;
+	hba->cid_que.cid_q_max_idx = hba->max_active_conns;
+	hba->cid_que.cid_free_cnt = hba->max_active_conns;
+
+	for (i = 0; i < hba->max_active_conns; i++) {
+		hba->cid_que.cid_que[i] = i;
+		hba->cid_que.conn_cid_tbl[i] = NULL;
+	}
+	return 0;
+}
+
+
+/**
+ * bnx2i_release_free_cid_que - releases 'iscsi_cid' queue resources
+ * @hba:	pointer to adapter instance
+ */
+static void bnx2i_release_free_cid_que(struct bnx2i_hba *hba)
+{
+	kfree(hba->cid_que.cid_que_base);
+	hba->cid_que.cid_que_base = NULL;
+
+	kfree(hba->cid_que.conn_cid_tbl);
+	hba->cid_que.conn_cid_tbl = NULL;
+}
+
+
+/**
+ * bnx2i_alloc_ep - allocates ep structure from global pool
+ * @hba:	pointer to adapter instance
+ *
+ * routine allocates a free endpoint structure from global pool and
+ *	a tcp port to be used for this connection.  Global resource lock,
+ *	'bnx2i_resc_lock' is held while accessing shared global data structures
+ */
+static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
+{
+	struct iscsi_endpoint *ep;
+	struct bnx2i_endpoint *bnx2i_ep;
+
+	ep = iscsi_create_endpoint(sizeof(*bnx2i_ep));
+	if (!ep) {
+		printk(KERN_ERR "bnx2i: Could not allocate ep\n");
+		return NULL;
+	}
+
+	bnx2i_ep = ep->dd_data;
+	INIT_LIST_HEAD(&bnx2i_ep->link);
+	bnx2i_ep->state = EP_STATE_IDLE;
+	bnx2i_ep->hba = hba;
+	bnx2i_ep->hba_age = hba->age;
+	hba->ofld_conns_active++;
+	init_waitqueue_head(&bnx2i_ep->ofld_wait);
+	return ep;
+}
+
+
+/**
+ * bnx2i_free_ep - free endpoint
+ * @ep:		pointer to iscsi endpoint structure
+ */
+static void bnx2i_free_ep(struct iscsi_endpoint *ep)
+{
+	struct bnx2i_endpoint *bnx2i_ep = ep->dd_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnx2i_resc_lock, flags);
+	bnx2i_ep->state = EP_STATE_IDLE;
+	bnx2i_ep->hba->ofld_conns_active--;
+
+	bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid);
+	if (bnx2i_ep->conn) {
+		bnx2i_ep->conn->ep = NULL;
+		bnx2i_ep->conn = NULL;
+	}
+
+	bnx2i_ep->hba = NULL;
+	spin_unlock_irqrestore(&bnx2i_resc_lock, flags);
+	iscsi_destroy_endpoint(ep);
+}
+
+
+/**
+ * bnx2i_alloc_bdt - allocates buffer descriptor (BD) table for the command
+ * @hba:	adapter instance pointer
+ * @session:	iscsi session pointer
+ * @cmd:	iscsi command structure
+ */
+static int bnx2i_alloc_bdt(struct bnx2i_hba *hba, struct iscsi_session *session,
+			   struct bnx2i_cmd *cmd)
+{
+	struct io_bdt *io = &cmd->io_tbl;
+	struct iscsi_bd *bd;
+
+	io->bd_tbl = dma_alloc_coherent(&hba->pcidev->dev,
+					ISCSI_MAX_BDS_PER_CMD * sizeof(*bd),
+					&io->bd_tbl_dma, GFP_KERNEL);
+	if (!io->bd_tbl) {
+		iscsi_session_printk(KERN_ERR, session, "Could not "
+				     "allocate bdt.\n");
+		return -ENOMEM;
+	}
+	io->bd_valid = 0;
+	return 0;
+}
+
+/**
+ * bnx2i_destroy_cmd_pool - destroys iscsi command pool and release BD table
+ * @hba:	adapter instance pointer
+ * @session:	iscsi session pointer
+ * @cmd:	iscsi command structure
+ */
+static void bnx2i_destroy_cmd_pool(struct bnx2i_hba *hba,
+				   struct iscsi_session *session)
+{
+	int i;
+
+	for (i = 0; i < session->cmds_max; i++) {
+		struct iscsi_task *task = session->cmds[i];
+		struct bnx2i_cmd *cmd = task->dd_data;
+
+		if (cmd->io_tbl.bd_tbl)
+			dma_free_coherent(&hba->pcidev->dev,
+					  ISCSI_MAX_BDS_PER_CMD *
+					  sizeof(struct iscsi_bd),
+					  cmd->io_tbl.bd_tbl,
+					  cmd->io_tbl.bd_tbl_dma);
+	}
+
+}
+
+
+/**
+ * bnx2i_setup_cmd_pool - sets up iscsi command pool for the session
+ * @hba:	adapter instance pointer
+ * @session:	iscsi session pointer
+ */
+static int bnx2i_setup_cmd_pool(struct bnx2i_hba *hba,
+				struct iscsi_session *session)
+{
+	int i;
+
+	for (i = 0; i < session->cmds_max; i++) {
+		struct iscsi_task *task = session->cmds[i];
+		struct bnx2i_cmd *cmd = task->dd_data;
+
+		/* Anil */
+		task->hdr = &cmd->hdr;
+		task->hdr_max = sizeof(struct iscsi_hdr);
+
+		if (bnx2i_alloc_bdt(hba, session, cmd))
+			goto free_bdts;
+	}
+
+	return 0;
+
+free_bdts:
+	bnx2i_destroy_cmd_pool(hba, session);
+	return -ENOMEM;
+}
+
+
+/**
+ * bnx2i_setup_mp_bdt - allocate BD table resources
+ * @hba:	pointer to adapter structure
+ *
+ * Allocate memory for dummy buffer and associated BD
+ * table to be used by middle path (MP) requests
+ */
+static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
+{
+	int rc = 0;
+	struct iscsi_bd *mp_bdt;
+	u64 addr;
+
+	hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+					    &hba->mp_bd_dma, GFP_KERNEL);
+	if (!hba->mp_bd_tbl) {
+		printk(KERN_ERR "unable to allocate Middle Path BDT\n");
+		rc = -1;
+		goto out;
+	}
+
+	hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+					       &hba->dummy_buf_dma, GFP_KERNEL);
+	if (!hba->dummy_buffer) {
+		printk(KERN_ERR "unable to alloc Middle Path Dummy Buffer\n");
+		dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+				  hba->mp_bd_tbl, hba->mp_bd_dma);
+		hba->mp_bd_tbl = NULL;
+		rc = -1;
+		goto out;
+	}
+
+	mp_bdt = (struct iscsi_bd *) hba->mp_bd_tbl;
+	addr = (unsigned long) hba->dummy_buf_dma;
+	mp_bdt->buffer_addr_lo = addr & 0xffffffff;
+	mp_bdt->buffer_addr_hi = addr >> 32;
+	mp_bdt->buffer_length = PAGE_SIZE;
+	mp_bdt->flags = ISCSI_BD_LAST_IN_BD_CHAIN |
+			ISCSI_BD_FIRST_IN_BD_CHAIN;
+out:
+	return rc;
+}
+
+
+/**
+ * bnx2i_free_mp_bdt - releases ITT back to free pool
+ * @hba:	pointer to adapter instance
+ *
+ * free MP dummy buffer and associated BD table
+ */
+static void bnx2i_free_mp_bdt(struct bnx2i_hba *hba)
+{
+	if (hba->mp_bd_tbl) {
+		dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+				  hba->mp_bd_tbl, hba->mp_bd_dma);
+		hba->mp_bd_tbl = NULL;
+	}
+	if (hba->dummy_buffer) {
+		dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+				  hba->dummy_buffer, hba->dummy_buf_dma);
+		hba->dummy_buffer = NULL;
+	}
+		return;
+}
+
+/**
+ * bnx2i_drop_session - notifies iscsid of connection error.
+ * @hba:	adapter instance pointer
+ * @session:	iscsi session pointer
+ *
+ * This notifies iscsid that there is a error, so it can initiate
+ * recovery.
+ *
+ * This relies on caller using the iscsi class iterator so the object
+ * is refcounted and does not disapper from under us.
+ */
+void bnx2i_drop_session(struct iscsi_cls_session *cls_session)
+{
+	iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
+}
+
+/**
+ * bnx2i_ep_destroy_list_add - add an entry to EP destroy list
+ * @hba:	pointer to adapter instance
+ * @ep:		pointer to endpoint (transport indentifier) structure
+ *
+ * EP destroy queue manager
+ */
+static int bnx2i_ep_destroy_list_add(struct bnx2i_hba *hba,
+				     struct bnx2i_endpoint *ep)
+{
+	write_lock_bh(&hba->ep_rdwr_lock);
+	list_add_tail(&ep->link, &hba->ep_destroy_list);
+	write_unlock_bh(&hba->ep_rdwr_lock);
+	return 0;
+}
+
+/**
+ * bnx2i_ep_destroy_list_del - add an entry to EP destroy list
+ *
+ * @hba: 		pointer to adapter instance
+ * @ep: 		pointer to endpoint (transport indentifier) structure
+ *
+ * EP destroy queue manager
+ */
+static int bnx2i_ep_destroy_list_del(struct bnx2i_hba *hba,
+				     struct bnx2i_endpoint *ep)
+{
+	write_lock_bh(&hba->ep_rdwr_lock);
+	list_del_init(&ep->link);
+	write_unlock_bh(&hba->ep_rdwr_lock);
+
+	return 0;
+}
+
+/**
+ * bnx2i_ep_ofld_list_add - add an entry to ep offload pending list
+ * @hba:	pointer to adapter instance
+ * @ep:		pointer to endpoint (transport indentifier) structure
+ *
+ * pending conn offload completion queue manager
+ */
+static int bnx2i_ep_ofld_list_add(struct bnx2i_hba *hba,
+				  struct bnx2i_endpoint *ep)
+{
+	write_lock_bh(&hba->ep_rdwr_lock);
+	list_add_tail(&ep->link, &hba->ep_ofld_list);
+	write_unlock_bh(&hba->ep_rdwr_lock);
+	return 0;
+}
+
+/**
+ * bnx2i_ep_ofld_list_del - add an entry to ep offload pending list
+ * @hba: 		pointer to adapter instance
+ * @ep: 		pointer to endpoint (transport indentifier) structure
+ *
+ * pending conn offload completion queue manager
+ */
+static int bnx2i_ep_ofld_list_del(struct bnx2i_hba *hba,
+				  struct bnx2i_endpoint *ep)
+{
+	write_lock_bh(&hba->ep_rdwr_lock);
+	list_del_init(&ep->link);
+	write_unlock_bh(&hba->ep_rdwr_lock);
+	return 0;
+}
+
+
+/**
+ * bnx2i_find_ep_in_ofld_list - find iscsi_cid in pending list of endpoints
+ *
+ * @hba: 		pointer to adapter instance
+ * @iscsi_cid:		iscsi context ID to find
+ *
+ */
+struct bnx2i_endpoint *
+bnx2i_find_ep_in_ofld_list(struct bnx2i_hba *hba, u32 iscsi_cid)
+{
+	struct list_head *list;
+	struct list_head *tmp;
+	struct bnx2i_endpoint *ep;
+
+	read_lock_bh(&hba->ep_rdwr_lock);
+	list_for_each_safe(list, tmp, &hba->ep_ofld_list) {
+		ep = (struct bnx2i_endpoint *)list;
+
+		if (ep->ep_iscsi_cid == iscsi_cid)
+			break;
+		ep = NULL;
+	}
+	read_unlock_bh(&hba->ep_rdwr_lock);
+
+	if (!ep)
+		printk(KERN_ERR "l5 cid %d not found\n", iscsi_cid);
+	return ep;
+}
+
+
+/**
+ * bnx2i_find_ep_in_destroy_list - find iscsi_cid in destroy list
+ * @hba: 		pointer to adapter instance
+ * @iscsi_cid:		iscsi context ID to find
+ *
+ */
+struct bnx2i_endpoint *
+bnx2i_find_ep_in_destroy_list(struct bnx2i_hba *hba, u32 iscsi_cid)
+{
+	struct list_head *list;
+	struct list_head *tmp;
+	struct bnx2i_endpoint *ep;
+
+	read_lock_bh(&hba->ep_rdwr_lock);
+	list_for_each_safe(list, tmp, &hba->ep_destroy_list) {
+		ep = (struct bnx2i_endpoint *)list;
+
+		if (ep->ep_iscsi_cid == iscsi_cid)
+			break;
+		ep = NULL;
+	}
+	read_unlock_bh(&hba->ep_rdwr_lock);
+
+	if (!ep)
+		printk(KERN_ERR "l5 cid %d not found\n", iscsi_cid);
+
+	return ep;
+}
+
+/**
+ * bnx2i_setup_host_queue_size - assigns shost->can_queue param
+ * @hba:	pointer to adapter instance
+ * @shost:	scsi host pointer
+ *
+ * Initializes 'can_queue' parameter based on how many outstanding commands
+ * 	the device can handle. Each device 5708/5709/57710 has different
+ *	capabilities
+ */
+static void bnx2i_setup_host_queue_size(struct bnx2i_hba *hba,
+					struct Scsi_Host *shost)
+{
+	if (test_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type))
+		shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5708;
+	else if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type))
+		shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5709;
+	else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
+		shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_57710;
+	else
+		shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5708;
+}
+
+
+/**
+ * bnx2i_alloc_hba - allocate and init adapter instance
+ * @cnic:	cnic device pointer
+ *
+ * allocate & initialize adapter structure and call other
+ *	support routines to do per adapter initialization
+ */
+struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
+{
+	struct Scsi_Host *shost;
+	struct bnx2i_hba *hba;
+
+	shost = iscsi_host_alloc(&bnx2i_host_template, sizeof(*hba), 0);
+	if (!shost)
+		return NULL;
+	shost->dma_boundary = cnic->pcidev->dma_mask;
+	shost->transportt = bnx2i_scsi_xport_template;
+	shost->max_id = ISCSI_MAX_CONNS_PER_HBA;
+	shost->max_channel = 0;
+	shost->max_lun = 512;
+	shost->max_cmd_len = 16;
+
+	hba = iscsi_host_priv(shost);
+	hba->shost = shost;
+	hba->netdev = cnic->netdev;
+	/* Get PCI related information and update hba struct members */
+	hba->pcidev = cnic->pcidev;
+	pci_dev_get(hba->pcidev);
+	hba->pci_did = hba->pcidev->device;
+	hba->pci_vid = hba->pcidev->vendor;
+	hba->pci_sdid = hba->pcidev->subsystem_device;
+	hba->pci_svid = hba->pcidev->subsystem_vendor;
+	hba->pci_func = PCI_FUNC(hba->pcidev->devfn);
+	hba->pci_devno = PCI_SLOT(hba->pcidev->devfn);
+	bnx2i_identify_device(hba);
+
+	bnx2i_identify_device(hba);
+	bnx2i_setup_host_queue_size(hba, shost);
+
+	if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) {
+		hba->regview = ioremap_nocache(hba->netdev->base_addr,
+					       BNX2_MQ_CONFIG2);
+		if (!hba->regview)
+			goto ioreg_map_err;
+	} else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
+		hba->regview = ioremap_nocache(hba->netdev->base_addr, 4096);
+		if (!hba->regview)
+			goto ioreg_map_err;
+	}
+
+	if (bnx2i_setup_mp_bdt(hba))
+		goto mp_bdt_mem_err;
+
+	INIT_LIST_HEAD(&hba->ep_ofld_list);
+	INIT_LIST_HEAD(&hba->ep_destroy_list);
+	rwlock_init(&hba->ep_rdwr_lock);
+
+	hba->mtu_supported = BNX2I_MAX_MTU_SUPPORTED;
+
+	/* different values for 5708/5709/57710 */
+	hba->max_active_conns = ISCSI_MAX_CONNS_PER_HBA;
+
+	if (bnx2i_setup_free_cid_que(hba))
+		goto cid_que_err;
+
+	/* SQ/RQ/CQ size can be changed via sysfx interface */
+	if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
+		if (sq_size && sq_size <= BNX2I_5770X_SQ_WQES_MAX)
+			hba->max_sqes = sq_size;
+		else
+			hba->max_sqes = BNX2I_5770X_SQ_WQES_DEFAULT;
+	} else {	/* 5706/5708/5709 */
+		if (sq_size && sq_size <= BNX2I_570X_SQ_WQES_MAX)
+			hba->max_sqes = sq_size;
+		else
+			hba->max_sqes = BNX2I_570X_SQ_WQES_DEFAULT;
+	}
+
+	hba->max_rqes = rq_size;
+	hba->max_cqes = hba->max_sqes + rq_size;
+	if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
+		if (hba->max_cqes > BNX2I_5770X_CQ_WQES_MAX)
+			hba->max_cqes = BNX2I_5770X_CQ_WQES_MAX;
+	} else if (hba->max_cqes > BNX2I_570X_CQ_WQES_MAX)
+		hba->max_cqes = BNX2I_570X_CQ_WQES_MAX;
+
+	hba->num_ccell = hba->max_sqes / 2;
+
+	spin_lock_init(&hba->lock);
+	mutex_init(&hba->net_dev_lock);
+
+	if (iscsi_host_add(shost, &hba->pcidev->dev))
+		goto free_dump_mem;
+	return hba;
+
+free_dump_mem:
+	bnx2i_release_free_cid_que(hba);
+cid_que_err:
+	bnx2i_free_mp_bdt(hba);
+mp_bdt_mem_err:
+	if (hba->regview) {
+		iounmap(hba->regview);
+		hba->regview = NULL;
+	}
+ioreg_map_err:
+	pci_dev_put(hba->pcidev);
+	scsi_host_put(shost);
+	return NULL;
+}
+
+/**
+ * bnx2i_free_hba- releases hba structure and resources held by the adapter
+ * @hba:	pointer to adapter instance
+ *
+ * free adapter structure and call various cleanup routines.
+ */
+void bnx2i_free_hba(struct bnx2i_hba *hba)
+{
+	struct Scsi_Host *shost = hba->shost;
+
+	iscsi_host_remove(shost);
+	INIT_LIST_HEAD(&hba->ep_ofld_list);
+	INIT_LIST_HEAD(&hba->ep_destroy_list);
+	pci_dev_put(hba->pcidev);
+
+	if (hba->regview) {
+		iounmap(hba->regview);
+		hba->regview = NULL;
+	}
+	bnx2i_free_mp_bdt(hba);
+	bnx2i_release_free_cid_que(hba);
+	iscsi_host_free(shost);
+}
+
+/**
+ * bnx2i_conn_free_login_resources - free DMA resources used for login process
+ * @hba:		pointer to adapter instance
+ * @bnx2i_conn:		iscsi connection pointer
+ *
+ * Login related resources, mostly BDT & payload DMA memory is freed
+ */
+static void bnx2i_conn_free_login_resources(struct bnx2i_hba *hba,
+					    struct bnx2i_conn *bnx2i_conn)
+{
+	if (bnx2i_conn->gen_pdu.resp_bd_tbl) {
+		dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+				  bnx2i_conn->gen_pdu.resp_bd_tbl,
+				  bnx2i_conn->gen_pdu.resp_bd_dma);
+		bnx2i_conn->gen_pdu.resp_bd_tbl = NULL;
+	}
+
+	if (bnx2i_conn->gen_pdu.req_bd_tbl) {
+		dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+				  bnx2i_conn->gen_pdu.req_bd_tbl,
+				  bnx2i_conn->gen_pdu.req_bd_dma);
+		bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
+	}
+
+	if (bnx2i_conn->gen_pdu.resp_buf) {
+		dma_free_coherent(&hba->pcidev->dev,
+				  ISCSI_DEF_MAX_RECV_SEG_LEN,
+				  bnx2i_conn->gen_pdu.resp_buf,
+				  bnx2i_conn->gen_pdu.resp_dma_addr);
+		bnx2i_conn->gen_pdu.resp_buf = NULL;
+	}
+
+	if (bnx2i_conn->gen_pdu.req_buf) {
+		dma_free_coherent(&hba->pcidev->dev,
+				  ISCSI_DEF_MAX_RECV_SEG_LEN,
+				  bnx2i_conn->gen_pdu.req_buf,
+				  bnx2i_conn->gen_pdu.req_dma_addr);
+		bnx2i_conn->gen_pdu.req_buf = NULL;
+	}
+}
+
+/**
+ * bnx2i_conn_alloc_login_resources - alloc DMA resources for login/nop.
+ * @hba:		pointer to adapter instance
+ * @bnx2i_conn:		iscsi connection pointer
+ *
+ * Mgmt task DNA resources are allocated in this routine.
+ */
+static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba,
+					    struct bnx2i_conn *bnx2i_conn)
+{
+	/* Allocate memory for login request/response buffers */
+	bnx2i_conn->gen_pdu.req_buf =
+		dma_alloc_coherent(&hba->pcidev->dev,
+				   ISCSI_DEF_MAX_RECV_SEG_LEN,
+				   &bnx2i_conn->gen_pdu.req_dma_addr,
+				   GFP_KERNEL);
+	if (bnx2i_conn->gen_pdu.req_buf == NULL)
+		goto login_req_buf_failure;
+
+	bnx2i_conn->gen_pdu.req_buf_size = 0;
+	bnx2i_conn->gen_pdu.req_wr_ptr = bnx2i_conn->gen_pdu.req_buf;
+
+	bnx2i_conn->gen_pdu.resp_buf =
+		dma_alloc_coherent(&hba->pcidev->dev,
+				   ISCSI_DEF_MAX_RECV_SEG_LEN,
+				   &bnx2i_conn->gen_pdu.resp_dma_addr,
+				   GFP_KERNEL);
+	if (bnx2i_conn->gen_pdu.resp_buf == NULL)
+		goto login_resp_buf_failure;
+
+	bnx2i_conn->gen_pdu.resp_buf_size = ISCSI_DEF_MAX_RECV_SEG_LEN;
+	bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf;
+
+	bnx2i_conn->gen_pdu.req_bd_tbl =
+		dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+				   &bnx2i_conn->gen_pdu.req_bd_dma, GFP_KERNEL);
+	if (bnx2i_conn->gen_pdu.req_bd_tbl == NULL)
+		goto login_req_bd_tbl_failure;
+
+	bnx2i_conn->gen_pdu.resp_bd_tbl =
+		dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+				   &bnx2i_conn->gen_pdu.resp_bd_dma,
+				   GFP_KERNEL);
+	if (bnx2i_conn->gen_pdu.resp_bd_tbl == NULL)
+		goto login_resp_bd_tbl_failure;
+
+	return 0;
+
+login_resp_bd_tbl_failure:
+	dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+			  bnx2i_conn->gen_pdu.req_bd_tbl,
+			  bnx2i_conn->gen_pdu.req_bd_dma);
+	bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
+
+login_req_bd_tbl_failure:
+	dma_free_coherent(&hba->pcidev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN,
+			  bnx2i_conn->gen_pdu.resp_buf,
+			  bnx2i_conn->gen_pdu.resp_dma_addr);
+	bnx2i_conn->gen_pdu.resp_buf = NULL;
+login_resp_buf_failure:
+	dma_free_coherent(&hba->pcidev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN,
+			  bnx2i_conn->gen_pdu.req_buf,
+			  bnx2i_conn->gen_pdu.req_dma_addr);
+	bnx2i_conn->gen_pdu.req_buf = NULL;
+login_req_buf_failure:
+	iscsi_conn_printk(KERN_ERR, bnx2i_conn->cls_conn->dd_data,
+			  "login resource alloc failed!!\n");
+	return -ENOMEM;
+
+}
+
+
+/**
+ * bnx2i_iscsi_prep_generic_pdu_bd - prepares BD table.
+ * @bnx2i_conn:		iscsi connection pointer
+ *
+ * Allocates buffers and BD tables before shipping requests to cnic
+ *	for PDUs prepared by 'iscsid' daemon
+ */
+static void bnx2i_iscsi_prep_generic_pdu_bd(struct bnx2i_conn *bnx2i_conn)
+{
+	struct iscsi_bd *bd_tbl;
+
+	bd_tbl = (struct iscsi_bd *) bnx2i_conn->gen_pdu.req_bd_tbl;
+
+	bd_tbl->buffer_addr_hi =
+		(u32) ((u64) bnx2i_conn->gen_pdu.req_dma_addr >> 32);
+	bd_tbl->buffer_addr_lo = (u32) bnx2i_conn->gen_pdu.req_dma_addr;
+	bd_tbl->buffer_length = bnx2i_conn->gen_pdu.req_wr_ptr -
+				bnx2i_conn->gen_pdu.req_buf;
+	bd_tbl->reserved0 = 0;
+	bd_tbl->flags = ISCSI_BD_LAST_IN_BD_CHAIN |
+			ISCSI_BD_FIRST_IN_BD_CHAIN;
+
+	bd_tbl = (struct iscsi_bd  *) bnx2i_conn->gen_pdu.resp_bd_tbl;
+	bd_tbl->buffer_addr_hi = (u64) bnx2i_conn->gen_pdu.resp_dma_addr >> 32;
+	bd_tbl->buffer_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_dma_addr;
+	bd_tbl->buffer_length = ISCSI_DEF_MAX_RECV_SEG_LEN;
+	bd_tbl->reserved0 = 0;
+	bd_tbl->flags = ISCSI_BD_LAST_IN_BD_CHAIN |
+			ISCSI_BD_FIRST_IN_BD_CHAIN;
+}
+
+
+/**
+ * bnx2i_iscsi_send_generic_request - called to send mgmt tasks.
+ * @task:	transport layer task pointer
+ *
+ * called to transmit PDUs prepared by the 'iscsid' daemon. iSCSI login,
+ *	Nop-out and Logout requests flow through this path.
+ */
+static int bnx2i_iscsi_send_generic_request(struct iscsi_task *task)
+{
+	struct bnx2i_cmd *cmd = task->dd_data;
+	struct bnx2i_conn *bnx2i_conn = cmd->conn;
+	int rc = 0;
+	char *buf;
+	int data_len;
+
+	bnx2i_iscsi_prep_generic_pdu_bd(bnx2i_conn);
+	switch (task->hdr->opcode & ISCSI_OPCODE_MASK) {
+	case ISCSI_OP_LOGIN:
+		bnx2i_send_iscsi_login(bnx2i_conn, task);
+		break;
+	case ISCSI_OP_NOOP_OUT:
+		data_len = bnx2i_conn->gen_pdu.req_buf_size;
+		buf = bnx2i_conn->gen_pdu.req_buf;
+		if (data_len)
+			rc = bnx2i_send_iscsi_nopout(bnx2i_conn, task,
+						     RESERVED_ITT,
+						     buf, data_len, 1);
+		else
+			rc = bnx2i_send_iscsi_nopout(bnx2i_conn, task,
+						     RESERVED_ITT,
+						     NULL, 0, 1);
+		break;
+	case ISCSI_OP_LOGOUT:
+		rc = bnx2i_send_iscsi_logout(bnx2i_conn, task);
+		break;
+	case ISCSI_OP_SCSI_TMFUNC:
+		rc = bnx2i_send_iscsi_tmf(bnx2i_conn, task);
+		break;
+	default:
+		iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data,
+				  "send_gen: unsupported op 0x%x\n",
+				  task->hdr->opcode);
+	}
+	return rc;
+}
+
+
+/**********************************************************************
+ *		SCSI-ML Interface
+ **********************************************************************/
+
+/**
+ * bnx2i_cpy_scsi_cdb - copies LUN & CDB fields in required format to sq wqe
+ * @sc:		SCSI-ML command pointer
+ * @cmd:	iscsi cmd pointer
+ */
+static void bnx2i_cpy_scsi_cdb(struct scsi_cmnd *sc, struct bnx2i_cmd *cmd)
+{
+	u32 dword;
+	int lpcnt;
+	u8 *srcp;
+	u32 *dstp;
+	u32 scsi_lun[2];
+
+	int_to_scsilun(sc->device->lun, (struct scsi_lun *) scsi_lun);
+	cmd->req.lun[0] = be32_to_cpu(scsi_lun[0]);
+	cmd->req.lun[1] = be32_to_cpu(scsi_lun[1]);
+
+	lpcnt = cmd->scsi_cmd->cmd_len / sizeof(dword);
+	srcp = (u8 *) sc->cmnd;
+	dstp = (u32 *) cmd->req.cdb;
+	while (lpcnt--) {
+		memcpy(&dword, (const void *) srcp, 4);
+		*dstp = cpu_to_be32(dword);
+		srcp += 4;
+		dstp++;
+	}
+	if (sc->cmd_len & 0x3) {
+		dword = (u32) srcp[0] | ((u32) srcp[1] << 8);
+		*dstp = cpu_to_be32(dword);
+	}
+}
+
+static void bnx2i_cleanup_task(struct iscsi_task *task)
+{
+	struct iscsi_conn *conn = task->conn;
+	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+	struct bnx2i_hba *hba = bnx2i_conn->hba;
+
+	/*
+	 * mgmt task or cmd was never sent to us to transmit.
+	 */
+	if (!task->sc || task->state == ISCSI_TASK_PENDING)
+		return;
+	/*
+	 * need to clean-up task context to claim dma buffers
+	 */
+	if (task->state == ISCSI_TASK_ABRT_TMF) {
+		bnx2i_send_cmd_cleanup_req(hba, task->dd_data);
+
+		spin_unlock_bh(&conn->session->lock);
+		wait_for_completion_timeout(&bnx2i_conn->cmd_cleanup_cmpl,
+				msecs_to_jiffies(ISCSI_CMD_CLEANUP_TIMEOUT));
+		spin_lock_bh(&conn->session->lock);
+	}
+	bnx2i_iscsi_unmap_sg_list(task->dd_data);
+}
+
+/**
+ * bnx2i_mtask_xmit - transmit mtask to chip for further processing
+ * @conn:	transport layer conn structure pointer
+ * @task:	transport layer command structure pointer
+ */
+static int
+bnx2i_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
+{
+	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+	struct bnx2i_cmd *cmd = task->dd_data;
+
+	memset(bnx2i_conn->gen_pdu.req_buf, 0, ISCSI_DEF_MAX_RECV_SEG_LEN);
+
+	bnx2i_setup_cmd_wqe_template(cmd);
+	bnx2i_conn->gen_pdu.req_buf_size = task->data_count;
+	if (task->data_count) {
+		memcpy(bnx2i_conn->gen_pdu.req_buf, task->data,
+		       task->data_count);
+		bnx2i_conn->gen_pdu.req_wr_ptr =
+			bnx2i_conn->gen_pdu.req_buf + task->data_count;
+	}
+	cmd->conn = conn->dd_data;
+	cmd->scsi_cmd = NULL;
+	return bnx2i_iscsi_send_generic_request(task);
+}
+
+/**
+ * bnx2i_task_xmit - transmit iscsi command to chip for further processing
+ * @task:	transport layer command structure pointer
+ *
+ * maps SG buffers and send request to chip/firmware in the form of SQ WQE
+ */
+static int bnx2i_task_xmit(struct iscsi_task *task)
+{
+	struct iscsi_conn *conn = task->conn;
+	struct iscsi_session *session = conn->session;
+	struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
+	struct bnx2i_hba *hba = iscsi_host_priv(shost);
+	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+	struct scsi_cmnd *sc = task->sc;
+	struct bnx2i_cmd *cmd = task->dd_data;
+	struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr;
+
+	if (test_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state))
+		return -ENOTCONN;
+
+	if (!bnx2i_conn->is_bound)
+		return -ENOTCONN;
+
+	/*
+	 * If there is no scsi_cmnd this must be a mgmt task
+	 */
+	if (!sc)
+		return bnx2i_mtask_xmit(conn, task);
+
+	bnx2i_setup_cmd_wqe_template(cmd);
+	cmd->req.op_code = ISCSI_OP_SCSI_CMD;
+	cmd->conn = bnx2i_conn;
+	cmd->scsi_cmd = sc;
+	cmd->req.total_data_transfer_length = scsi_bufflen(sc);
+	cmd->req.cmd_sn = be32_to_cpu(hdr->cmdsn);
+
+	bnx2i_iscsi_map_sg_list(cmd);
+	bnx2i_cpy_scsi_cdb(sc, cmd);
+
+	cmd->req.op_attr = ISCSI_ATTR_SIMPLE;
+	if (sc->sc_data_direction == DMA_TO_DEVICE) {
+		cmd->req.op_attr |= ISCSI_CMD_REQUEST_WRITE;
+		cmd->req.itt = task->itt |
+			(ISCSI_TASK_TYPE_WRITE << ISCSI_CMD_REQUEST_TYPE_SHIFT);
+		bnx2i_setup_write_cmd_bd_info(task);
+	} else {
+		if (scsi_bufflen(sc))
+			cmd->req.op_attr |= ISCSI_CMD_REQUEST_READ;
+		cmd->req.itt = task->itt |
+			(ISCSI_TASK_TYPE_READ << ISCSI_CMD_REQUEST_TYPE_SHIFT);
+	}
+
+	cmd->req.num_bds = cmd->io_tbl.bd_valid;
+	if (!cmd->io_tbl.bd_valid) {
+		cmd->req.bd_list_addr_lo = (u32) hba->mp_bd_dma;
+		cmd->req.bd_list_addr_hi = (u32) ((u64) hba->mp_bd_dma >> 32);
+		cmd->req.num_bds = 1;
+	}
+
+	bnx2i_send_iscsi_scsicmd(bnx2i_conn, cmd);
+	return 0;
+}
+
+/**
+ * bnx2i_session_create - create a new iscsi session
+ * @cmds_max:		max commands supported
+ * @qdepth:		scsi queue depth to support
+ * @initial_cmdsn:	initial iscsi CMDSN to be used for this session
+ *
+ * Creates a new iSCSI session instance on given device.
+ */
+static struct iscsi_cls_session *
+bnx2i_session_create(struct iscsi_endpoint *ep,
+		     uint16_t cmds_max, uint16_t qdepth,
+		     uint32_t initial_cmdsn)
+{
+	struct Scsi_Host *shost;
+	struct iscsi_cls_session *cls_session;
+	struct bnx2i_hba *hba;
+	struct bnx2i_endpoint *bnx2i_ep;
+
+	if (!ep) {
+		printk(KERN_ERR "bnx2i: missing ep.\n");
+		return NULL;
+	}
+
+	bnx2i_ep = ep->dd_data;
+	shost = bnx2i_ep->hba->shost;
+	hba = iscsi_host_priv(shost);
+	if (bnx2i_adapter_ready(hba))
+		return NULL;
+
+	/*
+	 * user can override hw limit as long as it is within
+	 * the min/max.
+	 */
+	if (cmds_max > hba->max_sqes)
+		cmds_max = hba->max_sqes;
+	else if (cmds_max < BNX2I_SQ_WQES_MIN)
+		cmds_max = BNX2I_SQ_WQES_MIN;
+
+	cls_session = iscsi_session_setup(&bnx2i_iscsi_transport, shost,
+					  cmds_max, sizeof(struct bnx2i_cmd),
+					  initial_cmdsn, ISCSI_MAX_TARGET);
+	if (!cls_session)
+		return NULL;
+
+	if (bnx2i_setup_cmd_pool(hba, cls_session->dd_data))
+		goto session_teardown;
+	return cls_session;
+
+session_teardown:
+	iscsi_session_teardown(cls_session);
+	return NULL;
+}
+
+
+/**
+ * bnx2i_session_destroy - destroys iscsi session
+ * @cls_session:	pointer to iscsi cls session
+ *
+ * Destroys previously created iSCSI session instance and releases
+ *	all resources held by it
+ */
+static void bnx2i_session_destroy(struct iscsi_cls_session *cls_session)
+{
+	struct iscsi_session *session = cls_session->dd_data;
+	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+	struct bnx2i_hba *hba = iscsi_host_priv(shost);
+
+	bnx2i_destroy_cmd_pool(hba, session);
+	iscsi_session_teardown(cls_session);
+}
+
+
+/**
+ * bnx2i_conn_create - create iscsi connection instance
+ * @cls_session:	pointer to iscsi cls session
+ * @cid:		iscsi cid as per rfc (not NX2's CID terminology)
+ *
+ * Creates a new iSCSI connection instance for a given session
+ */
+static struct iscsi_cls_conn *
+bnx2i_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid)
+{
+	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+	struct bnx2i_hba *hba = iscsi_host_priv(shost);
+	struct bnx2i_conn *bnx2i_conn;
+	struct iscsi_cls_conn *cls_conn;
+	struct iscsi_conn *conn;
+
+	cls_conn = iscsi_conn_setup(cls_session, sizeof(*bnx2i_conn),
+				    cid);
+	if (!cls_conn)
+		return NULL;
+	conn = cls_conn->dd_data;
+
+	bnx2i_conn = conn->dd_data;
+	bnx2i_conn->cls_conn = cls_conn;
+	bnx2i_conn->hba = hba;
+	/* 'ep' ptr will be assigned in bind() call */
+	bnx2i_conn->ep = NULL;
+	init_completion(&bnx2i_conn->cmd_cleanup_cmpl);
+
+	if (bnx2i_conn_alloc_login_resources(hba, bnx2i_conn)) {
+		iscsi_conn_printk(KERN_ALERT, conn,
+				  "conn_new: login resc alloc failed!!\n");
+		goto free_conn;
+	}
+
+	return cls_conn;
+
+free_conn:
+	iscsi_conn_teardown(cls_conn);
+	return NULL;
+}
+
+/**
+ * bnx2i_conn_bind - binds iscsi sess, conn and ep objects together
+ * @cls_session:	pointer to iscsi cls session
+ * @cls_conn:		pointer to iscsi cls conn
+ * @transport_fd:	64-bit EP handle
+ * @is_leading:		leading connection on this session?
+ *
+ * Binds together iSCSI session instance, iSCSI connection instance
+ *	and the TCP connection. This routine returns error code if
+ *	TCP connection does not belong on the device iSCSI sess/conn
+ *	is bound
+ */
+static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
+			   struct iscsi_cls_conn *cls_conn,
+			   uint64_t transport_fd, int is_leading)
+{
+	struct iscsi_conn *conn = cls_conn->dd_data;
+	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+	struct bnx2i_hba *hba = iscsi_host_priv(shost);
+	struct bnx2i_endpoint *bnx2i_ep;
+	struct iscsi_endpoint *ep;
+	int ret_code;
+
+	ep = iscsi_lookup_endpoint(transport_fd);
+	if (!ep)
+		return -EINVAL;
+
+	bnx2i_ep = ep->dd_data;
+	if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) ||
+	    (bnx2i_ep->state == EP_STATE_TCP_RST_RCVD))
+		/* Peer disconnect via' FIN or RST */
+		return -EINVAL;
+
+	if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
+		return -EINVAL;
+
+	if (bnx2i_ep->hba != hba) {
+		/* Error - TCP connection does not belong to this device
+		 */
+		iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data,
+				  "conn bind, ep=0x%p (%s) does not",
+				  bnx2i_ep, bnx2i_ep->hba->netdev->name);
+		iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data,
+				  "belong to hba (%s)\n",
+				  hba->netdev->name);
+		return -EEXIST;
+	}
+
+	bnx2i_ep->conn = bnx2i_conn;
+	bnx2i_conn->ep = bnx2i_ep;
+	bnx2i_conn->iscsi_conn_cid = bnx2i_ep->ep_iscsi_cid;
+	bnx2i_conn->fw_cid = bnx2i_ep->ep_cid;
+	bnx2i_conn->is_bound = 1;
+
+	ret_code = bnx2i_bind_conn_to_iscsi_cid(hba, bnx2i_conn,
+						bnx2i_ep->ep_iscsi_cid);
+
+	/* 5706/5708/5709 FW takes RQ as full when initiated, but for 57710
+	 * driver needs to explicitly replenish RQ index during setup.
+	 */
+	if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_ep->hba->cnic_dev_type))
+		bnx2i_put_rq_buf(bnx2i_conn, 0);
+
+	bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE);
+	return ret_code;
+}
+
+
+/**
+ * bnx2i_conn_destroy - destroy iscsi connection instance & release resources
+ * @cls_conn:	pointer to iscsi cls conn
+ *
+ * Destroy an iSCSI connection instance and release memory resources held by
+ *	this connection
+ */
+static void bnx2i_conn_destroy(struct iscsi_cls_conn *cls_conn)
+{
+	struct iscsi_conn *conn = cls_conn->dd_data;
+	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+	struct Scsi_Host *shost;
+	struct bnx2i_hba *hba;
+
+	shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn));
+	hba = iscsi_host_priv(shost);
+
+	bnx2i_conn_free_login_resources(hba, bnx2i_conn);
+	iscsi_conn_teardown(cls_conn);
+}
+
+
+/**
+ * bnx2i_conn_get_param - return iscsi connection parameter to caller
+ * @cls_conn:	pointer to iscsi cls conn
+ * @param:	parameter type identifier
+ * @buf: 	buffer pointer
+ *
+ * returns iSCSI connection parameters
+ */
+static int bnx2i_conn_get_param(struct iscsi_cls_conn *cls_conn,
+				enum iscsi_param param, char *buf)
+{
+	struct iscsi_conn *conn = cls_conn->dd_data;
+	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+	int len = 0;
+
+	switch (param) {
+	case ISCSI_PARAM_CONN_PORT:
+		if (bnx2i_conn->ep)
+			len = sprintf(buf, "%hu\n",
+				      bnx2i_conn->ep->cm_sk->dst_port);
+		break;
+	case ISCSI_PARAM_CONN_ADDRESS:
+		if (bnx2i_conn->ep)
+			len = sprintf(buf, NIPQUAD_FMT "\n",
+				      NIPQUAD(bnx2i_conn->ep->cm_sk->dst_ip));
+		break;
+	default:
+		return iscsi_conn_get_param(cls_conn, param, buf);
+	}
+
+	return len;
+}
+
+/**
+ * bnx2i_host_get_param - returns host (adapter) related parameters
+ * @shost:	scsi host pointer
+ * @param:	parameter type identifier
+ * @buf:	buffer pointer
+ */
+static int bnx2i_host_get_param(struct Scsi_Host *shost,
+				enum iscsi_host_param param, char *buf)
+{
+	struct bnx2i_hba *hba = iscsi_host_priv(shost);
+	int len = 0;
+
+	switch (param) {
+	case ISCSI_HOST_PARAM_HWADDRESS:
+		len = sysfs_format_mac(buf, hba->cnic->mac_addr, 6);
+		break;
+	case ISCSI_HOST_PARAM_NETDEV_NAME:
+		len = sprintf(buf, "%s\n", hba->netdev->name);
+		break;
+	default:
+		return iscsi_host_get_param(shost, param, buf);
+	}
+	return len;
+}
+
+/**
+ * bnx2i_conn_start - completes iscsi connection migration to FFP
+ * @cls_conn:	pointer to iscsi cls conn
+ *
+ * last call in FFP migration to handover iscsi conn to the driver
+ */
+static int bnx2i_conn_start(struct iscsi_cls_conn *cls_conn)
+{
+	struct iscsi_conn *conn = cls_conn->dd_data;
+	struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+
+	bnx2i_conn->ep->state = EP_STATE_ULP_UPDATE_START;
+	bnx2i_update_iscsi_conn(conn);
+
+	/*
+	 * this should normally not sleep for a long time so it should
+	 * not disrupt the caller.
+	 */
+	bnx2i_conn->ep->ofld_timer.expires = 1 * HZ + jiffies;
+	bnx2i_conn->ep->ofld_timer.function = bnx2i_ep_ofld_timer;
+	bnx2i_conn->ep->ofld_timer.data = (unsigned long) bnx2i_conn->ep;
+	add_timer(&bnx2i_conn->ep->ofld_timer);
+	/* update iSCSI context for this conn, wait for CNIC to complete */
+	wait_event_interruptible(bnx2i_conn->ep->ofld_wait,
+			bnx2i_conn->ep->state != EP_STATE_ULP_UPDATE_START);
+
+	if (signal_pending(current))
+		flush_signals(current);
+	del_timer_sync(&bnx2i_conn->ep->ofld_timer);
+
+	iscsi_conn_start(cls_conn);
+	return 0;
+}
+
+
+/**
+ * bnx2i_conn_get_stats - returns iSCSI stats
+ * @cls_conn:	pointer to iscsi cls conn
+ * @stats:	pointer to iscsi statistic struct
+ */
+static void bnx2i_conn_get_stats(struct iscsi_cls_conn *cls_conn,
+				 struct iscsi_stats *stats)
+{
+	struct iscsi_conn *conn = cls_conn->dd_data;
+
+	stats->txdata_octets = conn->txdata_octets;
+	stats->rxdata_octets = conn->rxdata_octets;
+	stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
+	stats->dataout_pdus = conn->dataout_pdus_cnt;
+	stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
+	stats->datain_pdus = conn->datain_pdus_cnt;
+	stats->r2t_pdus = conn->r2t_pdus_cnt;
+	stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
+	stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
+	stats->custom_length = 3;
+	strcpy(stats->custom[2].desc, "eh_abort_cnt");
+	stats->custom[2].value = conn->eh_abort_cnt;
+	stats->digest_err = 0;
+	stats->timeout_err = 0;
+	stats->custom_length = 0;
+}
+
+
+/**
+ * bnx2i_check_route - checks if target IP route belongs to one of NX2 devices
+ * @dst_addr:	target IP address
+ *
+ * check if route resolves to BNX2 device
+ */
+static struct bnx2i_hba *bnx2i_check_route(struct sockaddr *dst_addr)
+{
+	struct sockaddr_in *desti = (struct sockaddr_in *) dst_addr;
+	struct bnx2i_hba *hba;
+	struct cnic_dev *cnic = NULL;
+
+	bnx2i_reg_dev_all();
+
+	hba = get_adapter_list_head();
+	if (hba && hba->cnic)
+		cnic = hba->cnic->cm_select_dev(desti, CNIC_ULP_ISCSI);
+	if (!cnic) {
+		printk(KERN_ALERT "bnx2i: no route,"
+		       "can't connect using cnic\n");
+		goto no_nx2_route;
+	}
+	hba = bnx2i_find_hba_for_cnic(cnic);
+	if (!hba)
+		goto no_nx2_route;
+
+	if (bnx2i_adapter_ready(hba)) {
+		printk(KERN_ALERT "bnx2i: check route, hba not found\n");
+		goto no_nx2_route;
+	}
+	if (hba->netdev->mtu > hba->mtu_supported) {
+		printk(KERN_ALERT "bnx2i: %s network i/f mtu is set to %d\n",
+				  hba->netdev->name, hba->netdev->mtu);
+		printk(KERN_ALERT "bnx2i: iSCSI HBA can support mtu of %d\n",
+				  hba->mtu_supported);
+		goto no_nx2_route;
+	}
+	return hba;
+no_nx2_route:
+	return NULL;
+}
+
+
+/**
+ * bnx2i_tear_down_conn - tear down iscsi/tcp connection and free resources
+ * @hba:	pointer to adapter instance
+ * @ep:		endpoint (transport indentifier) structure
+ *
+ * destroys cm_sock structure and on chip iscsi context
+ */
+static int bnx2i_tear_down_conn(struct bnx2i_hba *hba,
+				 struct bnx2i_endpoint *ep)
+{
+	if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic))
+		hba->cnic->cm_destroy(ep->cm_sk);
+
+	if (test_bit(ADAPTER_STATE_GOING_DOWN, &ep->hba->adapter_state))
+		ep->state = EP_STATE_DISCONN_COMPL;
+
+	if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type) &&
+	    ep->state == EP_STATE_DISCONN_TIMEDOUT) {
+		printk(KERN_ALERT "bnx2i - ERROR - please submit GRC Dump,"
+				  " NW/PCIe trace, driver msgs to developers"
+				  " for analysis\n");
+		return 1;
+	}
+
+	ep->state = EP_STATE_CLEANUP_START;
+	init_timer(&ep->ofld_timer);
+	ep->ofld_timer.expires = 10*HZ + jiffies;
+	ep->ofld_timer.function = bnx2i_ep_ofld_timer;
+	ep->ofld_timer.data = (unsigned long) ep;
+	add_timer(&ep->ofld_timer);
+
+	bnx2i_ep_destroy_list_add(hba, ep);
+
+	/* destroy iSCSI context, wait for it to complete */
+	bnx2i_send_conn_destroy(hba, ep);
+	wait_event_interruptible(ep->ofld_wait,
+				 (ep->state != EP_STATE_CLEANUP_START));
+
+	if (signal_pending(current))
+		flush_signals(current);
+	del_timer_sync(&ep->ofld_timer);
+
+	bnx2i_ep_destroy_list_del(hba, ep);
+
+	if (ep->state != EP_STATE_CLEANUP_CMPL)
+		/* should never happen */
+		printk(KERN_ALERT "bnx2i - conn destroy failed\n");
+
+	return 0;
+}
+
+
+/**
+ * bnx2i_ep_connect - establish TCP connection to target portal
+ * @shost:		scsi host
+ * @dst_addr:		target IP address
+ * @non_blocking:	blocking or non-blocking call
+ *
+ * this routine initiates the TCP/IP connection by invoking Option-2 i/f
+ *	with l5_core and the CNIC. This is a multi-step process of resolving
+ *	route to target, create a iscsi connection context, handshaking with
+ *	CNIC module to create/initialize the socket struct and finally
+ *	sending down option-2 request to complete TCP 3-way handshake
+ */
+static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
+					       struct sockaddr *dst_addr,
+					       int non_blocking)
+{
+	u32 iscsi_cid = BNX2I_CID_RESERVED;
+	struct sockaddr_in *desti = (struct sockaddr_in *) dst_addr;
+	struct sockaddr_in6 *desti6;
+	struct bnx2i_endpoint *bnx2i_ep;
+	struct bnx2i_hba *hba;
+	struct cnic_dev *cnic;
+	struct cnic_sockaddr saddr;
+	struct iscsi_endpoint *ep;
+	int rc = 0;
+
+	if (shost)
+		/* driver is given scsi host to work with */
+		hba = iscsi_host_priv(shost);
+	else
+		/*
+		 * check if the given destination can be reached through
+		 * a iscsi capable NetXtreme2 device
+		 */
+		hba = bnx2i_check_route(dst_addr);
+	if (!hba) {
+		rc = -ENOMEM;
+		goto check_busy;
+	}
+
+	cnic = hba->cnic;
+	ep = bnx2i_alloc_ep(hba);
+	if (!ep) {
+		rc = -ENOMEM;
+		goto check_busy;
+	}
+	bnx2i_ep = ep->dd_data;
+
+	mutex_lock(&hba->net_dev_lock);
+	if (bnx2i_adapter_ready(hba)) {
+		rc = -EPERM;
+		goto net_if_down;
+	}
+
+	bnx2i_ep->state = EP_STATE_IDLE;
+	bnx2i_ep->ep_iscsi_cid = (u16) -1;
+	bnx2i_ep->num_active_cmds = 0;
+	iscsi_cid = bnx2i_alloc_iscsi_cid(hba);
+	if (iscsi_cid == -1) {
+		printk(KERN_ALERT "alloc_ep: unable to allocate iscsi cid\n");
+		rc = -ENOMEM;
+		goto iscsi_cid_err;
+	}
+	bnx2i_ep->hba_age = hba->age;
+
+	rc = bnx2i_alloc_qp_resc(hba, bnx2i_ep);
+	if (rc != 0) {
+		printk(KERN_ALERT "bnx2i: ep_conn, alloc QP resc error\n");
+		rc = -ENOMEM;
+		goto qp_resc_err;
+	}
+
+	bnx2i_ep->ep_iscsi_cid = (u16)iscsi_cid;
+	bnx2i_ep->state = EP_STATE_OFLD_START;
+	bnx2i_ep_ofld_list_add(hba, bnx2i_ep);
+
+	init_timer(&bnx2i_ep->ofld_timer);
+	bnx2i_ep->ofld_timer.expires = 2 * HZ + jiffies;
+	bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
+	bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
+	add_timer(&bnx2i_ep->ofld_timer);
+
+	bnx2i_send_conn_ofld_req(hba, bnx2i_ep);
+
+	/* Wait for CNIC hardware to setup conn context and return 'cid' */
+	wait_event_interruptible(bnx2i_ep->ofld_wait,
+				 bnx2i_ep->state != EP_STATE_OFLD_START);
+
+	if (signal_pending(current))
+		flush_signals(current);
+	del_timer_sync(&bnx2i_ep->ofld_timer);
+
+	bnx2i_ep_ofld_list_del(hba, bnx2i_ep);
+
+	if (bnx2i_ep->state != EP_STATE_OFLD_COMPL) {
+		rc = -ENOSPC;
+		goto conn_failed;
+	}
+
+	rc = cnic->cm_create(cnic, CNIC_ULP_ISCSI, bnx2i_ep->ep_cid,
+			     iscsi_cid, &bnx2i_ep->cm_sk, bnx2i_ep);
+	if (rc) {
+		rc = -EINVAL;
+		goto conn_failed;
+	}
+
+	bnx2i_ep->cm_sk->rcv_buf = 256 * 1024;
+	bnx2i_ep->cm_sk->snd_buf = 256 * 1024;
+	clear_bit(SK_TCP_TIMESTAMP, &bnx2i_ep->cm_sk->tcp_flags);
+
+	memset(&saddr, 0, sizeof(saddr));
+	if (dst_addr->sa_family == AF_INET) {
+		desti = (struct sockaddr_in *) dst_addr;
+		saddr.remote.v4 = *desti;
+		saddr.local.v4.sin_family = desti->sin_family;
+	} else if (dst_addr->sa_family == AF_INET6) {
+		desti6 = (struct sockaddr_in6 *) dst_addr;
+		saddr.remote.v6 = *desti6;
+		saddr.local.v6.sin6_family = desti6->sin6_family;
+	}
+
+	bnx2i_ep->timestamp = jiffies;
+	bnx2i_ep->state = EP_STATE_CONNECT_START;
+	if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
+		rc = -EINVAL;
+		goto conn_failed;
+	} else
+		rc = cnic->cm_connect(bnx2i_ep->cm_sk, &saddr);
+
+	if (rc)
+		goto release_ep;
+
+	if (bnx2i_map_ep_dbell_regs(bnx2i_ep))
+		goto release_ep;
+	mutex_unlock(&hba->net_dev_lock);
+	return ep;
+
+release_ep:
+	if (bnx2i_tear_down_conn(hba, bnx2i_ep)) {
+		mutex_unlock(&hba->net_dev_lock);
+		return ERR_PTR(rc);
+	}
+conn_failed:
+net_if_down:
+iscsi_cid_err:
+	bnx2i_free_qp_resc(hba, bnx2i_ep);
+qp_resc_err:
+	bnx2i_free_ep(ep);
+	mutex_unlock(&hba->net_dev_lock);
+check_busy:
+	bnx2i_unreg_dev_all();
+	return ERR_PTR(rc);
+}
+
+
+/**
+ * bnx2i_ep_poll - polls for TCP connection establishement
+ * @ep:			TCP connection (endpoint) handle
+ * @timeout_ms:		timeout value in milli secs
+ *
+ * polls for TCP connect request to complete
+ */
+static int bnx2i_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
+{
+	struct bnx2i_endpoint *bnx2i_ep;
+	int rc = 0;
+
+	bnx2i_ep = ep->dd_data;
+	if ((bnx2i_ep->state == EP_STATE_IDLE) ||
+	    (bnx2i_ep->state == EP_STATE_CONNECT_FAILED) ||
+	    (bnx2i_ep->state == EP_STATE_OFLD_FAILED))
+		return -1;
+	if (bnx2i_ep->state == EP_STATE_CONNECT_COMPL)
+		return 1;
+
+	rc = wait_event_interruptible_timeout(bnx2i_ep->ofld_wait,
+					      ((bnx2i_ep->state ==
+						EP_STATE_OFLD_FAILED) ||
+					       (bnx2i_ep->state ==
+						EP_STATE_CONNECT_FAILED) ||
+					       (bnx2i_ep->state ==
+						EP_STATE_CONNECT_COMPL)),
+					      msecs_to_jiffies(timeout_ms));
+	if (!rc || (bnx2i_ep->state == EP_STATE_OFLD_FAILED))
+		rc = -1;
+
+	if (rc > 0)
+		return 1;
+	else if (!rc)
+		return 0;	/* timeout */
+	else
+		return rc;
+}
+
+
+/**
+ * bnx2i_ep_tcp_conn_active - check EP state transition
+ * @ep:		endpoint pointer
+ *
+ * check if underlying TCP connection is active
+ */
+static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep)
+{
+	int ret;
+	int cnic_dev_10g = 0;
+
+	if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_ep->hba->cnic_dev_type))
+		cnic_dev_10g = 1;
+
+	switch (bnx2i_ep->state) {
+	case EP_STATE_CONNECT_START:
+	case EP_STATE_CLEANUP_FAILED:
+	case EP_STATE_OFLD_FAILED:
+	case EP_STATE_DISCONN_TIMEDOUT:
+		ret = 0;
+		break;
+	case EP_STATE_CONNECT_COMPL:
+	case EP_STATE_ULP_UPDATE_START:
+	case EP_STATE_ULP_UPDATE_COMPL:
+	case EP_STATE_TCP_FIN_RCVD:
+	case EP_STATE_ULP_UPDATE_FAILED:
+		ret = 1;
+		break;
+	case EP_STATE_TCP_RST_RCVD:
+		ret = 0;
+		break;
+	case EP_STATE_CONNECT_FAILED:
+		if (cnic_dev_10g)
+			ret = 1;
+		else
+			ret = 0;
+		break;
+	default:
+		ret = 0;
+	}
+
+	return ret;
+}
+
+
+/**
+ * bnx2i_ep_disconnect - executes TCP connection teardown process
+ * @ep:		TCP connection (endpoint) handle
+ *
+ * executes  TCP connection teardown process
+ */
+static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep)
+{
+	struct bnx2i_endpoint *bnx2i_ep;
+	struct bnx2i_conn *bnx2i_conn = NULL;
+	struct iscsi_session *session = NULL;
+	struct iscsi_conn *conn;
+	struct cnic_dev *cnic;
+	struct bnx2i_hba *hba;
+
+	bnx2i_ep = ep->dd_data;
+
+	/* driver should not attempt connection cleanup untill TCP_CONNECT
+	 * completes either successfully or fails. Timeout is 9-secs, so
+	 * wait for it to complete
+	 */
+	while ((bnx2i_ep->state == EP_STATE_CONNECT_START) &&
+		!time_after(jiffies, bnx2i_ep->timestamp + (12 * HZ)))
+		msleep(250);
+
+	if (bnx2i_ep->conn) {
+		bnx2i_conn = bnx2i_ep->conn;
+		conn = bnx2i_conn->cls_conn->dd_data;
+		session = conn->session;
+
+		spin_lock_bh(&session->lock);
+		bnx2i_conn->is_bound = 0;
+		spin_unlock_bh(&session->lock);
+	}
+
+	hba = bnx2i_ep->hba;
+	if (bnx2i_ep->state == EP_STATE_IDLE)
+		goto return_bnx2i_ep;
+	cnic = hba->cnic;
+
+	mutex_lock(&hba->net_dev_lock);
+
+	if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
+		goto free_resc;
+	if (bnx2i_ep->hba_age != hba->age)
+		goto free_resc;
+
+	if (!bnx2i_ep_tcp_conn_active(bnx2i_ep))
+		goto destory_conn;
+
+	bnx2i_ep->state = EP_STATE_DISCONN_START;
+
+	init_timer(&bnx2i_ep->ofld_timer);
+	bnx2i_ep->ofld_timer.expires = 10*HZ + jiffies;
+	bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
+	bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
+	add_timer(&bnx2i_ep->ofld_timer);
+
+	if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
+		int close = 0;
+
+		if (session) {
+			spin_lock_bh(&session->lock);
+			if (session->state == ISCSI_STATE_LOGGING_OUT)
+				close = 1;
+			spin_unlock_bh(&session->lock);
+		}
+		if (close)
+			cnic->cm_close(bnx2i_ep->cm_sk);
+		else
+			cnic->cm_abort(bnx2i_ep->cm_sk);
+	} else
+		goto free_resc;
+
+	/* wait for option-2 conn teardown */
+	wait_event_interruptible(bnx2i_ep->ofld_wait,
+				 bnx2i_ep->state != EP_STATE_DISCONN_START);
+
+	if (signal_pending(current))
+		flush_signals(current);
+	del_timer_sync(&bnx2i_ep->ofld_timer);
+
+destory_conn:
+	if (bnx2i_tear_down_conn(hba, bnx2i_ep)) {
+		mutex_unlock(&hba->net_dev_lock);
+		return;
+	}
+free_resc:
+	mutex_unlock(&hba->net_dev_lock);
+	bnx2i_free_qp_resc(hba, bnx2i_ep);
+return_bnx2i_ep:
+	if (bnx2i_conn)
+		bnx2i_conn->ep = NULL;
+
+	bnx2i_free_ep(ep);
+
+	if (!hba->ofld_conns_active)
+		bnx2i_unreg_dev_all();
+}
+
+
+/**
+ * bnx2i_nl_set_path - ISCSI_UEVENT_PATH_UPDATE user message handler
+ * @buf:	pointer to buffer containing iscsi path message
+ *
+ */
+static int bnx2i_nl_set_path(struct Scsi_Host *shost, struct iscsi_path *params)
+{
+	struct bnx2i_hba *hba = iscsi_host_priv(shost);
+	char *buf = (char *) params;
+	u16 len = sizeof(*params);
+
+	/* handled by cnic driver */
+	hba->cnic->iscsi_nl_msg_recv(hba->cnic, ISCSI_UEVENT_PATH_UPDATE, buf,
+				     len);
+
+	return 0;
+}
+
+
+/*
+ * 'Scsi_Host_Template' structure and 'iscsi_tranport' structure template
+ * used while registering with the scsi host and iSCSI transport module.
+ */
+static struct scsi_host_template bnx2i_host_template = {
+	.module			= THIS_MODULE,
+	.name			= "Broadcom Offload iSCSI Initiator",
+	.proc_name		= "bnx2i",
+	.queuecommand		= iscsi_queuecommand,
+	.eh_abort_handler	= iscsi_eh_abort,
+	.eh_device_reset_handler = iscsi_eh_device_reset,
+	.eh_target_reset_handler = iscsi_eh_target_reset,
+	.can_queue		= 1024,
+	.max_sectors		= 127,
+	.cmd_per_lun		= 32,
+	.this_id		= -1,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.sg_tablesize		= ISCSI_MAX_BDS_PER_CMD,
+	.shost_attrs		= bnx2i_dev_attributes,
+};
+
+struct iscsi_transport bnx2i_iscsi_transport = {
+	.owner			= THIS_MODULE,
+	.name			= "bnx2i",
+	.caps			= CAP_RECOVERY_L0 | CAP_HDRDGST |
+				  CAP_MULTI_R2T | CAP_DATADGST |
+				  CAP_DATA_PATH_OFFLOAD,
+	.param_mask		= ISCSI_MAX_RECV_DLENGTH |
+				  ISCSI_MAX_XMIT_DLENGTH |
+				  ISCSI_HDRDGST_EN |
+				  ISCSI_DATADGST_EN |
+				  ISCSI_INITIAL_R2T_EN |
+				  ISCSI_MAX_R2T |
+				  ISCSI_IMM_DATA_EN |
+				  ISCSI_FIRST_BURST |
+				  ISCSI_MAX_BURST |
+				  ISCSI_PDU_INORDER_EN |
+				  ISCSI_DATASEQ_INORDER_EN |
+				  ISCSI_ERL |
+				  ISCSI_CONN_PORT |
+				  ISCSI_CONN_ADDRESS |
+				  ISCSI_EXP_STATSN |
+				  ISCSI_PERSISTENT_PORT |
+				  ISCSI_PERSISTENT_ADDRESS |
+				  ISCSI_TARGET_NAME | ISCSI_TPGT |
+				  ISCSI_USERNAME | ISCSI_PASSWORD |
+				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
+				  ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
+				  ISCSI_LU_RESET_TMO |
+				  ISCSI_PING_TMO | ISCSI_RECV_TMO |
+				  ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
+	.host_param_mask	= ISCSI_HOST_HWADDRESS | ISCSI_HOST_NETDEV_NAME,
+	.create_session		= bnx2i_session_create,
+	.destroy_session	= bnx2i_session_destroy,
+	.create_conn		= bnx2i_conn_create,
+	.bind_conn		= bnx2i_conn_bind,
+	.destroy_conn		= bnx2i_conn_destroy,
+	.set_param		= iscsi_set_param,
+	.get_conn_param		= bnx2i_conn_get_param,
+	.get_session_param	= iscsi_session_get_param,
+	.get_host_param		= bnx2i_host_get_param,
+	.start_conn		= bnx2i_conn_start,
+	.stop_conn		= iscsi_conn_stop,
+	.send_pdu		= iscsi_conn_send_pdu,
+	.xmit_task		= bnx2i_task_xmit,
+	.get_stats		= bnx2i_conn_get_stats,
+	/* TCP connect - disconnect - option-2 interface calls */
+	.ep_connect		= bnx2i_ep_connect,
+	.ep_poll		= bnx2i_ep_poll,
+	.ep_disconnect		= bnx2i_ep_disconnect,
+	.set_path		= bnx2i_nl_set_path,
+	/* Error recovery timeout call */
+	.session_recovery_timedout = iscsi_session_recovery_timedout,
+	.cleanup_task		= bnx2i_cleanup_task,
+};
diff --git a/drivers/scsi/bnx2i/bnx2i_sysfs.c b/drivers/scsi/bnx2i/bnx2i_sysfs.c
new file mode 100644
index 0000000..96426b7
--- /dev/null
+++ b/drivers/scsi/bnx2i/bnx2i_sysfs.c
@@ -0,0 +1,142 @@
+/* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver.
+ *
+ * Copyright (c) 2004 - 2009 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ */
+
+#include "bnx2i.h"
+
+/**
+ * bnx2i_dev_to_hba - maps dev pointer to adapter struct
+ * @dev:	device pointer
+ *
+ * Map device to hba structure
+ */
+static inline struct bnx2i_hba *bnx2i_dev_to_hba(struct device *dev)
+{
+	struct Scsi_Host *shost = class_to_shost(dev);
+	return iscsi_host_priv(shost);
+}
+
+
+/**
+ * bnx2i_show_sq_info - return(s currently configured send queue (SQ) size
+ * @dev:	device pointer
+ * @buf:	buffer to return current SQ size parameter
+ *
+ * Returns current SQ size parameter, this paramater determines the number
+ * outstanding iSCSI commands supported on a connection
+ */
+static ssize_t bnx2i_show_sq_info(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev);
+
+	return sprintf(buf, "0x%x\n", hba->max_sqes);
+}
+
+
+/**
+ * bnx2i_set_sq_info - update send queue (SQ) size parameter
+ * @dev:	device pointer
+ * @buf:	buffer to return current SQ size parameter
+ * @count:	parameter buffer size
+ *
+ * Interface for user to change shared queue size allocated for each conn
+ * Must be within SQ limits and a power of 2. For the latter this is needed
+ * because of how libiscsi preallocates tasks.
+ */
+static ssize_t bnx2i_set_sq_info(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev);
+	u32 val;
+	int max_sq_size;
+
+	if (hba->ofld_conns_active)
+		goto skip_config;
+
+	if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
+		max_sq_size = BNX2I_5770X_SQ_WQES_MAX;
+	else
+		max_sq_size = BNX2I_570X_SQ_WQES_MAX;
+
+	if (sscanf(buf, " 0x%x ", &val) > 0) {
+		if ((val >= BNX2I_SQ_WQES_MIN) && (val <= max_sq_size) &&
+		    (is_power_of_2(val)))
+			hba->max_sqes = val;
+	}
+
+	return count;
+
+skip_config:
+	printk(KERN_ERR "bnx2i: device busy, cannot change SQ size\n");
+	return 0;
+}
+
+
+/**
+ * bnx2i_show_ccell_info - returns command cell (HQ) size
+ * @dev:	device pointer
+ * @buf:	buffer to return current SQ size parameter
+ *
+ * returns per-connection TCP history queue size parameter
+ */
+static ssize_t bnx2i_show_ccell_info(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev);
+
+	return sprintf(buf, "0x%x\n", hba->num_ccell);
+}
+
+
+/**
+ * bnx2i_get_link_state - set command cell (HQ) size
+ * @dev:	device pointer
+ * @buf:	buffer to return current SQ size parameter
+ * @count:	parameter buffer size
+ *
+ * updates per-connection TCP history queue size parameter
+ */
+static ssize_t bnx2i_set_ccell_info(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	u32 val;
+	struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev);
+
+	if (hba->ofld_conns_active)
+		goto skip_config;
+
+	if (sscanf(buf, " 0x%x ", &val) > 0) {
+		if ((val >= BNX2I_CCELLS_MIN) &&
+		    (val <= BNX2I_CCELLS_MAX)) {
+			hba->num_ccell = val;
+		}
+	}
+
+	return count;
+
+skip_config:
+	printk(KERN_ERR "bnx2i: device busy, cannot change CCELL size\n");
+	return 0;
+}
+
+
+static DEVICE_ATTR(sq_size, S_IRUGO | S_IWUSR,
+		   bnx2i_show_sq_info, bnx2i_set_sq_info);
+static DEVICE_ATTR(num_ccell, S_IRUGO | S_IWUSR,
+		   bnx2i_show_ccell_info, bnx2i_set_ccell_info);
+
+struct device_attribute *bnx2i_dev_attributes[] = {
+	&dev_attr_sq_size,
+	&dev_attr_num_ccell,
+	NULL
+};
diff --git a/drivers/scsi/cxgb3i/cxgb3i.h b/drivers/scsi/cxgb3i/cxgb3i.h
index 59b0958..e3133b5 100644
--- a/drivers/scsi/cxgb3i/cxgb3i.h
+++ b/drivers/scsi/cxgb3i/cxgb3i.h
@@ -144,7 +144,6 @@
 void cxgb3i_adapter_open(struct t3cdev *);
 void cxgb3i_adapter_close(struct t3cdev *);
 
-struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *);
 struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *,
 				       struct net_device *);
 void cxgb3i_hba_host_remove(struct cxgb3i_hba *);
diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
index 9212400..74369a3 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
@@ -13,6 +13,7 @@
 
 #include <linux/inet.h>
 #include <linux/crypto.h>
+#include <net/dst.h>
 #include <net/tcp.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -178,7 +179,7 @@
  * cxgb3i_hba_find_by_netdev - find the cxgb3i_hba structure via net_device
  * @t3dev: t3cdev adapter
  */
-struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev)
+static struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev)
 {
 	struct cxgb3i_adapter *snic;
 	int i;
@@ -261,20 +262,27 @@
 
 /**
  * cxgb3i_ep_connect - establish TCP connection to target portal
+ * @shost:		scsi host to use
  * @dst_addr:		target IP address
  * @non_blocking:	blocking or non-blocking call
  *
  * Initiates a TCP/IP connection to the dst_addr
  */
-static struct iscsi_endpoint *cxgb3i_ep_connect(struct sockaddr *dst_addr,
+static struct iscsi_endpoint *cxgb3i_ep_connect(struct Scsi_Host *shost,
+						struct sockaddr *dst_addr,
 						int non_blocking)
 {
 	struct iscsi_endpoint *ep;
 	struct cxgb3i_endpoint *cep;
-	struct cxgb3i_hba *hba;
+	struct cxgb3i_hba *hba = NULL;
 	struct s3_conn *c3cn = NULL;
 	int err = 0;
 
+	if (shost)
+		hba = iscsi_host_priv(shost);
+
+	cxgb3i_api_debug("shost 0x%p, hba 0x%p.\n", shost, hba);
+
 	c3cn = cxgb3i_c3cn_create();
 	if (!c3cn) {
 		cxgb3i_log_info("ep connect OOM.\n");
@@ -282,17 +290,27 @@
 		goto release_conn;
 	}
 
-	err = cxgb3i_c3cn_connect(c3cn, (struct sockaddr_in *)dst_addr);
+	err = cxgb3i_c3cn_connect(hba ? hba->ndev : NULL, c3cn,
+				 (struct sockaddr_in *)dst_addr);
 	if (err < 0) {
 		cxgb3i_log_info("ep connect failed.\n");
 		goto release_conn;
 	}
+
 	hba = cxgb3i_hba_find_by_netdev(c3cn->dst_cache->dev);
 	if (!hba) {
 		err = -ENOSPC;
 		cxgb3i_log_info("NOT going through cxgbi device.\n");
 		goto release_conn;
 	}
+
+	if (shost && hba != iscsi_host_priv(shost)) {
+		err = -ENOSPC;
+		cxgb3i_log_info("Could not connect through request host%u\n",
+				shost->host_no);
+		goto release_conn;
+	}
+
 	if (c3cn_is_closing(c3cn)) {
 		err = -ENOSPC;
 		cxgb3i_log_info("ep connect unable to connect.\n");
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c
index e11c9c1..c1d5be4 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_offload.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c
@@ -1479,12 +1479,13 @@
 	return NULL;
 }
 
-static struct rtable *find_route(__be32 saddr, __be32 daddr,
+static struct rtable *find_route(struct net_device *dev,
+				 __be32 saddr, __be32 daddr,
 				 __be16 sport, __be16 dport)
 {
 	struct rtable *rt;
 	struct flowi fl = {
-		.oif = 0,
+		.oif = dev ? dev->ifindex : 0,
 		.nl_u = {
 			 .ip4_u = {
 				   .daddr = daddr,
@@ -1573,36 +1574,40 @@
  *
  * return 0 if active open request is sent, < 0 otherwise.
  */
-int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin)
+int cxgb3i_c3cn_connect(struct net_device *dev, struct s3_conn *c3cn,
+			struct sockaddr_in *usin)
 {
 	struct rtable *rt;
-	struct net_device *dev;
 	struct cxgb3i_sdev_data *cdata;
 	struct t3cdev *cdev;
 	__be32 sipv4;
 	int err;
 
+	c3cn_conn_debug("c3cn 0x%p, dev 0x%p.\n", c3cn, dev);
+
 	if (usin->sin_family != AF_INET)
 		return -EAFNOSUPPORT;
 
 	c3cn->daddr.sin_port = usin->sin_port;
 	c3cn->daddr.sin_addr.s_addr = usin->sin_addr.s_addr;
 
-	rt = find_route(c3cn->saddr.sin_addr.s_addr,
+	rt = find_route(dev, c3cn->saddr.sin_addr.s_addr,
 			c3cn->daddr.sin_addr.s_addr,
 			c3cn->saddr.sin_port,
 			c3cn->daddr.sin_port);
 	if (rt == NULL) {
-		c3cn_conn_debug("NO route to 0x%x, port %u.\n",
+		c3cn_conn_debug("NO route to 0x%x, port %u, dev %s.\n",
 				c3cn->daddr.sin_addr.s_addr,
-				ntohs(c3cn->daddr.sin_port));
+				ntohs(c3cn->daddr.sin_port),
+				dev ? dev->name : "any");
 		return -ENETUNREACH;
 	}
 
 	if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
-		c3cn_conn_debug("multi-cast route to 0x%x, port %u.\n",
+		c3cn_conn_debug("multi-cast route to 0x%x, port %u, dev %s.\n",
 				c3cn->daddr.sin_addr.s_addr,
-				ntohs(c3cn->daddr.sin_port));
+				ntohs(c3cn->daddr.sin_port),
+				dev ? dev->name : "any");
 		ip_rt_put(rt);
 		return -ENETUNREACH;
 	}
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.h b/drivers/scsi/cxgb3i/cxgb3i_offload.h
index ebfca96..6a1d86b 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_offload.h
+++ b/drivers/scsi/cxgb3i/cxgb3i_offload.h
@@ -169,7 +169,8 @@
 void cxgb3i_sdev_remove(struct t3cdev *);
 
 struct s3_conn *cxgb3i_c3cn_create(void);
-int cxgb3i_c3cn_connect(struct s3_conn *, struct sockaddr_in *);
+int cxgb3i_c3cn_connect(struct net_device *, struct s3_conn *,
+			struct sockaddr_in *);
 void cxgb3i_c3cn_rx_credits(struct s3_conn *, int);
 int cxgb3i_c3cn_send_pdus(struct s3_conn *, struct sk_buff *);
 void cxgb3i_c3cn_release(struct s3_conn *);
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 43b8c51..fd0544f 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -561,6 +561,12 @@
 	struct rdac_dh_data *h = get_rdac_data(sdev);
 	switch (sense_hdr->sense_key) {
 	case NOT_READY:
+		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x01)
+			/* LUN Not Ready - Logical Unit Not Ready and is in
+			* the process of becoming ready
+			* Just retry.
+			*/
+			return ADD_TO_MLQUEUE;
 		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x81)
 			/* LUN Not Ready - Storage firmware incompatible
 			 * Manual code synchonisation required.
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 03e1926..e606b48 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -54,7 +54,6 @@
 /* fcoe host list */
 LIST_HEAD(fcoe_hostlist);
 DEFINE_RWLOCK(fcoe_hostlist_lock);
-DEFINE_TIMER(fcoe_timer, NULL, 0, 0);
 DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu);
 
 /* Function Prototypes */
@@ -71,7 +70,7 @@
 static int fcoe_hostlist_add(const struct fc_lport *);
 static int fcoe_hostlist_remove(const struct fc_lport *);
 
-static int fcoe_check_wait_queue(struct fc_lport *);
+static void fcoe_check_wait_queue(struct fc_lport *, struct sk_buff *);
 static int fcoe_device_notification(struct notifier_block *, ulong, void *);
 static void fcoe_dev_setup(void);
 static void fcoe_dev_cleanup(void);
@@ -146,6 +145,7 @@
 	lp->link_up = 0;
 	lp->qfull = 0;
 	lp->max_retry_count = 3;
+	lp->max_rport_retry_count = 3;
 	lp->e_d_tov = 2 * 1000;	/* FC-FS default */
 	lp->r_a_tov = 2 * 2 * 1000;
 	lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
@@ -167,6 +167,18 @@
 }
 
 /**
+ * fcoe_queue_timer() - fcoe queue timer
+ * @lp: the fc_lport pointer
+ *
+ * Calls fcoe_check_wait_queue on timeout
+ *
+ */
+static void fcoe_queue_timer(ulong lp)
+{
+	fcoe_check_wait_queue((struct fc_lport *)lp, NULL);
+}
+
+/**
  * fcoe_netdev_config() - Set up netdev for SW FCoE
  * @lp : ptr to the fc_lport
  * @netdev : ptr to the associated netdevice struct
@@ -236,6 +248,7 @@
 	}
 	skb_queue_head_init(&fc->fcoe_pending_queue);
 	fc->fcoe_pending_queue_active = 0;
+	setup_timer(&fc->timer, fcoe_queue_timer, (unsigned long)lp);
 
 	/* setup Source Mac Address */
 	memcpy(fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr,
@@ -386,6 +399,9 @@
 	/* Free existing skbs */
 	fcoe_clean_pending_queue(lp);
 
+	/* Stop the timer */
+	del_timer_sync(&fc->timer);
+
 	/* Free memory used by statistical counters */
 	fc_lport_free_stats(lp);
 
@@ -988,7 +1004,7 @@
  */
 int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
 {
-	int wlen, rc = 0;
+	int wlen;
 	u32 crc;
 	struct ethhdr *eh;
 	struct fcoe_crc_eof *cp;
@@ -1021,8 +1037,7 @@
 	sof = fr_sof(fp);
 	eof = fr_eof(fp);
 
-	elen = (fc->real_dev->priv_flags & IFF_802_1Q_VLAN) ?
-		sizeof(struct vlan_ethhdr) : sizeof(struct ethhdr);
+	elen = sizeof(struct ethhdr);
 	hlen = sizeof(struct fcoe_hdr);
 	tlen = sizeof(struct fcoe_crc_eof);
 	wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE;
@@ -1107,18 +1122,9 @@
 	/* send down to lld */
 	fr_dev(fp) = lp;
 	if (fc->fcoe_pending_queue.qlen)
-		rc = fcoe_check_wait_queue(lp);
-
-	if (rc == 0)
-		rc = fcoe_start_io(skb);
-
-	if (rc) {
-		spin_lock_bh(&fc->fcoe_pending_queue.lock);
-		__skb_queue_tail(&fc->fcoe_pending_queue, skb);
-		spin_unlock_bh(&fc->fcoe_pending_queue.lock);
-		if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
-			lp->qfull = 1;
-	}
+		fcoe_check_wait_queue(lp, skb);
+	else if (fcoe_start_io(skb))
+		fcoe_check_wait_queue(lp, skb);
 
 	return 0;
 }
@@ -1268,32 +1274,6 @@
 }
 
 /**
- * fcoe_watchdog() - fcoe timer callback
- * @vp:
- *
- * This checks the pending queue length for fcoe and set lport qfull
- * if the FCOE_MAX_QUEUE_DEPTH is reached. This is done for all fc_lport on the
- * fcoe_hostlist.
- *
- * Returns: 0 for success
- */
-void fcoe_watchdog(ulong vp)
-{
-	struct fcoe_softc *fc;
-
-	read_lock(&fcoe_hostlist_lock);
-	list_for_each_entry(fc, &fcoe_hostlist, list) {
-		if (fc->ctlr.lp)
-			fcoe_check_wait_queue(fc->ctlr.lp);
-	}
-	read_unlock(&fcoe_hostlist_lock);
-
-	fcoe_timer.expires = jiffies + (1 * HZ);
-	add_timer(&fcoe_timer);
-}
-
-
-/**
  * fcoe_check_wait_queue() - attempt to clear the transmit backlog
  * @lp: the fc_lport
  *
@@ -1305,16 +1285,17 @@
  * The wait_queue is used when the skb transmit fails. skb will go
  * in the wait_queue which will be emptied by the timer function or
  * by the next skb transmit.
- *
- * Returns: 0 for success
  */
-static int fcoe_check_wait_queue(struct fc_lport *lp)
+static void fcoe_check_wait_queue(struct fc_lport *lp, struct sk_buff *skb)
 {
 	struct fcoe_softc *fc = lport_priv(lp);
-	struct sk_buff *skb;
-	int rc = -1;
+	int rc;
 
 	spin_lock_bh(&fc->fcoe_pending_queue.lock);
+
+	if (skb)
+		__skb_queue_tail(&fc->fcoe_pending_queue, skb);
+
 	if (fc->fcoe_pending_queue_active)
 		goto out;
 	fc->fcoe_pending_queue_active = 1;
@@ -1340,23 +1321,26 @@
 
 	if (fc->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH)
 		lp->qfull = 0;
+	if (fc->fcoe_pending_queue.qlen && !timer_pending(&fc->timer))
+		mod_timer(&fc->timer, jiffies + 2);
 	fc->fcoe_pending_queue_active = 0;
-	rc = fc->fcoe_pending_queue.qlen;
 out:
+	if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
+		lp->qfull = 1;
 	spin_unlock_bh(&fc->fcoe_pending_queue.lock);
-	return rc;
+	return;
 }
 
 /**
  * fcoe_dev_setup() - setup link change notification interface
  */
-static void fcoe_dev_setup()
+static void fcoe_dev_setup(void)
 {
 	register_netdevice_notifier(&fcoe_notifier);
 }
 
 /**
- * fcoe_dev_setup() - cleanup link change notification interface
+ * fcoe_dev_cleanup() - cleanup link change notification interface
  */
 static void fcoe_dev_cleanup(void)
 {
@@ -1815,10 +1799,6 @@
 	/* Setup link change notification */
 	fcoe_dev_setup();
 
-	setup_timer(&fcoe_timer, fcoe_watchdog, 0);
-
-	mod_timer(&fcoe_timer, jiffies + (10 * HZ));
-
 	fcoe_if_init();
 
 	return 0;
@@ -1844,9 +1824,6 @@
 
 	fcoe_dev_cleanup();
 
-	/* Stop the timer */
-	del_timer_sync(&fcoe_timer);
-
 	/* releases the associated fcoe hosts */
 	list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list)
 		fcoe_if_destroy(fc->real_dev);
diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h
index 917aae8..a1eb8c1 100644
--- a/drivers/scsi/fcoe/fcoe.h
+++ b/drivers/scsi/fcoe/fcoe.h
@@ -61,6 +61,7 @@
 	struct packet_type  fip_packet_type;
 	struct sk_buff_head fcoe_pending_queue;
 	u8	fcoe_pending_queue_active;
+	struct timer_list timer;		/* queue timer */
 	struct fcoe_ctlr ctlr;
 };
 
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index 62ba0f3..9294118 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -213,7 +213,7 @@
 	sol->desc.size.fd_size = htons(fcoe_size);
 
 	skb_put(skb, sizeof(*sol));
-	skb->protocol = htons(ETH_P_802_3);
+	skb->protocol = htons(ETH_P_FIP);
 	skb_reset_mac_header(skb);
 	skb_reset_network_header(skb);
 	fip->send(fip, skb);
@@ -365,7 +365,7 @@
 	}
 
 	skb_put(skb, len);
-	skb->protocol = htons(ETH_P_802_3);
+	skb->protocol = htons(ETH_P_FIP);
 	skb_reset_mac_header(skb);
 	skb_reset_network_header(skb);
 	fip->send(fip, skb);
@@ -424,7 +424,7 @@
 	if (dtype != ELS_FLOGI)
 		memcpy(mac->fd_mac, fip->data_src_addr, ETH_ALEN);
 
-	skb->protocol = htons(ETH_P_802_3);
+	skb->protocol = htons(ETH_P_FIP);
 	skb_reset_mac_header(skb);
 	skb_reset_network_header(skb);
 	return 0;
@@ -447,14 +447,10 @@
 	u16 old_xid;
 	u8 op;
 
-	if (fip->state == FIP_ST_NON_FIP)
-		return 0;
-
 	fh = (struct fc_frame_header *)skb->data;
 	op = *(u8 *)(fh + 1);
 
-	switch (op) {
-	case ELS_FLOGI:
+	if (op == ELS_FLOGI) {
 		old_xid = fip->flogi_oxid;
 		fip->flogi_oxid = ntohs(fh->fh_ox_id);
 		if (fip->state == FIP_ST_AUTO) {
@@ -466,6 +462,15 @@
 			fip->map_dest = 1;
 			return 0;
 		}
+		if (fip->state == FIP_ST_NON_FIP)
+			fip->map_dest = 1;
+	}
+
+	if (fip->state == FIP_ST_NON_FIP)
+		return 0;
+
+	switch (op) {
+	case ELS_FLOGI:
 		op = FIP_DT_FLOGI;
 		break;
 	case ELS_FDISC:
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c
index 32ef6b8..a840728 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -680,6 +680,7 @@
 	}
 
 	lp->max_retry_count = fnic->config.flogi_retries;
+	lp->max_rport_retry_count = fnic->config.plogi_retries;
 	lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
 			      FCP_SPPF_CONF_COMPL);
 	if (fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR)
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index 59349a3..1258da3 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -152,6 +152,7 @@
                          struct Scsi_Host *host, gdth_ha_str *ha)
 {
     int size = 0,len = 0;
+    int hlen;
     off_t begin = 0,pos = 0;
     int id, i, j, k, sec, flag;
     int no_mdrv = 0, drv_no, is_mirr;
@@ -192,11 +193,11 @@
     if (reserve_list[0] == 0xff)
         strcpy(hrec, "--");
     else {
-        sprintf(hrec, "%d", reserve_list[0]);
+        hlen = sprintf(hrec, "%d", reserve_list[0]);
         for (i = 1;  i < MAX_RES_ARGS; i++) {
             if (reserve_list[i] == 0xff) 
                 break;
-            sprintf(hrec,"%s,%d", hrec, reserve_list[i]);
+            hlen += snprintf(hrec + hlen , 161 - hlen, ",%d", reserve_list[i]);
         }
     }
     size = sprintf(buffer+len,
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index ea4abee..b4b805e 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -110,7 +110,7 @@
 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_DEAD, DID_ERROR, 0, 1, "transport dead" },
 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_CONFIG_ERROR, DID_ERROR, 1, 1, "configuration error" },
 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_NAME_SERVER_FAIL, DID_ERROR, 1, 1, "name server failure" },
-	{ IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_HALTED, DID_REQUEUE, 0, 0, "link halted" },
+	{ IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_HALTED, DID_REQUEUE, 1, 0, "link halted" },
 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_GENERAL, DID_OK, 1, 0, "general transport error" },
 
 	{ IBMVFC_VIOS_FAILURE, IBMVFC_CRQ_FAILURE, DID_REQUEUE, 1, 1, "CRQ failure" },
@@ -143,6 +143,7 @@
 static void ibmvfc_tgt_send_prli(struct ibmvfc_target *);
 static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *);
 static void ibmvfc_tgt_query_target(struct ibmvfc_target *);
+static void ibmvfc_npiv_logout(struct ibmvfc_host *);
 
 static const char *unknown_error = "unknown error";
 
@@ -275,7 +276,7 @@
 	int fc_rsp_len = rsp->fcp_rsp_len;
 
 	if ((rsp->flags & FCP_RSP_LEN_VALID) &&
-	    ((!fc_rsp_len && fc_rsp_len != 4 && fc_rsp_len != 8) ||
+	    ((fc_rsp_len && fc_rsp_len != 4 && fc_rsp_len != 8) ||
 	     rsp->data.info.rsp_code))
 		return DID_ERROR << 16;
 
@@ -431,6 +432,8 @@
 	case IBMVFC_TGT_ACTION_DEL_RPORT:
 		break;
 	default:
+		if (action == IBMVFC_TGT_ACTION_DEL_RPORT)
+			tgt->add_rport = 0;
 		tgt->action = action;
 		break;
 	}
@@ -475,6 +478,10 @@
 		if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT)
 			vhost->action = action;
 		break;
+	case IBMVFC_HOST_ACTION_LOGO_WAIT:
+		if (vhost->action == IBMVFC_HOST_ACTION_LOGO)
+			vhost->action = action;
+		break;
 	case IBMVFC_HOST_ACTION_INIT_WAIT:
 		if (vhost->action == IBMVFC_HOST_ACTION_INIT)
 			vhost->action = action;
@@ -483,7 +490,7 @@
 		switch (vhost->action) {
 		case IBMVFC_HOST_ACTION_INIT_WAIT:
 		case IBMVFC_HOST_ACTION_NONE:
-		case IBMVFC_HOST_ACTION_TGT_ADD:
+		case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
 			vhost->action = action;
 			break;
 		default:
@@ -494,11 +501,11 @@
 		if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS)
 			vhost->action = action;
 		break;
+	case IBMVFC_HOST_ACTION_LOGO:
 	case IBMVFC_HOST_ACTION_INIT:
 	case IBMVFC_HOST_ACTION_TGT_DEL:
 	case IBMVFC_HOST_ACTION_QUERY_TGTS:
 	case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
-	case IBMVFC_HOST_ACTION_TGT_ADD:
 	case IBMVFC_HOST_ACTION_NONE:
 	default:
 		vhost->action = action;
@@ -576,7 +583,7 @@
 		}
 
 		list_for_each_entry(tgt, &vhost->targets, queue)
-			tgt->need_login = 1;
+			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
 		scsi_block_requests(vhost->host);
 		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
 		vhost->job_step = ibmvfc_npiv_login;
@@ -646,6 +653,7 @@
 	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
 
 	vhost->state = IBMVFC_NO_CRQ;
+	vhost->logged_in = 0;
 	dma_unmap_single(vhost->dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL);
 	free_page((unsigned long)crq->msgs);
 }
@@ -692,6 +700,7 @@
 	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
 
 	vhost->state = IBMVFC_NO_CRQ;
+	vhost->logged_in = 0;
 	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
 
 	/* Clean out the queue */
@@ -807,10 +816,10 @@
 }
 
 /**
- * __ibmvfc_reset_host - Reset the connection to the server (no locking)
+ * ibmvfc_hard_reset_host - Reset the connection to the server by breaking the CRQ
  * @vhost:	struct ibmvfc host to reset
  **/
-static void __ibmvfc_reset_host(struct ibmvfc_host *vhost)
+static void ibmvfc_hard_reset_host(struct ibmvfc_host *vhost)
 {
 	int rc;
 
@@ -826,9 +835,25 @@
 }
 
 /**
- * ibmvfc_reset_host - Reset the connection to the server
+ * __ibmvfc_reset_host - Reset the connection to the server (no locking)
  * @vhost:	struct ibmvfc host to reset
  **/
+static void __ibmvfc_reset_host(struct ibmvfc_host *vhost)
+{
+	if (vhost->logged_in && vhost->action != IBMVFC_HOST_ACTION_LOGO_WAIT &&
+	    !ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
+		scsi_block_requests(vhost->host);
+		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO);
+		vhost->job_step = ibmvfc_npiv_logout;
+		wake_up(&vhost->work_wait_q);
+	} else
+		ibmvfc_hard_reset_host(vhost);
+}
+
+/**
+ * ibmvfc_reset_host - Reset the connection to the server
+ * @vhost:	ibmvfc host struct
+ **/
 static void ibmvfc_reset_host(struct ibmvfc_host *vhost)
 {
 	unsigned long flags;
@@ -842,9 +867,13 @@
  * ibmvfc_retry_host_init - Retry host initialization if allowed
  * @vhost:	ibmvfc host struct
  *
+ * Returns: 1 if init will be retried / 0 if not
+ *
  **/
-static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost)
+static int ibmvfc_retry_host_init(struct ibmvfc_host *vhost)
 {
+	int retry = 0;
+
 	if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) {
 		vhost->delay_init = 1;
 		if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) {
@@ -853,11 +882,14 @@
 			ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE);
 		} else if (vhost->init_retries == IBMVFC_MAX_HOST_INIT_RETRIES)
 			__ibmvfc_reset_host(vhost);
-		else
+		else {
 			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
+			retry = 1;
+		}
 	}
 
 	wake_up(&vhost->work_wait_q);
+	return retry;
 }
 
 /**
@@ -1137,8 +1169,9 @@
 	login_info->partition_num = vhost->partition_number;
 	login_info->vfc_frame_version = 1;
 	login_info->fcp_version = 3;
+	login_info->flags = IBMVFC_FLUSH_ON_HALT;
 	if (vhost->client_migrated)
-		login_info->flags = IBMVFC_CLIENT_MIGRATED;
+		login_info->flags |= IBMVFC_CLIENT_MIGRATED;
 
 	login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ;
 	login_info->capabilities = IBMVFC_CAN_MIGRATE;
@@ -1452,6 +1485,27 @@
 }
 
 /**
+ * ibmvfc_relogin - Log back into the specified device
+ * @sdev:	scsi device struct
+ *
+ **/
+static void ibmvfc_relogin(struct scsi_device *sdev)
+{
+	struct ibmvfc_host *vhost = shost_priv(sdev->host);
+	struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
+	struct ibmvfc_target *tgt;
+
+	list_for_each_entry(tgt, &vhost->targets, queue) {
+		if (rport == tgt->rport) {
+			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
+			break;
+		}
+	}
+
+	ibmvfc_reinit_host(vhost);
+}
+
+/**
  * ibmvfc_scsi_done - Handle responses from commands
  * @evt:	ibmvfc event to be handled
  *
@@ -1483,7 +1537,7 @@
 			if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len && rsp_len <= 8)
 				memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len);
 			if ((vfc_cmd->status & IBMVFC_VIOS_FAILURE) && (vfc_cmd->error == IBMVFC_PLOGI_REQUIRED))
-				ibmvfc_reinit_host(evt->vhost);
+				ibmvfc_relogin(cmnd->device);
 
 			if (!cmnd->result && (!scsi_get_resid(cmnd) || (rsp->flags & FCP_RESID_OVER)))
 				cmnd->result = (DID_ERROR << 16);
@@ -2148,13 +2202,31 @@
 				struct ibmvfc_host *vhost)
 {
 	const char *desc = ibmvfc_get_ae_desc(crq->event);
+	struct ibmvfc_target *tgt;
 
 	ibmvfc_log(vhost, 3, "%s event received. scsi_id: %llx, wwpn: %llx,"
 		   " node_name: %llx\n", desc, crq->scsi_id, crq->wwpn, crq->node_name);
 
 	switch (crq->event) {
-	case IBMVFC_AE_LINK_UP:
 	case IBMVFC_AE_RESUME:
+		switch (crq->link_state) {
+		case IBMVFC_AE_LS_LINK_DOWN:
+			ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+			break;
+		case IBMVFC_AE_LS_LINK_DEAD:
+			ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+			break;
+		case IBMVFC_AE_LS_LINK_UP:
+		case IBMVFC_AE_LS_LINK_BOUNCED:
+		default:
+			vhost->events_to_log |= IBMVFC_AE_LINKUP;
+			vhost->delay_init = 1;
+			__ibmvfc_reset_host(vhost);
+			break;
+		};
+
+		break;
+	case IBMVFC_AE_LINK_UP:
 		vhost->events_to_log |= IBMVFC_AE_LINKUP;
 		vhost->delay_init = 1;
 		__ibmvfc_reset_host(vhost);
@@ -2168,9 +2240,23 @@
 	case IBMVFC_AE_SCN_NPORT:
 	case IBMVFC_AE_SCN_GROUP:
 		vhost->events_to_log |= IBMVFC_AE_RSCN;
+		ibmvfc_reinit_host(vhost);
+		break;
 	case IBMVFC_AE_ELS_LOGO:
 	case IBMVFC_AE_ELS_PRLO:
 	case IBMVFC_AE_ELS_PLOGI:
+		list_for_each_entry(tgt, &vhost->targets, queue) {
+			if (!crq->scsi_id && !crq->wwpn && !crq->node_name)
+				break;
+			if (crq->scsi_id && tgt->scsi_id != crq->scsi_id)
+				continue;
+			if (crq->wwpn && tgt->ids.port_name != crq->wwpn)
+				continue;
+			if (crq->node_name && tgt->ids.node_name != crq->node_name)
+				continue;
+			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
+		}
+
 		ibmvfc_reinit_host(vhost);
 		break;
 	case IBMVFC_AE_LINK_DOWN:
@@ -2222,6 +2308,7 @@
 		return;
 	case IBMVFC_CRQ_XPORT_EVENT:
 		vhost->state = IBMVFC_NO_CRQ;
+		vhost->logged_in = 0;
 		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
 		if (crq->format == IBMVFC_PARTITION_MIGRATED) {
 			/* We need to re-setup the interpartition connection */
@@ -2299,7 +2386,7 @@
 		done = 1;
 	}
 
-	if (vhost->state != IBMVFC_NO_CRQ && vhost->action == IBMVFC_HOST_ACTION_NONE)
+	if (vhost->scan_complete)
 		done = 1;
 	spin_unlock_irqrestore(shost->host_lock, flags);
 	return done;
@@ -2434,14 +2521,6 @@
 			vhost->login_buf->resp.partition_name);
 }
 
-static struct device_attribute ibmvfc_host_partition_name = {
-	.attr = {
-		.name = "partition_name",
-		.mode = S_IRUGO,
-	},
-	.show = ibmvfc_show_host_partition_name,
-};
-
 static ssize_t ibmvfc_show_host_device_name(struct device *dev,
 					    struct device_attribute *attr, char *buf)
 {
@@ -2452,14 +2531,6 @@
 			vhost->login_buf->resp.device_name);
 }
 
-static struct device_attribute ibmvfc_host_device_name = {
-	.attr = {
-		.name = "device_name",
-		.mode = S_IRUGO,
-	},
-	.show = ibmvfc_show_host_device_name,
-};
-
 static ssize_t ibmvfc_show_host_loc_code(struct device *dev,
 					 struct device_attribute *attr, char *buf)
 {
@@ -2470,14 +2541,6 @@
 			vhost->login_buf->resp.port_loc_code);
 }
 
-static struct device_attribute ibmvfc_host_loc_code = {
-	.attr = {
-		.name = "port_loc_code",
-		.mode = S_IRUGO,
-	},
-	.show = ibmvfc_show_host_loc_code,
-};
-
 static ssize_t ibmvfc_show_host_drc_name(struct device *dev,
 					 struct device_attribute *attr, char *buf)
 {
@@ -2488,14 +2551,6 @@
 			vhost->login_buf->resp.drc_name);
 }
 
-static struct device_attribute ibmvfc_host_drc_name = {
-	.attr = {
-		.name = "drc_name",
-		.mode = S_IRUGO,
-	},
-	.show = ibmvfc_show_host_drc_name,
-};
-
 static ssize_t ibmvfc_show_host_npiv_version(struct device *dev,
 					     struct device_attribute *attr, char *buf)
 {
@@ -2504,13 +2559,13 @@
 	return snprintf(buf, PAGE_SIZE, "%d\n", vhost->login_buf->resp.version);
 }
 
-static struct device_attribute ibmvfc_host_npiv_version = {
-	.attr = {
-		.name = "npiv_version",
-		.mode = S_IRUGO,
-	},
-	.show = ibmvfc_show_host_npiv_version,
-};
+static ssize_t ibmvfc_show_host_capabilities(struct device *dev,
+					     struct device_attribute *attr, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(dev);
+	struct ibmvfc_host *vhost = shost_priv(shost);
+	return snprintf(buf, PAGE_SIZE, "%llx\n", vhost->login_buf->resp.capabilities);
+}
 
 /**
  * ibmvfc_show_log_level - Show the adapter's error logging level
@@ -2556,14 +2611,14 @@
 	return strlen(buf);
 }
 
-static struct device_attribute ibmvfc_log_level_attr = {
-	.attr = {
-		.name =		"log_level",
-		.mode =		S_IRUGO | S_IWUSR,
-	},
-	.show = ibmvfc_show_log_level,
-	.store = ibmvfc_store_log_level
-};
+static DEVICE_ATTR(partition_name, S_IRUGO, ibmvfc_show_host_partition_name, NULL);
+static DEVICE_ATTR(device_name, S_IRUGO, ibmvfc_show_host_device_name, NULL);
+static DEVICE_ATTR(port_loc_code, S_IRUGO, ibmvfc_show_host_loc_code, NULL);
+static DEVICE_ATTR(drc_name, S_IRUGO, ibmvfc_show_host_drc_name, NULL);
+static DEVICE_ATTR(npiv_version, S_IRUGO, ibmvfc_show_host_npiv_version, NULL);
+static DEVICE_ATTR(capabilities, S_IRUGO, ibmvfc_show_host_capabilities, NULL);
+static DEVICE_ATTR(log_level, S_IRUGO | S_IWUSR,
+		   ibmvfc_show_log_level, ibmvfc_store_log_level);
 
 #ifdef CONFIG_SCSI_IBMVFC_TRACE
 /**
@@ -2612,12 +2667,13 @@
 #endif
 
 static struct device_attribute *ibmvfc_attrs[] = {
-	&ibmvfc_host_partition_name,
-	&ibmvfc_host_device_name,
-	&ibmvfc_host_loc_code,
-	&ibmvfc_host_drc_name,
-	&ibmvfc_host_npiv_version,
-	&ibmvfc_log_level_attr,
+	&dev_attr_partition_name,
+	&dev_attr_device_name,
+	&dev_attr_port_loc_code,
+	&dev_attr_drc_name,
+	&dev_attr_npiv_version,
+	&dev_attr_capabilities,
+	&dev_attr_log_level,
 	NULL
 };
 
@@ -2774,15 +2830,19 @@
  * @tgt:		ibmvfc target struct
  * @job_step:	initialization job step
  *
+ * Returns: 1 if step will be retried / 0 if not
+ *
  **/
-static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt,
+static int ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt,
 				  void (*job_step) (struct ibmvfc_target *))
 {
 	if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) {
 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
 		wake_up(&tgt->vhost->work_wait_q);
+		return 0;
 	} else
 		ibmvfc_init_tgt(tgt, job_step);
+	return 1;
 }
 
 /* Defined in FC-LS */
@@ -2831,7 +2891,7 @@
 	struct ibmvfc_process_login *rsp = &evt->xfer_iu->prli;
 	struct ibmvfc_prli_svc_parms *parms = &rsp->parms;
 	u32 status = rsp->common.status;
-	int index;
+	int index, level = IBMVFC_DEFAULT_LOG_LEVEL;
 
 	vhost->discovery_threads--;
 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
@@ -2850,7 +2910,7 @@
 						tgt->ids.roles |= FC_PORT_ROLE_FCP_TARGET;
 					if (parms->service_parms & IBMVFC_PRLI_INITIATOR_FUNC)
 						tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR;
-					ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_ADD_RPORT);
+					tgt->add_rport = 1;
 				} else
 					ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
 			} else if (prli_rsp[index].retry)
@@ -2867,13 +2927,14 @@
 		break;
 	case IBMVFC_MAD_FAILED:
 	default:
-		tgt_err(tgt, "Process Login failed: %s (%x:%x) rc=0x%02X\n",
-			ibmvfc_get_cmd_error(rsp->status, rsp->error),
-			rsp->status, rsp->error, status);
 		if (ibmvfc_retry_cmd(rsp->status, rsp->error))
-			ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli);
+			level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli);
 		else
 			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
+
+		tgt_log(tgt, level, "Process Login failed: %s (%x:%x) rc=0x%02X\n",
+			ibmvfc_get_cmd_error(rsp->status, rsp->error),
+			rsp->status, rsp->error, status);
 		break;
 	};
 
@@ -2932,6 +2993,7 @@
 	struct ibmvfc_host *vhost = evt->vhost;
 	struct ibmvfc_port_login *rsp = &evt->xfer_iu->plogi;
 	u32 status = rsp->common.status;
+	int level = IBMVFC_DEFAULT_LOG_LEVEL;
 
 	vhost->discovery_threads--;
 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
@@ -2960,15 +3022,15 @@
 		break;
 	case IBMVFC_MAD_FAILED:
 	default:
-		tgt_err(tgt, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
+		if (ibmvfc_retry_cmd(rsp->status, rsp->error))
+			level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi);
+		else
+			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
+
+		tgt_log(tgt, level, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
 			ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error,
 			ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type,
 			ibmvfc_get_ls_explain(rsp->fc_explain), rsp->fc_explain, status);
-
-		if (ibmvfc_retry_cmd(rsp->status, rsp->error))
-			ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi);
-		else
-			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
 		break;
 	};
 
@@ -3129,13 +3191,13 @@
 	case IBMVFC_MAD_SUCCESS:
 		tgt_dbg(tgt, "ADISC succeeded\n");
 		if (ibmvfc_adisc_needs_plogi(mad, tgt))
-			tgt->need_login = 1;
+			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
 		break;
 	case IBMVFC_MAD_DRIVER_FAILED:
 		break;
 	case IBMVFC_MAD_FAILED:
 	default:
-		tgt->need_login = 1;
+		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
 		fc_reason = (mad->fc_iu.response[1] & 0x00ff0000) >> 16;
 		fc_explain = (mad->fc_iu.response[1] & 0x0000ff00) >> 8;
 		tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
@@ -3322,6 +3384,7 @@
 	struct ibmvfc_host *vhost = evt->vhost;
 	struct ibmvfc_query_tgt *rsp = &evt->xfer_iu->query_tgt;
 	u32 status = rsp->common.status;
+	int level = IBMVFC_DEFAULT_LOG_LEVEL;
 
 	vhost->discovery_threads--;
 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
@@ -3341,19 +3404,19 @@
 		break;
 	case IBMVFC_MAD_FAILED:
 	default:
-		tgt_err(tgt, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
-			ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error,
-			ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type,
-			ibmvfc_get_gs_explain(rsp->fc_explain), rsp->fc_explain, status);
-
 		if ((rsp->status & IBMVFC_FABRIC_MAPPED) == IBMVFC_FABRIC_MAPPED &&
 		    rsp->error == IBMVFC_UNABLE_TO_PERFORM_REQ &&
 		    rsp->fc_explain == IBMVFC_PORT_NAME_NOT_REG)
 			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
 		else if (ibmvfc_retry_cmd(rsp->status, rsp->error))
-			ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target);
+			level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target);
 		else
 			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
+
+		tgt_log(tgt, level, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
+			ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error,
+			ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type,
+			ibmvfc_get_gs_explain(rsp->fc_explain), rsp->fc_explain, status);
 		break;
 	};
 
@@ -3420,7 +3483,7 @@
 	}
 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
 
-	tgt = mempool_alloc(vhost->tgt_pool, GFP_KERNEL);
+	tgt = mempool_alloc(vhost->tgt_pool, GFP_NOIO);
 	if (!tgt) {
 		dev_err(vhost->dev, "Target allocation failure for scsi id %08llx\n",
 			scsi_id);
@@ -3472,6 +3535,7 @@
 	struct ibmvfc_host *vhost = evt->vhost;
 	struct ibmvfc_discover_targets *rsp = &evt->xfer_iu->discover_targets;
 	u32 mad_status = rsp->common.status;
+	int level = IBMVFC_DEFAULT_LOG_LEVEL;
 
 	switch (mad_status) {
 	case IBMVFC_MAD_SUCCESS:
@@ -3480,9 +3544,9 @@
 		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS);
 		break;
 	case IBMVFC_MAD_FAILED:
-		dev_err(vhost->dev, "Discover Targets failed: %s (%x:%x)\n",
-			ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error);
-		ibmvfc_retry_host_init(vhost);
+		level += ibmvfc_retry_host_init(vhost);
+		ibmvfc_log(vhost, level, "Discover Targets failed: %s (%x:%x)\n",
+			   ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error);
 		break;
 	case IBMVFC_MAD_DRIVER_FAILED:
 		break;
@@ -3534,18 +3598,19 @@
 	u32 mad_status = evt->xfer_iu->npiv_login.common.status;
 	struct ibmvfc_npiv_login_resp *rsp = &vhost->login_buf->resp;
 	unsigned int npiv_max_sectors;
+	int level = IBMVFC_DEFAULT_LOG_LEVEL;
 
 	switch (mad_status) {
 	case IBMVFC_MAD_SUCCESS:
 		ibmvfc_free_event(evt);
 		break;
 	case IBMVFC_MAD_FAILED:
-		dev_err(vhost->dev, "NPIV Login failed: %s (%x:%x)\n",
-			ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error);
 		if (ibmvfc_retry_cmd(rsp->status, rsp->error))
-			ibmvfc_retry_host_init(vhost);
+			level += ibmvfc_retry_host_init(vhost);
 		else
 			ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+		ibmvfc_log(vhost, level, "NPIV Login failed: %s (%x:%x)\n",
+			   ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error);
 		ibmvfc_free_event(evt);
 		return;
 	case IBMVFC_MAD_CRQ_ERROR:
@@ -3578,6 +3643,7 @@
 		return;
 	}
 
+	vhost->logged_in = 1;
 	npiv_max_sectors = min((uint)(rsp->max_dma_len >> 9), IBMVFC_MAX_SECTORS);
 	dev_info(vhost->dev, "Host partition: %s, device: %s %s %s max sectors %u\n",
 		 rsp->partition_name, rsp->device_name, rsp->port_loc_code,
@@ -3636,6 +3702,65 @@
 };
 
 /**
+ * ibmvfc_npiv_logout_done - Completion handler for NPIV Logout
+ * @vhost:		ibmvfc host struct
+ *
+ **/
+static void ibmvfc_npiv_logout_done(struct ibmvfc_event *evt)
+{
+	struct ibmvfc_host *vhost = evt->vhost;
+	u32 mad_status = evt->xfer_iu->npiv_logout.common.status;
+
+	ibmvfc_free_event(evt);
+
+	switch (mad_status) {
+	case IBMVFC_MAD_SUCCESS:
+		if (list_empty(&vhost->sent) &&
+		    vhost->action == IBMVFC_HOST_ACTION_LOGO_WAIT) {
+			ibmvfc_init_host(vhost, 0);
+			return;
+		}
+		break;
+	case IBMVFC_MAD_FAILED:
+	case IBMVFC_MAD_NOT_SUPPORTED:
+	case IBMVFC_MAD_CRQ_ERROR:
+	case IBMVFC_MAD_DRIVER_FAILED:
+	default:
+		ibmvfc_dbg(vhost, "NPIV Logout failed. 0x%X\n", mad_status);
+		break;
+	}
+
+	ibmvfc_hard_reset_host(vhost);
+}
+
+/**
+ * ibmvfc_npiv_logout - Issue an NPIV Logout
+ * @vhost:		ibmvfc host struct
+ *
+ **/
+static void ibmvfc_npiv_logout(struct ibmvfc_host *vhost)
+{
+	struct ibmvfc_npiv_logout_mad *mad;
+	struct ibmvfc_event *evt;
+
+	evt = ibmvfc_get_event(vhost);
+	ibmvfc_init_event(evt, ibmvfc_npiv_logout_done, IBMVFC_MAD_FORMAT);
+
+	mad = &evt->iu.npiv_logout;
+	memset(mad, 0, sizeof(*mad));
+	mad->common.version = 1;
+	mad->common.opcode = IBMVFC_NPIV_LOGOUT;
+	mad->common.length = sizeof(struct ibmvfc_npiv_logout_mad);
+
+	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO_WAIT);
+
+	if (!ibmvfc_send_event(evt, vhost, default_timeout))
+		ibmvfc_dbg(vhost, "Sent NPIV logout\n");
+	else
+		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+}
+
+/**
  * ibmvfc_dev_init_to_do - Is there target initialization work to do?
  * @vhost:		ibmvfc host struct
  *
@@ -3671,6 +3796,7 @@
 	switch (vhost->action) {
 	case IBMVFC_HOST_ACTION_NONE:
 	case IBMVFC_HOST_ACTION_INIT_WAIT:
+	case IBMVFC_HOST_ACTION_LOGO_WAIT:
 		return 0;
 	case IBMVFC_HOST_ACTION_TGT_INIT:
 	case IBMVFC_HOST_ACTION_QUERY_TGTS:
@@ -3683,9 +3809,9 @@
 			if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT)
 				return 0;
 		return 1;
+	case IBMVFC_HOST_ACTION_LOGO:
 	case IBMVFC_HOST_ACTION_INIT:
 	case IBMVFC_HOST_ACTION_ALLOC_TGTS:
-	case IBMVFC_HOST_ACTION_TGT_ADD:
 	case IBMVFC_HOST_ACTION_TGT_DEL:
 	case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
 	case IBMVFC_HOST_ACTION_QUERY:
@@ -3740,25 +3866,26 @@
 static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
 {
 	struct ibmvfc_host *vhost = tgt->vhost;
-	struct fc_rport *rport = tgt->rport;
+	struct fc_rport *rport;
 	unsigned long flags;
 
-	if (rport) {
-		tgt_dbg(tgt, "Setting rport roles\n");
-		fc_remote_port_rolechg(rport, tgt->ids.roles);
-		spin_lock_irqsave(vhost->host->host_lock, flags);
-		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
-		spin_unlock_irqrestore(vhost->host->host_lock, flags);
-		return;
-	}
-
 	tgt_dbg(tgt, "Adding rport\n");
 	rport = fc_remote_port_add(vhost->host, 0, &tgt->ids);
 	spin_lock_irqsave(vhost->host->host_lock, flags);
-	tgt->rport = rport;
-	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
+
+	if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) {
+		tgt_dbg(tgt, "Deleting rport\n");
+		list_del(&tgt->queue);
+		spin_unlock_irqrestore(vhost->host->host_lock, flags);
+		fc_remote_port_delete(rport);
+		del_timer_sync(&tgt->timer);
+		kref_put(&tgt->kref, ibmvfc_release_tgt);
+		return;
+	}
+
 	if (rport) {
 		tgt_dbg(tgt, "rport add succeeded\n");
+		tgt->rport = rport;
 		rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff;
 		rport->supported_classes = 0;
 		tgt->target_id = rport->scsi_target_id;
@@ -3789,8 +3916,12 @@
 	vhost->events_to_log = 0;
 	switch (vhost->action) {
 	case IBMVFC_HOST_ACTION_NONE:
+	case IBMVFC_HOST_ACTION_LOGO_WAIT:
 	case IBMVFC_HOST_ACTION_INIT_WAIT:
 		break;
+	case IBMVFC_HOST_ACTION_LOGO:
+		vhost->job_step(vhost);
+		break;
 	case IBMVFC_HOST_ACTION_INIT:
 		BUG_ON(vhost->state != IBMVFC_INITIALIZING);
 		if (vhost->delay_init) {
@@ -3836,11 +3967,21 @@
 
 		if (vhost->state == IBMVFC_INITIALIZING) {
 			if (vhost->action == IBMVFC_HOST_ACTION_TGT_DEL_FAILED) {
-				ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE);
-				ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD);
-				vhost->init_retries = 0;
-				spin_unlock_irqrestore(vhost->host->host_lock, flags);
-				scsi_unblock_requests(vhost->host);
+				if (vhost->reinit) {
+					vhost->reinit = 0;
+					scsi_block_requests(vhost->host);
+					ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
+					spin_unlock_irqrestore(vhost->host->host_lock, flags);
+				} else {
+					ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE);
+					ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
+					wake_up(&vhost->init_wait_q);
+					schedule_work(&vhost->rport_add_work_q);
+					vhost->init_retries = 0;
+					spin_unlock_irqrestore(vhost->host->host_lock, flags);
+					scsi_unblock_requests(vhost->host);
+				}
+
 				return;
 			} else {
 				ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
@@ -3871,24 +4012,6 @@
 		if (!ibmvfc_dev_init_to_do(vhost))
 			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL_FAILED);
 		break;
-	case IBMVFC_HOST_ACTION_TGT_ADD:
-		list_for_each_entry(tgt, &vhost->targets, queue) {
-			if (tgt->action == IBMVFC_TGT_ACTION_ADD_RPORT) {
-				spin_unlock_irqrestore(vhost->host->host_lock, flags);
-				ibmvfc_tgt_add_rport(tgt);
-				return;
-			}
-		}
-
-		if (vhost->reinit && !ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
-			vhost->reinit = 0;
-			scsi_block_requests(vhost->host);
-			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
-		} else {
-			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
-			wake_up(&vhost->init_wait_q);
-		}
-		break;
 	default:
 		break;
 	};
@@ -4118,6 +4241,56 @@
 }
 
 /**
+ * ibmvfc_rport_add_thread - Worker thread for rport adds
+ * @work:	work struct
+ *
+ **/
+static void ibmvfc_rport_add_thread(struct work_struct *work)
+{
+	struct ibmvfc_host *vhost = container_of(work, struct ibmvfc_host,
+						 rport_add_work_q);
+	struct ibmvfc_target *tgt;
+	struct fc_rport *rport;
+	unsigned long flags;
+	int did_work;
+
+	ENTER;
+	spin_lock_irqsave(vhost->host->host_lock, flags);
+	do {
+		did_work = 0;
+		if (vhost->state != IBMVFC_ACTIVE)
+			break;
+
+		list_for_each_entry(tgt, &vhost->targets, queue) {
+			if (tgt->add_rport) {
+				did_work = 1;
+				tgt->add_rport = 0;
+				kref_get(&tgt->kref);
+				rport = tgt->rport;
+				if (!rport) {
+					spin_unlock_irqrestore(vhost->host->host_lock, flags);
+					ibmvfc_tgt_add_rport(tgt);
+				} else if (get_device(&rport->dev)) {
+					spin_unlock_irqrestore(vhost->host->host_lock, flags);
+					tgt_dbg(tgt, "Setting rport roles\n");
+					fc_remote_port_rolechg(rport, tgt->ids.roles);
+					put_device(&rport->dev);
+				}
+
+				kref_put(&tgt->kref, ibmvfc_release_tgt);
+				spin_lock_irqsave(vhost->host->host_lock, flags);
+				break;
+			}
+		}
+	} while(did_work);
+
+	if (vhost->state == IBMVFC_ACTIVE)
+		vhost->scan_complete = 1;
+	spin_unlock_irqrestore(vhost->host->host_lock, flags);
+	LEAVE;
+}
+
+/**
  * ibmvfc_probe - Adapter hot plug add entry point
  * @vdev:	vio device struct
  * @id:	vio device id struct
@@ -4160,6 +4333,7 @@
 	strcpy(vhost->partition_name, "UNKNOWN");
 	init_waitqueue_head(&vhost->work_wait_q);
 	init_waitqueue_head(&vhost->init_wait_q);
+	INIT_WORK(&vhost->rport_add_work_q, ibmvfc_rport_add_thread);
 
 	if ((rc = ibmvfc_alloc_mem(vhost)))
 		goto free_scsi_host;
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index ca1dcf7..c2668d7 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -29,8 +29,8 @@
 #include "viosrp.h"
 
 #define IBMVFC_NAME	"ibmvfc"
-#define IBMVFC_DRIVER_VERSION		"1.0.5"
-#define IBMVFC_DRIVER_DATE		"(March 19, 2009)"
+#define IBMVFC_DRIVER_VERSION		"1.0.6"
+#define IBMVFC_DRIVER_DATE		"(May 28, 2009)"
 
 #define IBMVFC_DEFAULT_TIMEOUT	60
 #define IBMVFC_ADISC_CANCEL_TIMEOUT	45
@@ -57,9 +57,10 @@
  * Ensure we have resources for ERP and initialization:
  * 1 for ERP
  * 1 for initialization
+ * 1 for NPIV Logout
  * 2 for each discovery thread
  */
-#define IBMVFC_NUM_INTERNAL_REQ	(1 + 1 + (disc_threads * 2))
+#define IBMVFC_NUM_INTERNAL_REQ	(1 + 1 + 1 + (disc_threads * 2))
 
 #define IBMVFC_MAD_SUCCESS		0x00
 #define IBMVFC_MAD_NOT_SUPPORTED	0xF1
@@ -127,6 +128,7 @@
 	IBMVFC_IMPLICIT_LOGOUT	= 0x0040,
 	IBMVFC_PASSTHRU		= 0x0200,
 	IBMVFC_TMF_MAD		= 0x0100,
+	IBMVFC_NPIV_LOGOUT	= 0x0800,
 };
 
 struct ibmvfc_mad_common {
@@ -143,6 +145,10 @@
 	struct srp_direct_buf buffer;
 }__attribute__((packed, aligned (8)));
 
+struct ibmvfc_npiv_logout_mad {
+	struct ibmvfc_mad_common common;
+}__attribute__((packed, aligned (8)));
+
 #define IBMVFC_MAX_NAME 256
 
 struct ibmvfc_npiv_login {
@@ -201,7 +207,8 @@
 #define IBMVFC_NATIVE_FC		0x01
 #define IBMVFC_CAN_FLUSH_ON_HALT	0x08
 	u32 reserved;
-	u64 capabilites;
+	u64 capabilities;
+#define IBMVFC_CAN_FLUSH_ON_HALT	0x08
 	u32 max_cmds;
 	u32 scsi_id_sz;
 	u64 max_dma_len;
@@ -541,9 +548,17 @@
 	dma_addr_t msg_token;
 };
 
+enum ibmvfc_ae_link_state {
+	IBMVFC_AE_LS_LINK_UP		= 0x01,
+	IBMVFC_AE_LS_LINK_BOUNCED	= 0x02,
+	IBMVFC_AE_LS_LINK_DOWN		= 0x04,
+	IBMVFC_AE_LS_LINK_DEAD		= 0x08,
+};
+
 struct ibmvfc_async_crq {
 	volatile u8 valid;
-	u8 pad[3];
+	u8 link_state;
+	u8 pad[2];
 	u32 pad2;
 	volatile u64 event;
 	volatile u64 scsi_id;
@@ -561,6 +576,7 @@
 union ibmvfc_iu {
 	struct ibmvfc_mad_common mad_common;
 	struct ibmvfc_npiv_login_mad npiv_login;
+	struct ibmvfc_npiv_logout_mad npiv_logout;
 	struct ibmvfc_discover_targets discover_targets;
 	struct ibmvfc_port_login plogi;
 	struct ibmvfc_process_login prli;
@@ -575,7 +591,6 @@
 	IBMVFC_TGT_ACTION_NONE = 0,
 	IBMVFC_TGT_ACTION_INIT,
 	IBMVFC_TGT_ACTION_INIT_WAIT,
-	IBMVFC_TGT_ACTION_ADD_RPORT,
 	IBMVFC_TGT_ACTION_DEL_RPORT,
 };
 
@@ -588,6 +603,7 @@
 	int target_id;
 	enum ibmvfc_target_action action;
 	int need_login;
+	int add_rport;
 	int init_retries;
 	u32 cancel_key;
 	struct ibmvfc_service_parms service_parms;
@@ -627,6 +643,8 @@
 
 enum ibmvfc_host_action {
 	IBMVFC_HOST_ACTION_NONE = 0,
+	IBMVFC_HOST_ACTION_LOGO,
+	IBMVFC_HOST_ACTION_LOGO_WAIT,
 	IBMVFC_HOST_ACTION_INIT,
 	IBMVFC_HOST_ACTION_INIT_WAIT,
 	IBMVFC_HOST_ACTION_QUERY,
@@ -635,7 +653,6 @@
 	IBMVFC_HOST_ACTION_ALLOC_TGTS,
 	IBMVFC_HOST_ACTION_TGT_INIT,
 	IBMVFC_HOST_ACTION_TGT_DEL_FAILED,
-	IBMVFC_HOST_ACTION_TGT_ADD,
 };
 
 enum ibmvfc_host_state {
@@ -682,6 +699,8 @@
 	int client_migrated;
 	int reinit;
 	int delay_init;
+	int scan_complete;
+	int logged_in;
 	int events_to_log;
 #define IBMVFC_AE_LINKUP	0x0001
 #define IBMVFC_AE_LINKDOWN	0x0002
@@ -692,6 +711,7 @@
 	void (*job_step) (struct ibmvfc_host *);
 	struct task_struct *work_thread;
 	struct tasklet_struct tasklet;
+	struct work_struct rport_add_work_q;
 	wait_queue_head_t init_wait_q;
 	wait_queue_head_t work_wait_q;
 };
@@ -707,6 +727,12 @@
 #define tgt_err(t, fmt, ...)		\
 	dev_err((t)->vhost->dev, "%llX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
 
+#define tgt_log(t, level, fmt, ...) \
+	do { \
+		if ((t)->vhost->log_level >= level) \
+			tgt_err(t, fmt, ##__VA_ARGS__); \
+	} while (0)
+
 #define ibmvfc_dbg(vhost, ...) \
 	DBG_CMD(dev_info((vhost)->dev, ##__VA_ARGS__))
 
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index c9aa761..11d2602 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -70,6 +70,7 @@
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <linux/of.h>
 #include <asm/firmware.h>
 #include <asm/vio.h>
 #include <asm/firmware.h>
@@ -87,9 +88,15 @@
  */
 static int max_id = 64;
 static int max_channel = 3;
-static int init_timeout = 5;
+static int init_timeout = 300;
+static int login_timeout = 60;
+static int info_timeout = 30;
+static int abort_timeout = 60;
+static int reset_timeout = 60;
 static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
 static int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2;
+static int fast_fail = 1;
+static int client_reserve = 1;
 
 static struct scsi_transport_template *ibmvscsi_transport_template;
 
@@ -110,6 +117,10 @@
 MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds");
 module_param_named(max_requests, max_requests, int, S_IRUGO);
 MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter");
+module_param_named(fast_fail, fast_fail, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(fast_fail, "Enable fast fail. [Default=1]");
+module_param_named(client_reserve, client_reserve, int, S_IRUGO );
+MODULE_PARM_DESC(client_reserve, "Attempt client managed reserve/release");
 
 /* ------------------------------------------------------------
  * Routines for the event pool and event structs
@@ -781,105 +792,53 @@
 /* ------------------------------------------------------------
  * Routines for driver initialization
  */
-/**
- * adapter_info_rsp: - Handle response to MAD adapter info request
- * @evt_struct:	srp_event_struct with the response
- *
- * Used as a "done" callback by when sending adapter_info. Gets called
- * by ibmvscsi_handle_crq()
-*/
-static void adapter_info_rsp(struct srp_event_struct *evt_struct)
-{
-	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
-	dma_unmap_single(hostdata->dev,
-			 evt_struct->iu.mad.adapter_info.buffer,
-			 evt_struct->iu.mad.adapter_info.common.length,
-			 DMA_BIDIRECTIONAL);
 
-	if (evt_struct->xfer_iu->mad.adapter_info.common.status) {
-		dev_err(hostdata->dev, "error %d getting adapter info\n",
-			evt_struct->xfer_iu->mad.adapter_info.common.status);
-	} else {
-		dev_info(hostdata->dev, "host srp version: %s, "
-			 "host partition %s (%d), OS %d, max io %u\n",
-			 hostdata->madapter_info.srp_version,
-			 hostdata->madapter_info.partition_name,
-			 hostdata->madapter_info.partition_number,
-			 hostdata->madapter_info.os_type,
-			 hostdata->madapter_info.port_max_txu[0]);
-		
-		if (hostdata->madapter_info.port_max_txu[0]) 
-			hostdata->host->max_sectors = 
-				hostdata->madapter_info.port_max_txu[0] >> 9;
-		
-		if (hostdata->madapter_info.os_type == 3 &&
-		    strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
-			dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n",
-				hostdata->madapter_info.srp_version);
-			dev_err(hostdata->dev, "limiting scatterlists to %d\n",
-				MAX_INDIRECT_BUFS);
-			hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
-		}
+/**
+ * map_persist_bufs: - Pre-map persistent data for adapter logins
+ * @hostdata:   ibmvscsi_host_data of host
+ *
+ * Map the capabilities and adapter info DMA buffers to avoid runtime failures.
+ * Return 1 on error, 0 on success.
+ */
+static int map_persist_bufs(struct ibmvscsi_host_data *hostdata)
+{
+
+	hostdata->caps_addr = dma_map_single(hostdata->dev, &hostdata->caps,
+					     sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
+
+	if (dma_mapping_error(hostdata->dev, hostdata->caps_addr)) {
+		dev_err(hostdata->dev, "Unable to map capabilities buffer!\n");
+		return 1;
 	}
+
+	hostdata->adapter_info_addr = dma_map_single(hostdata->dev,
+						     &hostdata->madapter_info,
+						     sizeof(hostdata->madapter_info),
+						     DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(hostdata->dev, hostdata->adapter_info_addr)) {
+		dev_err(hostdata->dev, "Unable to map adapter info buffer!\n");
+		dma_unmap_single(hostdata->dev, hostdata->caps_addr,
+				 sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
+		return 1;
+	}
+
+	return 0;
 }
 
 /**
- * send_mad_adapter_info: - Sends the mad adapter info request
- *      and stores the result so it can be retrieved with
- *      sysfs.  We COULD consider causing a failure if the
- *      returned SRP version doesn't match ours.
- * @hostdata:	ibmvscsi_host_data of host
- * 
- * Returns zero if successful.
-*/
-static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
+ * unmap_persist_bufs: - Unmap persistent data needed for adapter logins
+ * @hostdata:   ibmvscsi_host_data of host
+ *
+ * Unmap the capabilities and adapter info DMA buffers
+ */
+static void unmap_persist_bufs(struct ibmvscsi_host_data *hostdata)
 {
-	struct viosrp_adapter_info *req;
-	struct srp_event_struct *evt_struct;
-	unsigned long flags;
-	dma_addr_t addr;
+	dma_unmap_single(hostdata->dev, hostdata->caps_addr,
+			 sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
 
-	evt_struct = get_event_struct(&hostdata->pool);
-	if (!evt_struct) {
-		dev_err(hostdata->dev,
-			"couldn't allocate an event for ADAPTER_INFO_REQ!\n");
-		return;
-	}
-
-	init_event_struct(evt_struct,
-			  adapter_info_rsp,
-			  VIOSRP_MAD_FORMAT,
-			  init_timeout);
-	
-	req = &evt_struct->iu.mad.adapter_info;
-	memset(req, 0x00, sizeof(*req));
-	
-	req->common.type = VIOSRP_ADAPTER_INFO_TYPE;
-	req->common.length = sizeof(hostdata->madapter_info);
-	req->buffer = addr = dma_map_single(hostdata->dev,
-					    &hostdata->madapter_info,
-					    sizeof(hostdata->madapter_info),
-					    DMA_BIDIRECTIONAL);
-
-	if (dma_mapping_error(hostdata->dev, req->buffer)) {
-		if (!firmware_has_feature(FW_FEATURE_CMO))
-			dev_err(hostdata->dev,
-			        "Unable to map request_buffer for "
-			        "adapter_info!\n");
-		free_event_struct(&hostdata->pool, evt_struct);
-		return;
-	}
-	
-	spin_lock_irqsave(hostdata->host->host_lock, flags);
-	if (ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2)) {
-		dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n");
-		dma_unmap_single(hostdata->dev,
-				 addr,
-				 sizeof(hostdata->madapter_info),
-				 DMA_BIDIRECTIONAL);
-	}
-	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-};
+	dma_unmap_single(hostdata->dev, hostdata->adapter_info_addr,
+			 sizeof(hostdata->madapter_info), DMA_BIDIRECTIONAL);
+}
 
 /**
  * login_rsp: - Handle response to SRP login request
@@ -909,9 +868,7 @@
 	}
 
 	dev_info(hostdata->dev, "SRP_LOGIN succeeded\n");
-
-	if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta < 0)
-		dev_err(hostdata->dev, "Invalid request_limit.\n");
+	hostdata->client_migrated = 0;
 
 	/* Now we know what the real request-limit is.
 	 * This value is set rather than added to request_limit because
@@ -922,15 +879,12 @@
 
 	/* If we had any pending I/Os, kick them */
 	scsi_unblock_requests(hostdata->host);
-
-	send_mad_adapter_info(hostdata);
-	return;
 }
 
 /**
  * send_srp_login: - Sends the srp login
  * @hostdata:	ibmvscsi_host_data of host
- * 
+ *
  * Returns zero if successful.
 */
 static int send_srp_login(struct ibmvscsi_host_data *hostdata)
@@ -939,22 +893,17 @@
 	unsigned long flags;
 	struct srp_login_req *login;
 	struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool);
-	if (!evt_struct) {
-		dev_err(hostdata->dev, "couldn't allocate an event for login req!\n");
-		return FAILED;
-	}
 
-	init_event_struct(evt_struct,
-			  login_rsp,
-			  VIOSRP_SRP_FORMAT,
-			  init_timeout);
+	BUG_ON(!evt_struct);
+	init_event_struct(evt_struct, login_rsp,
+			  VIOSRP_SRP_FORMAT, login_timeout);
 
 	login = &evt_struct->iu.srp.login_req;
-	memset(login, 0x00, sizeof(struct srp_login_req));
+	memset(login, 0, sizeof(*login));
 	login->opcode = SRP_LOGIN_REQ;
 	login->req_it_iu_len = sizeof(union srp_iu);
 	login->req_buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT;
-	
+
 	spin_lock_irqsave(hostdata->host->host_lock, flags);
 	/* Start out with a request limit of 0, since this is negotiated in
 	 * the login request we are just sending and login requests always
@@ -962,13 +911,241 @@
 	 */
 	atomic_set(&hostdata->request_limit, 0);
 
-	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
+	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, login_timeout * 2);
 	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
 	dev_info(hostdata->dev, "sent SRP login\n");
 	return rc;
 };
 
 /**
+ * capabilities_rsp: - Handle response to MAD adapter capabilities request
+ * @evt_struct:	srp_event_struct with the response
+ *
+ * Used as a "done" callback by when sending adapter_info.
+ */
+static void capabilities_rsp(struct srp_event_struct *evt_struct)
+{
+	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
+
+	if (evt_struct->xfer_iu->mad.capabilities.common.status) {
+		dev_err(hostdata->dev, "error 0x%X getting capabilities info\n",
+			evt_struct->xfer_iu->mad.capabilities.common.status);
+	} else {
+		if (hostdata->caps.migration.common.server_support != SERVER_SUPPORTS_CAP)
+			dev_info(hostdata->dev, "Partition migration not supported\n");
+
+		if (client_reserve) {
+			if (hostdata->caps.reserve.common.server_support ==
+			    SERVER_SUPPORTS_CAP)
+				dev_info(hostdata->dev, "Client reserve enabled\n");
+			else
+				dev_info(hostdata->dev, "Client reserve not supported\n");
+		}
+	}
+
+	send_srp_login(hostdata);
+}
+
+/**
+ * send_mad_capabilities: - Sends the mad capabilities request
+ *      and stores the result so it can be retrieved with
+ * @hostdata:	ibmvscsi_host_data of host
+ */
+static void send_mad_capabilities(struct ibmvscsi_host_data *hostdata)
+{
+	struct viosrp_capabilities *req;
+	struct srp_event_struct *evt_struct;
+	unsigned long flags;
+	struct device_node *of_node = hostdata->dev->archdata.of_node;
+	const char *location;
+
+	evt_struct = get_event_struct(&hostdata->pool);
+	BUG_ON(!evt_struct);
+
+	init_event_struct(evt_struct, capabilities_rsp,
+			  VIOSRP_MAD_FORMAT, info_timeout);
+
+	req = &evt_struct->iu.mad.capabilities;
+	memset(req, 0, sizeof(*req));
+
+	hostdata->caps.flags = CAP_LIST_SUPPORTED;
+	if (hostdata->client_migrated)
+		hostdata->caps.flags |= CLIENT_MIGRATED;
+
+	strncpy(hostdata->caps.name, dev_name(&hostdata->host->shost_gendev),
+		sizeof(hostdata->caps.name));
+	hostdata->caps.name[sizeof(hostdata->caps.name) - 1] = '\0';
+
+	location = of_get_property(of_node, "ibm,loc-code", NULL);
+	location = location ? location : dev_name(hostdata->dev);
+	strncpy(hostdata->caps.loc, location, sizeof(hostdata->caps.loc));
+	hostdata->caps.loc[sizeof(hostdata->caps.loc) - 1] = '\0';
+
+	req->common.type = VIOSRP_CAPABILITIES_TYPE;
+	req->buffer = hostdata->caps_addr;
+
+	hostdata->caps.migration.common.cap_type = MIGRATION_CAPABILITIES;
+	hostdata->caps.migration.common.length = sizeof(hostdata->caps.migration);
+	hostdata->caps.migration.common.server_support = SERVER_SUPPORTS_CAP;
+	hostdata->caps.migration.ecl = 1;
+
+	if (client_reserve) {
+		hostdata->caps.reserve.common.cap_type = RESERVATION_CAPABILITIES;
+		hostdata->caps.reserve.common.length = sizeof(hostdata->caps.reserve);
+		hostdata->caps.reserve.common.server_support = SERVER_SUPPORTS_CAP;
+		hostdata->caps.reserve.type = CLIENT_RESERVE_SCSI_2;
+		req->common.length = sizeof(hostdata->caps);
+	} else
+		req->common.length = sizeof(hostdata->caps) - sizeof(hostdata->caps.reserve);
+
+	spin_lock_irqsave(hostdata->host->host_lock, flags);
+	if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2))
+		dev_err(hostdata->dev, "couldn't send CAPABILITIES_REQ!\n");
+	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+};
+
+/**
+ * fast_fail_rsp: - Handle response to MAD enable fast fail
+ * @evt_struct:	srp_event_struct with the response
+ *
+ * Used as a "done" callback by when sending enable fast fail. Gets called
+ * by ibmvscsi_handle_crq()
+ */
+static void fast_fail_rsp(struct srp_event_struct *evt_struct)
+{
+	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
+	u8 status = evt_struct->xfer_iu->mad.fast_fail.common.status;
+
+	if (status == VIOSRP_MAD_NOT_SUPPORTED)
+		dev_err(hostdata->dev, "fast_fail not supported in server\n");
+	else if (status == VIOSRP_MAD_FAILED)
+		dev_err(hostdata->dev, "fast_fail request failed\n");
+	else if (status != VIOSRP_MAD_SUCCESS)
+		dev_err(hostdata->dev, "error 0x%X enabling fast_fail\n", status);
+
+	send_mad_capabilities(hostdata);
+}
+
+/**
+ * init_host - Start host initialization
+ * @hostdata:	ibmvscsi_host_data of host
+ *
+ * Returns zero if successful.
+ */
+static int enable_fast_fail(struct ibmvscsi_host_data *hostdata)
+{
+	int rc;
+	unsigned long flags;
+	struct viosrp_fast_fail *fast_fail_mad;
+	struct srp_event_struct *evt_struct;
+
+	if (!fast_fail) {
+		send_mad_capabilities(hostdata);
+		return 0;
+	}
+
+	evt_struct = get_event_struct(&hostdata->pool);
+	BUG_ON(!evt_struct);
+
+	init_event_struct(evt_struct, fast_fail_rsp, VIOSRP_MAD_FORMAT, info_timeout);
+
+	fast_fail_mad = &evt_struct->iu.mad.fast_fail;
+	memset(fast_fail_mad, 0, sizeof(*fast_fail_mad));
+	fast_fail_mad->common.type = VIOSRP_ENABLE_FAST_FAIL;
+	fast_fail_mad->common.length = sizeof(*fast_fail_mad);
+
+	spin_lock_irqsave(hostdata->host->host_lock, flags);
+	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2);
+	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+	return rc;
+}
+
+/**
+ * adapter_info_rsp: - Handle response to MAD adapter info request
+ * @evt_struct:	srp_event_struct with the response
+ *
+ * Used as a "done" callback by when sending adapter_info. Gets called
+ * by ibmvscsi_handle_crq()
+*/
+static void adapter_info_rsp(struct srp_event_struct *evt_struct)
+{
+	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
+
+	if (evt_struct->xfer_iu->mad.adapter_info.common.status) {
+		dev_err(hostdata->dev, "error %d getting adapter info\n",
+			evt_struct->xfer_iu->mad.adapter_info.common.status);
+	} else {
+		dev_info(hostdata->dev, "host srp version: %s, "
+			 "host partition %s (%d), OS %d, max io %u\n",
+			 hostdata->madapter_info.srp_version,
+			 hostdata->madapter_info.partition_name,
+			 hostdata->madapter_info.partition_number,
+			 hostdata->madapter_info.os_type,
+			 hostdata->madapter_info.port_max_txu[0]);
+		
+		if (hostdata->madapter_info.port_max_txu[0]) 
+			hostdata->host->max_sectors = 
+				hostdata->madapter_info.port_max_txu[0] >> 9;
+		
+		if (hostdata->madapter_info.os_type == 3 &&
+		    strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
+			dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n",
+				hostdata->madapter_info.srp_version);
+			dev_err(hostdata->dev, "limiting scatterlists to %d\n",
+				MAX_INDIRECT_BUFS);
+			hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
+		}
+	}
+
+	enable_fast_fail(hostdata);
+}
+
+/**
+ * send_mad_adapter_info: - Sends the mad adapter info request
+ *      and stores the result so it can be retrieved with
+ *      sysfs.  We COULD consider causing a failure if the
+ *      returned SRP version doesn't match ours.
+ * @hostdata:	ibmvscsi_host_data of host
+ * 
+ * Returns zero if successful.
+*/
+static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
+{
+	struct viosrp_adapter_info *req;
+	struct srp_event_struct *evt_struct;
+	unsigned long flags;
+
+	evt_struct = get_event_struct(&hostdata->pool);
+	BUG_ON(!evt_struct);
+
+	init_event_struct(evt_struct,
+			  adapter_info_rsp,
+			  VIOSRP_MAD_FORMAT,
+			  info_timeout);
+	
+	req = &evt_struct->iu.mad.adapter_info;
+	memset(req, 0x00, sizeof(*req));
+	
+	req->common.type = VIOSRP_ADAPTER_INFO_TYPE;
+	req->common.length = sizeof(hostdata->madapter_info);
+	req->buffer = hostdata->adapter_info_addr;
+
+	spin_lock_irqsave(hostdata->host->host_lock, flags);
+	if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2))
+		dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n");
+	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+};
+
+/**
+ * init_adapter: Start virtual adapter initialization sequence
+ *
+ */
+static void init_adapter(struct ibmvscsi_host_data *hostdata)
+{
+	send_mad_adapter_info(hostdata);
+}
+
+/**
  * sync_completion: Signal that a synchronous command has completed
  * Note that after returning from this call, the evt_struct is freed.
  * the caller waiting on this completion shouldn't touch the evt_struct
@@ -1029,7 +1206,7 @@
 		init_event_struct(evt,
 				  sync_completion,
 				  VIOSRP_SRP_FORMAT,
-				  init_timeout);
+				  abort_timeout);
 
 		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
 	
@@ -1043,7 +1220,7 @@
 		evt->sync_srp = &srp_rsp;
 
 		init_completion(&evt->comp);
-		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, abort_timeout * 2);
 
 		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
 			break;
@@ -1152,7 +1329,7 @@
 		init_event_struct(evt,
 				  sync_completion,
 				  VIOSRP_SRP_FORMAT,
-				  init_timeout);
+				  reset_timeout);
 
 		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
 
@@ -1165,7 +1342,7 @@
 		evt->sync_srp = &srp_rsp;
 
 		init_completion(&evt->comp);
-		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, reset_timeout * 2);
 
 		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
 			break;
@@ -1281,7 +1458,7 @@
 			if ((rc = ibmvscsi_ops->send_crq(hostdata,
 							 0xC002000000000000LL, 0)) == 0) {
 				/* Now login */
-				send_srp_login(hostdata);
+				init_adapter(hostdata);
 			} else {
 				dev_err(hostdata->dev, "Unable to send init rsp. rc=%ld\n", rc);
 			}
@@ -1291,7 +1468,7 @@
 			dev_info(hostdata->dev, "partner initialization complete\n");
 
 			/* Now login */
-			send_srp_login(hostdata);
+			init_adapter(hostdata);
 			break;
 		default:
 			dev_err(hostdata->dev, "unknown crq message type: %d\n", crq->format);
@@ -1303,6 +1480,7 @@
 		if (crq->format == 0x06) {
 			/* We need to re-setup the interpartition connection */
 			dev_info(hostdata->dev, "Re-enabling adapter!\n");
+			hostdata->client_migrated = 1;
 			purge_requests(hostdata, DID_REQUEUE);
 			if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue,
 							      hostdata)) ||
@@ -1397,7 +1575,7 @@
 	init_event_struct(evt_struct,
 			  sync_completion,
 			  VIOSRP_MAD_FORMAT,
-			  init_timeout);
+			  info_timeout);
 
 	host_config = &evt_struct->iu.mad.host_config;
 
@@ -1419,7 +1597,7 @@
 
 	init_completion(&evt_struct->comp);
 	spin_lock_irqsave(hostdata->host->host_lock, flags);
-	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
+	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2);
 	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
 	if (rc == 0)
 		wait_for_completion(&evt_struct->comp);
@@ -1444,7 +1622,7 @@
 	spin_lock_irqsave(shost->host_lock, lock_flags);
 	if (sdev->type == TYPE_DISK) {
 		sdev->allow_restart = 1;
-		blk_queue_rq_timeout(sdev->request_queue, 60 * HZ);
+		blk_queue_rq_timeout(sdev->request_queue, 120 * HZ);
 	}
 	scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
 	spin_unlock_irqrestore(shost->host_lock, lock_flags);
@@ -1471,6 +1649,46 @@
 /* ------------------------------------------------------------
  * sysfs attributes
  */
+static ssize_t show_host_vhost_loc(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(dev);
+	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
+	int len;
+
+	len = snprintf(buf, sizeof(hostdata->caps.loc), "%s\n",
+		       hostdata->caps.loc);
+	return len;
+}
+
+static struct device_attribute ibmvscsi_host_vhost_loc = {
+	.attr = {
+		 .name = "vhost_loc",
+		 .mode = S_IRUGO,
+		 },
+	.show = show_host_vhost_loc,
+};
+
+static ssize_t show_host_vhost_name(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(dev);
+	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
+	int len;
+
+	len = snprintf(buf, sizeof(hostdata->caps.name), "%s\n",
+		       hostdata->caps.name);
+	return len;
+}
+
+static struct device_attribute ibmvscsi_host_vhost_name = {
+	.attr = {
+		 .name = "vhost_name",
+		 .mode = S_IRUGO,
+		 },
+	.show = show_host_vhost_name,
+};
+
 static ssize_t show_host_srp_version(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
@@ -1594,6 +1812,8 @@
 };
 
 static struct device_attribute *ibmvscsi_attrs[] = {
+	&ibmvscsi_host_vhost_loc,
+	&ibmvscsi_host_vhost_name,
 	&ibmvscsi_host_srp_version,
 	&ibmvscsi_host_partition_name,
 	&ibmvscsi_host_partition_number,
@@ -1674,6 +1894,11 @@
 	atomic_set(&hostdata->request_limit, -1);
 	hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT;
 
+	if (map_persist_bufs(hostdata)) {
+		dev_err(&vdev->dev, "couldn't map persistent buffers\n");
+		goto persist_bufs_failed;
+	}
+
 	rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events);
 	if (rc != 0 && rc != H_RESOURCE) {
 		dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
@@ -1687,6 +1912,7 @@
 	host->max_lun = 8;
 	host->max_id = max_id;
 	host->max_channel = max_channel;
+	host->max_cmd_len = 16;
 
 	if (scsi_add_host(hostdata->host, hostdata->dev))
 		goto add_host_failed;
@@ -1733,6 +1959,8 @@
       init_pool_failed:
 	ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events);
       init_crq_failed:
+	unmap_persist_bufs(hostdata);
+      persist_bufs_failed:
 	scsi_host_put(host);
       scsi_host_alloc_failed:
 	return -1;
@@ -1741,6 +1969,7 @@
 static int ibmvscsi_remove(struct vio_dev *vdev)
 {
 	struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data;
+	unmap_persist_bufs(hostdata);
 	release_event_pool(&hostdata->pool, hostdata);
 	ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
 					max_events);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 2d4339d..7642530 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -90,6 +90,7 @@
 /* all driver data associated with a host adapter */
 struct ibmvscsi_host_data {
 	atomic_t request_limit;
+	int client_migrated;
 	struct device *dev;
 	struct event_pool pool;
 	struct crq_queue queue;
@@ -97,6 +98,9 @@
 	struct list_head sent;
 	struct Scsi_Host *host;
 	struct mad_adapter_info_data madapter_info;
+	struct capabilities caps;
+	dma_addr_t caps_addr;
+	dma_addr_t adapter_info_addr;
 };
 
 /* routines for managing a command/response queue */
diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h
index 2046045..2cd735d 100644
--- a/drivers/scsi/ibmvscsi/viosrp.h
+++ b/drivers/scsi/ibmvscsi/viosrp.h
@@ -37,6 +37,7 @@
 
 #define SRP_VERSION "16.a"
 #define SRP_MAX_IU_LEN	256
+#define SRP_MAX_LOC_LEN 32
 
 union srp_iu {
 	struct srp_login_req login_req;
@@ -86,7 +87,37 @@
 	VIOSRP_EMPTY_IU_TYPE = 0x01,
 	VIOSRP_ERROR_LOG_TYPE = 0x02,
 	VIOSRP_ADAPTER_INFO_TYPE = 0x03,
-	VIOSRP_HOST_CONFIG_TYPE = 0x04
+	VIOSRP_HOST_CONFIG_TYPE = 0x04,
+	VIOSRP_CAPABILITIES_TYPE = 0x05,
+	VIOSRP_ENABLE_FAST_FAIL = 0x08,
+};
+
+enum viosrp_mad_status {
+	VIOSRP_MAD_SUCCESS = 0x00,
+	VIOSRP_MAD_NOT_SUPPORTED = 0xF1,
+	VIOSRP_MAD_FAILED = 0xF7,
+};
+
+enum viosrp_capability_type {
+	MIGRATION_CAPABILITIES = 0x01,
+	RESERVATION_CAPABILITIES = 0x02,
+};
+
+enum viosrp_capability_support {
+	SERVER_DOES_NOT_SUPPORTS_CAP = 0x0,
+	SERVER_SUPPORTS_CAP = 0x01,
+	SERVER_CAP_DATA = 0x02,
+};
+
+enum viosrp_reserve_type {
+	CLIENT_RESERVE_SCSI_2 = 0x01,
+};
+
+enum viosrp_capability_flag {
+	CLIENT_MIGRATED = 0x01,
+	CLIENT_RECONNECT = 0x02,
+	CAP_LIST_SUPPORTED = 0x04,
+	CAP_LIST_DATA = 0x08,
 };
 
 /* 
@@ -127,11 +158,46 @@
 	u64 buffer;
 };
 
+struct viosrp_fast_fail {
+	struct mad_common common;
+};
+
+struct viosrp_capabilities {
+	struct mad_common common;
+	u64 buffer;
+};
+
+struct mad_capability_common {
+	u32 cap_type;
+	u16 length;
+	u16 server_support;
+};
+
+struct mad_reserve_cap {
+	struct mad_capability_common common;
+	u32 type;
+};
+
+struct mad_migration_cap {
+	struct mad_capability_common common;
+	u32 ecl;
+};
+
+struct capabilities{
+	u32 flags;
+	char name[SRP_MAX_LOC_LEN];
+	char loc[SRP_MAX_LOC_LEN];
+	struct mad_migration_cap migration;
+	struct mad_reserve_cap reserve;
+};
+
 union mad_iu {
 	struct viosrp_empty_iu empty_iu;
 	struct viosrp_error_log error_log;
 	struct viosrp_adapter_info adapter_info;
 	struct viosrp_host_config host_config;
+	struct viosrp_fast_fail fast_fail;
+	struct viosrp_capabilities capabilities;
 };
 
 union viosrp_iu {
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index dd689de..0f8bc77 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -7003,6 +7003,7 @@
 		ioa_cfg->sdt_state = ABORT_DUMP;
 	ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES;
 	ioa_cfg->in_ioa_bringdown = 1;
+	ioa_cfg->allow_cmds = 0;
 	ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 }
@@ -7688,7 +7689,7 @@
  * Return value:
  * 	none
  **/
-static void ipr_remove(struct pci_dev *pdev)
+static void __devexit ipr_remove(struct pci_dev *pdev)
 {
 	struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
 
@@ -7864,7 +7865,7 @@
 	.name = IPR_NAME,
 	.id_table = ipr_pci_table,
 	.probe = ipr_probe,
-	.remove = ipr_remove,
+	.remove = __devexit_p(ipr_remove),
 	.shutdown = ipr_shutdown,
 	.err_handler = &ipr_err_handler,
 };
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 992af05..7af9bce 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -1159,6 +1159,10 @@
 		atomic_inc(&mp->stats.xid_not_found);
 		goto out;
 	}
+	if (ep->esb_stat & ESB_ST_COMPLETE) {
+		atomic_inc(&mp->stats.xid_not_found);
+		goto out;
+	}
 	if (ep->rxid == FC_XID_UNKNOWN)
 		ep->rxid = ntohs(fh->fh_rx_id);
 	if (ep->sid != 0 && ep->sid != ntoh24(fh->fh_d_id)) {
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index 521f996..ad8b747 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -1896,7 +1896,7 @@
 		sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status;
 		break;
 	case FC_CMD_ABORTED:
-		sc_cmd->result = (DID_ABORT << 16) | fsp->io_status;
+		sc_cmd->result = (DID_ERROR << 16) | fsp->io_status;
 		break;
 	case FC_CMD_TIME_OUT:
 		sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status;
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 747d73c..7bfbff7 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -478,7 +478,7 @@
 	if (PTR_ERR(fp) == -FC_EX_CLOSED)
 		return fc_rport_error(rport, fp);
 
-	if (rdata->retries < rdata->local_port->max_retry_count) {
+	if (rdata->retries < rdata->local_port->max_rport_retry_count) {
 		FC_DEBUG_RPORT("Error %ld in state %s, retrying\n",
 			       PTR_ERR(fp), fc_rport_state(rport));
 		rdata->retries++;
@@ -1330,7 +1330,7 @@
 }
 EXPORT_SYMBOL(fc_rport_init);
 
-int fc_setup_rport()
+int fc_setup_rport(void)
 {
 	rport_event_queue = create_singlethread_workqueue("fc_rport_eq");
 	if (!rport_event_queue)
@@ -1339,7 +1339,7 @@
 }
 EXPORT_SYMBOL(fc_setup_rport);
 
-void fc_destroy_rport()
+void fc_destroy_rport(void)
 {
 	destroy_workqueue(rport_event_queue);
 }
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index e72b4ad..59908ae 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -81,7 +81,8 @@
 	struct Scsi_Host *shost = conn->session->host;
 	struct iscsi_host *ihost = shost_priv(shost);
 
-	queue_work(ihost->workq, &conn->xmitwork);
+	if (ihost->workq)
+		queue_work(ihost->workq, &conn->xmitwork);
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_queue_work);
 
@@ -109,11 +110,9 @@
 		 * if the window closed with IO queued, then kick the
 		 * xmit thread
 		 */
-		if (!list_empty(&session->leadconn->xmitqueue) ||
-		    !list_empty(&session->leadconn->mgmtqueue)) {
-			if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD))
-				iscsi_conn_queue_work(session->leadconn);
-		}
+		if (!list_empty(&session->leadconn->cmdqueue) ||
+		    !list_empty(&session->leadconn->mgmtqueue))
+			iscsi_conn_queue_work(session->leadconn);
 	}
 }
 EXPORT_SYMBOL_GPL(iscsi_update_cmdsn);
@@ -257,9 +256,11 @@
 	itt_t itt;
 	int rc;
 
-	rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD);
-	if (rc)
-		return rc;
+	if (conn->session->tt->alloc_pdu) {
+		rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD);
+		if (rc)
+			return rc;
+	}
 	hdr = (struct iscsi_cmd *) task->hdr;
 	itt = hdr->itt;
 	memset(hdr, 0, sizeof(*hdr));
@@ -364,7 +365,6 @@
 		return -EIO;
 
 	task->state = ISCSI_TASK_RUNNING;
-	list_move_tail(&task->running, &conn->run_list);
 
 	conn->scsicmd_pdus_cnt++;
 	ISCSI_DBG_SESSION(session, "iscsi prep [%s cid %d sc %p cdb 0x%x "
@@ -380,26 +380,25 @@
 }
 
 /**
- * iscsi_complete_command - finish a task
+ * iscsi_free_task - free a task
  * @task: iscsi cmd task
  *
  * Must be called with session lock.
  * This function returns the scsi command to scsi-ml or cleans
  * up mgmt tasks then returns the task to the pool.
  */
-static void iscsi_complete_command(struct iscsi_task *task)
+static void iscsi_free_task(struct iscsi_task *task)
 {
 	struct iscsi_conn *conn = task->conn;
 	struct iscsi_session *session = conn->session;
 	struct scsi_cmnd *sc = task->sc;
 
-	session->tt->cleanup_task(task);
-	list_del_init(&task->running);
-	task->state = ISCSI_TASK_COMPLETED;
-	task->sc = NULL;
+	ISCSI_DBG_SESSION(session, "freeing task itt 0x%x state %d sc %p\n",
+			  task->itt, task->state, task->sc);
 
-	if (conn->task == task)
-		conn->task = NULL;
+	session->tt->cleanup_task(task);
+	task->state = ISCSI_TASK_FREE;
+	task->sc = NULL;
 	/*
 	 * login task is preallocated so do not free
 	 */
@@ -408,9 +407,6 @@
 
 	__kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*));
 
-	if (conn->ping_task == task)
-		conn->ping_task = NULL;
-
 	if (sc) {
 		task->sc = NULL;
 		/* SCSI eh reuses commands to verify us */
@@ -433,7 +429,7 @@
 static void __iscsi_put_task(struct iscsi_task *task)
 {
 	if (atomic_dec_and_test(&task->refcount))
-		iscsi_complete_command(task);
+		iscsi_free_task(task);
 }
 
 void iscsi_put_task(struct iscsi_task *task)
@@ -446,26 +442,74 @@
 }
 EXPORT_SYMBOL_GPL(iscsi_put_task);
 
-/*
- * session lock must be held
+/**
+ * iscsi_complete_task - finish a task
+ * @task: iscsi cmd task
+ * @state: state to complete task with
+ *
+ * Must be called with session lock.
  */
-static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
-			 int err)
+static void iscsi_complete_task(struct iscsi_task *task, int state)
 {
-	struct scsi_cmnd *sc;
+	struct iscsi_conn *conn = task->conn;
 
+	ISCSI_DBG_SESSION(conn->session,
+			  "complete task itt 0x%x state %d sc %p\n",
+			  task->itt, task->state, task->sc);
+	if (task->state == ISCSI_TASK_COMPLETED ||
+	    task->state == ISCSI_TASK_ABRT_TMF ||
+	    task->state == ISCSI_TASK_ABRT_SESS_RECOV)
+		return;
+	WARN_ON_ONCE(task->state == ISCSI_TASK_FREE);
+	task->state = state;
+
+	if (!list_empty(&task->running))
+		list_del_init(&task->running);
+
+	if (conn->task == task)
+		conn->task = NULL;
+
+	if (conn->ping_task == task)
+		conn->ping_task = NULL;
+
+	/* release get from queueing */
+	__iscsi_put_task(task);
+}
+
+/*
+ * session lock must be held and if not called for a task that is
+ * still pending or from the xmit thread, then xmit thread must
+ * be suspended.
+ */
+static void fail_scsi_task(struct iscsi_task *task, int err)
+{
+	struct iscsi_conn *conn = task->conn;
+	struct scsi_cmnd *sc;
+	int state;
+
+	/*
+	 * if a command completes and we get a successful tmf response
+	 * we will hit this because the scsi eh abort code does not take
+	 * a ref to the task.
+	 */
 	sc = task->sc;
 	if (!sc)
 		return;
 
-	if (task->state == ISCSI_TASK_PENDING)
+	if (task->state == ISCSI_TASK_PENDING) {
 		/*
 		 * cmd never made it to the xmit thread, so we should not count
 		 * the cmd in the sequencing
 		 */
 		conn->session->queued_cmdsn--;
+		/* it was never sent so just complete like normal */
+		state = ISCSI_TASK_COMPLETED;
+	} else if (err == DID_TRANSPORT_DISRUPTED)
+		state = ISCSI_TASK_ABRT_SESS_RECOV;
+	else
+		state = ISCSI_TASK_ABRT_TMF;
 
-	sc->result = err;
+	sc->result = err << 16;
 	if (!scsi_bidi_cmnd(sc))
 		scsi_set_resid(sc, scsi_bufflen(sc));
 	else {
@@ -473,10 +517,7 @@
 		scsi_in(sc)->resid = scsi_in(sc)->length;
 	}
 
-	if (conn->task == task)
-		conn->task = NULL;
-	/* release ref from queuecommand */
-	__iscsi_put_task(task);
+	iscsi_complete_task(task, state);
 }
 
 static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
@@ -516,7 +557,6 @@
 		session->state = ISCSI_STATE_LOGGING_OUT;
 
 	task->state = ISCSI_TASK_RUNNING;
-	list_move_tail(&task->running, &conn->mgmt_run_list);
 	ISCSI_DBG_SESSION(session, "mgmtpdu [op 0x%x hdr->itt 0x%x "
 			  "datalen %d]\n", hdr->opcode & ISCSI_OPCODE_MASK,
 			  hdr->itt, task->data_count);
@@ -528,6 +568,7 @@
 		      char *data, uint32_t data_size)
 {
 	struct iscsi_session *session = conn->session;
+	struct iscsi_host *ihost = shost_priv(session->host);
 	struct iscsi_task *task;
 	itt_t itt;
 
@@ -544,6 +585,9 @@
 		 */
 		task = conn->login_task;
 	else {
+		if (session->state != ISCSI_STATE_LOGGED_IN)
+			return NULL;
+
 		BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
 		BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
 
@@ -559,6 +603,8 @@
 	atomic_set(&task->refcount, 1);
 	task->conn = conn;
 	task->sc = NULL;
+	INIT_LIST_HEAD(&task->running);
+	task->state = ISCSI_TASK_PENDING;
 
 	if (data_size) {
 		memcpy(task->data, data, data_size);
@@ -566,11 +612,14 @@
 	} else
 		task->data_count = 0;
 
-	if (conn->session->tt->alloc_pdu(task, hdr->opcode)) {
-		iscsi_conn_printk(KERN_ERR, conn, "Could not allocate "
-				 "pdu for mgmt task.\n");
-		goto requeue_task;
+	if (conn->session->tt->alloc_pdu) {
+		if (conn->session->tt->alloc_pdu(task, hdr->opcode)) {
+			iscsi_conn_printk(KERN_ERR, conn, "Could not allocate "
+					 "pdu for mgmt task.\n");
+			goto free_task;
+		}
 	}
+
 	itt = task->hdr->itt;
 	task->hdr_len = sizeof(struct iscsi_hdr);
 	memcpy(task->hdr, hdr, sizeof(struct iscsi_hdr));
@@ -583,30 +632,22 @@
 						   task->conn->session->age);
 	}
 
-	INIT_LIST_HEAD(&task->running);
-	list_add_tail(&task->running, &conn->mgmtqueue);
-
-	if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
+	if (!ihost->workq) {
 		if (iscsi_prep_mgmt_task(conn, task))
 			goto free_task;
 
 		if (session->tt->xmit_task(task))
 			goto free_task;
-
-	} else
+	} else {
+		list_add_tail(&task->running, &conn->mgmtqueue);
 		iscsi_conn_queue_work(conn);
+	}
 
 	return task;
 
 free_task:
 	__iscsi_put_task(task);
 	return NULL;
-
-requeue_task:
-	if (task != conn->login_task)
-		__kfifo_put(session->cmdpool.queue, (void*)&task,
-			    sizeof(void*));
-	return NULL;
 }
 
 int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
@@ -701,11 +742,10 @@
 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
 	}
 out:
-	ISCSI_DBG_SESSION(session, "done [sc %p res %d itt 0x%x]\n",
+	ISCSI_DBG_SESSION(session, "cmd rsp done [sc %p res %d itt 0x%x]\n",
 			  sc, sc->result, task->itt);
 	conn->scsirsp_pdus_cnt++;
-
-	__iscsi_put_task(task);
+	iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
 }
 
 /**
@@ -724,6 +764,7 @@
 	if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS))
 		return;
 
+	iscsi_update_cmdsn(conn->session, (struct iscsi_nopin *)hdr);
 	sc->result = (DID_OK << 16) | rhdr->cmd_status;
 	conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
 	if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
@@ -738,8 +779,11 @@
 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
 	}
 
+	ISCSI_DBG_SESSION(conn->session, "data in with status done "
+			  "[sc %p res %d itt 0x%x]\n",
+			  sc, sc->result, task->itt);
 	conn->scsirsp_pdus_cnt++;
-	__iscsi_put_task(task);
+	iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
 }
 
 static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
@@ -823,7 +867,7 @@
  *
  * The session lock must be held.
  */
-static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
+struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
 {
 	struct iscsi_session *session = conn->session;
 	int i;
@@ -840,6 +884,7 @@
 
 	return session->cmds[i];
 }
+EXPORT_SYMBOL_GPL(iscsi_itt_to_task);
 
 /**
  * __iscsi_complete_pdu - complete pdu
@@ -959,7 +1004,7 @@
 		}
 
 		iscsi_tmf_rsp(conn, hdr);
-		__iscsi_put_task(task);
+		iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
 		break;
 	case ISCSI_OP_NOOP_IN:
 		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
@@ -977,7 +1022,7 @@
 			goto recv_pdu;
 
 		mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout);
-		__iscsi_put_task(task);
+		iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
 		break;
 	default:
 		rc = ISCSI_ERR_BAD_OPCODE;
@@ -989,7 +1034,7 @@
 recv_pdu:
 	if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
 		rc = ISCSI_ERR_CONN_FAILED;
-	__iscsi_put_task(task);
+	iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
@@ -1166,7 +1211,12 @@
 {
 	struct iscsi_conn *conn = task->conn;
 
-	list_move_tail(&task->running, &conn->requeue);
+	/*
+	 * this may be on the requeue list already if the xmit_task callout
+	 * is handling the r2ts while we are adding new ones
+	 */
+	if (list_empty(&task->running))
+		list_add_tail(&task->running, &conn->requeue);
 	iscsi_conn_queue_work(conn);
 }
 EXPORT_SYMBOL_GPL(iscsi_requeue_task);
@@ -1206,6 +1256,7 @@
 	while (!list_empty(&conn->mgmtqueue)) {
 		conn->task = list_entry(conn->mgmtqueue.next,
 					 struct iscsi_task, running);
+		list_del_init(&conn->task->running);
 		if (iscsi_prep_mgmt_task(conn, conn->task)) {
 			__iscsi_put_task(conn->task);
 			conn->task = NULL;
@@ -1217,23 +1268,26 @@
 	}
 
 	/* process pending command queue */
-	while (!list_empty(&conn->xmitqueue)) {
+	while (!list_empty(&conn->cmdqueue)) {
 		if (conn->tmf_state == TMF_QUEUED)
 			break;
 
-		conn->task = list_entry(conn->xmitqueue.next,
+		conn->task = list_entry(conn->cmdqueue.next,
 					 struct iscsi_task, running);
+		list_del_init(&conn->task->running);
 		if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
-			fail_command(conn, conn->task, DID_IMM_RETRY << 16);
+			fail_scsi_task(conn->task, DID_IMM_RETRY);
 			continue;
 		}
 		rc = iscsi_prep_scsi_cmd_pdu(conn->task);
 		if (rc) {
 			if (rc == -ENOMEM) {
+				list_add_tail(&conn->task->running,
+					      &conn->cmdqueue);
 				conn->task = NULL;
 				goto again;
 			} else
-				fail_command(conn, conn->task, DID_ABORT << 16);
+				fail_scsi_task(conn->task, DID_ABORT);
 			continue;
 		}
 		rc = iscsi_xmit_task(conn);
@@ -1260,8 +1314,8 @@
 
 		conn->task = list_entry(conn->requeue.next,
 					 struct iscsi_task, running);
+		list_del_init(&conn->task->running);
 		conn->task->state = ISCSI_TASK_RUNNING;
-		list_move_tail(conn->requeue.next, &conn->run_list);
 		rc = iscsi_xmit_task(conn);
 		if (rc)
 			goto again;
@@ -1328,6 +1382,7 @@
 {
 	struct iscsi_cls_session *cls_session;
 	struct Scsi_Host *host;
+	struct iscsi_host *ihost;
 	int reason = 0;
 	struct iscsi_session *session;
 	struct iscsi_conn *conn;
@@ -1338,6 +1393,7 @@
 	sc->SCp.ptr = NULL;
 
 	host = sc->device->host;
+	ihost = shost_priv(host);
 	spin_unlock(host->host_lock);
 
 	cls_session = starget_to_session(scsi_target(sc->device));
@@ -1350,13 +1406,7 @@
 		goto fault;
 	}
 
-	/*
-	 * ISCSI_STATE_FAILED is a temp. state. The recovery
-	 * code will decide what is best to do with command queued
-	 * during this time
-	 */
-	if (session->state != ISCSI_STATE_LOGGED_IN &&
-	    session->state != ISCSI_STATE_FAILED) {
+	if (session->state != ISCSI_STATE_LOGGED_IN) {
 		/*
 		 * to handle the race between when we set the recovery state
 		 * and block the session we requeue here (commands could
@@ -1364,12 +1414,15 @@
 		 * up because the block code is not locked)
 		 */
 		switch (session->state) {
+		case ISCSI_STATE_FAILED:
 		case ISCSI_STATE_IN_RECOVERY:
 			reason = FAILURE_SESSION_IN_RECOVERY;
-			goto reject;
+			sc->result = DID_IMM_RETRY << 16;
+			break;
 		case ISCSI_STATE_LOGGING_OUT:
 			reason = FAILURE_SESSION_LOGGING_OUT;
-			goto reject;
+			sc->result = DID_IMM_RETRY << 16;
+			break;
 		case ISCSI_STATE_RECOVERY_FAILED:
 			reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
 			sc->result = DID_TRANSPORT_FAILFAST << 16;
@@ -1402,9 +1455,8 @@
 		reason = FAILURE_OOM;
 		goto reject;
 	}
-	list_add_tail(&task->running, &conn->xmitqueue);
 
-	if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
+	if (!ihost->workq) {
 		reason = iscsi_prep_scsi_cmd_pdu(task);
 		if (reason) {
 			if (reason == -ENOMEM) {
@@ -1419,8 +1471,10 @@
 			reason = FAILURE_SESSION_NOT_READY;
 			goto prepd_reject;
 		}
-	} else
+	} else {
+		list_add_tail(&task->running, &conn->cmdqueue);
 		iscsi_conn_queue_work(conn);
+	}
 
 	session->queued_cmdsn++;
 	spin_unlock(&session->lock);
@@ -1429,7 +1483,7 @@
 
 prepd_reject:
 	sc->scsi_done = NULL;
-	iscsi_complete_command(task);
+	iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
 reject:
 	spin_unlock(&session->lock);
 	ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
@@ -1439,7 +1493,7 @@
 
 prepd_fault:
 	sc->scsi_done = NULL;
-	iscsi_complete_command(task);
+	iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
 fault:
 	spin_unlock(&session->lock);
 	ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
@@ -1608,44 +1662,24 @@
  * Fail commands. session lock held and recv side suspended and xmit
  * thread flushed
  */
-static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
-			      int error)
+static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun,
+			    int error)
 {
-	struct iscsi_task *task, *tmp;
+	struct iscsi_task *task;
+	int i;
 
-	if (conn->task) {
-		if (lun == -1 ||
-		    (conn->task->sc && conn->task->sc->device->lun == lun))
-			conn->task = NULL;
-	}
+	for (i = 0; i < conn->session->cmds_max; i++) {
+		task = conn->session->cmds[i];
+		if (!task->sc || task->state == ISCSI_TASK_FREE)
+			continue;
 
-	/* flush pending */
-	list_for_each_entry_safe(task, tmp, &conn->xmitqueue, running) {
-		if (lun == task->sc->device->lun || lun == -1) {
-			ISCSI_DBG_SESSION(conn->session,
-					  "failing pending sc %p itt 0x%x\n",
-					  task->sc, task->itt);
-			fail_command(conn, task, error << 16);
-		}
-	}
+		if (lun != -1 && lun != task->sc->device->lun)
+			continue;
 
-	list_for_each_entry_safe(task, tmp, &conn->requeue, running) {
-		if (lun == task->sc->device->lun || lun == -1) {
-			ISCSI_DBG_SESSION(conn->session,
-					  "failing requeued sc %p itt 0x%x\n",
-					  task->sc, task->itt);
-			fail_command(conn, task, error << 16);
-		}
-	}
-
-	/* fail all other running */
-	list_for_each_entry_safe(task, tmp, &conn->run_list, running) {
-		if (lun == task->sc->device->lun || lun == -1) {
-			ISCSI_DBG_SESSION(conn->session,
-					 "failing in progress sc %p itt 0x%x\n",
-					 task->sc, task->itt);
-			fail_command(conn, task, error << 16);
-		}
+		ISCSI_DBG_SESSION(conn->session,
+				  "failing sc %p itt 0x%x state %d\n",
+				  task->sc, task->itt, task->state);
+		fail_scsi_task(task, error);
 	}
 }
 
@@ -1655,7 +1689,7 @@
 	struct iscsi_host *ihost = shost_priv(shost);
 
 	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-	if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
+	if (ihost->workq)
 		flush_workqueue(ihost->workq);
 }
 EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
@@ -1663,8 +1697,23 @@
 static void iscsi_start_tx(struct iscsi_conn *conn)
 {
 	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-	if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
-		iscsi_conn_queue_work(conn);
+	iscsi_conn_queue_work(conn);
+}
+
+/*
+ * We want to make sure a ping is in flight. It has timed out.
+ * And we are not busy processing a pdu that is making
+ * progress but got started before the ping and is taking a while
+ * to complete so the ping is just stuck behind it in a queue.
+ */
+static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
+{
+	if (conn->ping_task &&
+	    time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
+			   (conn->ping_timeout * HZ), jiffies))
+		return 1;
+	else
+		return 0;
 }
 
 static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
@@ -1702,16 +1751,20 @@
 	 * if the ping timedout then we are in the middle of cleaning up
 	 * and can let the iscsi eh handle it
 	 */
-	if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
-			    (conn->ping_timeout * HZ), jiffies))
+	if (iscsi_has_ping_timed_out(conn)) {
 		rc = BLK_EH_RESET_TIMER;
+		goto done;
+	}
 	/*
 	 * if we are about to check the transport then give the command
 	 * more time
 	 */
 	if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ),
-			   jiffies))
+			   jiffies)) {
 		rc = BLK_EH_RESET_TIMER;
+		goto done;
+	}
+
 	/* if in the middle of checking the transport then give us more time */
 	if (conn->ping_task)
 		rc = BLK_EH_RESET_TIMER;
@@ -1738,13 +1791,13 @@
 
 	recv_timeout *= HZ;
 	last_recv = conn->last_recv;
-	if (conn->ping_task &&
-	    time_before_eq(conn->last_ping + (conn->ping_timeout * HZ),
-			   jiffies)) {
+
+	if (iscsi_has_ping_timed_out(conn)) {
 		iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs "
-				  "expired, last rx %lu, last ping %lu, "
-				  "now %lu\n", conn->ping_timeout, last_recv,
-				  conn->last_ping, jiffies);
+				  "expired, recv timeout %d, last rx %lu, "
+				  "last ping %lu, now %lu\n",
+				  conn->ping_timeout, conn->recv_timeout,
+				  last_recv, conn->last_ping, jiffies);
 		spin_unlock(&session->lock);
 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
 		return;
@@ -1788,6 +1841,8 @@
 	cls_session = starget_to_session(scsi_target(sc->device));
 	session = cls_session->dd_data;
 
+	ISCSI_DBG_SESSION(session, "aborting sc %p\n", sc);
+
 	mutex_lock(&session->eh_mutex);
 	spin_lock_bh(&session->lock);
 	/*
@@ -1810,6 +1865,8 @@
 	    sc->SCp.phase != session->age) {
 		spin_unlock_bh(&session->lock);
 		mutex_unlock(&session->eh_mutex);
+		ISCSI_DBG_SESSION(session, "failing abort due to dropped "
+				  "session.\n");
 		return FAILED;
 	}
 
@@ -1829,7 +1886,7 @@
 	}
 
 	if (task->state == ISCSI_TASK_PENDING) {
-		fail_command(conn, task, DID_ABORT << 16);
+		fail_scsi_task(task, DID_ABORT);
 		goto success;
 	}
 
@@ -1860,7 +1917,7 @@
 		 * then sent more data for the cmd.
 		 */
 		spin_lock(&session->lock);
-		fail_command(conn, task, DID_ABORT << 16);
+		fail_scsi_task(task, DID_ABORT);
 		conn->tmf_state = TMF_INITIAL;
 		spin_unlock(&session->lock);
 		iscsi_start_tx(conn);
@@ -1967,7 +2024,7 @@
 	iscsi_suspend_tx(conn);
 
 	spin_lock_bh(&session->lock);
-	fail_all_commands(conn, sc->device->lun, DID_ERROR);
+	fail_scsi_tasks(conn, sc->device->lun, DID_ERROR);
 	conn->tmf_state = TMF_INITIAL;
 	spin_unlock_bh(&session->lock);
 
@@ -2274,6 +2331,7 @@
 		if (cmd_task_size)
 			task->dd_data = &task[1];
 		task->itt = cmd_i;
+		task->state = ISCSI_TASK_FREE;
 		INIT_LIST_HEAD(&task->running);
 	}
 
@@ -2360,10 +2418,8 @@
 	conn->transport_timer.data = (unsigned long)conn;
 	conn->transport_timer.function = iscsi_check_transport_timeouts;
 
-	INIT_LIST_HEAD(&conn->run_list);
-	INIT_LIST_HEAD(&conn->mgmt_run_list);
 	INIT_LIST_HEAD(&conn->mgmtqueue);
-	INIT_LIST_HEAD(&conn->xmitqueue);
+	INIT_LIST_HEAD(&conn->cmdqueue);
 	INIT_LIST_HEAD(&conn->requeue);
 	INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
 
@@ -2531,27 +2587,28 @@
 EXPORT_SYMBOL_GPL(iscsi_conn_start);
 
 static void
-flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
+fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn)
 {
-	struct iscsi_task *task, *tmp;
+	struct iscsi_task *task;
+	int i, state;
 
-	/* handle pending */
-	list_for_each_entry_safe(task, tmp, &conn->mgmtqueue, running) {
-		ISCSI_DBG_SESSION(session, "flushing pending mgmt task "
-				  "itt 0x%x\n", task->itt);
-		/* release ref from prep task */
-		__iscsi_put_task(task);
+	for (i = 0; i < conn->session->cmds_max; i++) {
+		task = conn->session->cmds[i];
+		if (task->sc)
+			continue;
+
+		if (task->state == ISCSI_TASK_FREE)
+			continue;
+
+		ISCSI_DBG_SESSION(conn->session,
+				  "failing mgmt itt 0x%x state %d\n",
+				  task->itt, task->state);
+		state = ISCSI_TASK_ABRT_SESS_RECOV;
+		if (task->state == ISCSI_TASK_PENDING)
+			state = ISCSI_TASK_COMPLETED;
+		iscsi_complete_task(task, state);
+
 	}
-
-	/* handle running */
-	list_for_each_entry_safe(task, tmp, &conn->mgmt_run_list, running) {
-		ISCSI_DBG_SESSION(session, "flushing running mgmt task "
-				  "itt 0x%x\n", task->itt);
-		/* release ref from prep task */
-		__iscsi_put_task(task);
-	}
-
-	conn->task = NULL;
 }
 
 static void iscsi_start_session_recovery(struct iscsi_session *session,
@@ -2559,8 +2616,6 @@
 {
 	int old_stop_stage;
 
-	del_timer_sync(&conn->transport_timer);
-
 	mutex_lock(&session->eh_mutex);
 	spin_lock_bh(&session->lock);
 	if (conn->stop_stage == STOP_CONN_TERM) {
@@ -2578,13 +2633,17 @@
 		session->state = ISCSI_STATE_TERMINATE;
 	else if (conn->stop_stage != STOP_CONN_RECOVER)
 		session->state = ISCSI_STATE_IN_RECOVERY;
+	spin_unlock_bh(&session->lock);
 
+	del_timer_sync(&conn->transport_timer);
+	iscsi_suspend_tx(conn);
+
+	spin_lock_bh(&session->lock);
 	old_stop_stage = conn->stop_stage;
 	conn->stop_stage = flag;
 	conn->c_stage = ISCSI_CONN_STOPPED;
 	spin_unlock_bh(&session->lock);
 
-	iscsi_suspend_tx(conn);
 	/*
 	 * for connection level recovery we should not calculate
 	 * header digest. conn->hdr_size used for optimization
@@ -2605,11 +2664,8 @@
 	 * flush queues.
 	 */
 	spin_lock_bh(&session->lock);
-	if (flag == STOP_CONN_RECOVER)
-		fail_all_commands(conn, -1, DID_TRANSPORT_DISRUPTED);
-	else
-		fail_all_commands(conn, -1, DID_ERROR);
-	flush_control_queues(session, conn);
+	fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED);
+	fail_mgmt_tasks(session, conn);
 	spin_unlock_bh(&session->lock);
 	mutex_unlock(&session->eh_mutex);
 }
@@ -2651,6 +2707,23 @@
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_bind);
 
+static int iscsi_switch_str_param(char **param, char *new_val_buf)
+{
+	char *new_val;
+
+	if (*param) {
+		if (!strcmp(*param, new_val_buf))
+			return 0;
+	}
+
+	new_val = kstrdup(new_val_buf, GFP_NOIO);
+	if (!new_val)
+		return -ENOMEM;
+
+	kfree(*param);
+	*param = new_val;
+	return 0;
+}
 
 int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
 		    enum iscsi_param param, char *buf, int buflen)
@@ -2723,38 +2796,15 @@
 		sscanf(buf, "%u", &conn->exp_statsn);
 		break;
 	case ISCSI_PARAM_USERNAME:
-		kfree(session->username);
-		session->username = kstrdup(buf, GFP_KERNEL);
-		if (!session->username)
-			return -ENOMEM;
-		break;
+		return iscsi_switch_str_param(&session->username, buf);
 	case ISCSI_PARAM_USERNAME_IN:
-		kfree(session->username_in);
-		session->username_in = kstrdup(buf, GFP_KERNEL);
-		if (!session->username_in)
-			return -ENOMEM;
-		break;
+		return iscsi_switch_str_param(&session->username_in, buf);
 	case ISCSI_PARAM_PASSWORD:
-		kfree(session->password);
-		session->password = kstrdup(buf, GFP_KERNEL);
-		if (!session->password)
-			return -ENOMEM;
-		break;
+		return iscsi_switch_str_param(&session->password, buf);
 	case ISCSI_PARAM_PASSWORD_IN:
-		kfree(session->password_in);
-		session->password_in = kstrdup(buf, GFP_KERNEL);
-		if (!session->password_in)
-			return -ENOMEM;
-		break;
+		return iscsi_switch_str_param(&session->password_in, buf);
 	case ISCSI_PARAM_TARGET_NAME:
-		/* this should not change between logins */
-		if (session->targetname)
-			break;
-
-		session->targetname = kstrdup(buf, GFP_KERNEL);
-		if (!session->targetname)
-			return -ENOMEM;
-		break;
+		return iscsi_switch_str_param(&session->targetname, buf);
 	case ISCSI_PARAM_TPGT:
 		sscanf(buf, "%d", &session->tpgt);
 		break;
@@ -2762,25 +2812,11 @@
 		sscanf(buf, "%d", &conn->persistent_port);
 		break;
 	case ISCSI_PARAM_PERSISTENT_ADDRESS:
-		/*
-		 * this is the address returned in discovery so it should
-		 * not change between logins.
-		 */
-		if (conn->persistent_address)
-			break;
-
-		conn->persistent_address = kstrdup(buf, GFP_KERNEL);
-		if (!conn->persistent_address)
-			return -ENOMEM;
-		break;
+		return iscsi_switch_str_param(&conn->persistent_address, buf);
 	case ISCSI_PARAM_IFACE_NAME:
-		if (!session->ifacename)
-			session->ifacename = kstrdup(buf, GFP_KERNEL);
-		break;
+		return iscsi_switch_str_param(&session->ifacename, buf);
 	case ISCSI_PARAM_INITIATOR_NAME:
-		if (!session->initiatorname)
-			session->initiatorname = kstrdup(buf, GFP_KERNEL);
-		break;
+		return iscsi_switch_str_param(&session->initiatorname, buf);
 	default:
 		return -ENOSYS;
 	}
@@ -2851,10 +2887,7 @@
 		len = sprintf(buf, "%s\n", session->ifacename);
 		break;
 	case ISCSI_PARAM_INITIATOR_NAME:
-		if (!session->initiatorname)
-			len = sprintf(buf, "%s\n", "unknown");
-		else
-			len = sprintf(buf, "%s\n", session->initiatorname);
+		len = sprintf(buf, "%s\n", session->initiatorname);
 		break;
 	default:
 		return -ENOSYS;
@@ -2920,29 +2953,16 @@
 
 	switch (param) {
 	case ISCSI_HOST_PARAM_NETDEV_NAME:
-		if (!ihost->netdev)
-			len = sprintf(buf, "%s\n", "default");
-		else
-			len = sprintf(buf, "%s\n", ihost->netdev);
+		len = sprintf(buf, "%s\n", ihost->netdev);
 		break;
 	case ISCSI_HOST_PARAM_HWADDRESS:
-		if (!ihost->hwaddress)
-			len = sprintf(buf, "%s\n", "default");
-		else
-			len = sprintf(buf, "%s\n", ihost->hwaddress);
+		len = sprintf(buf, "%s\n", ihost->hwaddress);
 		break;
 	case ISCSI_HOST_PARAM_INITIATOR_NAME:
-		if (!ihost->initiatorname)
-			len = sprintf(buf, "%s\n", "unknown");
-		else
-			len = sprintf(buf, "%s\n", ihost->initiatorname);
+		len = sprintf(buf, "%s\n", ihost->initiatorname);
 		break;
 	case ISCSI_HOST_PARAM_IPADDRESS:
-		if (!strlen(ihost->local_address))
-			len = sprintf(buf, "%s\n", "unknown");
-		else
-			len = sprintf(buf, "%s\n",
-				      ihost->local_address);
+		len = sprintf(buf, "%s\n", ihost->local_address);
 		break;
 	default:
 		return -ENOSYS;
@@ -2959,17 +2979,11 @@
 
 	switch (param) {
 	case ISCSI_HOST_PARAM_NETDEV_NAME:
-		if (!ihost->netdev)
-			ihost->netdev = kstrdup(buf, GFP_KERNEL);
-		break;
+		return iscsi_switch_str_param(&ihost->netdev, buf);
 	case ISCSI_HOST_PARAM_HWADDRESS:
-		if (!ihost->hwaddress)
-			ihost->hwaddress = kstrdup(buf, GFP_KERNEL);
-		break;
+		return iscsi_switch_str_param(&ihost->hwaddress, buf);
 	case ISCSI_HOST_PARAM_INITIATOR_NAME:
-		if (!ihost->initiatorname)
-			ihost->initiatorname = kstrdup(buf, GFP_KERNEL);
-		break;
+		return iscsi_switch_str_param(&ihost->initiatorname, buf);
 	default:
 		return -ENOSYS;
 	}
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index b579ca9..2bc0709 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -440,8 +440,8 @@
 	struct iscsi_tcp_task *tcp_task = task->dd_data;
 	struct iscsi_r2t_info *r2t;
 
-	/* nothing to do for mgmt or pending tasks */
-	if (!task->sc || task->state == ISCSI_TASK_PENDING)
+	/* nothing to do for mgmt */
+	if (!task->sc)
 		return;
 
 	/* flush task's r2t queues */
@@ -473,7 +473,13 @@
 	int datasn = be32_to_cpu(rhdr->datasn);
 	unsigned total_in_length = scsi_in(task->sc)->length;
 
-	iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
+	/*
+	 * lib iscsi will update this in the completion handling if there
+	 * is status.
+	 */
+	if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS))
+		iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
+
 	if (tcp_conn->in.datalen == 0)
 		return 0;
 
@@ -857,6 +863,12 @@
 	int rc = 0;
 
 	ISCSI_DBG_TCP(conn, "in %d bytes\n", skb->len - offset);
+	/*
+	 * Update for each skb instead of pdu, because over slow networks a
+	 * data_in's data could take a while to read in. We also want to
+	 * account for r2ts.
+	 */
+	conn->last_recv = jiffies;
 
 	if (unlikely(conn->suspend_rx)) {
 		ISCSI_DBG_TCP(conn, "Rx suspended!\n");
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 1105f9a..5405698 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-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -23,6 +23,13 @@
 
 struct lpfc_sli2_slim;
 
+#define LPFC_PCI_DEV_LP		0x1
+#define LPFC_PCI_DEV_OC		0x2
+
+#define LPFC_SLI_REV2		2
+#define LPFC_SLI_REV3		3
+#define LPFC_SLI_REV4		4
+
 #define LPFC_MAX_TARGET		4096	/* max number of targets supported */
 #define LPFC_MAX_DISC_THREADS	64	/* max outstanding discovery els
 					   requests */
@@ -98,9 +105,11 @@
 };
 
 struct hbq_dmabuf {
+	struct lpfc_dmabuf hbuf;
 	struct lpfc_dmabuf dbuf;
 	uint32_t size;
 	uint32_t tag;
+	struct lpfc_rcqe rcqe;
 };
 
 /* Priority bit.  Set value to exceed low water mark in lpfc_mem. */
@@ -134,7 +143,10 @@
 	} rev;
 	struct {
 #ifdef __BIG_ENDIAN_BITFIELD
-		uint32_t rsvd2  :24;  /* Reserved                             */
+		uint32_t rsvd3  :19;  /* Reserved                             */
+		uint32_t cdss	: 1;  /* Configure Data Security SLI          */
+		uint32_t rsvd2	: 3;  /* Reserved                             */
+		uint32_t cbg	: 1;  /* Configure BlockGuard                 */
 		uint32_t cmv	: 1;  /* Configure Max VPIs                   */
 		uint32_t ccrp   : 1;  /* Config Command Ring Polling          */
 		uint32_t csah   : 1;  /* Configure Synchronous Abort Handling */
@@ -152,7 +164,10 @@
 		uint32_t csah   : 1;  /* Configure Synchronous Abort Handling */
 		uint32_t ccrp   : 1;  /* Config Command Ring Polling          */
 		uint32_t cmv	: 1;  /* Configure Max VPIs                   */
-		uint32_t rsvd2  :24;  /* Reserved                             */
+		uint32_t cbg	: 1;  /* Configure BlockGuard                 */
+		uint32_t rsvd2	: 3;  /* Reserved                             */
+		uint32_t cdss	: 1;  /* Configure Data Security SLI          */
+		uint32_t rsvd3  :19;  /* Reserved                             */
 #endif
 	} sli3Feat;
 } lpfc_vpd_t;
@@ -264,8 +279,8 @@
 };
 
 struct lpfc_vport {
-	struct list_head listentry;
 	struct lpfc_hba *phba;
+	struct list_head listentry;
 	uint8_t port_type;
 #define LPFC_PHYSICAL_PORT 1
 #define LPFC_NPIV_PORT  2
@@ -273,6 +288,9 @@
 	enum discovery_state port_state;
 
 	uint16_t vpi;
+	uint16_t vfi;
+	uint8_t vfi_state;
+#define LPFC_VFI_REGISTERED	0x1
 
 	uint32_t fc_flag;	/* FC flags */
 /* Several of these flags are HBA centric and should be moved to
@@ -385,6 +403,9 @@
 #endif
 	uint8_t stat_data_enabled;
 	uint8_t stat_data_blocked;
+	struct list_head rcv_buffer_list;
+	uint32_t vport_flag;
+#define STATIC_VPORT	1
 };
 
 struct hbq_s {
@@ -420,8 +441,66 @@
 };
 
 struct lpfc_hba {
+	/* SCSI interface function jump table entries */
+	int (*lpfc_new_scsi_buf)
+		(struct lpfc_vport *, int);
+	struct lpfc_scsi_buf * (*lpfc_get_scsi_buf)
+		(struct lpfc_hba *);
+	int (*lpfc_scsi_prep_dma_buf)
+		(struct lpfc_hba *, struct lpfc_scsi_buf *);
+	void (*lpfc_scsi_unprep_dma_buf)
+		(struct lpfc_hba *, struct lpfc_scsi_buf *);
+	void (*lpfc_release_scsi_buf)
+		(struct lpfc_hba *, struct lpfc_scsi_buf *);
+	void (*lpfc_rampdown_queue_depth)
+		(struct lpfc_hba *);
+	void (*lpfc_scsi_prep_cmnd)
+		(struct lpfc_vport *, struct lpfc_scsi_buf *,
+		 struct lpfc_nodelist *);
+	int (*lpfc_scsi_prep_task_mgmt_cmd)
+		(struct lpfc_vport *, struct lpfc_scsi_buf *,
+		 unsigned int, uint8_t);
+
+	/* IOCB interface function jump table entries */
+	int (*__lpfc_sli_issue_iocb)
+		(struct lpfc_hba *, uint32_t,
+		 struct lpfc_iocbq *, uint32_t);
+	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)
+		(struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *);
+
+	/* 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 *);
+	int (*lpfc_sli_brdrestart)
+		(struct lpfc_hba *);
+	int (*lpfc_sli_brdready)
+		(struct lpfc_hba *, uint32_t);
+	void (*lpfc_handle_eratt)
+		(struct lpfc_hba *);
+	void (*lpfc_stop_port)
+		(struct lpfc_hba *);
+
+
+	/* SLI4 specific HBA data structure */
+	struct lpfc_sli4_hba sli4_hba;
+
 	struct lpfc_sli sli;
-	uint32_t sli_rev;		/* SLI2 or SLI3 */
+	uint8_t pci_dev_grp;	/* lpfc PCI dev group: 0x0, 0x1, 0x2,... */
+	uint32_t sli_rev;		/* SLI2, SLI3, or SLI4 */
 	uint32_t sli3_options;		/* Mask of enabled SLI3 options */
 #define LPFC_SLI3_HBQ_ENABLED		0x01
 #define LPFC_SLI3_NPIV_ENABLED		0x02
@@ -429,6 +508,7 @@
 #define LPFC_SLI3_CRP_ENABLED		0x08
 #define LPFC_SLI3_INB_ENABLED		0x10
 #define LPFC_SLI3_BG_ENABLED		0x20
+#define LPFC_SLI3_DSS_ENABLED		0x40
 	uint32_t iocb_cmd_size;
 	uint32_t iocb_rsp_size;
 
@@ -442,8 +522,13 @@
 
 	uint32_t hba_flag;	/* hba generic flags */
 #define HBA_ERATT_HANDLED	0x1 /* This flag is set when eratt handled */
-
-#define DEFER_ERATT		0x4 /* Deferred error attention in progress */
+#define DEFER_ERATT		0x2 /* Deferred error attention in progress */
+#define HBA_FCOE_SUPPORT	0x4 /* HBA function supports FCOE */
+#define HBA_RECEIVE_BUFFER	0x8 /* Rcv buffer posted to worker thread */
+#define HBA_POST_RECEIVE_BUFFER 0x10 /* Rcv buffers need to be posted */
+#define FCP_XRI_ABORT_EVENT	0x20
+#define ELS_XRI_ABORT_EVENT	0x40
+#define ASYNC_EVENT		0x80
 	struct lpfc_dmabuf slim2p;
 
 	MAILBOX_t *mbox;
@@ -502,6 +587,9 @@
 	uint32_t cfg_poll;
 	uint32_t cfg_poll_tmo;
 	uint32_t cfg_use_msi;
+	uint32_t cfg_fcp_imax;
+	uint32_t cfg_fcp_wq_count;
+	uint32_t cfg_fcp_eq_count;
 	uint32_t cfg_sg_seg_cnt;
 	uint32_t cfg_prot_sg_seg_cnt;
 	uint32_t cfg_sg_dma_buf_size;
@@ -511,6 +599,8 @@
 	uint32_t cfg_enable_hba_reset;
 	uint32_t cfg_enable_hba_heartbeat;
 	uint32_t cfg_enable_bg;
+	uint32_t cfg_enable_fip;
+	uint32_t cfg_log_verbose;
 
 	lpfc_vpd_t vpd;		/* vital product data */
 
@@ -526,11 +616,12 @@
 	unsigned long data_flags;
 
 	uint32_t hbq_in_use;		/* HBQs in use flag */
-	struct list_head hbqbuf_in_list;  /* in-fly hbq buffer list */
+	struct list_head rb_pend_list;  /* Received buffers to be processed */
 	uint32_t hbq_count;	        /* Count of configured HBQs */
 	struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies  */
 
 	unsigned long pci_bar0_map;     /* Physical address for PCI BAR0 */
+	unsigned long pci_bar1_map;     /* Physical address for PCI BAR1 */
 	unsigned long pci_bar2_map;     /* Physical address for PCI BAR2 */
 	void __iomem *slim_memmap_p;	/* Kernel memory mapped address for
 					   PCI BAR0 */
@@ -593,7 +684,8 @@
 	/* pci_mem_pools */
 	struct pci_pool *lpfc_scsi_dma_buf_pool;
 	struct pci_pool *lpfc_mbuf_pool;
-	struct pci_pool *lpfc_hbq_pool;
+	struct pci_pool *lpfc_hrb_pool;	/* header receive buffer pool */
+	struct pci_pool *lpfc_drb_pool; /* data receive buffer pool */
 	struct lpfc_dma_pool lpfc_mbuf_safety_pool;
 
 	mempool_t *mbox_mem_pool;
@@ -609,6 +701,14 @@
 	struct lpfc_vport *pport;	/* physical lpfc_vport pointer */
 	uint16_t max_vpi;		/* Maximum virtual nports */
 #define LPFC_MAX_VPI 0xFFFF		/* Max number of VPI supported */
+	uint16_t max_vports;            /*
+					 * For IOV HBAs max_vpi can change
+					 * after a reset. max_vports is max
+					 * number of vports present. This can
+					 * be greater than max_vpi.
+					 */
+	uint16_t vpi_base;
+	uint16_t vfi_base;
 	unsigned long *vpi_bmask;	/* vpi allocation table */
 
 	/* Data structure used by fabric iocb scheduler */
@@ -667,6 +767,11 @@
 /* Maximum number of events that can be outstanding at any time*/
 #define LPFC_MAX_EVT_COUNT 512
 	atomic_t fast_event_count;
+	struct lpfc_fcf fcf;
+	uint8_t fc_map[3];
+	uint8_t valid_vlan;
+	uint16_t vlan_id;
+	struct list_head fcf_conn_rec_list;
 };
 
 static inline struct Scsi_Host *
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index c14f0cb..d73e677 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-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -30,8 +30,10 @@
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -505,12 +507,14 @@
 		return -ENOMEM;
 
 	memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
-	pmboxq->mb.mbxCommand = MBX_DOWN_LINK;
-	pmboxq->mb.mbxOwner = OWN_HOST;
+	pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK;
+	pmboxq->u.mb.mbxOwner = OWN_HOST;
 
 	mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2);
 
-	if ((mbxstatus == MBX_SUCCESS) && (pmboxq->mb.mbxStatus == 0)) {
+	if ((mbxstatus == MBX_SUCCESS) &&
+	    (pmboxq->u.mb.mbxStatus == 0 ||
+	     pmboxq->u.mb.mbxStatus == MBXERR_LINK_DOWN)) {
 		memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
 		lpfc_init_link(phba, pmboxq, phba->cfg_topology,
 			       phba->cfg_link_speed);
@@ -789,7 +793,8 @@
 		  uint32_t *mrpi, uint32_t *arpi,
 		  uint32_t *mvpi, uint32_t *avpi)
 {
-	struct lpfc_sli   *psli = &phba->sli;
+	struct lpfc_sli *psli = &phba->sli;
+	struct lpfc_mbx_read_config *rd_config;
 	LPFC_MBOXQ_t *pmboxq;
 	MAILBOX_t *pmb;
 	int rc = 0;
@@ -800,7 +805,7 @@
 	 */
 	if (phba->link_state < LPFC_LINK_DOWN ||
 	    !phba->mbox_mem_pool ||
-	    (phba->sli.sli_flag & LPFC_SLI2_ACTIVE) == 0)
+	    (phba->sli.sli_flag & LPFC_SLI_ACTIVE) == 0)
 		return 0;
 
 	if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)
@@ -811,13 +816,13 @@
 		return 0;
 	memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t));
 
-	pmb = &pmboxq->mb;
+	pmb = &pmboxq->u.mb;
 	pmb->mbxCommand = MBX_READ_CONFIG;
 	pmb->mbxOwner = OWN_HOST;
 	pmboxq->context1 = NULL;
 
 	if ((phba->pport->fc_flag & FC_OFFLINE_MODE) ||
-		(!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+		(!(psli->sli_flag & LPFC_SLI_ACTIVE)))
 		rc = MBX_NOT_FINISHED;
 	else
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -828,18 +833,37 @@
 		return 0;
 	}
 
-	if (mrpi)
-		*mrpi = pmb->un.varRdConfig.max_rpi;
-	if (arpi)
-		*arpi = pmb->un.varRdConfig.avail_rpi;
-	if (mxri)
-		*mxri = pmb->un.varRdConfig.max_xri;
-	if (axri)
-		*axri = pmb->un.varRdConfig.avail_xri;
-	if (mvpi)
-		*mvpi = pmb->un.varRdConfig.max_vpi;
-	if (avpi)
-		*avpi = pmb->un.varRdConfig.avail_vpi;
+	if (phba->sli_rev == LPFC_SLI_REV4) {
+		rd_config = &pmboxq->u.mqe.un.rd_config;
+		if (mrpi)
+			*mrpi = bf_get(lpfc_mbx_rd_conf_rpi_count, rd_config);
+		if (arpi)
+			*arpi = bf_get(lpfc_mbx_rd_conf_rpi_count, rd_config) -
+					phba->sli4_hba.max_cfg_param.rpi_used;
+		if (mxri)
+			*mxri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config);
+		if (axri)
+			*axri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config) -
+					phba->sli4_hba.max_cfg_param.xri_used;
+		if (mvpi)
+			*mvpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config);
+		if (avpi)
+			*avpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) -
+					phba->sli4_hba.max_cfg_param.vpi_used;
+	} else {
+		if (mrpi)
+			*mrpi = pmb->un.varRdConfig.max_rpi;
+		if (arpi)
+			*arpi = pmb->un.varRdConfig.avail_rpi;
+		if (mxri)
+			*mxri = pmb->un.varRdConfig.max_xri;
+		if (axri)
+			*axri = pmb->un.varRdConfig.avail_xri;
+		if (mvpi)
+			*mvpi = pmb->un.varRdConfig.max_vpi;
+		if (avpi)
+			*avpi = pmb->un.varRdConfig.avail_vpi;
+	}
 
 	mempool_free(pmboxq, phba->mbox_mem_pool);
 	return 1;
@@ -2021,22 +2045,9 @@
 # lpfc_log_verbose: Only turn this flag on if you are willing to risk being
 # deluged with LOTS of information.
 # You can set a bit mask to record specific types of verbose messages:
-#
-# LOG_ELS                       0x1        ELS events
-# LOG_DISCOVERY                 0x2        Link discovery events
-# LOG_MBOX                      0x4        Mailbox events
-# LOG_INIT                      0x8        Initialization events
-# LOG_LINK_EVENT                0x10       Link events
-# LOG_FCP                       0x40       FCP traffic history
-# LOG_NODE                      0x80       Node table events
-# LOG_BG                        0x200      BlockBuard events
-# LOG_MISC                      0x400      Miscellaneous events
-# LOG_SLI                       0x800      SLI events
-# LOG_FCP_ERROR                 0x1000     Only log FCP errors
-# LOG_LIBDFC                    0x2000     LIBDFC events
-# LOG_ALL_MSG                   0xffff     LOG all messages
+# See lpfc_logmsh.h for definitions.
 */
-LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffff,
+LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffffffff,
 		       "Verbose logging bit-mask");
 
 /*
@@ -2266,6 +2277,36 @@
 static DEVICE_ATTR(lpfc_topology, S_IRUGO | S_IWUSR,
 		lpfc_topology_show, lpfc_topology_store);
 
+/**
+ * lpfc_static_vport_show: Read callback function for
+ *   lpfc_static_vport sysfs file.
+ * @dev: Pointer to class device object.
+ * @attr: device attribute structure.
+ * @buf: Data buffer.
+ *
+ * This function is the read call back function for
+ * lpfc_static_vport sysfs file. The lpfc_static_vport
+ * sysfs file report the mageability of the vport.
+ **/
+static ssize_t
+lpfc_static_vport_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct Scsi_Host  *shost = class_to_shost(dev);
+	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+	if (vport->vport_flag & STATIC_VPORT)
+		sprintf(buf, "1\n");
+	else
+		sprintf(buf, "0\n");
+
+	return strlen(buf);
+}
+
+/*
+ * Sysfs attribute to control the statistical data collection.
+ */
+static DEVICE_ATTR(lpfc_static_vport, S_IRUGO,
+		   lpfc_static_vport_show, NULL);
 
 /**
  * lpfc_stat_data_ctrl_store - write call back for lpfc_stat_data_ctrl sysfs file
@@ -2341,7 +2382,7 @@
 		if (vports == NULL)
 			return -ENOMEM;
 
-		for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
 			v_shost = lpfc_shost_from_vport(vports[i]);
 			spin_lock_irq(v_shost->host_lock);
 			/* Block and reset data collection */
@@ -2356,7 +2397,7 @@
 		phba->bucket_base = base;
 		phba->bucket_step = step;
 
-		for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
 			v_shost = lpfc_shost_from_vport(vports[i]);
 
 			/* Unblock data collection */
@@ -2373,7 +2414,7 @@
 		if (vports == NULL)
 			return -ENOMEM;
 
-		for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
 			v_shost = lpfc_shost_from_vport(vports[i]);
 			spin_lock_irq(shost->host_lock);
 			vports[i]->stat_data_blocked = 1;
@@ -2844,15 +2885,39 @@
 /*
 # lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that
 #		support this feature
-#       0  = MSI disabled
+#       0  = MSI disabled (default)
 #       1  = MSI enabled
-#       2  = MSI-X enabled (default)
-# Value range is [0,2]. Default value is 2.
+#       2  = MSI-X enabled
+# Value range is [0,2]. Default value is 0.
 */
-LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or "
+LPFC_ATTR_R(use_msi, 0, 0, 2, "Use Message Signaled Interrupts (1) or "
 	    "MSI-X (2), if possible");
 
 /*
+# lpfc_fcp_imax: Set the maximum number of fast-path FCP interrupts per second
+#
+# Value range is [636,651042]. Default value is 10000.
+*/
+LPFC_ATTR_R(fcp_imax, LPFC_FP_DEF_IMAX, LPFC_MIM_IMAX, LPFC_DMULT_CONST,
+	    "Set the maximum number of fast-path FCP interrupts per second");
+
+/*
+# lpfc_fcp_wq_count: Set the number of fast-path FCP work queues
+#
+# Value range is [1,31]. Default value is 4.
+*/
+LPFC_ATTR_R(fcp_wq_count, LPFC_FP_WQN_DEF, LPFC_FP_WQN_MIN, LPFC_FP_WQN_MAX,
+	    "Set the number of fast-path FCP work queues, if possible");
+
+/*
+# lpfc_fcp_eq_count: Set the number of fast-path FCP event queues
+#
+# Value range is [1,7]. Default value is 1.
+*/
+LPFC_ATTR_R(fcp_eq_count, LPFC_FP_EQN_DEF, LPFC_FP_EQN_MIN, LPFC_FP_EQN_MAX,
+	    "Set the number of fast-path FCP event queues, if possible");
+
+/*
 # lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware.
 #       0  = HBA resets disabled
 #       1  = HBA resets enabled (default)
@@ -2876,6 +2941,14 @@
 */
 LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support");
 
+/*
+# lpfc_enable_fip: When set, FIP is required to start discovery. If not
+# set, the driver will add an FCF record manually if the port has no
+# FCF records available and start discovery.
+# Value range is [0,1]. Default value is 1 (enabled)
+*/
+LPFC_ATTR_RW(enable_fip, 0, 0, 1, "Enable FIP Discovery");
+
 
 /*
 # lpfc_prot_mask: i
@@ -2942,6 +3015,7 @@
 	&dev_attr_lpfc_peer_port_login,
 	&dev_attr_lpfc_nodev_tmo,
 	&dev_attr_lpfc_devloss_tmo,
+	&dev_attr_lpfc_enable_fip,
 	&dev_attr_lpfc_fcp_class,
 	&dev_attr_lpfc_use_adisc,
 	&dev_attr_lpfc_ack0,
@@ -2969,6 +3043,9 @@
 	&dev_attr_lpfc_poll,
 	&dev_attr_lpfc_poll_tmo,
 	&dev_attr_lpfc_use_msi,
+	&dev_attr_lpfc_fcp_imax,
+	&dev_attr_lpfc_fcp_wq_count,
+	&dev_attr_lpfc_fcp_eq_count,
 	&dev_attr_lpfc_enable_bg,
 	&dev_attr_lpfc_soft_wwnn,
 	&dev_attr_lpfc_soft_wwpn,
@@ -2991,6 +3068,7 @@
 	&dev_attr_lpfc_lun_queue_depth,
 	&dev_attr_lpfc_nodev_tmo,
 	&dev_attr_lpfc_devloss_tmo,
+	&dev_attr_lpfc_enable_fip,
 	&dev_attr_lpfc_hba_queue_depth,
 	&dev_attr_lpfc_peer_port_login,
 	&dev_attr_lpfc_restrict_login,
@@ -3003,6 +3081,7 @@
 	&dev_attr_lpfc_enable_da_id,
 	&dev_attr_lpfc_max_scsicmpl_time,
 	&dev_attr_lpfc_stat_data_ctrl,
+	&dev_attr_lpfc_static_vport,
 	NULL,
 };
 
@@ -3199,7 +3278,7 @@
 		}
 	}
 
-	memcpy((uint8_t *) & phba->sysfs_mbox.mbox->mb + off,
+	memcpy((uint8_t *) &phba->sysfs_mbox.mbox->u.mb + off,
 	       buf, count);
 
 	phba->sysfs_mbox.offset = off + count;
@@ -3241,6 +3320,7 @@
 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 	struct lpfc_hba   *phba = vport->phba;
 	int rc;
+	MAILBOX_t *pmb;
 
 	if (off > MAILBOX_CMD_SIZE)
 		return -ERANGE;
@@ -3265,8 +3345,8 @@
 	if (off == 0 &&
 	    phba->sysfs_mbox.state  == SMBOX_WRITING &&
 	    phba->sysfs_mbox.offset >= 2 * sizeof(uint32_t)) {
-
-		switch (phba->sysfs_mbox.mbox->mb.mbxCommand) {
+		pmb = &phba->sysfs_mbox.mbox->u.mb;
+		switch (pmb->mbxCommand) {
 			/* Offline only */
 		case MBX_INIT_LINK:
 		case MBX_DOWN_LINK:
@@ -3283,7 +3363,7 @@
 			if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
 				printk(KERN_WARNING "mbox_read:Command 0x%x "
 				       "is illegal in on-line state\n",
-				       phba->sysfs_mbox.mbox->mb.mbxCommand);
+				       pmb->mbxCommand);
 				sysfs_mbox_idle(phba);
 				spin_unlock_irq(&phba->hbalock);
 				return -EPERM;
@@ -3319,13 +3399,13 @@
 		case MBX_CONFIG_PORT:
 		case MBX_RUN_BIU_DIAG:
 			printk(KERN_WARNING "mbox_read: Illegal Command 0x%x\n",
-			       phba->sysfs_mbox.mbox->mb.mbxCommand);
+			       pmb->mbxCommand);
 			sysfs_mbox_idle(phba);
 			spin_unlock_irq(&phba->hbalock);
 			return -EPERM;
 		default:
 			printk(KERN_WARNING "mbox_read: Unknown Command 0x%x\n",
-			       phba->sysfs_mbox.mbox->mb.mbxCommand);
+			       pmb->mbxCommand);
 			sysfs_mbox_idle(phba);
 			spin_unlock_irq(&phba->hbalock);
 			return -EPERM;
@@ -3335,14 +3415,14 @@
 		 * or RESTART mailbox commands until the HBA is restarted.
 		 */
 		if (phba->pport->stopped &&
-		    phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_DUMP_MEMORY &&
-		    phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_RESTART &&
-		    phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_WRITE_VPARMS &&
-		    phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_WRITE_WWN)
+		    pmb->mbxCommand != MBX_DUMP_MEMORY &&
+		    pmb->mbxCommand != MBX_RESTART &&
+		    pmb->mbxCommand != MBX_WRITE_VPARMS &&
+		    pmb->mbxCommand != MBX_WRITE_WWN)
 			lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
 					"1259 mbox: Issued mailbox cmd "
 					"0x%x while in stopped state.\n",
-					phba->sysfs_mbox.mbox->mb.mbxCommand);
+					pmb->mbxCommand);
 
 		phba->sysfs_mbox.mbox->vport = vport;
 
@@ -3356,7 +3436,7 @@
 		}
 
 		if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-		    (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE))){
+		    (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) {
 
 			spin_unlock_irq(&phba->hbalock);
 			rc = lpfc_sli_issue_mbox (phba,
@@ -3368,8 +3448,7 @@
 			spin_unlock_irq(&phba->hbalock);
 			rc = lpfc_sli_issue_mbox_wait (phba,
 						       phba->sysfs_mbox.mbox,
-				lpfc_mbox_tmo_val(phba,
-				    phba->sysfs_mbox.mbox->mb.mbxCommand) * HZ);
+				lpfc_mbox_tmo_val(phba, pmb->mbxCommand) * HZ);
 			spin_lock_irq(&phba->hbalock);
 		}
 
@@ -3391,7 +3470,7 @@
 		return -EAGAIN;
 	}
 
-	memcpy(buf, (uint8_t *) & phba->sysfs_mbox.mbox->mb + off, count);
+	memcpy(buf, (uint8_t *) &pmb + off, count);
 
 	phba->sysfs_mbox.offset = off + count;
 
@@ -3585,6 +3664,9 @@
 			case LA_8GHZ_LINK:
 				fc_host_speed(shost) = FC_PORTSPEED_8GBIT;
 			break;
+			case LA_10GHZ_LINK:
+				fc_host_speed(shost) = FC_PORTSPEED_10GBIT;
+			break;
 			default:
 				fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
 			break;
@@ -3652,7 +3734,7 @@
 	 */
 	if (phba->link_state < LPFC_LINK_DOWN ||
 	    !phba->mbox_mem_pool ||
-	    (phba->sli.sli_flag & LPFC_SLI2_ACTIVE) == 0)
+	    (phba->sli.sli_flag & LPFC_SLI_ACTIVE) == 0)
 		return NULL;
 
 	if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)
@@ -3663,14 +3745,14 @@
 		return NULL;
 	memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t));
 
-	pmb = &pmboxq->mb;
+	pmb = &pmboxq->u.mb;
 	pmb->mbxCommand = MBX_READ_STATUS;
 	pmb->mbxOwner = OWN_HOST;
 	pmboxq->context1 = NULL;
 	pmboxq->vport = vport;
 
 	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-		(!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+		(!(psli->sli_flag & LPFC_SLI_ACTIVE)))
 		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
 	else
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -3695,7 +3777,7 @@
 	pmboxq->vport = vport;
 
 	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-	    (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+	    (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
 		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
 	else
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -3769,7 +3851,7 @@
 		return;
 	memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
 
-	pmb = &pmboxq->mb;
+	pmb = &pmboxq->u.mb;
 	pmb->mbxCommand = MBX_READ_STATUS;
 	pmb->mbxOwner = OWN_HOST;
 	pmb->un.varWords[0] = 0x1; /* reset request */
@@ -3777,7 +3859,7 @@
 	pmboxq->vport = vport;
 
 	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-		(!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+		(!(psli->sli_flag & LPFC_SLI_ACTIVE)))
 		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
 	else
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -3795,7 +3877,7 @@
 	pmboxq->vport = vport;
 
 	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-	    (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+	    (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
 		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
 	else
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -3962,6 +4044,21 @@
 		lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0);
 }
 
+/**
+ * lpfc_hba_log_verbose_init - Set hba's log verbose level
+ * @phba: Pointer to lpfc_hba struct.
+ *
+ * This function is called by the lpfc_get_cfgparam() routine to set the
+ * module lpfc_log_verbose into the @phba cfg_log_verbose for use with
+ * log messsage according to the module's lpfc_log_verbose parameter setting
+ * before hba port or vport created.
+ **/
+static void
+lpfc_hba_log_verbose_init(struct lpfc_hba *phba, uint32_t verbose)
+{
+	phba->cfg_log_verbose = verbose;
+}
+
 struct fc_function_template lpfc_transport_functions = {
 	/* fixed attributes the driver supports */
 	.show_host_node_name = 1,
@@ -4105,6 +4202,9 @@
 	lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
 	lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
 	lpfc_use_msi_init(phba, lpfc_use_msi);
+	lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
+	lpfc_fcp_wq_count_init(phba, lpfc_fcp_wq_count);
+	lpfc_fcp_eq_count_init(phba, lpfc_fcp_eq_count);
 	lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
 	lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
 	lpfc_enable_bg_init(phba, lpfc_enable_bg);
@@ -4113,26 +4213,10 @@
 	phba->cfg_soft_wwpn = 0L;
 	lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
 	lpfc_prot_sg_seg_cnt_init(phba, lpfc_prot_sg_seg_cnt);
-	/*
-	 * Since the sg_tablesize is module parameter, the sg_dma_buf_size
-	 * used to create the sg_dma_buf_pool must be dynamically calculated.
-	 * 2 segments are added since the IOCB needs a command and response bde.
-	 */
-	phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
-			sizeof(struct fcp_rsp) +
-			((phba->cfg_sg_seg_cnt + 2) * sizeof(struct ulp_bde64));
-
-	if (phba->cfg_enable_bg) {
-		phba->cfg_sg_seg_cnt = LPFC_MAX_SG_SEG_CNT;
-		phba->cfg_sg_dma_buf_size +=
-			phba->cfg_prot_sg_seg_cnt * sizeof(struct ulp_bde64);
-	}
-
-	/* Also reinitialize the host templates with new values. */
-	lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt;
-	lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt;
-
 	lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
+	lpfc_enable_fip_init(phba, lpfc_enable_fip);
+	lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
+
 	return;
 }
 
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index f88ce3f..d2a9229 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -23,6 +23,8 @@
 struct fc_rport;
 void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
 void lpfc_dump_wakeup_param(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
+int lpfc_dump_fcoe_param(struct lpfc_hba *, struct lpfcMboxq *);
 void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
 
@@ -35,17 +37,19 @@
 int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *, int);
 void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_reg_login(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
-		   LPFC_MBOXQ_t *, uint32_t);
+int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
+		 LPFC_MBOXQ_t *, uint32_t);
 void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
 void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
-void lpfc_reg_vpi(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
+void lpfc_reg_vpi(struct lpfc_vport *, LPFC_MBOXQ_t *);
 void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *);
 void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
+void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *);
 
 struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
 void lpfc_cleanup_rpis(struct lpfc_vport *, int);
 int lpfc_linkdown(struct lpfc_hba *);
+void lpfc_linkdown_port(struct lpfc_vport *);
 void lpfc_port_link_failure(struct lpfc_vport *);
 void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
 
@@ -54,6 +58,7 @@
 void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_enqueue_node(struct lpfc_vport *, struct lpfc_nodelist *);
 void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *);
 struct lpfc_nodelist *lpfc_enable_node(struct lpfc_vport *,
@@ -105,6 +110,7 @@
 int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
 int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *);
 int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t);
+int lpfc_issue_fabric_reglogin(struct lpfc_vport *);
 int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
 int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
 int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
@@ -149,15 +155,19 @@
 void lpfc_unblock_mgmt_io(struct lpfc_hba *);
 void lpfc_offline_prep(struct lpfc_hba *);
 void lpfc_offline(struct lpfc_hba *);
+void lpfc_reset_hba(struct lpfc_hba *);
 
 int lpfc_sli_setup(struct lpfc_hba *);
 int lpfc_sli_queue_setup(struct lpfc_hba *);
 
 void lpfc_handle_eratt(struct lpfc_hba *);
 void lpfc_handle_latt(struct lpfc_hba *);
-irqreturn_t lpfc_intr_handler(int, void *);
-irqreturn_t lpfc_sp_intr_handler(int, void *);
-irqreturn_t lpfc_fp_intr_handler(int, void *);
+irqreturn_t lpfc_sli_intr_handler(int, void *);
+irqreturn_t lpfc_sli_sp_intr_handler(int, void *);
+irqreturn_t lpfc_sli_fp_intr_handler(int, void *);
+irqreturn_t lpfc_sli4_intr_handler(int, void *);
+irqreturn_t lpfc_sli4_sp_intr_handler(int, void *);
+irqreturn_t lpfc_sli4_fp_intr_handler(int, void *);
 
 void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
@@ -165,16 +175,32 @@
 void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
 LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
+void __lpfc_mbox_cmpl_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbox_cmpl_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_mbox_cmd_check(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_mbox_dev_check(struct lpfc_hba *);
 int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
+void lpfc_init_vfi(struct lpfcMboxq *, struct lpfc_vport *);
+void lpfc_reg_vfi(struct lpfcMboxq *, struct lpfc_vport *, dma_addr_t);
+void lpfc_init_vpi(struct lpfcMboxq *, uint16_t);
+void lpfc_unreg_vfi(struct lpfcMboxq *, uint16_t);
+void lpfc_reg_fcfi(struct lpfc_hba *, struct lpfcMboxq *);
+void lpfc_unreg_fcfi(struct lpfcMboxq *, uint16_t);
+void lpfc_resume_rpi(struct lpfcMboxq *, struct lpfc_nodelist *);
 
 void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *,
 	uint32_t , LPFC_MBOXQ_t *);
 struct hbq_dmabuf *lpfc_els_hbq_alloc(struct lpfc_hba *);
 void lpfc_els_hbq_free(struct lpfc_hba *, struct hbq_dmabuf *);
+struct hbq_dmabuf *lpfc_sli4_rb_alloc(struct lpfc_hba *);
+void lpfc_sli4_rb_free(struct lpfc_hba *, struct hbq_dmabuf *);
+void lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *, struct fcf_record *,
+			uint16_t);
+void lpfc_unregister_unused_fcf(struct lpfc_hba *);
 
-int lpfc_mem_alloc(struct lpfc_hba *);
+int lpfc_mem_alloc(struct lpfc_hba *, int align);
 void lpfc_mem_free(struct lpfc_hba *);
+void lpfc_mem_free_all(struct lpfc_hba *);
 void lpfc_stop_vport_timers(struct lpfc_vport *);
 
 void lpfc_poll_timeout(unsigned long ptr);
@@ -186,6 +212,7 @@
 uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *);
 void lpfc_sli_cancel_iocbs(struct lpfc_hba *, struct list_head *, uint32_t,
 			   uint32_t);
+void lpfc_sli_wake_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *);
 
 void lpfc_reset_barrier(struct lpfc_hba * phba);
 int lpfc_sli_brdready(struct lpfc_hba *, uint32_t);
@@ -198,12 +225,13 @@
 int lpfc_sli_hba_down(struct lpfc_hba *);
 int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
 int lpfc_sli_handle_mb_event(struct lpfc_hba *);
-int lpfc_sli_flush_mbox_queue(struct lpfc_hba *);
+void lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *);
 int lpfc_sli_check_eratt(struct lpfc_hba *);
-int lpfc_sli_handle_slow_ring_event(struct lpfc_hba *,
+void lpfc_sli_handle_slow_ring_event(struct lpfc_hba *,
 				    struct lpfc_sli_ring *, uint32_t);
+int lpfc_sli4_handle_received_buffer(struct lpfc_hba *);
 void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_sli_issue_iocb(struct lpfc_hba *, struct lpfc_sli_ring *,
+int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
 			struct lpfc_iocbq *, uint32_t);
 void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t);
 void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *);
@@ -237,7 +265,7 @@
 
 int lpfc_sli_issue_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
 
-int lpfc_sli_issue_iocb_wait(struct lpfc_hba *, struct lpfc_sli_ring *,
+int lpfc_sli_issue_iocb_wait(struct lpfc_hba *, uint32_t,
 			     struct lpfc_iocbq *, struct lpfc_iocbq *,
 			     uint32_t);
 void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *, struct lpfc_iocbq *,
@@ -254,6 +282,12 @@
 const char* lpfc_info(struct Scsi_Host *);
 int lpfc_scan_finished(struct Scsi_Host *, unsigned long);
 
+int lpfc_init_api_table_setup(struct lpfc_hba *, uint8_t);
+int lpfc_sli_api_table_setup(struct lpfc_hba *, uint8_t);
+int lpfc_scsi_api_table_setup(struct lpfc_hba *, uint8_t);
+int lpfc_mbox_api_table_setup(struct lpfc_hba *, uint8_t);
+int lpfc_api_table_setup(struct lpfc_hba *, uint8_t);
+
 void lpfc_get_cfgparam(struct lpfc_hba *);
 void lpfc_get_vport_cfgparam(struct lpfc_vport *);
 int lpfc_alloc_sysfs_attr(struct lpfc_vport *);
@@ -314,8 +348,15 @@
 				struct lpfc_iocbq *);
 struct lpfc_fast_path_event *lpfc_alloc_fast_evt(struct lpfc_hba *);
 void lpfc_free_fast_evt(struct lpfc_hba *, struct lpfc_fast_path_event *);
+void lpfc_create_static_vport(struct lpfc_hba *);
+void lpfc_stop_hba_timers(struct lpfc_hba *);
+void lpfc_stop_port(struct lpfc_hba *);
+void lpfc_parse_fcoe_conf(struct lpfc_hba *, uint8_t *, uint32_t);
+int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int);
+void lpfc_start_fdiscs(struct lpfc_hba *phba);
 
 #define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
 #define HBA_EVENT_RSCN                   5
 #define HBA_EVENT_LINK_UP                2
 #define HBA_EVENT_LINK_DOWN              3
+
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 896c7b0..1dbccfd 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -32,8 +32,10 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -267,8 +269,6 @@
 	     uint32_t tmo, uint8_t retry)
 {
 	struct lpfc_hba  *phba = vport->phba;
-	struct lpfc_sli  *psli = &phba->sli;
-	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
 	IOCB_t *icmd;
 	struct lpfc_iocbq *geniocb;
 	int rc;
@@ -331,7 +331,7 @@
 	geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT;
 	geniocb->vport = vport;
 	geniocb->retry = retry;
-	rc = lpfc_sli_issue_iocb(phba, pring, geniocb, 0);
+	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, geniocb, 0);
 
 	if (rc == IOCB_ERROR) {
 		lpfc_sli_release_iocbq(phba, geniocb);
@@ -1578,6 +1578,9 @@
 				case LA_8GHZ_LINK:
 					ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
 				break;
+				case LA_10GHZ_LINK:
+					ae->un.PortSpeed = HBA_PORTSPEED_10GBIT;
+				break;
 				default:
 					ae->un.PortSpeed =
 						HBA_PORTSPEED_UNKNOWN;
@@ -1730,7 +1733,7 @@
 	uint8_t *fwname;
 
 	if (vp->rev.rBit) {
-		if (psli->sli_flag & LPFC_SLI2_ACTIVE)
+		if (psli->sli_flag & LPFC_SLI_ACTIVE)
 			rev = vp->rev.sli2FwRev;
 		else
 			rev = vp->rev.sli1FwRev;
@@ -1756,7 +1759,7 @@
 		}
 		b4 = (rev & 0x0000000f);
 
-		if (psli->sli_flag & LPFC_SLI2_ACTIVE)
+		if (psli->sli_flag & LPFC_SLI_ACTIVE)
 			fwname = vp->rev.sli2FwName;
 		else
 			fwname = vp->rev.sli1FwName;
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 52be564..2b02b1f 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-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2007-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -33,8 +33,10 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -280,6 +282,8 @@
 	struct lpfc_dmabuf *d_buf;
 	struct hbq_dmabuf *hbq_buf;
 
+	if (phba->sli_rev != 3)
+		return 0;
 	cnt = LPFC_HBQINFO_SIZE;
 	spin_lock_irq(&phba->hbalock);
 
@@ -489,12 +493,15 @@
 				 pring->next_cmdidx, pring->local_getidx,
 				 pring->flag, pgpp->rspPutInx, pring->numRiocb);
 	}
-	word0 = readl(phba->HAregaddr);
-	word1 = readl(phba->CAregaddr);
-	word2 = readl(phba->HSregaddr);
-	word3 = readl(phba->HCregaddr);
-	len +=  snprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x HC:%08x\n",
-	word0, word1, word2, word3);
+
+	if (phba->sli_rev <= LPFC_SLI_REV3) {
+		word0 = readl(phba->HAregaddr);
+		word1 = readl(phba->CAregaddr);
+		word2 = readl(phba->HSregaddr);
+		word3 = readl(phba->HCregaddr);
+		len +=  snprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x "
+				 "HC:%08x\n", word0, word1, word2, word3);
+	}
 	spin_unlock_irq(&phba->hbalock);
 	return len;
 }
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index ffd1089..1142070 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -135,6 +135,7 @@
 #define NLP_NODEV_REMOVE   0x08000000	/* Defer removal till discovery ends */
 #define NLP_TARGET_REMOVE  0x10000000   /* Target remove in process */
 #define NLP_SC_REQ         0x20000000	/* Target requires authentication */
+#define NLP_RPI_VALID      0x80000000	/* nlp_rpi is valid */
 
 /* ndlp usage management macros */
 #define NLP_CHK_NODE_ACT(ndlp)		(((ndlp)->nlp_usg_map \
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index b8b34cf..6bdeb14 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-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -28,8 +28,10 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -84,7 +86,8 @@
 	uint32_t ha_copy;
 
 	if (vport->port_state >= LPFC_VPORT_READY ||
-	    phba->link_state == LPFC_LINK_DOWN)
+	    phba->link_state == LPFC_LINK_DOWN ||
+	    phba->sli_rev > LPFC_SLI_REV3)
 		return 0;
 
 	/* Read the HBA Host Attention Register */
@@ -219,7 +222,7 @@
 		icmd->un.elsreq64.myID = vport->fc_myDID;
 
 		/* For ELS_REQUEST64_CR, use the VPI by default */
-		icmd->ulpContext = vport->vpi;
+		icmd->ulpContext = vport->vpi + phba->vpi_base;
 		icmd->ulpCt_h = 0;
 		/* The CT field must be 0=INVALID_RPI for the ECHO cmd */
 		if (elscmd == ELS_CMD_ECHO)
@@ -305,7 +308,7 @@
  *   0 - successfully issued fabric registration login for @vport
  *   -ENXIO -- failed to issue fabric registration login for @vport
  **/
-static int
+int
 lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
 {
 	struct lpfc_hba  *phba = vport->phba;
@@ -345,8 +348,7 @@
 		err = 4;
 		goto fail;
 	}
-	rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
-			    0);
+	rc = lpfc_reg_rpi(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox, 0);
 	if (rc) {
 		err = 5;
 		goto fail_free_mbox;
@@ -386,6 +388,75 @@
 }
 
 /**
+ * lpfc_issue_reg_vfi - Register VFI for this vport's fabric login
+ * @vport: pointer to a host virtual N_Port data structure.
+ *
+ * This routine issues a REG_VFI mailbox for the vfi, vpi, fcfi triplet for
+ * the @vport. This mailbox command is necessary for FCoE only.
+ *
+ * Return code
+ *   0 - successfully issued REG_VFI for @vport
+ *   A failure code otherwise.
+ **/
+static int
+lpfc_issue_reg_vfi(struct lpfc_vport *vport)
+{
+	struct lpfc_hba  *phba = vport->phba;
+	LPFC_MBOXQ_t *mboxq;
+	struct lpfc_nodelist *ndlp;
+	struct serv_parm *sp;
+	struct lpfc_dmabuf *dmabuf;
+	int rc = 0;
+
+	sp = &phba->fc_fabparam;
+	ndlp = lpfc_findnode_did(vport, Fabric_DID);
+	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
+		rc = -ENODEV;
+		goto fail;
+	}
+
+	dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+	if (!dmabuf) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+	dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
+	if (!dmabuf->virt) {
+		rc = -ENOMEM;
+		goto fail_free_dmabuf;
+	}
+	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mboxq) {
+		rc = -ENOMEM;
+		goto fail_free_coherent;
+	}
+	vport->port_state = LPFC_FABRIC_CFG_LINK;
+	memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam));
+	lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+	mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi;
+	mboxq->vport = vport;
+	mboxq->context1 = dmabuf;
+	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+	if (rc == MBX_NOT_FINISHED) {
+		rc = -ENXIO;
+		goto fail_free_mbox;
+	}
+	return 0;
+
+fail_free_mbox:
+	mempool_free(mboxq, phba->mbox_mem_pool);
+fail_free_coherent:
+	lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+fail_free_dmabuf:
+	kfree(dmabuf);
+fail:
+	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+		"0289 Issue Register VFI failed: Err %d\n", rc);
+	return rc;
+}
+
+/**
  * lpfc_cmpl_els_flogi_fabric - Completion function for flogi to a fabric port
  * @vport: pointer to a host virtual N_Port data structure.
  * @ndlp: pointer to a node-list data structure.
@@ -497,17 +568,24 @@
 		}
 	}
 
-	lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
-
-	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
-	    vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) {
-		lpfc_register_new_vport(phba, vport, ndlp);
-		return 0;
+	if (phba->sli_rev < LPFC_SLI_REV4) {
+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
+		if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
+		    vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
+			lpfc_register_new_vport(phba, vport, ndlp);
+		else
+			lpfc_issue_fabric_reglogin(vport);
+	} else {
+		ndlp->nlp_type |= NLP_FABRIC;
+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
+		if (vport->vfi_state & LPFC_VFI_REGISTERED) {
+			lpfc_start_fdiscs(phba);
+			lpfc_do_scr_ns_plogi(phba, vport);
+		} else
+			lpfc_issue_reg_vfi(vport);
 	}
-	lpfc_issue_fabric_reglogin(vport);
 	return 0;
 }
-
 /**
  * lpfc_cmpl_els_flogi_nport - Completion function for flogi to an N_Port
  * @vport: pointer to a host virtual N_Port data structure.
@@ -815,9 +893,14 @@
 	if (sp->cmn.fcphHigh < FC_PH3)
 		sp->cmn.fcphHigh = FC_PH3;
 
-	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+	if  (phba->sli_rev == LPFC_SLI_REV4) {
+		elsiocb->iocb.ulpCt_h = ((SLI4_CT_FCFI >> 1) & 1);
+		elsiocb->iocb.ulpCt_l = (SLI4_CT_FCFI & 1);
+		/* FLOGI needs to be 3 for WQE FCFI */
+		/* Set the fcfi to the fcfi we registered with */
+		elsiocb->iocb.ulpContext = phba->fcf.fcfi;
+	} else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
 		sp->cmn.request_multiple_Nport = 1;
-
 		/* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
 		icmd->ulpCt_h = 1;
 		icmd->ulpCt_l = 0;
@@ -930,6 +1013,8 @@
 		if (!ndlp)
 			return 0;
 		lpfc_nlp_init(vport, ndlp, Fabric_DID);
+		/* Set the node type */
+		ndlp->nlp_type |= NLP_FABRIC;
 		/* Put ndlp onto node list */
 		lpfc_enqueue_node(vport, ndlp);
 	} else if (!NLP_CHK_NODE_ACT(ndlp)) {
@@ -1350,14 +1435,12 @@
 	IOCB_t *icmd;
 	struct lpfc_nodelist *ndlp;
 	struct lpfc_iocbq *elsiocb;
-	struct lpfc_sli_ring *pring;
 	struct lpfc_sli *psli;
 	uint8_t *pcmd;
 	uint16_t cmdsize;
 	int ret;
 
 	psli = &phba->sli;
-	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
 
 	ndlp = lpfc_findnode_did(vport, did);
 	if (ndlp && !NLP_CHK_NODE_ACT(ndlp))
@@ -1391,7 +1474,7 @@
 
 	phba->fc_stat.elsXmitPLOGI++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi;
-	ret = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+	ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
 
 	if (ret == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
@@ -1501,14 +1584,9 @@
 	PRLI *npr;
 	IOCB_t *icmd;
 	struct lpfc_iocbq *elsiocb;
-	struct lpfc_sli_ring *pring;
-	struct lpfc_sli *psli;
 	uint8_t *pcmd;
 	uint16_t cmdsize;
 
-	psli = &phba->sli;
-	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
-
 	cmdsize = (sizeof(uint32_t) + sizeof(PRLI));
 	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
 				     ndlp->nlp_DID, ELS_CMD_PRLI);
@@ -1550,7 +1628,8 @@
 	spin_lock_irq(shost->host_lock);
 	ndlp->nlp_flag |= NLP_PRLI_SND;
 	spin_unlock_irq(shost->host_lock);
-	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+	if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) ==
+	    IOCB_ERROR) {
 		spin_lock_irq(shost->host_lock);
 		ndlp->nlp_flag &= ~NLP_PRLI_SND;
 		spin_unlock_irq(shost->host_lock);
@@ -1608,7 +1687,8 @@
 	 * and continue discovery.
 	 */
 	if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
-	    !(vport->fc_flag & FC_RSCN_MODE)) {
+	    !(vport->fc_flag & FC_RSCN_MODE) &&
+	    (phba->sli_rev < LPFC_SLI_REV4)) {
 		lpfc_issue_reg_vpi(phba, vport);
 		return;
 	}
@@ -1788,8 +1868,6 @@
 	ADISC *ap;
 	IOCB_t *icmd;
 	struct lpfc_iocbq *elsiocb;
-	struct lpfc_sli *psli = &phba->sli;
-	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
 	uint8_t *pcmd;
 	uint16_t cmdsize;
 
@@ -1822,7 +1900,8 @@
 	spin_lock_irq(shost->host_lock);
 	ndlp->nlp_flag |= NLP_ADISC_SND;
 	spin_unlock_irq(shost->host_lock);
-	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+	if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) ==
+	    IOCB_ERROR) {
 		spin_lock_irq(shost->host_lock);
 		ndlp->nlp_flag &= ~NLP_ADISC_SND;
 		spin_unlock_irq(shost->host_lock);
@@ -1937,15 +2016,10 @@
 	struct lpfc_hba  *phba = vport->phba;
 	IOCB_t *icmd;
 	struct lpfc_iocbq *elsiocb;
-	struct lpfc_sli_ring *pring;
-	struct lpfc_sli *psli;
 	uint8_t *pcmd;
 	uint16_t cmdsize;
 	int rc;
 
-	psli = &phba->sli;
-	pring = &psli->ring[LPFC_ELS_RING];
-
 	spin_lock_irq(shost->host_lock);
 	if (ndlp->nlp_flag & NLP_LOGO_SND) {
 		spin_unlock_irq(shost->host_lock);
@@ -1978,7 +2052,7 @@
 	spin_lock_irq(shost->host_lock);
 	ndlp->nlp_flag |= NLP_LOGO_SND;
 	spin_unlock_irq(shost->host_lock);
-	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
 
 	if (rc == IOCB_ERROR) {
 		spin_lock_irq(shost->host_lock);
@@ -2058,14 +2132,12 @@
 	struct lpfc_hba  *phba = vport->phba;
 	IOCB_t *icmd;
 	struct lpfc_iocbq *elsiocb;
-	struct lpfc_sli_ring *pring;
 	struct lpfc_sli *psli;
 	uint8_t *pcmd;
 	uint16_t cmdsize;
 	struct lpfc_nodelist *ndlp;
 
 	psli = &phba->sli;
-	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
 	cmdsize = (sizeof(uint32_t) + sizeof(SCR));
 
 	ndlp = lpfc_findnode_did(vport, nportid);
@@ -2108,7 +2180,8 @@
 
 	phba->fc_stat.elsXmitSCR++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
-	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+	if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) ==
+	    IOCB_ERROR) {
 		/* The additional lpfc_nlp_put will cause the following
 		 * lpfc_els_free_iocb routine to trigger the rlease of
 		 * the node.
@@ -2152,7 +2225,6 @@
 	struct lpfc_hba  *phba = vport->phba;
 	IOCB_t *icmd;
 	struct lpfc_iocbq *elsiocb;
-	struct lpfc_sli_ring *pring;
 	struct lpfc_sli *psli;
 	FARP *fp;
 	uint8_t *pcmd;
@@ -2162,7 +2234,6 @@
 	struct lpfc_nodelist *ndlp;
 
 	psli = &phba->sli;
-	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
 	cmdsize = (sizeof(uint32_t) + sizeof(FARP));
 
 	ndlp = lpfc_findnode_did(vport, nportid);
@@ -2219,7 +2290,8 @@
 
 	phba->fc_stat.elsXmitFARPR++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
-	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+	if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) ==
+	    IOCB_ERROR) {
 		/* The additional lpfc_nlp_put will cause the following
 		 * lpfc_els_free_iocb routine to trigger the release of
 		 * the node.
@@ -2949,6 +3021,14 @@
 	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
 
+	/*
+	 * This routine is used to register and unregister in previous SLI
+	 * modes.
+	 */
+	if ((pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) &&
+	    (phba->sli_rev == LPFC_SLI_REV4))
+		lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi);
+
 	pmb->context1 = NULL;
 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
 	kfree(mp);
@@ -2961,6 +3041,7 @@
 		 */
 		lpfc_nlp_not_used(ndlp);
 	}
+
 	return;
 }
 
@@ -3170,7 +3251,6 @@
 	IOCB_t *icmd;
 	IOCB_t *oldcmd;
 	struct lpfc_iocbq *elsiocb;
-	struct lpfc_sli_ring *pring;
 	struct lpfc_sli *psli;
 	uint8_t *pcmd;
 	uint16_t cmdsize;
@@ -3178,7 +3258,6 @@
 	ELS_PKT *els_pkt_ptr;
 
 	psli = &phba->sli;
-	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
 	oldcmd = &oldiocb->iocb;
 
 	switch (flag) {
@@ -3266,7 +3345,7 @@
 	}
 
 	phba->fc_stat.elsXmitACC++;
-	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
 	if (rc == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
 		return 1;
@@ -3305,15 +3384,12 @@
 	IOCB_t *icmd;
 	IOCB_t *oldcmd;
 	struct lpfc_iocbq *elsiocb;
-	struct lpfc_sli_ring *pring;
 	struct lpfc_sli *psli;
 	uint8_t *pcmd;
 	uint16_t cmdsize;
 	int rc;
 
 	psli = &phba->sli;
-	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
-
 	cmdsize = 2 * sizeof(uint32_t);
 	elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
 				     ndlp->nlp_DID, ELS_CMD_LS_RJT);
@@ -3346,7 +3422,7 @@
 
 	phba->fc_stat.elsXmitLSRJT++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
-	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
 
 	if (rc == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
@@ -3379,8 +3455,6 @@
 		       struct lpfc_nodelist *ndlp)
 {
 	struct lpfc_hba  *phba = vport->phba;
-	struct lpfc_sli  *psli = &phba->sli;
-	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
 	ADISC *ap;
 	IOCB_t *icmd, *oldcmd;
 	struct lpfc_iocbq *elsiocb;
@@ -3422,7 +3496,7 @@
 
 	phba->fc_stat.elsXmitACC++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
-	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
 	if (rc == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
 		return 1;
@@ -3459,14 +3533,12 @@
 	IOCB_t *icmd;
 	IOCB_t *oldcmd;
 	struct lpfc_iocbq *elsiocb;
-	struct lpfc_sli_ring *pring;
 	struct lpfc_sli *psli;
 	uint8_t *pcmd;
 	uint16_t cmdsize;
 	int rc;
 
 	psli = &phba->sli;
-	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
 
 	cmdsize = sizeof(uint32_t) + sizeof(PRLI);
 	elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
@@ -3520,7 +3592,7 @@
 	phba->fc_stat.elsXmitACC++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 
-	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
 	if (rc == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
 		return 1;
@@ -3562,15 +3634,12 @@
 	RNID *rn;
 	IOCB_t *icmd, *oldcmd;
 	struct lpfc_iocbq *elsiocb;
-	struct lpfc_sli_ring *pring;
 	struct lpfc_sli *psli;
 	uint8_t *pcmd;
 	uint16_t cmdsize;
 	int rc;
 
 	psli = &phba->sli;
-	pring = &psli->ring[LPFC_ELS_RING];
-
 	cmdsize = sizeof(uint32_t) + sizeof(uint32_t)
 					+ (2 * sizeof(struct lpfc_name));
 	if (format)
@@ -3626,7 +3695,7 @@
 	elsiocb->context1 = NULL;  /* Don't need ndlp for cmpl,
 				    * it could be freed */
 
-	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
 	if (rc == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
 		return 1;
@@ -3839,7 +3908,9 @@
 			payload_len -= sizeof(uint32_t);
 			switch (rscn_did.un.b.resv & RSCN_ADDRESS_FORMAT_MASK) {
 			case RSCN_ADDRESS_FORMAT_PORT:
-				if (ns_did.un.word == rscn_did.un.word)
+				if ((ns_did.un.b.domain == rscn_did.un.b.domain)
+				    && (ns_did.un.b.area == rscn_did.un.b.area)
+				    && (ns_did.un.b.id == rscn_did.un.b.id))
 					goto return_did_out;
 				break;
 			case RSCN_ADDRESS_FORMAT_AREA:
@@ -4300,7 +4371,7 @@
 			lpfc_init_link(phba, mbox,
 				       phba->cfg_topology,
 				       phba->cfg_link_speed);
-			mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
+			mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
 			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 			mbox->vport = vport;
 			rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
@@ -4440,8 +4511,6 @@
 static void
 lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
-	struct lpfc_sli *psli = &phba->sli;
-	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
 	MAILBOX_t *mb;
 	IOCB_t *icmd;
 	RPS_RSP *rps_rsp;
@@ -4451,7 +4520,7 @@
 	uint16_t xri, status;
 	uint32_t cmdsize;
 
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 
 	ndlp = (struct lpfc_nodelist *) pmb->context2;
 	xri = (uint16_t) ((unsigned long)(pmb->context1));
@@ -4507,7 +4576,7 @@
 			 ndlp->nlp_rpi);
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 	phba->fc_stat.elsXmitACC++;
-	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
+	if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR)
 		lpfc_els_free_iocb(phba, elsiocb);
 	return;
 }
@@ -4616,8 +4685,6 @@
 	IOCB_t *icmd, *oldcmd;
 	RPL_RSP rpl_rsp;
 	struct lpfc_iocbq *elsiocb;
-	struct lpfc_sli *psli = &phba->sli;
-	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
 	uint8_t *pcmd;
 
 	elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
@@ -4654,7 +4721,8 @@
 			 ndlp->nlp_rpi);
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 	phba->fc_stat.elsXmitACC++;
-	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+	if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) ==
+	    IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
 		return 1;
 	}
@@ -4883,7 +4951,10 @@
 		} else {
 			/* FAN verified - skip FLOGI */
 			vport->fc_myDID = vport->fc_prevDID;
-			lpfc_issue_fabric_reglogin(vport);
+			if (phba->sli_rev < LPFC_SLI_REV4)
+				lpfc_issue_fabric_reglogin(vport);
+			else
+				lpfc_issue_reg_vfi(vport);
 		}
 	}
 	return 0;
@@ -5566,11 +5637,10 @@
 
 dropit:
 	if (vport && !(vport->load_flag & FC_UNLOADING))
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-			"(%d):0111 Dropping received ELS cmd "
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+			"0111 Dropping received ELS cmd "
 			"Data: x%x x%x x%x\n",
-			vport->vpi, icmd->ulpStatus,
-			icmd->un.ulpWord[4], icmd->ulpTimeout);
+			icmd->ulpStatus, icmd->un.ulpWord[4], icmd->ulpTimeout);
 	phba->fc_stat.elsRcvDrop++;
 }
 
@@ -5646,10 +5716,9 @@
 	     icmd->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
 		if (icmd->unsli3.rcvsli3.vpi == 0xffff)
 			vport = phba->pport;
-		else {
-			uint16_t vpi = icmd->unsli3.rcvsli3.vpi;
-			vport = lpfc_find_vport_by_vpid(phba, vpi);
-		}
+		else
+			vport = lpfc_find_vport_by_vpid(phba,
+				icmd->unsli3.rcvsli3.vpi - phba->vpi_base);
 	}
 	/* If there are no BDEs associated
 	 * with this IOCB, there is nothing to do.
@@ -5781,7 +5850,7 @@
 	struct lpfc_vport *vport = pmb->vport;
 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 
 	spin_lock_irq(shost->host_lock);
 	vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
@@ -5818,7 +5887,10 @@
 
 	} else {
 		if (vport == phba->pport)
-			lpfc_issue_fabric_reglogin(vport);
+			if (phba->sli_rev < LPFC_SLI_REV4)
+				lpfc_issue_fabric_reglogin(vport);
+			else
+				lpfc_issue_reg_vfi(vport);
 		else
 			lpfc_do_scr_ns_plogi(phba, vport);
 	}
@@ -5850,7 +5922,7 @@
 
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (mbox) {
-		lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, mbox);
+		lpfc_reg_vpi(vport, mbox);
 		mbox->vport = vport;
 		mbox->context2 = lpfc_nlp_get(ndlp);
 		mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport;
@@ -6139,7 +6211,6 @@
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_hba  *phba = vport->phba;
-	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
 	IOCB_t *icmd;
 	struct lpfc_iocbq *elsiocb;
 	uint8_t *pcmd;
@@ -6169,7 +6240,8 @@
 	spin_lock_irq(shost->host_lock);
 	ndlp->nlp_flag |= NLP_LOGO_SND;
 	spin_unlock_irq(shost->host_lock);
-	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+	if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) ==
+	    IOCB_ERROR) {
 		spin_lock_irq(shost->host_lock);
 		ndlp->nlp_flag &= ~NLP_LOGO_SND;
 		spin_unlock_irq(shost->host_lock);
@@ -6224,7 +6296,6 @@
 	struct lpfc_iocbq *iocb;
 	unsigned long iflags;
 	int ret;
-	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
 	IOCB_t *cmd;
 
 repeat:
@@ -6248,7 +6319,7 @@
 			"Fabric sched1:   ste:x%x",
 			iocb->vport->port_state, 0, 0);
 
-		ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
+		ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, iocb, 0);
 
 		if (ret == IOCB_ERROR) {
 			iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
@@ -6394,7 +6465,6 @@
 lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
 {
 	unsigned long iflags;
-	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
 	int ready;
 	int ret;
 
@@ -6418,7 +6488,7 @@
 			"Fabric sched2:   ste:x%x",
 			iocb->vport->port_state, 0, 0);
 
-		ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
+		ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, iocb, 0);
 
 		if (ret == IOCB_ERROR) {
 			iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
@@ -6524,3 +6594,38 @@
 	lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
 			      IOERR_SLI_ABORTED);
 }
+
+/**
+ * lpfc_sli4_els_xri_aborted - Slow-path process of els xri abort
+ * @phba: pointer to lpfc hba data structure.
+ * @axri: pointer to the els xri abort wcqe structure.
+ *
+ * This routine is invoked by the worker thread to process a SLI4 slow-path
+ * ELS aborted xri.
+ **/
+void
+lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
+			  struct sli4_wcqe_xri_aborted *axri)
+{
+	uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
+	struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
+	unsigned long iflag = 0;
+
+	spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, iflag);
+	list_for_each_entry_safe(sglq_entry, sglq_next,
+			&phba->sli4_hba.lpfc_abts_els_sgl_list, list) {
+		if (sglq_entry->sli4_xritag == xri) {
+			list_del(&sglq_entry->list);
+			spin_unlock_irqrestore(
+					&phba->sli4_hba.abts_sgl_list_lock,
+					 iflag);
+			spin_lock_irqsave(&phba->hbalock, iflag);
+
+			list_add_tail(&sglq_entry->list,
+				&phba->sli4_hba.lpfc_sgl_list);
+			spin_unlock_irqrestore(&phba->hbalock, iflag);
+			return;
+		}
+	}
+	spin_unlock_irqrestore(&phba->sli4_hba.abts_sgl_list_lock, iflag);
+}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index e764ce0..35c41ae 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-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -29,10 +29,12 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_scsi.h"
 #include "lpfc.h"
 #include "lpfc_logmsg.h"
@@ -273,6 +275,8 @@
 	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
 	    (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
 		lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
+
+	lpfc_unregister_unused_fcf(phba);
 }
 
 /**
@@ -295,10 +299,11 @@
 
 	ret = kzalloc(sizeof(struct lpfc_fast_path_event),
 			GFP_ATOMIC);
-	if (ret)
+	if (ret) {
 		atomic_inc(&phba->fast_event_count);
-	INIT_LIST_HEAD(&ret->work_evt.evt_listp);
-	ret->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT;
+		INIT_LIST_HEAD(&ret->work_evt.evt_listp);
+		ret->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT;
+	}
 	return ret;
 }
 
@@ -491,6 +496,10 @@
 	phba->work_ha = 0;
 	spin_unlock_irq(&phba->hbalock);
 
+	/* First, try to post the next mailbox command to SLI4 device */
+	if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
+		lpfc_sli4_post_async_mbox(phba);
+
 	if (ha_copy & HA_ERATT)
 		/* Handle the error attention event */
 		lpfc_handle_eratt(phba);
@@ -501,9 +510,27 @@
 	if (ha_copy & HA_LATT)
 		lpfc_handle_latt(phba);
 
+	/* Process SLI4 events */
+	if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
+		if (phba->hba_flag & FCP_XRI_ABORT_EVENT)
+			lpfc_sli4_fcp_xri_abort_event_proc(phba);
+		if (phba->hba_flag & ELS_XRI_ABORT_EVENT)
+			lpfc_sli4_els_xri_abort_event_proc(phba);
+		if (phba->hba_flag & ASYNC_EVENT)
+			lpfc_sli4_async_event_proc(phba);
+		if (phba->hba_flag & HBA_POST_RECEIVE_BUFFER) {
+			spin_lock_irq(&phba->hbalock);
+			phba->hba_flag &= ~HBA_POST_RECEIVE_BUFFER;
+			spin_unlock_irq(&phba->hbalock);
+			lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
+		}
+		if (phba->hba_flag & HBA_RECEIVE_BUFFER)
+			lpfc_sli4_handle_received_buffer(phba);
+	}
+
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i <= phba->max_vpi; i++) {
+		for (i = 0; i <= phba->max_vports; i++) {
 			/*
 			 * We could have no vports in array if unloading, so if
 			 * this happens then just use the pport
@@ -555,23 +582,24 @@
 		/*
 		 * Turn on Ring interrupts
 		 */
-		spin_lock_irq(&phba->hbalock);
-		control = readl(phba->HCregaddr);
-		if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) {
-			lpfc_debugfs_slow_ring_trc(phba,
-				"WRK Enable ring: cntl:x%x hacopy:x%x",
-				control, ha_copy, 0);
+		if (phba->sli_rev <= LPFC_SLI_REV3) {
+			spin_lock_irq(&phba->hbalock);
+			control = readl(phba->HCregaddr);
+			if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) {
+				lpfc_debugfs_slow_ring_trc(phba,
+					"WRK Enable ring: cntl:x%x hacopy:x%x",
+					control, ha_copy, 0);
 
-			control |= (HC_R0INT_ENA << LPFC_ELS_RING);
-			writel(control, phba->HCregaddr);
-			readl(phba->HCregaddr); /* flush */
+				control |= (HC_R0INT_ENA << LPFC_ELS_RING);
+				writel(control, phba->HCregaddr);
+				readl(phba->HCregaddr); /* flush */
+			} else {
+				lpfc_debugfs_slow_ring_trc(phba,
+					"WRK Ring ok:     cntl:x%x hacopy:x%x",
+					control, ha_copy, 0);
+			}
+			spin_unlock_irq(&phba->hbalock);
 		}
-		else {
-			lpfc_debugfs_slow_ring_trc(phba,
-				"WRK Ring ok:     cntl:x%x hacopy:x%x",
-				control, ha_copy, 0);
-		}
-		spin_unlock_irq(&phba->hbalock);
 	}
 	lpfc_work_list_done(phba);
 }
@@ -689,7 +717,7 @@
 	lpfc_can_disctmo(vport);
 }
 
-static void
+void
 lpfc_linkdown_port(struct lpfc_vport *vport)
 {
 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
@@ -716,6 +744,7 @@
 	if (phba->link_state == LPFC_LINK_DOWN)
 		return 0;
 	spin_lock_irq(&phba->hbalock);
+	phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_DISCOVERED);
 	if (phba->link_state > LPFC_LINK_DOWN) {
 		phba->link_state = LPFC_LINK_DOWN;
 		phba->pport->fc_flag &= ~FC_LBIT;
@@ -723,7 +752,7 @@
 	spin_unlock_irq(&phba->hbalock);
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
 			/* Issue a LINK DOWN event to all nodes */
 			lpfc_linkdown_port(vports[i]);
 		}
@@ -833,10 +862,11 @@
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
 			lpfc_linkup_port(vports[i]);
 	lpfc_destroy_vport_work_array(phba, vports);
-	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+	if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+	    (phba->sli_rev < LPFC_SLI_REV4))
 		lpfc_issue_clear_la(phba, phba->pport);
 
 	return 0;
@@ -854,7 +884,7 @@
 	struct lpfc_vport *vport = pmb->vport;
 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_sli   *psli = &phba->sli;
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	uint32_t control;
 
 	/* Since we don't do discovery right now, turn these off here */
@@ -917,7 +947,7 @@
 {
 	struct lpfc_vport *vport = pmb->vport;
 
-	if (pmb->mb.mbxStatus)
+	if (pmb->u.mb.mbxStatus)
 		goto out;
 
 	mempool_free(pmb, phba->mbox_mem_pool);
@@ -945,7 +975,7 @@
 	lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
 			 "0306 CONFIG_LINK mbxStatus error x%x "
 			 "HBA state x%x\n",
-			 pmb->mb.mbxStatus, vport->port_state);
+			 pmb->u.mb.mbxStatus, vport->port_state);
 	mempool_free(pmb, phba->mbox_mem_pool);
 
 	lpfc_linkdown(phba);
@@ -959,9 +989,592 @@
 }
 
 static void
+lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+	struct lpfc_vport *vport = mboxq->vport;
+	unsigned long flags;
+
+	if (mboxq->u.mb.mbxStatus) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+			 "2017 REG_FCFI mbxStatus error x%x "
+			 "HBA state x%x\n",
+			 mboxq->u.mb.mbxStatus, vport->port_state);
+		mempool_free(mboxq, phba->mbox_mem_pool);
+		return;
+	}
+
+	/* Start FCoE discovery by sending a FLOGI. */
+	phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_fcfi, &mboxq->u.mqe.un.reg_fcfi);
+	/* Set the FCFI registered flag */
+	spin_lock_irqsave(&phba->hbalock, flags);
+	phba->fcf.fcf_flag |= FCF_REGISTERED;
+	spin_unlock_irqrestore(&phba->hbalock, flags);
+	if (vport->port_state != LPFC_FLOGI) {
+		spin_lock_irqsave(&phba->hbalock, flags);
+		phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
+		spin_unlock_irqrestore(&phba->hbalock, flags);
+		lpfc_initial_flogi(vport);
+	}
+
+	mempool_free(mboxq, phba->mbox_mem_pool);
+	return;
+}
+
+/**
+ * lpfc_fab_name_match - Check if the fcf fabric name match.
+ * @fab_name: pointer to fabric name.
+ * @new_fcf_record: pointer to fcf record.
+ *
+ * This routine compare the fcf record's fabric name with provided
+ * fabric name. If the fabric name are identical this function
+ * returns 1 else return 0.
+ **/
+static uint32_t
+lpfc_fab_name_match(uint8_t *fab_name, struct fcf_record *new_fcf_record)
+{
+	if ((fab_name[0] ==
+		bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record)) &&
+	    (fab_name[1] ==
+		bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record)) &&
+	    (fab_name[2] ==
+		bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record)) &&
+	    (fab_name[3] ==
+		bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record)) &&
+	    (fab_name[4] ==
+		bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record)) &&
+	    (fab_name[5] ==
+		bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record)) &&
+	    (fab_name[6] ==
+		bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record)) &&
+	    (fab_name[7] ==
+		bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record)))
+		return 1;
+	else
+		return 0;
+}
+
+/**
+ * lpfc_mac_addr_match - Check if the fcf mac address match.
+ * @phba: pointer to lpfc hba data structure.
+ * @new_fcf_record: pointer to fcf record.
+ *
+ * This routine compare the fcf record's mac address with HBA's
+ * FCF mac address. If the mac addresses are identical this function
+ * returns 1 else return 0.
+ **/
+static uint32_t
+lpfc_mac_addr_match(struct lpfc_hba *phba, struct fcf_record *new_fcf_record)
+{
+	if ((phba->fcf.mac_addr[0] ==
+		bf_get(lpfc_fcf_record_mac_0, new_fcf_record)) &&
+	    (phba->fcf.mac_addr[1] ==
+		bf_get(lpfc_fcf_record_mac_1, new_fcf_record)) &&
+	    (phba->fcf.mac_addr[2] ==
+		bf_get(lpfc_fcf_record_mac_2, new_fcf_record)) &&
+	    (phba->fcf.mac_addr[3] ==
+		bf_get(lpfc_fcf_record_mac_3, new_fcf_record)) &&
+	    (phba->fcf.mac_addr[4] ==
+		bf_get(lpfc_fcf_record_mac_4, new_fcf_record)) &&
+	    (phba->fcf.mac_addr[5] ==
+		bf_get(lpfc_fcf_record_mac_5, new_fcf_record)))
+		return 1;
+	else
+		return 0;
+}
+
+/**
+ * lpfc_copy_fcf_record - Copy fcf information to lpfc_hba.
+ * @phba: pointer to lpfc hba data structure.
+ * @new_fcf_record: pointer to fcf record.
+ *
+ * This routine copies the FCF information from the FCF
+ * record to lpfc_hba data structure.
+ **/
+static void
+lpfc_copy_fcf_record(struct lpfc_hba *phba, struct fcf_record *new_fcf_record)
+{
+	phba->fcf.fabric_name[0] =
+		bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record);
+	phba->fcf.fabric_name[1] =
+		bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record);
+	phba->fcf.fabric_name[2] =
+		bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record);
+	phba->fcf.fabric_name[3] =
+		bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record);
+	phba->fcf.fabric_name[4] =
+		bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record);
+	phba->fcf.fabric_name[5] =
+		bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record);
+	phba->fcf.fabric_name[6] =
+		bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record);
+	phba->fcf.fabric_name[7] =
+		bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record);
+	phba->fcf.mac_addr[0] =
+		bf_get(lpfc_fcf_record_mac_0, new_fcf_record);
+	phba->fcf.mac_addr[1] =
+		bf_get(lpfc_fcf_record_mac_1, new_fcf_record);
+	phba->fcf.mac_addr[2] =
+		bf_get(lpfc_fcf_record_mac_2, new_fcf_record);
+	phba->fcf.mac_addr[3] =
+		bf_get(lpfc_fcf_record_mac_3, new_fcf_record);
+	phba->fcf.mac_addr[4] =
+		bf_get(lpfc_fcf_record_mac_4, new_fcf_record);
+	phba->fcf.mac_addr[5] =
+		bf_get(lpfc_fcf_record_mac_5, new_fcf_record);
+	phba->fcf.fcf_indx = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
+	phba->fcf.priority = new_fcf_record->fip_priority;
+}
+
+/**
+ * lpfc_register_fcf - Register the FCF with hba.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine issues a register fcfi mailbox command to register
+ * the fcf with HBA.
+ **/
+static void
+lpfc_register_fcf(struct lpfc_hba *phba)
+{
+	LPFC_MBOXQ_t *fcf_mbxq;
+	int rc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&phba->hbalock, flags);
+
+	/* If the FCF is not availabe do nothing. */
+	if (!(phba->fcf.fcf_flag & FCF_AVAILABLE)) {
+		spin_unlock_irqrestore(&phba->hbalock, flags);
+		return;
+	}
+
+	/* The FCF is already registered, start discovery */
+	if (phba->fcf.fcf_flag & FCF_REGISTERED) {
+		phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
+		spin_unlock_irqrestore(&phba->hbalock, flags);
+		if (phba->pport->port_state != LPFC_FLOGI)
+			lpfc_initial_flogi(phba->pport);
+		return;
+	}
+	spin_unlock_irqrestore(&phba->hbalock, flags);
+
+	fcf_mbxq = mempool_alloc(phba->mbox_mem_pool,
+		GFP_KERNEL);
+	if (!fcf_mbxq)
+		return;
+
+	lpfc_reg_fcfi(phba, fcf_mbxq);
+	fcf_mbxq->vport = phba->pport;
+	fcf_mbxq->mbox_cmpl = lpfc_mbx_cmpl_reg_fcfi;
+	rc = lpfc_sli_issue_mbox(phba, fcf_mbxq, MBX_NOWAIT);
+	if (rc == MBX_NOT_FINISHED)
+		mempool_free(fcf_mbxq, phba->mbox_mem_pool);
+
+	return;
+}
+
+/**
+ * lpfc_match_fcf_conn_list - Check if the FCF record can be used for discovery.
+ * @phba: pointer to lpfc hba data structure.
+ * @new_fcf_record: pointer to fcf record.
+ * @boot_flag: Indicates if this record used by boot bios.
+ * @addr_mode: The address mode to be used by this FCF
+ *
+ * This routine compare the fcf record with connect list obtained from the
+ * config region to decide if this FCF can be used for SAN discovery. It returns
+ * 1 if this record can be used for SAN discovery else return zero. If this FCF
+ * record can be used for SAN discovery, the boot_flag will indicate if this FCF
+ * is used by boot bios and addr_mode will indicate the addressing mode to be
+ * used for this FCF when the function returns.
+ * If the FCF record need to be used with a particular vlan id, the vlan is
+ * set in the vlan_id on return of the function. If not VLAN tagging need to
+ * be used with the FCF vlan_id will be set to 0xFFFF;
+ **/
+static int
+lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
+			struct fcf_record *new_fcf_record,
+			uint32_t *boot_flag, uint32_t *addr_mode,
+			uint16_t *vlan_id)
+{
+	struct lpfc_fcf_conn_entry *conn_entry;
+
+	if (!phba->cfg_enable_fip) {
+		*boot_flag = 0;
+		*addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov,
+				new_fcf_record);
+		if (phba->valid_vlan)
+			*vlan_id = phba->vlan_id;
+		else
+			*vlan_id = 0xFFFF;
+		return 1;
+	}
+
+	/*
+	 * If there are no FCF connection table entry, driver connect to all
+	 * FCFs.
+	 */
+	if (list_empty(&phba->fcf_conn_rec_list)) {
+		*boot_flag = 0;
+		*addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov,
+			new_fcf_record);
+		*vlan_id = 0xFFFF;
+		return 1;
+	}
+
+	list_for_each_entry(conn_entry, &phba->fcf_conn_rec_list, list) {
+		if (!(conn_entry->conn_rec.flags & FCFCNCT_VALID))
+			continue;
+
+		if ((conn_entry->conn_rec.flags & FCFCNCT_FBNM_VALID) &&
+			!lpfc_fab_name_match(conn_entry->conn_rec.fabric_name,
+				new_fcf_record))
+			continue;
+
+		if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID) {
+			/*
+			 * If the vlan bit map does not have the bit set for the
+			 * vlan id to be used, then it is not a match.
+			 */
+			if (!(new_fcf_record->vlan_bitmap
+				[conn_entry->conn_rec.vlan_tag / 8] &
+				(1 << (conn_entry->conn_rec.vlan_tag % 8))))
+				continue;
+		}
+
+		/*
+		 * Check if the connection record specifies a required
+		 * addressing mode.
+		 */
+		if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) &&
+			!(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED)) {
+
+			/*
+			 * If SPMA required but FCF not support this continue.
+			 */
+			if ((conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) &&
+				!(bf_get(lpfc_fcf_record_mac_addr_prov,
+					new_fcf_record) & LPFC_FCF_SPMA))
+				continue;
+
+			/*
+			 * If FPMA required but FCF not support this continue.
+			 */
+			if (!(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) &&
+				!(bf_get(lpfc_fcf_record_mac_addr_prov,
+				new_fcf_record) & LPFC_FCF_FPMA))
+				continue;
+		}
+
+		/*
+		 * This fcf record matches filtering criteria.
+		 */
+		if (conn_entry->conn_rec.flags & FCFCNCT_BOOT)
+			*boot_flag = 1;
+		else
+			*boot_flag = 0;
+
+		*addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov,
+				new_fcf_record);
+		/*
+		 * If the user specified a required address mode, assign that
+		 * address mode
+		 */
+		if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) &&
+			(!(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED)))
+			*addr_mode = (conn_entry->conn_rec.flags &
+				FCFCNCT_AM_SPMA) ?
+				LPFC_FCF_SPMA : LPFC_FCF_FPMA;
+		/*
+		 * If the user specified a prefered address mode, use the
+		 * addr mode only if FCF support the addr_mode.
+		 */
+		else if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) &&
+			(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED) &&
+			(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) &&
+			(*addr_mode & LPFC_FCF_SPMA))
+				*addr_mode = LPFC_FCF_SPMA;
+		else if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) &&
+			(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED) &&
+			!(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) &&
+			(*addr_mode & LPFC_FCF_FPMA))
+				*addr_mode = LPFC_FCF_FPMA;
+		/*
+		 * If user did not specify any addressing mode, use FPMA if
+		 * possible else use SPMA.
+		 */
+		else if (*addr_mode & LPFC_FCF_FPMA)
+			*addr_mode = LPFC_FCF_FPMA;
+
+		if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID)
+			*vlan_id = conn_entry->conn_rec.vlan_tag;
+		else
+			*vlan_id = 0xFFFF;
+
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox.
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: pointer to mailbox object.
+ *
+ * This function iterate through all the fcf records available in
+ * HBA and choose the optimal FCF record for discovery. After finding
+ * the FCF for discovery it register the FCF record and kick start
+ * discovery.
+ * If FCF_IN_USE flag is set in currently used FCF, the routine try to
+ * use a FCF record which match fabric name and mac address of the
+ * currently used FCF record.
+ * If the driver support only one FCF, it will try to use the FCF record
+ * used by BOOT_BIOS.
+ */
+void
+lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+	void *virt_addr;
+	dma_addr_t phys_addr;
+	uint8_t *bytep;
+	struct lpfc_mbx_sge sge;
+	struct lpfc_mbx_read_fcf_tbl *read_fcf;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+	struct fcf_record *new_fcf_record;
+	int rc;
+	uint32_t boot_flag, addr_mode;
+	uint32_t next_fcf_index;
+	unsigned long flags;
+	uint16_t vlan_id;
+
+	/* Get the first SGE entry from the non-embedded DMA memory. This
+	 * routine only uses a single SGE.
+	 */
+	lpfc_sli4_mbx_sge_get(mboxq, 0, &sge);
+	phys_addr = getPaddr(sge.pa_hi, sge.pa_lo);
+	if (unlikely(!mboxq->sge_array)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+				"2524 Failed to get the non-embedded SGE "
+				"virtual address\n");
+		goto out;
+	}
+	virt_addr = mboxq->sge_array->addr[0];
+
+	shdr = (union lpfc_sli4_cfg_shdr *)virt_addr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
+				 &shdr->response);
+	/*
+	 * The FCF Record was read and there is no reason for the driver
+	 * to maintain the FCF record data or memory. Instead, just need
+	 * to book keeping the FCFIs can be used.
+	 */
+	if (shdr_status || shdr_add_status) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2521 READ_FCF_RECORD mailbox failed "
+				"with status x%x add_status x%x, mbx\n",
+				shdr_status, shdr_add_status);
+		goto out;
+	}
+	/* Interpreting the returned information of FCF records */
+	read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr;
+	lpfc_sli_pcimem_bcopy(read_fcf, read_fcf,
+			      sizeof(struct lpfc_mbx_read_fcf_tbl));
+	next_fcf_index = bf_get(lpfc_mbx_read_fcf_tbl_nxt_vindx, read_fcf);
+
+	new_fcf_record = (struct fcf_record *)(virt_addr +
+			  sizeof(struct lpfc_mbx_read_fcf_tbl));
+	lpfc_sli_pcimem_bcopy(new_fcf_record, new_fcf_record,
+			      sizeof(struct fcf_record));
+	bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr);
+
+	rc = lpfc_match_fcf_conn_list(phba, new_fcf_record,
+				      &boot_flag, &addr_mode,
+					&vlan_id);
+	/*
+	 * If the fcf record does not match with connect list entries
+	 * read the next entry.
+	 */
+	if (!rc)
+		goto read_next_fcf;
+	/*
+	 * If this is not the first FCF discovery of the HBA, use last
+	 * FCF record for the discovery.
+	 */
+	spin_lock_irqsave(&phba->hbalock, flags);
+	if (phba->fcf.fcf_flag & FCF_IN_USE) {
+		if (lpfc_fab_name_match(phba->fcf.fabric_name,
+			new_fcf_record) &&
+		    lpfc_mac_addr_match(phba, new_fcf_record)) {
+			phba->fcf.fcf_flag |= FCF_AVAILABLE;
+			spin_unlock_irqrestore(&phba->hbalock, flags);
+			goto out;
+		}
+		spin_unlock_irqrestore(&phba->hbalock, flags);
+		goto read_next_fcf;
+	}
+	if (phba->fcf.fcf_flag & FCF_AVAILABLE) {
+		/*
+		 * If the current FCF record does not have boot flag
+		 * set and new fcf record has boot flag set, use the
+		 * new fcf record.
+		 */
+		if (boot_flag && !(phba->fcf.fcf_flag & FCF_BOOT_ENABLE)) {
+			/* Use this FCF record */
+			lpfc_copy_fcf_record(phba, new_fcf_record);
+			phba->fcf.addr_mode = addr_mode;
+			phba->fcf.fcf_flag |= FCF_BOOT_ENABLE;
+			if (vlan_id != 0xFFFF) {
+				phba->fcf.fcf_flag |= FCF_VALID_VLAN;
+				phba->fcf.vlan_id = vlan_id;
+			}
+			spin_unlock_irqrestore(&phba->hbalock, flags);
+			goto read_next_fcf;
+		}
+		/*
+		 * If the current FCF record has boot flag set and the
+		 * new FCF record does not have boot flag, read the next
+		 * FCF record.
+		 */
+		if (!boot_flag && (phba->fcf.fcf_flag & FCF_BOOT_ENABLE)) {
+			spin_unlock_irqrestore(&phba->hbalock, flags);
+			goto read_next_fcf;
+		}
+		/*
+		 * If there is a record with lower priority value for
+		 * the current FCF, use that record.
+		 */
+		if (lpfc_fab_name_match(phba->fcf.fabric_name, new_fcf_record)
+			&& (new_fcf_record->fip_priority <
+				phba->fcf.priority)) {
+			/* Use this FCF record */
+			lpfc_copy_fcf_record(phba, new_fcf_record);
+			phba->fcf.addr_mode = addr_mode;
+			if (vlan_id != 0xFFFF) {
+				phba->fcf.fcf_flag |= FCF_VALID_VLAN;
+				phba->fcf.vlan_id = vlan_id;
+			}
+			spin_unlock_irqrestore(&phba->hbalock, flags);
+			goto read_next_fcf;
+		}
+		spin_unlock_irqrestore(&phba->hbalock, flags);
+		goto read_next_fcf;
+	}
+	/*
+	 * This is the first available FCF record, use this
+	 * record.
+	 */
+	lpfc_copy_fcf_record(phba, new_fcf_record);
+	phba->fcf.addr_mode = addr_mode;
+	if (boot_flag)
+		phba->fcf.fcf_flag |= FCF_BOOT_ENABLE;
+	phba->fcf.fcf_flag |= FCF_AVAILABLE;
+	if (vlan_id != 0xFFFF) {
+		phba->fcf.fcf_flag |= FCF_VALID_VLAN;
+		phba->fcf.vlan_id = vlan_id;
+	}
+	spin_unlock_irqrestore(&phba->hbalock, flags);
+	goto read_next_fcf;
+
+read_next_fcf:
+	lpfc_sli4_mbox_cmd_free(phba, mboxq);
+	if (next_fcf_index == LPFC_FCOE_FCF_NEXT_NONE || next_fcf_index == 0)
+		lpfc_register_fcf(phba);
+	else
+		lpfc_sli4_read_fcf_record(phba, next_fcf_index);
+	return;
+
+out:
+	lpfc_sli4_mbox_cmd_free(phba, mboxq);
+	lpfc_register_fcf(phba);
+
+	return;
+}
+
+/**
+ * lpfc_start_fdiscs - send fdiscs for each vports on this port.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This function loops through the list of vports on the @phba and issues an
+ * FDISC if possible.
+ */
+void
+lpfc_start_fdiscs(struct lpfc_hba *phba)
+{
+	struct lpfc_vport **vports;
+	int i;
+
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL) {
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+			if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
+				continue;
+			/* There are no vpi for this vport */
+			if (vports[i]->vpi > phba->max_vpi) {
+				lpfc_vport_set_state(vports[i],
+						     FC_VPORT_FAILED);
+				continue;
+			}
+			if (phba->fc_topology == TOPOLOGY_LOOP) {
+				lpfc_vport_set_state(vports[i],
+						     FC_VPORT_LINKDOWN);
+				continue;
+			}
+			if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
+				lpfc_initial_fdisc(vports[i]);
+			else {
+				lpfc_vport_set_state(vports[i],
+						     FC_VPORT_NO_FABRIC_SUPP);
+				lpfc_printf_vlog(vports[i], KERN_ERR,
+						 LOG_ELS,
+						 "0259 No NPIV "
+						 "Fabric support\n");
+			}
+		}
+	}
+	lpfc_destroy_vport_work_array(phba, vports);
+}
+
+void
+lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+	struct lpfc_dmabuf *dmabuf = mboxq->context1;
+	struct lpfc_vport *vport = mboxq->vport;
+
+	if (mboxq->u.mb.mbxStatus) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+			 "2018 REG_VFI mbxStatus error x%x "
+			 "HBA state x%x\n",
+			 mboxq->u.mb.mbxStatus, vport->port_state);
+		if (phba->fc_topology == TOPOLOGY_LOOP) {
+			/* FLOGI failed, use loop map to make discovery list */
+			lpfc_disc_list_loopmap(vport);
+			/* Start discovery */
+			lpfc_disc_start(vport);
+			goto fail_free_mem;
+		}
+		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+		goto fail_free_mem;
+	}
+	/* Mark the vport has registered with its VFI */
+	vport->vfi_state |= LPFC_VFI_REGISTERED;
+
+	if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
+		lpfc_start_fdiscs(phba);
+		lpfc_do_scr_ns_plogi(phba, vport);
+	}
+
+fail_free_mem:
+	mempool_free(mboxq, phba->mbox_mem_pool);
+	lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+	kfree(dmabuf);
+	return;
+}
+
+static void
 lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1;
 	struct lpfc_vport  *vport = pmb->vport;
 
@@ -1012,13 +1625,13 @@
 lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
 {
 	struct lpfc_vport *vport = phba->pport;
-	LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox;
+	LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox = NULL;
 	int i;
 	struct lpfc_dmabuf *mp;
 	int rc;
+	struct fcf_record *fcf_record;
 
 	sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-	cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 
 	spin_lock_irq(&phba->hbalock);
 	switch (la->UlnkSpeed) {
@@ -1034,6 +1647,9 @@
 	case LA_8GHZ_LINK:
 		phba->fc_linkspeed = LA_8GHZ_LINK;
 		break;
+	case LA_10GHZ_LINK:
+		phba->fc_linkspeed = LA_10GHZ_LINK;
+		break;
 	default:
 		phba->fc_linkspeed = LA_UNKNW_LINK;
 		break;
@@ -1115,22 +1731,66 @@
 			lpfc_mbuf_free(phba, mp->virt, mp->phys);
 			kfree(mp);
 			mempool_free(sparam_mbox, phba->mbox_mem_pool);
-			if (cfglink_mbox)
-				mempool_free(cfglink_mbox, phba->mbox_mem_pool);
 			goto out;
 		}
 	}
 
-	if (cfglink_mbox) {
+	if (!(phba->hba_flag & HBA_FCOE_SUPPORT)) {
+		cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+		if (!cfglink_mbox)
+			goto out;
 		vport->port_state = LPFC_LOCAL_CFG_LINK;
 		lpfc_config_link(phba, cfglink_mbox);
 		cfglink_mbox->vport = vport;
 		cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
 		rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT);
-		if (rc != MBX_NOT_FINISHED)
-			return;
-		mempool_free(cfglink_mbox, phba->mbox_mem_pool);
+		if (rc == MBX_NOT_FINISHED) {
+			mempool_free(cfglink_mbox, phba->mbox_mem_pool);
+			goto out;
+		}
+	} else {
+		/*
+		 * Add the driver's default FCF record at FCF index 0 now. This
+		 * is phase 1 implementation that support FCF index 0 and driver
+		 * defaults.
+		 */
+		if (phba->cfg_enable_fip == 0) {
+			fcf_record = kzalloc(sizeof(struct fcf_record),
+					GFP_KERNEL);
+			if (unlikely(!fcf_record)) {
+				lpfc_printf_log(phba, KERN_ERR,
+					LOG_MBOX | LOG_SLI,
+					"2554 Could not allocate memmory for "
+					"fcf record\n");
+				rc = -ENODEV;
+				goto out;
+			}
+
+			lpfc_sli4_build_dflt_fcf_record(phba, fcf_record,
+						LPFC_FCOE_FCF_DEF_INDEX);
+			rc = lpfc_sli4_add_fcf_record(phba, fcf_record);
+			if (unlikely(rc)) {
+				lpfc_printf_log(phba, KERN_ERR,
+					LOG_MBOX | LOG_SLI,
+					"2013 Could not manually add FCF "
+					"record 0, status %d\n", rc);
+				rc = -ENODEV;
+				kfree(fcf_record);
+				goto out;
+			}
+			kfree(fcf_record);
+		}
+		/*
+		 * The driver is expected to do FIP/FCF. Call the port
+		 * and get the FCF Table.
+		 */
+		rc = lpfc_sli4_read_fcf_record(phba,
+					LPFC_FCOE_FCF_GET_FIRST);
+		if (rc)
+			goto out;
 	}
+
+	return;
 out:
 	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 	lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
@@ -1147,10 +1807,12 @@
 	struct lpfc_sli *psli = &phba->sli;
 	spin_lock_irq(&phba->hbalock);
 	psli->sli_flag |= LPFC_PROCESS_LA;
-	control = readl(phba->HCregaddr);
-	control |= HC_LAINT_ENA;
-	writel(control, phba->HCregaddr);
-	readl(phba->HCregaddr); /* flush */
+	if (phba->sli_rev <= LPFC_SLI_REV3) {
+		control = readl(phba->HCregaddr);
+		control |= HC_LAINT_ENA;
+		writel(control, phba->HCregaddr);
+		readl(phba->HCregaddr); /* flush */
+	}
 	spin_unlock_irq(&phba->hbalock);
 }
 
@@ -1159,6 +1821,7 @@
 {
 	lpfc_linkdown(phba);
 	lpfc_enable_la(phba);
+	lpfc_unregister_unused_fcf(phba);
 	/* turn on Link Attention interrupts - no CLEAR_LA needed */
 }
 
@@ -1175,7 +1838,7 @@
 	struct lpfc_vport *vport = pmb->vport;
 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
 	READ_LA_VAR *la;
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
 
 	/* Unblock ELS traffic */
@@ -1190,7 +1853,7 @@
 		goto lpfc_mbx_cmpl_read_la_free_mbuf;
 	}
 
-	la = (READ_LA_VAR *) & pmb->mb.un.varReadLA;
+	la = (READ_LA_VAR *) &pmb->u.mb.un.varReadLA;
 
 	memcpy(&phba->alpa_map[0], mp->virt, 128);
 
@@ -1328,7 +1991,7 @@
 static void
 lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	struct lpfc_vport *vport = pmb->vport;
 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
 
@@ -1381,7 +2044,7 @@
 {
 	struct lpfc_vport *vport = pmb->vport;
 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 
 	switch (mb->mbxStatus) {
 	case 0x0011:
@@ -1416,6 +2079,128 @@
 	return;
 }
 
+/**
+ * lpfc_create_static_vport - Read HBA config region to create static vports.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine issue a DUMP mailbox command for config region 22 to get
+ * the list of static vports to be created. The function create vports
+ * based on the information returned from the HBA.
+ **/
+void
+lpfc_create_static_vport(struct lpfc_hba *phba)
+{
+	LPFC_MBOXQ_t *pmb = NULL;
+	MAILBOX_t *mb;
+	struct static_vport_info *vport_info;
+	int rc, i;
+	struct fc_vport_identifiers vport_id;
+	struct fc_vport *new_fc_vport;
+	struct Scsi_Host *shost;
+	struct lpfc_vport *vport;
+	uint16_t offset = 0;
+	uint8_t *vport_buff;
+
+	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!pmb) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0542 lpfc_create_static_vport failed to"
+				" allocate mailbox memory\n");
+		return;
+	}
+
+	mb = &pmb->u.mb;
+
+	vport_info = kzalloc(sizeof(struct static_vport_info), GFP_KERNEL);
+	if (!vport_info) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0543 lpfc_create_static_vport failed to"
+				" allocate vport_info\n");
+		mempool_free(pmb, phba->mbox_mem_pool);
+		return;
+	}
+
+	vport_buff = (uint8_t *) vport_info;
+	do {
+		lpfc_dump_static_vport(phba, pmb, offset);
+		pmb->vport = phba->pport;
+		rc = lpfc_sli_issue_mbox_wait(phba, pmb, LPFC_MBOX_TMO);
+
+		if ((rc != MBX_SUCCESS) || mb->mbxStatus) {
+			lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"0544 lpfc_create_static_vport failed to"
+				" issue dump mailbox command ret 0x%x "
+				"status 0x%x\n",
+				rc, mb->mbxStatus);
+			goto out;
+		}
+
+		if (mb->un.varDmp.word_cnt >
+			sizeof(struct static_vport_info) - offset)
+			mb->un.varDmp.word_cnt =
+			sizeof(struct static_vport_info) - offset;
+
+		lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
+			vport_buff + offset,
+			mb->un.varDmp.word_cnt);
+		offset += mb->un.varDmp.word_cnt;
+
+	} while (mb->un.varDmp.word_cnt &&
+		offset < sizeof(struct static_vport_info));
+
+
+	if ((le32_to_cpu(vport_info->signature) != VPORT_INFO_SIG) ||
+		((le32_to_cpu(vport_info->rev) & VPORT_INFO_REV_MASK)
+			!= VPORT_INFO_REV)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"0545 lpfc_create_static_vport bad"
+			" information header 0x%x 0x%x\n",
+			le32_to_cpu(vport_info->signature),
+			le32_to_cpu(vport_info->rev) & VPORT_INFO_REV_MASK);
+
+		goto out;
+	}
+
+	shost = lpfc_shost_from_vport(phba->pport);
+
+	for (i = 0; i < MAX_STATIC_VPORT_COUNT; i++) {
+		memset(&vport_id, 0, sizeof(vport_id));
+		vport_id.port_name = wwn_to_u64(vport_info->vport_list[i].wwpn);
+		vport_id.node_name = wwn_to_u64(vport_info->vport_list[i].wwnn);
+		if (!vport_id.port_name || !vport_id.node_name)
+			continue;
+
+		vport_id.roles = FC_PORT_ROLE_FCP_INITIATOR;
+		vport_id.vport_type = FC_PORTTYPE_NPIV;
+		vport_id.disable = false;
+		new_fc_vport = fc_vport_create(shost, 0, &vport_id);
+
+		if (!new_fc_vport) {
+			lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"0546 lpfc_create_static_vport failed to"
+				" create vport \n");
+			continue;
+		}
+
+		vport = *(struct lpfc_vport **)new_fc_vport->dd_data;
+		vport->vport_flag |= STATIC_VPORT;
+	}
+
+out:
+	/*
+	 * If this is timed out command, setting NULL to context2 tell SLI
+	 * layer not to use this buffer.
+	 */
+	spin_lock_irq(&phba->hbalock);
+	pmb->context2 = NULL;
+	spin_unlock_irq(&phba->hbalock);
+	kfree(vport_info);
+	if (rc != MBX_TIMEOUT)
+		mempool_free(pmb, phba->mbox_mem_pool);
+
+	return;
+}
+
 /*
  * This routine handles processing a Fabric REG_LOGIN mailbox
  * command upon completion. It is setup in the LPFC_MBOXQ
@@ -1426,16 +2211,17 @@
 lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
 	struct lpfc_vport *vport = pmb->vport;
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
 	struct lpfc_nodelist *ndlp;
-	struct lpfc_vport **vports;
-	int i;
 
 	ndlp = (struct lpfc_nodelist *) pmb->context2;
 	pmb->context1 = NULL;
 	pmb->context2 = NULL;
 	if (mb->mbxStatus) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+				 "0258 Register Fabric login error: 0x%x\n",
+				 mb->mbxStatus);
 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
 		kfree(mp);
 		mempool_free(pmb, phba->mbox_mem_pool);
@@ -1454,9 +2240,6 @@
 		}
 
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
-				 "0258 Register Fabric login error: 0x%x\n",
-				 mb->mbxStatus);
 		/* Decrement the reference count to ndlp after the reference
 		 * to the ndlp are done.
 		 */
@@ -1465,34 +2248,12 @@
 	}
 
 	ndlp->nlp_rpi = mb->un.varWords[0];
+	ndlp->nlp_flag |= NLP_RPI_VALID;
 	ndlp->nlp_type |= NLP_FABRIC;
 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
 
 	if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
-		vports = lpfc_create_vport_work_array(phba);
-		if (vports != NULL)
-			for(i = 0;
-			    i <= phba->max_vpi && vports[i] != NULL;
-			    i++) {
-				if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
-					continue;
-				if (phba->fc_topology == TOPOLOGY_LOOP) {
-					lpfc_vport_set_state(vports[i],
-							FC_VPORT_LINKDOWN);
-					continue;
-				}
-				if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
-					lpfc_initial_fdisc(vports[i]);
-				else {
-					lpfc_vport_set_state(vports[i],
-						FC_VPORT_NO_FABRIC_SUPP);
-					lpfc_printf_vlog(vport, KERN_ERR,
-							 LOG_ELS,
-							"0259 No NPIV "
-							"Fabric support\n");
-				}
-			}
-		lpfc_destroy_vport_work_array(phba, vports);
+		lpfc_start_fdiscs(phba);
 		lpfc_do_scr_ns_plogi(phba, vport);
 	}
 
@@ -1516,13 +2277,16 @@
 void
 lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
 	struct lpfc_vport *vport = pmb->vport;
 
 	if (mb->mbxStatus) {
 out:
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0260 Register NameServer error: 0x%x\n",
+				 mb->mbxStatus);
 		/* decrement the node reference count held for this
 		 * callback function.
 		 */
@@ -1546,15 +2310,13 @@
 			return;
 		}
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-				 "0260 Register NameServer error: 0x%x\n",
-				 mb->mbxStatus);
 		return;
 	}
 
 	pmb->context1 = NULL;
 
 	ndlp->nlp_rpi = mb->un.varWords[0];
+	ndlp->nlp_flag |= NLP_RPI_VALID;
 	ndlp->nlp_type |= NLP_FABRIC;
 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
 
@@ -2055,7 +2817,7 @@
 	if (pring->ringno == LPFC_ELS_RING) {
 		switch (icmd->ulpCommand) {
 		case CMD_GEN_REQUEST64_CR:
-			if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi)
+			if (iocb->context_un.ndlp == ndlp)
 				return 1;
 		case CMD_ELS_REQUEST64_CR:
 			if (icmd->un.elsreq64.remoteID == ndlp->nlp_DID)
@@ -2102,7 +2864,7 @@
 	 */
 	psli = &phba->sli;
 	rpi = ndlp->nlp_rpi;
-	if (rpi) {
+	if (ndlp->nlp_flag & NLP_RPI_VALID) {
 		/* Now process each ring */
 		for (i = 0; i < psli->num_rings; i++) {
 			pring = &psli->ring[i];
@@ -2150,7 +2912,7 @@
 	LPFC_MBOXQ_t    *mbox;
 	int rc;
 
-	if (ndlp->nlp_rpi) {
+	if (ndlp->nlp_flag & NLP_RPI_VALID) {
 		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 		if (mbox) {
 			lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox);
@@ -2162,6 +2924,7 @@
 		}
 		lpfc_no_rpi(phba, ndlp);
 		ndlp->nlp_rpi = 0;
+		ndlp->nlp_flag &= ~NLP_RPI_VALID;
 		return 1;
 	}
 	return 0;
@@ -2252,7 +3015,7 @@
 
 	/* cleanup any ndlp on mbox q waiting for reglogin cmpl */
 	if ((mb = phba->sli.mbox_active)) {
-		if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+		if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
 		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
 			mb->context2 = NULL;
 			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
@@ -2261,7 +3024,7 @@
 
 	spin_lock_irq(&phba->hbalock);
 	list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
-		if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+		if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
 		    (ndlp == (struct lpfc_nodelist *) mb->context2)) {
 			mp = (struct lpfc_dmabuf *) (mb->context1);
 			if (mp) {
@@ -2309,13 +3072,14 @@
 	int rc;
 
 	lpfc_cancel_retry_delay_tmo(vport, ndlp);
-	if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) {
+	if ((ndlp->nlp_flag & NLP_DEFER_RM) &&
+	    !(ndlp->nlp_flag & NLP_RPI_VALID)) {
 		/* For this case we need to cleanup the default rpi
 		 * allocated by the firmware.
 		 */
 		if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))
 			!= NULL) {
-			rc = lpfc_reg_login(phba, vport->vpi, ndlp->nlp_DID,
+			rc = lpfc_reg_rpi(phba, vport->vpi, ndlp->nlp_DID,
 			    (uint8_t *) &vport->fc_sparam, mbox, 0);
 			if (rc) {
 				mempool_free(mbox, phba->mbox_mem_pool);
@@ -2553,7 +3317,8 @@
 	 * clear_la then don't send it.
 	 */
 	if ((phba->link_state >= LPFC_CLEAR_LA) ||
-	    (vport->port_type != LPFC_PHYSICAL_PORT))
+	    (vport->port_type != LPFC_PHYSICAL_PORT) ||
+		(phba->sli_rev == LPFC_SLI_REV4))
 		return;
 
 			/* Link up discovery */
@@ -2582,7 +3347,7 @@
 
 	regvpimbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (regvpimbox) {
-		lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, regvpimbox);
+		lpfc_reg_vpi(vport, regvpimbox);
 		regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi;
 		regvpimbox->vport = vport;
 		if (lpfc_sli_issue_mbox(phba, regvpimbox, MBX_NOWAIT)
@@ -2642,7 +3407,8 @@
 	 */
 	if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
 	    !(vport->fc_flag & FC_PT2PT) &&
-	    !(vport->fc_flag & FC_RSCN_MODE)) {
+	    !(vport->fc_flag & FC_RSCN_MODE) &&
+	    (phba->sli_rev < LPFC_SLI_REV4)) {
 		lpfc_issue_reg_vpi(phba, vport);
 		return;
 	}
@@ -2919,11 +3685,13 @@
 		 * set port_state to PORT_READY if SLI2.
 		 * cmpl_reg_vpi will set port_state to READY for SLI3.
 		 */
-		if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
-			lpfc_issue_reg_vpi(phba, vport);
-		else  {	/* NPIV Not enabled */
-			lpfc_issue_clear_la(phba, vport);
-			vport->port_state = LPFC_VPORT_READY;
+		if (phba->sli_rev < LPFC_SLI_REV4) {
+			if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+				lpfc_issue_reg_vpi(phba, vport);
+			else  {	/* NPIV Not enabled */
+				lpfc_issue_clear_la(phba, vport);
+				vport->port_state = LPFC_VPORT_READY;
+			}
 		}
 
 		/* Setup and issue mailbox INITIALIZE LINK command */
@@ -2939,7 +3707,7 @@
 		lpfc_linkdown(phba);
 		lpfc_init_link(phba, initlinkmbox, phba->cfg_topology,
 			       phba->cfg_link_speed);
-		initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
+		initlinkmbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
 		initlinkmbox->vport = vport;
 		initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 		rc = lpfc_sli_issue_mbox(phba, initlinkmbox, MBX_NOWAIT);
@@ -2959,11 +3727,13 @@
 		 * set port_state to PORT_READY if SLI2.
 		 * cmpl_reg_vpi will set port_state to READY for SLI3.
 		 */
-		if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
-			lpfc_issue_reg_vpi(phba, vport);
-		else {	/* NPIV Not enabled */
-			lpfc_issue_clear_la(phba, vport);
-			vport->port_state = LPFC_VPORT_READY;
+		if (phba->sli_rev < LPFC_SLI_REV4) {
+			if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+				lpfc_issue_reg_vpi(phba, vport);
+			else  {	/* NPIV Not enabled */
+				lpfc_issue_clear_la(phba, vport);
+				vport->port_state = LPFC_VPORT_READY;
+			}
 		}
 		break;
 
@@ -3036,7 +3806,7 @@
 void
 lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	struct lpfc_dmabuf   *mp = (struct lpfc_dmabuf *) (pmb->context1);
 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
 	struct lpfc_vport    *vport = pmb->vport;
@@ -3044,6 +3814,7 @@
 	pmb->context1 = NULL;
 
 	ndlp->nlp_rpi = mb->un.varWords[0];
+	ndlp->nlp_flag |= NLP_RPI_VALID;
 	ndlp->nlp_type |= NLP_FABRIC;
 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
 
@@ -3297,3 +4068,395 @@
 			return 1;
 	return 0;
 }
+
+/**
+ * lpfc_fcf_inuse - Check if FCF can be unregistered.
+ * @phba: Pointer to hba context object.
+ *
+ * This function iterate through all FC nodes associated
+ * will all vports to check if there is any node with
+ * fc_rports associated with it. If there is an fc_rport
+ * associated with the node, then the node is either in
+ * discovered state or its devloss_timer is pending.
+ */
+static int
+lpfc_fcf_inuse(struct lpfc_hba *phba)
+{
+	struct lpfc_vport **vports;
+	int i, ret = 0;
+	struct lpfc_nodelist *ndlp;
+	struct Scsi_Host  *shost;
+
+	vports = lpfc_create_vport_work_array(phba);
+
+	for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+		shost = lpfc_shost_from_vport(vports[i]);
+		spin_lock_irq(shost->host_lock);
+		list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) {
+			if (NLP_CHK_NODE_ACT(ndlp) && ndlp->rport &&
+			  (ndlp->rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
+				ret = 1;
+				spin_unlock_irq(shost->host_lock);
+				goto out;
+			}
+		}
+		spin_unlock_irq(shost->host_lock);
+	}
+out:
+	lpfc_destroy_vport_work_array(phba, vports);
+	return ret;
+}
+
+/**
+ * lpfc_unregister_vfi_cmpl - Completion handler for unreg vfi.
+ * @phba: Pointer to hba context object.
+ * @mboxq: Pointer to mailbox object.
+ *
+ * This function frees memory associated with the mailbox command.
+ */
+static void
+lpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+	struct lpfc_vport *vport = mboxq->vport;
+
+	if (mboxq->u.mb.mbxStatus) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+			"2555 UNREG_VFI mbxStatus error x%x "
+			"HBA state x%x\n",
+			mboxq->u.mb.mbxStatus, vport->port_state);
+	}
+	mempool_free(mboxq, phba->mbox_mem_pool);
+	return;
+}
+
+/**
+ * lpfc_unregister_fcfi_cmpl - Completion handler for unreg fcfi.
+ * @phba: Pointer to hba context object.
+ * @mboxq: Pointer to mailbox object.
+ *
+ * This function frees memory associated with the mailbox command.
+ */
+static void
+lpfc_unregister_fcfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+	struct lpfc_vport *vport = mboxq->vport;
+
+	if (mboxq->u.mb.mbxStatus) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+			"2550 UNREG_FCFI mbxStatus error x%x "
+			"HBA state x%x\n",
+			mboxq->u.mb.mbxStatus, vport->port_state);
+	}
+	mempool_free(mboxq, phba->mbox_mem_pool);
+	return;
+}
+
+/**
+ * lpfc_unregister_unused_fcf - Unregister FCF if all devices are disconnected.
+ * @phba: Pointer to hba context object.
+ *
+ * This function check if there are any connected remote port for the FCF and
+ * if all the devices are disconnected, this function unregister FCFI.
+ * This function also tries to use another FCF for discovery.
+ */
+void
+lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
+{
+	LPFC_MBOXQ_t *mbox;
+	int rc;
+	struct lpfc_vport **vports;
+	int i;
+
+	spin_lock_irq(&phba->hbalock);
+	/*
+	 * If HBA is not running in FIP mode or
+	 * If HBA does not support FCoE or
+	 * If FCF is not registered.
+	 * do nothing.
+	 */
+	if (!(phba->hba_flag & HBA_FCOE_SUPPORT) ||
+		!(phba->fcf.fcf_flag & FCF_REGISTERED) ||
+		(phba->cfg_enable_fip == 0)) {
+		spin_unlock_irq(&phba->hbalock);
+		return;
+	}
+	spin_unlock_irq(&phba->hbalock);
+
+	if (lpfc_fcf_inuse(phba))
+		return;
+
+
+	/* Unregister VPIs */
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports &&
+		(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED))
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+			lpfc_mbx_unreg_vpi(vports[i]);
+			vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+			vports[i]->vfi_state &= ~LPFC_VFI_REGISTERED;
+		}
+	lpfc_destroy_vport_work_array(phba, vports);
+
+	/* Unregister VFI */
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+			"2556 UNREG_VFI mbox allocation failed"
+			"HBA state x%x\n",
+			phba->pport->port_state);
+		return;
+	}
+
+	lpfc_unreg_vfi(mbox, phba->pport->vfi);
+	mbox->vport = phba->pport;
+	mbox->mbox_cmpl = lpfc_unregister_vfi_cmpl;
+
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+	if (rc == MBX_NOT_FINISHED) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+			"2557 UNREG_VFI issue mbox failed rc x%x "
+			"HBA state x%x\n",
+			rc, phba->pport->port_state);
+		mempool_free(mbox, phba->mbox_mem_pool);
+		return;
+	}
+
+	/* Unregister FCF */
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+			"2551 UNREG_FCFI mbox allocation failed"
+			"HBA state x%x\n",
+			phba->pport->port_state);
+		return;
+	}
+
+	lpfc_unreg_fcfi(mbox, phba->fcf.fcfi);
+	mbox->vport = phba->pport;
+	mbox->mbox_cmpl = lpfc_unregister_fcfi_cmpl;
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+
+	if (rc == MBX_NOT_FINISHED) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+			"2552 UNREG_FCFI issue mbox failed rc x%x "
+			"HBA state x%x\n",
+			rc, phba->pport->port_state);
+		mempool_free(mbox, phba->mbox_mem_pool);
+		return;
+	}
+
+	spin_lock_irq(&phba->hbalock);
+	phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_REGISTERED |
+		FCF_DISCOVERED | FCF_BOOT_ENABLE | FCF_IN_USE |
+		FCF_VALID_VLAN);
+	spin_unlock_irq(&phba->hbalock);
+
+	/*
+	 * If driver is not unloading, check if there is any other
+	 * FCF record that can be used for discovery.
+	 */
+	if ((phba->pport->load_flag & FC_UNLOADING) ||
+		(phba->link_state < LPFC_LINK_UP))
+		return;
+
+	rc = lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
+
+	if (rc)
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+			"2553 lpfc_unregister_unused_fcf failed to read FCF"
+			" record HBA state x%x\n",
+			phba->pport->port_state);
+}
+
+/**
+ * lpfc_read_fcf_conn_tbl - Create driver FCF connection table.
+ * @phba: Pointer to hba context object.
+ * @buff: Buffer containing the FCF connection table as in the config
+ *         region.
+ * This function create driver data structure for the FCF connection
+ * record table read from config region 23.
+ */
+static void
+lpfc_read_fcf_conn_tbl(struct lpfc_hba *phba,
+	uint8_t *buff)
+{
+	struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry;
+	struct lpfc_fcf_conn_hdr *conn_hdr;
+	struct lpfc_fcf_conn_rec *conn_rec;
+	uint32_t record_count;
+	int i;
+
+	/* Free the current connect table */
+	list_for_each_entry_safe(conn_entry, next_conn_entry,
+		&phba->fcf_conn_rec_list, list)
+		kfree(conn_entry);
+
+	conn_hdr = (struct lpfc_fcf_conn_hdr *) buff;
+	record_count = conn_hdr->length * sizeof(uint32_t)/
+		sizeof(struct lpfc_fcf_conn_rec);
+
+	conn_rec = (struct lpfc_fcf_conn_rec *)
+		(buff + sizeof(struct lpfc_fcf_conn_hdr));
+
+	for (i = 0; i < record_count; i++) {
+		if (!(conn_rec[i].flags & FCFCNCT_VALID))
+			continue;
+		conn_entry = kzalloc(sizeof(struct lpfc_fcf_conn_entry),
+			GFP_KERNEL);
+		if (!conn_entry) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2566 Failed to allocate connection"
+				" table entry\n");
+			return;
+		}
+
+		memcpy(&conn_entry->conn_rec, &conn_rec[i],
+			sizeof(struct lpfc_fcf_conn_rec));
+		conn_entry->conn_rec.vlan_tag =
+			le16_to_cpu(conn_entry->conn_rec.vlan_tag) & 0xFFF;
+		conn_entry->conn_rec.flags =
+			le16_to_cpu(conn_entry->conn_rec.flags);
+		list_add_tail(&conn_entry->list,
+			&phba->fcf_conn_rec_list);
+	}
+}
+
+/**
+ * lpfc_read_fcoe_param - Read FCoe parameters from conf region..
+ * @phba: Pointer to hba context object.
+ * @buff: Buffer containing the FCoE parameter data structure.
+ *
+ *  This function update driver data structure with config
+ *  parameters read from config region 23.
+ */
+static void
+lpfc_read_fcoe_param(struct lpfc_hba *phba,
+			uint8_t *buff)
+{
+	struct lpfc_fip_param_hdr *fcoe_param_hdr;
+	struct lpfc_fcoe_params *fcoe_param;
+
+	fcoe_param_hdr = (struct lpfc_fip_param_hdr *)
+		buff;
+	fcoe_param = (struct lpfc_fcoe_params *)
+		buff + sizeof(struct lpfc_fip_param_hdr);
+
+	if ((fcoe_param_hdr->parm_version != FIPP_VERSION) ||
+		(fcoe_param_hdr->length != FCOE_PARAM_LENGTH))
+		return;
+
+	if (bf_get(lpfc_fip_param_hdr_fipp_mode, fcoe_param_hdr) ==
+			FIPP_MODE_ON)
+		phba->cfg_enable_fip = 1;
+
+	if (bf_get(lpfc_fip_param_hdr_fipp_mode, fcoe_param_hdr) ==
+		FIPP_MODE_OFF)
+		phba->cfg_enable_fip = 0;
+
+	if (fcoe_param_hdr->parm_flags & FIPP_VLAN_VALID) {
+		phba->valid_vlan = 1;
+		phba->vlan_id = le16_to_cpu(fcoe_param->vlan_tag) &
+			0xFFF;
+	}
+
+	phba->fc_map[0] = fcoe_param->fc_map[0];
+	phba->fc_map[1] = fcoe_param->fc_map[1];
+	phba->fc_map[2] = fcoe_param->fc_map[2];
+	return;
+}
+
+/**
+ * lpfc_get_rec_conf23 - Get a record type in config region data.
+ * @buff: Buffer containing config region 23 data.
+ * @size: Size of the data buffer.
+ * @rec_type: Record type to be searched.
+ *
+ * This function searches config region data to find the begining
+ * of the record specified by record_type. If record found, this
+ * function return pointer to the record else return NULL.
+ */
+static uint8_t *
+lpfc_get_rec_conf23(uint8_t *buff, uint32_t size, uint8_t rec_type)
+{
+	uint32_t offset = 0, rec_length;
+
+	if ((buff[0] == LPFC_REGION23_LAST_REC) ||
+		(size < sizeof(uint32_t)))
+		return NULL;
+
+	rec_length = buff[offset + 1];
+
+	/*
+	 * One TLV record has one word header and number of data words
+	 * specified in the rec_length field of the record header.
+	 */
+	while ((offset + rec_length * sizeof(uint32_t) + sizeof(uint32_t))
+		<= size) {
+		if (buff[offset] == rec_type)
+			return &buff[offset];
+
+		if (buff[offset] == LPFC_REGION23_LAST_REC)
+			return NULL;
+
+		offset += rec_length * sizeof(uint32_t) + sizeof(uint32_t);
+		rec_length = buff[offset + 1];
+	}
+	return NULL;
+}
+
+/**
+ * lpfc_parse_fcoe_conf - Parse FCoE config data read from config region 23.
+ * @phba: Pointer to lpfc_hba data structure.
+ * @buff: Buffer containing config region 23 data.
+ * @size: Size of the data buffer.
+ *
+ * This fuction parse the FCoE config parameters in config region 23 and
+ * populate driver data structure with the parameters.
+ */
+void
+lpfc_parse_fcoe_conf(struct lpfc_hba *phba,
+		uint8_t *buff,
+		uint32_t size)
+{
+	uint32_t offset = 0, rec_length;
+	uint8_t *rec_ptr;
+
+	/*
+	 * If data size is less than 2 words signature and version cannot be
+	 * verified.
+	 */
+	if (size < 2*sizeof(uint32_t))
+		return;
+
+	/* Check the region signature first */
+	if (memcmp(buff, LPFC_REGION23_SIGNATURE, 4)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"2567 Config region 23 has bad signature\n");
+		return;
+	}
+
+	offset += 4;
+
+	/* Check the data structure version */
+	if (buff[offset] != LPFC_REGION23_VERSION) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"2568 Config region 23 has bad version\n");
+		return;
+	}
+	offset += 4;
+
+	rec_length = buff[offset + 1];
+
+	/* Read FCoE param record */
+	rec_ptr = lpfc_get_rec_conf23(&buff[offset],
+			size - offset, FCOE_PARAM_TYPE);
+	if (rec_ptr)
+		lpfc_read_fcoe_param(phba, rec_ptr);
+
+	/* Read FCF connection table */
+	rec_ptr = lpfc_get_rec_conf23(&buff[offset],
+		size - offset, FCOE_CONN_TBL_TYPE);
+	if (rec_ptr)
+		lpfc_read_fcf_conn_tbl(phba, rec_ptr);
+
+}
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 4168c7b..02aa016 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-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -471,6 +471,35 @@
 };
 
 /*
+ * Virtual Fabric Tagging Header
+ */
+struct fc_vft_header {
+	 uint32_t word0;
+#define fc_vft_hdr_r_ctl_SHIFT		24
+#define fc_vft_hdr_r_ctl_MASK		0xFF
+#define fc_vft_hdr_r_ctl_WORD		word0
+#define fc_vft_hdr_ver_SHIFT		22
+#define fc_vft_hdr_ver_MASK		0x3
+#define fc_vft_hdr_ver_WORD		word0
+#define fc_vft_hdr_type_SHIFT		18
+#define fc_vft_hdr_type_MASK		0xF
+#define fc_vft_hdr_type_WORD		word0
+#define fc_vft_hdr_e_SHIFT		16
+#define fc_vft_hdr_e_MASK		0x1
+#define fc_vft_hdr_e_WORD		word0
+#define fc_vft_hdr_priority_SHIFT	13
+#define fc_vft_hdr_priority_MASK	0x7
+#define fc_vft_hdr_priority_WORD	word0
+#define fc_vft_hdr_vf_id_SHIFT		1
+#define fc_vft_hdr_vf_id_MASK		0xFFF
+#define fc_vft_hdr_vf_id_WORD		word0
+	uint32_t word1;
+#define fc_vft_hdr_hopct_SHIFT		24
+#define fc_vft_hdr_hopct_MASK		0xFF
+#define fc_vft_hdr_hopct_WORD		word1
+};
+
+/*
  *  Extended Link Service LS_COMMAND codes (Payload Word 0)
  */
 #ifdef __BIG_ENDIAN_BITFIELD
@@ -1152,6 +1181,9 @@
 #define PCI_DEVICE_ID_HORNET        0xfe05
 #define PCI_DEVICE_ID_ZEPHYR_SCSP   0xfe11
 #define PCI_DEVICE_ID_ZEPHYR_DCSP   0xfe12
+#define PCI_VENDOR_ID_SERVERENGINE  0x19a2
+#define PCI_DEVICE_ID_TIGERSHARK    0x0704
+#define PCI_DEVICE_ID_TIGERSHARK_S  0x0705
 
 #define JEDEC_ID_ADDRESS            0x0080001c
 #define FIREFLY_JEDEC_ID            0x1ACC
@@ -1342,15 +1374,21 @@
 #define MBX_READ_LA64       0x95
 #define MBX_REG_VPI	    0x96
 #define MBX_UNREG_VPI	    0x97
-#define MBX_REG_VNPID	    0x96
-#define MBX_UNREG_VNPID	    0x97
 
 #define MBX_WRITE_WWN       0x98
 #define MBX_SET_DEBUG       0x99
 #define MBX_LOAD_EXP_ROM    0x9C
-
-#define MBX_MAX_CMDS        0x9D
+#define MBX_SLI4_CONFIG	    0x9B
+#define MBX_SLI4_REQ_FTRS   0x9D
+#define MBX_MAX_CMDS        0x9E
+#define MBX_RESUME_RPI      0x9E
 #define MBX_SLI2_CMD_MASK   0x80
+#define MBX_REG_VFI         0x9F
+#define MBX_REG_FCFI        0xA0
+#define MBX_UNREG_VFI       0xA1
+#define MBX_UNREG_FCFI	    0xA2
+#define MBX_INIT_VFI        0xA3
+#define MBX_INIT_VPI        0xA4
 
 /* IOCB Commands */
 
@@ -1440,6 +1478,16 @@
 #define CMD_IOCB_LOGENTRY_CN		0x94
 #define CMD_IOCB_LOGENTRY_ASYNC_CN	0x96
 
+/* Unhandled Data Security SLI Commands */
+#define DSSCMD_IWRITE64_CR 		0xD8
+#define DSSCMD_IWRITE64_CX		0xD9
+#define DSSCMD_IREAD64_CR		0xDA
+#define DSSCMD_IREAD64_CX		0xDB
+#define DSSCMD_INVALIDATE_DEK		0xDC
+#define DSSCMD_SET_KEK			0xDD
+#define DSSCMD_GET_KEK_ID		0xDE
+#define DSSCMD_GEN_XFER			0xDF
+
 #define CMD_MAX_IOCB_CMD        0xE6
 #define CMD_IOCB_MASK           0xff
 
@@ -1466,6 +1514,7 @@
 #define MBXERR_BAD_RCV_LENGTH       14
 #define MBXERR_DMA_ERROR            15
 #define MBXERR_ERROR                16
+#define MBXERR_LINK_DOWN            0x33
 #define MBX_NOT_FINISHED           255
 
 #define MBX_BUSY                   0xffffff /* Attempted cmd to busy Mailbox */
@@ -1504,32 +1553,6 @@
 #endif
 };
 
-struct ulp_bde64 {	/* SLI-2 */
-	union ULP_BDE_TUS {
-		uint32_t w;
-		struct {
-#ifdef __BIG_ENDIAN_BITFIELD
-			uint32_t bdeFlags:8;	/* BDE Flags 0 IS A SUPPORTED
-						   VALUE !! */
-			uint32_t bdeSize:24;	/* Size of buffer (in bytes) */
-#else	/*  __LITTLE_ENDIAN_BITFIELD */
-			uint32_t bdeSize:24;	/* Size of buffer (in bytes) */
-			uint32_t bdeFlags:8;	/* BDE Flags 0 IS A SUPPORTED
-						   VALUE !! */
-#endif
-#define BUFF_TYPE_BDE_64    0x00	/* BDE (Host_resident) */
-#define BUFF_TYPE_BDE_IMMED 0x01	/* Immediate Data BDE */
-#define BUFF_TYPE_BDE_64P   0x02	/* BDE (Port-resident) */
-#define BUFF_TYPE_BDE_64I   0x08	/* Input BDE (Host-resident) */
-#define BUFF_TYPE_BDE_64IP  0x0A	/* Input BDE (Port-resident) */
-#define BUFF_TYPE_BLP_64    0x40	/* BLP (Host-resident) */
-#define BUFF_TYPE_BLP_64P   0x42	/* BLP (Port-resident) */
-		} f;
-	} tus;
-	uint32_t addrLow;
-	uint32_t addrHigh;
-};
-
 typedef struct ULP_BDL {	/* SLI-2 */
 #ifdef __BIG_ENDIAN_BITFIELD
 	uint32_t bdeFlags:8;	/* BDL Flags */
@@ -2287,7 +2310,7 @@
 	uint32_t rsvd3;
 	uint32_t rsvd4;
 	uint32_t rsvd5;
-	uint16_t rsvd6;
+	uint16_t vfi;
 	uint16_t vpi;
 #else	/*  __LITTLE_ENDIAN */
 	uint32_t rsvd1;
@@ -2297,7 +2320,7 @@
 	uint32_t rsvd4;
 	uint32_t rsvd5;
 	uint16_t vpi;
-	uint16_t rsvd6;
+	uint16_t vfi;
 #endif
 } REG_VPI_VAR;
 
@@ -2457,7 +2480,7 @@
 	uint32_t entry_index:16;
 #endif
 
-	uint32_t rsvd1;
+	uint32_t sli4_length;
 	uint32_t word_cnt;
 	uint32_t resp_offset;
 } DUMP_VAR;
@@ -2470,9 +2493,32 @@
 #define  DMP_RSP_OFFSET          0x14   /* word 5 contains first word of rsp */
 #define  DMP_RSP_SIZE            0x6C   /* maximum of 27 words of rsp data */
 
+#define  DMP_REGION_VPORT	 0x16   /* VPort info region */
+#define  DMP_VPORT_REGION_SIZE	 0x200
+#define  DMP_MBOX_OFFSET_WORD	 0x5
+
+#define  DMP_REGION_FCOEPARAM	 0x17   /* fcoe param region */
+#define  DMP_FCOEPARAM_RGN_SIZE	 0x400
+
 #define  WAKE_UP_PARMS_REGION_ID    4
 #define  WAKE_UP_PARMS_WORD_SIZE   15
 
+struct vport_rec {
+	uint8_t wwpn[8];
+	uint8_t wwnn[8];
+};
+
+#define VPORT_INFO_SIG 0x32324752
+#define VPORT_INFO_REV_MASK 0xff
+#define VPORT_INFO_REV 0x1
+#define MAX_STATIC_VPORT_COUNT 16
+struct static_vport_info {
+	uint32_t 		signature;
+	uint32_t		rev;
+	struct vport_rec 	vport_list[MAX_STATIC_VPORT_COUNT];
+	uint32_t		resvd[66];
+};
+
 /* Option rom version structure */
 struct prog_id {
 #ifdef __BIG_ENDIAN_BITFIELD
@@ -2697,7 +2743,9 @@
 #endif
 
 #ifdef __BIG_ENDIAN_BITFIELD
-	uint32_t rsvd1     : 23;  /* Reserved                             */
+	uint32_t rsvd1     : 19;  /* Reserved                             */
+	uint32_t cdss      :  1;  /* Configure Data Security SLI          */
+	uint32_t rsvd2     :  3;  /* Reserved                             */
 	uint32_t cbg       :  1;  /* Configure BlockGuard                 */
 	uint32_t cmv       :  1;  /* Configure Max VPIs                   */
 	uint32_t ccrp      :  1;  /* Config Command Ring Polling          */
@@ -2717,10 +2765,14 @@
 	uint32_t ccrp      :  1;  /* Config Command Ring Polling          */
 	uint32_t cmv	   :  1;  /* Configure Max VPIs                   */
 	uint32_t cbg       :  1;  /* Configure BlockGuard                 */
-	uint32_t rsvd1     : 23;  /* Reserved                             */
+	uint32_t rsvd2     :  3;  /* Reserved                             */
+	uint32_t cdss      :  1;  /* Configure Data Security SLI          */
+	uint32_t rsvd1     : 19;  /* Reserved                             */
 #endif
 #ifdef __BIG_ENDIAN_BITFIELD
-	uint32_t rsvd2     : 23;  /* Reserved                             */
+	uint32_t rsvd3     : 19;  /* Reserved                             */
+	uint32_t gdss      :  1;  /* Configure Data Security SLI          */
+	uint32_t rsvd4     :  3;  /* Reserved                             */
 	uint32_t gbg       :  1;  /* Grant BlockGuard                     */
 	uint32_t gmv	   :  1;  /* Grant Max VPIs                       */
 	uint32_t gcrp	   :  1;  /* Grant Command Ring Polling           */
@@ -2740,7 +2792,9 @@
 	uint32_t gcrp	   :  1;  /* Grant Command Ring Polling           */
 	uint32_t gmv	   :  1;  /* Grant Max VPIs                       */
 	uint32_t gbg       :  1;  /* Grant BlockGuard                     */
-	uint32_t rsvd2     : 23;  /* Reserved                             */
+	uint32_t rsvd4     :  3;  /* Reserved                             */
+	uint32_t gdss      :  1;  /* Configure Data Security SLI          */
+	uint32_t rsvd3     : 19;  /* Reserved                             */
 #endif
 
 #ifdef __BIG_ENDIAN_BITFIELD
@@ -2753,20 +2807,20 @@
 
 #ifdef __BIG_ENDIAN_BITFIELD
 	uint32_t max_hbq   : 16;  /* Max HBQs Host expect to configure    */
-	uint32_t rsvd3     : 16;  /* Max HBQs Host expect to configure    */
+	uint32_t rsvd5     : 16;  /* Max HBQs Host expect to configure    */
 #else	/*  __LITTLE_ENDIAN */
-	uint32_t rsvd3     : 16;  /* Max HBQs Host expect to configure    */
+	uint32_t rsvd5     : 16;  /* Max HBQs Host expect to configure    */
 	uint32_t max_hbq   : 16;  /* Max HBQs Host expect to configure    */
 #endif
 
-	uint32_t rsvd4;           /* Reserved                             */
+	uint32_t rsvd6;           /* Reserved                             */
 
 #ifdef __BIG_ENDIAN_BITFIELD
-	uint32_t rsvd5      : 16;  /* Reserved                             */
+	uint32_t rsvd7      : 16;  /* Reserved                             */
 	uint32_t max_vpi    : 16;  /* Max number of virt N-Ports           */
 #else	/*  __LITTLE_ENDIAN */
 	uint32_t max_vpi    : 16;  /* Max number of virt N-Ports           */
-	uint32_t rsvd5      : 16;  /* Reserved                             */
+	uint32_t rsvd7      : 16;  /* Reserved                             */
 #endif
 
 } CONFIG_PORT_VAR;
@@ -3666,3 +3720,5 @@
 #define MENLO_TIMEOUT 30
 #define SETVAR_MLOMNT 0x103107
 #define SETVAR_MLORST 0x103007
+
+#define BPL_ALIGN_SZ 8 /* 8 byte alignment for bpl and mbufs */
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
new file mode 100644
index 0000000..39c34b3
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -0,0 +1,2141 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2009 Emulex.  All rights reserved.                *
+ * EMULEX and SLI are trademarks of Emulex.                        *
+ * www.emulex.com                                                  *
+ *                                                                 *
+ * 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. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
+ *******************************************************************/
+
+/* Macros to deal with bit fields. Each bit field must have 3 #defines
+ * associated with it (_SHIFT, _MASK, and _WORD).
+ * EG. For a bit field that is in the 7th bit of the "field4" field of a
+ * structure and is 2 bits in size the following #defines must exist:
+ *	struct temp {
+ *		uint32_t	field1;
+ *		uint32_t	field2;
+ *		uint32_t	field3;
+ *		uint32_t	field4;
+ *	#define example_bit_field_SHIFT		7
+ *	#define example_bit_field_MASK		0x03
+ *	#define example_bit_field_WORD		field4
+ *		uint32_t	field5;
+ *	};
+ * Then the macros below may be used to get or set the value of that field.
+ * EG. To get the value of the bit field from the above example:
+ *	struct temp t1;
+ *	value = bf_get(example_bit_field, &t1);
+ * And then to set that bit field:
+ *	bf_set(example_bit_field, &t1, 2);
+ * Or clear that bit field:
+ *	bf_set(example_bit_field, &t1, 0);
+ */
+#define bf_get(name, ptr) \
+	(((ptr)->name##_WORD >> name##_SHIFT) & name##_MASK)
+#define bf_set(name, ptr, value) \
+	((ptr)->name##_WORD = ((((value) & name##_MASK) << name##_SHIFT) | \
+		 ((ptr)->name##_WORD & ~(name##_MASK << name##_SHIFT))))
+
+struct dma_address {
+	uint32_t addr_lo;
+	uint32_t addr_hi;
+};
+
+#define LPFC_SLI4_BAR0		1
+#define LPFC_SLI4_BAR1		2
+#define LPFC_SLI4_BAR2		4
+
+#define LPFC_SLI4_MBX_EMBED	true
+#define LPFC_SLI4_MBX_NEMBED	false
+
+#define LPFC_SLI4_MB_WORD_COUNT		64
+#define LPFC_MAX_MQ_PAGE		8
+#define LPFC_MAX_WQ_PAGE		8
+#define LPFC_MAX_CQ_PAGE		4
+#define LPFC_MAX_EQ_PAGE		8
+
+#define LPFC_VIR_FUNC_MAX       32 /* Maximum number of virtual functions */
+#define LPFC_PCI_FUNC_MAX        5 /* Maximum number of PCI functions */
+#define LPFC_VFR_PAGE_SIZE	0x1000 /* 4KB BAR2 per-VF register page size */
+
+/* Define SLI4 Alignment requirements. */
+#define LPFC_ALIGN_16_BYTE	16
+#define LPFC_ALIGN_64_BYTE	64
+
+/* Define SLI4 specific definitions. */
+#define LPFC_MQ_CQE_BYTE_OFFSET	256
+#define LPFC_MBX_CMD_HDR_LENGTH 16
+#define LPFC_MBX_ERROR_RANGE	0x4000
+#define LPFC_BMBX_BIT1_ADDR_HI	0x2
+#define LPFC_BMBX_BIT1_ADDR_LO	0
+#define LPFC_RPI_HDR_COUNT	64
+#define LPFC_HDR_TEMPLATE_SIZE	4096
+#define LPFC_RPI_ALLOC_ERROR 	0xFFFF
+#define LPFC_FCF_RECORD_WD_CNT	132
+#define LPFC_ENTIRE_FCF_DATABASE 0
+#define LPFC_DFLT_FCF_INDEX	 0
+
+/* Virtual function numbers */
+#define LPFC_VF0		0
+#define LPFC_VF1		1
+#define LPFC_VF2		2
+#define LPFC_VF3		3
+#define LPFC_VF4		4
+#define LPFC_VF5		5
+#define LPFC_VF6		6
+#define LPFC_VF7		7
+#define LPFC_VF8		8
+#define LPFC_VF9		9
+#define LPFC_VF10		10
+#define LPFC_VF11		11
+#define LPFC_VF12		12
+#define LPFC_VF13		13
+#define LPFC_VF14		14
+#define LPFC_VF15		15
+#define LPFC_VF16		16
+#define LPFC_VF17		17
+#define LPFC_VF18		18
+#define LPFC_VF19		19
+#define LPFC_VF20		20
+#define LPFC_VF21		21
+#define LPFC_VF22		22
+#define LPFC_VF23		23
+#define LPFC_VF24		24
+#define LPFC_VF25		25
+#define LPFC_VF26		26
+#define LPFC_VF27		27
+#define LPFC_VF28		28
+#define LPFC_VF29		29
+#define LPFC_VF30		30
+#define LPFC_VF31		31
+
+/* PCI function numbers */
+#define LPFC_PCI_FUNC0		0
+#define LPFC_PCI_FUNC1		1
+#define LPFC_PCI_FUNC2		2
+#define LPFC_PCI_FUNC3		3
+#define LPFC_PCI_FUNC4		4
+
+/* Active interrupt test count */
+#define LPFC_ACT_INTR_CNT	4
+
+/* Delay Multiplier constant */
+#define LPFC_DMULT_CONST       651042
+#define LPFC_MIM_IMAX          636
+#define LPFC_FP_DEF_IMAX       10000
+#define LPFC_SP_DEF_IMAX       10000
+
+struct ulp_bde64 {
+	union ULP_BDE_TUS {
+		uint32_t w;
+		struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+			uint32_t bdeFlags:8;	/* BDE Flags 0 IS A SUPPORTED
+						   VALUE !! */
+			uint32_t bdeSize:24;	/* Size of buffer (in bytes) */
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+			uint32_t bdeSize:24;	/* Size of buffer (in bytes) */
+			uint32_t bdeFlags:8;	/* BDE Flags 0 IS A SUPPORTED
+						   VALUE !! */
+#endif
+#define BUFF_TYPE_BDE_64    0x00	/* BDE (Host_resident) */
+#define BUFF_TYPE_BDE_IMMED 0x01	/* Immediate Data BDE */
+#define BUFF_TYPE_BDE_64P   0x02	/* BDE (Port-resident) */
+#define BUFF_TYPE_BDE_64I   0x08	/* Input BDE (Host-resident) */
+#define BUFF_TYPE_BDE_64IP  0x0A	/* Input BDE (Port-resident) */
+#define BUFF_TYPE_BLP_64    0x40	/* BLP (Host-resident) */
+#define BUFF_TYPE_BLP_64P   0x42	/* BLP (Port-resident) */
+		} f;
+	} tus;
+	uint32_t addrLow;
+	uint32_t addrHigh;
+};
+
+struct lpfc_sli4_flags {
+	uint32_t word0;
+#define lpfc_fip_flag_SHIFT 0
+#define lpfc_fip_flag_MASK 0x00000001
+#define lpfc_fip_flag_WORD word0
+};
+
+/* event queue entry structure */
+struct lpfc_eqe {
+	uint32_t word0;
+#define lpfc_eqe_resource_id_SHIFT	16
+#define lpfc_eqe_resource_id_MASK	0x000000FF
+#define lpfc_eqe_resource_id_WORD	word0
+#define lpfc_eqe_minor_code_SHIFT	4
+#define lpfc_eqe_minor_code_MASK	0x00000FFF
+#define lpfc_eqe_minor_code_WORD	word0
+#define lpfc_eqe_major_code_SHIFT	1
+#define lpfc_eqe_major_code_MASK	0x00000007
+#define lpfc_eqe_major_code_WORD	word0
+#define lpfc_eqe_valid_SHIFT		0
+#define lpfc_eqe_valid_MASK		0x00000001
+#define lpfc_eqe_valid_WORD		word0
+};
+
+/* completion queue entry structure (common fields for all cqe types) */
+struct lpfc_cqe {
+	uint32_t reserved0;
+	uint32_t reserved1;
+	uint32_t reserved2;
+	uint32_t word3;
+#define lpfc_cqe_valid_SHIFT		31
+#define lpfc_cqe_valid_MASK		0x00000001
+#define lpfc_cqe_valid_WORD		word3
+#define lpfc_cqe_code_SHIFT		16
+#define lpfc_cqe_code_MASK		0x000000FF
+#define lpfc_cqe_code_WORD		word3
+};
+
+/* Completion Queue Entry Status Codes */
+#define CQE_STATUS_SUCCESS		0x0
+#define CQE_STATUS_FCP_RSP_FAILURE	0x1
+#define CQE_STATUS_REMOTE_STOP		0x2
+#define CQE_STATUS_LOCAL_REJECT		0x3
+#define CQE_STATUS_NPORT_RJT		0x4
+#define CQE_STATUS_FABRIC_RJT		0x5
+#define CQE_STATUS_NPORT_BSY		0x6
+#define CQE_STATUS_FABRIC_BSY		0x7
+#define CQE_STATUS_INTERMED_RSP		0x8
+#define CQE_STATUS_LS_RJT		0x9
+#define CQE_STATUS_CMD_REJECT		0xb
+#define CQE_STATUS_FCP_TGT_LENCHECK	0xc
+#define CQE_STATUS_NEED_BUFF_ENTRY	0xf
+
+/* Status returned by hardware (valid only if status = CQE_STATUS_SUCCESS). */
+#define CQE_HW_STATUS_NO_ERR		0x0
+#define CQE_HW_STATUS_UNDERRUN		0x1
+#define CQE_HW_STATUS_OVERRUN		0x2
+
+/* Completion Queue Entry Codes */
+#define CQE_CODE_COMPL_WQE		0x1
+#define CQE_CODE_RELEASE_WQE		0x2
+#define CQE_CODE_RECEIVE		0x4
+#define CQE_CODE_XRI_ABORTED		0x5
+
+/* completion queue entry for wqe completions */
+struct lpfc_wcqe_complete {
+	uint32_t word0;
+#define lpfc_wcqe_c_request_tag_SHIFT	16
+#define lpfc_wcqe_c_request_tag_MASK	0x0000FFFF
+#define lpfc_wcqe_c_request_tag_WORD	word0
+#define lpfc_wcqe_c_status_SHIFT	8
+#define lpfc_wcqe_c_status_MASK		0x000000FF
+#define lpfc_wcqe_c_status_WORD		word0
+#define lpfc_wcqe_c_hw_status_SHIFT	0
+#define lpfc_wcqe_c_hw_status_MASK	0x000000FF
+#define lpfc_wcqe_c_hw_status_WORD	word0
+	uint32_t total_data_placed;
+	uint32_t parameter;
+	uint32_t word3;
+#define lpfc_wcqe_c_valid_SHIFT		lpfc_cqe_valid_SHIFT
+#define lpfc_wcqe_c_valid_MASK		lpfc_cqe_valid_MASK
+#define lpfc_wcqe_c_valid_WORD		lpfc_cqe_valid_WORD
+#define lpfc_wcqe_c_xb_SHIFT		28
+#define lpfc_wcqe_c_xb_MASK		0x00000001
+#define lpfc_wcqe_c_xb_WORD		word3
+#define lpfc_wcqe_c_pv_SHIFT		27
+#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_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
+};
+
+/* completion queue entry for wqe release */
+struct lpfc_wcqe_release {
+	uint32_t reserved0;
+	uint32_t reserved1;
+	uint32_t word2;
+#define lpfc_wcqe_r_wq_id_SHIFT		16
+#define lpfc_wcqe_r_wq_id_MASK		0x0000FFFF
+#define lpfc_wcqe_r_wq_id_WORD		word2
+#define lpfc_wcqe_r_wqe_index_SHIFT	0
+#define lpfc_wcqe_r_wqe_index_MASK	0x0000FFFF
+#define lpfc_wcqe_r_wqe_index_WORD	word2
+	uint32_t word3;
+#define lpfc_wcqe_r_valid_SHIFT		lpfc_cqe_valid_SHIFT
+#define lpfc_wcqe_r_valid_MASK		lpfc_cqe_valid_MASK
+#define lpfc_wcqe_r_valid_WORD		lpfc_cqe_valid_WORD
+#define lpfc_wcqe_r_code_SHIFT		lpfc_cqe_code_SHIFT
+#define lpfc_wcqe_r_code_MASK		lpfc_cqe_code_MASK
+#define lpfc_wcqe_r_code_WORD		lpfc_cqe_code_WORD
+};
+
+struct sli4_wcqe_xri_aborted {
+	uint32_t word0;
+#define lpfc_wcqe_xa_status_SHIFT		8
+#define lpfc_wcqe_xa_status_MASK		0x000000FF
+#define lpfc_wcqe_xa_status_WORD		word0
+	uint32_t parameter;
+	uint32_t word2;
+#define lpfc_wcqe_xa_remote_xid_SHIFT	16
+#define lpfc_wcqe_xa_remote_xid_MASK	0x0000FFFF
+#define lpfc_wcqe_xa_remote_xid_WORD	word2
+#define lpfc_wcqe_xa_xri_SHIFT		0
+#define lpfc_wcqe_xa_xri_MASK		0x0000FFFF
+#define lpfc_wcqe_xa_xri_WORD		word2
+	uint32_t word3;
+#define lpfc_wcqe_xa_valid_SHIFT	lpfc_cqe_valid_SHIFT
+#define lpfc_wcqe_xa_valid_MASK		lpfc_cqe_valid_MASK
+#define lpfc_wcqe_xa_valid_WORD		lpfc_cqe_valid_WORD
+#define lpfc_wcqe_xa_ia_SHIFT		30
+#define lpfc_wcqe_xa_ia_MASK		0x00000001
+#define lpfc_wcqe_xa_ia_WORD		word3
+#define CQE_XRI_ABORTED_IA_REMOTE	0
+#define CQE_XRI_ABORTED_IA_LOCAL	1
+#define lpfc_wcqe_xa_br_SHIFT		29
+#define lpfc_wcqe_xa_br_MASK		0x00000001
+#define lpfc_wcqe_xa_br_WORD		word3
+#define CQE_XRI_ABORTED_BR_BA_ACC	0
+#define CQE_XRI_ABORTED_BR_BA_RJT	1
+#define lpfc_wcqe_xa_eo_SHIFT		28
+#define lpfc_wcqe_xa_eo_MASK		0x00000001
+#define lpfc_wcqe_xa_eo_WORD		word3
+#define CQE_XRI_ABORTED_EO_REMOTE	0
+#define CQE_XRI_ABORTED_EO_LOCAL	1
+#define lpfc_wcqe_xa_code_SHIFT		lpfc_cqe_code_SHIFT
+#define lpfc_wcqe_xa_code_MASK		lpfc_cqe_code_MASK
+#define lpfc_wcqe_xa_code_WORD		lpfc_cqe_code_WORD
+};
+
+/* completion queue entry structure for rqe completion */
+struct lpfc_rcqe {
+	uint32_t word0;
+#define lpfc_rcqe_bindex_SHIFT		16
+#define lpfc_rcqe_bindex_MASK		0x0000FFF
+#define lpfc_rcqe_bindex_WORD		word0
+#define lpfc_rcqe_status_SHIFT		8
+#define lpfc_rcqe_status_MASK		0x000000FF
+#define lpfc_rcqe_status_WORD		word0
+#define FC_STATUS_RQ_SUCCESS		0x10 /* Async receive successful */
+#define FC_STATUS_RQ_BUF_LEN_EXCEEDED 	0x11 /* payload truncated */
+#define FC_STATUS_INSUFF_BUF_NEED_BUF 	0x12 /* Insufficient buffers */
+#define FC_STATUS_INSUFF_BUF_FRM_DISC 	0x13 /* Frame Discard */
+	uint32_t reserved1;
+	uint32_t word2;
+#define lpfc_rcqe_length_SHIFT		16
+#define lpfc_rcqe_length_MASK		0x0000FFFF
+#define lpfc_rcqe_length_WORD		word2
+#define lpfc_rcqe_rq_id_SHIFT		6
+#define lpfc_rcqe_rq_id_MASK		0x000003FF
+#define lpfc_rcqe_rq_id_WORD		word2
+#define lpfc_rcqe_fcf_id_SHIFT		0
+#define lpfc_rcqe_fcf_id_MASK		0x0000003F
+#define lpfc_rcqe_fcf_id_WORD		word2
+	uint32_t word3;
+#define lpfc_rcqe_valid_SHIFT		lpfc_cqe_valid_SHIFT
+#define lpfc_rcqe_valid_MASK		lpfc_cqe_valid_MASK
+#define lpfc_rcqe_valid_WORD		lpfc_cqe_valid_WORD
+#define lpfc_rcqe_port_SHIFT		30
+#define lpfc_rcqe_port_MASK		0x00000001
+#define lpfc_rcqe_port_WORD		word3
+#define lpfc_rcqe_hdr_length_SHIFT	24
+#define lpfc_rcqe_hdr_length_MASK	0x0000001F
+#define lpfc_rcqe_hdr_length_WORD	word3
+#define lpfc_rcqe_code_SHIFT		lpfc_cqe_code_SHIFT
+#define lpfc_rcqe_code_MASK		lpfc_cqe_code_MASK
+#define lpfc_rcqe_code_WORD		lpfc_cqe_code_WORD
+#define lpfc_rcqe_eof_SHIFT		8
+#define lpfc_rcqe_eof_MASK		0x000000FF
+#define lpfc_rcqe_eof_WORD		word3
+#define FCOE_EOFn	0x41
+#define FCOE_EOFt	0x42
+#define FCOE_EOFni	0x49
+#define FCOE_EOFa	0x50
+#define lpfc_rcqe_sof_SHIFT		0
+#define lpfc_rcqe_sof_MASK		0x000000FF
+#define lpfc_rcqe_sof_WORD		word3
+#define FCOE_SOFi2	0x2d
+#define FCOE_SOFi3	0x2e
+#define FCOE_SOFn2	0x35
+#define FCOE_SOFn3	0x36
+};
+
+struct lpfc_wqe_generic{
+	struct ulp_bde64 bde;
+	uint32_t word3;
+	uint32_t word4;
+	uint32_t word5;
+	uint32_t word6;
+#define lpfc_wqe_gen_context_SHIFT	16
+#define lpfc_wqe_gen_context_MASK	0x0000FFFF
+#define lpfc_wqe_gen_context_WORD	word6
+#define lpfc_wqe_gen_xri_SHIFT		0
+#define lpfc_wqe_gen_xri_MASK		0x0000FFFF
+#define lpfc_wqe_gen_xri_WORD		word6
+	uint32_t word7;
+#define lpfc_wqe_gen_lnk_SHIFT		23
+#define lpfc_wqe_gen_lnk_MASK		0x00000001
+#define lpfc_wqe_gen_lnk_WORD		word7
+#define lpfc_wqe_gen_erp_SHIFT		22
+#define lpfc_wqe_gen_erp_MASK		0x00000001
+#define lpfc_wqe_gen_erp_WORD		word7
+#define lpfc_wqe_gen_pu_SHIFT		20
+#define lpfc_wqe_gen_pu_MASK		0x00000003
+#define lpfc_wqe_gen_pu_WORD		word7
+#define lpfc_wqe_gen_class_SHIFT	16
+#define lpfc_wqe_gen_class_MASK		0x00000007
+#define lpfc_wqe_gen_class_WORD		word7
+#define lpfc_wqe_gen_command_SHIFT	8
+#define lpfc_wqe_gen_command_MASK	0x000000FF
+#define lpfc_wqe_gen_command_WORD	word7
+#define lpfc_wqe_gen_status_SHIFT	4
+#define lpfc_wqe_gen_status_MASK	0x0000000F
+#define lpfc_wqe_gen_status_WORD	word7
+#define lpfc_wqe_gen_ct_SHIFT		2
+#define lpfc_wqe_gen_ct_MASK		0x00000007
+#define lpfc_wqe_gen_ct_WORD		word7
+	uint32_t abort_tag;
+	uint32_t word9;
+#define lpfc_wqe_gen_request_tag_SHIFT	0
+#define lpfc_wqe_gen_request_tag_MASK	0x0000FFFF
+#define lpfc_wqe_gen_request_tag_WORD	word9
+	uint32_t word10;
+#define lpfc_wqe_gen_ccp_SHIFT		24
+#define lpfc_wqe_gen_ccp_MASK		0x000000FF
+#define lpfc_wqe_gen_ccp_WORD		word10
+#define lpfc_wqe_gen_ccpe_SHIFT		23
+#define lpfc_wqe_gen_ccpe_MASK		0x00000001
+#define lpfc_wqe_gen_ccpe_WORD		word10
+#define lpfc_wqe_gen_pv_SHIFT		19
+#define lpfc_wqe_gen_pv_MASK		0x00000001
+#define lpfc_wqe_gen_pv_WORD		word10
+#define lpfc_wqe_gen_pri_SHIFT		16
+#define lpfc_wqe_gen_pri_MASK		0x00000007
+#define lpfc_wqe_gen_pri_WORD		word10
+	uint32_t word11;
+#define lpfc_wqe_gen_cq_id_SHIFT	16
+#define lpfc_wqe_gen_cq_id_MASK		0x000003FF
+#define lpfc_wqe_gen_cq_id_WORD		word11
+#define LPFC_WQE_CQ_ID_DEFAULT	0x3ff
+#define lpfc_wqe_gen_wqec_SHIFT		7
+#define lpfc_wqe_gen_wqec_MASK		0x00000001
+#define lpfc_wqe_gen_wqec_WORD		word11
+#define lpfc_wqe_gen_cmd_type_SHIFT	0
+#define lpfc_wqe_gen_cmd_type_MASK	0x0000000F
+#define lpfc_wqe_gen_cmd_type_WORD	word11
+	uint32_t payload[4];
+};
+
+struct lpfc_rqe {
+	uint32_t address_hi;
+	uint32_t address_lo;
+};
+
+/* buffer descriptors */
+struct lpfc_bde4 {
+	uint32_t addr_hi;
+	uint32_t addr_lo;
+	uint32_t word2;
+#define lpfc_bde4_last_SHIFT		31
+#define lpfc_bde4_last_MASK		0x00000001
+#define lpfc_bde4_last_WORD		word2
+#define lpfc_bde4_sge_offset_SHIFT	0
+#define lpfc_bde4_sge_offset_MASK	0x000003FF
+#define lpfc_bde4_sge_offset_WORD	word2
+	uint32_t word3;
+#define lpfc_bde4_length_SHIFT		0
+#define lpfc_bde4_length_MASK		0x000000FF
+#define lpfc_bde4_length_WORD		word3
+};
+
+struct lpfc_register {
+	uint32_t word0;
+};
+
+#define LPFC_UERR_STATUS_HI		0x00A4
+#define LPFC_UERR_STATUS_LO		0x00A0
+#define LPFC_ONLINE0			0x00B0
+#define LPFC_ONLINE1			0x00B4
+#define LPFC_SCRATCHPAD			0x0058
+
+/* BAR0 Registers */
+#define LPFC_HST_STATE			0x00AC
+#define lpfc_hst_state_perr_SHIFT	31
+#define lpfc_hst_state_perr_MASK	0x1
+#define lpfc_hst_state_perr_WORD	word0
+#define lpfc_hst_state_sfi_SHIFT	30
+#define lpfc_hst_state_sfi_MASK		0x1
+#define lpfc_hst_state_sfi_WORD		word0
+#define lpfc_hst_state_nip_SHIFT	29
+#define lpfc_hst_state_nip_MASK		0x1
+#define lpfc_hst_state_nip_WORD		word0
+#define lpfc_hst_state_ipc_SHIFT	28
+#define lpfc_hst_state_ipc_MASK		0x1
+#define lpfc_hst_state_ipc_WORD		word0
+#define lpfc_hst_state_xrom_SHIFT	27
+#define lpfc_hst_state_xrom_MASK	0x1
+#define lpfc_hst_state_xrom_WORD	word0
+#define lpfc_hst_state_dl_SHIFT		26
+#define lpfc_hst_state_dl_MASK		0x1
+#define lpfc_hst_state_dl_WORD		word0
+#define lpfc_hst_state_port_status_SHIFT	0
+#define lpfc_hst_state_port_status_MASK		0xFFFF
+#define lpfc_hst_state_port_status_WORD		word0
+
+#define LPFC_POST_STAGE_POWER_ON_RESET			0x0000
+#define LPFC_POST_STAGE_AWAITING_HOST_RDY		0x0001
+#define LPFC_POST_STAGE_HOST_RDY			0x0002
+#define LPFC_POST_STAGE_BE_RESET			0x0003
+#define LPFC_POST_STAGE_SEEPROM_CS_START		0x0100
+#define LPFC_POST_STAGE_SEEPROM_CS_DONE			0x0101
+#define LPFC_POST_STAGE_DDR_CONFIG_START		0x0200
+#define LPFC_POST_STAGE_DDR_CONFIG_DONE			0x0201
+#define LPFC_POST_STAGE_DDR_CALIBRATE_START		0x0300
+#define LPFC_POST_STAGE_DDR_CALIBRATE_DONE		0x0301
+#define LPFC_POST_STAGE_DDR_TEST_START			0x0400
+#define LPFC_POST_STAGE_DDR_TEST_DONE			0x0401
+#define LPFC_POST_STAGE_REDBOOT_INIT_START		0x0600
+#define LPFC_POST_STAGE_REDBOOT_INIT_DONE		0x0601
+#define LPFC_POST_STAGE_FW_IMAGE_LOAD_START		0x0700
+#define LPFC_POST_STAGE_FW_IMAGE_LOAD_DONE		0x0701
+#define LPFC_POST_STAGE_ARMFW_START			0x0800
+#define LPFC_POST_STAGE_DHCP_QUERY_START		0x0900
+#define LPFC_POST_STAGE_DHCP_QUERY_DONE			0x0901
+#define LPFC_POST_STAGE_BOOT_TARGET_DISCOVERY_START	0x0A00
+#define LPFC_POST_STAGE_BOOT_TARGET_DISCOVERY_DONE	0x0A01
+#define LPFC_POST_STAGE_RC_OPTION_SET			0x0B00
+#define LPFC_POST_STAGE_SWITCH_LINK			0x0B01
+#define LPFC_POST_STAGE_SEND_ICDS_MESSAGE		0x0B02
+#define LPFC_POST_STAGE_PERFROM_TFTP			0x0B03
+#define LPFC_POST_STAGE_PARSE_XML			0x0B04
+#define LPFC_POST_STAGE_DOWNLOAD_IMAGE			0x0B05
+#define LPFC_POST_STAGE_FLASH_IMAGE			0x0B06
+#define LPFC_POST_STAGE_RC_DONE				0x0B07
+#define LPFC_POST_STAGE_REBOOT_SYSTEM			0x0B08
+#define LPFC_POST_STAGE_MAC_ADDRESS			0x0C00
+#define LPFC_POST_STAGE_ARMFW_READY			0xC000
+#define LPFC_POST_STAGE_ARMFW_UE 			0xF000
+
+#define lpfc_scratchpad_slirev_SHIFT			4
+#define lpfc_scratchpad_slirev_MASK			0xF
+#define lpfc_scratchpad_slirev_WORD			word0
+#define lpfc_scratchpad_chiptype_SHIFT			8
+#define lpfc_scratchpad_chiptype_MASK			0xFF
+#define lpfc_scratchpad_chiptype_WORD			word0
+#define lpfc_scratchpad_featurelevel1_SHIFT		16
+#define lpfc_scratchpad_featurelevel1_MASK		0xFF
+#define lpfc_scratchpad_featurelevel1_WORD		word0
+#define lpfc_scratchpad_featurelevel2_SHIFT		24
+#define lpfc_scratchpad_featurelevel2_MASK		0xFF
+#define lpfc_scratchpad_featurelevel2_WORD		word0
+
+/* BAR1 Registers */
+#define LPFC_IMR_MASK_ALL	0xFFFFFFFF
+#define LPFC_ISCR_CLEAR_ALL	0xFFFFFFFF
+
+#define LPFC_HST_ISR0		0x0C18
+#define LPFC_HST_ISR1		0x0C1C
+#define LPFC_HST_ISR2		0x0C20
+#define LPFC_HST_ISR3		0x0C24
+#define LPFC_HST_ISR4		0x0C28
+
+#define LPFC_HST_IMR0		0x0C48
+#define LPFC_HST_IMR1		0x0C4C
+#define LPFC_HST_IMR2		0x0C50
+#define LPFC_HST_IMR3		0x0C54
+#define LPFC_HST_IMR4		0x0C58
+
+#define LPFC_HST_ISCR0		0x0C78
+#define LPFC_HST_ISCR1		0x0C7C
+#define LPFC_HST_ISCR2		0x0C80
+#define LPFC_HST_ISCR3		0x0C84
+#define LPFC_HST_ISCR4		0x0C88
+
+#define LPFC_SLI4_INTR0			BIT0
+#define LPFC_SLI4_INTR1			BIT1
+#define LPFC_SLI4_INTR2			BIT2
+#define LPFC_SLI4_INTR3			BIT3
+#define LPFC_SLI4_INTR4			BIT4
+#define LPFC_SLI4_INTR5			BIT5
+#define LPFC_SLI4_INTR6			BIT6
+#define LPFC_SLI4_INTR7			BIT7
+#define LPFC_SLI4_INTR8			BIT8
+#define LPFC_SLI4_INTR9			BIT9
+#define LPFC_SLI4_INTR10		BIT10
+#define LPFC_SLI4_INTR11		BIT11
+#define LPFC_SLI4_INTR12		BIT12
+#define LPFC_SLI4_INTR13		BIT13
+#define LPFC_SLI4_INTR14		BIT14
+#define LPFC_SLI4_INTR15		BIT15
+#define LPFC_SLI4_INTR16		BIT16
+#define LPFC_SLI4_INTR17		BIT17
+#define LPFC_SLI4_INTR18		BIT18
+#define LPFC_SLI4_INTR19		BIT19
+#define LPFC_SLI4_INTR20		BIT20
+#define LPFC_SLI4_INTR21		BIT21
+#define LPFC_SLI4_INTR22		BIT22
+#define LPFC_SLI4_INTR23		BIT23
+#define LPFC_SLI4_INTR24		BIT24
+#define LPFC_SLI4_INTR25		BIT25
+#define LPFC_SLI4_INTR26		BIT26
+#define LPFC_SLI4_INTR27		BIT27
+#define LPFC_SLI4_INTR28		BIT28
+#define LPFC_SLI4_INTR29		BIT29
+#define LPFC_SLI4_INTR30		BIT30
+#define LPFC_SLI4_INTR31		BIT31
+
+/* BAR2 Registers */
+#define LPFC_RQ_DOORBELL		0x00A0
+#define lpfc_rq_doorbell_num_posted_SHIFT	16
+#define lpfc_rq_doorbell_num_posted_MASK	0x3FFF
+#define lpfc_rq_doorbell_num_posted_WORD	word0
+#define LPFC_RQ_POST_BATCH		8	/* RQEs to post at one time */
+#define lpfc_rq_doorbell_id_SHIFT		0
+#define lpfc_rq_doorbell_id_MASK		0x03FF
+#define lpfc_rq_doorbell_id_WORD		word0
+
+#define LPFC_WQ_DOORBELL		0x0040
+#define lpfc_wq_doorbell_num_posted_SHIFT	24
+#define lpfc_wq_doorbell_num_posted_MASK	0x00FF
+#define lpfc_wq_doorbell_num_posted_WORD	word0
+#define lpfc_wq_doorbell_index_SHIFT		16
+#define lpfc_wq_doorbell_index_MASK		0x00FF
+#define lpfc_wq_doorbell_index_WORD		word0
+#define lpfc_wq_doorbell_id_SHIFT		0
+#define lpfc_wq_doorbell_id_MASK		0xFFFF
+#define lpfc_wq_doorbell_id_WORD		word0
+
+#define LPFC_EQCQ_DOORBELL		0x0120
+#define lpfc_eqcq_doorbell_arm_SHIFT		29
+#define lpfc_eqcq_doorbell_arm_MASK		0x0001
+#define lpfc_eqcq_doorbell_arm_WORD		word0
+#define lpfc_eqcq_doorbell_num_released_SHIFT	16
+#define lpfc_eqcq_doorbell_num_released_MASK	0x1FFF
+#define lpfc_eqcq_doorbell_num_released_WORD	word0
+#define lpfc_eqcq_doorbell_qt_SHIFT		10
+#define lpfc_eqcq_doorbell_qt_MASK		0x0001
+#define lpfc_eqcq_doorbell_qt_WORD		word0
+#define LPFC_QUEUE_TYPE_COMPLETION	0
+#define LPFC_QUEUE_TYPE_EVENT		1
+#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_BMBX			0x0160
+#define lpfc_bmbx_addr_SHIFT		2
+#define lpfc_bmbx_addr_MASK		0x3FFFFFFF
+#define lpfc_bmbx_addr_WORD		word0
+#define lpfc_bmbx_hi_SHIFT		1
+#define lpfc_bmbx_hi_MASK		0x0001
+#define lpfc_bmbx_hi_WORD		word0
+#define lpfc_bmbx_rdy_SHIFT		0
+#define lpfc_bmbx_rdy_MASK		0x0001
+#define lpfc_bmbx_rdy_WORD		word0
+
+#define LPFC_MQ_DOORBELL			0x0140
+#define lpfc_mq_doorbell_num_posted_SHIFT	16
+#define lpfc_mq_doorbell_num_posted_MASK	0x3FFF
+#define lpfc_mq_doorbell_num_posted_WORD	word0
+#define lpfc_mq_doorbell_id_SHIFT		0
+#define lpfc_mq_doorbell_id_MASK		0x03FF
+#define lpfc_mq_doorbell_id_WORD		word0
+
+struct lpfc_sli4_cfg_mhdr {
+	uint32_t word1;
+#define lpfc_mbox_hdr_emb_SHIFT		0
+#define lpfc_mbox_hdr_emb_MASK		0x00000001
+#define lpfc_mbox_hdr_emb_WORD		word1
+#define lpfc_mbox_hdr_sge_cnt_SHIFT	3
+#define lpfc_mbox_hdr_sge_cnt_MASK	0x0000001F
+#define lpfc_mbox_hdr_sge_cnt_WORD	word1
+	uint32_t payload_length;
+	uint32_t tag_lo;
+	uint32_t tag_hi;
+	uint32_t reserved5;
+};
+
+union lpfc_sli4_cfg_shdr {
+	struct {
+		uint32_t word6;
+#define lpfc_mbox_hdr_opcode_SHIFT		0
+#define lpfc_mbox_hdr_opcode_MASK		0x000000FF
+#define lpfc_mbox_hdr_opcode_WORD		word6
+#define lpfc_mbox_hdr_subsystem_SHIFT		8
+#define lpfc_mbox_hdr_subsystem_MASK		0x000000FF
+#define lpfc_mbox_hdr_subsystem_WORD		word6
+#define lpfc_mbox_hdr_port_number_SHIFT		16
+#define lpfc_mbox_hdr_port_number_MASK		0x000000FF
+#define lpfc_mbox_hdr_port_number_WORD		word6
+#define lpfc_mbox_hdr_domain_SHIFT		24
+#define lpfc_mbox_hdr_domain_MASK		0x000000FF
+#define lpfc_mbox_hdr_domain_WORD		word6
+		uint32_t timeout;
+		uint32_t request_length;
+		uint32_t reserved9;
+	} request;
+	struct {
+		uint32_t word6;
+#define lpfc_mbox_hdr_opcode_SHIFT		0
+#define lpfc_mbox_hdr_opcode_MASK		0x000000FF
+#define lpfc_mbox_hdr_opcode_WORD		word6
+#define lpfc_mbox_hdr_subsystem_SHIFT		8
+#define lpfc_mbox_hdr_subsystem_MASK		0x000000FF
+#define lpfc_mbox_hdr_subsystem_WORD		word6
+#define lpfc_mbox_hdr_domain_SHIFT		24
+#define lpfc_mbox_hdr_domain_MASK		0x000000FF
+#define lpfc_mbox_hdr_domain_WORD		word6
+		uint32_t word7;
+#define lpfc_mbox_hdr_status_SHIFT		0
+#define lpfc_mbox_hdr_status_MASK		0x000000FF
+#define lpfc_mbox_hdr_status_WORD		word7
+#define lpfc_mbox_hdr_add_status_SHIFT		8
+#define lpfc_mbox_hdr_add_status_MASK		0x000000FF
+#define lpfc_mbox_hdr_add_status_WORD		word7
+		uint32_t response_length;
+		uint32_t actual_response_length;
+	} response;
+};
+
+/* Mailbox structures */
+struct mbox_header {
+	struct lpfc_sli4_cfg_mhdr cfg_mhdr;
+	union  lpfc_sli4_cfg_shdr cfg_shdr;
+};
+
+/* Subsystem Definitions */
+#define LPFC_MBOX_SUBSYSTEM_COMMON	0x1
+#define LPFC_MBOX_SUBSYSTEM_FCOE	0xC
+
+/* Device Specific Definitions */
+
+/* The HOST ENDIAN defines are in Big Endian format. */
+#define HOST_ENDIAN_LOW_WORD0   0xFF3412FF
+#define HOST_ENDIAN_HIGH_WORD1	0xFF7856FF
+
+/* Common Opcodes */
+#define LPFC_MBOX_OPCODE_CQ_CREATE		0x0C
+#define LPFC_MBOX_OPCODE_EQ_CREATE		0x0D
+#define LPFC_MBOX_OPCODE_MQ_CREATE		0x15
+#define LPFC_MBOX_OPCODE_GET_CNTL_ATTRIBUTES	0x20
+#define LPFC_MBOX_OPCODE_NOP			0x21
+#define LPFC_MBOX_OPCODE_MQ_DESTROY		0x35
+#define LPFC_MBOX_OPCODE_CQ_DESTROY		0x36
+#define LPFC_MBOX_OPCODE_EQ_DESTROY		0x37
+#define LPFC_MBOX_OPCODE_FUNCTION_RESET		0x3D
+
+/* FCoE Opcodes */
+#define LPFC_MBOX_OPCODE_FCOE_WQ_CREATE			0x01
+#define LPFC_MBOX_OPCODE_FCOE_WQ_DESTROY		0x02
+#define LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES		0x03
+#define LPFC_MBOX_OPCODE_FCOE_REMOVE_SGL_PAGES		0x04
+#define LPFC_MBOX_OPCODE_FCOE_RQ_CREATE			0x05
+#define LPFC_MBOX_OPCODE_FCOE_RQ_DESTROY		0x06
+#define LPFC_MBOX_OPCODE_FCOE_READ_FCF_TABLE		0x08
+#define LPFC_MBOX_OPCODE_FCOE_ADD_FCF			0x09
+#define LPFC_MBOX_OPCODE_FCOE_DELETE_FCF		0x0A
+#define LPFC_MBOX_OPCODE_FCOE_POST_HDR_TEMPLATE		0x0B
+
+/* Mailbox command structures */
+struct eq_context {
+	uint32_t word0;
+#define lpfc_eq_context_size_SHIFT	31
+#define lpfc_eq_context_size_MASK	0x00000001
+#define lpfc_eq_context_size_WORD	word0
+#define LPFC_EQE_SIZE_4			0x0
+#define LPFC_EQE_SIZE_16		0x1
+#define lpfc_eq_context_valid_SHIFT	29
+#define lpfc_eq_context_valid_MASK	0x00000001
+#define lpfc_eq_context_valid_WORD	word0
+	uint32_t word1;
+#define lpfc_eq_context_count_SHIFT	26
+#define lpfc_eq_context_count_MASK	0x00000003
+#define lpfc_eq_context_count_WORD	word1
+#define LPFC_EQ_CNT_256		0x0
+#define LPFC_EQ_CNT_512		0x1
+#define LPFC_EQ_CNT_1024	0x2
+#define LPFC_EQ_CNT_2048	0x3
+#define LPFC_EQ_CNT_4096	0x4
+	uint32_t word2;
+#define lpfc_eq_context_delay_multi_SHIFT	13
+#define lpfc_eq_context_delay_multi_MASK	0x000003FF
+#define lpfc_eq_context_delay_multi_WORD	word2
+	uint32_t reserved3;
+};
+
+struct sgl_page_pairs {
+	uint32_t sgl_pg0_addr_lo;
+	uint32_t sgl_pg0_addr_hi;
+	uint32_t sgl_pg1_addr_lo;
+	uint32_t sgl_pg1_addr_hi;
+};
+
+struct lpfc_mbx_post_sgl_pages {
+	struct mbox_header header;
+	uint32_t word0;
+#define lpfc_post_sgl_pages_xri_SHIFT	0
+#define lpfc_post_sgl_pages_xri_MASK	0x0000FFFF
+#define lpfc_post_sgl_pages_xri_WORD	word0
+#define lpfc_post_sgl_pages_xricnt_SHIFT	16
+#define lpfc_post_sgl_pages_xricnt_MASK	0x0000FFFF
+#define lpfc_post_sgl_pages_xricnt_WORD	word0
+	struct sgl_page_pairs  sgl_pg_pairs[1];
+};
+
+/* word0 of page-1 struct shares the same SHIFT/MASK/WORD defines as above */
+struct lpfc_mbx_post_uembed_sgl_page1 {
+	union  lpfc_sli4_cfg_shdr cfg_shdr;
+	uint32_t word0;
+	struct sgl_page_pairs sgl_pg_pairs;
+};
+
+struct lpfc_mbx_sge {
+	uint32_t pa_lo;
+	uint32_t pa_hi;
+	uint32_t length;
+};
+
+struct lpfc_mbx_nembed_cmd {
+	struct lpfc_sli4_cfg_mhdr cfg_mhdr;
+#define LPFC_SLI4_MBX_SGE_MAX_PAGES	19
+	struct lpfc_mbx_sge sge[LPFC_SLI4_MBX_SGE_MAX_PAGES];
+};
+
+struct lpfc_mbx_nembed_sge_virt {
+	void *addr[LPFC_SLI4_MBX_SGE_MAX_PAGES];
+};
+
+struct lpfc_mbx_eq_create {
+	struct mbox_header header;
+	union {
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_eq_create_num_pages_SHIFT	0
+#define lpfc_mbx_eq_create_num_pages_MASK	0x0000FFFF
+#define lpfc_mbx_eq_create_num_pages_WORD	word0
+			struct eq_context context;
+			struct dma_address page[LPFC_MAX_EQ_PAGE];
+		} request;
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_eq_create_q_id_SHIFT	0
+#define lpfc_mbx_eq_create_q_id_MASK	0x0000FFFF
+#define lpfc_mbx_eq_create_q_id_WORD	word0
+		} response;
+	} u;
+};
+
+struct lpfc_mbx_eq_destroy {
+	struct mbox_header header;
+	union {
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_eq_destroy_q_id_SHIFT	0
+#define lpfc_mbx_eq_destroy_q_id_MASK	0x0000FFFF
+#define lpfc_mbx_eq_destroy_q_id_WORD	word0
+		} request;
+		struct {
+			uint32_t word0;
+		} response;
+	} u;
+};
+
+struct lpfc_mbx_nop {
+	struct mbox_header header;
+	uint32_t context[2];
+};
+
+struct cq_context {
+	uint32_t word0;
+#define lpfc_cq_context_event_SHIFT	31
+#define lpfc_cq_context_event_MASK	0x00000001
+#define lpfc_cq_context_event_WORD	word0
+#define lpfc_cq_context_valid_SHIFT	29
+#define lpfc_cq_context_valid_MASK	0x00000001
+#define lpfc_cq_context_valid_WORD	word0
+#define lpfc_cq_context_count_SHIFT	27
+#define lpfc_cq_context_count_MASK	0x00000003
+#define lpfc_cq_context_count_WORD	word0
+#define LPFC_CQ_CNT_256		0x0
+#define LPFC_CQ_CNT_512		0x1
+#define LPFC_CQ_CNT_1024	0x2
+	uint32_t word1;
+#define lpfc_cq_eq_id_SHIFT		22
+#define lpfc_cq_eq_id_MASK		0x000000FF
+#define lpfc_cq_eq_id_WORD		word1
+	uint32_t reserved0;
+	uint32_t reserved1;
+};
+
+struct lpfc_mbx_cq_create {
+	struct mbox_header header;
+	union {
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_cq_create_num_pages_SHIFT	0
+#define lpfc_mbx_cq_create_num_pages_MASK	0x0000FFFF
+#define lpfc_mbx_cq_create_num_pages_WORD	word0
+			struct cq_context context;
+			struct dma_address page[LPFC_MAX_CQ_PAGE];
+		} request;
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_cq_create_q_id_SHIFT	0
+#define lpfc_mbx_cq_create_q_id_MASK	0x0000FFFF
+#define lpfc_mbx_cq_create_q_id_WORD	word0
+		} response;
+	} u;
+};
+
+struct lpfc_mbx_cq_destroy {
+	struct mbox_header header;
+	union {
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_cq_destroy_q_id_SHIFT	0
+#define lpfc_mbx_cq_destroy_q_id_MASK	0x0000FFFF
+#define lpfc_mbx_cq_destroy_q_id_WORD	word0
+		} request;
+		struct {
+			uint32_t word0;
+		} response;
+	} u;
+};
+
+struct wq_context {
+	uint32_t reserved0;
+	uint32_t reserved1;
+	uint32_t reserved2;
+	uint32_t reserved3;
+};
+
+struct lpfc_mbx_wq_create {
+	struct mbox_header header;
+	union {
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_wq_create_num_pages_SHIFT	0
+#define lpfc_mbx_wq_create_num_pages_MASK	0x0000FFFF
+#define lpfc_mbx_wq_create_num_pages_WORD	word0
+#define lpfc_mbx_wq_create_cq_id_SHIFT		16
+#define lpfc_mbx_wq_create_cq_id_MASK		0x0000FFFF
+#define lpfc_mbx_wq_create_cq_id_WORD		word0
+			struct dma_address page[LPFC_MAX_WQ_PAGE];
+		} request;
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_wq_create_q_id_SHIFT	0
+#define lpfc_mbx_wq_create_q_id_MASK	0x0000FFFF
+#define lpfc_mbx_wq_create_q_id_WORD	word0
+		} response;
+	} u;
+};
+
+struct lpfc_mbx_wq_destroy {
+	struct mbox_header header;
+	union {
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_wq_destroy_q_id_SHIFT	0
+#define lpfc_mbx_wq_destroy_q_id_MASK	0x0000FFFF
+#define lpfc_mbx_wq_destroy_q_id_WORD	word0
+		} request;
+		struct {
+			uint32_t word0;
+		} response;
+	} u;
+};
+
+#define LPFC_HDR_BUF_SIZE 128
+#define LPFC_DATA_BUF_SIZE 4096
+struct rq_context {
+	uint32_t word0;
+#define lpfc_rq_context_rq_size_SHIFT	16
+#define lpfc_rq_context_rq_size_MASK	0x0000000F
+#define lpfc_rq_context_rq_size_WORD	word0
+#define LPFC_RQ_RING_SIZE_512		9	/* 512 entries */
+#define LPFC_RQ_RING_SIZE_1024		10	/* 1024 entries */
+#define LPFC_RQ_RING_SIZE_2048		11	/* 2048 entries */
+#define LPFC_RQ_RING_SIZE_4096		12	/* 4096 entries */
+	uint32_t reserved1;
+	uint32_t word2;
+#define lpfc_rq_context_cq_id_SHIFT	16
+#define lpfc_rq_context_cq_id_MASK	0x000003FF
+#define lpfc_rq_context_cq_id_WORD	word2
+#define lpfc_rq_context_buf_size_SHIFT	0
+#define lpfc_rq_context_buf_size_MASK	0x0000FFFF
+#define lpfc_rq_context_buf_size_WORD	word2
+	uint32_t reserved3;
+};
+
+struct lpfc_mbx_rq_create {
+	struct mbox_header header;
+	union {
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_rq_create_num_pages_SHIFT	0
+#define lpfc_mbx_rq_create_num_pages_MASK	0x0000FFFF
+#define lpfc_mbx_rq_create_num_pages_WORD	word0
+			struct rq_context context;
+			struct dma_address page[LPFC_MAX_WQ_PAGE];
+		} request;
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_rq_create_q_id_SHIFT	0
+#define lpfc_mbx_rq_create_q_id_MASK	0x0000FFFF
+#define lpfc_mbx_rq_create_q_id_WORD	word0
+		} response;
+	} u;
+};
+
+struct lpfc_mbx_rq_destroy {
+	struct mbox_header header;
+	union {
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_rq_destroy_q_id_SHIFT	0
+#define lpfc_mbx_rq_destroy_q_id_MASK	0x0000FFFF
+#define lpfc_mbx_rq_destroy_q_id_WORD	word0
+		} request;
+		struct {
+			uint32_t word0;
+		} response;
+	} u;
+};
+
+struct mq_context {
+	uint32_t word0;
+#define lpfc_mq_context_cq_id_SHIFT	22
+#define lpfc_mq_context_cq_id_MASK	0x000003FF
+#define lpfc_mq_context_cq_id_WORD	word0
+#define lpfc_mq_context_count_SHIFT	16
+#define lpfc_mq_context_count_MASK	0x0000000F
+#define lpfc_mq_context_count_WORD	word0
+#define LPFC_MQ_CNT_16		0x5
+#define LPFC_MQ_CNT_32		0x6
+#define LPFC_MQ_CNT_64		0x7
+#define LPFC_MQ_CNT_128		0x8
+	uint32_t word1;
+#define lpfc_mq_context_valid_SHIFT	31
+#define lpfc_mq_context_valid_MASK	0x00000001
+#define lpfc_mq_context_valid_WORD	word1
+	uint32_t reserved2;
+	uint32_t reserved3;
+};
+
+struct lpfc_mbx_mq_create {
+	struct mbox_header header;
+	union {
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_mq_create_num_pages_SHIFT	0
+#define lpfc_mbx_mq_create_num_pages_MASK	0x0000FFFF
+#define lpfc_mbx_mq_create_num_pages_WORD	word0
+			struct mq_context context;
+			struct dma_address page[LPFC_MAX_MQ_PAGE];
+		} request;
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_mq_create_q_id_SHIFT	0
+#define lpfc_mbx_mq_create_q_id_MASK	0x0000FFFF
+#define lpfc_mbx_mq_create_q_id_WORD	word0
+		} response;
+	} u;
+};
+
+struct lpfc_mbx_mq_destroy {
+	struct mbox_header header;
+	union {
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_mq_destroy_q_id_SHIFT	0
+#define lpfc_mbx_mq_destroy_q_id_MASK	0x0000FFFF
+#define lpfc_mbx_mq_destroy_q_id_WORD	word0
+		} request;
+		struct {
+			uint32_t word0;
+		} response;
+	} u;
+};
+
+struct lpfc_mbx_post_hdr_tmpl {
+	struct mbox_header header;
+	uint32_t word10;
+#define lpfc_mbx_post_hdr_tmpl_rpi_offset_SHIFT  0
+#define lpfc_mbx_post_hdr_tmpl_rpi_offset_MASK   0x0000FFFF
+#define lpfc_mbx_post_hdr_tmpl_rpi_offset_WORD   word10
+#define lpfc_mbx_post_hdr_tmpl_page_cnt_SHIFT   16
+#define lpfc_mbx_post_hdr_tmpl_page_cnt_MASK    0x0000FFFF
+#define lpfc_mbx_post_hdr_tmpl_page_cnt_WORD    word10
+	uint32_t rpi_paddr_lo;
+	uint32_t rpi_paddr_hi;
+};
+
+struct sli4_sge {	/* SLI-4 */
+	uint32_t addr_hi;
+	uint32_t addr_lo;
+
+	uint32_t word2;
+#define lpfc_sli4_sge_offset_SHIFT	0 /* Offset of buffer - Not used*/
+#define lpfc_sli4_sge_offset_MASK	0x00FFFFFF
+#define lpfc_sli4_sge_offset_WORD	word2
+#define lpfc_sli4_sge_last_SHIFT	31 /* Last SEG in the SGL sets
+						this  flag !! */
+#define lpfc_sli4_sge_last_MASK		0x00000001
+#define lpfc_sli4_sge_last_WORD		word2
+	uint32_t word3;
+#define lpfc_sli4_sge_len_SHIFT		0
+#define lpfc_sli4_sge_len_MASK		0x0001FFFF
+#define lpfc_sli4_sge_len_WORD		word3
+};
+
+struct fcf_record {
+	uint32_t max_rcv_size;
+	uint32_t fka_adv_period;
+	uint32_t fip_priority;
+	uint32_t word3;
+#define lpfc_fcf_record_mac_0_SHIFT		0
+#define lpfc_fcf_record_mac_0_MASK		0x000000FF
+#define lpfc_fcf_record_mac_0_WORD		word3
+#define lpfc_fcf_record_mac_1_SHIFT		8
+#define lpfc_fcf_record_mac_1_MASK		0x000000FF
+#define lpfc_fcf_record_mac_1_WORD		word3
+#define lpfc_fcf_record_mac_2_SHIFT		16
+#define lpfc_fcf_record_mac_2_MASK		0x000000FF
+#define lpfc_fcf_record_mac_2_WORD		word3
+#define lpfc_fcf_record_mac_3_SHIFT		24
+#define lpfc_fcf_record_mac_3_MASK		0x000000FF
+#define lpfc_fcf_record_mac_3_WORD		word3
+	uint32_t word4;
+#define lpfc_fcf_record_mac_4_SHIFT		0
+#define lpfc_fcf_record_mac_4_MASK		0x000000FF
+#define lpfc_fcf_record_mac_4_WORD		word4
+#define lpfc_fcf_record_mac_5_SHIFT		8
+#define lpfc_fcf_record_mac_5_MASK		0x000000FF
+#define lpfc_fcf_record_mac_5_WORD		word4
+#define lpfc_fcf_record_fcf_avail_SHIFT		16
+#define lpfc_fcf_record_fcf_avail_MASK		0x000000FF
+#define lpfc_fcf_record_fc_avail_WORD		word4
+#define lpfc_fcf_record_mac_addr_prov_SHIFT	24
+#define lpfc_fcf_record_mac_addr_prov_MASK	0x000000FF
+#define lpfc_fcf_record_mac_addr_prov_WORD	word4
+#define LPFC_FCF_FPMA           1 	/* Fabric Provided MAC Address */
+#define LPFC_FCF_SPMA           2       /* Server Provided MAC Address */
+	uint32_t word5;
+#define lpfc_fcf_record_fab_name_0_SHIFT	0
+#define lpfc_fcf_record_fab_name_0_MASK		0x000000FF
+#define lpfc_fcf_record_fab_name_0_WORD		word5
+#define lpfc_fcf_record_fab_name_1_SHIFT	8
+#define lpfc_fcf_record_fab_name_1_MASK		0x000000FF
+#define lpfc_fcf_record_fab_name_1_WORD		word5
+#define lpfc_fcf_record_fab_name_2_SHIFT	16
+#define lpfc_fcf_record_fab_name_2_MASK		0x000000FF
+#define lpfc_fcf_record_fab_name_2_WORD		word5
+#define lpfc_fcf_record_fab_name_3_SHIFT	24
+#define lpfc_fcf_record_fab_name_3_MASK		0x000000FF
+#define lpfc_fcf_record_fab_name_3_WORD		word5
+	uint32_t word6;
+#define lpfc_fcf_record_fab_name_4_SHIFT	0
+#define lpfc_fcf_record_fab_name_4_MASK		0x000000FF
+#define lpfc_fcf_record_fab_name_4_WORD		word6
+#define lpfc_fcf_record_fab_name_5_SHIFT	8
+#define lpfc_fcf_record_fab_name_5_MASK		0x000000FF
+#define lpfc_fcf_record_fab_name_5_WORD		word6
+#define lpfc_fcf_record_fab_name_6_SHIFT	16
+#define lpfc_fcf_record_fab_name_6_MASK		0x000000FF
+#define lpfc_fcf_record_fab_name_6_WORD		word6
+#define lpfc_fcf_record_fab_name_7_SHIFT	24
+#define lpfc_fcf_record_fab_name_7_MASK		0x000000FF
+#define lpfc_fcf_record_fab_name_7_WORD		word6
+	uint32_t word7;
+#define lpfc_fcf_record_fc_map_0_SHIFT		0
+#define lpfc_fcf_record_fc_map_0_MASK		0x000000FF
+#define lpfc_fcf_record_fc_map_0_WORD		word7
+#define lpfc_fcf_record_fc_map_1_SHIFT		8
+#define lpfc_fcf_record_fc_map_1_MASK		0x000000FF
+#define lpfc_fcf_record_fc_map_1_WORD		word7
+#define lpfc_fcf_record_fc_map_2_SHIFT		16
+#define lpfc_fcf_record_fc_map_2_MASK		0x000000FF
+#define lpfc_fcf_record_fc_map_2_WORD		word7
+#define lpfc_fcf_record_fcf_valid_SHIFT		24
+#define lpfc_fcf_record_fcf_valid_MASK		0x000000FF
+#define lpfc_fcf_record_fcf_valid_WORD		word7
+	uint32_t word8;
+#define lpfc_fcf_record_fcf_index_SHIFT		0
+#define lpfc_fcf_record_fcf_index_MASK		0x0000FFFF
+#define lpfc_fcf_record_fcf_index_WORD		word8
+#define lpfc_fcf_record_fcf_state_SHIFT		16
+#define lpfc_fcf_record_fcf_state_MASK		0x0000FFFF
+#define lpfc_fcf_record_fcf_state_WORD		word8
+	uint8_t vlan_bitmap[512];
+};
+
+struct lpfc_mbx_read_fcf_tbl {
+	union lpfc_sli4_cfg_shdr cfg_shdr;
+	union {
+		struct {
+			uint32_t word10;
+#define lpfc_mbx_read_fcf_tbl_indx_SHIFT	0
+#define lpfc_mbx_read_fcf_tbl_indx_MASK		0x0000FFFF
+#define lpfc_mbx_read_fcf_tbl_indx_WORD		word10
+		} request;
+		struct {
+			uint32_t eventag;
+		} response;
+	} u;
+	uint32_t word11;
+#define lpfc_mbx_read_fcf_tbl_nxt_vindx_SHIFT	0
+#define lpfc_mbx_read_fcf_tbl_nxt_vindx_MASK	0x0000FFFF
+#define lpfc_mbx_read_fcf_tbl_nxt_vindx_WORD	word11
+};
+
+struct lpfc_mbx_add_fcf_tbl_entry {
+	union lpfc_sli4_cfg_shdr cfg_shdr;
+	uint32_t word10;
+#define lpfc_mbx_add_fcf_tbl_fcfi_SHIFT        0
+#define lpfc_mbx_add_fcf_tbl_fcfi_MASK         0x0000FFFF
+#define lpfc_mbx_add_fcf_tbl_fcfi_WORD         word10
+	struct lpfc_mbx_sge fcf_sge;
+};
+
+struct lpfc_mbx_del_fcf_tbl_entry {
+	struct mbox_header header;
+	uint32_t word10;
+#define lpfc_mbx_del_fcf_tbl_count_SHIFT	0
+#define lpfc_mbx_del_fcf_tbl_count_MASK		0x0000FFFF
+#define lpfc_mbx_del_fcf_tbl_count_WORD		word10
+#define lpfc_mbx_del_fcf_tbl_index_SHIFT	16
+#define lpfc_mbx_del_fcf_tbl_index_MASK		0x0000FFFF
+#define lpfc_mbx_del_fcf_tbl_index_WORD		word10
+};
+
+/* Status field for embedded SLI_CONFIG mailbox command */
+#define STATUS_SUCCESS					0x0
+#define STATUS_FAILED 					0x1
+#define STATUS_ILLEGAL_REQUEST				0x2
+#define STATUS_ILLEGAL_FIELD				0x3
+#define STATUS_INSUFFICIENT_BUFFER 			0x4
+#define STATUS_UNAUTHORIZED_REQUEST			0x5
+#define STATUS_FLASHROM_SAVE_FAILED			0x17
+#define STATUS_FLASHROM_RESTORE_FAILED			0x18
+#define STATUS_ICCBINDEX_ALLOC_FAILED			0x1a
+#define STATUS_IOCTLHANDLE_ALLOC_FAILED 		0x1b
+#define STATUS_INVALID_PHY_ADDR_FROM_OSM		0x1c
+#define STATUS_INVALID_PHY_ADDR_LEN_FROM_OSM		0x1d
+#define STATUS_ASSERT_FAILED				0x1e
+#define STATUS_INVALID_SESSION				0x1f
+#define STATUS_INVALID_CONNECTION			0x20
+#define STATUS_BTL_PATH_EXCEEDS_OSM_LIMIT		0x21
+#define STATUS_BTL_NO_FREE_SLOT_PATH			0x24
+#define STATUS_BTL_NO_FREE_SLOT_TGTID			0x25
+#define STATUS_OSM_DEVSLOT_NOT_FOUND			0x26
+#define STATUS_FLASHROM_READ_FAILED			0x27
+#define STATUS_POLL_IOCTL_TIMEOUT			0x28
+#define STATUS_ERROR_ACITMAIN				0x2a
+#define STATUS_REBOOT_REQUIRED				0x2c
+#define STATUS_FCF_IN_USE				0x3a
+
+struct lpfc_mbx_sli4_config {
+	struct mbox_header header;
+};
+
+struct lpfc_mbx_init_vfi {
+	uint32_t word1;
+#define lpfc_init_vfi_vr_SHIFT		31
+#define lpfc_init_vfi_vr_MASK		0x00000001
+#define lpfc_init_vfi_vr_WORD		word1
+#define lpfc_init_vfi_vt_SHIFT		30
+#define lpfc_init_vfi_vt_MASK		0x00000001
+#define lpfc_init_vfi_vt_WORD		word1
+#define lpfc_init_vfi_vf_SHIFT		29
+#define lpfc_init_vfi_vf_MASK		0x00000001
+#define lpfc_init_vfi_vf_WORD		word1
+#define lpfc_init_vfi_vfi_SHIFT		0
+#define lpfc_init_vfi_vfi_MASK		0x0000FFFF
+#define lpfc_init_vfi_vfi_WORD		word1
+	uint32_t word2;
+#define lpfc_init_vfi_fcfi_SHIFT	0
+#define lpfc_init_vfi_fcfi_MASK		0x0000FFFF
+#define lpfc_init_vfi_fcfi_WORD		word2
+	uint32_t word3;
+#define lpfc_init_vfi_pri_SHIFT		13
+#define lpfc_init_vfi_pri_MASK		0x00000007
+#define lpfc_init_vfi_pri_WORD		word3
+#define lpfc_init_vfi_vf_id_SHIFT	1
+#define lpfc_init_vfi_vf_id_MASK	0x00000FFF
+#define lpfc_init_vfi_vf_id_WORD	word3
+	uint32_t word4;
+#define lpfc_init_vfi_hop_count_SHIFT	24
+#define lpfc_init_vfi_hop_count_MASK	0x000000FF
+#define lpfc_init_vfi_hop_count_WORD	word4
+};
+
+struct lpfc_mbx_reg_vfi {
+	uint32_t word1;
+#define lpfc_reg_vfi_vp_SHIFT		28
+#define lpfc_reg_vfi_vp_MASK		0x00000001
+#define lpfc_reg_vfi_vp_WORD		word1
+#define lpfc_reg_vfi_vfi_SHIFT		0
+#define lpfc_reg_vfi_vfi_MASK		0x0000FFFF
+#define lpfc_reg_vfi_vfi_WORD		word1
+	uint32_t word2;
+#define lpfc_reg_vfi_vpi_SHIFT		16
+#define lpfc_reg_vfi_vpi_MASK		0x0000FFFF
+#define lpfc_reg_vfi_vpi_WORD		word2
+#define lpfc_reg_vfi_fcfi_SHIFT		0
+#define lpfc_reg_vfi_fcfi_MASK		0x0000FFFF
+#define lpfc_reg_vfi_fcfi_WORD		word2
+	uint32_t word3_rsvd;
+	uint32_t word4_rsvd;
+	struct ulp_bde64 bde;
+	uint32_t word8_rsvd;
+	uint32_t word9_rsvd;
+	uint32_t word10;
+#define lpfc_reg_vfi_nport_id_SHIFT		0
+#define lpfc_reg_vfi_nport_id_MASK		0x00FFFFFF
+#define lpfc_reg_vfi_nport_id_WORD		word10
+};
+
+struct lpfc_mbx_init_vpi {
+	uint32_t word1;
+#define lpfc_init_vpi_vfi_SHIFT		16
+#define lpfc_init_vpi_vfi_MASK		0x0000FFFF
+#define lpfc_init_vpi_vfi_WORD		word1
+#define lpfc_init_vpi_vpi_SHIFT		0
+#define lpfc_init_vpi_vpi_MASK		0x0000FFFF
+#define lpfc_init_vpi_vpi_WORD		word1
+};
+
+struct lpfc_mbx_read_vpi {
+	uint32_t word1_rsvd;
+	uint32_t word2;
+#define lpfc_mbx_read_vpi_vnportid_SHIFT	0
+#define lpfc_mbx_read_vpi_vnportid_MASK		0x00FFFFFF
+#define lpfc_mbx_read_vpi_vnportid_WORD		word2
+	uint32_t word3_rsvd;
+	uint32_t word4;
+#define lpfc_mbx_read_vpi_acq_alpa_SHIFT	0
+#define lpfc_mbx_read_vpi_acq_alpa_MASK		0x000000FF
+#define lpfc_mbx_read_vpi_acq_alpa_WORD		word4
+#define lpfc_mbx_read_vpi_pb_SHIFT		15
+#define lpfc_mbx_read_vpi_pb_MASK		0x00000001
+#define lpfc_mbx_read_vpi_pb_WORD		word4
+#define lpfc_mbx_read_vpi_spec_alpa_SHIFT	16
+#define lpfc_mbx_read_vpi_spec_alpa_MASK	0x000000FF
+#define lpfc_mbx_read_vpi_spec_alpa_WORD	word4
+#define lpfc_mbx_read_vpi_ns_SHIFT		30
+#define lpfc_mbx_read_vpi_ns_MASK		0x00000001
+#define lpfc_mbx_read_vpi_ns_WORD		word4
+#define lpfc_mbx_read_vpi_hl_SHIFT		31
+#define lpfc_mbx_read_vpi_hl_MASK		0x00000001
+#define lpfc_mbx_read_vpi_hl_WORD		word4
+	uint32_t word5_rsvd;
+	uint32_t word6;
+#define lpfc_mbx_read_vpi_vpi_SHIFT		0
+#define lpfc_mbx_read_vpi_vpi_MASK		0x0000FFFF
+#define lpfc_mbx_read_vpi_vpi_WORD		word6
+	uint32_t word7;
+#define lpfc_mbx_read_vpi_mac_0_SHIFT		0
+#define lpfc_mbx_read_vpi_mac_0_MASK		0x000000FF
+#define lpfc_mbx_read_vpi_mac_0_WORD		word7
+#define lpfc_mbx_read_vpi_mac_1_SHIFT		8
+#define lpfc_mbx_read_vpi_mac_1_MASK		0x000000FF
+#define lpfc_mbx_read_vpi_mac_1_WORD		word7
+#define lpfc_mbx_read_vpi_mac_2_SHIFT		16
+#define lpfc_mbx_read_vpi_mac_2_MASK		0x000000FF
+#define lpfc_mbx_read_vpi_mac_2_WORD		word7
+#define lpfc_mbx_read_vpi_mac_3_SHIFT		24
+#define lpfc_mbx_read_vpi_mac_3_MASK		0x000000FF
+#define lpfc_mbx_read_vpi_mac_3_WORD		word7
+	uint32_t word8;
+#define lpfc_mbx_read_vpi_mac_4_SHIFT		0
+#define lpfc_mbx_read_vpi_mac_4_MASK		0x000000FF
+#define lpfc_mbx_read_vpi_mac_4_WORD		word8
+#define lpfc_mbx_read_vpi_mac_5_SHIFT		8
+#define lpfc_mbx_read_vpi_mac_5_MASK		0x000000FF
+#define lpfc_mbx_read_vpi_mac_5_WORD		word8
+#define lpfc_mbx_read_vpi_vlan_tag_SHIFT	16
+#define lpfc_mbx_read_vpi_vlan_tag_MASK		0x00000FFF
+#define lpfc_mbx_read_vpi_vlan_tag_WORD		word8
+#define lpfc_mbx_read_vpi_vv_SHIFT		28
+#define lpfc_mbx_read_vpi_vv_MASK		0x0000001
+#define lpfc_mbx_read_vpi_vv_WORD		word8
+};
+
+struct lpfc_mbx_unreg_vfi {
+	uint32_t word1_rsvd;
+	uint32_t word2;
+#define lpfc_unreg_vfi_vfi_SHIFT	0
+#define lpfc_unreg_vfi_vfi_MASK		0x0000FFFF
+#define lpfc_unreg_vfi_vfi_WORD		word2
+};
+
+struct lpfc_mbx_resume_rpi {
+	uint32_t word1;
+#define lpfc_resume_rpi_rpi_SHIFT	0
+#define lpfc_resume_rpi_rpi_MASK	0x0000FFFF
+#define lpfc_resume_rpi_rpi_WORD	word1
+	uint32_t event_tag;
+	uint32_t word3_rsvd;
+	uint32_t word4_rsvd;
+	uint32_t word5_rsvd;
+	uint32_t word6;
+#define lpfc_resume_rpi_vpi_SHIFT	0
+#define lpfc_resume_rpi_vpi_MASK	0x0000FFFF
+#define lpfc_resume_rpi_vpi_WORD	word6
+#define lpfc_resume_rpi_vfi_SHIFT	16
+#define lpfc_resume_rpi_vfi_MASK	0x0000FFFF
+#define lpfc_resume_rpi_vfi_WORD	word6
+};
+
+#define REG_FCF_INVALID_QID	0xFFFF
+struct lpfc_mbx_reg_fcfi {
+	uint32_t word1;
+#define lpfc_reg_fcfi_info_index_SHIFT	0
+#define lpfc_reg_fcfi_info_index_MASK	0x0000FFFF
+#define lpfc_reg_fcfi_info_index_WORD	word1
+#define lpfc_reg_fcfi_fcfi_SHIFT	16
+#define lpfc_reg_fcfi_fcfi_MASK		0x0000FFFF
+#define lpfc_reg_fcfi_fcfi_WORD		word1
+	uint32_t word2;
+#define lpfc_reg_fcfi_rq_id1_SHIFT	0
+#define lpfc_reg_fcfi_rq_id1_MASK	0x0000FFFF
+#define lpfc_reg_fcfi_rq_id1_WORD	word2
+#define lpfc_reg_fcfi_rq_id0_SHIFT	16
+#define lpfc_reg_fcfi_rq_id0_MASK	0x0000FFFF
+#define lpfc_reg_fcfi_rq_id0_WORD	word2
+	uint32_t word3;
+#define lpfc_reg_fcfi_rq_id3_SHIFT	0
+#define lpfc_reg_fcfi_rq_id3_MASK	0x0000FFFF
+#define lpfc_reg_fcfi_rq_id3_WORD	word3
+#define lpfc_reg_fcfi_rq_id2_SHIFT	16
+#define lpfc_reg_fcfi_rq_id2_MASK	0x0000FFFF
+#define lpfc_reg_fcfi_rq_id2_WORD	word3
+	uint32_t word4;
+#define lpfc_reg_fcfi_type_match0_SHIFT	24
+#define lpfc_reg_fcfi_type_match0_MASK	0x000000FF
+#define lpfc_reg_fcfi_type_match0_WORD	word4
+#define lpfc_reg_fcfi_type_mask0_SHIFT	16
+#define lpfc_reg_fcfi_type_mask0_MASK	0x000000FF
+#define lpfc_reg_fcfi_type_mask0_WORD	word4
+#define lpfc_reg_fcfi_rctl_match0_SHIFT	8
+#define lpfc_reg_fcfi_rctl_match0_MASK	0x000000FF
+#define lpfc_reg_fcfi_rctl_match0_WORD	word4
+#define lpfc_reg_fcfi_rctl_mask0_SHIFT	0
+#define lpfc_reg_fcfi_rctl_mask0_MASK	0x000000FF
+#define lpfc_reg_fcfi_rctl_mask0_WORD	word4
+	uint32_t word5;
+#define lpfc_reg_fcfi_type_match1_SHIFT	24
+#define lpfc_reg_fcfi_type_match1_MASK	0x000000FF
+#define lpfc_reg_fcfi_type_match1_WORD	word5
+#define lpfc_reg_fcfi_type_mask1_SHIFT	16
+#define lpfc_reg_fcfi_type_mask1_MASK	0x000000FF
+#define lpfc_reg_fcfi_type_mask1_WORD	word5
+#define lpfc_reg_fcfi_rctl_match1_SHIFT	8
+#define lpfc_reg_fcfi_rctl_match1_MASK	0x000000FF
+#define lpfc_reg_fcfi_rctl_match1_WORD	word5
+#define lpfc_reg_fcfi_rctl_mask1_SHIFT	0
+#define lpfc_reg_fcfi_rctl_mask1_MASK	0x000000FF
+#define lpfc_reg_fcfi_rctl_mask1_WORD	word5
+	uint32_t word6;
+#define lpfc_reg_fcfi_type_match2_SHIFT	24
+#define lpfc_reg_fcfi_type_match2_MASK	0x000000FF
+#define lpfc_reg_fcfi_type_match2_WORD	word6
+#define lpfc_reg_fcfi_type_mask2_SHIFT	16
+#define lpfc_reg_fcfi_type_mask2_MASK	0x000000FF
+#define lpfc_reg_fcfi_type_mask2_WORD	word6
+#define lpfc_reg_fcfi_rctl_match2_SHIFT	8
+#define lpfc_reg_fcfi_rctl_match2_MASK	0x000000FF
+#define lpfc_reg_fcfi_rctl_match2_WORD	word6
+#define lpfc_reg_fcfi_rctl_mask2_SHIFT	0
+#define lpfc_reg_fcfi_rctl_mask2_MASK	0x000000FF
+#define lpfc_reg_fcfi_rctl_mask2_WORD	word6
+	uint32_t word7;
+#define lpfc_reg_fcfi_type_match3_SHIFT	24
+#define lpfc_reg_fcfi_type_match3_MASK	0x000000FF
+#define lpfc_reg_fcfi_type_match3_WORD	word7
+#define lpfc_reg_fcfi_type_mask3_SHIFT	16
+#define lpfc_reg_fcfi_type_mask3_MASK	0x000000FF
+#define lpfc_reg_fcfi_type_mask3_WORD	word7
+#define lpfc_reg_fcfi_rctl_match3_SHIFT	8
+#define lpfc_reg_fcfi_rctl_match3_MASK	0x000000FF
+#define lpfc_reg_fcfi_rctl_match3_WORD	word7
+#define lpfc_reg_fcfi_rctl_mask3_SHIFT	0
+#define lpfc_reg_fcfi_rctl_mask3_MASK	0x000000FF
+#define lpfc_reg_fcfi_rctl_mask3_WORD	word7
+	uint32_t word8;
+#define lpfc_reg_fcfi_mam_SHIFT		13
+#define lpfc_reg_fcfi_mam_MASK		0x00000003
+#define lpfc_reg_fcfi_mam_WORD		word8
+#define LPFC_MAM_BOTH		0	/* Both SPMA and FPMA */
+#define LPFC_MAM_SPMA		1	/* Server Provided MAC Address */
+#define LPFC_MAM_FPMA		2	/* Fabric Provided MAC Address */
+#define lpfc_reg_fcfi_vv_SHIFT		12
+#define lpfc_reg_fcfi_vv_MASK		0x00000001
+#define lpfc_reg_fcfi_vv_WORD		word8
+#define lpfc_reg_fcfi_vlan_tag_SHIFT	0
+#define lpfc_reg_fcfi_vlan_tag_MASK	0x00000FFF
+#define lpfc_reg_fcfi_vlan_tag_WORD	word8
+};
+
+struct lpfc_mbx_unreg_fcfi {
+	uint32_t word1_rsv;
+	uint32_t word2;
+#define lpfc_unreg_fcfi_SHIFT		0
+#define lpfc_unreg_fcfi_MASK		0x0000FFFF
+#define lpfc_unreg_fcfi_WORD		word2
+};
+
+struct lpfc_mbx_read_rev {
+	uint32_t word1;
+#define lpfc_mbx_rd_rev_sli_lvl_SHIFT  		16
+#define lpfc_mbx_rd_rev_sli_lvl_MASK   		0x0000000F
+#define lpfc_mbx_rd_rev_sli_lvl_WORD   		word1
+#define lpfc_mbx_rd_rev_fcoe_SHIFT		20
+#define lpfc_mbx_rd_rev_fcoe_MASK		0x00000001
+#define lpfc_mbx_rd_rev_fcoe_WORD		word1
+#define lpfc_mbx_rd_rev_vpd_SHIFT		29
+#define lpfc_mbx_rd_rev_vpd_MASK		0x00000001
+#define lpfc_mbx_rd_rev_vpd_WORD		word1
+	uint32_t first_hw_rev;
+	uint32_t second_hw_rev;
+	uint32_t word4_rsvd;
+	uint32_t third_hw_rev;
+	uint32_t word6;
+#define lpfc_mbx_rd_rev_fcph_low_SHIFT		0
+#define lpfc_mbx_rd_rev_fcph_low_MASK		0x000000FF
+#define lpfc_mbx_rd_rev_fcph_low_WORD		word6
+#define lpfc_mbx_rd_rev_fcph_high_SHIFT		8
+#define lpfc_mbx_rd_rev_fcph_high_MASK		0x000000FF
+#define lpfc_mbx_rd_rev_fcph_high_WORD		word6
+#define lpfc_mbx_rd_rev_ftr_lvl_low_SHIFT	16
+#define lpfc_mbx_rd_rev_ftr_lvl_low_MASK	0x000000FF
+#define lpfc_mbx_rd_rev_ftr_lvl_low_WORD	word6
+#define lpfc_mbx_rd_rev_ftr_lvl_high_SHIFT	24
+#define lpfc_mbx_rd_rev_ftr_lvl_high_MASK	0x000000FF
+#define lpfc_mbx_rd_rev_ftr_lvl_high_WORD	word6
+	uint32_t word7_rsvd;
+	uint32_t fw_id_rev;
+	uint8_t  fw_name[16];
+	uint32_t ulp_fw_id_rev;
+	uint8_t  ulp_fw_name[16];
+	uint32_t word18_47_rsvd[30];
+	uint32_t word48;
+#define lpfc_mbx_rd_rev_avail_len_SHIFT		0
+#define lpfc_mbx_rd_rev_avail_len_MASK		0x00FFFFFF
+#define lpfc_mbx_rd_rev_avail_len_WORD		word48
+	uint32_t vpd_paddr_low;
+	uint32_t vpd_paddr_high;
+	uint32_t avail_vpd_len;
+	uint32_t rsvd_52_63[12];
+};
+
+struct lpfc_mbx_read_config {
+	uint32_t word1;
+#define lpfc_mbx_rd_conf_max_bbc_SHIFT		0
+#define lpfc_mbx_rd_conf_max_bbc_MASK		0x000000FF
+#define lpfc_mbx_rd_conf_max_bbc_WORD		word1
+#define lpfc_mbx_rd_conf_init_bbc_SHIFT		8
+#define lpfc_mbx_rd_conf_init_bbc_MASK		0x000000FF
+#define lpfc_mbx_rd_conf_init_bbc_WORD		word1
+	uint32_t word2;
+#define lpfc_mbx_rd_conf_nport_did_SHIFT	0
+#define lpfc_mbx_rd_conf_nport_did_MASK		0x00FFFFFF
+#define lpfc_mbx_rd_conf_nport_did_WORD		word2
+#define lpfc_mbx_rd_conf_topology_SHIFT		24
+#define lpfc_mbx_rd_conf_topology_MASK		0x000000FF
+#define lpfc_mbx_rd_conf_topology_WORD		word2
+	uint32_t word3;
+#define lpfc_mbx_rd_conf_ao_SHIFT		0
+#define lpfc_mbx_rd_conf_ao_MASK		0x00000001
+#define lpfc_mbx_rd_conf_ao_WORD		word3
+#define lpfc_mbx_rd_conf_bb_scn_SHIFT		8
+#define lpfc_mbx_rd_conf_bb_scn_MASK		0x0000000F
+#define lpfc_mbx_rd_conf_bb_scn_WORD		word3
+#define lpfc_mbx_rd_conf_cbb_scn_SHIFT		12
+#define lpfc_mbx_rd_conf_cbb_scn_MASK		0x0000000F
+#define lpfc_mbx_rd_conf_cbb_scn_WORD		word3
+#define lpfc_mbx_rd_conf_mc_SHIFT		29
+#define lpfc_mbx_rd_conf_mc_MASK		0x00000001
+#define lpfc_mbx_rd_conf_mc_WORD		word3
+	uint32_t word4;
+#define lpfc_mbx_rd_conf_e_d_tov_SHIFT		0
+#define lpfc_mbx_rd_conf_e_d_tov_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_e_d_tov_WORD		word4
+	uint32_t word5;
+#define lpfc_mbx_rd_conf_lp_tov_SHIFT		0
+#define lpfc_mbx_rd_conf_lp_tov_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_lp_tov_WORD		word5
+	uint32_t word6;
+#define lpfc_mbx_rd_conf_r_a_tov_SHIFT		0
+#define lpfc_mbx_rd_conf_r_a_tov_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_r_a_tov_WORD		word6
+	uint32_t word7;
+#define lpfc_mbx_rd_conf_r_t_tov_SHIFT		0
+#define lpfc_mbx_rd_conf_r_t_tov_MASK		0x000000FF
+#define lpfc_mbx_rd_conf_r_t_tov_WORD		word7
+	uint32_t word8;
+#define lpfc_mbx_rd_conf_al_tov_SHIFT		0
+#define lpfc_mbx_rd_conf_al_tov_MASK		0x0000000F
+#define lpfc_mbx_rd_conf_al_tov_WORD		word8
+	uint32_t word9;
+#define lpfc_mbx_rd_conf_lmt_SHIFT		0
+#define lpfc_mbx_rd_conf_lmt_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_lmt_WORD		word9
+	uint32_t word10;
+#define lpfc_mbx_rd_conf_max_alpa_SHIFT		0
+#define lpfc_mbx_rd_conf_max_alpa_MASK		0x000000FF
+#define lpfc_mbx_rd_conf_max_alpa_WORD		word10
+	uint32_t word11_rsvd;
+	uint32_t word12;
+#define lpfc_mbx_rd_conf_xri_base_SHIFT		0
+#define lpfc_mbx_rd_conf_xri_base_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_xri_base_WORD		word12
+#define lpfc_mbx_rd_conf_xri_count_SHIFT	16
+#define lpfc_mbx_rd_conf_xri_count_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_xri_count_WORD		word12
+	uint32_t word13;
+#define lpfc_mbx_rd_conf_rpi_base_SHIFT		0
+#define lpfc_mbx_rd_conf_rpi_base_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_rpi_base_WORD		word13
+#define lpfc_mbx_rd_conf_rpi_count_SHIFT	16
+#define lpfc_mbx_rd_conf_rpi_count_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_rpi_count_WORD		word13
+	uint32_t word14;
+#define lpfc_mbx_rd_conf_vpi_base_SHIFT		0
+#define lpfc_mbx_rd_conf_vpi_base_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_vpi_base_WORD		word14
+#define lpfc_mbx_rd_conf_vpi_count_SHIFT	16
+#define lpfc_mbx_rd_conf_vpi_count_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_vpi_count_WORD		word14
+	uint32_t word15;
+#define lpfc_mbx_rd_conf_vfi_base_SHIFT         0
+#define lpfc_mbx_rd_conf_vfi_base_MASK          0x0000FFFF
+#define lpfc_mbx_rd_conf_vfi_base_WORD          word15
+#define lpfc_mbx_rd_conf_vfi_count_SHIFT        16
+#define lpfc_mbx_rd_conf_vfi_count_MASK         0x0000FFFF
+#define lpfc_mbx_rd_conf_vfi_count_WORD         word15
+	uint32_t word16;
+#define lpfc_mbx_rd_conf_fcfi_base_SHIFT	0
+#define lpfc_mbx_rd_conf_fcfi_base_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_fcfi_base_WORD		word16
+#define lpfc_mbx_rd_conf_fcfi_count_SHIFT	16
+#define lpfc_mbx_rd_conf_fcfi_count_MASK	0x0000FFFF
+#define lpfc_mbx_rd_conf_fcfi_count_WORD	word16
+	uint32_t word17;
+#define lpfc_mbx_rd_conf_rq_count_SHIFT		0
+#define lpfc_mbx_rd_conf_rq_count_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_rq_count_WORD		word17
+#define lpfc_mbx_rd_conf_eq_count_SHIFT		16
+#define lpfc_mbx_rd_conf_eq_count_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_eq_count_WORD		word17
+	uint32_t word18;
+#define lpfc_mbx_rd_conf_wq_count_SHIFT		0
+#define lpfc_mbx_rd_conf_wq_count_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_wq_count_WORD		word18
+#define lpfc_mbx_rd_conf_cq_count_SHIFT		16
+#define lpfc_mbx_rd_conf_cq_count_MASK		0x0000FFFF
+#define lpfc_mbx_rd_conf_cq_count_WORD		word18
+};
+
+struct lpfc_mbx_request_features {
+	uint32_t word1;
+#define lpfc_mbx_rq_ftr_qry_SHIFT		0
+#define lpfc_mbx_rq_ftr_qry_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_qry_WORD		word1
+	uint32_t word2;
+#define lpfc_mbx_rq_ftr_rq_iaab_SHIFT		0
+#define lpfc_mbx_rq_ftr_rq_iaab_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rq_iaab_WORD		word2
+#define lpfc_mbx_rq_ftr_rq_npiv_SHIFT		1
+#define lpfc_mbx_rq_ftr_rq_npiv_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rq_npiv_WORD		word2
+#define lpfc_mbx_rq_ftr_rq_dif_SHIFT		2
+#define lpfc_mbx_rq_ftr_rq_dif_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rq_dif_WORD		word2
+#define lpfc_mbx_rq_ftr_rq_vf_SHIFT		3
+#define lpfc_mbx_rq_ftr_rq_vf_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rq_vf_WORD		word2
+#define lpfc_mbx_rq_ftr_rq_fcpi_SHIFT		4
+#define lpfc_mbx_rq_ftr_rq_fcpi_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rq_fcpi_WORD		word2
+#define lpfc_mbx_rq_ftr_rq_fcpt_SHIFT		5
+#define lpfc_mbx_rq_ftr_rq_fcpt_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rq_fcpt_WORD		word2
+#define lpfc_mbx_rq_ftr_rq_fcpc_SHIFT		6
+#define lpfc_mbx_rq_ftr_rq_fcpc_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rq_fcpc_WORD		word2
+#define lpfc_mbx_rq_ftr_rq_ifip_SHIFT		7
+#define lpfc_mbx_rq_ftr_rq_ifip_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rq_ifip_WORD		word2
+	uint32_t word3;
+#define lpfc_mbx_rq_ftr_rsp_iaab_SHIFT		0
+#define lpfc_mbx_rq_ftr_rsp_iaab_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rsp_iaab_WORD		word3
+#define lpfc_mbx_rq_ftr_rsp_npiv_SHIFT		1
+#define lpfc_mbx_rq_ftr_rsp_npiv_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rsp_npiv_WORD		word3
+#define lpfc_mbx_rq_ftr_rsp_dif_SHIFT		2
+#define lpfc_mbx_rq_ftr_rsp_dif_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rsp_dif_WORD		word3
+#define lpfc_mbx_rq_ftr_rsp_vf_SHIFT		3
+#define lpfc_mbx_rq_ftr_rsp_vf__MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rsp_vf_WORD		word3
+#define lpfc_mbx_rq_ftr_rsp_fcpi_SHIFT		4
+#define lpfc_mbx_rq_ftr_rsp_fcpi_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rsp_fcpi_WORD		word3
+#define lpfc_mbx_rq_ftr_rsp_fcpt_SHIFT		5
+#define lpfc_mbx_rq_ftr_rsp_fcpt_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rsp_fcpt_WORD		word3
+#define lpfc_mbx_rq_ftr_rsp_fcpc_SHIFT		6
+#define lpfc_mbx_rq_ftr_rsp_fcpc_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rsp_fcpc_WORD		word3
+#define lpfc_mbx_rq_ftr_rsp_ifip_SHIFT		7
+#define lpfc_mbx_rq_ftr_rsp_ifip_MASK		0x00000001
+#define lpfc_mbx_rq_ftr_rsp_ifip_WORD		word3
+};
+
+/* Mailbox Completion Queue Error Messages */
+#define MB_CQE_STATUS_SUCCESS 			0x0
+#define MB_CQE_STATUS_INSUFFICIENT_PRIVILEGES	0x1
+#define MB_CQE_STATUS_INVALID_PARAMETER		0x2
+#define MB_CQE_STATUS_INSUFFICIENT_RESOURCES	0x3
+#define MB_CEQ_STATUS_QUEUE_FLUSHING		0x4
+#define MB_CQE_STATUS_DMA_FAILED		0x5
+
+/* mailbox queue entry structure */
+struct lpfc_mqe {
+	uint32_t word0;
+#define lpfc_mqe_status_SHIFT		16
+#define lpfc_mqe_status_MASK		0x0000FFFF
+#define lpfc_mqe_status_WORD		word0
+#define lpfc_mqe_command_SHIFT		8
+#define lpfc_mqe_command_MASK		0x000000FF
+#define lpfc_mqe_command_WORD		word0
+	union {
+		uint32_t mb_words[LPFC_SLI4_MB_WORD_COUNT - 1];
+		/* sli4 mailbox commands */
+		struct lpfc_mbx_sli4_config sli4_config;
+		struct lpfc_mbx_init_vfi init_vfi;
+		struct lpfc_mbx_reg_vfi reg_vfi;
+		struct lpfc_mbx_reg_vfi unreg_vfi;
+		struct lpfc_mbx_init_vpi init_vpi;
+		struct lpfc_mbx_resume_rpi resume_rpi;
+		struct lpfc_mbx_read_fcf_tbl read_fcf_tbl;
+		struct lpfc_mbx_add_fcf_tbl_entry add_fcf_entry;
+		struct lpfc_mbx_del_fcf_tbl_entry del_fcf_entry;
+		struct lpfc_mbx_reg_fcfi reg_fcfi;
+		struct lpfc_mbx_unreg_fcfi unreg_fcfi;
+		struct lpfc_mbx_mq_create mq_create;
+		struct lpfc_mbx_eq_create eq_create;
+		struct lpfc_mbx_cq_create cq_create;
+		struct lpfc_mbx_wq_create wq_create;
+		struct lpfc_mbx_rq_create rq_create;
+		struct lpfc_mbx_mq_destroy mq_destroy;
+		struct lpfc_mbx_eq_destroy eq_destroy;
+		struct lpfc_mbx_cq_destroy cq_destroy;
+		struct lpfc_mbx_wq_destroy wq_destroy;
+		struct lpfc_mbx_rq_destroy rq_destroy;
+		struct lpfc_mbx_post_sgl_pages post_sgl_pages;
+		struct lpfc_mbx_nembed_cmd nembed_cmd;
+		struct lpfc_mbx_read_rev read_rev;
+		struct lpfc_mbx_read_vpi read_vpi;
+		struct lpfc_mbx_read_config rd_config;
+		struct lpfc_mbx_request_features req_ftrs;
+		struct lpfc_mbx_post_hdr_tmpl hdr_tmpl;
+		struct lpfc_mbx_nop nop;
+	} un;
+};
+
+struct lpfc_mcqe {
+	uint32_t word0;
+#define lpfc_mcqe_status_SHIFT		0
+#define lpfc_mcqe_status_MASK		0x0000FFFF
+#define lpfc_mcqe_status_WORD		word0
+#define lpfc_mcqe_ext_status_SHIFT	16
+#define lpfc_mcqe_ext_status_MASK  	0x0000FFFF
+#define lpfc_mcqe_ext_status_WORD 	word0
+	uint32_t mcqe_tag0;
+	uint32_t mcqe_tag1;
+	uint32_t trailer;
+#define lpfc_trailer_valid_SHIFT	31
+#define lpfc_trailer_valid_MASK		0x00000001
+#define lpfc_trailer_valid_WORD		trailer
+#define lpfc_trailer_async_SHIFT	30
+#define lpfc_trailer_async_MASK		0x00000001
+#define lpfc_trailer_async_WORD		trailer
+#define lpfc_trailer_hpi_SHIFT		29
+#define lpfc_trailer_hpi_MASK		0x00000001
+#define lpfc_trailer_hpi_WORD		trailer
+#define lpfc_trailer_completed_SHIFT	28
+#define lpfc_trailer_completed_MASK	0x00000001
+#define lpfc_trailer_completed_WORD	trailer
+#define lpfc_trailer_consumed_SHIFT	27
+#define lpfc_trailer_consumed_MASK	0x00000001
+#define lpfc_trailer_consumed_WORD	trailer
+#define lpfc_trailer_type_SHIFT		16
+#define lpfc_trailer_type_MASK		0x000000FF
+#define lpfc_trailer_type_WORD		trailer
+#define lpfc_trailer_code_SHIFT		8
+#define lpfc_trailer_code_MASK		0x000000FF
+#define lpfc_trailer_code_WORD		trailer
+#define LPFC_TRAILER_CODE_LINK	0x1
+#define LPFC_TRAILER_CODE_FCOE	0x2
+#define LPFC_TRAILER_CODE_DCBX	0x3
+};
+
+struct lpfc_acqe_link {
+	uint32_t word0;
+#define lpfc_acqe_link_speed_SHIFT		24
+#define lpfc_acqe_link_speed_MASK		0x000000FF
+#define lpfc_acqe_link_speed_WORD		word0
+#define LPFC_ASYNC_LINK_SPEED_ZERO		0x0
+#define LPFC_ASYNC_LINK_SPEED_10MBPS		0x1
+#define LPFC_ASYNC_LINK_SPEED_100MBPS		0x2
+#define LPFC_ASYNC_LINK_SPEED_1GBPS		0x3
+#define LPFC_ASYNC_LINK_SPEED_10GBPS		0x4
+#define lpfc_acqe_link_duplex_SHIFT		16
+#define lpfc_acqe_link_duplex_MASK		0x000000FF
+#define lpfc_acqe_link_duplex_WORD		word0
+#define LPFC_ASYNC_LINK_DUPLEX_NONE		0x0
+#define LPFC_ASYNC_LINK_DUPLEX_HALF		0x1
+#define LPFC_ASYNC_LINK_DUPLEX_FULL		0x2
+#define lpfc_acqe_link_status_SHIFT		8
+#define lpfc_acqe_link_status_MASK		0x000000FF
+#define lpfc_acqe_link_status_WORD		word0
+#define LPFC_ASYNC_LINK_STATUS_DOWN		0x0
+#define LPFC_ASYNC_LINK_STATUS_UP		0x1
+#define LPFC_ASYNC_LINK_STATUS_LOGICAL_DOWN	0x2
+#define LPFC_ASYNC_LINK_STATUS_LOGICAL_UP	0x3
+#define lpfc_acqe_link_physical_SHIFT		0
+#define lpfc_acqe_link_physical_MASK		0x000000FF
+#define lpfc_acqe_link_physical_WORD		word0
+#define LPFC_ASYNC_LINK_PORT_A			0x0
+#define LPFC_ASYNC_LINK_PORT_B			0x1
+	uint32_t word1;
+#define lpfc_acqe_link_fault_SHIFT	0
+#define lpfc_acqe_link_fault_MASK	0x000000FF
+#define lpfc_acqe_link_fault_WORD	word1
+#define LPFC_ASYNC_LINK_FAULT_NONE	0x0
+#define LPFC_ASYNC_LINK_FAULT_LOCAL	0x1
+#define LPFC_ASYNC_LINK_FAULT_REMOTE	0x2
+	uint32_t event_tag;
+	uint32_t trailer;
+};
+
+struct lpfc_acqe_fcoe {
+	uint32_t fcf_index;
+	uint32_t word1;
+#define lpfc_acqe_fcoe_fcf_count_SHIFT		0
+#define lpfc_acqe_fcoe_fcf_count_MASK		0x0000FFFF
+#define lpfc_acqe_fcoe_fcf_count_WORD		word1
+#define lpfc_acqe_fcoe_event_type_SHIFT		16
+#define lpfc_acqe_fcoe_event_type_MASK		0x0000FFFF
+#define lpfc_acqe_fcoe_event_type_WORD		word1
+#define LPFC_FCOE_EVENT_TYPE_NEW_FCF		0x1
+#define LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL	0x2
+#define LPFC_FCOE_EVENT_TYPE_FCF_DEAD		0x3
+	uint32_t event_tag;
+	uint32_t trailer;
+};
+
+struct lpfc_acqe_dcbx {
+	uint32_t tlv_ttl;
+	uint32_t reserved;
+	uint32_t event_tag;
+	uint32_t trailer;
+};
+
+/*
+ * Define the bootstrap mailbox (bmbx) region used to communicate
+ * mailbox command between the host and port. The mailbox consists
+ * of a payload area of 256 bytes and a completion queue of length
+ * 16 bytes.
+ */
+struct lpfc_bmbx_create {
+	struct lpfc_mqe mqe;
+	struct lpfc_mcqe mcqe;
+};
+
+#define SGL_ALIGN_SZ 64
+#define SGL_PAGE_SIZE 4096
+/* align SGL addr on a size boundary - adjust address up */
+#define NO_XRI ((uint16_t)-1)
+struct wqe_common {
+	uint32_t word6;
+#define wqe_xri_SHIFT         0
+#define wqe_xri_MASK          0x0000FFFF
+#define wqe_xri_WORD          word6
+#define wqe_ctxt_tag_SHIFT    16
+#define wqe_ctxt_tag_MASK     0x0000FFFF
+#define wqe_ctxt_tag_WORD     word6
+	uint32_t word7;
+#define wqe_ct_SHIFT          2
+#define wqe_ct_MASK           0x00000003
+#define wqe_ct_WORD           word7
+#define wqe_status_SHIFT      4
+#define wqe_status_MASK       0x0000000f
+#define wqe_status_WORD       word7
+#define wqe_cmnd_SHIFT        8
+#define wqe_cmnd_MASK         0x000000ff
+#define wqe_cmnd_WORD         word7
+#define wqe_class_SHIFT       16
+#define wqe_class_MASK        0x00000007
+#define wqe_class_WORD        word7
+#define wqe_pu_SHIFT          20
+#define wqe_pu_MASK           0x00000003
+#define wqe_pu_WORD           word7
+#define wqe_erp_SHIFT         22
+#define wqe_erp_MASK          0x00000001
+#define wqe_erp_WORD          word7
+#define wqe_lnk_SHIFT         23
+#define wqe_lnk_MASK          0x00000001
+#define wqe_lnk_WORD          word7
+#define wqe_tmo_SHIFT         24
+#define wqe_tmo_MASK          0x000000ff
+#define wqe_tmo_WORD          word7
+	uint32_t abort_tag; /* word 8 in WQE */
+	uint32_t word9;
+#define wqe_reqtag_SHIFT      0
+#define wqe_reqtag_MASK       0x0000FFFF
+#define wqe_reqtag_WORD       word9
+#define wqe_rcvoxid_SHIFT     16
+#define wqe_rcvoxid_MASK       0x0000FFFF
+#define wqe_rcvoxid_WORD       word9
+	uint32_t word10;
+#define wqe_pri_SHIFT         16
+#define wqe_pri_MASK          0x00000007
+#define wqe_pri_WORD          word10
+#define wqe_pv_SHIFT          19
+#define wqe_pv_MASK           0x00000001
+#define wqe_pv_WORD           word10
+#define wqe_xc_SHIFT          21
+#define wqe_xc_MASK           0x00000001
+#define wqe_xc_WORD           word10
+#define wqe_ccpe_SHIFT        23
+#define wqe_ccpe_MASK         0x00000001
+#define wqe_ccpe_WORD         word10
+#define wqe_ccp_SHIFT         24
+#define wqe_ccp_MASK         0x000000ff
+#define wqe_ccp_WORD         word10
+	uint32_t word11;
+#define wqe_cmd_type_SHIFT  0
+#define wqe_cmd_type_MASK   0x0000000f
+#define wqe_cmd_type_WORD   word11
+#define wqe_wqec_SHIFT      7
+#define wqe_wqec_MASK       0x00000001
+#define wqe_wqec_WORD       word11
+#define wqe_cqid_SHIFT      16
+#define wqe_cqid_MASK       0x000003ff
+#define wqe_cqid_WORD       word11
+};
+
+struct wqe_did {
+	uint32_t word5;
+#define wqe_els_did_SHIFT         0
+#define wqe_els_did_MASK          0x00FFFFFF
+#define wqe_els_did_WORD          word5
+#define wqe_xmit_bls_ar_SHIFT         30
+#define wqe_xmit_bls_ar_MASK          0x00000001
+#define wqe_xmit_bls_ar_WORD          word5
+#define wqe_xmit_bls_xo_SHIFT         31
+#define wqe_xmit_bls_xo_MASK          0x00000001
+#define wqe_xmit_bls_xo_WORD          word5
+};
+
+struct els_request64_wqe {
+	struct ulp_bde64 bde;
+	uint32_t payload_len;
+	uint32_t word4;
+#define els_req64_sid_SHIFT         0
+#define els_req64_sid_MASK          0x00FFFFFF
+#define els_req64_sid_WORD          word4
+#define els_req64_sp_SHIFT          24
+#define els_req64_sp_MASK           0x00000001
+#define els_req64_sp_WORD           word4
+#define els_req64_vf_SHIFT          25
+#define els_req64_vf_MASK           0x00000001
+#define els_req64_vf_WORD           word4
+	struct wqe_did	wqe_dest;
+	struct wqe_common wqe_com; /* words 6-11 */
+	uint32_t word12;
+#define els_req64_vfid_SHIFT        1
+#define els_req64_vfid_MASK         0x00000FFF
+#define els_req64_vfid_WORD         word12
+#define els_req64_pri_SHIFT         13
+#define els_req64_pri_MASK          0x00000007
+#define els_req64_pri_WORD          word12
+	uint32_t word13;
+#define els_req64_hopcnt_SHIFT      24
+#define els_req64_hopcnt_MASK       0x000000ff
+#define els_req64_hopcnt_WORD       word13
+	uint32_t reserved[2];
+};
+
+struct xmit_els_rsp64_wqe {
+	struct ulp_bde64 bde;
+	uint32_t rsvd3;
+	uint32_t rsvd4;
+	struct wqe_did	wqe_dest;
+	struct wqe_common wqe_com; /* words 6-11 */
+	uint32_t rsvd_12_15[4];
+};
+
+struct xmit_bls_rsp64_wqe {
+	uint32_t payload0;
+	uint32_t word1;
+#define xmit_bls_rsp64_rxid_SHIFT  0
+#define xmit_bls_rsp64_rxid_MASK   0x0000ffff
+#define xmit_bls_rsp64_rxid_WORD   word1
+#define xmit_bls_rsp64_oxid_SHIFT  16
+#define xmit_bls_rsp64_oxid_MASK   0x0000ffff
+#define xmit_bls_rsp64_oxid_WORD   word1
+	uint32_t word2;
+#define xmit_bls_rsp64_seqcntlo_SHIFT  0
+#define xmit_bls_rsp64_seqcntlo_MASK   0x0000ffff
+#define xmit_bls_rsp64_seqcntlo_WORD   word2
+#define xmit_bls_rsp64_seqcnthi_SHIFT  16
+#define xmit_bls_rsp64_seqcnthi_MASK   0x0000ffff
+#define xmit_bls_rsp64_seqcnthi_WORD   word2
+	uint32_t rsrvd3;
+	uint32_t rsrvd4;
+	struct wqe_did	wqe_dest;
+	struct wqe_common wqe_com; /* words 6-11 */
+	uint32_t rsvd_12_15[4];
+};
+struct wqe_rctl_dfctl {
+	uint32_t word5;
+#define wqe_si_SHIFT 2
+#define wqe_si_MASK  0x000000001
+#define wqe_si_WORD  word5
+#define wqe_la_SHIFT 3
+#define wqe_la_MASK  0x000000001
+#define wqe_la_WORD  word5
+#define wqe_ls_SHIFT 7
+#define wqe_ls_MASK  0x000000001
+#define wqe_ls_WORD  word5
+#define wqe_dfctl_SHIFT 8
+#define wqe_dfctl_MASK  0x0000000ff
+#define wqe_dfctl_WORD  word5
+#define wqe_type_SHIFT 16
+#define wqe_type_MASK  0x0000000ff
+#define wqe_type_WORD  word5
+#define wqe_rctl_SHIFT 24
+#define wqe_rctl_MASK  0x0000000ff
+#define wqe_rctl_WORD  word5
+};
+
+struct xmit_seq64_wqe {
+	struct ulp_bde64 bde;
+	uint32_t paylaod_offset;
+	uint32_t relative_offset;
+	struct wqe_rctl_dfctl wge_ctl;
+	struct wqe_common wqe_com; /* words 6-11 */
+	/* Note: word10 different REVISIT */
+	uint32_t xmit_len;
+	uint32_t rsvd_12_15[3];
+};
+struct xmit_bcast64_wqe {
+	struct ulp_bde64 bde;
+	uint32_t paylaod_len;
+	uint32_t rsvd4;
+	struct wqe_rctl_dfctl wge_ctl; /* word 5 */
+	struct wqe_common wqe_com;     /* words 6-11 */
+	uint32_t rsvd_12_15[4];
+};
+
+struct gen_req64_wqe {
+	struct ulp_bde64 bde;
+	uint32_t command_len;
+	uint32_t payload_len;
+	struct wqe_rctl_dfctl wge_ctl; /* word 5 */
+	struct wqe_common wqe_com;     /* words 6-11 */
+	uint32_t rsvd_12_15[4];
+};
+
+struct create_xri_wqe {
+	uint32_t rsrvd[5];           /* words 0-4 */
+	struct wqe_did	wqe_dest;  /* word 5 */
+	struct wqe_common wqe_com; /* words 6-11 */
+	uint32_t rsvd_12_15[4];         /* word 12-15 */
+};
+
+#define T_REQUEST_TAG 3
+#define T_XRI_TAG 1
+
+struct abort_cmd_wqe {
+	uint32_t rsrvd[3];
+	uint32_t word3;
+#define	abort_cmd_ia_SHIFT  0
+#define	abort_cmd_ia_MASK  0x000000001
+#define	abort_cmd_ia_WORD  word3
+#define	abort_cmd_criteria_SHIFT  8
+#define	abort_cmd_criteria_MASK  0x0000000ff
+#define	abort_cmd_criteria_WORD  word3
+	uint32_t rsrvd4;
+	uint32_t rsrvd5;
+	struct wqe_common wqe_com;     /* words 6-11 */
+	uint32_t rsvd_12_15[4];         /* word 12-15 */
+};
+
+struct fcp_iwrite64_wqe {
+	struct ulp_bde64 bde;
+	uint32_t payload_len;
+	uint32_t total_xfer_len;
+	uint32_t initial_xfer_len;
+	struct wqe_common wqe_com;     /* words 6-11 */
+	uint32_t rsvd_12_15[4];         /* word 12-15 */
+};
+
+struct fcp_iread64_wqe {
+	struct ulp_bde64 bde;
+	uint32_t payload_len;          /* word 3 */
+	uint32_t total_xfer_len;       /* word 4 */
+	uint32_t rsrvd5;               /* word 5 */
+	struct wqe_common wqe_com;     /* words 6-11 */
+	uint32_t rsvd_12_15[4];         /* word 12-15 */
+};
+
+struct fcp_icmnd64_wqe {
+	struct ulp_bde64 bde;	 /* words 0-2 */
+	uint32_t rsrvd[3];             /* words 3-5 */
+	struct wqe_common wqe_com;     /* words 6-11 */
+	uint32_t rsvd_12_15[4];         /* word 12-15 */
+};
+
+
+union lpfc_wqe {
+	uint32_t words[16];
+	struct lpfc_wqe_generic generic;
+	struct fcp_icmnd64_wqe fcp_icmd;
+	struct fcp_iread64_wqe fcp_iread;
+	struct fcp_iwrite64_wqe fcp_iwrite;
+	struct abort_cmd_wqe abort_cmd;
+	struct create_xri_wqe create_xri;
+	struct xmit_bcast64_wqe xmit_bcast64;
+	struct xmit_seq64_wqe xmit_sequence;
+	struct xmit_bls_rsp64_wqe xmit_bls_rsp;
+	struct xmit_els_rsp64_wqe xmit_els_rsp;
+	struct els_request64_wqe els_req;
+	struct gen_req64_wqe gen_req;
+};
+
+#define FCP_COMMAND 0x0
+#define FCP_COMMAND_DATA_OUT 0x1
+#define ELS_COMMAND_NON_FIP 0xC
+#define ELS_COMMAND_FIP 0xD
+#define OTHER_COMMAND 0x8
+
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 86d1bdc..2f5907f 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-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -34,8 +34,10 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -51,9 +53,23 @@
 unsigned long _dump_buf_dif_order;
 spinlock_t _dump_buf_lock;
 
-static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int);
 static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);
 static int lpfc_post_rcv_buf(struct lpfc_hba *);
+static int lpfc_sli4_queue_create(struct lpfc_hba *);
+static void lpfc_sli4_queue_destroy(struct lpfc_hba *);
+static int lpfc_create_bootstrap_mbox(struct lpfc_hba *);
+static int lpfc_setup_endian_order(struct lpfc_hba *);
+static int lpfc_sli4_read_config(struct lpfc_hba *);
+static void lpfc_destroy_bootstrap_mbox(struct lpfc_hba *);
+static void lpfc_free_sgl_list(struct lpfc_hba *);
+static int lpfc_init_sgl_list(struct lpfc_hba *);
+static int lpfc_init_active_sgl_array(struct lpfc_hba *);
+static void lpfc_free_active_sgl(struct lpfc_hba *);
+static int lpfc_hba_down_post_s3(struct lpfc_hba *phba);
+static int lpfc_hba_down_post_s4(struct lpfc_hba *phba);
+static int lpfc_sli4_cq_event_pool_create(struct lpfc_hba *);
+static void lpfc_sli4_cq_event_pool_destroy(struct lpfc_hba *);
+static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *);
 
 static struct scsi_transport_template *lpfc_transport_template = NULL;
 static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
@@ -92,7 +108,7 @@
 		return -ENOMEM;
 	}
 
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 	phba->link_state = LPFC_INIT_MBX_CMDS;
 
 	if (lpfc_is_LC_HBA(phba->pcidev->device)) {
@@ -205,6 +221,11 @@
 					mb->mbxCommand, mb->mbxStatus);
 			mb->un.varDmp.word_cnt = 0;
 		}
+		/* dump mem may return a zero when finished or we got a
+		 * mailbox error, either way we are done.
+		 */
+		if (mb->un.varDmp.word_cnt == 0)
+			break;
 		if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset)
 			mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset;
 		lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
@@ -233,7 +254,7 @@
 static void
 lpfc_config_async_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
 {
-	if (pmboxq->mb.mbxStatus == MBX_SUCCESS)
+	if (pmboxq->u.mb.mbxStatus == MBX_SUCCESS)
 		phba->temp_sensor_support = 1;
 	else
 		phba->temp_sensor_support = 0;
@@ -260,7 +281,7 @@
 	/* character array used for decoding dist type. */
 	char dist_char[] = "nabx";
 
-	if (pmboxq->mb.mbxStatus != MBX_SUCCESS) {
+	if (pmboxq->u.mb.mbxStatus != MBX_SUCCESS) {
 		mempool_free(pmboxq, phba->mbox_mem_pool);
 		return;
 	}
@@ -268,7 +289,7 @@
 	prg = (struct prog_id *) &prog_id_word;
 
 	/* word 7 contain option rom version */
-	prog_id_word = pmboxq->mb.un.varWords[7];
+	prog_id_word = pmboxq->u.mb.un.varWords[7];
 
 	/* Decode the Option rom version word to a readable string */
 	if (prg->dist < 4)
@@ -325,7 +346,7 @@
 		phba->link_state = LPFC_HBA_ERROR;
 		return -ENOMEM;
 	}
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 
 	/* Get login parameters for NID.  */
 	lpfc_read_sparam(phba, pmb, 0);
@@ -364,6 +385,7 @@
 	/* Update the fc_host data structures with new wwn. */
 	fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn);
 	fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn);
+	fc_host_max_npiv_vports(shost) = phba->max_vpi;
 
 	/* If no serial number in VPD data, use low 6 bytes of WWNN */
 	/* This should be consolidated into parse_vpd ? - mr */
@@ -460,17 +482,18 @@
 			lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
 					"0352 Config MSI mailbox command "
 					"failed, mbxCmd x%x, mbxStatus x%x\n",
-					pmb->mb.mbxCommand, pmb->mb.mbxStatus);
+					pmb->u.mb.mbxCommand,
+					pmb->u.mb.mbxStatus);
 			mempool_free(pmb, phba->mbox_mem_pool);
 			return -EIO;
 		}
 	}
 
+	spin_lock_irq(&phba->hbalock);
 	/* Initialize ERATT handling flag */
 	phba->hba_flag &= ~HBA_ERATT_HANDLED;
 
 	/* Enable appropriate host interrupts */
-	spin_lock_irq(&phba->hbalock);
 	status = readl(phba->HCregaddr);
 	status |= HC_MBINT_ENA | HC_ERINT_ENA | HC_LAINT_ENA;
 	if (psli->num_rings > 0)
@@ -571,16 +594,20 @@
 {
 	struct lpfc_vport **vports;
 	int i;
-	/* Disable interrupts */
-	writel(0, phba->HCregaddr);
-	readl(phba->HCregaddr); /* flush */
+
+	if (phba->sli_rev <= LPFC_SLI_REV3) {
+		/* Disable interrupts */
+		writel(0, phba->HCregaddr);
+		readl(phba->HCregaddr); /* flush */
+	}
 
 	if (phba->pport->load_flag & FC_UNLOADING)
 		lpfc_cleanup_discovery_resources(phba->pport);
 	else {
 		vports = lpfc_create_vport_work_array(phba);
 		if (vports != NULL)
-			for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
+			for (i = 0; i <= phba->max_vports &&
+				vports[i] != NULL; i++)
 				lpfc_cleanup_discovery_resources(vports[i]);
 		lpfc_destroy_vport_work_array(phba, vports);
 	}
@@ -588,7 +615,7 @@
 }
 
 /**
- * lpfc_hba_down_post - Perform lpfc uninitialization after HBA reset
+ * lpfc_hba_down_post_s3 - Perform lpfc uninitialization after HBA reset
  * @phba: pointer to lpfc HBA data structure.
  *
  * This routine will do uninitialization after the HBA is reset when bring
@@ -598,8 +625,8 @@
  *   0 - sucess.
  *   Any other value - error.
  **/
-int
-lpfc_hba_down_post(struct lpfc_hba *phba)
+static int
+lpfc_hba_down_post_s3(struct lpfc_hba *phba)
 {
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring *pring;
@@ -642,6 +669,77 @@
 
 	return 0;
 }
+/**
+ * lpfc_hba_down_post_s4 - Perform lpfc uninitialization after HBA reset
+ * @phba: pointer to lpfc HBA data structure.
+ *
+ * This routine will do uninitialization after the HBA is reset when bring
+ * down the SLI Layer.
+ *
+ * Return codes
+ *   0 - sucess.
+ *   Any other value - error.
+ **/
+static int
+lpfc_hba_down_post_s4(struct lpfc_hba *phba)
+{
+	struct lpfc_scsi_buf *psb, *psb_next;
+	LIST_HEAD(aborts);
+	int ret;
+	unsigned long iflag = 0;
+	ret = lpfc_hba_down_post_s3(phba);
+	if (ret)
+		return ret;
+	/* At this point in time the HBA is either reset or DOA. Either
+	 * way, nothing should be on lpfc_abts_els_sgl_list, it needs to be
+	 * on the lpfc_sgl_list so that it can either be freed if the
+	 * driver is unloading or reposted if the driver is restarting
+	 * the port.
+	 */
+	spin_lock_irq(&phba->hbalock);  /* required for lpfc_sgl_list and */
+					/* scsl_buf_list */
+	/* abts_sgl_list_lock required because worker thread uses this
+	 * list.
+	 */
+	spin_lock(&phba->sli4_hba.abts_sgl_list_lock);
+	list_splice_init(&phba->sli4_hba.lpfc_abts_els_sgl_list,
+			&phba->sli4_hba.lpfc_sgl_list);
+	spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
+	/* abts_scsi_buf_list_lock required because worker thread uses this
+	 * list.
+	 */
+	spin_lock(&phba->sli4_hba.abts_scsi_buf_list_lock);
+	list_splice_init(&phba->sli4_hba.lpfc_abts_scsi_buf_list,
+			&aborts);
+	spin_unlock(&phba->sli4_hba.abts_scsi_buf_list_lock);
+	spin_unlock_irq(&phba->hbalock);
+
+	list_for_each_entry_safe(psb, psb_next, &aborts, list) {
+		psb->pCmd = NULL;
+		psb->status = IOSTAT_SUCCESS;
+	}
+	spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
+	list_splice(&aborts, &phba->lpfc_scsi_buf_list);
+	spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
+	return 0;
+}
+
+/**
+ * lpfc_hba_down_post - Wrapper func for hba down post routine
+ * @phba: pointer to lpfc HBA data structure.
+ *
+ * This routine wraps the actual SLI3 or SLI4 routine for performing
+ * uninitialization after the HBA is reset when bring down the SLI Layer.
+ *
+ * Return codes
+ *   0 - sucess.
+ *   Any other value - error.
+ **/
+int
+lpfc_hba_down_post(struct lpfc_hba *phba)
+{
+	return (*phba->lpfc_hba_down_post)(phba);
+}
 
 /**
  * lpfc_hb_timeout - The HBA-timer timeout handler
@@ -809,7 +907,7 @@
 					"taking this port offline.\n");
 
 			spin_lock_irq(&phba->hbalock);
-			psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+			psli->sli_flag &= ~LPFC_SLI_ACTIVE;
 			spin_unlock_irq(&phba->hbalock);
 
 			lpfc_offline_prep(phba);
@@ -834,13 +932,15 @@
 	struct lpfc_sli   *psli = &phba->sli;
 
 	spin_lock_irq(&phba->hbalock);
-	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+	psli->sli_flag &= ~LPFC_SLI_ACTIVE;
 	spin_unlock_irq(&phba->hbalock);
 	lpfc_offline_prep(phba);
 
 	lpfc_offline(phba);
 	lpfc_reset_barrier(phba);
+	spin_lock_irq(&phba->hbalock);
 	lpfc_sli_brdreset(phba);
+	spin_unlock_irq(&phba->hbalock);
 	lpfc_hba_down_post(phba);
 	lpfc_sli_brdready(phba, HS_MBRDY);
 	lpfc_unblock_mgmt_io(phba);
@@ -849,6 +949,25 @@
 }
 
 /**
+ * lpfc_sli4_offline_eratt - Bring lpfc offline on SLI4 hardware error attention
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to bring a SLI4 HBA offline when HBA hardware error
+ * other than Port Error 6 has been detected.
+ **/
+static void
+lpfc_sli4_offline_eratt(struct lpfc_hba *phba)
+{
+	lpfc_offline_prep(phba);
+	lpfc_offline(phba);
+	lpfc_sli4_brdreset(phba);
+	lpfc_hba_down_post(phba);
+	lpfc_sli4_post_status_check(phba);
+	lpfc_unblock_mgmt_io(phba);
+	phba->link_state = LPFC_HBA_ERROR;
+}
+
+/**
  * lpfc_handle_deferred_eratt - The HBA hardware deferred error handler
  * @phba: pointer to lpfc hba data structure.
  *
@@ -864,6 +983,16 @@
 	struct lpfc_sli_ring  *pring;
 	struct lpfc_sli *psli = &phba->sli;
 
+	/* If the pci channel is offline, ignore possible errors,
+	 * since we cannot communicate with the pci card anyway.
+	 */
+	if (pci_channel_offline(phba->pcidev)) {
+		spin_lock_irq(&phba->hbalock);
+		phba->hba_flag &= ~DEFER_ERATT;
+		spin_unlock_irq(&phba->hbalock);
+		return;
+	}
+
 	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 		"0479 Deferred Adapter Hardware Error "
 		"Data: x%x x%x x%x\n",
@@ -871,7 +1000,7 @@
 		phba->work_status[0], phba->work_status[1]);
 
 	spin_lock_irq(&phba->hbalock);
-	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+	psli->sli_flag &= ~LPFC_SLI_ACTIVE;
 	spin_unlock_irq(&phba->hbalock);
 
 
@@ -909,13 +1038,30 @@
 	if ((!phba->work_hs) && (!(phba->pport->load_flag & FC_UNLOADING)))
 		phba->work_hs = old_host_status & ~HS_FFER1;
 
+	spin_lock_irq(&phba->hbalock);
 	phba->hba_flag &= ~DEFER_ERATT;
+	spin_unlock_irq(&phba->hbalock);
 	phba->work_status[0] = readl(phba->MBslimaddr + 0xa8);
 	phba->work_status[1] = readl(phba->MBslimaddr + 0xac);
 }
 
+static void
+lpfc_board_errevt_to_mgmt(struct lpfc_hba *phba)
+{
+	struct lpfc_board_event_header board_event;
+	struct Scsi_Host *shost;
+
+	board_event.event_type = FC_REG_BOARD_EVENT;
+	board_event.subcategory = LPFC_EVENT_PORTINTERR;
+	shost = lpfc_shost_from_vport(phba->pport);
+	fc_host_post_vendor_event(shost, fc_get_event_number(),
+				  sizeof(board_event),
+				  (char *) &board_event,
+				  LPFC_NL_VENDOR_ID);
+}
+
 /**
- * lpfc_handle_eratt - The HBA hardware error handler
+ * lpfc_handle_eratt_s3 - The SLI3 HBA hardware error handler
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to handle the following HBA hardware error
@@ -924,8 +1070,8 @@
  * 2 - DMA ring index out of range
  * 3 - Mailbox command came back as unknown
  **/
-void
-lpfc_handle_eratt(struct lpfc_hba *phba)
+static void
+lpfc_handle_eratt_s3(struct lpfc_hba *phba)
 {
 	struct lpfc_vport *vport = phba->pport;
 	struct lpfc_sli   *psli = &phba->sli;
@@ -934,24 +1080,23 @@
 	unsigned long temperature;
 	struct temp_event temp_event_data;
 	struct Scsi_Host  *shost;
-	struct lpfc_board_event_header board_event;
 
 	/* If the pci channel is offline, ignore possible errors,
-	 * since we cannot communicate with the pci card anyway. */
-	if (pci_channel_offline(phba->pcidev))
+	 * since we cannot communicate with the pci card anyway.
+	 */
+	if (pci_channel_offline(phba->pcidev)) {
+		spin_lock_irq(&phba->hbalock);
+		phba->hba_flag &= ~DEFER_ERATT;
+		spin_unlock_irq(&phba->hbalock);
 		return;
+	}
+
 	/* If resets are disabled then leave the HBA alone and return */
 	if (!phba->cfg_enable_hba_reset)
 		return;
 
 	/* Send an internal error event to mgmt application */
-	board_event.event_type = FC_REG_BOARD_EVENT;
-	board_event.subcategory = LPFC_EVENT_PORTINTERR;
-	shost = lpfc_shost_from_vport(phba->pport);
-	fc_host_post_vendor_event(shost, fc_get_event_number(),
-				  sizeof(board_event),
-				  (char *) &board_event,
-				  LPFC_NL_VENDOR_ID);
+	lpfc_board_errevt_to_mgmt(phba);
 
 	if (phba->hba_flag & DEFER_ERATT)
 		lpfc_handle_deferred_eratt(phba);
@@ -965,7 +1110,7 @@
 				phba->work_status[0], phba->work_status[1]);
 
 		spin_lock_irq(&phba->hbalock);
-		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+		psli->sli_flag &= ~LPFC_SLI_ACTIVE;
 		spin_unlock_irq(&phba->hbalock);
 
 		/*
@@ -1037,6 +1182,65 @@
 }
 
 /**
+ * lpfc_handle_eratt_s4 - The SLI4 HBA hardware error handler
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to handle the SLI4 HBA hardware error attention
+ * conditions.
+ **/
+static void
+lpfc_handle_eratt_s4(struct lpfc_hba *phba)
+{
+	struct lpfc_vport *vport = phba->pport;
+	uint32_t event_data;
+	struct Scsi_Host *shost;
+
+	/* If the pci channel is offline, ignore possible errors, since
+	 * we cannot communicate with the pci card anyway.
+	 */
+	if (pci_channel_offline(phba->pcidev))
+		return;
+	/* If resets are disabled then leave the HBA alone and return */
+	if (!phba->cfg_enable_hba_reset)
+		return;
+
+	/* Send an internal error event to mgmt application */
+	lpfc_board_errevt_to_mgmt(phba);
+
+	/* For now, the actual action for SLI4 device handling is not
+	 * specified yet, just treated it as adaptor hardware failure
+	 */
+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"0143 SLI4 Adapter Hardware Error Data: x%x x%x\n",
+			phba->work_status[0], phba->work_status[1]);
+
+	event_data = FC_REG_DUMP_EVENT;
+	shost = lpfc_shost_from_vport(vport);
+	fc_host_post_vendor_event(shost, fc_get_event_number(),
+				  sizeof(event_data), (char *) &event_data,
+				  SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
+
+	lpfc_sli4_offline_eratt(phba);
+}
+
+/**
+ * lpfc_handle_eratt - Wrapper func for handling hba error attention
+ * @phba: pointer to lpfc HBA data structure.
+ *
+ * This routine wraps the actual SLI3 or SLI4 hba error attention handling
+ * routine from the API jump table function pointer from the lpfc_hba struct.
+ *
+ * Return codes
+ *   0 - sucess.
+ *   Any other value - error.
+ **/
+void
+lpfc_handle_eratt(struct lpfc_hba *phba)
+{
+	(*phba->lpfc_handle_eratt)(phba);
+}
+
+/**
  * lpfc_handle_latt - The HBA link event handler
  * @phba: pointer to lpfc hba data structure.
  *
@@ -1137,7 +1341,7 @@
  *   0 - pointer to the VPD passed in is NULL
  *   1 - success
  **/
-static int
+int
 lpfc_parse_vpd(struct lpfc_hba *phba, uint8_t *vpd, int len)
 {
 	uint8_t lenlo, lenhi;
@@ -1292,6 +1496,7 @@
 	uint16_t dev_id = phba->pcidev->device;
 	int max_speed;
 	int GE = 0;
+	int oneConnect = 0; /* default is not a oneConnect */
 	struct {
 		char * name;
 		int    max_speed;
@@ -1437,6 +1642,14 @@
 	case PCI_DEVICE_ID_PROTEUS_S:
 		m = (typeof(m)) {"LPemv12002-S", max_speed, "PCIe IOV"};
 		break;
+	case PCI_DEVICE_ID_TIGERSHARK:
+		oneConnect = 1;
+		m = (typeof(m)) {"OCe10100-F", max_speed, "PCIe"};
+		break;
+	case PCI_DEVICE_ID_TIGERSHARK_S:
+		oneConnect = 1;
+		m = (typeof(m)) {"OCe10100-F-S", max_speed, "PCIe"};
+		break;
 	default:
 		m = (typeof(m)){ NULL };
 		break;
@@ -1444,13 +1657,24 @@
 
 	if (mdp && mdp[0] == '\0')
 		snprintf(mdp, 79,"%s", m.name);
-	if (descp && descp[0] == '\0')
-		snprintf(descp, 255,
-			"Emulex %s %d%s %s %s",
-			m.name, m.max_speed,
-			(GE) ? "GE" : "Gb",
-			m.bus,
-			(GE) ? "FCoE Adapter" : "Fibre Channel Adapter");
+	/* oneConnect hba requires special processing, they are all initiators
+	 * and we put the port number on the end
+	 */
+	if (descp && descp[0] == '\0') {
+		if (oneConnect)
+			snprintf(descp, 255,
+				"Emulex OneConnect %s, FCoE Initiator, Port %s",
+				m.name,
+				phba->Port);
+		else
+			snprintf(descp, 255,
+				"Emulex %s %d%s %s %s",
+				m.name, m.max_speed,
+				(GE) ? "GE" : "Gb",
+				m.bus,
+				(GE) ? "FCoE Adapter" :
+					"Fibre Channel Adapter");
+	}
 }
 
 /**
@@ -1533,7 +1757,8 @@
 		icmd->ulpCommand = CMD_QUE_RING_BUF64_CN;
 		icmd->ulpLe = 1;
 
-		if (lpfc_sli_issue_iocb(phba, pring, iocb, 0) == IOCB_ERROR) {
+		if (lpfc_sli_issue_iocb(phba, pring->ringno, iocb, 0) ==
+		    IOCB_ERROR) {
 			lpfc_mbuf_free(phba, mp1->virt, mp1->phys);
 			kfree(mp1);
 			cnt++;
@@ -1761,7 +1986,6 @@
 	 * Lets wait for this to happen, if needed.
 	 */
 	while (!list_empty(&vport->fc_nodes)) {
-
 		if (i++ > 3000) {
 			lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
 				"0233 Nodelist not empty\n");
@@ -1782,7 +2006,6 @@
 		/* Wait for any activity on ndlps to settle */
 		msleep(10);
 	}
-	return;
 }
 
 /**
@@ -1803,22 +2026,36 @@
 }
 
 /**
- * lpfc_stop_phba_timers - Stop all the timers associated with an HBA
+ * lpfc_stop_hba_timers - Stop all the timers associated with an HBA
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine stops all the timers associated with a HBA. This function is
  * invoked before either putting a HBA offline or unloading the driver.
  **/
-static void
-lpfc_stop_phba_timers(struct lpfc_hba *phba)
+void
+lpfc_stop_hba_timers(struct lpfc_hba *phba)
 {
-	del_timer_sync(&phba->fcp_poll_timer);
 	lpfc_stop_vport_timers(phba->pport);
 	del_timer_sync(&phba->sli.mbox_tmo);
 	del_timer_sync(&phba->fabric_block_timer);
-	phba->hb_outstanding = 0;
-	del_timer_sync(&phba->hb_tmofunc);
 	del_timer_sync(&phba->eratt_poll);
+	del_timer_sync(&phba->hb_tmofunc);
+	phba->hb_outstanding = 0;
+
+	switch (phba->pci_dev_grp) {
+	case LPFC_PCI_DEV_LP:
+		/* Stop any LightPulse device specific driver timers */
+		del_timer_sync(&phba->fcp_poll_timer);
+		break;
+	case LPFC_PCI_DEV_OC:
+		/* Stop any OneConnect device sepcific driver timers */
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0297 Invalid device group (x%x)\n",
+				phba->pci_dev_grp);
+		break;
+	}
 	return;
 }
 
@@ -1878,14 +2115,21 @@
 		return 1;
 	}
 
-	if (lpfc_sli_hba_setup(phba)) {	/* Initialize the HBA */
-		lpfc_unblock_mgmt_io(phba);
-		return 1;
+	if (phba->sli_rev == LPFC_SLI_REV4) {
+		if (lpfc_sli4_hba_setup(phba)) { /* Initialize SLI4 HBA */
+			lpfc_unblock_mgmt_io(phba);
+			return 1;
+		}
+	} else {
+		if (lpfc_sli_hba_setup(phba)) {	/* Initialize SLI2/SLI3 HBA */
+			lpfc_unblock_mgmt_io(phba);
+			return 1;
+		}
 	}
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
 			struct Scsi_Host *shost;
 			shost = lpfc_shost_from_vport(vports[i]);
 			spin_lock_irq(shost->host_lock);
@@ -1947,11 +2191,12 @@
 	/* Issue an unreg_login to all nodes on all vports */
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL) {
-		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
 			struct Scsi_Host *shost;
 
 			if (vports[i]->load_flag & FC_UNLOADING)
 				continue;
+			vports[i]->vfi_state &= ~LPFC_VFI_REGISTERED;
 			shost =	lpfc_shost_from_vport(vports[i]);
 			list_for_each_entry_safe(ndlp, next_ndlp,
 						 &vports[i]->fc_nodes,
@@ -1975,7 +2220,7 @@
 	}
 	lpfc_destroy_vport_work_array(phba, vports);
 
-	lpfc_sli_flush_mbox_queue(phba);
+	lpfc_sli_mbox_sys_shutdown(phba);
 }
 
 /**
@@ -1996,11 +2241,11 @@
 	if (phba->pport->fc_flag & FC_OFFLINE_MODE)
 		return;
 
-	/* stop all timers associated with this hba */
-	lpfc_stop_phba_timers(phba);
+	/* stop port and all timers associated with this hba */
+	lpfc_stop_port(phba);
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
 			lpfc_stop_vport_timers(vports[i]);
 	lpfc_destroy_vport_work_array(phba, vports);
 	lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
@@ -2013,7 +2258,7 @@
 	spin_unlock_irq(&phba->hbalock);
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
 			shost = lpfc_shost_from_vport(vports[i]);
 			spin_lock_irq(shost->host_lock);
 			vports[i]->work_port_events = 0;
@@ -2106,6 +2351,10 @@
 	shost->max_lun = vport->cfg_max_luns;
 	shost->this_id = -1;
 	shost->max_cmd_len = 16;
+	if (phba->sli_rev == LPFC_SLI_REV4) {
+		shost->dma_boundary = LPFC_SLI4_MAX_SEGMENT_SIZE;
+		shost->sg_tablesize = phba->cfg_sg_seg_cnt;
+	}
 
 	/*
 	 * Set initial can_queue value since 0 is no longer supported and
@@ -2123,6 +2372,7 @@
 
 	/* Initialize all internally managed lists. */
 	INIT_LIST_HEAD(&vport->fc_nodes);
+	INIT_LIST_HEAD(&vport->rcv_buffer_list);
 	spin_lock_init(&vport->work_port_lock);
 
 	init_timer(&vport->fc_disctmo);
@@ -2314,15 +2564,3461 @@
 }
 
 /**
- * lpfc_enable_msix - Enable MSI-X interrupt mode
+ * lpfc_stop_port_s3 - Stop SLI3 device port
  * @phba: pointer to lpfc hba data structure.
  *
- * This routine is invoked to enable the MSI-X interrupt vectors. The kernel
- * function pci_enable_msix() is called to enable the MSI-X vectors. Note that
- * pci_enable_msix(), once invoked, enables either all or nothing, depending
- * on the current availability of PCI vector resources. The device driver is
- * responsible for calling the individual request_irq() to register each MSI-X
- * vector with a interrupt handler, which is done in this function. Note that
+ * This routine is invoked to stop an SLI3 device port, it stops the device
+ * from generating interrupts and stops the device driver's timers for the
+ * device.
+ **/
+static void
+lpfc_stop_port_s3(struct lpfc_hba *phba)
+{
+	/* Clear all interrupt enable conditions */
+	writel(0, phba->HCregaddr);
+	readl(phba->HCregaddr); /* flush */
+	/* Clear all pending interrupts */
+	writel(0xffffffff, phba->HAregaddr);
+	readl(phba->HAregaddr); /* flush */
+
+	/* Reset some HBA SLI setup states */
+	lpfc_stop_hba_timers(phba);
+	phba->pport->work_port_events = 0;
+}
+
+/**
+ * lpfc_stop_port_s4 - Stop SLI4 device port
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to stop an SLI4 device port, it stops the device
+ * from generating interrupts and stops the device driver's timers for the
+ * device.
+ **/
+static void
+lpfc_stop_port_s4(struct lpfc_hba *phba)
+{
+	/* Reset some HBA SLI4 setup states */
+	lpfc_stop_hba_timers(phba);
+	phba->pport->work_port_events = 0;
+	phba->sli4_hba.intr_enable = 0;
+	/* Hard clear it for now, shall have more graceful way to wait later */
+	phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+}
+
+/**
+ * lpfc_stop_port - Wrapper function for stopping hba port
+ * @phba: Pointer to HBA context object.
+ *
+ * This routine wraps the actual SLI3 or SLI4 hba stop port routine from
+ * the API jump table function pointer from the lpfc_hba struct.
+ **/
+void
+lpfc_stop_port(struct lpfc_hba *phba)
+{
+	phba->lpfc_stop_port(phba);
+}
+
+/**
+ * lpfc_sli4_remove_dflt_fcf - Remove the driver default fcf record from the port.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to remove the driver default fcf record from
+ * the port.  This routine currently acts on FCF Index 0.
+ *
+ **/
+void
+lpfc_sli_remove_dflt_fcf(struct lpfc_hba *phba)
+{
+	int rc = 0;
+	LPFC_MBOXQ_t *mboxq;
+	struct lpfc_mbx_del_fcf_tbl_entry *del_fcf_record;
+	uint32_t mbox_tmo, req_len;
+	uint32_t shdr_status, shdr_add_status;
+
+	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mboxq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"2020 Failed to allocate mbox for ADD_FCF cmd\n");
+		return;
+	}
+
+	req_len = sizeof(struct lpfc_mbx_del_fcf_tbl_entry) -
+		  sizeof(struct lpfc_sli4_cfg_mhdr);
+	rc = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
+			      LPFC_MBOX_OPCODE_FCOE_DELETE_FCF,
+			      req_len, LPFC_SLI4_MBX_EMBED);
+	/*
+	 * In phase 1, there is a single FCF index, 0.  In phase2, the driver
+	 * supports multiple FCF indices.
+	 */
+	del_fcf_record = &mboxq->u.mqe.un.del_fcf_entry;
+	bf_set(lpfc_mbx_del_fcf_tbl_count, del_fcf_record, 1);
+	bf_set(lpfc_mbx_del_fcf_tbl_index, del_fcf_record,
+	       phba->fcf.fcf_indx);
+
+	if (!phba->sli4_hba.intr_enable)
+		rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+	else {
+		mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+		rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
+	}
+	/* The IOCTL status is embedded in the mailbox subheader. */
+	shdr_status = bf_get(lpfc_mbox_hdr_status,
+			     &del_fcf_record->header.cfg_shdr.response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
+				 &del_fcf_record->header.cfg_shdr.response);
+	if (shdr_status || shdr_add_status || rc != MBX_SUCCESS) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2516 DEL FCF of default FCF Index failed "
+				"mbx status x%x, status x%x add_status x%x\n",
+				rc, shdr_status, shdr_add_status);
+	}
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mboxq, phba->mbox_mem_pool);
+}
+
+/**
+ * lpfc_sli4_parse_latt_fault - Parse sli4 link-attention link fault code
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_link: pointer to the async link completion queue entry.
+ *
+ * This routine is to parse the SLI4 link-attention link fault code and
+ * translate it into the base driver's read link attention mailbox command
+ * status.
+ *
+ * Return: Link-attention status in terms of base driver's coding.
+ **/
+static uint16_t
+lpfc_sli4_parse_latt_fault(struct lpfc_hba *phba,
+			   struct lpfc_acqe_link *acqe_link)
+{
+	uint16_t latt_fault;
+
+	switch (bf_get(lpfc_acqe_link_fault, acqe_link)) {
+	case LPFC_ASYNC_LINK_FAULT_NONE:
+	case LPFC_ASYNC_LINK_FAULT_LOCAL:
+	case LPFC_ASYNC_LINK_FAULT_REMOTE:
+		latt_fault = 0;
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0398 Invalid link fault code: x%x\n",
+				bf_get(lpfc_acqe_link_fault, acqe_link));
+		latt_fault = MBXERR_ERROR;
+		break;
+	}
+	return latt_fault;
+}
+
+/**
+ * lpfc_sli4_parse_latt_type - Parse sli4 link attention type
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_link: pointer to the async link completion queue entry.
+ *
+ * This routine is to parse the SLI4 link attention type and translate it
+ * into the base driver's link attention type coding.
+ *
+ * Return: Link attention type in terms of base driver's coding.
+ **/
+static uint8_t
+lpfc_sli4_parse_latt_type(struct lpfc_hba *phba,
+			  struct lpfc_acqe_link *acqe_link)
+{
+	uint8_t att_type;
+
+	switch (bf_get(lpfc_acqe_link_status, acqe_link)) {
+	case LPFC_ASYNC_LINK_STATUS_DOWN:
+	case LPFC_ASYNC_LINK_STATUS_LOGICAL_DOWN:
+		att_type = AT_LINK_DOWN;
+		break;
+	case LPFC_ASYNC_LINK_STATUS_UP:
+		/* Ignore physical link up events - wait for logical link up */
+		att_type = AT_RESERVED;
+		break;
+	case LPFC_ASYNC_LINK_STATUS_LOGICAL_UP:
+		att_type = AT_LINK_UP;
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0399 Invalid link attention type: x%x\n",
+				bf_get(lpfc_acqe_link_status, acqe_link));
+		att_type = AT_RESERVED;
+		break;
+	}
+	return att_type;
+}
+
+/**
+ * lpfc_sli4_parse_latt_link_speed - Parse sli4 link-attention link speed
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_link: pointer to the async link completion queue entry.
+ *
+ * This routine is to parse the SLI4 link-attention link speed and translate
+ * it into the base driver's link-attention link speed coding.
+ *
+ * Return: Link-attention link speed in terms of base driver's coding.
+ **/
+static uint8_t
+lpfc_sli4_parse_latt_link_speed(struct lpfc_hba *phba,
+				struct lpfc_acqe_link *acqe_link)
+{
+	uint8_t link_speed;
+
+	switch (bf_get(lpfc_acqe_link_speed, acqe_link)) {
+	case LPFC_ASYNC_LINK_SPEED_ZERO:
+		link_speed = LA_UNKNW_LINK;
+		break;
+	case LPFC_ASYNC_LINK_SPEED_10MBPS:
+		link_speed = LA_UNKNW_LINK;
+		break;
+	case LPFC_ASYNC_LINK_SPEED_100MBPS:
+		link_speed = LA_UNKNW_LINK;
+		break;
+	case LPFC_ASYNC_LINK_SPEED_1GBPS:
+		link_speed = LA_1GHZ_LINK;
+		break;
+	case LPFC_ASYNC_LINK_SPEED_10GBPS:
+		link_speed = LA_10GHZ_LINK;
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0483 Invalid link-attention link speed: x%x\n",
+				bf_get(lpfc_acqe_link_speed, acqe_link));
+		link_speed = LA_UNKNW_LINK;
+		break;
+	}
+	return link_speed;
+}
+
+/**
+ * lpfc_sli4_async_link_evt - Process the asynchronous link event
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_link: pointer to the async link completion queue entry.
+ *
+ * This routine is to handle the SLI4 asynchronous link event.
+ **/
+static void
+lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
+			 struct lpfc_acqe_link *acqe_link)
+{
+	struct lpfc_dmabuf *mp;
+	LPFC_MBOXQ_t *pmb;
+	MAILBOX_t *mb;
+	READ_LA_VAR *la;
+	uint8_t att_type;
+
+	att_type = lpfc_sli4_parse_latt_type(phba, acqe_link);
+	if (att_type != AT_LINK_DOWN && att_type != AT_LINK_UP)
+		return;
+	pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!pmb) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0395 The mboxq allocation failed\n");
+		return;
+	}
+	mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+	if (!mp) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0396 The lpfc_dmabuf allocation failed\n");
+		goto out_free_pmb;
+	}
+	mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+	if (!mp->virt) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0397 The mbuf allocation failed\n");
+		goto out_free_dmabuf;
+	}
+
+	/* Cleanup any outstanding ELS commands */
+	lpfc_els_flush_all_cmd(phba);
+
+	/* Block ELS IOCBs until we have done process link event */
+	phba->sli.ring[LPFC_ELS_RING].flag |= LPFC_STOP_IOCB_EVENT;
+
+	/* Update link event statistics */
+	phba->sli.slistat.link_event++;
+
+	/* Create pseudo lpfc_handle_latt mailbox command from link ACQE */
+	lpfc_read_la(phba, pmb, mp);
+	pmb->vport = phba->pport;
+
+	/* Parse and translate status field */
+	mb = &pmb->u.mb;
+	mb->mbxStatus = lpfc_sli4_parse_latt_fault(phba, acqe_link);
+
+	/* Parse and translate link attention fields */
+	la = (READ_LA_VAR *) &pmb->u.mb.un.varReadLA;
+	la->eventTag = acqe_link->event_tag;
+	la->attType = att_type;
+	la->UlnkSpeed = lpfc_sli4_parse_latt_link_speed(phba, acqe_link);
+
+	/* Fake the the following irrelvant fields */
+	la->topology = TOPOLOGY_PT_PT;
+	la->granted_AL_PA = 0;
+	la->il = 0;
+	la->pb = 0;
+	la->fa = 0;
+	la->mm = 0;
+
+	/* Keep the link status for extra SLI4 state machine reference */
+	phba->sli4_hba.link_state.speed =
+				bf_get(lpfc_acqe_link_speed, acqe_link);
+	phba->sli4_hba.link_state.duplex =
+				bf_get(lpfc_acqe_link_duplex, acqe_link);
+	phba->sli4_hba.link_state.status =
+				bf_get(lpfc_acqe_link_status, acqe_link);
+	phba->sli4_hba.link_state.physical =
+				bf_get(lpfc_acqe_link_physical, acqe_link);
+	phba->sli4_hba.link_state.fault =
+				bf_get(lpfc_acqe_link_fault, acqe_link);
+
+	/* Invoke the lpfc_handle_latt mailbox command callback function */
+	lpfc_mbx_cmpl_read_la(phba, pmb);
+
+	return;
+
+out_free_dmabuf:
+	kfree(mp);
+out_free_pmb:
+	mempool_free(pmb, phba->mbox_mem_pool);
+}
+
+/**
+ * lpfc_sli4_async_fcoe_evt - Process the asynchronous fcoe event
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_link: pointer to the async fcoe completion queue entry.
+ *
+ * This routine is to handle the SLI4 asynchronous fcoe event.
+ **/
+static void
+lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
+			 struct lpfc_acqe_fcoe *acqe_fcoe)
+{
+	uint8_t event_type = bf_get(lpfc_acqe_fcoe_event_type, acqe_fcoe);
+	int rc;
+
+	switch (event_type) {
+	case LPFC_FCOE_EVENT_TYPE_NEW_FCF:
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+			"2546 New FCF found index 0x%x tag 0x%x \n",
+			acqe_fcoe->fcf_index,
+			acqe_fcoe->event_tag);
+		/*
+		 * If the current FCF is in discovered state,
+		 * do nothing.
+		 */
+		spin_lock_irq(&phba->hbalock);
+		if (phba->fcf.fcf_flag & FCF_DISCOVERED) {
+			spin_unlock_irq(&phba->hbalock);
+			break;
+		}
+		spin_unlock_irq(&phba->hbalock);
+
+		/* Read the FCF table and re-discover SAN. */
+		rc = lpfc_sli4_read_fcf_record(phba,
+			LPFC_FCOE_FCF_GET_FIRST);
+		if (rc)
+			lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+				"2547 Read FCF record failed 0x%x\n",
+				rc);
+		break;
+
+	case LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL:
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+			"2548 FCF Table full count 0x%x tag 0x%x \n",
+			bf_get(lpfc_acqe_fcoe_fcf_count, acqe_fcoe),
+			acqe_fcoe->event_tag);
+		break;
+
+	case LPFC_FCOE_EVENT_TYPE_FCF_DEAD:
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+			"2549 FCF disconnected fron network index 0x%x"
+			" tag 0x%x \n", acqe_fcoe->fcf_index,
+			acqe_fcoe->event_tag);
+		/* If the event is not for currently used fcf do nothing */
+		if (phba->fcf.fcf_indx != acqe_fcoe->fcf_index)
+			break;
+		/*
+		 * Currently, driver support only one FCF - so treat this as
+		 * a link down.
+		 */
+		lpfc_linkdown(phba);
+		/* Unregister FCF if no devices connected to it */
+		lpfc_unregister_unused_fcf(phba);
+		break;
+
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+			"0288 Unknown FCoE event type 0x%x event tag "
+			"0x%x\n", event_type, acqe_fcoe->event_tag);
+		break;
+	}
+}
+
+/**
+ * lpfc_sli4_async_dcbx_evt - Process the asynchronous dcbx event
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_link: pointer to the async dcbx completion queue entry.
+ *
+ * This routine is to handle the SLI4 asynchronous dcbx event.
+ **/
+static void
+lpfc_sli4_async_dcbx_evt(struct lpfc_hba *phba,
+			 struct lpfc_acqe_dcbx *acqe_dcbx)
+{
+	lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+			"0290 The SLI4 DCBX asynchronous event is not "
+			"handled yet\n");
+}
+
+/**
+ * lpfc_sli4_async_event_proc - Process all the pending asynchronous event
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked by the worker thread to process all the pending
+ * SLI4 asynchronous events.
+ **/
+void lpfc_sli4_async_event_proc(struct lpfc_hba *phba)
+{
+	struct lpfc_cq_event *cq_event;
+
+	/* First, declare the async event has been handled */
+	spin_lock_irq(&phba->hbalock);
+	phba->hba_flag &= ~ASYNC_EVENT;
+	spin_unlock_irq(&phba->hbalock);
+	/* Now, handle all the async events */
+	while (!list_empty(&phba->sli4_hba.sp_asynce_work_queue)) {
+		/* Get the first event from the head of the event queue */
+		spin_lock_irq(&phba->hbalock);
+		list_remove_head(&phba->sli4_hba.sp_asynce_work_queue,
+				 cq_event, struct lpfc_cq_event, list);
+		spin_unlock_irq(&phba->hbalock);
+		/* Process the asynchronous event */
+		switch (bf_get(lpfc_trailer_code, &cq_event->cqe.mcqe_cmpl)) {
+		case LPFC_TRAILER_CODE_LINK:
+			lpfc_sli4_async_link_evt(phba,
+						 &cq_event->cqe.acqe_link);
+			break;
+		case LPFC_TRAILER_CODE_FCOE:
+			lpfc_sli4_async_fcoe_evt(phba,
+						 &cq_event->cqe.acqe_fcoe);
+			break;
+		case LPFC_TRAILER_CODE_DCBX:
+			lpfc_sli4_async_dcbx_evt(phba,
+						 &cq_event->cqe.acqe_dcbx);
+			break;
+		default:
+			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+					"1804 Invalid asynchrous event code: "
+					"x%x\n", bf_get(lpfc_trailer_code,
+					&cq_event->cqe.mcqe_cmpl));
+			break;
+		}
+		/* Free the completion event processed to the free pool */
+		lpfc_sli4_cq_event_release(phba, cq_event);
+	}
+}
+
+/**
+ * lpfc_api_table_setup - Set up per hba pci-device group func api jump table
+ * @phba: pointer to lpfc hba data structure.
+ * @dev_grp: The HBA PCI-Device group number.
+ *
+ * This routine is invoked to set up the per HBA PCI-Device group function
+ * API jump table entries.
+ *
+ * Return: 0 if success, otherwise -ENODEV
+ **/
+int
+lpfc_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
+{
+	int rc;
+
+	/* Set up lpfc PCI-device group */
+	phba->pci_dev_grp = dev_grp;
+
+	/* The LPFC_PCI_DEV_OC uses SLI4 */
+	if (dev_grp == LPFC_PCI_DEV_OC)
+		phba->sli_rev = LPFC_SLI_REV4;
+
+	/* Set up device INIT API function jump table */
+	rc = lpfc_init_api_table_setup(phba, dev_grp);
+	if (rc)
+		return -ENODEV;
+	/* Set up SCSI API function jump table */
+	rc = lpfc_scsi_api_table_setup(phba, dev_grp);
+	if (rc)
+		return -ENODEV;
+	/* Set up SLI API function jump table */
+	rc = lpfc_sli_api_table_setup(phba, dev_grp);
+	if (rc)
+		return -ENODEV;
+	/* Set up MBOX API function jump table */
+	rc = lpfc_mbox_api_table_setup(phba, dev_grp);
+	if (rc)
+		return -ENODEV;
+
+	return 0;
+}
+
+/**
+ * lpfc_log_intr_mode - Log the active interrupt mode
+ * @phba: pointer to lpfc hba data structure.
+ * @intr_mode: active interrupt mode adopted.
+ *
+ * This routine it invoked to log the currently used active interrupt mode
+ * to the device.
+ **/
+static void lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode)
+{
+	switch (intr_mode) {
+	case 0:
+		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"0470 Enable INTx interrupt mode.\n");
+		break;
+	case 1:
+		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"0481 Enabled MSI interrupt mode.\n");
+		break;
+	case 2:
+		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"0480 Enabled MSI-X interrupt mode.\n");
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0482 Illegal interrupt mode.\n");
+		break;
+	}
+	return;
+}
+
+/**
+ * lpfc_enable_pci_dev - Enable a generic PCI device.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to enable the PCI device that is common to all
+ * PCI devices.
+ *
+ * Return codes
+ * 	0 - sucessful
+ * 	other values - error
+ **/
+static int
+lpfc_enable_pci_dev(struct lpfc_hba *phba)
+{
+	struct pci_dev *pdev;
+	int bars;
+
+	/* Obtain PCI device reference */
+	if (!phba->pcidev)
+		goto out_error;
+	else
+		pdev = phba->pcidev;
+	/* Select PCI BARs */
+	bars = pci_select_bars(pdev, IORESOURCE_MEM);
+	/* Enable PCI device */
+	if (pci_enable_device_mem(pdev))
+		goto out_error;
+	/* Request PCI resource for the device */
+	if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME))
+		goto out_disable_device;
+	/* Set up device as PCI master and save state for EEH */
+	pci_set_master(pdev);
+	pci_try_set_mwi(pdev);
+	pci_save_state(pdev);
+
+	return 0;
+
+out_disable_device:
+	pci_disable_device(pdev);
+out_error:
+	return -ENODEV;
+}
+
+/**
+ * lpfc_disable_pci_dev - Disable a generic PCI device.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to disable the PCI device that is common to all
+ * PCI devices.
+ **/
+static void
+lpfc_disable_pci_dev(struct lpfc_hba *phba)
+{
+	struct pci_dev *pdev;
+	int bars;
+
+	/* Obtain PCI device reference */
+	if (!phba->pcidev)
+		return;
+	else
+		pdev = phba->pcidev;
+	/* Select PCI BARs */
+	bars = pci_select_bars(pdev, IORESOURCE_MEM);
+	/* Release PCI resource and disable PCI device */
+	pci_release_selected_regions(pdev, bars);
+	pci_disable_device(pdev);
+	/* Null out PCI private reference to driver */
+	pci_set_drvdata(pdev, NULL);
+
+	return;
+}
+
+/**
+ * lpfc_reset_hba - Reset a hba
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to reset a hba device. It brings the HBA
+ * offline, performs a board restart, and then brings the board back
+ * online. The lpfc_offline calls lpfc_sli_hba_down which will clean up
+ * on outstanding mailbox commands.
+ **/
+void
+lpfc_reset_hba(struct lpfc_hba *phba)
+{
+	/* If resets are disabled then set error state and return. */
+	if (!phba->cfg_enable_hba_reset) {
+		phba->link_state = LPFC_HBA_ERROR;
+		return;
+	}
+	lpfc_offline_prep(phba);
+	lpfc_offline(phba);
+	lpfc_sli_brdrestart(phba);
+	lpfc_online(phba);
+	lpfc_unblock_mgmt_io(phba);
+}
+
+/**
+ * lpfc_sli_driver_resource_setup - Setup driver internal resources for SLI3 dev.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up the driver internal resources specific to
+ * support the SLI-3 HBA device it attached to.
+ *
+ * Return codes
+ * 	0 - sucessful
+ * 	other values - error
+ **/
+static int
+lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
+{
+	struct lpfc_sli *psli;
+
+	/*
+	 * Initialize timers used by driver
+	 */
+
+	/* Heartbeat timer */
+	init_timer(&phba->hb_tmofunc);
+	phba->hb_tmofunc.function = lpfc_hb_timeout;
+	phba->hb_tmofunc.data = (unsigned long)phba;
+
+	psli = &phba->sli;
+	/* MBOX heartbeat timer */
+	init_timer(&psli->mbox_tmo);
+	psli->mbox_tmo.function = lpfc_mbox_timeout;
+	psli->mbox_tmo.data = (unsigned long) phba;
+	/* FCP polling mode timer */
+	init_timer(&phba->fcp_poll_timer);
+	phba->fcp_poll_timer.function = lpfc_poll_timeout;
+	phba->fcp_poll_timer.data = (unsigned long) phba;
+	/* Fabric block timer */
+	init_timer(&phba->fabric_block_timer);
+	phba->fabric_block_timer.function = lpfc_fabric_block_timeout;
+	phba->fabric_block_timer.data = (unsigned long) phba;
+	/* EA polling mode timer */
+	init_timer(&phba->eratt_poll);
+	phba->eratt_poll.function = lpfc_poll_eratt;
+	phba->eratt_poll.data = (unsigned long) phba;
+
+	/* Host attention work mask setup */
+	phba->work_ha_mask = (HA_ERATT | HA_MBATT | HA_LATT);
+	phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4));
+
+	/* Get all the module params for configuring this host */
+	lpfc_get_cfgparam(phba);
+	/*
+	 * Since the sg_tablesize is module parameter, the sg_dma_buf_size
+	 * used to create the sg_dma_buf_pool must be dynamically calculated.
+	 * 2 segments are added since the IOCB needs a command and response bde.
+	 */
+	phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
+		sizeof(struct fcp_rsp) +
+			((phba->cfg_sg_seg_cnt + 2) * sizeof(struct ulp_bde64));
+
+	if (phba->cfg_enable_bg) {
+		phba->cfg_sg_seg_cnt = LPFC_MAX_SG_SEG_CNT;
+		phba->cfg_sg_dma_buf_size +=
+			phba->cfg_prot_sg_seg_cnt * sizeof(struct ulp_bde64);
+	}
+
+	/* Also reinitialize the host templates with new values. */
+	lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt;
+	lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt;
+
+	phba->max_vpi = LPFC_MAX_VPI;
+	/* This will be set to correct value after config_port mbox */
+	phba->max_vports = 0;
+
+	/*
+	 * Initialize the SLI Layer to run with lpfc HBAs.
+	 */
+	lpfc_sli_setup(phba);
+	lpfc_sli_queue_setup(phba);
+
+	/* Allocate device driver memory */
+	if (lpfc_mem_alloc(phba, BPL_ALIGN_SZ))
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * lpfc_sli_driver_resource_unset - Unset drvr internal resources for SLI3 dev
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset the driver internal resources set up
+ * specific for supporting the SLI-3 HBA device it attached to.
+ **/
+static void
+lpfc_sli_driver_resource_unset(struct lpfc_hba *phba)
+{
+	/* Free device driver memory allocated */
+	lpfc_mem_free_all(phba);
+
+	return;
+}
+
+/**
+ * lpfc_sli4_driver_resource_setup - Setup drvr internal resources for SLI4 dev
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up the driver internal resources specific to
+ * support the SLI-4 HBA device it attached to.
+ *
+ * Return codes
+ * 	0 - sucessful
+ * 	other values - error
+ **/
+static int
+lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
+{
+	struct lpfc_sli *psli;
+	int rc;
+	int i, hbq_count;
+
+	/* Before proceed, wait for POST done and device ready */
+	rc = lpfc_sli4_post_status_check(phba);
+	if (rc)
+		return -ENODEV;
+
+	/*
+	 * Initialize timers used by driver
+	 */
+
+	/* Heartbeat timer */
+	init_timer(&phba->hb_tmofunc);
+	phba->hb_tmofunc.function = lpfc_hb_timeout;
+	phba->hb_tmofunc.data = (unsigned long)phba;
+
+	psli = &phba->sli;
+	/* MBOX heartbeat timer */
+	init_timer(&psli->mbox_tmo);
+	psli->mbox_tmo.function = lpfc_mbox_timeout;
+	psli->mbox_tmo.data = (unsigned long) phba;
+	/* Fabric block timer */
+	init_timer(&phba->fabric_block_timer);
+	phba->fabric_block_timer.function = lpfc_fabric_block_timeout;
+	phba->fabric_block_timer.data = (unsigned long) phba;
+	/* EA polling mode timer */
+	init_timer(&phba->eratt_poll);
+	phba->eratt_poll.function = lpfc_poll_eratt;
+	phba->eratt_poll.data = (unsigned long) phba;
+	/*
+	 * We need to do a READ_CONFIG mailbox command here before
+	 * calling lpfc_get_cfgparam. For VFs this will report the
+	 * MAX_XRI, MAX_VPI, MAX_RPI, MAX_IOCB, and MAX_VFI settings.
+	 * All of the resources allocated
+	 * for this Port are tied to these values.
+	 */
+	/* Get all the module params for configuring this host */
+	lpfc_get_cfgparam(phba);
+	phba->max_vpi = LPFC_MAX_VPI;
+	/* This will be set to correct value after the read_config mbox */
+	phba->max_vports = 0;
+
+	/* Program the default value of vlan_id and fc_map */
+	phba->valid_vlan = 0;
+	phba->fc_map[0] = LPFC_FCOE_FCF_MAP0;
+	phba->fc_map[1] = LPFC_FCOE_FCF_MAP1;
+	phba->fc_map[2] = LPFC_FCOE_FCF_MAP2;
+
+	/*
+	 * Since the sg_tablesize is module parameter, the sg_dma_buf_size
+	 * used to create the sg_dma_buf_pool must be dynamically calculated.
+	 * 2 segments are added since the IOCB needs a command and response bde.
+	 * To insure that the scsi sgl does not cross a 4k page boundary only
+	 * sgl sizes of 1k, 2k, 4k, and 8k are supported.
+	 * Table of sgl sizes and seg_cnt:
+	 * sgl size, 	sg_seg_cnt	total seg
+	 * 1k		50		52
+	 * 2k		114		116
+	 * 4k		242		244
+	 * 8k		498		500
+	 * cmd(32) + rsp(160) + (52 * sizeof(sli4_sge)) = 1024
+	 * cmd(32) + rsp(160) + (116 * sizeof(sli4_sge)) = 2048
+	 * cmd(32) + rsp(160) + (244 * sizeof(sli4_sge)) = 4096
+	 * cmd(32) + rsp(160) + (500 * sizeof(sli4_sge)) = 8192
+	 */
+	if (phba->cfg_sg_seg_cnt <= LPFC_DEFAULT_SG_SEG_CNT)
+		phba->cfg_sg_seg_cnt = 50;
+	else if (phba->cfg_sg_seg_cnt <= 114)
+		phba->cfg_sg_seg_cnt = 114;
+	else if (phba->cfg_sg_seg_cnt <= 242)
+		phba->cfg_sg_seg_cnt = 242;
+	else
+		phba->cfg_sg_seg_cnt = 498;
+
+	phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd)
+					+ sizeof(struct fcp_rsp);
+	phba->cfg_sg_dma_buf_size +=
+		((phba->cfg_sg_seg_cnt + 2) * sizeof(struct sli4_sge));
+
+	/* Initialize buffer queue management fields */
+	hbq_count = lpfc_sli_hbq_count();
+	for (i = 0; i < hbq_count; ++i)
+		INIT_LIST_HEAD(&phba->hbqs[i].hbq_buffer_list);
+	INIT_LIST_HEAD(&phba->rb_pend_list);
+	phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_sli4_rb_alloc;
+	phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_sli4_rb_free;
+
+	/*
+	 * Initialize the SLI Layer to run with lpfc SLI4 HBAs.
+	 */
+	/* Initialize the Abort scsi buffer list used by driver */
+	spin_lock_init(&phba->sli4_hba.abts_scsi_buf_list_lock);
+	INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_scsi_buf_list);
+	/* This abort list used by worker thread */
+	spin_lock_init(&phba->sli4_hba.abts_sgl_list_lock);
+
+	/*
+	 * Initialize dirver internal slow-path work queues
+	 */
+
+	/* Driver internel slow-path CQ Event pool */
+	INIT_LIST_HEAD(&phba->sli4_hba.sp_cqe_event_pool);
+	/* Response IOCB work queue list */
+	INIT_LIST_HEAD(&phba->sli4_hba.sp_rspiocb_work_queue);
+	/* Asynchronous event CQ Event work queue list */
+	INIT_LIST_HEAD(&phba->sli4_hba.sp_asynce_work_queue);
+	/* Fast-path XRI aborted CQ Event work queue list */
+	INIT_LIST_HEAD(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue);
+	/* Slow-path XRI aborted CQ Event work queue list */
+	INIT_LIST_HEAD(&phba->sli4_hba.sp_els_xri_aborted_work_queue);
+	/* Receive queue CQ Event work queue list */
+	INIT_LIST_HEAD(&phba->sli4_hba.sp_unsol_work_queue);
+
+	/* Initialize the driver internal SLI layer lists. */
+	lpfc_sli_setup(phba);
+	lpfc_sli_queue_setup(phba);
+
+	/* Allocate device driver memory */
+	rc = lpfc_mem_alloc(phba, SGL_ALIGN_SZ);
+	if (rc)
+		return -ENOMEM;
+
+	/* Create the bootstrap mailbox command */
+	rc = lpfc_create_bootstrap_mbox(phba);
+	if (unlikely(rc))
+		goto out_free_mem;
+
+	/* Set up the host's endian order with the device. */
+	rc = lpfc_setup_endian_order(phba);
+	if (unlikely(rc))
+		goto out_free_bsmbx;
+
+	/* Set up the hba's configuration parameters. */
+	rc = lpfc_sli4_read_config(phba);
+	if (unlikely(rc))
+		goto out_free_bsmbx;
+
+	/* Perform a function reset */
+	rc = lpfc_pci_function_reset(phba);
+	if (unlikely(rc))
+		goto out_free_bsmbx;
+
+	/* Create all the SLI4 queues */
+	rc = lpfc_sli4_queue_create(phba);
+	if (rc)
+		goto out_free_bsmbx;
+
+	/* Create driver internal CQE event pool */
+	rc = lpfc_sli4_cq_event_pool_create(phba);
+	if (rc)
+		goto out_destroy_queue;
+
+	/* Initialize and populate the iocb list per host */
+	rc = lpfc_init_sgl_list(phba);
+	if (rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1400 Failed to initialize sgl list.\n");
+		goto out_destroy_cq_event_pool;
+	}
+	rc = lpfc_init_active_sgl_array(phba);
+	if (rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1430 Failed to initialize sgl list.\n");
+		goto out_free_sgl_list;
+	}
+
+	rc = lpfc_sli4_init_rpi_hdrs(phba);
+	if (rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1432 Failed to initialize rpi headers.\n");
+		goto out_free_active_sgl;
+	}
+
+	phba->sli4_hba.fcp_eq_hdl = kzalloc((sizeof(struct lpfc_fcp_eq_hdl) *
+				    phba->cfg_fcp_eq_count), GFP_KERNEL);
+	if (!phba->sli4_hba.fcp_eq_hdl) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2572 Failed allocate memory for fast-path "
+				"per-EQ handle array\n");
+		goto out_remove_rpi_hdrs;
+	}
+
+	phba->sli4_hba.msix_entries = kzalloc((sizeof(struct msix_entry) *
+				      phba->sli4_hba.cfg_eqn), GFP_KERNEL);
+	if (!phba->sli4_hba.msix_entries) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2573 Failed allocate memory for msi-x "
+				"interrupt vector entries\n");
+		goto out_free_fcp_eq_hdl;
+	}
+
+	return rc;
+
+out_free_fcp_eq_hdl:
+	kfree(phba->sli4_hba.fcp_eq_hdl);
+out_remove_rpi_hdrs:
+	lpfc_sli4_remove_rpi_hdrs(phba);
+out_free_active_sgl:
+	lpfc_free_active_sgl(phba);
+out_free_sgl_list:
+	lpfc_free_sgl_list(phba);
+out_destroy_cq_event_pool:
+	lpfc_sli4_cq_event_pool_destroy(phba);
+out_destroy_queue:
+	lpfc_sli4_queue_destroy(phba);
+out_free_bsmbx:
+	lpfc_destroy_bootstrap_mbox(phba);
+out_free_mem:
+	lpfc_mem_free(phba);
+	return rc;
+}
+
+/**
+ * lpfc_sli4_driver_resource_unset - Unset drvr internal resources for SLI4 dev
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset the driver internal resources set up
+ * specific for supporting the SLI-4 HBA device it attached to.
+ **/
+static void
+lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
+{
+	struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry;
+
+	/* unregister default FCFI from the HBA */
+	lpfc_sli4_fcfi_unreg(phba, phba->fcf.fcfi);
+
+	/* Free the default FCR table */
+	lpfc_sli_remove_dflt_fcf(phba);
+
+	/* Free memory allocated for msi-x interrupt vector entries */
+	kfree(phba->sli4_hba.msix_entries);
+
+	/* Free memory allocated for fast-path work queue handles */
+	kfree(phba->sli4_hba.fcp_eq_hdl);
+
+	/* Free the allocated rpi headers. */
+	lpfc_sli4_remove_rpi_hdrs(phba);
+
+	/* Free the ELS sgl list */
+	lpfc_free_active_sgl(phba);
+	lpfc_free_sgl_list(phba);
+
+	/* Free the SCSI sgl management array */
+	kfree(phba->sli4_hba.lpfc_scsi_psb_array);
+
+	/* Free the SLI4 queues */
+	lpfc_sli4_queue_destroy(phba);
+
+	/* Free the completion queue EQ event pool */
+	lpfc_sli4_cq_event_release_all(phba);
+	lpfc_sli4_cq_event_pool_destroy(phba);
+
+	/* Reset SLI4 HBA FCoE function */
+	lpfc_pci_function_reset(phba);
+
+	/* Free the bsmbx region. */
+	lpfc_destroy_bootstrap_mbox(phba);
+
+	/* Free the SLI Layer memory with SLI4 HBAs */
+	lpfc_mem_free_all(phba);
+
+	/* Free the current connect table */
+	list_for_each_entry_safe(conn_entry, next_conn_entry,
+		&phba->fcf_conn_rec_list, list)
+		kfree(conn_entry);
+
+	return;
+}
+
+/**
+ * lpfc_init_api_table_setup - Set up init api fucntion jump table
+ * @phba: The hba struct for which this call is being executed.
+ * @dev_grp: The HBA PCI-Device group number.
+ *
+ * This routine sets up the device INIT interface API function jump table
+ * in @phba struct.
+ *
+ * Returns: 0 - success, -ENODEV - failure.
+ **/
+int
+lpfc_init_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
+{
+	switch (dev_grp) {
+	case LPFC_PCI_DEV_LP:
+		phba->lpfc_hba_down_post = lpfc_hba_down_post_s3;
+		phba->lpfc_handle_eratt = lpfc_handle_eratt_s3;
+		phba->lpfc_stop_port = lpfc_stop_port_s3;
+		break;
+	case LPFC_PCI_DEV_OC:
+		phba->lpfc_hba_down_post = lpfc_hba_down_post_s4;
+		phba->lpfc_handle_eratt = lpfc_handle_eratt_s4;
+		phba->lpfc_stop_port = lpfc_stop_port_s4;
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1431 Invalid HBA PCI-device group: 0x%x\n",
+				dev_grp);
+		return -ENODEV;
+		break;
+	}
+	return 0;
+}
+
+/**
+ * lpfc_setup_driver_resource_phase1 - Phase1 etup driver internal resources.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up the driver internal resources before the
+ * device specific resource setup to support the HBA device it attached to.
+ *
+ * Return codes
+ *	0 - sucessful
+ *	other values - error
+ **/
+static int
+lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba)
+{
+	/*
+	 * Driver resources common to all SLI revisions
+	 */
+	atomic_set(&phba->fast_event_count, 0);
+	spin_lock_init(&phba->hbalock);
+
+	/* Initialize ndlp management spinlock */
+	spin_lock_init(&phba->ndlp_lock);
+
+	INIT_LIST_HEAD(&phba->port_list);
+	INIT_LIST_HEAD(&phba->work_list);
+	init_waitqueue_head(&phba->wait_4_mlo_m_q);
+
+	/* Initialize the wait queue head for the kernel thread */
+	init_waitqueue_head(&phba->work_waitq);
+
+	/* Initialize the scsi buffer list used by driver for scsi IO */
+	spin_lock_init(&phba->scsi_buf_list_lock);
+	INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list);
+
+	/* Initialize the fabric iocb list */
+	INIT_LIST_HEAD(&phba->fabric_iocb_list);
+
+	/* Initialize list to save ELS buffers */
+	INIT_LIST_HEAD(&phba->elsbuf);
+
+	/* Initialize FCF connection rec list */
+	INIT_LIST_HEAD(&phba->fcf_conn_rec_list);
+
+	return 0;
+}
+
+/**
+ * lpfc_setup_driver_resource_phase2 - Phase2 setup driver internal resources.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up the driver internal resources after the
+ * device specific resource setup to support the HBA device it attached to.
+ *
+ * Return codes
+ * 	0 - sucessful
+ * 	other values - error
+ **/
+static int
+lpfc_setup_driver_resource_phase2(struct lpfc_hba *phba)
+{
+	int error;
+
+	/* Startup the kernel thread for this host adapter. */
+	phba->worker_thread = kthread_run(lpfc_do_work, phba,
+					  "lpfc_worker_%d", phba->brd_no);
+	if (IS_ERR(phba->worker_thread)) {
+		error = PTR_ERR(phba->worker_thread);
+		return error;
+	}
+
+	return 0;
+}
+
+/**
+ * lpfc_unset_driver_resource_phase2 - Phase2 unset driver internal resources.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset the driver internal resources set up after
+ * the device specific resource setup for supporting the HBA device it
+ * attached to.
+ **/
+static void
+lpfc_unset_driver_resource_phase2(struct lpfc_hba *phba)
+{
+	/* Stop kernel worker thread */
+	kthread_stop(phba->worker_thread);
+}
+
+/**
+ * lpfc_free_iocb_list - Free iocb list.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to free the driver's IOCB list and memory.
+ **/
+static void
+lpfc_free_iocb_list(struct lpfc_hba *phba)
+{
+	struct lpfc_iocbq *iocbq_entry = NULL, *iocbq_next = NULL;
+
+	spin_lock_irq(&phba->hbalock);
+	list_for_each_entry_safe(iocbq_entry, iocbq_next,
+				 &phba->lpfc_iocb_list, list) {
+		list_del(&iocbq_entry->list);
+		kfree(iocbq_entry);
+		phba->total_iocbq_bufs--;
+	}
+	spin_unlock_irq(&phba->hbalock);
+
+	return;
+}
+
+/**
+ * lpfc_init_iocb_list - Allocate and initialize iocb list.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to allocate and initizlize the driver's IOCB
+ * list and set up the IOCB tag array accordingly.
+ *
+ * Return codes
+ *	0 - sucessful
+ *	other values - error
+ **/
+static int
+lpfc_init_iocb_list(struct lpfc_hba *phba, int iocb_count)
+{
+	struct lpfc_iocbq *iocbq_entry = NULL;
+	uint16_t iotag;
+	int i;
+
+	/* Initialize and populate the iocb list per host.  */
+	INIT_LIST_HEAD(&phba->lpfc_iocb_list);
+	for (i = 0; i < iocb_count; i++) {
+		iocbq_entry = kzalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL);
+		if (iocbq_entry == NULL) {
+			printk(KERN_ERR "%s: only allocated %d iocbs of "
+				"expected %d count. Unloading driver.\n",
+				__func__, i, LPFC_IOCB_LIST_CNT);
+			goto out_free_iocbq;
+		}
+
+		iotag = lpfc_sli_next_iotag(phba, iocbq_entry);
+		if (iotag == 0) {
+			kfree(iocbq_entry);
+			printk(KERN_ERR "%s: failed to allocate IOTAG. "
+				"Unloading driver.\n", __func__);
+			goto out_free_iocbq;
+		}
+		iocbq_entry->sli4_xritag = NO_XRI;
+
+		spin_lock_irq(&phba->hbalock);
+		list_add(&iocbq_entry->list, &phba->lpfc_iocb_list);
+		phba->total_iocbq_bufs++;
+		spin_unlock_irq(&phba->hbalock);
+	}
+
+	return 0;
+
+out_free_iocbq:
+	lpfc_free_iocb_list(phba);
+
+	return -ENOMEM;
+}
+
+/**
+ * lpfc_free_sgl_list - Free sgl list.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to free the driver's sgl list and memory.
+ **/
+static void
+lpfc_free_sgl_list(struct lpfc_hba *phba)
+{
+	struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
+	LIST_HEAD(sglq_list);
+	int rc = 0;
+
+	spin_lock_irq(&phba->hbalock);
+	list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &sglq_list);
+	spin_unlock_irq(&phba->hbalock);
+
+	list_for_each_entry_safe(sglq_entry, sglq_next,
+				 &sglq_list, list) {
+		list_del(&sglq_entry->list);
+		lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys);
+		kfree(sglq_entry);
+		phba->sli4_hba.total_sglq_bufs--;
+	}
+	rc = lpfc_sli4_remove_all_sgl_pages(phba);
+	if (rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+			"2005 Unable to deregister pages from HBA: %x", rc);
+	}
+	kfree(phba->sli4_hba.lpfc_els_sgl_array);
+}
+
+/**
+ * lpfc_init_active_sgl_array - Allocate the buf to track active ELS XRIs.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to allocate the driver's active sgl memory.
+ * This array will hold the sglq_entry's for active IOs.
+ **/
+static int
+lpfc_init_active_sgl_array(struct lpfc_hba *phba)
+{
+	int size;
+	size = sizeof(struct lpfc_sglq *);
+	size *= phba->sli4_hba.max_cfg_param.max_xri;
+
+	phba->sli4_hba.lpfc_sglq_active_list =
+		kzalloc(size, GFP_KERNEL);
+	if (!phba->sli4_hba.lpfc_sglq_active_list)
+		return -ENOMEM;
+	return 0;
+}
+
+/**
+ * lpfc_free_active_sgl - Free the buf that tracks active ELS XRIs.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to walk through the array of active sglq entries
+ * and free all of the resources.
+ * This is just a place holder for now.
+ **/
+static void
+lpfc_free_active_sgl(struct lpfc_hba *phba)
+{
+	kfree(phba->sli4_hba.lpfc_sglq_active_list);
+}
+
+/**
+ * lpfc_init_sgl_list - Allocate and initialize sgl list.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to allocate and initizlize the driver's sgl
+ * list and set up the sgl xritag tag array accordingly.
+ *
+ * Return codes
+ *	0 - sucessful
+ *	other values - error
+ **/
+static int
+lpfc_init_sgl_list(struct lpfc_hba *phba)
+{
+	struct lpfc_sglq *sglq_entry = NULL;
+	int i;
+	int els_xri_cnt;
+
+	els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
+	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+				"2400 lpfc_init_sgl_list els %d.\n",
+				els_xri_cnt);
+	/* Initialize and populate the sglq list per host/VF. */
+	INIT_LIST_HEAD(&phba->sli4_hba.lpfc_sgl_list);
+	INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_els_sgl_list);
+
+	/* Sanity check on XRI management */
+	if (phba->sli4_hba.max_cfg_param.max_xri <= els_xri_cnt) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2562 No room left for SCSI XRI allocation: "
+				"max_xri=%d, els_xri=%d\n",
+				phba->sli4_hba.max_cfg_param.max_xri,
+				els_xri_cnt);
+		return -ENOMEM;
+	}
+
+	/* Allocate memory for the ELS XRI management array */
+	phba->sli4_hba.lpfc_els_sgl_array =
+			kzalloc((sizeof(struct lpfc_sglq *) * els_xri_cnt),
+			GFP_KERNEL);
+
+	if (!phba->sli4_hba.lpfc_els_sgl_array) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2401 Failed to allocate memory for ELS "
+				"XRI management array of size %d.\n",
+				els_xri_cnt);
+		return -ENOMEM;
+	}
+
+	/* Keep the SCSI XRI into the XRI management array */
+	phba->sli4_hba.scsi_xri_max =
+			phba->sli4_hba.max_cfg_param.max_xri - els_xri_cnt;
+	phba->sli4_hba.scsi_xri_cnt = 0;
+
+	phba->sli4_hba.lpfc_scsi_psb_array =
+			kzalloc((sizeof(struct lpfc_scsi_buf *) *
+			phba->sli4_hba.scsi_xri_max), GFP_KERNEL);
+
+	if (!phba->sli4_hba.lpfc_scsi_psb_array) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2563 Failed to allocate memory for SCSI "
+				"XRI management array of size %d.\n",
+				phba->sli4_hba.scsi_xri_max);
+		kfree(phba->sli4_hba.lpfc_els_sgl_array);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < els_xri_cnt; i++) {
+		sglq_entry = kzalloc(sizeof(struct lpfc_sglq), GFP_KERNEL);
+		if (sglq_entry == NULL) {
+			printk(KERN_ERR "%s: only allocated %d sgls of "
+				"expected %d count. Unloading driver.\n",
+				__func__, i, els_xri_cnt);
+			goto out_free_mem;
+		}
+
+		sglq_entry->sli4_xritag = lpfc_sli4_next_xritag(phba);
+		if (sglq_entry->sli4_xritag == NO_XRI) {
+			kfree(sglq_entry);
+			printk(KERN_ERR "%s: failed to allocate XRI.\n"
+				"Unloading driver.\n", __func__);
+			goto out_free_mem;
+		}
+		sglq_entry->buff_type = GEN_BUFF_TYPE;
+		sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, &sglq_entry->phys);
+		if (sglq_entry->virt == NULL) {
+			kfree(sglq_entry);
+			printk(KERN_ERR "%s: failed to allocate mbuf.\n"
+				"Unloading driver.\n", __func__);
+			goto out_free_mem;
+		}
+		sglq_entry->sgl = sglq_entry->virt;
+		memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE);
+
+		/* The list order is used by later block SGL registraton */
+		spin_lock_irq(&phba->hbalock);
+		list_add_tail(&sglq_entry->list, &phba->sli4_hba.lpfc_sgl_list);
+		phba->sli4_hba.lpfc_els_sgl_array[i] = sglq_entry;
+		phba->sli4_hba.total_sglq_bufs++;
+		spin_unlock_irq(&phba->hbalock);
+	}
+	return 0;
+
+out_free_mem:
+	kfree(phba->sli4_hba.lpfc_scsi_psb_array);
+	lpfc_free_sgl_list(phba);
+	return -ENOMEM;
+}
+
+/**
+ * lpfc_sli4_init_rpi_hdrs - Post the rpi header memory region to the port
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to post rpi header templates to the
+ * HBA consistent with the SLI-4 interface spec.  This routine
+ * posts a PAGE_SIZE memory region to the port to hold up to
+ * PAGE_SIZE modulo 64 rpi context headers.
+ * No locks are held here because this is an initialization routine
+ * called only from probe or lpfc_online when interrupts are not
+ * enabled and the driver is reinitializing the device.
+ *
+ * Return codes
+ * 	0 - sucessful
+ * 	ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+int
+lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba)
+{
+	int rc = 0;
+	int longs;
+	uint16_t rpi_count;
+	struct lpfc_rpi_hdr *rpi_hdr;
+
+	INIT_LIST_HEAD(&phba->sli4_hba.lpfc_rpi_hdr_list);
+
+	/*
+	 * Provision an rpi bitmask range for discovery. The total count
+	 * is the difference between max and base + 1.
+	 */
+	rpi_count = phba->sli4_hba.max_cfg_param.rpi_base +
+		    phba->sli4_hba.max_cfg_param.max_rpi - 1;
+
+	longs = ((rpi_count) + BITS_PER_LONG - 1) / BITS_PER_LONG;
+	phba->sli4_hba.rpi_bmask = kzalloc(longs * sizeof(unsigned long),
+					   GFP_KERNEL);
+	if (!phba->sli4_hba.rpi_bmask)
+		return -ENOMEM;
+
+	rpi_hdr = lpfc_sli4_create_rpi_hdr(phba);
+	if (!rpi_hdr) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+				"0391 Error during rpi post operation\n");
+		lpfc_sli4_remove_rpis(phba);
+		rc = -ENODEV;
+	}
+
+	return rc;
+}
+
+/**
+ * lpfc_sli4_create_rpi_hdr - Allocate an rpi header memory region
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to allocate a single 4KB memory region to
+ * support rpis and stores them in the phba.  This single region
+ * provides support for up to 64 rpis.  The region is used globally
+ * by the device.
+ *
+ * Returns:
+ *   A valid rpi hdr on success.
+ *   A NULL pointer on any failure.
+ **/
+struct lpfc_rpi_hdr *
+lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba)
+{
+	uint16_t rpi_limit, curr_rpi_range;
+	struct lpfc_dmabuf *dmabuf;
+	struct lpfc_rpi_hdr *rpi_hdr;
+
+	rpi_limit = phba->sli4_hba.max_cfg_param.rpi_base +
+		    phba->sli4_hba.max_cfg_param.max_rpi - 1;
+
+	spin_lock_irq(&phba->hbalock);
+	curr_rpi_range = phba->sli4_hba.next_rpi;
+	spin_unlock_irq(&phba->hbalock);
+
+	/*
+	 * The port has a limited number of rpis. The increment here
+	 * is LPFC_RPI_HDR_COUNT - 1 to account for the starting value
+	 * and to allow the full max_rpi range per port.
+	 */
+	if ((curr_rpi_range + (LPFC_RPI_HDR_COUNT - 1)) > rpi_limit)
+		return NULL;
+
+	/*
+	 * First allocate the protocol header region for the port.  The
+	 * port expects a 4KB DMA-mapped memory region that is 4K aligned.
+	 */
+	dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+	if (!dmabuf)
+		return NULL;
+
+	dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
+					  LPFC_HDR_TEMPLATE_SIZE,
+					  &dmabuf->phys,
+					  GFP_KERNEL);
+	if (!dmabuf->virt) {
+		rpi_hdr = NULL;
+		goto err_free_dmabuf;
+	}
+
+	memset(dmabuf->virt, 0, LPFC_HDR_TEMPLATE_SIZE);
+	if (!IS_ALIGNED(dmabuf->phys, LPFC_HDR_TEMPLATE_SIZE)) {
+		rpi_hdr = NULL;
+		goto err_free_coherent;
+	}
+
+	/* Save the rpi header data for cleanup later. */
+	rpi_hdr = kzalloc(sizeof(struct lpfc_rpi_hdr), GFP_KERNEL);
+	if (!rpi_hdr)
+		goto err_free_coherent;
+
+	rpi_hdr->dmabuf = dmabuf;
+	rpi_hdr->len = LPFC_HDR_TEMPLATE_SIZE;
+	rpi_hdr->page_count = 1;
+	spin_lock_irq(&phba->hbalock);
+	rpi_hdr->start_rpi = phba->sli4_hba.next_rpi;
+	list_add_tail(&rpi_hdr->list, &phba->sli4_hba.lpfc_rpi_hdr_list);
+
+	/*
+	 * The next_rpi stores the next module-64 rpi value to post
+	 * in any subsequent rpi memory region postings.
+	 */
+	phba->sli4_hba.next_rpi += LPFC_RPI_HDR_COUNT;
+	spin_unlock_irq(&phba->hbalock);
+	return rpi_hdr;
+
+ err_free_coherent:
+	dma_free_coherent(&phba->pcidev->dev, LPFC_HDR_TEMPLATE_SIZE,
+			  dmabuf->virt, dmabuf->phys);
+ err_free_dmabuf:
+	kfree(dmabuf);
+	return NULL;
+}
+
+/**
+ * lpfc_sli4_remove_rpi_hdrs - Remove all rpi header memory regions
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to remove all memory resources allocated
+ * to support rpis. This routine presumes the caller has released all
+ * rpis consumed by fabric or port logins and is prepared to have
+ * the header pages removed.
+ **/
+void
+lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *phba)
+{
+	struct lpfc_rpi_hdr *rpi_hdr, *next_rpi_hdr;
+
+	list_for_each_entry_safe(rpi_hdr, next_rpi_hdr,
+				 &phba->sli4_hba.lpfc_rpi_hdr_list, list) {
+		list_del(&rpi_hdr->list);
+		dma_free_coherent(&phba->pcidev->dev, rpi_hdr->len,
+				  rpi_hdr->dmabuf->virt, rpi_hdr->dmabuf->phys);
+		kfree(rpi_hdr->dmabuf);
+		kfree(rpi_hdr);
+	}
+
+	phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.rpi_base;
+	memset(phba->sli4_hba.rpi_bmask, 0, sizeof(*phba->sli4_hba.rpi_bmask));
+}
+
+/**
+ * lpfc_hba_alloc - Allocate driver hba data structure for a device.
+ * @pdev: pointer to pci device data structure.
+ *
+ * This routine is invoked to allocate the driver hba data structure for an
+ * HBA device. If the allocation is successful, the phba reference to the
+ * PCI device data structure is set.
+ *
+ * Return codes
+ *      pointer to @phba - sucessful
+ *      NULL - error
+ **/
+static struct lpfc_hba *
+lpfc_hba_alloc(struct pci_dev *pdev)
+{
+	struct lpfc_hba *phba;
+
+	/* Allocate memory for HBA structure */
+	phba = kzalloc(sizeof(struct lpfc_hba), GFP_KERNEL);
+	if (!phba) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1417 Failed to allocate hba struct.\n");
+		return NULL;
+	}
+
+	/* Set reference to PCI device in HBA structure */
+	phba->pcidev = pdev;
+
+	/* Assign an unused board number */
+	phba->brd_no = lpfc_get_instance();
+	if (phba->brd_no < 0) {
+		kfree(phba);
+		return NULL;
+	}
+
+	return phba;
+}
+
+/**
+ * lpfc_hba_free - Free driver hba data structure with a device.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to free the driver hba data structure with an
+ * HBA device.
+ **/
+static void
+lpfc_hba_free(struct lpfc_hba *phba)
+{
+	/* Release the driver assigned board number */
+	idr_remove(&lpfc_hba_index, phba->brd_no);
+
+	kfree(phba);
+	return;
+}
+
+/**
+ * lpfc_create_shost - Create hba physical port with associated scsi host.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to create HBA physical port and associate a SCSI
+ * host with it.
+ *
+ * Return codes
+ *      0 - sucessful
+ *      other values - error
+ **/
+static int
+lpfc_create_shost(struct lpfc_hba *phba)
+{
+	struct lpfc_vport *vport;
+	struct Scsi_Host  *shost;
+
+	/* Initialize HBA FC structure */
+	phba->fc_edtov = FF_DEF_EDTOV;
+	phba->fc_ratov = FF_DEF_RATOV;
+	phba->fc_altov = FF_DEF_ALTOV;
+	phba->fc_arbtov = FF_DEF_ARBTOV;
+
+	vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev);
+	if (!vport)
+		return -ENODEV;
+
+	shost = lpfc_shost_from_vport(vport);
+	phba->pport = vport;
+	lpfc_debugfs_initialize(vport);
+	/* Put reference to SCSI host to driver's device private data */
+	pci_set_drvdata(phba->pcidev, shost);
+
+	return 0;
+}
+
+/**
+ * lpfc_destroy_shost - Destroy hba physical port with associated scsi host.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to destroy HBA physical port and the associated
+ * SCSI host.
+ **/
+static void
+lpfc_destroy_shost(struct lpfc_hba *phba)
+{
+	struct lpfc_vport *vport = phba->pport;
+
+	/* Destroy physical port that associated with the SCSI host */
+	destroy_port(vport);
+
+	return;
+}
+
+/**
+ * lpfc_setup_bg - Setup Block guard structures and debug areas.
+ * @phba: pointer to lpfc hba data structure.
+ * @shost: the shost to be used to detect Block guard settings.
+ *
+ * This routine sets up the local Block guard protocol settings for @shost.
+ * This routine also allocates memory for debugging bg buffers.
+ **/
+static void
+lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost)
+{
+	int pagecnt = 10;
+	if (lpfc_prot_mask && lpfc_prot_guard) {
+		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"1478 Registering BlockGuard with the "
+				"SCSI layer\n");
+		scsi_host_set_prot(shost, lpfc_prot_mask);
+		scsi_host_set_guard(shost, lpfc_prot_guard);
+	}
+	if (!_dump_buf_data) {
+		while (pagecnt) {
+			spin_lock_init(&_dump_buf_lock);
+			_dump_buf_data =
+				(char *) __get_free_pages(GFP_KERNEL, pagecnt);
+			if (_dump_buf_data) {
+				printk(KERN_ERR "BLKGRD allocated %d pages for "
+				       "_dump_buf_data at 0x%p\n",
+				       (1 << pagecnt), _dump_buf_data);
+				_dump_buf_data_order = pagecnt;
+				memset(_dump_buf_data, 0,
+				       ((1 << PAGE_SHIFT) << pagecnt));
+				break;
+			} else
+				--pagecnt;
+		}
+		if (!_dump_buf_data_order)
+			printk(KERN_ERR "BLKGRD ERROR unable to allocate "
+			       "memory for hexdump\n");
+	} else
+		printk(KERN_ERR "BLKGRD already allocated _dump_buf_data=0x%p"
+		       "\n", _dump_buf_data);
+	if (!_dump_buf_dif) {
+		while (pagecnt) {
+			_dump_buf_dif =
+				(char *) __get_free_pages(GFP_KERNEL, pagecnt);
+			if (_dump_buf_dif) {
+				printk(KERN_ERR "BLKGRD allocated %d pages for "
+				       "_dump_buf_dif at 0x%p\n",
+				       (1 << pagecnt), _dump_buf_dif);
+				_dump_buf_dif_order = pagecnt;
+				memset(_dump_buf_dif, 0,
+				       ((1 << PAGE_SHIFT) << pagecnt));
+				break;
+			} else
+				--pagecnt;
+		}
+		if (!_dump_buf_dif_order)
+			printk(KERN_ERR "BLKGRD ERROR unable to allocate "
+			       "memory for hexdump\n");
+	} else
+		printk(KERN_ERR "BLKGRD already allocated _dump_buf_dif=0x%p\n",
+		       _dump_buf_dif);
+}
+
+/**
+ * lpfc_post_init_setup - Perform necessary device post initialization setup.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to perform all the necessary post initialization
+ * setup for the device.
+ **/
+static void
+lpfc_post_init_setup(struct lpfc_hba *phba)
+{
+	struct Scsi_Host  *shost;
+	struct lpfc_adapter_event_header adapter_event;
+
+	/* Get the default values for Model Name and Description */
+	lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc);
+
+	/*
+	 * hba setup may have changed the hba_queue_depth so we need to
+	 * adjust the value of can_queue.
+	 */
+	shost = pci_get_drvdata(phba->pcidev);
+	shost->can_queue = phba->cfg_hba_queue_depth - 10;
+	if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
+		lpfc_setup_bg(phba, shost);
+
+	lpfc_host_attrib_init(shost);
+
+	if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
+		spin_lock_irq(shost->host_lock);
+		lpfc_poll_start_timer(phba);
+		spin_unlock_irq(shost->host_lock);
+	}
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"0428 Perform SCSI scan\n");
+	/* Send board arrival event to upper layer */
+	adapter_event.event_type = FC_REG_ADAPTER_EVENT;
+	adapter_event.subcategory = LPFC_EVENT_ARRIVAL;
+	fc_host_post_vendor_event(shost, fc_get_event_number(),
+				  sizeof(adapter_event),
+				  (char *) &adapter_event,
+				  LPFC_NL_VENDOR_ID);
+	return;
+}
+
+/**
+ * lpfc_sli_pci_mem_setup - Setup SLI3 HBA PCI memory space.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up the PCI device memory space for device
+ * with SLI-3 interface spec.
+ *
+ * Return codes
+ * 	0 - sucessful
+ * 	other values - error
+ **/
+static int
+lpfc_sli_pci_mem_setup(struct lpfc_hba *phba)
+{
+	struct pci_dev *pdev;
+	unsigned long bar0map_len, bar2map_len;
+	int i, hbq_count;
+	void *ptr;
+	int error = -ENODEV;
+
+	/* Obtain PCI device reference */
+	if (!phba->pcidev)
+		return error;
+	else
+		pdev = phba->pcidev;
+
+	/* Set the device DMA mask size */
+	if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)
+		if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
+			return error;
+
+	/* Get the bus address of Bar0 and Bar2 and the number of bytes
+	 * required by each mapping.
+	 */
+	phba->pci_bar0_map = pci_resource_start(pdev, 0);
+	bar0map_len = pci_resource_len(pdev, 0);
+
+	phba->pci_bar2_map = pci_resource_start(pdev, 2);
+	bar2map_len = pci_resource_len(pdev, 2);
+
+	/* Map HBA SLIM to a kernel virtual address. */
+	phba->slim_memmap_p = ioremap(phba->pci_bar0_map, bar0map_len);
+	if (!phba->slim_memmap_p) {
+		dev_printk(KERN_ERR, &pdev->dev,
+			   "ioremap failed for SLIM memory.\n");
+		goto out;
+	}
+
+	/* Map HBA Control Registers to a kernel virtual address. */
+	phba->ctrl_regs_memmap_p = ioremap(phba->pci_bar2_map, bar2map_len);
+	if (!phba->ctrl_regs_memmap_p) {
+		dev_printk(KERN_ERR, &pdev->dev,
+			   "ioremap failed for HBA control registers.\n");
+		goto out_iounmap_slim;
+	}
+
+	/* Allocate memory for SLI-2 structures */
+	phba->slim2p.virt = dma_alloc_coherent(&pdev->dev,
+					       SLI2_SLIM_SIZE,
+					       &phba->slim2p.phys,
+					       GFP_KERNEL);
+	if (!phba->slim2p.virt)
+		goto out_iounmap;
+
+	memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE);
+	phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx);
+	phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb));
+	phba->IOCBs = (phba->slim2p.virt +
+		       offsetof(struct lpfc_sli2_slim, IOCBs));
+
+	phba->hbqslimp.virt = dma_alloc_coherent(&pdev->dev,
+						 lpfc_sli_hbq_size(),
+						 &phba->hbqslimp.phys,
+						 GFP_KERNEL);
+	if (!phba->hbqslimp.virt)
+		goto out_free_slim;
+
+	hbq_count = lpfc_sli_hbq_count();
+	ptr = phba->hbqslimp.virt;
+	for (i = 0; i < hbq_count; ++i) {
+		phba->hbqs[i].hbq_virt = ptr;
+		INIT_LIST_HEAD(&phba->hbqs[i].hbq_buffer_list);
+		ptr += (lpfc_hbq_defs[i]->entry_count *
+			sizeof(struct lpfc_hbq_entry));
+	}
+	phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_els_hbq_alloc;
+	phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_els_hbq_free;
+
+	memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size());
+
+	INIT_LIST_HEAD(&phba->rb_pend_list);
+
+	phba->MBslimaddr = phba->slim_memmap_p;
+	phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
+	phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
+	phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
+	phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+
+	return 0;
+
+out_free_slim:
+	dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
+			  phba->slim2p.virt, phba->slim2p.phys);
+out_iounmap:
+	iounmap(phba->ctrl_regs_memmap_p);
+out_iounmap_slim:
+	iounmap(phba->slim_memmap_p);
+out:
+	return error;
+}
+
+/**
+ * lpfc_sli_pci_mem_unset - Unset SLI3 HBA PCI memory space.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset the PCI device memory space for device
+ * with SLI-3 interface spec.
+ **/
+static void
+lpfc_sli_pci_mem_unset(struct lpfc_hba *phba)
+{
+	struct pci_dev *pdev;
+
+	/* Obtain PCI device reference */
+	if (!phba->pcidev)
+		return;
+	else
+		pdev = phba->pcidev;
+
+	/* Free coherent DMA memory allocated */
+	dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(),
+			  phba->hbqslimp.virt, phba->hbqslimp.phys);
+	dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
+			  phba->slim2p.virt, phba->slim2p.phys);
+
+	/* I/O memory unmap */
+	iounmap(phba->ctrl_regs_memmap_p);
+	iounmap(phba->slim_memmap_p);
+
+	return;
+}
+
+/**
+ * lpfc_sli4_post_status_check - Wait for SLI4 POST done and check status
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to wait for SLI4 device Power On Self Test (POST)
+ * done and check status.
+ *
+ * Return 0 if successful, otherwise -ENODEV.
+ **/
+int
+lpfc_sli4_post_status_check(struct lpfc_hba *phba)
+{
+	struct lpfc_register sta_reg, uerrlo_reg, uerrhi_reg, scratchpad;
+	uint32_t onlnreg0, onlnreg1;
+	int i, port_error = -ENODEV;
+
+	if (!phba->sli4_hba.STAregaddr)
+		return -ENODEV;
+
+	/* With uncoverable error, log the error message and return error */
+	onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr);
+	onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr);
+	if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) {
+		uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr);
+		uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr);
+		if (uerrlo_reg.word0 || uerrhi_reg.word0) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"1422 HBA Unrecoverable error: "
+					"uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
+					"online0_reg=0x%x, online1_reg=0x%x\n",
+					uerrlo_reg.word0, uerrhi_reg.word0,
+					onlnreg0, onlnreg1);
+		}
+		return -ENODEV;
+	}
+
+	/* Wait up to 30 seconds for the SLI Port POST done and ready */
+	for (i = 0; i < 3000; i++) {
+		sta_reg.word0 = readl(phba->sli4_hba.STAregaddr);
+		/* Encounter fatal POST error, break out */
+		if (bf_get(lpfc_hst_state_perr, &sta_reg)) {
+			port_error = -ENODEV;
+			break;
+		}
+		if (LPFC_POST_STAGE_ARMFW_READY ==
+		    bf_get(lpfc_hst_state_port_status, &sta_reg)) {
+			port_error = 0;
+			break;
+		}
+		msleep(10);
+	}
+
+	if (port_error)
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"1408 Failure HBA POST Status: sta_reg=0x%x, "
+			"perr=x%x, sfi=x%x, nip=x%x, ipc=x%x, xrom=x%x, "
+			"dl=x%x, pstatus=x%x\n", sta_reg.word0,
+			bf_get(lpfc_hst_state_perr, &sta_reg),
+			bf_get(lpfc_hst_state_sfi, &sta_reg),
+			bf_get(lpfc_hst_state_nip, &sta_reg),
+			bf_get(lpfc_hst_state_ipc, &sta_reg),
+			bf_get(lpfc_hst_state_xrom, &sta_reg),
+			bf_get(lpfc_hst_state_dl, &sta_reg),
+			bf_get(lpfc_hst_state_port_status, &sta_reg));
+
+	/* Log device information */
+	scratchpad.word0 =  readl(phba->sli4_hba.SCRATCHPADregaddr);
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"2534 Device Info: ChipType=0x%x, SliRev=0x%x, "
+			"FeatureL1=0x%x, FeatureL2=0x%x\n",
+			bf_get(lpfc_scratchpad_chiptype, &scratchpad),
+			bf_get(lpfc_scratchpad_slirev, &scratchpad),
+			bf_get(lpfc_scratchpad_featurelevel1, &scratchpad),
+			bf_get(lpfc_scratchpad_featurelevel2, &scratchpad));
+
+	return port_error;
+}
+
+/**
+ * lpfc_sli4_bar0_register_memmap - Set up SLI4 BAR0 register memory map.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up SLI4 BAR0 PCI config space register
+ * memory map.
+ **/
+static void
+lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba)
+{
+	phba->sli4_hba.UERRLOregaddr = phba->sli4_hba.conf_regs_memmap_p +
+					LPFC_UERR_STATUS_LO;
+	phba->sli4_hba.UERRHIregaddr = phba->sli4_hba.conf_regs_memmap_p +
+					LPFC_UERR_STATUS_HI;
+	phba->sli4_hba.ONLINE0regaddr = phba->sli4_hba.conf_regs_memmap_p +
+					LPFC_ONLINE0;
+	phba->sli4_hba.ONLINE1regaddr = phba->sli4_hba.conf_regs_memmap_p +
+					LPFC_ONLINE1;
+	phba->sli4_hba.SCRATCHPADregaddr = phba->sli4_hba.conf_regs_memmap_p +
+					LPFC_SCRATCHPAD;
+}
+
+/**
+ * lpfc_sli4_bar1_register_memmap - Set up SLI4 BAR1 register memory map.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up SLI4 BAR1 control status register (CSR)
+ * memory map.
+ **/
+static void
+lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba)
+{
+
+	phba->sli4_hba.STAregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+				    LPFC_HST_STATE;
+	phba->sli4_hba.ISRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+				    LPFC_HST_ISR0;
+	phba->sli4_hba.IMRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+				    LPFC_HST_IMR0;
+	phba->sli4_hba.ISCRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+				     LPFC_HST_ISCR0;
+	return;
+}
+
+/**
+ * lpfc_sli4_bar2_register_memmap - Set up SLI4 BAR2 register memory map.
+ * @phba: pointer to lpfc hba data structure.
+ * @vf: virtual function number
+ *
+ * This routine is invoked to set up SLI4 BAR2 doorbell register memory map
+ * based on the given viftual function number, @vf.
+ *
+ * Return 0 if successful, otherwise -ENODEV.
+ **/
+static int
+lpfc_sli4_bar2_register_memmap(struct lpfc_hba *phba, uint32_t vf)
+{
+	if (vf > LPFC_VIR_FUNC_MAX)
+		return -ENODEV;
+
+	phba->sli4_hba.RQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
+				vf * LPFC_VFR_PAGE_SIZE + LPFC_RQ_DOORBELL);
+	phba->sli4_hba.WQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
+				vf * LPFC_VFR_PAGE_SIZE + LPFC_WQ_DOORBELL);
+	phba->sli4_hba.EQCQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
+				vf * LPFC_VFR_PAGE_SIZE + LPFC_EQCQ_DOORBELL);
+	phba->sli4_hba.MQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
+				vf * LPFC_VFR_PAGE_SIZE + LPFC_MQ_DOORBELL);
+	phba->sli4_hba.BMBXregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
+				vf * LPFC_VFR_PAGE_SIZE + LPFC_BMBX);
+	return 0;
+}
+
+/**
+ * lpfc_create_bootstrap_mbox - Create the bootstrap mailbox
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to create the bootstrap mailbox
+ * region consistent with the SLI-4 interface spec.  This
+ * routine allocates all memory necessary to communicate
+ * mailbox commands to the port and sets up all alignment
+ * needs.  No locks are expected to be held when calling
+ * this routine.
+ *
+ * Return codes
+ * 	0 - sucessful
+ * 	ENOMEM - could not allocated memory.
+ **/
+static int
+lpfc_create_bootstrap_mbox(struct lpfc_hba *phba)
+{
+	uint32_t bmbx_size;
+	struct lpfc_dmabuf *dmabuf;
+	struct dma_address *dma_address;
+	uint32_t pa_addr;
+	uint64_t phys_addr;
+
+	dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+	if (!dmabuf)
+		return -ENOMEM;
+
+	/*
+	 * The bootstrap mailbox region is comprised of 2 parts
+	 * plus an alignment restriction of 16 bytes.
+	 */
+	bmbx_size = sizeof(struct lpfc_bmbx_create) + (LPFC_ALIGN_16_BYTE - 1);
+	dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
+					  bmbx_size,
+					  &dmabuf->phys,
+					  GFP_KERNEL);
+	if (!dmabuf->virt) {
+		kfree(dmabuf);
+		return -ENOMEM;
+	}
+	memset(dmabuf->virt, 0, bmbx_size);
+
+	/*
+	 * Initialize the bootstrap mailbox pointers now so that the register
+	 * operations are simple later.  The mailbox dma address is required
+	 * to be 16-byte aligned.  Also align the virtual memory as each
+	 * maibox is copied into the bmbx mailbox region before issuing the
+	 * command to the port.
+	 */
+	phba->sli4_hba.bmbx.dmabuf = dmabuf;
+	phba->sli4_hba.bmbx.bmbx_size = bmbx_size;
+
+	phba->sli4_hba.bmbx.avirt = PTR_ALIGN(dmabuf->virt,
+					      LPFC_ALIGN_16_BYTE);
+	phba->sli4_hba.bmbx.aphys = ALIGN(dmabuf->phys,
+					      LPFC_ALIGN_16_BYTE);
+
+	/*
+	 * Set the high and low physical addresses now.  The SLI4 alignment
+	 * requirement is 16 bytes and the mailbox is posted to the port
+	 * as two 30-bit addresses.  The other data is a bit marking whether
+	 * the 30-bit address is the high or low address.
+	 * Upcast bmbx aphys to 64bits so shift instruction compiles
+	 * clean on 32 bit machines.
+	 */
+	dma_address = &phba->sli4_hba.bmbx.dma_address;
+	phys_addr = (uint64_t)phba->sli4_hba.bmbx.aphys;
+	pa_addr = (uint32_t) ((phys_addr >> 34) & 0x3fffffff);
+	dma_address->addr_hi = (uint32_t) ((pa_addr << 2) |
+					   LPFC_BMBX_BIT1_ADDR_HI);
+
+	pa_addr = (uint32_t) ((phba->sli4_hba.bmbx.aphys >> 4) & 0x3fffffff);
+	dma_address->addr_lo = (uint32_t) ((pa_addr << 2) |
+					   LPFC_BMBX_BIT1_ADDR_LO);
+	return 0;
+}
+
+/**
+ * lpfc_destroy_bootstrap_mbox - Destroy all bootstrap mailbox resources
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to teardown the bootstrap mailbox
+ * region and release all host resources. This routine requires
+ * the caller to ensure all mailbox commands recovered, no
+ * additional mailbox comands are sent, and interrupts are disabled
+ * before calling this routine.
+ *
+ **/
+static void
+lpfc_destroy_bootstrap_mbox(struct lpfc_hba *phba)
+{
+	dma_free_coherent(&phba->pcidev->dev,
+			  phba->sli4_hba.bmbx.bmbx_size,
+			  phba->sli4_hba.bmbx.dmabuf->virt,
+			  phba->sli4_hba.bmbx.dmabuf->phys);
+
+	kfree(phba->sli4_hba.bmbx.dmabuf);
+	memset(&phba->sli4_hba.bmbx, 0, sizeof(struct lpfc_bmbx));
+}
+
+/**
+ * lpfc_sli4_read_config - Get the config parameters.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to read the configuration parameters from the HBA.
+ * The configuration parameters are used to set the base and maximum values
+ * for RPI's XRI's VPI's VFI's and FCFIs. These values also affect the resource
+ * allocation for the port.
+ *
+ * Return codes
+ * 	0 - sucessful
+ * 	ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+static int
+lpfc_sli4_read_config(struct lpfc_hba *phba)
+{
+	LPFC_MBOXQ_t *pmb;
+	struct lpfc_mbx_read_config *rd_config;
+	uint32_t rc = 0;
+
+	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!pmb) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2011 Unable to allocate memory for issuing "
+				"SLI_CONFIG_SPECIAL mailbox command\n");
+		return -ENOMEM;
+	}
+
+	lpfc_read_config(phba, pmb);
+
+	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+	if (rc != MBX_SUCCESS) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+			"2012 Mailbox failed , mbxCmd x%x "
+			"READ_CONFIG, mbxStatus x%x\n",
+			bf_get(lpfc_mqe_command, &pmb->u.mqe),
+			bf_get(lpfc_mqe_status, &pmb->u.mqe));
+		rc = -EIO;
+	} else {
+		rd_config = &pmb->u.mqe.un.rd_config;
+		phba->sli4_hba.max_cfg_param.max_xri =
+			bf_get(lpfc_mbx_rd_conf_xri_count, rd_config);
+		phba->sli4_hba.max_cfg_param.xri_base =
+			bf_get(lpfc_mbx_rd_conf_xri_base, rd_config);
+		phba->sli4_hba.max_cfg_param.max_vpi =
+			bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config);
+		phba->sli4_hba.max_cfg_param.vpi_base =
+			bf_get(lpfc_mbx_rd_conf_vpi_base, rd_config);
+		phba->sli4_hba.max_cfg_param.max_rpi =
+			bf_get(lpfc_mbx_rd_conf_rpi_count, rd_config);
+		phba->sli4_hba.max_cfg_param.rpi_base =
+			bf_get(lpfc_mbx_rd_conf_rpi_base, rd_config);
+		phba->sli4_hba.max_cfg_param.max_vfi =
+			bf_get(lpfc_mbx_rd_conf_vfi_count, rd_config);
+		phba->sli4_hba.max_cfg_param.vfi_base =
+			bf_get(lpfc_mbx_rd_conf_vfi_base, rd_config);
+		phba->sli4_hba.max_cfg_param.max_fcfi =
+			bf_get(lpfc_mbx_rd_conf_fcfi_count, rd_config);
+		phba->sli4_hba.max_cfg_param.fcfi_base =
+			bf_get(lpfc_mbx_rd_conf_fcfi_base, rd_config);
+		phba->sli4_hba.max_cfg_param.max_eq =
+			bf_get(lpfc_mbx_rd_conf_eq_count, rd_config);
+		phba->sli4_hba.max_cfg_param.max_rq =
+			bf_get(lpfc_mbx_rd_conf_rq_count, rd_config);
+		phba->sli4_hba.max_cfg_param.max_wq =
+			bf_get(lpfc_mbx_rd_conf_wq_count, rd_config);
+		phba->sli4_hba.max_cfg_param.max_cq =
+			bf_get(lpfc_mbx_rd_conf_cq_count, rd_config);
+		phba->lmt = bf_get(lpfc_mbx_rd_conf_lmt, rd_config);
+		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;
+		phba->max_vports = phba->max_vpi;
+		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+				"2003 cfg params XRI(B:%d M:%d), "
+				"VPI(B:%d M:%d) "
+				"VFI(B:%d M:%d) "
+				"RPI(B:%d M:%d) "
+				"FCFI(B:%d M:%d)\n",
+				phba->sli4_hba.max_cfg_param.xri_base,
+				phba->sli4_hba.max_cfg_param.max_xri,
+				phba->sli4_hba.max_cfg_param.vpi_base,
+				phba->sli4_hba.max_cfg_param.max_vpi,
+				phba->sli4_hba.max_cfg_param.vfi_base,
+				phba->sli4_hba.max_cfg_param.max_vfi,
+				phba->sli4_hba.max_cfg_param.rpi_base,
+				phba->sli4_hba.max_cfg_param.max_rpi,
+				phba->sli4_hba.max_cfg_param.fcfi_base,
+				phba->sli4_hba.max_cfg_param.max_fcfi);
+	}
+	mempool_free(pmb, phba->mbox_mem_pool);
+
+	/* Reset the DFT_HBA_Q_DEPTH to the max xri  */
+	if (phba->cfg_hba_queue_depth > (phba->sli4_hba.max_cfg_param.max_xri))
+		phba->cfg_hba_queue_depth =
+				phba->sli4_hba.max_cfg_param.max_xri;
+	return rc;
+}
+
+/**
+ * lpfc_dev_endian_order_setup - Notify the port of the host's endian order.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to setup the host-side endian order to the
+ * HBA consistent with the SLI-4 interface spec.
+ *
+ * Return codes
+ * 	0 - sucessful
+ * 	ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+static int
+lpfc_setup_endian_order(struct lpfc_hba *phba)
+{
+	LPFC_MBOXQ_t *mboxq;
+	uint32_t rc = 0;
+	uint32_t endian_mb_data[2] = {HOST_ENDIAN_LOW_WORD0,
+				      HOST_ENDIAN_HIGH_WORD1};
+
+	mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mboxq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0492 Unable to allocate memory for issuing "
+				"SLI_CONFIG_SPECIAL mailbox command\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * The SLI4_CONFIG_SPECIAL mailbox command requires the first two
+	 * words to contain special data values and no other data.
+	 */
+	memset(mboxq, 0, sizeof(LPFC_MBOXQ_t));
+	memcpy(&mboxq->u.mqe, &endian_mb_data, sizeof(endian_mb_data));
+	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+	if (rc != MBX_SUCCESS) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0493 SLI_CONFIG_SPECIAL mailbox failed with "
+				"status x%x\n",
+				rc);
+		rc = -EIO;
+	}
+
+	mempool_free(mboxq, phba->mbox_mem_pool);
+	return rc;
+}
+
+/**
+ * lpfc_sli4_queue_create - Create all the SLI4 queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to allocate all the SLI4 queues for the FCoE HBA
+ * operation. For each SLI4 queue type, the parameters such as queue entry
+ * count (queue depth) shall be taken from the module parameter. For now,
+ * we just use some constant number as place holder.
+ *
+ * Return codes
+ *      0 - sucessful
+ *      ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+static int
+lpfc_sli4_queue_create(struct lpfc_hba *phba)
+{
+	struct lpfc_queue *qdesc;
+	int fcp_eqidx, fcp_cqidx, fcp_wqidx;
+	int cfg_fcp_wq_count;
+	int cfg_fcp_eq_count;
+
+	/*
+	 * Sanity check for confiugred queue parameters against the run-time
+	 * device parameters
+	 */
+
+	/* Sanity check on FCP fast-path WQ parameters */
+	cfg_fcp_wq_count = phba->cfg_fcp_wq_count;
+	if (cfg_fcp_wq_count >
+	    (phba->sli4_hba.max_cfg_param.max_wq - LPFC_SP_WQN_DEF)) {
+		cfg_fcp_wq_count = phba->sli4_hba.max_cfg_param.max_wq -
+				   LPFC_SP_WQN_DEF;
+		if (cfg_fcp_wq_count < LPFC_FP_WQN_MIN) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"2581 Not enough WQs (%d) from "
+					"the pci function for supporting "
+					"FCP WQs (%d)\n",
+					phba->sli4_hba.max_cfg_param.max_wq,
+					phba->cfg_fcp_wq_count);
+			goto out_error;
+		}
+		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"2582 Not enough WQs (%d) from the pci "
+				"function for supporting the requested "
+				"FCP WQs (%d), the actual FCP WQs can "
+				"be supported: %d\n",
+				phba->sli4_hba.max_cfg_param.max_wq,
+				phba->cfg_fcp_wq_count, cfg_fcp_wq_count);
+	}
+	/* The actual number of FCP work queues adopted */
+	phba->cfg_fcp_wq_count = cfg_fcp_wq_count;
+
+	/* Sanity check on FCP fast-path EQ parameters */
+	cfg_fcp_eq_count = phba->cfg_fcp_eq_count;
+	if (cfg_fcp_eq_count >
+	    (phba->sli4_hba.max_cfg_param.max_eq - LPFC_SP_EQN_DEF)) {
+		cfg_fcp_eq_count = phba->sli4_hba.max_cfg_param.max_eq -
+				   LPFC_SP_EQN_DEF;
+		if (cfg_fcp_eq_count < LPFC_FP_EQN_MIN) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"2574 Not enough EQs (%d) from the "
+					"pci function for supporting FCP "
+					"EQs (%d)\n",
+					phba->sli4_hba.max_cfg_param.max_eq,
+					phba->cfg_fcp_eq_count);
+			goto out_error;
+		}
+		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"2575 Not enough EQs (%d) from the pci "
+				"function for supporting the requested "
+				"FCP EQs (%d), the actual FCP EQs can "
+				"be supported: %d\n",
+				phba->sli4_hba.max_cfg_param.max_eq,
+				phba->cfg_fcp_eq_count, cfg_fcp_eq_count);
+	}
+	/* It does not make sense to have more EQs than WQs */
+	if (cfg_fcp_eq_count > phba->cfg_fcp_wq_count) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"2593 The number of FCP EQs (%d) is more "
+				"than the number of FCP WQs (%d), take "
+				"the number of FCP EQs same as than of "
+				"WQs (%d)\n", cfg_fcp_eq_count,
+				phba->cfg_fcp_wq_count,
+				phba->cfg_fcp_wq_count);
+		cfg_fcp_eq_count = phba->cfg_fcp_wq_count;
+	}
+	/* The actual number of FCP event queues adopted */
+	phba->cfg_fcp_eq_count = cfg_fcp_eq_count;
+	/* The overall number of event queues used */
+	phba->sli4_hba.cfg_eqn = phba->cfg_fcp_eq_count + LPFC_SP_EQN_DEF;
+
+	/*
+	 * Create Event Queues (EQs)
+	 */
+
+	/* Get EQ depth from module parameter, fake the default for now */
+	phba->sli4_hba.eq_esize = LPFC_EQE_SIZE_4B;
+	phba->sli4_hba.eq_ecount = LPFC_EQE_DEF_COUNT;
+
+	/* Create slow path event queue */
+	qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize,
+				      phba->sli4_hba.eq_ecount);
+	if (!qdesc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0496 Failed allocate slow-path EQ\n");
+		goto out_error;
+	}
+	phba->sli4_hba.sp_eq = qdesc;
+
+	/* Create fast-path FCP Event Queue(s) */
+	phba->sli4_hba.fp_eq = kzalloc((sizeof(struct lpfc_queue *) *
+			       phba->cfg_fcp_eq_count), GFP_KERNEL);
+	if (!phba->sli4_hba.fp_eq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2576 Failed allocate memory for fast-path "
+				"EQ record array\n");
+		goto out_free_sp_eq;
+	}
+	for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) {
+		qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize,
+					      phba->sli4_hba.eq_ecount);
+		if (!qdesc) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"0497 Failed allocate fast-path EQ\n");
+			goto out_free_fp_eq;
+		}
+		phba->sli4_hba.fp_eq[fcp_eqidx] = qdesc;
+	}
+
+	/*
+	 * Create Complete Queues (CQs)
+	 */
+
+	/* Get CQ depth from module parameter, fake the default for now */
+	phba->sli4_hba.cq_esize = LPFC_CQE_SIZE;
+	phba->sli4_hba.cq_ecount = LPFC_CQE_DEF_COUNT;
+
+	/* Create slow-path Mailbox Command Complete Queue */
+	qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize,
+				      phba->sli4_hba.cq_ecount);
+	if (!qdesc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0500 Failed allocate slow-path mailbox CQ\n");
+		goto out_free_fp_eq;
+	}
+	phba->sli4_hba.mbx_cq = qdesc;
+
+	/* Create slow-path ELS Complete Queue */
+	qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize,
+				      phba->sli4_hba.cq_ecount);
+	if (!qdesc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0501 Failed allocate slow-path ELS CQ\n");
+		goto out_free_mbx_cq;
+	}
+	phba->sli4_hba.els_cq = qdesc;
+
+	/* Create slow-path Unsolicited Receive Complete Queue */
+	qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize,
+				      phba->sli4_hba.cq_ecount);
+	if (!qdesc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0502 Failed allocate slow-path USOL RX CQ\n");
+		goto out_free_els_cq;
+	}
+	phba->sli4_hba.rxq_cq = qdesc;
+
+	/* Create fast-path FCP Completion Queue(s), one-to-one with EQs */
+	phba->sli4_hba.fcp_cq = kzalloc((sizeof(struct lpfc_queue *) *
+				phba->cfg_fcp_eq_count), GFP_KERNEL);
+	if (!phba->sli4_hba.fcp_cq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2577 Failed allocate memory for fast-path "
+				"CQ record array\n");
+		goto out_free_rxq_cq;
+	}
+	for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) {
+		qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize,
+					      phba->sli4_hba.cq_ecount);
+		if (!qdesc) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"0499 Failed allocate fast-path FCP "
+					"CQ (%d)\n", fcp_cqidx);
+			goto out_free_fcp_cq;
+		}
+		phba->sli4_hba.fcp_cq[fcp_cqidx] = qdesc;
+	}
+
+	/* Create Mailbox Command Queue */
+	phba->sli4_hba.mq_esize = LPFC_MQE_SIZE;
+	phba->sli4_hba.mq_ecount = LPFC_MQE_DEF_COUNT;
+
+	qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.mq_esize,
+				      phba->sli4_hba.mq_ecount);
+	if (!qdesc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0505 Failed allocate slow-path MQ\n");
+		goto out_free_fcp_cq;
+	}
+	phba->sli4_hba.mbx_wq = qdesc;
+
+	/*
+	 * Create all the Work Queues (WQs)
+	 */
+	phba->sli4_hba.wq_esize = LPFC_WQE_SIZE;
+	phba->sli4_hba.wq_ecount = LPFC_WQE_DEF_COUNT;
+
+	/* Create slow-path ELS Work Queue */
+	qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize,
+				      phba->sli4_hba.wq_ecount);
+	if (!qdesc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0504 Failed allocate slow-path ELS WQ\n");
+		goto out_free_mbx_wq;
+	}
+	phba->sli4_hba.els_wq = qdesc;
+
+	/* Create fast-path FCP Work Queue(s) */
+	phba->sli4_hba.fcp_wq = kzalloc((sizeof(struct lpfc_queue *) *
+				phba->cfg_fcp_wq_count), GFP_KERNEL);
+	if (!phba->sli4_hba.fcp_wq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2578 Failed allocate memory for fast-path "
+				"WQ record array\n");
+		goto out_free_els_wq;
+	}
+	for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) {
+		qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize,
+					      phba->sli4_hba.wq_ecount);
+		if (!qdesc) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"0503 Failed allocate fast-path FCP "
+					"WQ (%d)\n", fcp_wqidx);
+			goto out_free_fcp_wq;
+		}
+		phba->sli4_hba.fcp_wq[fcp_wqidx] = qdesc;
+	}
+
+	/*
+	 * Create Receive Queue (RQ)
+	 */
+	phba->sli4_hba.rq_esize = LPFC_RQE_SIZE;
+	phba->sli4_hba.rq_ecount = LPFC_RQE_DEF_COUNT;
+
+	/* Create Receive Queue for header */
+	qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.rq_esize,
+				      phba->sli4_hba.rq_ecount);
+	if (!qdesc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0506 Failed allocate receive HRQ\n");
+		goto out_free_fcp_wq;
+	}
+	phba->sli4_hba.hdr_rq = qdesc;
+
+	/* Create Receive Queue for data */
+	qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.rq_esize,
+				      phba->sli4_hba.rq_ecount);
+	if (!qdesc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0507 Failed allocate receive DRQ\n");
+		goto out_free_hdr_rq;
+	}
+	phba->sli4_hba.dat_rq = qdesc;
+
+	return 0;
+
+out_free_hdr_rq:
+	lpfc_sli4_queue_free(phba->sli4_hba.hdr_rq);
+	phba->sli4_hba.hdr_rq = NULL;
+out_free_fcp_wq:
+	for (--fcp_wqidx; fcp_wqidx >= 0; fcp_wqidx--) {
+		lpfc_sli4_queue_free(phba->sli4_hba.fcp_wq[fcp_wqidx]);
+		phba->sli4_hba.fcp_wq[fcp_wqidx] = NULL;
+	}
+	kfree(phba->sli4_hba.fcp_wq);
+out_free_els_wq:
+	lpfc_sli4_queue_free(phba->sli4_hba.els_wq);
+	phba->sli4_hba.els_wq = NULL;
+out_free_mbx_wq:
+	lpfc_sli4_queue_free(phba->sli4_hba.mbx_wq);
+	phba->sli4_hba.mbx_wq = NULL;
+out_free_fcp_cq:
+	for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--) {
+		lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_cqidx]);
+		phba->sli4_hba.fcp_cq[fcp_cqidx] = NULL;
+	}
+	kfree(phba->sli4_hba.fcp_cq);
+out_free_rxq_cq:
+	lpfc_sli4_queue_free(phba->sli4_hba.rxq_cq);
+	phba->sli4_hba.rxq_cq = NULL;
+out_free_els_cq:
+	lpfc_sli4_queue_free(phba->sli4_hba.els_cq);
+	phba->sli4_hba.els_cq = NULL;
+out_free_mbx_cq:
+	lpfc_sli4_queue_free(phba->sli4_hba.mbx_cq);
+	phba->sli4_hba.mbx_cq = NULL;
+out_free_fp_eq:
+	for (--fcp_eqidx; fcp_eqidx >= 0; fcp_eqidx--) {
+		lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_eqidx]);
+		phba->sli4_hba.fp_eq[fcp_eqidx] = NULL;
+	}
+	kfree(phba->sli4_hba.fp_eq);
+out_free_sp_eq:
+	lpfc_sli4_queue_free(phba->sli4_hba.sp_eq);
+	phba->sli4_hba.sp_eq = NULL;
+out_error:
+	return -ENOMEM;
+}
+
+/**
+ * lpfc_sli4_queue_destroy - Destroy all the SLI4 queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release all the SLI4 queues with the FCoE HBA
+ * operation.
+ *
+ * Return codes
+ *      0 - sucessful
+ *      ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+static void
+lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
+{
+	int fcp_qidx;
+
+	/* Release mailbox command work queue */
+	lpfc_sli4_queue_free(phba->sli4_hba.mbx_wq);
+	phba->sli4_hba.mbx_wq = NULL;
+
+	/* Release ELS work queue */
+	lpfc_sli4_queue_free(phba->sli4_hba.els_wq);
+	phba->sli4_hba.els_wq = NULL;
+
+	/* Release FCP work queue */
+	for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++)
+		lpfc_sli4_queue_free(phba->sli4_hba.fcp_wq[fcp_qidx]);
+	kfree(phba->sli4_hba.fcp_wq);
+	phba->sli4_hba.fcp_wq = NULL;
+
+	/* Release unsolicited receive queue */
+	lpfc_sli4_queue_free(phba->sli4_hba.hdr_rq);
+	phba->sli4_hba.hdr_rq = NULL;
+	lpfc_sli4_queue_free(phba->sli4_hba.dat_rq);
+	phba->sli4_hba.dat_rq = NULL;
+
+	/* Release unsolicited receive complete queue */
+	lpfc_sli4_queue_free(phba->sli4_hba.rxq_cq);
+	phba->sli4_hba.rxq_cq = NULL;
+
+	/* Release ELS complete queue */
+	lpfc_sli4_queue_free(phba->sli4_hba.els_cq);
+	phba->sli4_hba.els_cq = NULL;
+
+	/* Release mailbox command complete queue */
+	lpfc_sli4_queue_free(phba->sli4_hba.mbx_cq);
+	phba->sli4_hba.mbx_cq = NULL;
+
+	/* Release FCP response complete queue */
+	for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++)
+		lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_qidx]);
+	kfree(phba->sli4_hba.fcp_cq);
+	phba->sli4_hba.fcp_cq = NULL;
+
+	/* Release fast-path event queue */
+	for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++)
+		lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_qidx]);
+	kfree(phba->sli4_hba.fp_eq);
+	phba->sli4_hba.fp_eq = NULL;
+
+	/* Release slow-path event queue */
+	lpfc_sli4_queue_free(phba->sli4_hba.sp_eq);
+	phba->sli4_hba.sp_eq = NULL;
+
+	return;
+}
+
+/**
+ * lpfc_sli4_queue_setup - Set up all the SLI4 queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up all the SLI4 queues for the FCoE HBA
+ * operation.
+ *
+ * Return codes
+ *      0 - sucessful
+ *      ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+int
+lpfc_sli4_queue_setup(struct lpfc_hba *phba)
+{
+	int rc = -ENOMEM;
+	int fcp_eqidx, fcp_cqidx, fcp_wqidx;
+	int fcp_cq_index = 0;
+
+	/*
+	 * Set up Event Queues (EQs)
+	 */
+
+	/* Set up slow-path event queue */
+	if (!phba->sli4_hba.sp_eq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0520 Slow-path EQ not allocated\n");
+		goto out_error;
+	}
+	rc = lpfc_eq_create(phba, phba->sli4_hba.sp_eq,
+			    LPFC_SP_DEF_IMAX);
+	if (rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0521 Failed setup of slow-path EQ: "
+				"rc = 0x%x\n", rc);
+		goto out_error;
+	}
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"2583 Slow-path EQ setup: queue-id=%d\n",
+			phba->sli4_hba.sp_eq->queue_id);
+
+	/* Set up fast-path event queue */
+	for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) {
+		if (!phba->sli4_hba.fp_eq[fcp_eqidx]) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"0522 Fast-path EQ (%d) not "
+					"allocated\n", fcp_eqidx);
+			goto out_destroy_fp_eq;
+		}
+		rc = lpfc_eq_create(phba, phba->sli4_hba.fp_eq[fcp_eqidx],
+				    phba->cfg_fcp_imax);
+		if (rc) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"0523 Failed setup of fast-path EQ "
+					"(%d), rc = 0x%x\n", fcp_eqidx, rc);
+			goto out_destroy_fp_eq;
+		}
+		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"2584 Fast-path EQ setup: "
+				"queue[%d]-id=%d\n", fcp_eqidx,
+				phba->sli4_hba.fp_eq[fcp_eqidx]->queue_id);
+	}
+
+	/*
+	 * Set up Complete Queues (CQs)
+	 */
+
+	/* Set up slow-path MBOX Complete Queue as the first CQ */
+	if (!phba->sli4_hba.mbx_cq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0528 Mailbox CQ not allocated\n");
+		goto out_destroy_fp_eq;
+	}
+	rc = lpfc_cq_create(phba, phba->sli4_hba.mbx_cq, phba->sli4_hba.sp_eq,
+			    LPFC_MCQ, LPFC_MBOX);
+	if (rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0529 Failed setup of slow-path mailbox CQ: "
+				"rc = 0x%x\n", rc);
+		goto out_destroy_fp_eq;
+	}
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"2585 MBX CQ setup: cq-id=%d, parent eq-id=%d\n",
+			phba->sli4_hba.mbx_cq->queue_id,
+			phba->sli4_hba.sp_eq->queue_id);
+
+	/* Set up slow-path ELS Complete Queue */
+	if (!phba->sli4_hba.els_cq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0530 ELS CQ not allocated\n");
+		goto out_destroy_mbx_cq;
+	}
+	rc = lpfc_cq_create(phba, phba->sli4_hba.els_cq, phba->sli4_hba.sp_eq,
+			    LPFC_WCQ, LPFC_ELS);
+	if (rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0531 Failed setup of slow-path ELS CQ: "
+				"rc = 0x%x\n", rc);
+		goto out_destroy_mbx_cq;
+	}
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"2586 ELS CQ setup: cq-id=%d, parent eq-id=%d\n",
+			phba->sli4_hba.els_cq->queue_id,
+			phba->sli4_hba.sp_eq->queue_id);
+
+	/* Set up slow-path Unsolicited Receive Complete Queue */
+	if (!phba->sli4_hba.rxq_cq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0532 USOL RX CQ not allocated\n");
+		goto out_destroy_els_cq;
+	}
+	rc = lpfc_cq_create(phba, phba->sli4_hba.rxq_cq, phba->sli4_hba.sp_eq,
+			    LPFC_RCQ, LPFC_USOL);
+	if (rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0533 Failed setup of slow-path USOL RX CQ: "
+				"rc = 0x%x\n", rc);
+		goto out_destroy_els_cq;
+	}
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"2587 USL CQ setup: cq-id=%d, parent eq-id=%d\n",
+			phba->sli4_hba.rxq_cq->queue_id,
+			phba->sli4_hba.sp_eq->queue_id);
+
+	/* Set up fast-path FCP Response Complete Queue */
+	for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) {
+		if (!phba->sli4_hba.fcp_cq[fcp_cqidx]) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"0526 Fast-path FCP CQ (%d) not "
+					"allocated\n", fcp_cqidx);
+			goto out_destroy_fcp_cq;
+		}
+		rc = lpfc_cq_create(phba, phba->sli4_hba.fcp_cq[fcp_cqidx],
+				    phba->sli4_hba.fp_eq[fcp_cqidx],
+				    LPFC_WCQ, LPFC_FCP);
+		if (rc) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"0527 Failed setup of fast-path FCP "
+					"CQ (%d), rc = 0x%x\n", fcp_cqidx, rc);
+			goto out_destroy_fcp_cq;
+		}
+		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"2588 FCP CQ setup: cq[%d]-id=%d, "
+				"parent eq[%d]-id=%d\n",
+				fcp_cqidx,
+				phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id,
+				fcp_cqidx,
+				phba->sli4_hba.fp_eq[fcp_cqidx]->queue_id);
+	}
+
+	/*
+	 * Set up all the Work Queues (WQs)
+	 */
+
+	/* Set up Mailbox Command Queue */
+	if (!phba->sli4_hba.mbx_wq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0538 Slow-path MQ not allocated\n");
+		goto out_destroy_fcp_cq;
+	}
+	rc = lpfc_mq_create(phba, phba->sli4_hba.mbx_wq,
+			    phba->sli4_hba.mbx_cq, LPFC_MBOX);
+	if (rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0539 Failed setup of slow-path MQ: "
+				"rc = 0x%x\n", rc);
+		goto out_destroy_fcp_cq;
+	}
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"2589 MBX MQ setup: wq-id=%d, parent cq-id=%d\n",
+			phba->sli4_hba.mbx_wq->queue_id,
+			phba->sli4_hba.mbx_cq->queue_id);
+
+	/* Set up slow-path ELS Work Queue */
+	if (!phba->sli4_hba.els_wq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0536 Slow-path ELS WQ not allocated\n");
+		goto out_destroy_mbx_wq;
+	}
+	rc = lpfc_wq_create(phba, phba->sli4_hba.els_wq,
+			    phba->sli4_hba.els_cq, LPFC_ELS);
+	if (rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0537 Failed setup of slow-path ELS WQ: "
+				"rc = 0x%x\n", rc);
+		goto out_destroy_mbx_wq;
+	}
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"2590 ELS WQ setup: wq-id=%d, parent cq-id=%d\n",
+			phba->sli4_hba.els_wq->queue_id,
+			phba->sli4_hba.els_cq->queue_id);
+
+	/* Set up fast-path FCP Work Queue */
+	for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) {
+		if (!phba->sli4_hba.fcp_wq[fcp_wqidx]) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"0534 Fast-path FCP WQ (%d) not "
+					"allocated\n", fcp_wqidx);
+			goto out_destroy_fcp_wq;
+		}
+		rc = lpfc_wq_create(phba, phba->sli4_hba.fcp_wq[fcp_wqidx],
+				    phba->sli4_hba.fcp_cq[fcp_cq_index],
+				    LPFC_FCP);
+		if (rc) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"0535 Failed setup of fast-path FCP "
+					"WQ (%d), rc = 0x%x\n", fcp_wqidx, rc);
+			goto out_destroy_fcp_wq;
+		}
+		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"2591 FCP WQ setup: wq[%d]-id=%d, "
+				"parent cq[%d]-id=%d\n",
+				fcp_wqidx,
+				phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id,
+				fcp_cq_index,
+				phba->sli4_hba.fcp_cq[fcp_cq_index]->queue_id);
+		/* Round robin FCP Work Queue's Completion Queue assignment */
+		fcp_cq_index = ((fcp_cq_index + 1) % phba->cfg_fcp_eq_count);
+	}
+
+	/*
+	 * Create Receive Queue (RQ)
+	 */
+	if (!phba->sli4_hba.hdr_rq || !phba->sli4_hba.dat_rq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0540 Receive Queue not allocated\n");
+		goto out_destroy_fcp_wq;
+	}
+	rc = lpfc_rq_create(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq,
+			    phba->sli4_hba.rxq_cq, LPFC_USOL);
+	if (rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0541 Failed setup of Receive Queue: "
+				"rc = 0x%x\n", rc);
+		goto out_destroy_fcp_wq;
+	}
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"2592 USL RQ setup: hdr-rq-id=%d, dat-rq-id=%d "
+			"parent cq-id=%d\n",
+			phba->sli4_hba.hdr_rq->queue_id,
+			phba->sli4_hba.dat_rq->queue_id,
+			phba->sli4_hba.rxq_cq->queue_id);
+	return 0;
+
+out_destroy_fcp_wq:
+	for (--fcp_wqidx; fcp_wqidx >= 0; fcp_wqidx--)
+		lpfc_wq_destroy(phba, phba->sli4_hba.fcp_wq[fcp_wqidx]);
+	lpfc_wq_destroy(phba, phba->sli4_hba.els_wq);
+out_destroy_mbx_wq:
+	lpfc_mq_destroy(phba, phba->sli4_hba.mbx_wq);
+out_destroy_fcp_cq:
+	for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--)
+		lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_cqidx]);
+	lpfc_cq_destroy(phba, phba->sli4_hba.rxq_cq);
+out_destroy_els_cq:
+	lpfc_cq_destroy(phba, phba->sli4_hba.els_cq);
+out_destroy_mbx_cq:
+	lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq);
+out_destroy_fp_eq:
+	for (--fcp_eqidx; fcp_eqidx >= 0; fcp_eqidx--)
+		lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_eqidx]);
+	lpfc_eq_destroy(phba, phba->sli4_hba.sp_eq);
+out_error:
+	return rc;
+}
+
+/**
+ * lpfc_sli4_queue_unset - Unset all the SLI4 queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset all the SLI4 queues with the FCoE HBA
+ * operation.
+ *
+ * Return codes
+ *      0 - sucessful
+ *      ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+void
+lpfc_sli4_queue_unset(struct lpfc_hba *phba)
+{
+	int fcp_qidx;
+
+	/* Unset mailbox command work queue */
+	lpfc_mq_destroy(phba, phba->sli4_hba.mbx_wq);
+	/* Unset ELS work queue */
+	lpfc_wq_destroy(phba, phba->sli4_hba.els_wq);
+	/* Unset unsolicited receive queue */
+	lpfc_rq_destroy(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq);
+	/* Unset FCP work queue */
+	for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++)
+		lpfc_wq_destroy(phba, phba->sli4_hba.fcp_wq[fcp_qidx]);
+	/* Unset mailbox command complete queue */
+	lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq);
+	/* Unset ELS complete queue */
+	lpfc_cq_destroy(phba, phba->sli4_hba.els_cq);
+	/* Unset unsolicited receive complete queue */
+	lpfc_cq_destroy(phba, phba->sli4_hba.rxq_cq);
+	/* Unset FCP response complete queue */
+	for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++)
+		lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_qidx]);
+	/* Unset fast-path event queue */
+	for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++)
+		lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_qidx]);
+	/* Unset slow-path event queue */
+	lpfc_eq_destroy(phba, phba->sli4_hba.sp_eq);
+}
+
+/**
+ * lpfc_sli4_cq_event_pool_create - Create completion-queue event free pool
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to allocate and set up a pool of completion queue
+ * events. The body of the completion queue event is a completion queue entry
+ * CQE. For now, this pool is used for the interrupt service routine to queue
+ * the following HBA completion queue events for the worker thread to process:
+ *   - Mailbox asynchronous events
+ *   - Receive queue completion unsolicited events
+ * Later, this can be used for all the slow-path events.
+ *
+ * Return codes
+ *      0 - sucessful
+ *      -ENOMEM - No availble memory
+ **/
+static int
+lpfc_sli4_cq_event_pool_create(struct lpfc_hba *phba)
+{
+	struct lpfc_cq_event *cq_event;
+	int i;
+
+	for (i = 0; i < (4 * phba->sli4_hba.cq_ecount); i++) {
+		cq_event = kmalloc(sizeof(struct lpfc_cq_event), GFP_KERNEL);
+		if (!cq_event)
+			goto out_pool_create_fail;
+		list_add_tail(&cq_event->list,
+			      &phba->sli4_hba.sp_cqe_event_pool);
+	}
+	return 0;
+
+out_pool_create_fail:
+	lpfc_sli4_cq_event_pool_destroy(phba);
+	return -ENOMEM;
+}
+
+/**
+ * lpfc_sli4_cq_event_pool_destroy - Free completion-queue event free pool
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to free the pool of completion queue events at
+ * driver unload time. Note that, it is the responsibility of the driver
+ * cleanup routine to free all the outstanding completion-queue events
+ * allocated from this pool back into the pool before invoking this routine
+ * to destroy the pool.
+ **/
+static void
+lpfc_sli4_cq_event_pool_destroy(struct lpfc_hba *phba)
+{
+	struct lpfc_cq_event *cq_event, *next_cq_event;
+
+	list_for_each_entry_safe(cq_event, next_cq_event,
+				 &phba->sli4_hba.sp_cqe_event_pool, list) {
+		list_del(&cq_event->list);
+		kfree(cq_event);
+	}
+}
+
+/**
+ * __lpfc_sli4_cq_event_alloc - Allocate a completion-queue event from free pool
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is the lock free version of the API invoked to allocate a
+ * completion-queue event from the free pool.
+ *
+ * Return: Pointer to the newly allocated completion-queue event if successful
+ *         NULL otherwise.
+ **/
+struct lpfc_cq_event *
+__lpfc_sli4_cq_event_alloc(struct lpfc_hba *phba)
+{
+	struct lpfc_cq_event *cq_event = NULL;
+
+	list_remove_head(&phba->sli4_hba.sp_cqe_event_pool, cq_event,
+			 struct lpfc_cq_event, list);
+	return cq_event;
+}
+
+/**
+ * lpfc_sli4_cq_event_alloc - Allocate a completion-queue event from free pool
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is the lock version of the API invoked to allocate a
+ * completion-queue event from the free pool.
+ *
+ * Return: Pointer to the newly allocated completion-queue event if successful
+ *         NULL otherwise.
+ **/
+struct lpfc_cq_event *
+lpfc_sli4_cq_event_alloc(struct lpfc_hba *phba)
+{
+	struct lpfc_cq_event *cq_event;
+	unsigned long iflags;
+
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	cq_event = __lpfc_sli4_cq_event_alloc(phba);
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+	return cq_event;
+}
+
+/**
+ * __lpfc_sli4_cq_event_release - Release a completion-queue event to free pool
+ * @phba: pointer to lpfc hba data structure.
+ * @cq_event: pointer to the completion queue event to be freed.
+ *
+ * This routine is the lock free version of the API invoked to release a
+ * completion-queue event back into the free pool.
+ **/
+void
+__lpfc_sli4_cq_event_release(struct lpfc_hba *phba,
+			     struct lpfc_cq_event *cq_event)
+{
+	list_add_tail(&cq_event->list, &phba->sli4_hba.sp_cqe_event_pool);
+}
+
+/**
+ * lpfc_sli4_cq_event_release - Release a completion-queue event to free pool
+ * @phba: pointer to lpfc hba data structure.
+ * @cq_event: pointer to the completion queue event to be freed.
+ *
+ * This routine is the lock version of the API invoked to release a
+ * completion-queue event back into the free pool.
+ **/
+void
+lpfc_sli4_cq_event_release(struct lpfc_hba *phba,
+			   struct lpfc_cq_event *cq_event)
+{
+	unsigned long iflags;
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	__lpfc_sli4_cq_event_release(phba, cq_event);
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+}
+
+/**
+ * lpfc_sli4_cq_event_release_all - Release all cq events to the free pool
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is to free all the pending completion-queue events to the
+ * back into the free pool for device reset.
+ **/
+static void
+lpfc_sli4_cq_event_release_all(struct lpfc_hba *phba)
+{
+	LIST_HEAD(cqelist);
+	struct lpfc_cq_event *cqe;
+	unsigned long iflags;
+
+	/* Retrieve all the pending WCQEs from pending WCQE lists */
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	/* Pending FCP XRI abort events */
+	list_splice_init(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue,
+			 &cqelist);
+	/* Pending ELS XRI abort events */
+	list_splice_init(&phba->sli4_hba.sp_els_xri_aborted_work_queue,
+			 &cqelist);
+	/* Pending asynnc events */
+	list_splice_init(&phba->sli4_hba.sp_asynce_work_queue,
+			 &cqelist);
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+	while (!list_empty(&cqelist)) {
+		list_remove_head(&cqelist, cqe, struct lpfc_cq_event, list);
+		lpfc_sli4_cq_event_release(phba, cqe);
+	}
+}
+
+/**
+ * lpfc_pci_function_reset - Reset pci function.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to request a PCI function reset. It will destroys
+ * all resources assigned to the PCI function which originates this request.
+ *
+ * Return codes
+ *      0 - sucessful
+ *      ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+int
+lpfc_pci_function_reset(struct lpfc_hba *phba)
+{
+	LPFC_MBOXQ_t *mboxq;
+	uint32_t rc = 0;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mboxq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0494 Unable to allocate memory for issuing "
+				"SLI_FUNCTION_RESET mailbox command\n");
+		return -ENOMEM;
+	}
+
+	/* Set up PCI function reset SLI4_CONFIG mailbox-ioctl command */
+	lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
+			 LPFC_MBOX_OPCODE_FUNCTION_RESET, 0,
+			 LPFC_SLI4_MBX_EMBED);
+	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+	shdr = (union lpfc_sli4_cfg_shdr *)
+		&mboxq->u.mqe.un.sli4_config.header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mboxq, phba->mbox_mem_pool);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0495 SLI_FUNCTION_RESET mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		rc = -ENXIO;
+	}
+	return rc;
+}
+
+/**
+ * lpfc_sli4_send_nop_mbox_cmds - Send sli-4 nop mailbox commands
+ * @phba: pointer to lpfc hba data structure.
+ * @cnt: number of nop mailbox commands to send.
+ *
+ * This routine is invoked to send a number @cnt of NOP mailbox command and
+ * wait for each command to complete.
+ *
+ * Return: the number of NOP mailbox command completed.
+ **/
+static int
+lpfc_sli4_send_nop_mbox_cmds(struct lpfc_hba *phba, uint32_t cnt)
+{
+	LPFC_MBOXQ_t *mboxq;
+	int length, cmdsent;
+	uint32_t mbox_tmo;
+	uint32_t rc = 0;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	if (cnt == 0) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"2518 Requested to send 0 NOP mailbox cmd\n");
+		return cnt;
+	}
+
+	mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mboxq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2519 Unable to allocate memory for issuing "
+				"NOP mailbox command\n");
+		return 0;
+	}
+
+	/* Set up NOP SLI4_CONFIG mailbox-ioctl command */
+	length = (sizeof(struct lpfc_mbx_nop) -
+		  sizeof(struct lpfc_sli4_cfg_mhdr));
+	lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
+			 LPFC_MBOX_OPCODE_NOP, length, LPFC_SLI4_MBX_EMBED);
+
+	mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+	for (cmdsent = 0; cmdsent < cnt; cmdsent++) {
+		if (!phba->sli4_hba.intr_enable)
+			rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+		else
+			rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
+		if (rc == MBX_TIMEOUT)
+			break;
+		/* Check return status */
+		shdr = (union lpfc_sli4_cfg_shdr *)
+			&mboxq->u.mqe.un.sli4_config.header.cfg_shdr;
+		shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+		shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
+					 &shdr->response);
+		if (shdr_status || shdr_add_status || rc) {
+			lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+					"2520 NOP mailbox command failed "
+					"status x%x add_status x%x mbx "
+					"status x%x\n", shdr_status,
+					shdr_add_status, rc);
+			break;
+		}
+	}
+
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mboxq, phba->mbox_mem_pool);
+
+	return cmdsent;
+}
+
+/**
+ * lpfc_sli4_fcfi_unreg - Unregister fcfi to device
+ * @phba: pointer to lpfc hba data structure.
+ * @fcfi: fcf index.
+ *
+ * This routine is invoked to unregister a FCFI from device.
+ **/
+void
+lpfc_sli4_fcfi_unreg(struct lpfc_hba *phba, uint16_t fcfi)
+{
+	LPFC_MBOXQ_t *mbox;
+	uint32_t mbox_tmo;
+	int rc;
+	unsigned long flags;
+
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+
+	if (!mbox)
+		return;
+
+	lpfc_unreg_fcfi(mbox, fcfi);
+
+	if (!phba->sli4_hba.intr_enable)
+		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+	else {
+		mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+		rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+	}
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mbox, phba->mbox_mem_pool);
+	if (rc != MBX_SUCCESS)
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2517 Unregister FCFI command failed "
+				"status %d, mbxStatus x%x\n", rc,
+				bf_get(lpfc_mqe_status, &mbox->u.mqe));
+	else {
+		spin_lock_irqsave(&phba->hbalock, flags);
+		/* Mark the FCFI is no longer registered */
+		phba->fcf.fcf_flag &=
+			~(FCF_AVAILABLE | FCF_REGISTERED | FCF_DISCOVERED);
+		spin_unlock_irqrestore(&phba->hbalock, flags);
+	}
+}
+
+/**
+ * lpfc_sli4_pci_mem_setup - Setup SLI4 HBA PCI memory space.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up the PCI device memory space for device
+ * with SLI-4 interface spec.
+ *
+ * Return codes
+ * 	0 - sucessful
+ * 	other values - error
+ **/
+static int
+lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
+{
+	struct pci_dev *pdev;
+	unsigned long bar0map_len, bar1map_len, bar2map_len;
+	int error = -ENODEV;
+
+	/* Obtain PCI device reference */
+	if (!phba->pcidev)
+		return error;
+	else
+		pdev = phba->pcidev;
+
+	/* Set the device DMA mask size */
+	if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)
+		if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
+			return error;
+
+	/* Get the bus address of SLI4 device Bar0, Bar1, and Bar2 and the
+	 * number of bytes required by each mapping. They are actually
+	 * mapping to the PCI BAR regions 1, 2, and 4 by the SLI4 device.
+	 */
+	phba->pci_bar0_map = pci_resource_start(pdev, LPFC_SLI4_BAR0);
+	bar0map_len = pci_resource_len(pdev, LPFC_SLI4_BAR0);
+
+	phba->pci_bar1_map = pci_resource_start(pdev, LPFC_SLI4_BAR1);
+	bar1map_len = pci_resource_len(pdev, LPFC_SLI4_BAR1);
+
+	phba->pci_bar2_map = pci_resource_start(pdev, LPFC_SLI4_BAR2);
+	bar2map_len = pci_resource_len(pdev, LPFC_SLI4_BAR2);
+
+	/* Map SLI4 PCI Config Space Register base to a kernel virtual addr */
+	phba->sli4_hba.conf_regs_memmap_p =
+				ioremap(phba->pci_bar0_map, bar0map_len);
+	if (!phba->sli4_hba.conf_regs_memmap_p) {
+		dev_printk(KERN_ERR, &pdev->dev,
+			   "ioremap failed for SLI4 PCI config registers.\n");
+		goto out;
+	}
+
+	/* Map SLI4 HBA Control Register base to a kernel virtual address. */
+	phba->sli4_hba.ctrl_regs_memmap_p =
+				ioremap(phba->pci_bar1_map, bar1map_len);
+	if (!phba->sli4_hba.ctrl_regs_memmap_p) {
+		dev_printk(KERN_ERR, &pdev->dev,
+			   "ioremap failed for SLI4 HBA control registers.\n");
+		goto out_iounmap_conf;
+	}
+
+	/* Map SLI4 HBA Doorbell Register base to a kernel virtual address. */
+	phba->sli4_hba.drbl_regs_memmap_p =
+				ioremap(phba->pci_bar2_map, bar2map_len);
+	if (!phba->sli4_hba.drbl_regs_memmap_p) {
+		dev_printk(KERN_ERR, &pdev->dev,
+			   "ioremap failed for SLI4 HBA doorbell registers.\n");
+		goto out_iounmap_ctrl;
+	}
+
+	/* Set up BAR0 PCI config space register memory map */
+	lpfc_sli4_bar0_register_memmap(phba);
+
+	/* Set up BAR1 register memory map */
+	lpfc_sli4_bar1_register_memmap(phba);
+
+	/* Set up BAR2 register memory map */
+	error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0);
+	if (error)
+		goto out_iounmap_all;
+
+	return 0;
+
+out_iounmap_all:
+	iounmap(phba->sli4_hba.drbl_regs_memmap_p);
+out_iounmap_ctrl:
+	iounmap(phba->sli4_hba.ctrl_regs_memmap_p);
+out_iounmap_conf:
+	iounmap(phba->sli4_hba.conf_regs_memmap_p);
+out:
+	return error;
+}
+
+/**
+ * lpfc_sli4_pci_mem_unset - Unset SLI4 HBA PCI memory space.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset the PCI device memory space for device
+ * with SLI-4 interface spec.
+ **/
+static void
+lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba)
+{
+	struct pci_dev *pdev;
+
+	/* Obtain PCI device reference */
+	if (!phba->pcidev)
+		return;
+	else
+		pdev = phba->pcidev;
+
+	/* Free coherent DMA memory allocated */
+
+	/* Unmap I/O memory space */
+	iounmap(phba->sli4_hba.drbl_regs_memmap_p);
+	iounmap(phba->sli4_hba.ctrl_regs_memmap_p);
+	iounmap(phba->sli4_hba.conf_regs_memmap_p);
+
+	return;
+}
+
+/**
+ * lpfc_sli_enable_msix - Enable MSI-X interrupt mode on SLI-3 device
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to enable the MSI-X interrupt vectors to device
+ * with SLI-3 interface specs. The kernel function pci_enable_msix() is
+ * called to enable the MSI-X vectors. Note that pci_enable_msix(), once
+ * invoked, enables either all or nothing, depending on the current
+ * availability of PCI vector resources. The device driver is responsible
+ * for calling the individual request_irq() to register each MSI-X vector
+ * with a interrupt handler, which is done in this function. Note that
  * later when device is unloading, the driver should always call free_irq()
  * on all MSI-X vectors it has done request_irq() on before calling
  * pci_disable_msix(). Failure to do so results in a BUG_ON() and a device
@@ -2333,7 +6029,7 @@
  *   other values - error
  **/
 static int
-lpfc_enable_msix(struct lpfc_hba *phba)
+lpfc_sli_enable_msix(struct lpfc_hba *phba)
 {
 	int rc, i;
 	LPFC_MBOXQ_t *pmb;
@@ -2349,20 +6045,21 @@
 		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
 				"0420 PCI enable MSI-X failed (%d)\n", rc);
 		goto msi_fail_out;
-	} else
-		for (i = 0; i < LPFC_MSIX_VECTORS; i++)
-			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-					"0477 MSI-X entry[%d]: vector=x%x "
-					"message=%d\n", i,
-					phba->msix_entries[i].vector,
-					phba->msix_entries[i].entry);
+	}
+	for (i = 0; i < LPFC_MSIX_VECTORS; i++)
+		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"0477 MSI-X entry[%d]: vector=x%x "
+				"message=%d\n", i,
+				phba->msix_entries[i].vector,
+				phba->msix_entries[i].entry);
 	/*
 	 * Assign MSI-X vectors to interrupt handlers
 	 */
 
 	/* vector-0 is associated to slow-path handler */
-	rc = request_irq(phba->msix_entries[0].vector, &lpfc_sp_intr_handler,
-			 IRQF_SHARED, LPFC_SP_DRIVER_HANDLER_NAME, phba);
+	rc = request_irq(phba->msix_entries[0].vector,
+			 &lpfc_sli_sp_intr_handler, IRQF_SHARED,
+			 LPFC_SP_DRIVER_HANDLER_NAME, phba);
 	if (rc) {
 		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
 				"0421 MSI-X slow-path request_irq failed "
@@ -2371,8 +6068,9 @@
 	}
 
 	/* vector-1 is associated to fast-path handler */
-	rc = request_irq(phba->msix_entries[1].vector, &lpfc_fp_intr_handler,
-			 IRQF_SHARED, LPFC_FP_DRIVER_HANDLER_NAME, phba);
+	rc = request_irq(phba->msix_entries[1].vector,
+			 &lpfc_sli_fp_intr_handler, IRQF_SHARED,
+			 LPFC_FP_DRIVER_HANDLER_NAME, phba);
 
 	if (rc) {
 		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
@@ -2401,7 +6099,7 @@
 		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
 				"0351 Config MSI mailbox command failed, "
 				"mbxCmd x%x, mbxStatus x%x\n",
-				pmb->mb.mbxCommand, pmb->mb.mbxStatus);
+				pmb->u.mb.mbxCommand, pmb->u.mb.mbxStatus);
 		goto mbx_fail_out;
 	}
 
@@ -2428,14 +6126,14 @@
 }
 
 /**
- * lpfc_disable_msix - Disable MSI-X interrupt mode
+ * lpfc_sli_disable_msix - Disable MSI-X interrupt mode on SLI-3 device.
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to release the MSI-X vectors and then disable the
- * MSI-X interrupt mode.
+ * MSI-X interrupt mode to device with SLI-3 interface spec.
  **/
 static void
-lpfc_disable_msix(struct lpfc_hba *phba)
+lpfc_sli_disable_msix(struct lpfc_hba *phba)
 {
 	int i;
 
@@ -2444,23 +6142,26 @@
 		free_irq(phba->msix_entries[i].vector, phba);
 	/* Disable MSI-X */
 	pci_disable_msix(phba->pcidev);
+
+	return;
 }
 
 /**
- * lpfc_enable_msi - Enable MSI interrupt mode
+ * lpfc_sli_enable_msi - Enable MSI interrupt mode on SLI-3 device.
  * @phba: pointer to lpfc hba data structure.
  *
- * This routine is invoked to enable the MSI interrupt mode. The kernel
- * function pci_enable_msi() is called to enable the MSI vector. The
- * device driver is responsible for calling the request_irq() to register
- * MSI vector with a interrupt the handler, which is done in this function.
+ * This routine is invoked to enable the MSI interrupt mode to device with
+ * SLI-3 interface spec. The kernel function pci_enable_msi() is called to
+ * enable the MSI vector. The device driver is responsible for calling the
+ * request_irq() to register MSI vector with a interrupt the handler, which
+ * is done in this function.
  *
  * Return codes
  * 	0 - sucessful
  * 	other values - error
  */
 static int
-lpfc_enable_msi(struct lpfc_hba *phba)
+lpfc_sli_enable_msi(struct lpfc_hba *phba)
 {
 	int rc;
 
@@ -2474,7 +6175,7 @@
 		return rc;
 	}
 
-	rc = request_irq(phba->pcidev->irq, lpfc_intr_handler,
+	rc = request_irq(phba->pcidev->irq, lpfc_sli_intr_handler,
 			 IRQF_SHARED, LPFC_DRIVER_NAME, phba);
 	if (rc) {
 		pci_disable_msi(phba->pcidev);
@@ -2485,17 +6186,17 @@
 }
 
 /**
- * lpfc_disable_msi - Disable MSI interrupt mode
+ * lpfc_sli_disable_msi - Disable MSI interrupt mode to SLI-3 device.
  * @phba: pointer to lpfc hba data structure.
  *
- * This routine is invoked to disable the MSI interrupt mode. The driver
- * calls free_irq() on MSI vector it has done request_irq() on before
- * calling pci_disable_msi(). Failure to do so results in a BUG_ON() and
- * a device will be left with MSI enabled and leaks its vector.
+ * This routine is invoked to disable the MSI interrupt mode to device with
+ * SLI-3 interface spec. The driver calls free_irq() on MSI vector it has
+ * done request_irq() on before calling pci_disable_msi(). Failure to do so
+ * results in a BUG_ON() and a device will be left with MSI enabled and leaks
+ * its vector.
  */
-
 static void
-lpfc_disable_msi(struct lpfc_hba *phba)
+lpfc_sli_disable_msi(struct lpfc_hba *phba)
 {
 	free_irq(phba->pcidev->irq, phba);
 	pci_disable_msi(phba->pcidev);
@@ -2503,80 +6204,33 @@
 }
 
 /**
- * lpfc_log_intr_mode - Log the active interrupt mode
- * @phba: pointer to lpfc hba data structure.
- * @intr_mode: active interrupt mode adopted.
- *
- * This routine it invoked to log the currently used active interrupt mode
- * to the device.
- */
-static void
-lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode)
-{
-	switch (intr_mode) {
-	case 0:
-		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-				"0470 Enable INTx interrupt mode.\n");
-		break;
-	case 1:
-		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-				"0481 Enabled MSI interrupt mode.\n");
-		break;
-	case 2:
-		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-				"0480 Enabled MSI-X interrupt mode.\n");
-		break;
-	default:
-		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"0482 Illegal interrupt mode.\n");
-		break;
-	}
-	return;
-}
-
-static void
-lpfc_stop_port(struct lpfc_hba *phba)
-{
-	/* Clear all interrupt enable conditions */
-	writel(0, phba->HCregaddr);
-	readl(phba->HCregaddr); /* flush */
-	/* Clear all pending interrupts */
-	writel(0xffffffff, phba->HAregaddr);
-	readl(phba->HAregaddr); /* flush */
-
-	/* Reset some HBA SLI setup states */
-	lpfc_stop_phba_timers(phba);
-	phba->pport->work_port_events = 0;
-
-	return;
-}
-
-/**
- * lpfc_enable_intr - Enable device interrupt
+ * lpfc_sli_enable_intr - Enable device interrupt to SLI-3 device.
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to enable device interrupt and associate driver's
- * interrupt handler(s) to interrupt vector(s). Depends on the interrupt
- * mode configured to the driver, the driver will try to fallback from the
- * configured interrupt mode to an interrupt mode which is supported by the
- * platform, kernel, and device in the order of: MSI-X -> MSI -> IRQ.
+ * interrupt handler(s) to interrupt vector(s) to device with SLI-3 interface
+ * spec. Depends on the interrupt mode configured to the driver, the driver
+ * will try to fallback from the configured interrupt mode to an interrupt
+ * mode which is supported by the platform, kernel, and device in the order
+ * of:
+ * MSI-X -> MSI -> IRQ.
  *
  * Return codes
  *   0 - sucessful
  *   other values - error
  **/
 static uint32_t
-lpfc_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
+lpfc_sli_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
 {
 	uint32_t intr_mode = LPFC_INTR_ERROR;
 	int retval;
 
 	if (cfg_mode == 2) {
 		/* Need to issue conf_port mbox cmd before conf_msi mbox cmd */
-		retval = lpfc_sli_config_port(phba, 3);
+		retval = lpfc_sli_config_port(phba, LPFC_SLI_REV3);
 		if (!retval) {
 			/* Now, try to enable MSI-X interrupt mode */
-			retval = lpfc_enable_msix(phba);
+			retval = lpfc_sli_enable_msix(phba);
 			if (!retval) {
 				/* Indicate initialization to MSI-X mode */
 				phba->intr_type = MSIX;
@@ -2587,7 +6241,7 @@
 
 	/* Fallback to MSI if MSI-X initialization failed */
 	if (cfg_mode >= 1 && phba->intr_type == NONE) {
-		retval = lpfc_enable_msi(phba);
+		retval = lpfc_sli_enable_msi(phba);
 		if (!retval) {
 			/* Indicate initialization to MSI mode */
 			phba->intr_type = MSI;
@@ -2597,7 +6251,7 @@
 
 	/* Fallback to INTx if both MSI-X/MSI initalization failed */
 	if (phba->intr_type == NONE) {
-		retval = request_irq(phba->pcidev->irq, lpfc_intr_handler,
+		retval = request_irq(phba->pcidev->irq, lpfc_sli_intr_handler,
 				     IRQF_SHARED, LPFC_DRIVER_NAME, phba);
 		if (!retval) {
 			/* Indicate initialization to INTx mode */
@@ -2609,22 +6263,22 @@
 }
 
 /**
- * lpfc_disable_intr - Disable device interrupt
+ * lpfc_sli_disable_intr - Disable device interrupt to SLI-3 device.
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to disable device interrupt and disassociate the
- * driver's interrupt handler(s) from interrupt vector(s). Depending on the
- * interrupt mode, the driver will release the interrupt vector(s) for the
- * message signaled interrupt.
+ * driver's interrupt handler(s) from interrupt vector(s) to device with
+ * SLI-3 interface spec. Depending on the interrupt mode, the driver will
+ * release the interrupt vector(s) for the message signaled interrupt.
  **/
 static void
-lpfc_disable_intr(struct lpfc_hba *phba)
+lpfc_sli_disable_intr(struct lpfc_hba *phba)
 {
 	/* Disable the currently initialized interrupt mode */
 	if (phba->intr_type == MSIX)
-		lpfc_disable_msix(phba);
+		lpfc_sli_disable_msix(phba);
 	else if (phba->intr_type == MSI)
-		lpfc_disable_msi(phba);
+		lpfc_sli_disable_msi(phba);
 	else if (phba->intr_type == INTx)
 		free_irq(phba->pcidev->irq, phba);
 
@@ -2636,263 +6290,503 @@
 }
 
 /**
- * lpfc_pci_probe_one - lpfc PCI probe func to register device to PCI subsystem
- * @pdev: pointer to PCI device
- * @pid: pointer to PCI device identifier
+ * lpfc_sli4_enable_msix - Enable MSI-X interrupt mode to SLI-4 device
+ * @phba: pointer to lpfc hba data structure.
  *
- * This routine is to be registered to the kernel's PCI subsystem. When an
- * Emulex HBA is presented in PCI bus, the kernel PCI subsystem looks at
- * PCI device-specific information of the device and driver to see if the
- * driver state that it can support this kind of device. If the match is
- * successful, the driver core invokes this routine. If this routine
- * determines it can claim the HBA, it does all the initialization that it
- * needs to do to handle the HBA properly.
+ * This routine is invoked to enable the MSI-X interrupt vectors to device
+ * with SLI-4 interface spec. The kernel function pci_enable_msix() is called
+ * to enable the MSI-X vectors. Note that pci_enable_msix(), once invoked,
+ * enables either all or nothing, depending on the current availability of
+ * PCI vector resources. The device driver is responsible for calling the
+ * individual request_irq() to register each MSI-X vector with a interrupt
+ * handler, which is done in this function. Note that later when device is
+ * unloading, the driver should always call free_irq() on all MSI-X vectors
+ * it has done request_irq() on before calling pci_disable_msix(). Failure
+ * to do so results in a BUG_ON() and a device will be left with MSI-X
+ * enabled and leaks its vectors.
  *
- * Return code
- *   0 - driver can claim the device
- *   negative value - driver can not claim the device
+ * Return codes
+ * 0 - sucessful
+ * other values - error
  **/
-static int __devinit
-lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
+static int
+lpfc_sli4_enable_msix(struct lpfc_hba *phba)
 {
-	struct lpfc_vport *vport = NULL;
-	struct lpfc_hba   *phba;
-	struct lpfc_sli   *psli;
-	struct lpfc_iocbq *iocbq_entry = NULL, *iocbq_next = NULL;
-	struct Scsi_Host  *shost = NULL;
-	void *ptr;
-	unsigned long bar0map_len, bar2map_len;
-	int error = -ENODEV, retval;
-	int  i, hbq_count;
-	uint16_t iotag;
-	uint32_t cfg_mode, intr_mode;
-	int bars = pci_select_bars(pdev, IORESOURCE_MEM);
-	struct lpfc_adapter_event_header adapter_event;
+	int rc, index;
 
-	if (pci_enable_device_mem(pdev))
-		goto out;
-	if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME))
-		goto out_disable_device;
+	/* Set up MSI-X multi-message vectors */
+	for (index = 0; index < phba->sli4_hba.cfg_eqn; index++)
+		phba->sli4_hba.msix_entries[index].entry = index;
 
-	phba = kzalloc(sizeof (struct lpfc_hba), GFP_KERNEL);
-	if (!phba)
-		goto out_release_regions;
-
-	atomic_set(&phba->fast_event_count, 0);
-	spin_lock_init(&phba->hbalock);
-
-	/* Initialize ndlp management spinlock */
-	spin_lock_init(&phba->ndlp_lock);
-
-	phba->pcidev = pdev;
-
-	/* Assign an unused board number */
-	if ((phba->brd_no = lpfc_get_instance()) < 0)
-		goto out_free_phba;
-
-	INIT_LIST_HEAD(&phba->port_list);
-	init_waitqueue_head(&phba->wait_4_mlo_m_q);
+	/* Configure MSI-X capability structure */
+	rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries,
+			     phba->sli4_hba.cfg_eqn);
+	if (rc) {
+		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"0484 PCI enable MSI-X failed (%d)\n", rc);
+		goto msi_fail_out;
+	}
+	/* Log MSI-X vector assignment */
+	for (index = 0; index < phba->sli4_hba.cfg_eqn; index++)
+		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"0489 MSI-X entry[%d]: vector=x%x "
+				"message=%d\n", index,
+				phba->sli4_hba.msix_entries[index].vector,
+				phba->sli4_hba.msix_entries[index].entry);
 	/*
-	 * Get all the module params for configuring this host and then
-	 * establish the host.
+	 * Assign MSI-X vectors to interrupt handlers
 	 */
-	lpfc_get_cfgparam(phba);
-	phba->max_vpi = LPFC_MAX_VPI;
 
-	/* Initialize timers used by driver */
-	init_timer(&phba->hb_tmofunc);
-	phba->hb_tmofunc.function = lpfc_hb_timeout;
-	phba->hb_tmofunc.data = (unsigned long)phba;
+	/* The first vector must associated to slow-path handler for MQ */
+	rc = request_irq(phba->sli4_hba.msix_entries[0].vector,
+			 &lpfc_sli4_sp_intr_handler, IRQF_SHARED,
+			 LPFC_SP_DRIVER_HANDLER_NAME, phba);
+	if (rc) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"0485 MSI-X slow-path request_irq failed "
+				"(%d)\n", rc);
+		goto msi_fail_out;
+	}
 
-	psli = &phba->sli;
-	init_timer(&psli->mbox_tmo);
-	psli->mbox_tmo.function = lpfc_mbox_timeout;
-	psli->mbox_tmo.data = (unsigned long) phba;
-	init_timer(&phba->fcp_poll_timer);
-	phba->fcp_poll_timer.function = lpfc_poll_timeout;
-	phba->fcp_poll_timer.data = (unsigned long) phba;
-	init_timer(&phba->fabric_block_timer);
-	phba->fabric_block_timer.function = lpfc_fabric_block_timeout;
-	phba->fabric_block_timer.data = (unsigned long) phba;
-	init_timer(&phba->eratt_poll);
-	phba->eratt_poll.function = lpfc_poll_eratt;
-	phba->eratt_poll.data = (unsigned long) phba;
+	/* The rest of the vector(s) are associated to fast-path handler(s) */
+	for (index = 1; index < phba->sli4_hba.cfg_eqn; index++) {
+		phba->sli4_hba.fcp_eq_hdl[index - 1].idx = index - 1;
+		phba->sli4_hba.fcp_eq_hdl[index - 1].phba = phba;
+		rc = request_irq(phba->sli4_hba.msix_entries[index].vector,
+				 &lpfc_sli4_fp_intr_handler, IRQF_SHARED,
+				 LPFC_FP_DRIVER_HANDLER_NAME,
+				 &phba->sli4_hba.fcp_eq_hdl[index - 1]);
+		if (rc) {
+			lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+					"0486 MSI-X fast-path (%d) "
+					"request_irq failed (%d)\n", index, rc);
+			goto cfg_fail_out;
+		}
+	}
 
-	pci_set_master(pdev);
-	pci_save_state(pdev);
-	pci_try_set_mwi(pdev);
+	return rc;
 
-	if (pci_set_dma_mask(phba->pcidev, DMA_BIT_MASK(64)) != 0)
-		if (pci_set_dma_mask(phba->pcidev, DMA_BIT_MASK(32)) != 0)
-			goto out_idr_remove;
+cfg_fail_out:
+	/* free the irq already requested */
+	for (--index; index >= 1; index--)
+		free_irq(phba->sli4_hba.msix_entries[index - 1].vector,
+			 &phba->sli4_hba.fcp_eq_hdl[index - 1]);
+
+	/* free the irq already requested */
+	free_irq(phba->sli4_hba.msix_entries[0].vector, phba);
+
+msi_fail_out:
+	/* Unconfigure MSI-X capability structure */
+	pci_disable_msix(phba->pcidev);
+	return rc;
+}
+
+/**
+ * lpfc_sli4_disable_msix - Disable MSI-X interrupt mode to SLI-4 device
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release the MSI-X vectors and then disable the
+ * MSI-X interrupt mode to device with SLI-4 interface spec.
+ **/
+static void
+lpfc_sli4_disable_msix(struct lpfc_hba *phba)
+{
+	int index;
+
+	/* Free up MSI-X multi-message vectors */
+	free_irq(phba->sli4_hba.msix_entries[0].vector, phba);
+
+	for (index = 1; index < phba->sli4_hba.cfg_eqn; index++)
+		free_irq(phba->sli4_hba.msix_entries[index].vector,
+			 &phba->sli4_hba.fcp_eq_hdl[index - 1]);
+	/* Disable MSI-X */
+	pci_disable_msix(phba->pcidev);
+
+	return;
+}
+
+/**
+ * lpfc_sli4_enable_msi - Enable MSI interrupt mode to SLI-4 device
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to enable the MSI interrupt mode to device with
+ * SLI-4 interface spec. The kernel function pci_enable_msi() is called
+ * to enable the MSI vector. The device driver is responsible for calling
+ * the request_irq() to register MSI vector with a interrupt the handler,
+ * which is done in this function.
+ *
+ * Return codes
+ * 	0 - sucessful
+ * 	other values - error
+ **/
+static int
+lpfc_sli4_enable_msi(struct lpfc_hba *phba)
+{
+	int rc, index;
+
+	rc = pci_enable_msi(phba->pcidev);
+	if (!rc)
+		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"0487 PCI enable MSI mode success.\n");
+	else {
+		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"0488 PCI enable MSI mode failed (%d)\n", rc);
+		return rc;
+	}
+
+	rc = request_irq(phba->pcidev->irq, lpfc_sli4_intr_handler,
+			 IRQF_SHARED, LPFC_DRIVER_NAME, phba);
+	if (rc) {
+		pci_disable_msi(phba->pcidev);
+		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"0490 MSI request_irq failed (%d)\n", rc);
+	}
+
+	for (index = 0; index < phba->cfg_fcp_eq_count; index++) {
+		phba->sli4_hba.fcp_eq_hdl[index].idx = index;
+		phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
+	}
+
+	return rc;
+}
+
+/**
+ * lpfc_sli4_disable_msi - Disable MSI interrupt mode to SLI-4 device
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to disable the MSI interrupt mode to device with
+ * SLI-4 interface spec. The driver calls free_irq() on MSI vector it has
+ * done request_irq() on before calling pci_disable_msi(). Failure to do so
+ * results in a BUG_ON() and a device will be left with MSI enabled and leaks
+ * its vector.
+ **/
+static void
+lpfc_sli4_disable_msi(struct lpfc_hba *phba)
+{
+	free_irq(phba->pcidev->irq, phba);
+	pci_disable_msi(phba->pcidev);
+	return;
+}
+
+/**
+ * lpfc_sli4_enable_intr - Enable device interrupt to SLI-4 device
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to enable device interrupt and associate driver's
+ * interrupt handler(s) to interrupt vector(s) to device with SLI-4
+ * interface spec. Depends on the interrupt mode configured to the driver,
+ * the driver will try to fallback from the configured interrupt mode to an
+ * interrupt mode which is supported by the platform, kernel, and device in
+ * the order of:
+ * MSI-X -> MSI -> IRQ.
+ *
+ * Return codes
+ * 	0 - sucessful
+ * 	other values - error
+ **/
+static uint32_t
+lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
+{
+	uint32_t intr_mode = LPFC_INTR_ERROR;
+	int retval, index;
+
+	if (cfg_mode == 2) {
+		/* Preparation before conf_msi mbox cmd */
+		retval = 0;
+		if (!retval) {
+			/* Now, try to enable MSI-X interrupt mode */
+			retval = lpfc_sli4_enable_msix(phba);
+			if (!retval) {
+				/* Indicate initialization to MSI-X mode */
+				phba->intr_type = MSIX;
+				intr_mode = 2;
+			}
+		}
+	}
+
+	/* Fallback to MSI if MSI-X initialization failed */
+	if (cfg_mode >= 1 && phba->intr_type == NONE) {
+		retval = lpfc_sli4_enable_msi(phba);
+		if (!retval) {
+			/* Indicate initialization to MSI mode */
+			phba->intr_type = MSI;
+			intr_mode = 1;
+		}
+	}
+
+	/* Fallback to INTx if both MSI-X/MSI initalization failed */
+	if (phba->intr_type == NONE) {
+		retval = request_irq(phba->pcidev->irq, lpfc_sli4_intr_handler,
+				     IRQF_SHARED, LPFC_DRIVER_NAME, phba);
+		if (!retval) {
+			/* Indicate initialization to INTx mode */
+			phba->intr_type = INTx;
+			intr_mode = 0;
+			for (index = 0; index < phba->cfg_fcp_eq_count;
+			     index++) {
+				phba->sli4_hba.fcp_eq_hdl[index].idx = index;
+				phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
+			}
+		}
+	}
+	return intr_mode;
+}
+
+/**
+ * lpfc_sli4_disable_intr - Disable device interrupt to SLI-4 device
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to disable device interrupt and disassociate
+ * the driver's interrupt handler(s) from interrupt vector(s) to device
+ * with SLI-4 interface spec. Depending on the interrupt mode, the driver
+ * will release the interrupt vector(s) for the message signaled interrupt.
+ **/
+static void
+lpfc_sli4_disable_intr(struct lpfc_hba *phba)
+{
+	/* Disable the currently initialized interrupt mode */
+	if (phba->intr_type == MSIX)
+		lpfc_sli4_disable_msix(phba);
+	else if (phba->intr_type == MSI)
+		lpfc_sli4_disable_msi(phba);
+	else if (phba->intr_type == INTx)
+		free_irq(phba->pcidev->irq, phba);
+
+	/* Reset interrupt management states */
+	phba->intr_type = NONE;
+	phba->sli.slistat.sli_intr = 0;
+
+	return;
+}
+
+/**
+ * lpfc_unset_hba - Unset SLI3 hba device initialization
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset the HBA device initialization steps to
+ * a device with SLI-3 interface spec.
+ **/
+static void
+lpfc_unset_hba(struct lpfc_hba *phba)
+{
+	struct lpfc_vport *vport = phba->pport;
+	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
+
+	spin_lock_irq(shost->host_lock);
+	vport->load_flag |= FC_UNLOADING;
+	spin_unlock_irq(shost->host_lock);
+
+	lpfc_stop_hba_timers(phba);
+
+	phba->pport->work_port_events = 0;
+
+	lpfc_sli_hba_down(phba);
+
+	lpfc_sli_brdrestart(phba);
+
+	lpfc_sli_disable_intr(phba);
+
+	return;
+}
+
+/**
+ * lpfc_sli4_unset_hba - Unset SLI4 hba device initialization.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset the HBA device initialization steps to
+ * a device with SLI-4 interface spec.
+ **/
+static void
+lpfc_sli4_unset_hba(struct lpfc_hba *phba)
+{
+	struct lpfc_vport *vport = phba->pport;
+	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
+
+	spin_lock_irq(shost->host_lock);
+	vport->load_flag |= FC_UNLOADING;
+	spin_unlock_irq(shost->host_lock);
+
+	phba->pport->work_port_events = 0;
+
+	lpfc_sli4_hba_down(phba);
+
+	lpfc_sli4_disable_intr(phba);
+
+	return;
+}
+
+/**
+ * lpfc_sli4_hba_unset - Unset the fcoe hba
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called in the SLI4 code path to reset the HBA's FCoE
+ * function. The caller is not required to hold any lock. This routine
+ * issues PCI function reset mailbox command to reset the FCoE function.
+ * At the end of the function, it calls lpfc_hba_down_post function to
+ * free any pending commands.
+ **/
+static void
+lpfc_sli4_hba_unset(struct lpfc_hba *phba)
+{
+	int wait_cnt = 0;
+	LPFC_MBOXQ_t *mboxq;
+
+	lpfc_stop_hba_timers(phba);
+	phba->sli4_hba.intr_enable = 0;
 
 	/*
-	 * Get the bus address of Bar0 and Bar2 and the number of bytes
-	 * required by each mapping.
+	 * Gracefully wait out the potential current outstanding asynchronous
+	 * mailbox command.
 	 */
-	phba->pci_bar0_map = pci_resource_start(phba->pcidev, 0);
-	bar0map_len        = pci_resource_len(phba->pcidev, 0);
 
-	phba->pci_bar2_map = pci_resource_start(phba->pcidev, 2);
-	bar2map_len        = pci_resource_len(phba->pcidev, 2);
-
-	/* Map HBA SLIM to a kernel virtual address. */
-	phba->slim_memmap_p = ioremap(phba->pci_bar0_map, bar0map_len);
-	if (!phba->slim_memmap_p) {
-		error = -ENODEV;
-		dev_printk(KERN_ERR, &pdev->dev,
-			   "ioremap failed for SLIM memory.\n");
-		goto out_idr_remove;
+	/* First, block any pending async mailbox command from posted */
+	spin_lock_irq(&phba->hbalock);
+	phba->sli.sli_flag |= LPFC_SLI_ASYNC_MBX_BLK;
+	spin_unlock_irq(&phba->hbalock);
+	/* Now, trying to wait it out if we can */
+	while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) {
+		msleep(10);
+		if (++wait_cnt > LPFC_ACTIVE_MBOX_WAIT_CNT)
+			break;
 	}
-
-	/* Map HBA Control Registers to a kernel virtual address. */
-	phba->ctrl_regs_memmap_p = ioremap(phba->pci_bar2_map, bar2map_len);
-	if (!phba->ctrl_regs_memmap_p) {
-		error = -ENODEV;
-		dev_printk(KERN_ERR, &pdev->dev,
-			   "ioremap failed for HBA control registers.\n");
-		goto out_iounmap_slim;
-	}
-
-	/* Allocate memory for SLI-2 structures */
-	phba->slim2p.virt = dma_alloc_coherent(&phba->pcidev->dev,
-					       SLI2_SLIM_SIZE,
-					       &phba->slim2p.phys,
-					       GFP_KERNEL);
-	if (!phba->slim2p.virt)
-		goto out_iounmap;
-
-	memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE);
-	phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx);
-	phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb));
-	phba->IOCBs = (phba->slim2p.virt +
-		       offsetof(struct lpfc_sli2_slim, IOCBs));
-
-	phba->hbqslimp.virt = dma_alloc_coherent(&phba->pcidev->dev,
-						 lpfc_sli_hbq_size(),
-						 &phba->hbqslimp.phys,
-						 GFP_KERNEL);
-	if (!phba->hbqslimp.virt)
-		goto out_free_slim;
-
-	hbq_count = lpfc_sli_hbq_count();
-	ptr = phba->hbqslimp.virt;
-	for (i = 0; i < hbq_count; ++i) {
-		phba->hbqs[i].hbq_virt = ptr;
-		INIT_LIST_HEAD(&phba->hbqs[i].hbq_buffer_list);
-		ptr += (lpfc_hbq_defs[i]->entry_count *
-			sizeof(struct lpfc_hbq_entry));
-	}
-	phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_els_hbq_alloc;
-	phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer  = lpfc_els_hbq_free;
-
-	memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size());
-
-	INIT_LIST_HEAD(&phba->hbqbuf_in_list);
-
-	/* Initialize the SLI Layer to run with lpfc HBAs. */
-	lpfc_sli_setup(phba);
-	lpfc_sli_queue_setup(phba);
-
-	retval = lpfc_mem_alloc(phba);
-	if (retval) {
-		error = retval;
-		goto out_free_hbqslimp;
-	}
-
-	/* Initialize and populate the iocb list per host.  */
-	INIT_LIST_HEAD(&phba->lpfc_iocb_list);
-	for (i = 0; i < LPFC_IOCB_LIST_CNT; i++) {
-		iocbq_entry = kzalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL);
-		if (iocbq_entry == NULL) {
-			printk(KERN_ERR "%s: only allocated %d iocbs of "
-				"expected %d count. Unloading driver.\n",
-				__func__, i, LPFC_IOCB_LIST_CNT);
-			error = -ENOMEM;
-			goto out_free_iocbq;
-		}
-
-		iotag = lpfc_sli_next_iotag(phba, iocbq_entry);
-		if (iotag == 0) {
-			kfree (iocbq_entry);
-			printk(KERN_ERR "%s: failed to allocate IOTAG. "
-			       "Unloading driver.\n",
-				__func__);
-			error = -ENOMEM;
-			goto out_free_iocbq;
-		}
-
+	/* Forcefully release the outstanding mailbox command if timed out */
+	if (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) {
 		spin_lock_irq(&phba->hbalock);
-		list_add(&iocbq_entry->list, &phba->lpfc_iocb_list);
-		phba->total_iocbq_bufs++;
+		mboxq = phba->sli.mbox_active;
+		mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED;
+		__lpfc_mbox_cmpl_put(phba, mboxq);
+		phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+		phba->sli.mbox_active = NULL;
 		spin_unlock_irq(&phba->hbalock);
 	}
 
-	/* Initialize HBA structure */
-	phba->fc_edtov = FF_DEF_EDTOV;
-	phba->fc_ratov = FF_DEF_RATOV;
-	phba->fc_altov = FF_DEF_ALTOV;
-	phba->fc_arbtov = FF_DEF_ARBTOV;
+	/* Tear down the queues in the HBA */
+	lpfc_sli4_queue_unset(phba);
 
-	INIT_LIST_HEAD(&phba->work_list);
-	phba->work_ha_mask = (HA_ERATT | HA_MBATT | HA_LATT);
-	phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4));
+	/* Disable PCI subsystem interrupt */
+	lpfc_sli4_disable_intr(phba);
 
-	/* Initialize the wait queue head for the kernel thread */
-	init_waitqueue_head(&phba->work_waitq);
+	/* Stop kthread signal shall trigger work_done one more time */
+	kthread_stop(phba->worker_thread);
 
-	/* Startup the kernel thread for this host adapter. */
-	phba->worker_thread = kthread_run(lpfc_do_work, phba,
-				       "lpfc_worker_%d", phba->brd_no);
-	if (IS_ERR(phba->worker_thread)) {
-		error = PTR_ERR(phba->worker_thread);
-		goto out_free_iocbq;
+	/* Stop the SLI4 device port */
+	phba->pport->work_port_events = 0;
+}
+
+/**
+ * lpfc_pci_probe_one_s3 - PCI probe func to reg SLI-3 device to PCI subsystem.
+ * @pdev: pointer to PCI device
+ * @pid: pointer to PCI device identifier
+ *
+ * This routine is to be called to attach a device with SLI-3 interface spec
+ * to the PCI subsystem. When an Emulex HBA with SLI-3 interface spec is
+ * presented on PCI bus, the kernel PCI subsystem looks at PCI device-specific
+ * information of the device and driver to see if the driver state that it can
+ * support this kind of device. If the match is successful, the driver core
+ * invokes this routine. If this routine determines it can claim the HBA, it
+ * does all the initialization that it needs to do to handle the HBA properly.
+ *
+ * Return code
+ * 	0 - driver can claim the device
+ * 	negative value - driver can not claim the device
+ **/
+static int __devinit
+lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid)
+{
+	struct lpfc_hba   *phba;
+	struct lpfc_vport *vport = NULL;
+	int error;
+	uint32_t cfg_mode, intr_mode;
+
+	/* Allocate memory for HBA structure */
+	phba = lpfc_hba_alloc(pdev);
+	if (!phba)
+		return -ENOMEM;
+
+	/* Perform generic PCI device enabling operation */
+	error = lpfc_enable_pci_dev(phba);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1401 Failed to enable pci device.\n");
+		goto out_free_phba;
 	}
 
-	/* Initialize the list of scsi buffers used by driver for scsi IO. */
-	spin_lock_init(&phba->scsi_buf_list_lock);
-	INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list);
+	/* Set up SLI API function jump table for PCI-device group-0 HBAs */
+	error = lpfc_api_table_setup(phba, LPFC_PCI_DEV_LP);
+	if (error)
+		goto out_disable_pci_dev;
 
-	/* Initialize list of fabric iocbs */
-	INIT_LIST_HEAD(&phba->fabric_iocb_list);
+	/* Set up SLI-3 specific device PCI memory space */
+	error = lpfc_sli_pci_mem_setup(phba);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1402 Failed to set up pci memory space.\n");
+		goto out_disable_pci_dev;
+	}
 
-	/* Initialize list to save ELS buffers */
-	INIT_LIST_HEAD(&phba->elsbuf);
+	/* Set up phase-1 common device driver resources */
+	error = lpfc_setup_driver_resource_phase1(phba);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1403 Failed to set up driver resource.\n");
+		goto out_unset_pci_mem_s3;
+	}
 
-	vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev);
-	if (!vport)
-		goto out_kthread_stop;
+	/* Set up SLI-3 specific device driver resources */
+	error = lpfc_sli_driver_resource_setup(phba);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1404 Failed to set up driver resource.\n");
+		goto out_unset_pci_mem_s3;
+	}
 
-	shost = lpfc_shost_from_vport(vport);
-	phba->pport = vport;
-	lpfc_debugfs_initialize(vport);
+	/* Initialize and populate the iocb list per host */
+	error = lpfc_init_iocb_list(phba, LPFC_IOCB_LIST_CNT);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1405 Failed to initialize iocb list.\n");
+		goto out_unset_driver_resource_s3;
+	}
 
-	pci_set_drvdata(pdev, shost);
+	/* Set up common device driver resources */
+	error = lpfc_setup_driver_resource_phase2(phba);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1406 Failed to set up driver resource.\n");
+		goto out_free_iocb_list;
+	}
 
-	phba->MBslimaddr = phba->slim_memmap_p;
-	phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
-	phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
-	phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
-	phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+	/* Create SCSI host to the physical port */
+	error = lpfc_create_shost(phba);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1407 Failed to create scsi host.\n");
+		goto out_unset_driver_resource;
+	}
 
 	/* Configure sysfs attributes */
-	if (lpfc_alloc_sysfs_attr(vport)) {
+	vport = phba->pport;
+	error = lpfc_alloc_sysfs_attr(vport);
+	if (error) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"1476 Failed to allocate sysfs attr\n");
-		error = -ENOMEM;
-		goto out_destroy_port;
+		goto out_destroy_shost;
 	}
 
+	/* Now, trying to enable interrupt and bring up the device */
 	cfg_mode = phba->cfg_use_msi;
 	while (true) {
+		/* Put device to a known state before enabling interrupt */
+		lpfc_stop_port(phba);
 		/* Configure and enable interrupt */
-		intr_mode = lpfc_enable_intr(phba, cfg_mode);
+		intr_mode = lpfc_sli_enable_intr(phba, cfg_mode);
 		if (intr_mode == LPFC_INTR_ERROR) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-					"0426 Failed to enable interrupt.\n");
+					"0431 Failed to enable interrupt.\n");
+			error = -ENODEV;
 			goto out_free_sysfs_attr;
 		}
-		/* HBA SLI setup */
+		/* SLI-3 HBA setup */
 		if (lpfc_sli_hba_setup(phba)) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 					"1477 Failed to set up hba\n");
@@ -2902,185 +6796,65 @@
 
 		/* Wait 50ms for the interrupts of previous mailbox commands */
 		msleep(50);
-		/* Check active interrupts received */
-		if (phba->sli.slistat.sli_intr > LPFC_MSIX_VECTORS) {
+		/* Check active interrupts on message signaled interrupts */
+		if (intr_mode == 0 ||
+		    phba->sli.slistat.sli_intr > LPFC_MSIX_VECTORS) {
 			/* Log the current active interrupt mode */
 			phba->intr_mode = intr_mode;
 			lpfc_log_intr_mode(phba, intr_mode);
 			break;
 		} else {
 			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-					"0451 Configure interrupt mode (%d) "
+					"0447 Configure interrupt mode (%d) "
 					"failed active interrupt test.\n",
 					intr_mode);
-			if (intr_mode == 0) {
-				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-						"0479 Failed to enable "
-						"interrupt.\n");
-				error = -ENODEV;
-				goto out_remove_device;
-			}
-			/* Stop HBA SLI setups */
-			lpfc_stop_port(phba);
 			/* Disable the current interrupt mode */
-			lpfc_disable_intr(phba);
+			lpfc_sli_disable_intr(phba);
 			/* Try next level of interrupt mode */
 			cfg_mode = --intr_mode;
 		}
 	}
 
-	/*
-	 * hba setup may have changed the hba_queue_depth so we need to adjust
-	 * the value of can_queue.
-	 */
-	shost->can_queue = phba->cfg_hba_queue_depth - 10;
-	if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
+	/* Perform post initialization setup */
+	lpfc_post_init_setup(phba);
 
-		if (lpfc_prot_mask && lpfc_prot_guard) {
-			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-					"1478 Registering BlockGuard with the "
-					"SCSI layer\n");
-
-			scsi_host_set_prot(shost, lpfc_prot_mask);
-			scsi_host_set_guard(shost, lpfc_prot_guard);
-		}
-	}
-
-	if (!_dump_buf_data) {
-		int pagecnt = 10;
-		while (pagecnt) {
-			spin_lock_init(&_dump_buf_lock);
-			_dump_buf_data =
-				(char *) __get_free_pages(GFP_KERNEL, pagecnt);
-			if (_dump_buf_data) {
-				printk(KERN_ERR "BLKGRD allocated %d pages for "
-						"_dump_buf_data at 0x%p\n",
-						(1 << pagecnt), _dump_buf_data);
-				_dump_buf_data_order = pagecnt;
-				memset(_dump_buf_data, 0, ((1 << PAGE_SHIFT)
-							   << pagecnt));
-				break;
-			} else {
-				--pagecnt;
-			}
-
-		}
-
-		if (!_dump_buf_data_order)
-			printk(KERN_ERR "BLKGRD ERROR unable to allocate "
-					"memory for hexdump\n");
-
-	} else {
-		printk(KERN_ERR "BLKGRD already allocated _dump_buf_data=0x%p"
-		       "\n", _dump_buf_data);
-	}
-
-
-	if (!_dump_buf_dif) {
-		int pagecnt = 10;
-		while (pagecnt) {
-			_dump_buf_dif =
-				(char *) __get_free_pages(GFP_KERNEL, pagecnt);
-			if (_dump_buf_dif) {
-				printk(KERN_ERR "BLKGRD allocated %d pages for "
-						"_dump_buf_dif at 0x%p\n",
-						(1 << pagecnt), _dump_buf_dif);
-				_dump_buf_dif_order = pagecnt;
-				memset(_dump_buf_dif, 0, ((1 << PAGE_SHIFT)
-							  << pagecnt));
-				break;
-			} else {
-				--pagecnt;
-			}
-
-		}
-
-		if (!_dump_buf_dif_order)
-			printk(KERN_ERR "BLKGRD ERROR unable to allocate "
-					"memory for hexdump\n");
-
-	} else {
-		printk(KERN_ERR "BLKGRD already allocated _dump_buf_dif=0x%p\n",
-				_dump_buf_dif);
-	}
-
-	lpfc_host_attrib_init(shost);
-
-	if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
-		spin_lock_irq(shost->host_lock);
-		lpfc_poll_start_timer(phba);
-		spin_unlock_irq(shost->host_lock);
-	}
-
-	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-			"0428 Perform SCSI scan\n");
-	/* Send board arrival event to upper layer */
-	adapter_event.event_type = FC_REG_ADAPTER_EVENT;
-	adapter_event.subcategory = LPFC_EVENT_ARRIVAL;
-	fc_host_post_vendor_event(shost, fc_get_event_number(),
-		sizeof(adapter_event),
-		(char *) &adapter_event,
-		LPFC_NL_VENDOR_ID);
+	/* Check if there are static vports to be created. */
+	lpfc_create_static_vport(phba);
 
 	return 0;
 
 out_remove_device:
-	spin_lock_irq(shost->host_lock);
-	vport->load_flag |= FC_UNLOADING;
-	spin_unlock_irq(shost->host_lock);
-	lpfc_stop_phba_timers(phba);
-	phba->pport->work_port_events = 0;
-	lpfc_disable_intr(phba);
-	lpfc_sli_hba_down(phba);
-	lpfc_sli_brdrestart(phba);
+	lpfc_unset_hba(phba);
 out_free_sysfs_attr:
 	lpfc_free_sysfs_attr(vport);
-out_destroy_port:
-	destroy_port(vport);
-out_kthread_stop:
-	kthread_stop(phba->worker_thread);
-out_free_iocbq:
-	list_for_each_entry_safe(iocbq_entry, iocbq_next,
-						&phba->lpfc_iocb_list, list) {
-		kfree(iocbq_entry);
-		phba->total_iocbq_bufs--;
-	}
-	lpfc_mem_free(phba);
-out_free_hbqslimp:
-	dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(),
-			  phba->hbqslimp.virt, phba->hbqslimp.phys);
-out_free_slim:
-	dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
-			  phba->slim2p.virt, phba->slim2p.phys);
-out_iounmap:
-	iounmap(phba->ctrl_regs_memmap_p);
-out_iounmap_slim:
-	iounmap(phba->slim_memmap_p);
-out_idr_remove:
-	idr_remove(&lpfc_hba_index, phba->brd_no);
+out_destroy_shost:
+	lpfc_destroy_shost(phba);
+out_unset_driver_resource:
+	lpfc_unset_driver_resource_phase2(phba);
+out_free_iocb_list:
+	lpfc_free_iocb_list(phba);
+out_unset_driver_resource_s3:
+	lpfc_sli_driver_resource_unset(phba);
+out_unset_pci_mem_s3:
+	lpfc_sli_pci_mem_unset(phba);
+out_disable_pci_dev:
+	lpfc_disable_pci_dev(phba);
 out_free_phba:
-	kfree(phba);
-out_release_regions:
-	pci_release_selected_regions(pdev, bars);
-out_disable_device:
-	pci_disable_device(pdev);
-out:
-	pci_set_drvdata(pdev, NULL);
-	if (shost)
-		scsi_host_put(shost);
+	lpfc_hba_free(phba);
 	return error;
 }
 
 /**
- * lpfc_pci_remove_one - lpfc PCI func to unregister device from PCI subsystem
+ * lpfc_pci_remove_one_s3 - PCI func to unreg SLI-3 device from PCI subsystem.
  * @pdev: pointer to PCI device
  *
- * This routine is to be registered to the kernel's PCI subsystem. When an
- * Emulex HBA is removed from PCI bus, it performs all the necessary cleanup
- * for the HBA device to be removed from the PCI subsystem properly.
+ * This routine is to be called to disattach a device with SLI-3 interface
+ * spec from PCI subsystem. When an Emulex HBA with SLI-3 interface spec is
+ * removed from PCI bus, it performs all the necessary cleanup for the HBA
+ * device to be removed from the PCI subsystem properly.
  **/
 static void __devexit
-lpfc_pci_remove_one(struct pci_dev *pdev)
+lpfc_pci_remove_one_s3(struct pci_dev *pdev)
 {
 	struct Scsi_Host  *shost = pci_get_drvdata(pdev);
 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
@@ -3098,7 +6872,7 @@
 	/* Release all the vports against this physical port */
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for (i = 1; i <= phba->max_vpi && vports[i] != NULL; i++)
+		for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++)
 			fc_vport_terminate(vports[i]->fc_vport);
 	lpfc_destroy_vport_work_array(phba, vports);
 
@@ -3120,7 +6894,7 @@
 	/* Final cleanup of txcmplq and reset the HBA */
 	lpfc_sli_brdrestart(phba);
 
-	lpfc_stop_phba_timers(phba);
+	lpfc_stop_hba_timers(phba);
 	spin_lock_irq(&phba->hbalock);
 	list_del_init(&vport->listentry);
 	spin_unlock_irq(&phba->hbalock);
@@ -3128,7 +6902,7 @@
 	lpfc_debugfs_terminate(vport);
 
 	/* Disable interrupt */
-	lpfc_disable_intr(phba);
+	lpfc_sli_disable_intr(phba);
 
 	pci_set_drvdata(pdev, NULL);
 	scsi_host_put(shost);
@@ -3138,7 +6912,7 @@
 	 * corresponding pools here.
 	 */
 	lpfc_scsi_free(phba);
-	lpfc_mem_free(phba);
+	lpfc_mem_free_all(phba);
 
 	dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(),
 			  phba->hbqslimp.virt, phba->hbqslimp.phys);
@@ -3151,36 +6925,35 @@
 	iounmap(phba->ctrl_regs_memmap_p);
 	iounmap(phba->slim_memmap_p);
 
-	idr_remove(&lpfc_hba_index, phba->brd_no);
-
-	kfree(phba);
+	lpfc_hba_free(phba);
 
 	pci_release_selected_regions(pdev, bars);
 	pci_disable_device(pdev);
 }
 
 /**
- * lpfc_pci_suspend_one - lpfc PCI func to suspend device for power management
+ * lpfc_pci_suspend_one_s3 - PCI func to suspend SLI-3 device for power mgmnt
  * @pdev: pointer to PCI device
  * @msg: power management message
  *
- * This routine is to be registered to the kernel's PCI subsystem to support
- * system Power Management (PM). When PM invokes this method, it quiesces the
- * device by stopping the driver's worker thread for the device, turning off
- * device's interrupt and DMA, and bring the device offline. Note that as the
- * driver implements the minimum PM requirements to a power-aware driver's PM
- * support for suspend/resume -- all the possible PM messages (SUSPEND,
- * HIBERNATE, FREEZE) to the suspend() method call will be treated as SUSPEND
- * and the driver will fully reinitialize its device during resume() method
- * call, the driver will set device to PCI_D3hot state in PCI config space
- * instead of setting it according to the @msg provided by the PM.
+ * This routine is to be called from the kernel's PCI subsystem to support
+ * system Power Management (PM) to device with SLI-3 interface spec. When
+ * PM invokes this method, it quiesces the device by stopping the driver's
+ * worker thread for the device, turning off device's interrupt and DMA,
+ * and bring the device offline. Note that as the driver implements the
+ * minimum PM requirements to a power-aware driver's PM support for the
+ * suspend/resume -- all the possible PM messages (SUSPEND, HIBERNATE, FREEZE)
+ * to the suspend() method call will be treated as SUSPEND and the driver will
+ * fully reinitialize its device during resume() method call, the driver will
+ * set device to PCI_D3hot state in PCI config space instead of setting it
+ * according to the @msg provided by the PM.
  *
  * Return code
- *   0 - driver suspended the device
- *   Error otherwise
+ * 	0 - driver suspended the device
+ * 	Error otherwise
  **/
 static int
-lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg)
+lpfc_pci_suspend_one_s3(struct pci_dev *pdev, pm_message_t msg)
 {
 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
 	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
@@ -3194,7 +6967,7 @@
 	kthread_stop(phba->worker_thread);
 
 	/* Disable interrupt from device */
-	lpfc_disable_intr(phba);
+	lpfc_sli_disable_intr(phba);
 
 	/* Save device state to PCI config space */
 	pci_save_state(pdev);
@@ -3204,25 +6977,26 @@
 }
 
 /**
- * lpfc_pci_resume_one - lpfc PCI func to resume device for power management
+ * lpfc_pci_resume_one_s3 - PCI func to resume SLI-3 device for power mgmnt
  * @pdev: pointer to PCI device
  *
- * This routine is to be registered to the kernel's PCI subsystem to support
- * system Power Management (PM). When PM invokes this method, it restores
- * the device's PCI config space state and fully reinitializes the device
- * and brings it online. Note that as the driver implements the minimum PM
- * requirements to a power-aware driver's PM for suspend/resume -- all
- * the possible PM messages (SUSPEND, HIBERNATE, FREEZE) to the suspend()
- * method call will be treated as SUSPEND and the driver will fully
- * reinitialize its device during resume() method call, the device will be
- * set to PCI_D0 directly in PCI config space before restoring the state.
+ * This routine is to be called from the kernel's PCI subsystem to support
+ * system Power Management (PM) to device with SLI-3 interface spec. When PM
+ * invokes this method, it restores the device's PCI config space state and
+ * fully reinitializes the device and brings it online. Note that as the
+ * driver implements the minimum PM requirements to a power-aware driver's
+ * PM for suspend/resume -- all the possible PM messages (SUSPEND, HIBERNATE,
+ * FREEZE) to the suspend() method call will be treated as SUSPEND and the
+ * driver will fully reinitialize its device during resume() method call,
+ * the device will be set to PCI_D0 directly in PCI config space before
+ * restoring the state.
  *
  * Return code
- *   0 - driver suspended the device
- *   Error otherwise
+ * 	0 - driver suspended the device
+ * 	Error otherwise
  **/
 static int
-lpfc_pci_resume_one(struct pci_dev *pdev)
+lpfc_pci_resume_one_s3(struct pci_dev *pdev)
 {
 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
 	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
@@ -3250,7 +7024,7 @@
 	}
 
 	/* Configure and enable interrupt */
-	intr_mode = lpfc_enable_intr(phba, phba->intr_mode);
+	intr_mode = lpfc_sli_enable_intr(phba, phba->intr_mode);
 	if (intr_mode == LPFC_INTR_ERROR) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"0430 PM resume Failed to enable interrupt\n");
@@ -3269,23 +7043,24 @@
 }
 
 /**
- * lpfc_io_error_detected - Driver method for handling PCI I/O error detected
+ * lpfc_io_error_detected_s3 - Method for handling SLI-3 device PCI I/O error
  * @pdev: pointer to PCI device.
  * @state: the current PCI connection state.
  *
- * This routine is registered to the PCI subsystem for error handling. This
- * function is called by the PCI subsystem after a PCI bus error affecting
- * this device has been detected. When this function is invoked, it will
- * need to stop all the I/Os and interrupt(s) to the device. Once that is
- * done, it will return PCI_ERS_RESULT_NEED_RESET for the PCI subsystem to
- * perform proper recovery as desired.
+ * This routine is called from the PCI subsystem for I/O error handling to
+ * device with SLI-3 interface spec. This function is called by the PCI
+ * subsystem after a PCI bus error affecting this device has been detected.
+ * When this function is invoked, it will need to stop all the I/Os and
+ * interrupt(s) to the device. Once that is done, it will return
+ * PCI_ERS_RESULT_NEED_RESET for the PCI subsystem to perform proper recovery
+ * as desired.
  *
  * Return codes
- *   PCI_ERS_RESULT_NEED_RESET - need to reset before recovery
- *   PCI_ERS_RESULT_DISCONNECT - device could not be recovered
+ * 	PCI_ERS_RESULT_NEED_RESET - need to reset before recovery
+ * 	PCI_ERS_RESULT_DISCONNECT - device could not be recovered
  **/
-static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev,
-				pci_channel_state_t state)
+static pci_ers_result_t
+lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state)
 {
 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
 	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
@@ -3312,30 +7087,32 @@
 	lpfc_sli_abort_iocb_ring(phba, pring);
 
 	/* Disable interrupt */
-	lpfc_disable_intr(phba);
+	lpfc_sli_disable_intr(phba);
 
 	/* Request a slot reset. */
 	return PCI_ERS_RESULT_NEED_RESET;
 }
 
 /**
- * lpfc_io_slot_reset - Restart a PCI device from scratch
+ * lpfc_io_slot_reset_s3 - Method for restarting PCI SLI-3 device from scratch.
  * @pdev: pointer to PCI device.
  *
- * This routine is registered to the PCI subsystem for error handling. This is
- * called after PCI bus has been reset to restart the PCI card from scratch,
- * as if from a cold-boot. During the PCI subsystem error recovery, after the
- * driver returns PCI_ERS_RESULT_NEED_RESET, the PCI subsystem will perform
- * proper error recovery and then call this routine before calling the .resume
- * method to recover the device. This function will initialize the HBA device,
- * enable the interrupt, but it will just put the HBA to offline state without
- * passing any I/O traffic.
+ * This routine is called from the PCI subsystem for error handling to
+ * device with SLI-3 interface spec. This is called after PCI bus has been
+ * reset to restart the PCI card from scratch, as if from a cold-boot.
+ * During the PCI subsystem error recovery, after driver returns
+ * PCI_ERS_RESULT_NEED_RESET, the PCI subsystem will perform proper error
+ * recovery and then call this routine before calling the .resume method
+ * to recover the device. This function will initialize the HBA device,
+ * enable the interrupt, but it will just put the HBA to offline state
+ * without passing any I/O traffic.
  *
  * Return codes
- *   PCI_ERS_RESULT_RECOVERED - the device has been recovered
- *   PCI_ERS_RESULT_DISCONNECT - device could not be recovered
+ * 	PCI_ERS_RESULT_RECOVERED - the device has been recovered
+ * 	PCI_ERS_RESULT_DISCONNECT - device could not be recovered
  */
-static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
+static pci_ers_result_t
+lpfc_io_slot_reset_s3(struct pci_dev *pdev)
 {
 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
 	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
@@ -3354,11 +7131,11 @@
 		pci_set_master(pdev);
 
 	spin_lock_irq(&phba->hbalock);
-	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+	psli->sli_flag &= ~LPFC_SLI_ACTIVE;
 	spin_unlock_irq(&phba->hbalock);
 
 	/* Configure and enable interrupt */
-	intr_mode = lpfc_enable_intr(phba, phba->intr_mode);
+	intr_mode = lpfc_sli_enable_intr(phba, phba->intr_mode);
 	if (intr_mode == LPFC_INTR_ERROR) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"0427 Cannot re-enable interrupt after "
@@ -3378,15 +7155,17 @@
 }
 
 /**
- * lpfc_io_resume - Resume PCI I/O operation
+ * lpfc_io_resume_s3 - Method for resuming PCI I/O operation on SLI-3 device.
  * @pdev: pointer to PCI device
  *
- * This routine is registered to the PCI subsystem for error handling. It is
- * called when kernel error recovery tells the lpfc driver that it is ok to
- * resume normal PCI operation after PCI bus error recovery. After this call,
- * traffic can start to flow from this device again.
+ * This routine is called from the PCI subsystem for error handling to device
+ * with SLI-3 interface spec. It is called when kernel error recovery tells
+ * the lpfc driver that it is ok to resume normal PCI operation after PCI bus
+ * error recovery. After this call, traffic can start to flow from this device
+ * again.
  */
-static void lpfc_io_resume(struct pci_dev *pdev)
+static void
+lpfc_io_resume_s3(struct pci_dev *pdev)
 {
 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
 	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
@@ -3394,6 +7173,697 @@
 	lpfc_online(phba);
 }
 
+/**
+ * lpfc_sli4_get_els_iocb_cnt - Calculate the # of ELS IOCBs to reserve
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * returns the number of ELS/CT IOCBs to reserve
+ **/
+int
+lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba)
+{
+	int max_xri = phba->sli4_hba.max_cfg_param.max_xri;
+
+	if (max_xri <= 100)
+		return 4;
+	else if (max_xri <= 256)
+		return 8;
+	else if (max_xri <= 512)
+		return 16;
+	else if (max_xri <= 1024)
+		return 32;
+	else
+		return 48;
+}
+
+/**
+ * lpfc_pci_probe_one_s4 - PCI probe func to reg SLI-4 device to PCI subsys
+ * @pdev: pointer to PCI device
+ * @pid: pointer to PCI device identifier
+ *
+ * This routine is called from the kernel's PCI subsystem to device with
+ * SLI-4 interface spec. When an Emulex HBA with SLI-4 interface spec is
+ * presented on PCI bus, the kernel PCI subsystem looks at PCI device-specific
+ * information of the device and driver to see if the driver state that it
+ * can support this kind of device. If the match is successful, the driver
+ * core invokes this routine. If this routine determines it can claim the HBA,
+ * it does all the initialization that it needs to do to handle the HBA
+ * properly.
+ *
+ * Return code
+ * 	0 - driver can claim the device
+ * 	negative value - driver can not claim the device
+ **/
+static int __devinit
+lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
+{
+	struct lpfc_hba   *phba;
+	struct lpfc_vport *vport = NULL;
+	int error;
+	uint32_t cfg_mode, intr_mode;
+	int mcnt;
+
+	/* Allocate memory for HBA structure */
+	phba = lpfc_hba_alloc(pdev);
+	if (!phba)
+		return -ENOMEM;
+
+	/* Perform generic PCI device enabling operation */
+	error = lpfc_enable_pci_dev(phba);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1409 Failed to enable pci device.\n");
+		goto out_free_phba;
+	}
+
+	/* Set up SLI API function jump table for PCI-device group-1 HBAs */
+	error = lpfc_api_table_setup(phba, LPFC_PCI_DEV_OC);
+	if (error)
+		goto out_disable_pci_dev;
+
+	/* Set up SLI-4 specific device PCI memory space */
+	error = lpfc_sli4_pci_mem_setup(phba);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1410 Failed to set up pci memory space.\n");
+		goto out_disable_pci_dev;
+	}
+
+	/* Set up phase-1 common device driver resources */
+	error = lpfc_setup_driver_resource_phase1(phba);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1411 Failed to set up driver resource.\n");
+		goto out_unset_pci_mem_s4;
+	}
+
+	/* Set up SLI-4 Specific device driver resources */
+	error = lpfc_sli4_driver_resource_setup(phba);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1412 Failed to set up driver resource.\n");
+		goto out_unset_pci_mem_s4;
+	}
+
+	/* Initialize and populate the iocb list per host */
+	error = lpfc_init_iocb_list(phba,
+			phba->sli4_hba.max_cfg_param.max_xri);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1413 Failed to initialize iocb list.\n");
+		goto out_unset_driver_resource_s4;
+	}
+
+	/* Set up common device driver resources */
+	error = lpfc_setup_driver_resource_phase2(phba);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1414 Failed to set up driver resource.\n");
+		goto out_free_iocb_list;
+	}
+
+	/* Create SCSI host to the physical port */
+	error = lpfc_create_shost(phba);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1415 Failed to create scsi host.\n");
+		goto out_unset_driver_resource;
+	}
+
+	/* Configure sysfs attributes */
+	vport = phba->pport;
+	error = lpfc_alloc_sysfs_attr(vport);
+	if (error) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1416 Failed to allocate sysfs attr\n");
+		goto out_destroy_shost;
+	}
+
+	/* Now, trying to enable interrupt and bring up the device */
+	cfg_mode = phba->cfg_use_msi;
+	while (true) {
+		/* Put device to a known state before enabling interrupt */
+		lpfc_stop_port(phba);
+		/* Configure and enable interrupt */
+		intr_mode = lpfc_sli4_enable_intr(phba, cfg_mode);
+		if (intr_mode == LPFC_INTR_ERROR) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"0426 Failed to enable interrupt.\n");
+			error = -ENODEV;
+			goto out_free_sysfs_attr;
+		}
+		/* Set up SLI-4 HBA */
+		if (lpfc_sli4_hba_setup(phba)) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"1421 Failed to set up hba\n");
+			error = -ENODEV;
+			goto out_disable_intr;
+		}
+
+		/* Send NOP mbx cmds for non-INTx mode active interrupt test */
+		if (intr_mode != 0)
+			mcnt = lpfc_sli4_send_nop_mbox_cmds(phba,
+							    LPFC_ACT_INTR_CNT);
+
+		/* Check active interrupts received only for MSI/MSI-X */
+		if (intr_mode == 0 ||
+		    phba->sli.slistat.sli_intr >= LPFC_ACT_INTR_CNT) {
+			/* Log the current active interrupt mode */
+			phba->intr_mode = intr_mode;
+			lpfc_log_intr_mode(phba, intr_mode);
+			break;
+		}
+		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"0451 Configure interrupt mode (%d) "
+				"failed active interrupt test.\n",
+				intr_mode);
+		/* Unset the preivous SLI-4 HBA setup */
+		lpfc_sli4_unset_hba(phba);
+		/* Try next level of interrupt mode */
+		cfg_mode = --intr_mode;
+	}
+
+	/* Perform post initialization setup */
+	lpfc_post_init_setup(phba);
+
+	return 0;
+
+out_disable_intr:
+	lpfc_sli4_disable_intr(phba);
+out_free_sysfs_attr:
+	lpfc_free_sysfs_attr(vport);
+out_destroy_shost:
+	lpfc_destroy_shost(phba);
+out_unset_driver_resource:
+	lpfc_unset_driver_resource_phase2(phba);
+out_free_iocb_list:
+	lpfc_free_iocb_list(phba);
+out_unset_driver_resource_s4:
+	lpfc_sli4_driver_resource_unset(phba);
+out_unset_pci_mem_s4:
+	lpfc_sli4_pci_mem_unset(phba);
+out_disable_pci_dev:
+	lpfc_disable_pci_dev(phba);
+out_free_phba:
+	lpfc_hba_free(phba);
+	return error;
+}
+
+/**
+ * lpfc_pci_remove_one_s4 - PCI func to unreg SLI-4 device from PCI subsystem
+ * @pdev: pointer to PCI device
+ *
+ * This routine is called from the kernel's PCI subsystem to device with
+ * SLI-4 interface spec. When an Emulex HBA with SLI-4 interface spec is
+ * removed from PCI bus, it performs all the necessary cleanup for the HBA
+ * device to be removed from the PCI subsystem properly.
+ **/
+static void __devexit
+lpfc_pci_remove_one_s4(struct pci_dev *pdev)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+	struct lpfc_vport **vports;
+	struct lpfc_hba *phba = vport->phba;
+	int i;
+
+	/* Mark the device unloading flag */
+	spin_lock_irq(&phba->hbalock);
+	vport->load_flag |= FC_UNLOADING;
+	spin_unlock_irq(&phba->hbalock);
+
+	/* Free the HBA sysfs attributes */
+	lpfc_free_sysfs_attr(vport);
+
+	/* Release all the vports against this physical port */
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL)
+		for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++)
+			fc_vport_terminate(vports[i]->fc_vport);
+	lpfc_destroy_vport_work_array(phba, vports);
+
+	/* Remove FC host and then SCSI host with the physical port */
+	fc_remove_host(shost);
+	scsi_remove_host(shost);
+
+	/* Perform cleanup on the physical port */
+	lpfc_cleanup(vport);
+
+	/*
+	 * Bring down the SLI Layer. This step disables all interrupts,
+	 * clears the rings, discards all mailbox commands, and resets
+	 * the HBA FCoE function.
+	 */
+	lpfc_debugfs_terminate(vport);
+	lpfc_sli4_hba_unset(phba);
+
+	spin_lock_irq(&phba->hbalock);
+	list_del_init(&vport->listentry);
+	spin_unlock_irq(&phba->hbalock);
+
+	/* Call scsi_free before lpfc_sli4_driver_resource_unset since scsi
+	 * buffers are released to their corresponding pools here.
+	 */
+	lpfc_scsi_free(phba);
+	lpfc_sli4_driver_resource_unset(phba);
+
+	/* Unmap adapter Control and Doorbell registers */
+	lpfc_sli4_pci_mem_unset(phba);
+
+	/* Release PCI resources and disable device's PCI function */
+	scsi_host_put(shost);
+	lpfc_disable_pci_dev(phba);
+
+	/* Finally, free the driver's device data structure */
+	lpfc_hba_free(phba);
+
+	return;
+}
+
+/**
+ * lpfc_pci_suspend_one_s4 - PCI func to suspend SLI-4 device for power mgmnt
+ * @pdev: pointer to PCI device
+ * @msg: power management message
+ *
+ * This routine is called from the kernel's PCI subsystem to support system
+ * Power Management (PM) to device with SLI-4 interface spec. When PM invokes
+ * this method, it quiesces the device by stopping the driver's worker
+ * thread for the device, turning off device's interrupt and DMA, and bring
+ * the device offline. Note that as the driver implements the minimum PM
+ * requirements to a power-aware driver's PM support for suspend/resume -- all
+ * the possible PM messages (SUSPEND, HIBERNATE, FREEZE) to the suspend()
+ * method call will be treated as SUSPEND and the driver will fully
+ * reinitialize its device during resume() method call, the driver will set
+ * device to PCI_D3hot state in PCI config space instead of setting it
+ * according to the @msg provided by the PM.
+ *
+ * Return code
+ * 	0 - driver suspended the device
+ * 	Error otherwise
+ **/
+static int
+lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"0298 PCI device Power Management suspend.\n");
+
+	/* Bring down the device */
+	lpfc_offline_prep(phba);
+	lpfc_offline(phba);
+	kthread_stop(phba->worker_thread);
+
+	/* Disable interrupt from device */
+	lpfc_sli4_disable_intr(phba);
+
+	/* Save device state to PCI config space */
+	pci_save_state(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+
+	return 0;
+}
+
+/**
+ * lpfc_pci_resume_one_s4 - PCI func to resume SLI-4 device for power mgmnt
+ * @pdev: pointer to PCI device
+ *
+ * This routine is called from the kernel's PCI subsystem to support system
+ * Power Management (PM) to device with SLI-4 interface spac. When PM invokes
+ * this method, it restores the device's PCI config space state and fully
+ * reinitializes the device and brings it online. Note that as the driver
+ * implements the minimum PM requirements to a power-aware driver's PM for
+ * suspend/resume -- all the possible PM messages (SUSPEND, HIBERNATE, FREEZE)
+ * to the suspend() method call will be treated as SUSPEND and the driver
+ * will fully reinitialize its device during resume() method call, the device
+ * will be set to PCI_D0 directly in PCI config space before restoring the
+ * state.
+ *
+ * Return code
+ * 	0 - driver suspended the device
+ * 	Error otherwise
+ **/
+static int
+lpfc_pci_resume_one_s4(struct pci_dev *pdev)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+	uint32_t intr_mode;
+	int error;
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"0292 PCI device Power Management resume.\n");
+
+	/* Restore device state from PCI config space */
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	if (pdev->is_busmaster)
+		pci_set_master(pdev);
+
+	 /* Startup the kernel thread for this host adapter. */
+	phba->worker_thread = kthread_run(lpfc_do_work, phba,
+					"lpfc_worker_%d", phba->brd_no);
+	if (IS_ERR(phba->worker_thread)) {
+		error = PTR_ERR(phba->worker_thread);
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0293 PM resume failed to start worker "
+				"thread: error=x%x.\n", error);
+		return error;
+	}
+
+	/* Configure and enable interrupt */
+	intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode);
+	if (intr_mode == LPFC_INTR_ERROR) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0294 PM resume Failed to enable interrupt\n");
+		return -EIO;
+	} else
+		phba->intr_mode = intr_mode;
+
+	/* Restart HBA and bring it online */
+	lpfc_sli_brdrestart(phba);
+	lpfc_online(phba);
+
+	/* Log the current active interrupt mode */
+	lpfc_log_intr_mode(phba, phba->intr_mode);
+
+	return 0;
+}
+
+/**
+ * lpfc_io_error_detected_s4 - Method for handling PCI I/O error to SLI-4 device
+ * @pdev: pointer to PCI device.
+ * @state: the current PCI connection state.
+ *
+ * This routine is called from the PCI subsystem for error handling to device
+ * with SLI-4 interface spec. This function is called by the PCI subsystem
+ * after a PCI bus error affecting this device has been detected. When this
+ * function is invoked, it will need to stop all the I/Os and interrupt(s)
+ * to the device. Once that is done, it will return PCI_ERS_RESULT_NEED_RESET
+ * for the PCI subsystem to perform proper recovery as desired.
+ *
+ * Return codes
+ * 	PCI_ERS_RESULT_NEED_RESET - need to reset before recovery
+ * 	PCI_ERS_RESULT_DISCONNECT - device could not be recovered
+ **/
+static pci_ers_result_t
+lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state)
+{
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * lpfc_io_slot_reset_s4 - Method for restart PCI SLI-4 device from scratch
+ * @pdev: pointer to PCI device.
+ *
+ * This routine is called from the PCI subsystem for error handling to device
+ * with SLI-4 interface spec. It is called after PCI bus has been reset to
+ * restart the PCI card from scratch, as if from a cold-boot. During the
+ * PCI subsystem error recovery, after the driver returns
+ * PCI_ERS_RESULT_NEED_RESET, the PCI subsystem will perform proper error
+ * recovery and then call this routine before calling the .resume method to
+ * recover the device. This function will initialize the HBA device, enable
+ * the interrupt, but it will just put the HBA to offline state without
+ * passing any I/O traffic.
+ *
+ * Return codes
+ * 	PCI_ERS_RESULT_RECOVERED - the device has been recovered
+ * 	PCI_ERS_RESULT_DISCONNECT - device could not be recovered
+ */
+static pci_ers_result_t
+lpfc_io_slot_reset_s4(struct pci_dev *pdev)
+{
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * lpfc_io_resume_s4 - Method for resuming PCI I/O operation to SLI-4 device
+ * @pdev: pointer to PCI device
+ *
+ * This routine is called from the PCI subsystem for error handling to device
+ * with SLI-4 interface spec. It is called when kernel error recovery tells
+ * the lpfc driver that it is ok to resume normal PCI operation after PCI bus
+ * error recovery. After this call, traffic can start to flow from this device
+ * again.
+ **/
+static void
+lpfc_io_resume_s4(struct pci_dev *pdev)
+{
+	return;
+}
+
+/**
+ * lpfc_pci_probe_one - lpfc PCI probe func to reg dev to PCI subsystem
+ * @pdev: pointer to PCI device
+ * @pid: pointer to PCI device identifier
+ *
+ * This routine is to be registered to the kernel's PCI subsystem. When an
+ * Emulex HBA device is presented on PCI bus, the kernel PCI subsystem looks
+ * at PCI device-specific information of the device and driver to see if the
+ * driver state that it can support this kind of device. If the match is
+ * successful, the driver core invokes this routine. This routine dispatches
+ * the action to the proper SLI-3 or SLI-4 device probing routine, which will
+ * do all the initialization that it needs to do to handle the HBA device
+ * properly.
+ *
+ * Return code
+ * 	0 - driver can claim the device
+ * 	negative value - driver can not claim the device
+ **/
+static int __devinit
+lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
+{
+	int rc;
+	uint16_t dev_id;
+
+	if (pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id))
+		return -ENODEV;
+
+	switch (dev_id) {
+	case PCI_DEVICE_ID_TIGERSHARK:
+	case PCI_DEVICE_ID_TIGERSHARK_S:
+		rc = lpfc_pci_probe_one_s4(pdev, pid);
+		break;
+	default:
+		rc = lpfc_pci_probe_one_s3(pdev, pid);
+		break;
+	}
+	return rc;
+}
+
+/**
+ * lpfc_pci_remove_one - lpfc PCI func to unreg dev from PCI subsystem
+ * @pdev: pointer to PCI device
+ *
+ * This routine is to be registered to the kernel's PCI subsystem. When an
+ * Emulex HBA is removed from PCI bus, the driver core invokes this routine.
+ * This routine dispatches the action to the proper SLI-3 or SLI-4 device
+ * remove routine, which will perform all the necessary cleanup for the
+ * device to be removed from the PCI subsystem properly.
+ **/
+static void __devexit
+lpfc_pci_remove_one(struct pci_dev *pdev)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+	switch (phba->pci_dev_grp) {
+	case LPFC_PCI_DEV_LP:
+		lpfc_pci_remove_one_s3(pdev);
+		break;
+	case LPFC_PCI_DEV_OC:
+		lpfc_pci_remove_one_s4(pdev);
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1424 Invalid PCI device group: 0x%x\n",
+				phba->pci_dev_grp);
+		break;
+	}
+	return;
+}
+
+/**
+ * lpfc_pci_suspend_one - lpfc PCI func to suspend dev for power management
+ * @pdev: pointer to PCI device
+ * @msg: power management message
+ *
+ * This routine is to be registered to the kernel's PCI subsystem to support
+ * system Power Management (PM). When PM invokes this method, it dispatches
+ * the action to the proper SLI-3 or SLI-4 device suspend routine, which will
+ * suspend the device.
+ *
+ * Return code
+ * 	0 - driver suspended the device
+ * 	Error otherwise
+ **/
+static int
+lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+	int rc = -ENODEV;
+
+	switch (phba->pci_dev_grp) {
+	case LPFC_PCI_DEV_LP:
+		rc = lpfc_pci_suspend_one_s3(pdev, msg);
+		break;
+	case LPFC_PCI_DEV_OC:
+		rc = lpfc_pci_suspend_one_s4(pdev, msg);
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1425 Invalid PCI device group: 0x%x\n",
+				phba->pci_dev_grp);
+		break;
+	}
+	return rc;
+}
+
+/**
+ * lpfc_pci_resume_one - lpfc PCI func to resume dev for power management
+ * @pdev: pointer to PCI device
+ *
+ * This routine is to be registered to the kernel's PCI subsystem to support
+ * system Power Management (PM). When PM invokes this method, it dispatches
+ * the action to the proper SLI-3 or SLI-4 device resume routine, which will
+ * resume the device.
+ *
+ * Return code
+ * 	0 - driver suspended the device
+ * 	Error otherwise
+ **/
+static int
+lpfc_pci_resume_one(struct pci_dev *pdev)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+	int rc = -ENODEV;
+
+	switch (phba->pci_dev_grp) {
+	case LPFC_PCI_DEV_LP:
+		rc = lpfc_pci_resume_one_s3(pdev);
+		break;
+	case LPFC_PCI_DEV_OC:
+		rc = lpfc_pci_resume_one_s4(pdev);
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1426 Invalid PCI device group: 0x%x\n",
+				phba->pci_dev_grp);
+		break;
+	}
+	return rc;
+}
+
+/**
+ * lpfc_io_error_detected - lpfc method for handling PCI I/O error
+ * @pdev: pointer to PCI device.
+ * @state: the current PCI connection state.
+ *
+ * This routine is registered to the PCI subsystem for error handling. This
+ * function is called by the PCI subsystem after a PCI bus error affecting
+ * this device has been detected. When this routine is invoked, it dispatches
+ * the action to the proper SLI-3 or SLI-4 device error detected handling
+ * routine, which will perform the proper error detected operation.
+ *
+ * Return codes
+ * 	PCI_ERS_RESULT_NEED_RESET - need to reset before recovery
+ * 	PCI_ERS_RESULT_DISCONNECT - device could not be recovered
+ **/
+static pci_ers_result_t
+lpfc_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+	pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT;
+
+	switch (phba->pci_dev_grp) {
+	case LPFC_PCI_DEV_LP:
+		rc = lpfc_io_error_detected_s3(pdev, state);
+		break;
+	case LPFC_PCI_DEV_OC:
+		rc = lpfc_io_error_detected_s4(pdev, state);
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1427 Invalid PCI device group: 0x%x\n",
+				phba->pci_dev_grp);
+		break;
+	}
+	return rc;
+}
+
+/**
+ * lpfc_io_slot_reset - lpfc method for restart PCI dev from scratch
+ * @pdev: pointer to PCI device.
+ *
+ * This routine is registered to the PCI subsystem for error handling. This
+ * function is called after PCI bus has been reset to restart the PCI card
+ * from scratch, as if from a cold-boot. When this routine is invoked, it
+ * dispatches the action to the proper SLI-3 or SLI-4 device reset handling
+ * routine, which will perform the proper device reset.
+ *
+ * Return codes
+ * 	PCI_ERS_RESULT_RECOVERED - the device has been recovered
+ * 	PCI_ERS_RESULT_DISCONNECT - device could not be recovered
+ **/
+static pci_ers_result_t
+lpfc_io_slot_reset(struct pci_dev *pdev)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+	pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT;
+
+	switch (phba->pci_dev_grp) {
+	case LPFC_PCI_DEV_LP:
+		rc = lpfc_io_slot_reset_s3(pdev);
+		break;
+	case LPFC_PCI_DEV_OC:
+		rc = lpfc_io_slot_reset_s4(pdev);
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1428 Invalid PCI device group: 0x%x\n",
+				phba->pci_dev_grp);
+		break;
+	}
+	return rc;
+}
+
+/**
+ * lpfc_io_resume - lpfc method for resuming PCI I/O operation
+ * @pdev: pointer to PCI device
+ *
+ * This routine is registered to the PCI subsystem for error handling. It
+ * is called when kernel error recovery tells the lpfc driver that it is
+ * OK to resume normal PCI operation after PCI bus error recovery. When
+ * this routine is invoked, it dispatches the action to the proper SLI-3
+ * or SLI-4 device io_resume routine, which will resume the device operation.
+ **/
+static void
+lpfc_io_resume(struct pci_dev *pdev)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+	switch (phba->pci_dev_grp) {
+	case LPFC_PCI_DEV_LP:
+		lpfc_io_resume_s3(pdev);
+		break;
+	case LPFC_PCI_DEV_OC:
+		lpfc_io_resume_s4(pdev);
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1429 Invalid PCI device group: 0x%x\n",
+				phba->pci_dev_grp);
+		break;
+	}
+	return;
+}
+
 static struct pci_device_id lpfc_id_table[] = {
 	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER,
 		PCI_ANY_ID, PCI_ANY_ID, },
@@ -3469,6 +7939,10 @@
 		PCI_ANY_ID, PCI_ANY_ID, },
 	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_S,
 		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK_S,
+		PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0 }
 };
 
@@ -3486,7 +7960,7 @@
 	.probe		= lpfc_pci_probe_one,
 	.remove		= __devexit_p(lpfc_pci_remove_one),
 	.suspend        = lpfc_pci_suspend_one,
-	.resume         = lpfc_pci_resume_one,
+	.resume		= lpfc_pci_resume_one,
 	.err_handler    = &lpfc_err_handler,
 };
 
diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h
index 1aa8570..954ba57 100644
--- a/drivers/scsi/lpfc/lpfc_logmsg.h
+++ b/drivers/scsi/lpfc/lpfc_logmsg.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -18,33 +18,39 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LOG_ELS                       0x1	/* ELS events */
-#define LOG_DISCOVERY                 0x2	/* Link discovery events */
-#define LOG_MBOX                      0x4	/* Mailbox events */
-#define LOG_INIT                      0x8	/* Initialization events */
-#define LOG_LINK_EVENT                0x10	/* Link events */
-#define LOG_IP                        0x20	/* IP traffic history */
-#define LOG_FCP                       0x40	/* FCP traffic history */
-#define LOG_NODE                      0x80	/* Node table events */
-#define LOG_TEMP                      0x100	/* Temperature sensor events */
-#define LOG_BG			      0x200	/* BlockGuard events */
-#define LOG_MISC                      0x400	/* Miscellaneous events */
-#define LOG_SLI                       0x800	/* SLI events */
-#define LOG_FCP_ERROR                 0x1000	/* log errors, not underruns */
-#define LOG_LIBDFC                    0x2000	/* Libdfc events */
-#define LOG_VPORT                     0x4000	/* NPIV events */
-#define LOG_ALL_MSG                   0xffff	/* LOG all messages */
+#define LOG_ELS		0x00000001	/* ELS events */
+#define LOG_DISCOVERY	0x00000002	/* Link discovery events */
+#define LOG_MBOX	0x00000004	/* Mailbox events */
+#define LOG_INIT	0x00000008	/* Initialization events */
+#define LOG_LINK_EVENT	0x00000010	/* Link events */
+#define LOG_IP		0x00000020	/* IP traffic history */
+#define LOG_FCP		0x00000040	/* FCP traffic history */
+#define LOG_NODE	0x00000080	/* Node table events */
+#define LOG_TEMP	0x00000100	/* Temperature sensor events */
+#define LOG_BG		0x00000200	/* BlockGuard events */
+#define LOG_MISC	0x00000400	/* Miscellaneous events */
+#define LOG_SLI		0x00000800	/* SLI events */
+#define LOG_FCP_ERROR	0x00001000	/* log errors, not underruns */
+#define LOG_LIBDFC	0x00002000	/* Libdfc events */
+#define LOG_VPORT	0x00004000	/* NPIV events */
+#define LOF_SECURITY	0x00008000	/* Security events */
+#define LOG_EVENT	0x00010000	/* CT,TEMP,DUMP, logging */
+#define LOG_ALL_MSG	0xffffffff	/* LOG all messages */
 
 #define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \
-	do { \
-	{ if (((mask) &(vport)->cfg_log_verbose) || (level[1] <= '3')) \
+do { \
+	{ if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '3')) \
 		dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \
 			   fmt, (vport)->phba->brd_no, vport->vpi, ##arg); } \
-	} while (0)
+} while (0)
 
 #define lpfc_printf_log(phba, level, mask, fmt, arg...) \
-	do { \
-	{ if (((mask) &(phba)->pport->cfg_log_verbose) || (level[1] <= '3')) \
+do { \
+	{ uint32_t log_verbose = (phba)->pport ? \
+				 (phba)->pport->cfg_log_verbose : \
+				 (phba)->cfg_log_verbose; \
+	  if (((mask) & log_verbose) || (level[1] <= '3')) \
 		dev_printk(level, &((phba)->pcidev)->dev, "%d:" \
-			   fmt, phba->brd_no, ##arg); } \
-	} while (0)
+			   fmt, phba->brd_no, ##arg); \
+	} \
+} while (0)
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 134fc7f..b9b451c 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -28,8 +28,10 @@
 
 #include <scsi/scsi.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -39,6 +41,44 @@
 #include "lpfc_compat.h"
 
 /**
+ * lpfc_dump_static_vport - Dump HBA's static vport information.
+ * @phba: pointer to lpfc hba data structure.
+ * @pmb: pointer to the driver internal queue element for mailbox command.
+ * @offset: offset for dumping vport info.
+ *
+ * The dump mailbox command provides a method for the device driver to obtain
+ * various types of information from the HBA device.
+ *
+ * This routine prepares the mailbox command for dumping list of static
+ * vports to be created.
+ **/
+void
+lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb,
+		uint16_t offset)
+{
+	MAILBOX_t *mb;
+	void *ctx;
+
+	mb = &pmb->u.mb;
+	ctx = pmb->context2;
+
+	/* Setup to dump vport info region */
+	memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
+	mb->mbxCommand = MBX_DUMP_MEMORY;
+	mb->un.varDmp.cv = 1;
+	mb->un.varDmp.type = DMP_NV_PARAMS;
+	mb->un.varDmp.entry_index = offset;
+	mb->un.varDmp.region_id = DMP_REGION_VPORT;
+	mb->un.varDmp.word_cnt = DMP_RSP_SIZE/sizeof(uint32_t);
+	mb->un.varDmp.co = 0;
+	mb->un.varDmp.resp_offset = 0;
+	pmb->context2 = ctx;
+	mb->mbxOwner = OWN_HOST;
+
+	return;
+}
+
+/**
  * lpfc_dump_mem - Prepare a mailbox command for retrieving HBA's VPD memory
  * @phba: pointer to lpfc hba data structure.
  * @pmb: pointer to the driver internal queue element for mailbox command.
@@ -58,7 +98,7 @@
 	MAILBOX_t *mb;
 	void *ctx;
 
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 	ctx = pmb->context2;
 
 	/* Setup to dump VPD region */
@@ -90,7 +130,7 @@
 	MAILBOX_t *mb;
 	void *ctx;
 
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 	/* Save context so that we can restore after memset */
 	ctx = pmb->context2;
 
@@ -125,7 +165,7 @@
 {
 	MAILBOX_t *mb;
 
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 	mb->mbxCommand = MBX_READ_NV;
 	mb->mbxOwner = OWN_HOST;
@@ -151,7 +191,7 @@
 {
 	MAILBOX_t *mb;
 
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 	mb->mbxCommand = MBX_ASYNCEVT_ENABLE;
 	mb->un.varCfgAsyncEvent.ring = ring;
@@ -177,7 +217,7 @@
 {
 	MAILBOX_t *mb;
 
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 	mb->mbxCommand = MBX_HEARTBEAT;
 	mb->mbxOwner = OWN_HOST;
@@ -211,7 +251,7 @@
 	struct lpfc_sli *psli;
 
 	psli = &phba->sli;
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
 	INIT_LIST_HEAD(&mp->list);
@@ -248,7 +288,7 @@
 {
 	MAILBOX_t *mb;
 
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
 	mb->un.varClearLA.eventTag = phba->fc_eventTag;
@@ -275,7 +315,7 @@
 lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
 	struct lpfc_vport  *vport = phba->pport;
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
 	/* NEW_FEATURE
@@ -321,7 +361,7 @@
 int
 lpfc_config_msi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	uint32_t attentionConditions[2];
 
 	/* Sanity check */
@@ -405,7 +445,7 @@
 	struct lpfc_sli *psli;
 	MAILBOX_t *mb;
 
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
 	psli = &phba->sli;
@@ -492,7 +532,7 @@
 	struct lpfc_sli *psli;
 
 	psli = &phba->sli;
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
 	mb->mbxOwner = OWN_HOST;
@@ -515,7 +555,7 @@
 	mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
 	mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(mp->phys);
 	mb->un.varRdSparm.un.sp64.addrLow = putPaddrLow(mp->phys);
-	mb->un.varRdSparm.vpi = vpi;
+	mb->un.varRdSparm.vpi = vpi + phba->vpi_base;
 
 	/* save address for completion */
 	pmb->context1 = mp;
@@ -544,10 +584,12 @@
 {
 	MAILBOX_t *mb;
 
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
 	mb->un.varUnregDID.did = did;
+	if (vpi != 0xffff)
+		vpi += phba->vpi_base;
 	mb->un.varUnregDID.vpi = vpi;
 
 	mb->mbxCommand = MBX_UNREG_D_ID;
@@ -573,7 +615,7 @@
 {
 	MAILBOX_t *mb;
 
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
 	mb->mbxCommand = MBX_READ_CONFIG;
@@ -598,7 +640,7 @@
 {
 	MAILBOX_t *mb;
 
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
 	mb->mbxCommand = MBX_READ_LNK_STAT;
@@ -607,7 +649,7 @@
 }
 
 /**
- * lpfc_reg_login - Prepare a mailbox command for registering remote login
+ * lpfc_reg_rpi - Prepare a mailbox command for registering remote login
  * @phba: pointer to lpfc hba data structure.
  * @vpi: virtual N_Port identifier.
  * @did: remote port identifier.
@@ -631,17 +673,23 @@
  *    1 - DMA memory allocation failed
  **/
 int
-lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
+lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
 	       uint8_t *param, LPFC_MBOXQ_t *pmb, uint32_t flag)
 {
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	uint8_t *sparam;
 	struct lpfc_dmabuf *mp;
 
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
 	mb->un.varRegLogin.rpi = 0;
-	mb->un.varRegLogin.vpi = vpi;
+	if (phba->sli_rev == LPFC_SLI_REV4) {
+		mb->un.varRegLogin.rpi = lpfc_sli4_alloc_rpi(phba);
+		if (mb->un.varRegLogin.rpi == LPFC_RPI_ALLOC_ERROR)
+			return 1;
+	}
+
+	mb->un.varRegLogin.vpi = vpi + phba->vpi_base;
 	mb->un.varRegLogin.did = did;
 	mb->un.varWords[30] = flag;	/* Set flag to issue action on cmpl */
 
@@ -697,15 +745,16 @@
 {
 	MAILBOX_t *mb;
 
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
 	mb->un.varUnregLogin.rpi = (uint16_t) rpi;
 	mb->un.varUnregLogin.rsvd1 = 0;
-	mb->un.varUnregLogin.vpi = vpi;
+	mb->un.varUnregLogin.vpi = vpi + phba->vpi_base;
 
 	mb->mbxCommand = MBX_UNREG_LOGIN;
 	mb->mbxOwner = OWN_HOST;
+
 	return;
 }
 
@@ -725,15 +774,15 @@
  * This routine prepares the mailbox command for registering a virtual N_Port.
  **/
 void
-lpfc_reg_vpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t sid,
-	     LPFC_MBOXQ_t *pmb)
+lpfc_reg_vpi(struct lpfc_vport *vport, LPFC_MBOXQ_t *pmb)
 {
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
-	mb->un.varRegVpi.vpi = vpi;
-	mb->un.varRegVpi.sid = sid;
+	mb->un.varRegVpi.vpi = vport->vpi + vport->phba->vpi_base;
+	mb->un.varRegVpi.sid = vport->fc_myDID;
+	mb->un.varRegVpi.vfi = vport->vfi + vport->phba->vfi_base;
 
 	mb->mbxCommand = MBX_REG_VPI;
 	mb->mbxOwner = OWN_HOST;
@@ -760,10 +809,10 @@
 void
 lpfc_unreg_vpi(struct lpfc_hba *phba, uint16_t vpi, LPFC_MBOXQ_t *pmb)
 {
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
-	mb->un.varUnregVpi.vpi = vpi;
+	mb->un.varUnregVpi.vpi = vpi + phba->vpi_base;
 
 	mb->mbxCommand = MBX_UNREG_VPI;
 	mb->mbxOwner = OWN_HOST;
@@ -852,7 +901,7 @@
 void
 lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 	mb->un.varRdRev.cv = 1;
 	mb->un.varRdRev.v3req = 1; /* Request SLI3 info */
@@ -945,7 +994,7 @@
 		uint32_t hbq_entry_index, LPFC_MBOXQ_t *pmb)
 {
 	int i;
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	struct config_hbq_var *hbqmb = &mb->un.varCfgHbq;
 
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
@@ -1020,7 +1069,7 @@
 lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb)
 {
 	int i;
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	struct lpfc_sli *psli;
 	struct lpfc_sli_ring *pring;
 
@@ -1075,7 +1124,7 @@
 lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
 	MAILBOX_t __iomem *mb_slim = (MAILBOX_t __iomem *) phba->MBslimaddr;
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	dma_addr_t pdma_addr;
 	uint32_t bar_low, bar_high;
 	size_t offset;
@@ -1099,21 +1148,22 @@
 
 	/* If HBA supports SLI=3 ask for it */
 
-	if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) {
+	if (phba->sli_rev == LPFC_SLI_REV3 && phba->vpd.sli3Feat.cerbm) {
 		if (phba->cfg_enable_bg)
 			mb->un.varCfgPort.cbg = 1; /* configure BlockGuard */
+		mb->un.varCfgPort.cdss = 1; /* Configure Security */
 		mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
 		mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */
 		mb->un.varCfgPort.cinb = 1; /* Interrupt Notification Block */
 		mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count();
 		if (phba->max_vpi && phba->cfg_enable_npiv &&
 		    phba->vpd.sli3Feat.cmv) {
-			mb->un.varCfgPort.max_vpi = phba->max_vpi;
+			mb->un.varCfgPort.max_vpi = LPFC_MAX_VPI;
 			mb->un.varCfgPort.cmv = 1;
 		} else
 			mb->un.varCfgPort.max_vpi = phba->max_vpi = 0;
 	} else
-		phba->sli_rev = 2;
+		phba->sli_rev = LPFC_SLI_REV2;
 	mb->un.varCfgPort.sli_mode = phba->sli_rev;
 
 	/* Now setup pcb */
@@ -1245,7 +1295,7 @@
 void
 lpfc_kill_board(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 
 	memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
 	mb->mbxCommand = MBX_KILL_BOARD;
@@ -1305,29 +1355,98 @@
 }
 
 /**
+ * __lpfc_mbox_cmpl_put - Put mailbox cmd into mailbox cmd complete list
+ * @phba: pointer to lpfc hba data structure.
+ * @mbq: pointer to the driver internal queue element for mailbox command.
+ *
+ * This routine put the completed mailbox command into the mailbox command
+ * complete list. This is the unlocked version of the routine. The mailbox
+ * complete list is used by the driver worker thread to process mailbox
+ * complete callback functions outside the driver interrupt handler.
+ **/
+void
+__lpfc_mbox_cmpl_put(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbq)
+{
+	list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl);
+}
+
+/**
  * lpfc_mbox_cmpl_put - Put mailbox command into mailbox command complete list
  * @phba: pointer to lpfc hba data structure.
  * @mbq: pointer to the driver internal queue element for mailbox command.
  *
  * This routine put the completed mailbox command into the mailbox command
- * complete list. This routine is called from driver interrupt handler
- * context.The mailbox complete list is used by the driver worker thread
- * to process mailbox complete callback functions outside the driver interrupt
- * handler.
+ * complete list. This is the locked version of the routine. The mailbox
+ * complete list is used by the driver worker thread to process mailbox
+ * complete callback functions outside the driver interrupt handler.
  **/
 void
-lpfc_mbox_cmpl_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq)
+lpfc_mbox_cmpl_put(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbq)
 {
 	unsigned long iflag;
 
 	/* This function expects to be called from interrupt context */
 	spin_lock_irqsave(&phba->hbalock, iflag);
-	list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl);
+	__lpfc_mbox_cmpl_put(phba, mbq);
 	spin_unlock_irqrestore(&phba->hbalock, iflag);
 	return;
 }
 
 /**
+ * lpfc_mbox_cmd_check - Check the validality of a mailbox command
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: pointer to the driver internal queue element for mailbox command.
+ *
+ * This routine is to check whether a mailbox command is valid to be issued.
+ * This check will be performed by both the mailbox issue API when a client
+ * is to issue a mailbox command to the mailbox transport.
+ *
+ * Return 0 - pass the check, -ENODEV - fail the check
+ **/
+int
+lpfc_mbox_cmd_check(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+	/* Mailbox command that have a completion handler must also have a
+	 * vport specified.
+	 */
+	if (mboxq->mbox_cmpl && mboxq->mbox_cmpl != lpfc_sli_def_mbox_cmpl &&
+	    mboxq->mbox_cmpl != lpfc_sli_wake_mbox_wait) {
+		if (!mboxq->vport) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT,
+					"1814 Mbox x%x failed, no vport\n",
+					mboxq->u.mb.mbxCommand);
+			dump_stack();
+			return -ENODEV;
+		}
+	}
+	return 0;
+}
+
+/**
+ * lpfc_mbox_dev_check - Check the device state for issuing a mailbox command
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is to check whether the HBA device is ready for posting a
+ * mailbox command. It is used by the mailbox transport API at the time the
+ * to post a mailbox command to the device.
+ *
+ * Return 0 - pass the check, -ENODEV - fail the check
+ **/
+int
+lpfc_mbox_dev_check(struct lpfc_hba *phba)
+{
+	/* If the PCI channel is in offline state, do not issue mbox */
+	if (unlikely(pci_channel_offline(phba->pcidev)))
+		return -ENODEV;
+
+	/* If the HBA is in error state, do not issue mbox */
+	if (phba->link_state == LPFC_HBA_ERROR)
+		return -ENODEV;
+
+	return 0;
+}
+
+/**
  * lpfc_mbox_tmo_val - Retrieve mailbox command timeout value
  * @phba: pointer to lpfc hba data structure.
  * @cmd: mailbox command code.
@@ -1350,6 +1469,475 @@
 	case MBX_WRITE_WWN:     /* 0x98 */
 	case MBX_LOAD_EXP_ROM:	/* 0x9C */
 		return LPFC_MBOX_TMO_FLASH_CMD;
+	case MBX_SLI4_CONFIG:	/* 0x9b */
+		return LPFC_MBOX_SLI4_CONFIG_TMO;
 	}
 	return LPFC_MBOX_TMO;
 }
+
+/**
+ * lpfc_sli4_mbx_sge_set - Set a sge entry in non-embedded mailbox command
+ * @mbox: pointer to lpfc mbox command.
+ * @sgentry: sge entry index.
+ * @phyaddr: physical address for the sge
+ * @length: Length of the sge.
+ *
+ * This routine sets up an entry in the non-embedded mailbox command at the sge
+ * index location.
+ **/
+void
+lpfc_sli4_mbx_sge_set(struct lpfcMboxq *mbox, uint32_t sgentry,
+		      dma_addr_t phyaddr, uint32_t length)
+{
+	struct lpfc_mbx_nembed_cmd *nembed_sge;
+
+	nembed_sge = (struct lpfc_mbx_nembed_cmd *)
+				&mbox->u.mqe.un.nembed_cmd;
+	nembed_sge->sge[sgentry].pa_lo = putPaddrLow(phyaddr);
+	nembed_sge->sge[sgentry].pa_hi = putPaddrHigh(phyaddr);
+	nembed_sge->sge[sgentry].length = length;
+}
+
+/**
+ * lpfc_sli4_mbx_sge_get - Get a sge entry from non-embedded mailbox command
+ * @mbox: pointer to lpfc mbox command.
+ * @sgentry: sge entry index.
+ *
+ * This routine gets an entry from the non-embedded mailbox command at the sge
+ * index location.
+ **/
+void
+lpfc_sli4_mbx_sge_get(struct lpfcMboxq *mbox, uint32_t sgentry,
+		      struct lpfc_mbx_sge *sge)
+{
+	struct lpfc_mbx_nembed_cmd *nembed_sge;
+
+	nembed_sge = (struct lpfc_mbx_nembed_cmd *)
+				&mbox->u.mqe.un.nembed_cmd;
+	sge->pa_lo = nembed_sge->sge[sgentry].pa_lo;
+	sge->pa_hi = nembed_sge->sge[sgentry].pa_hi;
+	sge->length = nembed_sge->sge[sgentry].length;
+}
+
+/**
+ * lpfc_sli4_mbox_cmd_free - Free a sli4 mailbox command
+ * @phba: pointer to lpfc hba data structure.
+ * @mbox: pointer to lpfc mbox command.
+ *
+ * This routine frees SLI4 specific mailbox command for sending IOCTL command.
+ **/
+void
+lpfc_sli4_mbox_cmd_free(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
+{
+	struct lpfc_mbx_sli4_config *sli4_cfg;
+	struct lpfc_mbx_sge sge;
+	dma_addr_t phyaddr;
+	uint32_t sgecount, sgentry;
+
+	sli4_cfg = &mbox->u.mqe.un.sli4_config;
+
+	/* For embedded mbox command, just free the mbox command */
+	if (bf_get(lpfc_mbox_hdr_emb, &sli4_cfg->header.cfg_mhdr)) {
+		mempool_free(mbox, phba->mbox_mem_pool);
+		return;
+	}
+
+	/* For non-embedded mbox command, we need to free the pages first */
+	sgecount = bf_get(lpfc_mbox_hdr_sge_cnt, &sli4_cfg->header.cfg_mhdr);
+	/* There is nothing we can do if there is no sge address array */
+	if (unlikely(!mbox->sge_array)) {
+		mempool_free(mbox, phba->mbox_mem_pool);
+		return;
+	}
+	/* Each non-embedded DMA memory was allocated in the length of a page */
+	for (sgentry = 0; sgentry < sgecount; sgentry++) {
+		lpfc_sli4_mbx_sge_get(mbox, sgentry, &sge);
+		phyaddr = getPaddr(sge.pa_hi, sge.pa_lo);
+		dma_free_coherent(&phba->pcidev->dev, PAGE_SIZE,
+				  mbox->sge_array->addr[sgentry], phyaddr);
+	}
+	/* Free the sge address array memory */
+	kfree(mbox->sge_array);
+	/* Finally, free the mailbox command itself */
+	mempool_free(mbox, phba->mbox_mem_pool);
+}
+
+/**
+ * lpfc_sli4_config - Initialize the  SLI4 Config Mailbox command
+ * @phba: pointer to lpfc hba data structure.
+ * @mbox: pointer to lpfc mbox command.
+ * @subsystem: The sli4 config sub mailbox subsystem.
+ * @opcode: The sli4 config sub mailbox command opcode.
+ * @length: Length of the sli4 config mailbox command.
+ *
+ * This routine sets up the header fields of SLI4 specific mailbox command
+ * for sending IOCTL command.
+ *
+ * Return: the actual length of the mbox command allocated (mostly useful
+ *         for none embedded mailbox command).
+ **/
+int
+lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
+		 uint8_t subsystem, uint8_t opcode, uint32_t length, bool emb)
+{
+	struct lpfc_mbx_sli4_config *sli4_config;
+	union lpfc_sli4_cfg_shdr *cfg_shdr = NULL;
+	uint32_t alloc_len;
+	uint32_t resid_len;
+	uint32_t pagen, pcount;
+	void *viraddr;
+	dma_addr_t phyaddr;
+
+	/* Set up SLI4 mailbox command header fields */
+	memset(mbox, 0, sizeof(*mbox));
+	bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_SLI4_CONFIG);
+
+	/* Set up SLI4 ioctl command header fields */
+	sli4_config = &mbox->u.mqe.un.sli4_config;
+
+	/* Setup for the embedded mbox command */
+	if (emb) {
+		/* Set up main header fields */
+		bf_set(lpfc_mbox_hdr_emb, &sli4_config->header.cfg_mhdr, 1);
+		sli4_config->header.cfg_mhdr.payload_length =
+					LPFC_MBX_CMD_HDR_LENGTH + length;
+		/* Set up sub-header fields following main header */
+		bf_set(lpfc_mbox_hdr_opcode,
+			&sli4_config->header.cfg_shdr.request, opcode);
+		bf_set(lpfc_mbox_hdr_subsystem,
+			&sli4_config->header.cfg_shdr.request, subsystem);
+		sli4_config->header.cfg_shdr.request.request_length = length;
+		return length;
+	}
+
+	/* Setup for the none-embedded mbox command */
+	pcount = (PAGE_ALIGN(length))/PAGE_SIZE;
+	pcount = (pcount > LPFC_SLI4_MBX_SGE_MAX_PAGES) ?
+				LPFC_SLI4_MBX_SGE_MAX_PAGES : pcount;
+	/* Allocate record for keeping SGE virtual addresses */
+	mbox->sge_array = kmalloc(sizeof(struct lpfc_mbx_nembed_sge_virt),
+				  GFP_KERNEL);
+	if (!mbox->sge_array)
+		return 0;
+
+	for (pagen = 0, alloc_len = 0; pagen < pcount; pagen++) {
+		/* The DMA memory is always allocated in the length of a
+		 * page even though the last SGE might not fill up to a
+		 * page, this is used as a priori size of PAGE_SIZE for
+		 * the later DMA memory free.
+		 */
+		viraddr = dma_alloc_coherent(&phba->pcidev->dev, PAGE_SIZE,
+					     &phyaddr, GFP_KERNEL);
+		/* In case of malloc fails, proceed with whatever we have */
+		if (!viraddr)
+			break;
+		mbox->sge_array->addr[pagen] = viraddr;
+		/* Keep the first page for later sub-header construction */
+		if (pagen == 0)
+			cfg_shdr = (union lpfc_sli4_cfg_shdr *)viraddr;
+		resid_len = length - alloc_len;
+		if (resid_len > PAGE_SIZE) {
+			lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr,
+					      PAGE_SIZE);
+			alloc_len += PAGE_SIZE;
+		} else {
+			lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr,
+					      resid_len);
+			alloc_len = length;
+		}
+	}
+
+	/* Set up main header fields in mailbox command */
+	sli4_config->header.cfg_mhdr.payload_length = alloc_len;
+	bf_set(lpfc_mbox_hdr_sge_cnt, &sli4_config->header.cfg_mhdr, pagen);
+
+	/* Set up sub-header fields into the first page */
+	if (pagen > 0) {
+		bf_set(lpfc_mbox_hdr_opcode, &cfg_shdr->request, opcode);
+		bf_set(lpfc_mbox_hdr_subsystem, &cfg_shdr->request, subsystem);
+		cfg_shdr->request.request_length =
+				alloc_len - sizeof(union  lpfc_sli4_cfg_shdr);
+	}
+	/* The sub-header is in DMA memory, which needs endian converstion */
+	lpfc_sli_pcimem_bcopy(cfg_shdr, cfg_shdr,
+			      sizeof(union  lpfc_sli4_cfg_shdr));
+
+	return alloc_len;
+}
+
+/**
+ * lpfc_sli4_mbox_opcode_get - Get the opcode from a sli4 mailbox command
+ * @phba: pointer to lpfc hba data structure.
+ * @mbox: pointer to lpfc mbox command.
+ *
+ * This routine gets the opcode from a SLI4 specific mailbox command for
+ * sending IOCTL command. If the mailbox command is not MBX_SLI4_CONFIG
+ * (0x9B) or if the IOCTL sub-header is not present, opcode 0x0 shall be
+ * returned.
+ **/
+uint8_t
+lpfc_sli4_mbox_opcode_get(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
+{
+	struct lpfc_mbx_sli4_config *sli4_cfg;
+	union lpfc_sli4_cfg_shdr *cfg_shdr;
+
+	if (mbox->u.mb.mbxCommand != MBX_SLI4_CONFIG)
+		return 0;
+	sli4_cfg = &mbox->u.mqe.un.sli4_config;
+
+	/* For embedded mbox command, get opcode from embedded sub-header*/
+	if (bf_get(lpfc_mbox_hdr_emb, &sli4_cfg->header.cfg_mhdr)) {
+		cfg_shdr = &mbox->u.mqe.un.sli4_config.header.cfg_shdr;
+		return bf_get(lpfc_mbox_hdr_opcode, &cfg_shdr->request);
+	}
+
+	/* For non-embedded mbox command, get opcode from first dma page */
+	if (unlikely(!mbox->sge_array))
+		return 0;
+	cfg_shdr = (union lpfc_sli4_cfg_shdr *)mbox->sge_array->addr[0];
+	return bf_get(lpfc_mbox_hdr_opcode, &cfg_shdr->request);
+}
+
+/**
+ * lpfc_request_features: Configure SLI4 REQUEST_FEATURES mailbox
+ * @mboxq: pointer to lpfc mbox command.
+ *
+ * This routine sets up the mailbox for an SLI4 REQUEST_FEATURES
+ * mailbox command.
+ **/
+void
+lpfc_request_features(struct lpfc_hba *phba, struct lpfcMboxq *mboxq)
+{
+	/* Set up SLI4 mailbox command header fields */
+	memset(mboxq, 0, sizeof(LPFC_MBOXQ_t));
+	bf_set(lpfc_mqe_command, &mboxq->u.mqe, MBX_SLI4_REQ_FTRS);
+
+	/* Set up host requested features. */
+	bf_set(lpfc_mbx_rq_ftr_rq_fcpi, &mboxq->u.mqe.un.req_ftrs, 1);
+
+	/* Virtual fabrics and FIPs are not supported yet. */
+	bf_set(lpfc_mbx_rq_ftr_rq_ifip, &mboxq->u.mqe.un.req_ftrs, 0);
+
+	/* Enable DIF (block guard) only if configured to do so. */
+	if (phba->cfg_enable_bg)
+		bf_set(lpfc_mbx_rq_ftr_rq_dif, &mboxq->u.mqe.un.req_ftrs, 1);
+
+	/* Enable NPIV only if configured to do so. */
+	if (phba->max_vpi && phba->cfg_enable_npiv)
+		bf_set(lpfc_mbx_rq_ftr_rq_npiv, &mboxq->u.mqe.un.req_ftrs, 1);
+
+	return;
+}
+
+/**
+ * lpfc_init_vfi - Initialize the INIT_VFI mailbox command
+ * @mbox: pointer to lpfc mbox command to initialize.
+ * @vport: Vport associated with the VF.
+ *
+ * This routine initializes @mbox to all zeros and then fills in the mailbox
+ * fields from @vport. INIT_VFI configures virtual fabrics identified by VFI
+ * in the context of an FCF. The driver issues this command to setup a VFI
+ * before issuing a FLOGI to login to the VSAN. The driver should also issue a
+ * REG_VFI after a successful VSAN login.
+ **/
+void
+lpfc_init_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport)
+{
+	struct lpfc_mbx_init_vfi *init_vfi;
+
+	memset(mbox, 0, sizeof(*mbox));
+	init_vfi = &mbox->u.mqe.un.init_vfi;
+	bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_INIT_VFI);
+	bf_set(lpfc_init_vfi_vr, init_vfi, 1);
+	bf_set(lpfc_init_vfi_vt, init_vfi, 1);
+	bf_set(lpfc_init_vfi_vfi, init_vfi, vport->vfi + vport->phba->vfi_base);
+	bf_set(lpfc_init_vfi_fcfi, init_vfi, vport->phba->fcf.fcfi);
+}
+
+/**
+ * lpfc_reg_vfi - Initialize the REG_VFI mailbox command
+ * @mbox: pointer to lpfc mbox command to initialize.
+ * @vport: vport associated with the VF.
+ * @phys: BDE DMA bus address used to send the service parameters to the HBA.
+ *
+ * This routine initializes @mbox to all zeros and then fills in the mailbox
+ * fields from @vport, and uses @buf as a DMAable buffer to send the vport's
+ * fc service parameters to the HBA for this VFI. REG_VFI configures virtual
+ * fabrics identified by VFI in the context of an FCF.
+ **/
+void
+lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
+{
+	struct lpfc_mbx_reg_vfi *reg_vfi;
+
+	memset(mbox, 0, sizeof(*mbox));
+	reg_vfi = &mbox->u.mqe.un.reg_vfi;
+	bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_REG_VFI);
+	bf_set(lpfc_reg_vfi_vp, reg_vfi, 1);
+	bf_set(lpfc_reg_vfi_vfi, reg_vfi, vport->vfi + vport->phba->vfi_base);
+	bf_set(lpfc_reg_vfi_fcfi, reg_vfi, vport->phba->fcf.fcfi);
+	bf_set(lpfc_reg_vfi_vpi, reg_vfi, vport->vpi + vport->phba->vpi_base);
+	reg_vfi->bde.addrHigh = putPaddrHigh(phys);
+	reg_vfi->bde.addrLow = putPaddrLow(phys);
+	reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam);
+	reg_vfi->bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+	bf_set(lpfc_reg_vfi_nport_id, reg_vfi, vport->fc_myDID);
+}
+
+/**
+ * lpfc_init_vpi - Initialize the INIT_VPI mailbox command
+ * @mbox: pointer to lpfc mbox command to initialize.
+ * @vpi: VPI to be initialized.
+ *
+ * The INIT_VPI mailbox command supports virtual N_Ports. The driver uses the
+ * command to activate a virtual N_Port. The HBA assigns a MAC address to use
+ * with the virtual N Port.  The SLI Host issues this command before issuing a
+ * FDISC to connect to the Fabric. The SLI Host should issue a REG_VPI after a
+ * successful virtual NPort login.
+ **/
+void
+lpfc_init_vpi(struct lpfcMboxq *mbox, uint16_t vpi)
+{
+	memset(mbox, 0, sizeof(*mbox));
+	bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_INIT_VPI);
+	bf_set(lpfc_init_vpi_vpi, &mbox->u.mqe.un.init_vpi, vpi);
+}
+
+/**
+ * lpfc_unreg_vfi - Initialize the UNREG_VFI mailbox command
+ * @mbox: pointer to lpfc mbox command to initialize.
+ * @vfi: VFI to be unregistered.
+ *
+ * The UNREG_VFI mailbox command causes the SLI Host to put a virtual fabric
+ * (logical NPort) into the inactive state. The SLI Host must have logged out
+ * and unregistered all remote N_Ports to abort any activity on the virtual
+ * fabric. The SLI Port posts the mailbox response after marking the virtual
+ * fabric inactive.
+ **/
+void
+lpfc_unreg_vfi(struct lpfcMboxq *mbox, uint16_t vfi)
+{
+	memset(mbox, 0, sizeof(*mbox));
+	bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_UNREG_VFI);
+	bf_set(lpfc_unreg_vfi_vfi, &mbox->u.mqe.un.unreg_vfi, vfi);
+}
+
+/**
+ * lpfc_dump_fcoe_param - Dump config region 23 to get FCoe parameters.
+ * @phba: pointer to the hba structure containing.
+ * @mbox: pointer to lpfc mbox command to initialize.
+ *
+ * This function create a SLI4 dump mailbox command to dump FCoE
+ * parameters stored in region 23.
+ **/
+int
+lpfc_dump_fcoe_param(struct lpfc_hba *phba,
+		struct lpfcMboxq *mbox)
+{
+	struct lpfc_dmabuf *mp = NULL;
+	MAILBOX_t *mb;
+
+	memset(mbox, 0, sizeof(*mbox));
+	mb = &mbox->u.mb;
+
+	mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+	if (mp)
+		mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+
+	if (!mp || !mp->virt) {
+		kfree(mp);
+		/* dump_fcoe_param failed to allocate memory */
+		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
+			"2569 lpfc_dump_fcoe_param: memory"
+			" allocation failed \n");
+		return 1;
+	}
+
+	memset(mp->virt, 0, LPFC_BPL_SIZE);
+	INIT_LIST_HEAD(&mp->list);
+
+	/* save address for completion */
+	mbox->context1 = (uint8_t *) mp;
+
+	mb->mbxCommand = MBX_DUMP_MEMORY;
+	mb->un.varDmp.type = DMP_NV_PARAMS;
+	mb->un.varDmp.region_id = DMP_REGION_FCOEPARAM;
+	mb->un.varDmp.sli4_length = DMP_FCOEPARAM_RGN_SIZE;
+	mb->un.varWords[3] = putPaddrLow(mp->phys);
+	mb->un.varWords[4] = putPaddrHigh(mp->phys);
+	return 0;
+}
+
+/**
+ * lpfc_reg_fcfi - Initialize the REG_FCFI mailbox command
+ * @phba: pointer to the hba structure containing the FCF index and RQ ID.
+ * @mbox: pointer to lpfc mbox command to initialize.
+ *
+ * The REG_FCFI mailbox command supports Fibre Channel Forwarders (FCFs). The
+ * SLI Host uses the command to activate an FCF after it has acquired FCF
+ * information via a READ_FCF mailbox command. This mailbox command also is used
+ * to indicate where received unsolicited frames from this FCF will be sent. By
+ * default this routine will set up the FCF to forward all unsolicited frames
+ * the the RQ ID passed in the @phba. This can be overridden by the caller for
+ * more complicated setups.
+ **/
+void
+lpfc_reg_fcfi(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
+{
+	struct lpfc_mbx_reg_fcfi *reg_fcfi;
+
+	memset(mbox, 0, sizeof(*mbox));
+	reg_fcfi = &mbox->u.mqe.un.reg_fcfi;
+	bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_REG_FCFI);
+	bf_set(lpfc_reg_fcfi_rq_id0, reg_fcfi, phba->sli4_hba.hdr_rq->queue_id);
+	bf_set(lpfc_reg_fcfi_rq_id1, reg_fcfi, REG_FCF_INVALID_QID);
+	bf_set(lpfc_reg_fcfi_rq_id2, reg_fcfi, REG_FCF_INVALID_QID);
+	bf_set(lpfc_reg_fcfi_rq_id3, reg_fcfi, REG_FCF_INVALID_QID);
+	bf_set(lpfc_reg_fcfi_info_index, reg_fcfi, phba->fcf.fcf_indx);
+	/* reg_fcf addr mode is bit wise inverted value of fcf addr_mode */
+	bf_set(lpfc_reg_fcfi_mam, reg_fcfi,
+		(~phba->fcf.addr_mode) & 0x3);
+	if (phba->fcf.fcf_flag & FCF_VALID_VLAN) {
+		bf_set(lpfc_reg_fcfi_vv, reg_fcfi, 1);
+		bf_set(lpfc_reg_fcfi_vlan_tag, reg_fcfi, phba->fcf.vlan_id);
+	}
+}
+
+/**
+ * lpfc_unreg_fcfi - Initialize the UNREG_FCFI mailbox command
+ * @mbox: pointer to lpfc mbox command to initialize.
+ * @fcfi: FCFI to be unregistered.
+ *
+ * The UNREG_FCFI mailbox command supports Fibre Channel Forwarders (FCFs).
+ * The SLI Host uses the command to inactivate an FCFI.
+ **/
+void
+lpfc_unreg_fcfi(struct lpfcMboxq *mbox, uint16_t fcfi)
+{
+	memset(mbox, 0, sizeof(*mbox));
+	bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_UNREG_FCFI);
+	bf_set(lpfc_unreg_fcfi, &mbox->u.mqe.un.unreg_fcfi, fcfi);
+}
+
+/**
+ * lpfc_resume_rpi - Initialize the RESUME_RPI mailbox command
+ * @mbox: pointer to lpfc mbox command to initialize.
+ * @ndlp: The nodelist structure that describes the RPI to resume.
+ *
+ * The RESUME_RPI mailbox command is used to restart I/O to an RPI after a
+ * link event.
+ **/
+void
+lpfc_resume_rpi(struct lpfcMboxq *mbox, struct lpfc_nodelist *ndlp)
+{
+	struct lpfc_mbx_resume_rpi *resume_rpi;
+
+	memset(mbox, 0, sizeof(*mbox));
+	resume_rpi = &mbox->u.mqe.un.resume_rpi;
+	bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_RESUME_RPI);
+	bf_set(lpfc_resume_rpi_rpi, resume_rpi, ndlp->nlp_rpi);
+	bf_set(lpfc_resume_rpi_vpi, resume_rpi,
+	       ndlp->vport->vpi + ndlp->vport->phba->vpi_base);
+	bf_set(lpfc_resume_rpi_vfi, resume_rpi,
+	       ndlp->vport->vfi + ndlp->vport->phba->vfi_base);
+}
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 35a9767..e198c91 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -28,8 +28,10 @@
 
 #include <scsi/scsi.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -45,7 +47,7 @@
  * @phba: HBA to allocate pools for
  *
  * Description: Creates and allocates PCI pools lpfc_scsi_dma_buf_pool,
- * lpfc_mbuf_pool, lpfc_hbq_pool.  Creates and allocates kmalloc-backed mempools
+ * lpfc_mbuf_pool, lpfc_hrb_pool.  Creates and allocates kmalloc-backed mempools
  * for LPFC_MBOXQ_t and lpfc_nodelist.  Also allocates the VPI bitmask.
  *
  * Notes: Not interrupt-safe.  Must be called with no locks held.  If any
@@ -56,19 +58,30 @@
  *   -ENOMEM on failure (if any memory allocations fail)
  **/
 int
-lpfc_mem_alloc(struct lpfc_hba * phba)
+lpfc_mem_alloc(struct lpfc_hba *phba, int align)
 {
 	struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
 	int longs;
 	int i;
 
-	phba->lpfc_scsi_dma_buf_pool = pci_pool_create("lpfc_scsi_dma_buf_pool",
-				phba->pcidev, phba->cfg_sg_dma_buf_size, 8, 0);
+	if (phba->sli_rev == LPFC_SLI_REV4)
+		phba->lpfc_scsi_dma_buf_pool =
+			pci_pool_create("lpfc_scsi_dma_buf_pool",
+				phba->pcidev,
+				phba->cfg_sg_dma_buf_size,
+				phba->cfg_sg_dma_buf_size,
+				0);
+	else
+		phba->lpfc_scsi_dma_buf_pool =
+			pci_pool_create("lpfc_scsi_dma_buf_pool",
+				phba->pcidev, phba->cfg_sg_dma_buf_size,
+				align, 0);
 	if (!phba->lpfc_scsi_dma_buf_pool)
 		goto fail;
 
 	phba->lpfc_mbuf_pool = pci_pool_create("lpfc_mbuf_pool", phba->pcidev,
-							LPFC_BPL_SIZE, 8,0);
+							LPFC_BPL_SIZE,
+							align, 0);
 	if (!phba->lpfc_mbuf_pool)
 		goto fail_free_dma_buf_pool;
 
@@ -97,23 +110,31 @@
 						sizeof(struct lpfc_nodelist));
 	if (!phba->nlp_mem_pool)
 		goto fail_free_mbox_pool;
-
-	phba->lpfc_hbq_pool = pci_pool_create("lpfc_hbq_pool",phba->pcidev,
-					      LPFC_BPL_SIZE, 8, 0);
-	if (!phba->lpfc_hbq_pool)
+	phba->lpfc_hrb_pool = pci_pool_create("lpfc_hrb_pool",
+					      phba->pcidev,
+					      LPFC_HDR_BUF_SIZE, align, 0);
+	if (!phba->lpfc_hrb_pool)
 		goto fail_free_nlp_mem_pool;
+	phba->lpfc_drb_pool = pci_pool_create("lpfc_drb_pool",
+					      phba->pcidev,
+					      LPFC_DATA_BUF_SIZE, align, 0);
+	if (!phba->lpfc_drb_pool)
+		goto fail_free_hbq_pool;
 
 	/* vpi zero is reserved for the physical port so add 1 to max */
 	longs = ((phba->max_vpi + 1) + BITS_PER_LONG - 1) / BITS_PER_LONG;
 	phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL);
 	if (!phba->vpi_bmask)
-		goto fail_free_hbq_pool;
+		goto fail_free_dbq_pool;
 
 	return 0;
 
+ fail_free_dbq_pool:
+	pci_pool_destroy(phba->lpfc_drb_pool);
+	phba->lpfc_drb_pool = NULL;
  fail_free_hbq_pool:
-	lpfc_sli_hbqbuf_free_all(phba);
-	pci_pool_destroy(phba->lpfc_hbq_pool);
+	pci_pool_destroy(phba->lpfc_hrb_pool);
+	phba->lpfc_hrb_pool = NULL;
  fail_free_nlp_mem_pool:
 	mempool_destroy(phba->nlp_mem_pool);
 	phba->nlp_mem_pool = NULL;
@@ -136,27 +157,73 @@
 }
 
 /**
- * lpfc_mem_free - Frees all PCI and memory allocated by lpfc_mem_alloc
+ * lpfc_mem_free - Frees memory allocated by lpfc_mem_alloc
  * @phba: HBA to free memory for
  *
- * Description: Frees PCI pools lpfc_scsi_dma_buf_pool, lpfc_mbuf_pool,
- * lpfc_hbq_pool.  Frees kmalloc-backed mempools for LPFC_MBOXQ_t and
- * lpfc_nodelist.  Also frees the VPI bitmask
+ * Description: Free the memory allocated by lpfc_mem_alloc routine. This
+ * routine is a the counterpart of lpfc_mem_alloc.
  *
  * Returns: None
  **/
 void
-lpfc_mem_free(struct lpfc_hba * phba)
+lpfc_mem_free(struct lpfc_hba *phba)
+{
+	int i;
+	struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
+
+	/* Free VPI bitmask memory */
+	kfree(phba->vpi_bmask);
+
+	/* Free HBQ pools */
+	lpfc_sli_hbqbuf_free_all(phba);
+	pci_pool_destroy(phba->lpfc_drb_pool);
+	phba->lpfc_drb_pool = NULL;
+	pci_pool_destroy(phba->lpfc_hrb_pool);
+	phba->lpfc_hrb_pool = NULL;
+
+	/* Free NLP memory pool */
+	mempool_destroy(phba->nlp_mem_pool);
+	phba->nlp_mem_pool = NULL;
+
+	/* Free mbox memory pool */
+	mempool_destroy(phba->mbox_mem_pool);
+	phba->mbox_mem_pool = NULL;
+
+	/* Free MBUF memory pool */
+	for (i = 0; i < pool->current_count; i++)
+		pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
+			      pool->elements[i].phys);
+	kfree(pool->elements);
+
+	pci_pool_destroy(phba->lpfc_mbuf_pool);
+	phba->lpfc_mbuf_pool = NULL;
+
+	/* Free DMA buffer memory pool */
+	pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
+	phba->lpfc_scsi_dma_buf_pool = NULL;
+
+	return;
+}
+
+/**
+ * lpfc_mem_free_all - Frees all PCI and driver memory
+ * @phba: HBA to free memory for
+ *
+ * Description: Free memory from PCI and driver memory pools and also those
+ * used : lpfc_scsi_dma_buf_pool, lpfc_mbuf_pool, lpfc_hrb_pool. Frees
+ * kmalloc-backed mempools for LPFC_MBOXQ_t and lpfc_nodelist. Also frees
+ * the VPI bitmask.
+ *
+ * Returns: None
+ **/
+void
+lpfc_mem_free_all(struct lpfc_hba *phba)
 {
 	struct lpfc_sli *psli = &phba->sli;
-	struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
 	LPFC_MBOXQ_t *mbox, *next_mbox;
 	struct lpfc_dmabuf   *mp;
-	int i;
 
-	kfree(phba->vpi_bmask);
-	lpfc_sli_hbqbuf_free_all(phba);
-
+	/* Free memory used in mailbox queue back to mailbox memory pool */
 	list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) {
 		mp = (struct lpfc_dmabuf *) (mbox->context1);
 		if (mp) {
@@ -166,6 +233,7 @@
 		list_del(&mbox->list);
 		mempool_free(mbox, phba->mbox_mem_pool);
 	}
+	/* Free memory used in mailbox cmpl list back to mailbox memory pool */
 	list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq_cmpl, list) {
 		mp = (struct lpfc_dmabuf *) (mbox->context1);
 		if (mp) {
@@ -175,8 +243,10 @@
 		list_del(&mbox->list);
 		mempool_free(mbox, phba->mbox_mem_pool);
 	}
-
+	/* Free the active mailbox command back to the mailbox memory pool */
+	spin_lock_irq(&phba->hbalock);
 	psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+	spin_unlock_irq(&phba->hbalock);
 	if (psli->mbox_active) {
 		mbox = psli->mbox_active;
 		mp = (struct lpfc_dmabuf *) (mbox->context1);
@@ -188,27 +258,14 @@
 		psli->mbox_active = NULL;
 	}
 
-	for (i = 0; i < pool->current_count; i++)
-		pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
-						 pool->elements[i].phys);
-	kfree(pool->elements);
-
-	pci_pool_destroy(phba->lpfc_hbq_pool);
-	mempool_destroy(phba->nlp_mem_pool);
-	mempool_destroy(phba->mbox_mem_pool);
-
-	pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
-	pci_pool_destroy(phba->lpfc_mbuf_pool);
-
-	phba->lpfc_hbq_pool = NULL;
-	phba->nlp_mem_pool = NULL;
-	phba->mbox_mem_pool = NULL;
-	phba->lpfc_scsi_dma_buf_pool = NULL;
-	phba->lpfc_mbuf_pool = NULL;
+	/* Free and destroy all the allocated memory pools */
+	lpfc_mem_free(phba);
 
 	/* Free the iocb lookup array */
 	kfree(psli->iocbq_lookup);
 	psli->iocbq_lookup = NULL;
+
+	return;
 }
 
 /**
@@ -305,7 +362,7 @@
  * lpfc_els_hbq_alloc - Allocate an HBQ buffer
  * @phba: HBA to allocate HBQ buffer for
  *
- * Description: Allocates a DMA-mapped HBQ buffer from the lpfc_hbq_pool PCI
+ * Description: Allocates a DMA-mapped HBQ buffer from the lpfc_hrb_pool PCI
  * pool along a non-DMA-mapped container for it.
  *
  * Notes: Not interrupt-safe.  Must be called with no locks held.
@@ -323,7 +380,7 @@
 	if (!hbqbp)
 		return NULL;
 
-	hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_KERNEL,
+	hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hrb_pool, GFP_KERNEL,
 					  &hbqbp->dbuf.phys);
 	if (!hbqbp->dbuf.virt) {
 		kfree(hbqbp);
@@ -334,7 +391,7 @@
 }
 
 /**
- * lpfc_mem_hbq_free - Frees an HBQ buffer allocated with lpfc_els_hbq_alloc
+ * lpfc_els_hbq_free - Frees an HBQ buffer allocated with lpfc_els_hbq_alloc
  * @phba: HBA buffer was allocated for
  * @hbqbp: HBQ container returned by lpfc_els_hbq_alloc
  *
@@ -348,12 +405,73 @@
 void
 lpfc_els_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp)
 {
-	pci_pool_free(phba->lpfc_hbq_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys);
+	pci_pool_free(phba->lpfc_hrb_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys);
 	kfree(hbqbp);
 	return;
 }
 
 /**
+ * lpfc_sli4_rb_alloc - Allocate an SLI4 Receive buffer
+ * @phba: HBA to allocate a receive buffer for
+ *
+ * Description: Allocates a DMA-mapped receive buffer from the lpfc_hrb_pool PCI
+ * pool along a non-DMA-mapped container for it.
+ *
+ * Notes: Not interrupt-safe.  Must be called with no locks held.
+ *
+ * Returns:
+ *   pointer to HBQ on success
+ *   NULL on failure
+ **/
+struct hbq_dmabuf *
+lpfc_sli4_rb_alloc(struct lpfc_hba *phba)
+{
+	struct hbq_dmabuf *dma_buf;
+
+	dma_buf = kmalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL);
+	if (!dma_buf)
+		return NULL;
+
+	dma_buf->hbuf.virt = pci_pool_alloc(phba->lpfc_hrb_pool, GFP_KERNEL,
+					    &dma_buf->hbuf.phys);
+	if (!dma_buf->hbuf.virt) {
+		kfree(dma_buf);
+		return NULL;
+	}
+	dma_buf->dbuf.virt = pci_pool_alloc(phba->lpfc_drb_pool, GFP_KERNEL,
+					    &dma_buf->dbuf.phys);
+	if (!dma_buf->dbuf.virt) {
+		pci_pool_free(phba->lpfc_hrb_pool, dma_buf->hbuf.virt,
+			      dma_buf->hbuf.phys);
+		kfree(dma_buf);
+		return NULL;
+	}
+	dma_buf->size = LPFC_BPL_SIZE;
+	return dma_buf;
+}
+
+/**
+ * lpfc_sli4_rb_free - Frees a receive buffer
+ * @phba: HBA buffer was allocated for
+ * @dmab: DMA Buffer container returned by lpfc_sli4_hbq_alloc
+ *
+ * Description: Frees both the container and the DMA-mapped buffers returned by
+ * lpfc_sli4_rb_alloc.
+ *
+ * Notes: Can be called with or without locks held.
+ *
+ * Returns: None
+ **/
+void
+lpfc_sli4_rb_free(struct lpfc_hba *phba, struct hbq_dmabuf *dmab)
+{
+	pci_pool_free(phba->lpfc_hrb_pool, dmab->hbuf.virt, dmab->hbuf.phys);
+	pci_pool_free(phba->lpfc_drb_pool, dmab->dbuf.virt, dmab->dbuf.phys);
+	kfree(dmab);
+	return;
+}
+
+/**
  * lpfc_in_buf_free - Free a DMA buffer
  * @phba: HBA buffer is associated with
  * @mp: Buffer to free
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 08cdc77..09f659f 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-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -28,8 +28,10 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -361,7 +363,7 @@
 	if (!mbox)
 		goto out;
 
-	rc = lpfc_reg_login(phba, vport->vpi, icmd->un.rcvels.remoteID,
+	rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
 			    (uint8_t *) sp, mbox, 0);
 	if (rc) {
 		mempool_free(mbox, phba->mbox_mem_pool);
@@ -495,11 +497,19 @@
 		lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
 	else
 		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
+	if ((ndlp->nlp_type & NLP_FABRIC) &&
+		vport->port_type == LPFC_NPIV_PORT) {
+		lpfc_linkdown_port(vport);
+		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
+		spin_lock_irq(shost->host_lock);
+		ndlp->nlp_flag |= NLP_DELAY_TMO;
+		spin_unlock_irq(shost->host_lock);
 
-	if ((!(ndlp->nlp_type & NLP_FABRIC) &&
-	     ((ndlp->nlp_type & NLP_FCP_TARGET) ||
-	      !(ndlp->nlp_type & NLP_FCP_INITIATOR))) ||
-	    (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
+		ndlp->nlp_last_elscmd = ELS_CMD_FDISC;
+	} else if ((!(ndlp->nlp_type & NLP_FABRIC) &&
+		((ndlp->nlp_type & NLP_FCP_TARGET) ||
+		!(ndlp->nlp_type & NLP_FCP_INITIATOR))) ||
+		(ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
 		/* Only try to re-login if this is NOT a Fabric Node */
 		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
 		spin_lock_irq(shost->host_lock);
@@ -567,7 +577,7 @@
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 
-	if (!ndlp->nlp_rpi) {
+	if (!(ndlp->nlp_flag & NLP_RPI_VALID)) {
 		ndlp->nlp_flag &= ~NLP_NPR_ADISC;
 		return 0;
 	}
@@ -857,7 +867,7 @@
 
 	lpfc_unreg_rpi(vport, ndlp);
 
-	if (lpfc_reg_login(phba, vport->vpi, irsp->un.elsreq64.remoteID,
+	if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID,
 			   (uint8_t *) sp, mbox, 0) == 0) {
 		switch (ndlp->nlp_DID) {
 		case NameServer_DID:
@@ -1068,6 +1078,7 @@
 	struct lpfc_iocbq *cmdiocb, *rspiocb;
 	IOCB_t *irsp;
 	ADISC *ap;
+	int rc;
 
 	cmdiocb = (struct lpfc_iocbq *) arg;
 	rspiocb = cmdiocb->context_un.rsp_iocb;
@@ -1093,6 +1104,15 @@
 		return ndlp->nlp_state;
 	}
 
+	if (phba->sli_rev == LPFC_SLI_REV4) {
+		rc = lpfc_sli4_resume_rpi(ndlp);
+		if (rc) {
+			/* Stay in state and retry. */
+			ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
+			return ndlp->nlp_state;
+		}
+	}
+
 	if (ndlp->nlp_type & NLP_FCP_TARGET) {
 		ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
 		lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
@@ -1100,6 +1120,7 @@
 		ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
 		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
 	}
+
 	return ndlp->nlp_state;
 }
 
@@ -1190,7 +1211,7 @@
 
 	/* cleanup any ndlp on mbox q waiting for reglogin cmpl */
 	if ((mb = phba->sli.mbox_active)) {
-		if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+		if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
 		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
 			lpfc_nlp_put(ndlp);
 			mb->context2 = NULL;
@@ -1200,7 +1221,7 @@
 
 	spin_lock_irq(&phba->hbalock);
 	list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
-		if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+		if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
 		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
 			mp = (struct lpfc_dmabuf *) (mb->context1);
 			if (mp) {
@@ -1251,7 +1272,7 @@
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
-	MAILBOX_t *mb = &pmb->mb;
+	MAILBOX_t *mb = &pmb->u.mb;
 	uint32_t did  = mb->un.varWords[1];
 
 	if (mb->mbxStatus) {
@@ -1283,6 +1304,7 @@
 	}
 
 	ndlp->nlp_rpi = mb->un.varWords[0];
+	ndlp->nlp_flag |= NLP_RPI_VALID;
 
 	/* Only if we are not a fabric nport do we issue PRLI */
 	if (!(ndlp->nlp_type & NLP_FABRIC)) {
@@ -1878,11 +1900,12 @@
 			    void *arg, uint32_t evt)
 {
 	LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
-	MAILBOX_t    *mb = &pmb->mb;
+	MAILBOX_t    *mb = &pmb->u.mb;
 
-	if (!mb->mbxStatus)
+	if (!mb->mbxStatus) {
 		ndlp->nlp_rpi = mb->un.varWords[0];
-	else {
+		ndlp->nlp_flag |= NLP_RPI_VALID;
+	} else {
 		if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
 			lpfc_drop_node(vport, ndlp);
 			return NLP_STE_FREED_NODE;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 679adff..7991ba1 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-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -31,8 +31,10 @@
 #include <scsi/scsi_transport_fc.h>
 
 #include "lpfc_version.h"
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -57,6 +59,8 @@
 	"SCSI_PROT_READ_CONVERT",
 	"SCSI_PROT_WRITE_CONVERT"
 };
+static void
+lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);
 
 static void
 lpfc_debug_save_data(struct scsi_cmnd *cmnd)
@@ -325,7 +329,7 @@
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
 			shost = lpfc_shost_from_vport(vports[i]);
 			shost_for_each_device(sdev, shost) {
 				new_queue_depth =
@@ -379,7 +383,7 @@
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
 			shost = lpfc_shost_from_vport(vports[i]);
 			shost_for_each_device(sdev, shost) {
 				if (vports[i]->cfg_lun_queue_depth <=
@@ -427,7 +431,7 @@
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
 			shost = lpfc_shost_from_vport(vports[i]);
 			shost_for_each_device(sdev, shost) {
 				rport = starget_to_rport(scsi_target(sdev));
@@ -438,22 +442,23 @@
 }
 
 /**
- * lpfc_new_scsi_buf - Scsi buffer allocator
+ * lpfc_new_scsi_buf_s3 - Scsi buffer allocator for HBA with SLI3 IF spec
  * @vport: The virtual port for which this call being executed.
+ * @num_to_allocate: The requested number of buffers to allocate.
  *
- * This routine allocates a scsi buffer, which contains all the necessary
- * information needed to initiate a SCSI I/O.  The non-DMAable buffer region
- * contains information to build the IOCB.  The DMAable region contains
- * memory for the FCP CMND, FCP RSP, and the initial BPL.  In addition to
- * allocating memory, the FCP CMND and FCP RSP BDEs are setup in the BPL
- * and the BPL BDE is setup in the IOCB.
+ * This routine allocates a scsi buffer for device with SLI-3 interface spec,
+ * the scsi buffer contains all the necessary information needed to initiate
+ * a SCSI I/O. The non-DMAable buffer region contains information to build
+ * the IOCB. The DMAable region contains memory for the FCP CMND, FCP RSP,
+ * and the initial BPL. In addition to allocating memory, the FCP CMND and
+ * FCP RSP BDEs are setup in the BPL and the BPL BDE is setup in the IOCB.
  *
  * Return codes:
- *   NULL - Error
- *   Pointer to lpfc_scsi_buf data structure - Success
+ *   int - number of scsi buffers that were allocated.
+ *   0 = failure, less than num_to_alloc is a partial failure.
  **/
-static struct lpfc_scsi_buf *
-lpfc_new_scsi_buf(struct lpfc_vport *vport)
+static int
+lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc)
 {
 	struct lpfc_hba *phba = vport->phba;
 	struct lpfc_scsi_buf *psb;
@@ -463,107 +468,401 @@
 	dma_addr_t pdma_phys_fcp_rsp;
 	dma_addr_t pdma_phys_bpl;
 	uint16_t iotag;
+	int bcnt;
 
-	psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
-	if (!psb)
-		return NULL;
+	for (bcnt = 0; bcnt < num_to_alloc; bcnt++) {
+		psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
+		if (!psb)
+			break;
 
-	/*
-	 * Get memory from the pci pool to map the virt space to pci bus space
-	 * for an I/O.  The DMA buffer includes space for the struct fcp_cmnd,
-	 * struct fcp_rsp and the number of bde's necessary to support the
-	 * sg_tablesize.
-	 */
-	psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool, GFP_KERNEL,
-							&psb->dma_handle);
-	if (!psb->data) {
-		kfree(psb);
-		return NULL;
-	}
+		/*
+		 * Get memory from the pci pool to map the virt space to pci
+		 * bus space for an I/O.  The DMA buffer includes space for the
+		 * struct fcp_cmnd, struct fcp_rsp and the number of bde's
+		 * necessary to support the sg_tablesize.
+		 */
+		psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool,
+					GFP_KERNEL, &psb->dma_handle);
+		if (!psb->data) {
+			kfree(psb);
+			break;
+		}
 
-	/* Initialize virtual ptrs to dma_buf region. */
-	memset(psb->data, 0, phba->cfg_sg_dma_buf_size);
+		/* Initialize virtual ptrs to dma_buf region. */
+		memset(psb->data, 0, phba->cfg_sg_dma_buf_size);
 
-	/* Allocate iotag for psb->cur_iocbq. */
-	iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq);
-	if (iotag == 0) {
-		pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
-			      psb->data, psb->dma_handle);
-		kfree (psb);
-		return NULL;
-	}
-	psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP;
+		/* Allocate iotag for psb->cur_iocbq. */
+		iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq);
+		if (iotag == 0) {
+			pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
+					psb->data, psb->dma_handle);
+			kfree(psb);
+			break;
+		}
+		psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP;
 
-	psb->fcp_cmnd = psb->data;
-	psb->fcp_rsp = psb->data + sizeof(struct fcp_cmnd);
-	psb->fcp_bpl = psb->data + sizeof(struct fcp_cmnd) +
-							sizeof(struct fcp_rsp);
-
-	/* Initialize local short-hand pointers. */
-	bpl = psb->fcp_bpl;
-	pdma_phys_fcp_cmd = psb->dma_handle;
-	pdma_phys_fcp_rsp = psb->dma_handle + sizeof(struct fcp_cmnd);
-	pdma_phys_bpl = psb->dma_handle + sizeof(struct fcp_cmnd) +
+		psb->fcp_cmnd = psb->data;
+		psb->fcp_rsp = psb->data + sizeof(struct fcp_cmnd);
+		psb->fcp_bpl = psb->data + sizeof(struct fcp_cmnd) +
 			sizeof(struct fcp_rsp);
 
-	/*
-	 * The first two bdes are the FCP_CMD and FCP_RSP.  The balance are sg
-	 * list bdes.  Initialize the first two and leave the rest for
-	 * queuecommand.
-	 */
-	bpl[0].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_cmd));
-	bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd));
-	bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd);
-	bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
-	bpl[0].tus.w = le32_to_cpu(bpl[0].tus.w);
+		/* Initialize local short-hand pointers. */
+		bpl = psb->fcp_bpl;
+		pdma_phys_fcp_cmd = psb->dma_handle;
+		pdma_phys_fcp_rsp = psb->dma_handle + sizeof(struct fcp_cmnd);
+		pdma_phys_bpl = psb->dma_handle + sizeof(struct fcp_cmnd) +
+			sizeof(struct fcp_rsp);
 
-	/* Setup the physical region for the FCP RSP */
-	bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp));
-	bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp));
-	bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp);
-	bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
-	bpl[1].tus.w = le32_to_cpu(bpl[1].tus.w);
+		/*
+		 * The first two bdes are the FCP_CMD and FCP_RSP. The balance
+		 * are sg list bdes.  Initialize the first two and leave the
+		 * rest for queuecommand.
+		 */
+		bpl[0].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_cmd));
+		bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd));
+		bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd);
+		bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+		bpl[0].tus.w = le32_to_cpu(bpl[0].tus.w);
 
-	/*
-	 * Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf,
-	 * initialize it with all known data now.
-	 */
-	iocb = &psb->cur_iocbq.iocb;
-	iocb->un.fcpi64.bdl.ulpIoTag32 = 0;
-	if ((phba->sli_rev == 3) &&
-	    !(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) {
-		/* fill in immediate fcp command BDE */
-		iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_IMMED;
-		iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd);
-		iocb->un.fcpi64.bdl.addrLow = offsetof(IOCB_t,
-						       unsli3.fcp_ext.icd);
-		iocb->un.fcpi64.bdl.addrHigh = 0;
-		iocb->ulpBdeCount = 0;
-		iocb->ulpLe = 0;
-		/* fill in responce BDE */
-		iocb->unsli3.fcp_ext.rbde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
-		iocb->unsli3.fcp_ext.rbde.tus.f.bdeSize =
-						sizeof(struct fcp_rsp);
-		iocb->unsli3.fcp_ext.rbde.addrLow =
-						putPaddrLow(pdma_phys_fcp_rsp);
-		iocb->unsli3.fcp_ext.rbde.addrHigh =
-						putPaddrHigh(pdma_phys_fcp_rsp);
-	} else {
-		iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
-		iocb->un.fcpi64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64));
-		iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys_bpl);
-		iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys_bpl);
-		iocb->ulpBdeCount = 1;
-		iocb->ulpLe = 1;
+		/* Setup the physical region for the FCP RSP */
+		bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp));
+		bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp));
+		bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp);
+		bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+		bpl[1].tus.w = le32_to_cpu(bpl[1].tus.w);
+
+		/*
+		 * Since the IOCB for the FCP I/O is built into this
+		 * lpfc_scsi_buf, initialize it with all known data now.
+		 */
+		iocb = &psb->cur_iocbq.iocb;
+		iocb->un.fcpi64.bdl.ulpIoTag32 = 0;
+		if ((phba->sli_rev == 3) &&
+				!(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) {
+			/* fill in immediate fcp command BDE */
+			iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_IMMED;
+			iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd);
+			iocb->un.fcpi64.bdl.addrLow = offsetof(IOCB_t,
+					unsli3.fcp_ext.icd);
+			iocb->un.fcpi64.bdl.addrHigh = 0;
+			iocb->ulpBdeCount = 0;
+			iocb->ulpLe = 0;
+			/* fill in responce BDE */
+			iocb->unsli3.fcp_ext.rbde.tus.f.bdeFlags =
+							BUFF_TYPE_BDE_64;
+			iocb->unsli3.fcp_ext.rbde.tus.f.bdeSize =
+				sizeof(struct fcp_rsp);
+			iocb->unsli3.fcp_ext.rbde.addrLow =
+				putPaddrLow(pdma_phys_fcp_rsp);
+			iocb->unsli3.fcp_ext.rbde.addrHigh =
+				putPaddrHigh(pdma_phys_fcp_rsp);
+		} else {
+			iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
+			iocb->un.fcpi64.bdl.bdeSize =
+					(2 * sizeof(struct ulp_bde64));
+			iocb->un.fcpi64.bdl.addrLow =
+					putPaddrLow(pdma_phys_bpl);
+			iocb->un.fcpi64.bdl.addrHigh =
+					putPaddrHigh(pdma_phys_bpl);
+			iocb->ulpBdeCount = 1;
+			iocb->ulpLe = 1;
+		}
+		iocb->ulpClass = CLASS3;
+		psb->status = IOSTAT_SUCCESS;
+		/* Put it back into the SCSI buffer list */
+		lpfc_release_scsi_buf_s4(phba, psb);
+
 	}
-	iocb->ulpClass = CLASS3;
 
-	return psb;
+	return bcnt;
 }
 
 /**
- * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list list of Hba
- * @phba: The Hba for which this call is being executed.
+ * lpfc_sli4_fcp_xri_aborted - Fast-path process of fcp xri abort
+ * @phba: pointer to lpfc hba data structure.
+ * @axri: pointer to the fcp xri abort wcqe structure.
+ *
+ * This routine is invoked by the worker thread to process a SLI4 fast-path
+ * FCP aborted xri.
+ **/
+void
+lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
+			  struct sli4_wcqe_xri_aborted *axri)
+{
+	uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
+	struct lpfc_scsi_buf *psb, *next_psb;
+	unsigned long iflag = 0;
+
+	spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock, iflag);
+	list_for_each_entry_safe(psb, next_psb,
+		&phba->sli4_hba.lpfc_abts_scsi_buf_list, list) {
+		if (psb->cur_iocbq.sli4_xritag == xri) {
+			list_del(&psb->list);
+			psb->status = IOSTAT_SUCCESS;
+			spin_unlock_irqrestore(
+				&phba->sli4_hba.abts_scsi_buf_list_lock,
+				iflag);
+			lpfc_release_scsi_buf_s4(phba, psb);
+			return;
+		}
+	}
+	spin_unlock_irqrestore(&phba->sli4_hba.abts_scsi_buf_list_lock,
+				iflag);
+}
+
+/**
+ * lpfc_sli4_repost_scsi_sgl_list - Repsot the Scsi buffers sgl pages as block
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine walks the list of scsi buffers that have been allocated and
+ * repost them to the HBA by using SGL block post. This is needed after a
+ * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine
+ * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list
+ * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers.
+ *
+ * Returns: 0 = success, non-zero failure.
+ **/
+int
+lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
+{
+	struct lpfc_scsi_buf *psb;
+	int index, status, bcnt = 0, rcnt = 0, rc = 0;
+	LIST_HEAD(sblist);
+
+	for (index = 0; index < phba->sli4_hba.scsi_xri_cnt; index++) {
+		psb = phba->sli4_hba.lpfc_scsi_psb_array[index];
+		if (psb) {
+			/* Remove from SCSI buffer list */
+			list_del(&psb->list);
+			/* Add it to a local SCSI buffer list */
+			list_add_tail(&psb->list, &sblist);
+			if (++rcnt == LPFC_NEMBED_MBOX_SGL_CNT) {
+				bcnt = rcnt;
+				rcnt = 0;
+			}
+		} else
+			/* A hole present in the XRI array, need to skip */
+			bcnt = rcnt;
+
+		if (index == phba->sli4_hba.scsi_xri_cnt - 1)
+			/* End of XRI array for SCSI buffer, complete */
+			bcnt = rcnt;
+
+		/* Continue until collect up to a nembed page worth of sgls */
+		if (bcnt == 0)
+			continue;
+		/* Now, post the SCSI buffer list sgls as a block */
+		status = lpfc_sli4_post_scsi_sgl_block(phba, &sblist, bcnt);
+		/* Reset SCSI buffer count for next round of posting */
+		bcnt = 0;
+		while (!list_empty(&sblist)) {
+			list_remove_head(&sblist, psb, struct lpfc_scsi_buf,
+					 list);
+			if (status) {
+				/* Put this back on the abort scsi list */
+				psb->status = IOSTAT_LOCAL_REJECT;
+				psb->result = IOERR_ABORT_REQUESTED;
+				rc++;
+			} else
+				psb->status = IOSTAT_SUCCESS;
+			/* Put it back into the SCSI buffer list */
+			lpfc_release_scsi_buf_s4(phba, psb);
+		}
+	}
+	return rc;
+}
+
+/**
+ * lpfc_new_scsi_buf_s4 - Scsi buffer allocator for HBA with SLI4 IF spec
+ * @vport: The virtual port for which this call being executed.
+ * @num_to_allocate: The requested number of buffers to allocate.
+ *
+ * This routine allocates a scsi buffer for device with SLI-4 interface spec,
+ * the scsi buffer contains all the necessary information needed to initiate
+ * a SCSI I/O.
+ *
+ * Return codes:
+ *   int - number of scsi buffers that were allocated.
+ *   0 = failure, less than num_to_alloc is a partial failure.
+ **/
+static int
+lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
+{
+	struct lpfc_hba *phba = vport->phba;
+	struct lpfc_scsi_buf *psb;
+	struct sli4_sge *sgl;
+	IOCB_t *iocb;
+	dma_addr_t pdma_phys_fcp_cmd;
+	dma_addr_t pdma_phys_fcp_rsp;
+	dma_addr_t pdma_phys_bpl, pdma_phys_bpl1;
+	uint16_t iotag, last_xritag = NO_XRI;
+	int status = 0, index;
+	int bcnt;
+	int non_sequential_xri = 0;
+	int rc = 0;
+	LIST_HEAD(sblist);
+
+	for (bcnt = 0; bcnt < num_to_alloc; bcnt++) {
+		psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
+		if (!psb)
+			break;
+
+		/*
+		 * Get memory from the pci pool to map the virt space to pci bus
+		 * space for an I/O.  The DMA buffer includes space for the
+		 * struct fcp_cmnd, struct fcp_rsp and the number of bde's
+		 * necessary to support the sg_tablesize.
+		 */
+		psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool,
+						GFP_KERNEL, &psb->dma_handle);
+		if (!psb->data) {
+			kfree(psb);
+			break;
+		}
+
+		/* Initialize virtual ptrs to dma_buf region. */
+		memset(psb->data, 0, phba->cfg_sg_dma_buf_size);
+
+		/* Allocate iotag for psb->cur_iocbq. */
+		iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq);
+		if (iotag == 0) {
+			kfree(psb);
+			break;
+		}
+
+		psb->cur_iocbq.sli4_xritag = lpfc_sli4_next_xritag(phba);
+		if (psb->cur_iocbq.sli4_xritag == NO_XRI) {
+			pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
+			      psb->data, psb->dma_handle);
+			kfree(psb);
+			break;
+		}
+		if (last_xritag != NO_XRI
+			&& psb->cur_iocbq.sli4_xritag != (last_xritag+1)) {
+			non_sequential_xri = 1;
+		} else
+			list_add_tail(&psb->list, &sblist);
+		last_xritag = psb->cur_iocbq.sli4_xritag;
+
+		index = phba->sli4_hba.scsi_xri_cnt++;
+		psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP;
+
+		psb->fcp_bpl = psb->data;
+		psb->fcp_cmnd = (psb->data + phba->cfg_sg_dma_buf_size)
+			- (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp));
+		psb->fcp_rsp = (struct fcp_rsp *)((uint8_t *)psb->fcp_cmnd +
+					sizeof(struct fcp_cmnd));
+
+		/* Initialize local short-hand pointers. */
+		sgl = (struct sli4_sge *)psb->fcp_bpl;
+		pdma_phys_bpl = psb->dma_handle;
+		pdma_phys_fcp_cmd =
+			(psb->dma_handle + phba->cfg_sg_dma_buf_size)
+			 - (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp));
+		pdma_phys_fcp_rsp = pdma_phys_fcp_cmd + sizeof(struct fcp_cmnd);
+
+		/*
+		 * The first two bdes are the FCP_CMD and FCP_RSP.  The balance
+		 * are sg list bdes.  Initialize the first two and leave the
+		 * rest for queuecommand.
+		 */
+		sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd));
+		sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd));
+		bf_set(lpfc_sli4_sge_len, sgl, sizeof(struct fcp_cmnd));
+		bf_set(lpfc_sli4_sge_last, sgl, 0);
+		sgl->word2 = cpu_to_le32(sgl->word2);
+		sgl->word3 = cpu_to_le32(sgl->word3);
+		sgl++;
+
+		/* Setup the physical region for the FCP RSP */
+		sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_rsp));
+		sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_rsp));
+		bf_set(lpfc_sli4_sge_len, sgl, sizeof(struct fcp_rsp));
+		bf_set(lpfc_sli4_sge_last, sgl, 1);
+		sgl->word2 = cpu_to_le32(sgl->word2);
+		sgl->word3 = cpu_to_le32(sgl->word3);
+
+		/*
+		 * Since the IOCB for the FCP I/O is built into this
+		 * lpfc_scsi_buf, initialize it with all known data now.
+		 */
+		iocb = &psb->cur_iocbq.iocb;
+		iocb->un.fcpi64.bdl.ulpIoTag32 = 0;
+		iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_64;
+		/* setting the BLP size to 2 * sizeof BDE may not be correct.
+		 * We are setting the bpl to point to out sgl. An sgl's
+		 * entries are 16 bytes, a bpl entries are 12 bytes.
+		 */
+		iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd);
+		iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys_fcp_cmd);
+		iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys_fcp_cmd);
+		iocb->ulpBdeCount = 1;
+		iocb->ulpLe = 1;
+		iocb->ulpClass = CLASS3;
+		if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE)
+			pdma_phys_bpl1 = pdma_phys_bpl + SGL_PAGE_SIZE;
+		else
+			pdma_phys_bpl1 = 0;
+		psb->dma_phys_bpl = pdma_phys_bpl;
+		phba->sli4_hba.lpfc_scsi_psb_array[index] = psb;
+		if (non_sequential_xri) {
+			status = lpfc_sli4_post_sgl(phba, pdma_phys_bpl,
+						pdma_phys_bpl1,
+						psb->cur_iocbq.sli4_xritag);
+			if (status) {
+				/* Put this back on the abort scsi list */
+				psb->status = IOSTAT_LOCAL_REJECT;
+				psb->result = IOERR_ABORT_REQUESTED;
+				rc++;
+			} else
+				psb->status = IOSTAT_SUCCESS;
+			/* Put it back into the SCSI buffer list */
+			lpfc_release_scsi_buf_s4(phba, psb);
+			break;
+		}
+	}
+	if (bcnt) {
+		status = lpfc_sli4_post_scsi_sgl_block(phba, &sblist, bcnt);
+		/* Reset SCSI buffer count for next round of posting */
+		while (!list_empty(&sblist)) {
+			list_remove_head(&sblist, psb, struct lpfc_scsi_buf,
+				 list);
+			if (status) {
+				/* Put this back on the abort scsi list */
+				psb->status = IOSTAT_LOCAL_REJECT;
+				psb->result = IOERR_ABORT_REQUESTED;
+				rc++;
+			} else
+				psb->status = IOSTAT_SUCCESS;
+			/* Put it back into the SCSI buffer list */
+			lpfc_release_scsi_buf_s4(phba, psb);
+		}
+	}
+
+	return bcnt + non_sequential_xri - rc;
+}
+
+/**
+ * lpfc_new_scsi_buf - Wrapper funciton for scsi buffer allocator
+ * @vport: The virtual port for which this call being executed.
+ * @num_to_allocate: The requested number of buffers to allocate.
+ *
+ * This routine wraps the actual SCSI buffer allocator function pointer from
+ * the lpfc_hba struct.
+ *
+ * Return codes:
+ *   int - number of scsi buffers that were allocated.
+ *   0 = failure, less than num_to_alloc is a partial failure.
+ **/
+static inline int
+lpfc_new_scsi_buf(struct lpfc_vport *vport, int num_to_alloc)
+{
+	return vport->phba->lpfc_new_scsi_buf(vport, num_to_alloc);
+}
+
+/**
+ * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
+ * @phba: The HBA for which this call is being executed.
  *
  * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list
  * and returns to caller.
@@ -591,7 +890,7 @@
 }
 
 /**
- * lpfc_release_scsi_buf - Return a scsi buffer back to hba's lpfc_scsi_buf_list
+ * lpfc_release_scsi_buf - Return a scsi buffer back to hba scsi buf list
  * @phba: The Hba for which this call is being executed.
  * @psb: The scsi buffer which is being released.
  *
@@ -599,7 +898,7 @@
  * lpfc_scsi_buf_list list.
  **/
 static void
-lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
+lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
 {
 	unsigned long iflag = 0;
 
@@ -610,21 +909,69 @@
 }
 
 /**
- * lpfc_scsi_prep_dma_buf - Routine to do DMA mapping for scsi buffer
+ * lpfc_release_scsi_buf_s4: Return a scsi buffer back to hba scsi buf list.
+ * @phba: The Hba for which this call is being executed.
+ * @psb: The scsi buffer which is being released.
+ *
+ * This routine releases @psb scsi buffer by adding it to tail of @phba
+ * lpfc_scsi_buf_list list. For SLI4 XRI's are tied to the scsi buffer
+ * and cannot be reused for at least RA_TOV amount of time if it was
+ * aborted.
+ **/
+static void
+lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
+{
+	unsigned long iflag = 0;
+
+	if (psb->status == IOSTAT_LOCAL_REJECT
+		&& psb->result == IOERR_ABORT_REQUESTED) {
+		spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock,
+					iflag);
+		psb->pCmd = NULL;
+		list_add_tail(&psb->list,
+			&phba->sli4_hba.lpfc_abts_scsi_buf_list);
+		spin_unlock_irqrestore(&phba->sli4_hba.abts_scsi_buf_list_lock,
+					iflag);
+	} else {
+
+		spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
+		psb->pCmd = NULL;
+		list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list);
+		spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
+	}
+}
+
+/**
+ * lpfc_release_scsi_buf: Return a scsi buffer back to hba scsi buf list.
+ * @phba: The Hba for which this call is being executed.
+ * @psb: The scsi buffer which is being released.
+ *
+ * This routine releases @psb scsi buffer by adding it to tail of @phba
+ * lpfc_scsi_buf_list list.
+ **/
+static void
+lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
+{
+
+	phba->lpfc_release_scsi_buf(phba, psb);
+}
+
+/**
+ * lpfc_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 mapped.
  *
  * This routine does the pci dma mapping for scatter-gather list of scsi cmnd
- * field of @lpfc_cmd. This routine scans through sg elements and format the
- * bdea. This routine also initializes all IOCB fields which are dependent on
- * scsi command request buffer.
+ * field of @lpfc_cmd for device with SLI-3 interface spec. This routine scans
+ * through sg elements and format the bdea. This routine also initializes all
+ * IOCB fields which are dependent on scsi command request buffer.
  *
  * Return codes:
  *   1 - Error
  *   0 - Success
  **/
 static int
-lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
+lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
 {
 	struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
 	struct scatterlist *sgel = NULL;
@@ -1412,6 +1759,133 @@
 }
 
 /**
+ * lpfc_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 routine does the pci dma mapping for scatter-gather list of scsi cmnd
+ * field of @lpfc_cmd for device with SLI-4 interface spec.
+ *
+ * Return codes:
+ * 	1 - Error
+ * 	0 - Success
+ **/
+static int
+lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
+{
+	struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
+	struct scatterlist *sgel = NULL;
+	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;
+	dma_addr_t physaddr;
+	uint32_t num_bde = 0;
+	uint32_t dma_len;
+	uint32_t dma_offset = 0;
+	int nseg;
+
+	/*
+	 * There are three possibilities here - use scatter-gather segment, use
+	 * the single mapping, or neither.  Start the lpfc command prep by
+	 * bumping the bpl beyond the fcp_cmnd and 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.
+		 */
+
+		nseg = scsi_dma_map(scsi_cmnd);
+		if (unlikely(!nseg))
+			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 = nseg;
+		if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
+			printk(KERN_ERR "%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;
+		}
+
+		/*
+		 * The driver established a maximum scatter-gather segment count
+		 * during probe that limits the number of sg elements in any
+		 * single scsi command.  Just run through the seg_cnt and format
+		 * the sge's.
+		 * When using SLI-3 the driver will try to fit all the BDEs into
+		 * the IOCB. If it can't then the BDEs get added to a BPL as it
+		 * does for SLI-2 mode.
+		 */
+		scsi_for_each_sg(scsi_cmnd, sgel, nseg, num_bde) {
+			physaddr = sg_dma_address(sgel);
+			dma_len = sg_dma_len(sgel);
+			bf_set(lpfc_sli4_sge_len, sgl, sg_dma_len(sgel));
+			sgl->addr_lo = cpu_to_le32(putPaddrLow(physaddr));
+			sgl->addr_hi = cpu_to_le32(putPaddrHigh(physaddr));
+			if ((num_bde + 1) == nseg)
+				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);
+			sgl->word2 = cpu_to_le32(sgl->word2);
+			sgl->word3 = cpu_to_le32(sgl->word3);
+			dma_offset += dma_len;
+			sgl++;
+		}
+	} else {
+		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, 1);
+		sgl->word2 = cpu_to_le32(sgl->word2);
+	}
+
+	/*
+	 * Finish initializing those IOCB fields that are dependent on the
+	 * scsi_cmnd request_buffer.  Note that for SLI-2 the bdeSize is
+	 * explicitly reinitialized.
+	 * all iocb memory resources are reused.
+	 */
+	fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd));
+
+	/*
+	 * 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 = scsi_bufflen(scsi_cmnd);
+	return 0;
+}
+
+/**
+ * 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.
+ *
+ * This routine wraps the actual DMA mapping function pointer from the
+ * lpfc_hba struct.
+ *
+ * Return codes:
+ * 	1 - Error
+ * 	0 - Success
+ **/
+static inline int
+lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
+{
+	return phba->lpfc_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.
@@ -1504,15 +1978,15 @@
 }
 
 /**
- * lpfc_scsi_unprep_dma_buf - Routine to un-map DMA mapping of scatter gather
- * @phba: The Hba for which this call is being executed.
+ * lpfc_scsi_unprep_dma_buf_s3 - Un-map DMA mapping of SG-list for SLI3 dev
+ * @phba: The HBA for which this call is being executed.
  * @psb: The scsi buffer which is going to be un-mapped.
  *
  * This routine does DMA un-mapping of scatter gather list of scsi command
- * field of @lpfc_cmd.
+ * field of @lpfc_cmd for device with SLI-3 interface spec.
  **/
 static void
-lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
+lpfc_scsi_unprep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
 {
 	/*
 	 * There are only two special cases to consider.  (1) the scsi command
@@ -1529,6 +2003,36 @@
 }
 
 /**
+ * lpfc_scsi_unprep_dma_buf_s4 - Un-map DMA mapping of SG-list for SLI4 dev
+ * @phba: The Hba for which this call is being executed.
+ * @psb: The scsi buffer which is going to be un-mapped.
+ *
+ * This routine does DMA un-mapping of scatter gather list of scsi command
+ * field of @lpfc_cmd for device with SLI-4 interface spec. If we have to
+ * remove the sgl for this scsi buffer then we will do it here. For now
+ * we should be able to just call the sli3 unprep routine.
+ **/
+static void
+lpfc_scsi_unprep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
+{
+	lpfc_scsi_unprep_dma_buf_s3(phba, psb);
+}
+
+/**
+ * lpfc_scsi_unprep_dma_buf - Wrapper function for unmap DMA mapping of SG-list
+ * @phba: The Hba for which this call is being executed.
+ * @psb: The scsi buffer which is going to be un-mapped.
+ *
+ * This routine does DMA un-mapping of scatter gather list of scsi command
+ * field of @lpfc_cmd for device with SLI-4 interface spec.
+ **/
+static void
+lpfc_scsi_unprep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
+{
+	phba->lpfc_scsi_unprep_dma_buf(phba, psb);
+}
+
+/**
  * lpfc_handler_fcp_err - FCP response handler
  * @vport: The virtual port for which this call is being executed.
  * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure.
@@ -1676,7 +2180,7 @@
  * lpfc_scsi_cmd_iocb_cmpl - Scsi cmnd IOCB completion routine
  * @phba: The Hba for which this call is being executed.
  * @pIocbIn: The command IOCBQ for the scsi cmnd.
- * @pIocbOut: The response IOCBQ for the scsi cmnd .
+ * @pIocbOut: The response IOCBQ for the scsi cmnd.
  *
  * This routine assigns scsi command result by looking into response IOCB
  * status field appropriately. This routine handles QUEUE FULL condition as
@@ -1957,16 +2461,16 @@
 }
 
 /**
- * lpfc_scsi_prep_cmnd -  Routine to convert scsi cmnd to FCP information unit
+ * lpfc_scsi_prep_cmnd_s3 - Convert scsi cmnd to FCP infor unit for SLI3 dev
  * @vport: The virtual port for which this call is being executed.
  * @lpfc_cmd: The scsi command which needs to send.
  * @pnode: Pointer to lpfc_nodelist.
  *
  * This routine initializes fcp_cmnd and iocb data structure from scsi command
- * to transfer.
+ * to transfer for device with SLI3 interface spec.
  **/
 static void
-lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
+lpfc_scsi_prep_cmnd_s3(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 		    struct lpfc_nodelist *pnode)
 {
 	struct lpfc_hba *phba = vport->phba;
@@ -2013,8 +2517,11 @@
 	if (scsi_sg_count(scsi_cmnd)) {
 		if (datadir == DMA_TO_DEVICE) {
 			iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR;
-			iocb_cmd->un.fcpi.fcpi_parm = 0;
-			iocb_cmd->ulpPU = 0;
+			if (phba->sli_rev < LPFC_SLI_REV4) {
+				iocb_cmd->un.fcpi.fcpi_parm = 0;
+				iocb_cmd->ulpPU = 0;
+			} else
+				iocb_cmd->ulpPU = PARM_READ_CHECK;
 			fcp_cmnd->fcpCntl3 = WRITE_DATA;
 			phba->fc4OutputRequests++;
 		} else {
@@ -2051,20 +2558,60 @@
 }
 
 /**
- * lpfc_scsi_prep_task_mgmt_cmnd - Convert scsi TM cmnd to FCP information unit
+ * lpfc_scsi_prep_cmnd_s4 - Convert scsi cmnd to FCP infor unit for SLI4 dev
+ * @vport: The virtual port for which this call is being executed.
+ * @lpfc_cmd: The scsi command which needs to send.
+ * @pnode: Pointer to lpfc_nodelist.
+ *
+ * This routine initializes fcp_cmnd and iocb data structure from scsi command
+ * to transfer for device with SLI4 interface spec.
+ **/
+static void
+lpfc_scsi_prep_cmnd_s4(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
+		       struct lpfc_nodelist *pnode)
+{
+	/*
+	 * The prep cmnd routines do not touch the sgl or its
+	 * entries. We may not have to do anything different.
+	 * I will leave this function in place until we can
+	 * run some IO through the driver and determine if changes
+	 * are needed.
+	 */
+	return lpfc_scsi_prep_cmnd_s3(vport, lpfc_cmd, pnode);
+}
+
+/**
+ * lpfc_scsi_prep_cmnd - Wrapper func for convert scsi cmnd to FCP info unit
+ * @vport: The virtual port for which this call is being executed.
+ * @lpfc_cmd: The scsi command which needs to send.
+ * @pnode: Pointer to lpfc_nodelist.
+ *
+ * This routine wraps the actual convert SCSI cmnd function pointer from
+ * the lpfc_hba struct.
+ **/
+static inline void
+lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
+		    struct lpfc_nodelist *pnode)
+{
+	vport->phba->lpfc_scsi_prep_cmnd(vport, lpfc_cmd, pnode);
+}
+
+/**
+ * lpfc_scsi_prep_task_mgmt_cmnd_s3 - Convert SLI3 scsi TM cmd to FCP info unit
  * @vport: The virtual port for which this call is being executed.
  * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure.
  * @lun: Logical unit number.
  * @task_mgmt_cmd: SCSI task management command.
  *
- * This routine creates FCP information unit corresponding to @task_mgmt_cmd.
+ * This routine creates FCP information unit corresponding to @task_mgmt_cmd
+ * for device with SLI-3 interface spec.
  *
  * Return codes:
  *   0 - Error
  *   1 - Success
  **/
 static int
-lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport,
+lpfc_scsi_prep_task_mgmt_cmd_s3(struct lpfc_vport *vport,
 			     struct lpfc_scsi_buf *lpfc_cmd,
 			     unsigned int lun,
 			     uint8_t task_mgmt_cmd)
@@ -2114,6 +2661,107 @@
 }
 
 /**
+ * lpfc_scsi_prep_task_mgmt_cmnd_s4 - Convert SLI4 scsi TM cmd to FCP info unit
+ * @vport: The virtual port for which this call is being executed.
+ * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure.
+ * @lun: Logical unit number.
+ * @task_mgmt_cmd: SCSI task management command.
+ *
+ * This routine creates FCP information unit corresponding to @task_mgmt_cmd
+ * for device with SLI-4 interface spec.
+ *
+ * Return codes:
+ * 	0 - Error
+ * 	1 - Success
+ **/
+static int
+lpfc_scsi_prep_task_mgmt_cmd_s4(struct lpfc_vport *vport,
+				struct lpfc_scsi_buf *lpfc_cmd,
+				unsigned int lun,
+				uint8_t task_mgmt_cmd)
+{
+	/*
+	 * The prep cmnd routines do not touch the sgl or its
+	 * entries. We may not have to do anything different.
+	 * I will leave this function in place until we can
+	 * run some IO through the driver and determine if changes
+	 * are needed.
+	 */
+	return lpfc_scsi_prep_task_mgmt_cmd_s3(vport, lpfc_cmd, lun,
+						task_mgmt_cmd);
+}
+
+/**
+ * lpfc_scsi_prep_task_mgmt_cmnd - Wrapper func convert scsi TM cmd to FCP info
+ * @vport: The virtual port for which this call is being executed.
+ * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure.
+ * @lun: Logical unit number.
+ * @task_mgmt_cmd: SCSI task management command.
+ *
+ * This routine wraps the actual convert SCSI TM to FCP information unit
+ * function pointer from the lpfc_hba struct.
+ *
+ * Return codes:
+ * 	0 - Error
+ * 	1 - Success
+ **/
+static inline int
+lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport,
+			     struct lpfc_scsi_buf *lpfc_cmd,
+			     unsigned int lun,
+			     uint8_t task_mgmt_cmd)
+{
+	struct lpfc_hba *phba = vport->phba;
+
+	return phba->lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun,
+						  task_mgmt_cmd);
+}
+
+/**
+ * lpfc_scsi_api_table_setup - Set up scsi api fucntion jump table
+ * @phba: The hba struct for which this call is being executed.
+ * @dev_grp: The HBA PCI-Device group number.
+ *
+ * This routine sets up the SCSI interface API function jump table in @phba
+ * struct.
+ * Returns: 0 - success, -ENODEV - failure.
+ **/
+int
+lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
+{
+
+	switch (dev_grp) {
+	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_scsi_prep_cmnd = lpfc_scsi_prep_cmnd_s3;
+		phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf_s3;
+		phba->lpfc_scsi_prep_task_mgmt_cmd =
+					lpfc_scsi_prep_task_mgmt_cmd_s3;
+		phba->lpfc_release_scsi_buf = lpfc_release_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_scsi_prep_cmnd = lpfc_scsi_prep_cmnd_s4;
+		phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf_s4;
+		phba->lpfc_scsi_prep_task_mgmt_cmd =
+					lpfc_scsi_prep_task_mgmt_cmd_s4;
+		phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s4;
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1418 Invalid HBA PCI-device group: 0x%x\n",
+				dev_grp);
+		return -ENODEV;
+		break;
+	}
+	phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf;
+	phba->lpfc_rampdown_queue_depth = lpfc_rampdown_queue_depth;
+	return 0;
+}
+
+/**
  * lpfc_taskmgmt_def_cmpl - IOCB completion routine for task management command
  * @phba: The Hba for which this call is being executed.
  * @cmdiocbq: Pointer to lpfc_iocbq data structure.
@@ -2178,9 +2826,8 @@
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
 			 "0702 Issue Target Reset to TGT %d Data: x%x x%x\n",
 			 tgt_id, rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag);
-	status = lpfc_sli_issue_iocb_wait(phba,
-				       &phba->sli.ring[phba->sli.fcp_ring],
-				       iocbq, iocbqrsp, lpfc_cmd->timeout);
+	status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING,
+					  iocbq, iocbqrsp, lpfc_cmd->timeout);
 	if (status != IOCB_SUCCESS) {
 		if (status == IOCB_TIMEDOUT) {
 			iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
@@ -2305,7 +2952,6 @@
 	struct Scsi_Host  *shost = cmnd->device->host;
 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 	struct lpfc_hba   *phba = vport->phba;
-	struct lpfc_sli   *psli = &phba->sli;
 	struct lpfc_rport_data *rdata = cmnd->device->hostdata;
 	struct lpfc_nodelist *ndlp = rdata->pnode;
 	struct lpfc_scsi_buf *lpfc_cmd;
@@ -2427,7 +3073,7 @@
 	lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp);
 
 	atomic_inc(&ndlp->cmd_pending);
-	err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring],
+	err = lpfc_sli_issue_iocb(phba, LPFC_FCP_RING,
 				  &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
 	if (err) {
 		atomic_dec(&ndlp->cmd_pending);
@@ -2490,7 +3136,6 @@
 	struct Scsi_Host  *shost = cmnd->device->host;
 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 	struct lpfc_hba   *phba = vport->phba;
-	struct lpfc_sli_ring *pring = &phba->sli.ring[phba->sli.fcp_ring];
 	struct lpfc_iocbq *iocb;
 	struct lpfc_iocbq *abtsiocb;
 	struct lpfc_scsi_buf *lpfc_cmd;
@@ -2531,7 +3176,10 @@
 	icmd = &abtsiocb->iocb;
 	icmd->un.acxri.abortType = ABORT_TYPE_ABTS;
 	icmd->un.acxri.abortContextTag = cmd->ulpContext;
-	icmd->un.acxri.abortIoTag = cmd->ulpIoTag;
+	if (phba->sli_rev == LPFC_SLI_REV4)
+		icmd->un.acxri.abortIoTag = iocb->sli4_xritag;
+	else
+		icmd->un.acxri.abortIoTag = cmd->ulpIoTag;
 
 	icmd->ulpLe = 1;
 	icmd->ulpClass = cmd->ulpClass;
@@ -2542,7 +3190,8 @@
 
 	abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;
 	abtsiocb->vport = vport;
-	if (lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0) == IOCB_ERROR) {
+	if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) ==
+	    IOCB_ERROR) {
 		lpfc_sli_release_iocbq(phba, abtsiocb);
 		ret = FAILED;
 		goto out;
@@ -2668,8 +3317,7 @@
 			 "0703 Issue target reset to TGT %d LUN %d "
 			 "rpi x%x nlp_flag x%x\n", cmnd->device->id,
 			 cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
-	status = lpfc_sli_issue_iocb_wait(phba,
-					  &phba->sli.ring[phba->sli.fcp_ring],
+	status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING,
 					  iocbq, iocbqrsp, lpfc_cmd->timeout);
 	if (status == IOCB_TIMEDOUT) {
 		iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
@@ -2825,11 +3473,10 @@
 {
 	struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
 	struct lpfc_hba   *phba = vport->phba;
-	struct lpfc_scsi_buf *scsi_buf = NULL;
 	struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
-	uint32_t total = 0, i;
+	uint32_t total = 0;
 	uint32_t num_to_alloc = 0;
-	unsigned long flags;
+	int num_allocated = 0;
 
 	if (!rport || fc_remote_port_chkready(rport))
 		return -ENXIO;
@@ -2863,20 +3510,13 @@
 				 (phba->cfg_hba_queue_depth - total));
 		num_to_alloc = phba->cfg_hba_queue_depth - total;
 	}
-
-	for (i = 0; i < num_to_alloc; i++) {
-		scsi_buf = lpfc_new_scsi_buf(vport);
-		if (!scsi_buf) {
-			lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
-					 "0706 Failed to allocate "
-					 "command buffer\n");
-			break;
-		}
-
-		spin_lock_irqsave(&phba->scsi_buf_list_lock, flags);
-		phba->total_scsi_bufs++;
-		list_add_tail(&scsi_buf->list, &phba->lpfc_scsi_buf_list);
-		spin_unlock_irqrestore(&phba->scsi_buf_list_lock, flags);
+	num_allocated = lpfc_new_scsi_buf(vport, num_to_alloc);
+	if (num_to_alloc != num_allocated) {
+			lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+				 "0708 Allocation request of %d "
+				 "command buffers did not succeed.  "
+				 "Allocated %d buffers.\n",
+				 num_to_alloc, num_allocated);
 	}
 	return 0;
 }
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
index c7c440d..65dfc8b 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.h
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -140,6 +140,8 @@
 	struct fcp_rsp *fcp_rsp;
 	struct ulp_bde64 *fcp_bpl;
 
+	dma_addr_t dma_phys_bpl;
+
 	/* cur_iocbq has phys of the dma-able buffer.
 	 * Iotag is in here
 	 */
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index eb5c75c..ff04daf 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-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -29,9 +29,12 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
+#include <scsi/fc/fc_fs.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -40,24 +43,7 @@
 #include "lpfc_logmsg.h"
 #include "lpfc_compat.h"
 #include "lpfc_debugfs.h"
-
-/*
- * Define macro to log: Mailbox command x%x cannot issue Data
- * This allows multiple uses of lpfc_msgBlk0311
- * w/o perturbing log msg utility.
- */
-#define LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag) \
-			lpfc_printf_log(phba, \
-				KERN_INFO, \
-				LOG_MBOX | LOG_SLI, \
-				"(%d):0311 Mailbox command x%x cannot " \
-				"issue Data: x%x x%x x%x\n", \
-				pmbox->vport ? pmbox->vport->vpi : 0, \
-				pmbox->mb.mbxCommand,		\
-				phba->pport->port_state,	\
-				psli->sli_flag,	\
-				flag)
-
+#include "lpfc_vport.h"
 
 /* There are only four IOCB completion types. */
 typedef enum _lpfc_iocb_type {
@@ -67,6 +53,350 @@
 	LPFC_ABORT_IOCB
 } lpfc_iocb_type;
 
+
+/* Provide function prototypes local to this module. */
+static int lpfc_sli_issue_mbox_s4(struct lpfc_hba *, LPFC_MBOXQ_t *,
+				  uint32_t);
+static int lpfc_sli4_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *,
+			    uint8_t *, uint32_t *);
+
+static IOCB_t *
+lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
+{
+	return &iocbq->iocb;
+}
+
+/**
+ * lpfc_sli4_wq_put - Put a Work Queue Entry on an Work Queue
+ * @q: The Work Queue to operate on.
+ * @wqe: The work Queue Entry to put on the Work queue.
+ *
+ * This routine will copy the contents of @wqe to the next available entry on
+ * the @q. This function will then ring the Work Queue Doorbell to signal the
+ * HBA to start processing the Work Queue Entry. This function returns 0 if
+ * successful. If no entries are available on @q then this function will return
+ * -ENOMEM.
+ * The caller is expected to hold the hbalock when calling this routine.
+ **/
+static uint32_t
+lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
+{
+	union lpfc_wqe *temp_wqe = q->qe[q->host_index].wqe;
+	struct lpfc_register doorbell;
+	uint32_t host_index;
+
+	/* If the host has not yet processed the next entry then we are done */
+	if (((q->host_index + 1) % q->entry_count) == q->hba_index)
+		return -ENOMEM;
+	/* set consumption flag every once in a while */
+	if (!((q->host_index + 1) % LPFC_RELEASE_NOTIFICATION_INTERVAL))
+		bf_set(lpfc_wqe_gen_wqec, &wqe->generic, 1);
+
+	lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size);
+
+	/* Update the host index before invoking device */
+	host_index = q->host_index;
+	q->host_index = ((q->host_index + 1) % q->entry_count);
+
+	/* Ring Doorbell */
+	doorbell.word0 = 0;
+	bf_set(lpfc_wq_doorbell_num_posted, &doorbell, 1);
+	bf_set(lpfc_wq_doorbell_index, &doorbell, host_index);
+	bf_set(lpfc_wq_doorbell_id, &doorbell, q->queue_id);
+	writel(doorbell.word0, q->phba->sli4_hba.WQDBregaddr);
+	readl(q->phba->sli4_hba.WQDBregaddr); /* Flush */
+
+	return 0;
+}
+
+/**
+ * lpfc_sli4_wq_release - Updates internal hba index for WQ
+ * @q: The Work Queue to operate on.
+ * @index: The index to advance the hba index to.
+ *
+ * This routine will update the HBA index of a queue to reflect consumption of
+ * Work Queue Entries by the HBA. When the HBA indicates that it has consumed
+ * an entry the host calls this function to update the queue's internal
+ * pointers. This routine returns the number of entries that were consumed by
+ * the HBA.
+ **/
+static uint32_t
+lpfc_sli4_wq_release(struct lpfc_queue *q, uint32_t index)
+{
+	uint32_t released = 0;
+
+	if (q->hba_index == index)
+		return 0;
+	do {
+		q->hba_index = ((q->hba_index + 1) % q->entry_count);
+		released++;
+	} while (q->hba_index != index);
+	return released;
+}
+
+/**
+ * lpfc_sli4_mq_put - Put a Mailbox Queue Entry on an Mailbox Queue
+ * @q: The Mailbox Queue to operate on.
+ * @wqe: The Mailbox Queue Entry to put on the Work queue.
+ *
+ * This routine will copy the contents of @mqe to the next available entry on
+ * the @q. This function will then ring the Work Queue Doorbell to signal the
+ * HBA to start processing the Work Queue Entry. This function returns 0 if
+ * successful. If no entries are available on @q then this function will return
+ * -ENOMEM.
+ * The caller is expected to hold the hbalock when calling this routine.
+ **/
+static uint32_t
+lpfc_sli4_mq_put(struct lpfc_queue *q, struct lpfc_mqe *mqe)
+{
+	struct lpfc_mqe *temp_mqe = q->qe[q->host_index].mqe;
+	struct lpfc_register doorbell;
+	uint32_t host_index;
+
+	/* If the host has not yet processed the next entry then we are done */
+	if (((q->host_index + 1) % q->entry_count) == q->hba_index)
+		return -ENOMEM;
+	lpfc_sli_pcimem_bcopy(mqe, temp_mqe, q->entry_size);
+	/* Save off the mailbox pointer for completion */
+	q->phba->mbox = (MAILBOX_t *)temp_mqe;
+
+	/* Update the host index before invoking device */
+	host_index = q->host_index;
+	q->host_index = ((q->host_index + 1) % q->entry_count);
+
+	/* Ring Doorbell */
+	doorbell.word0 = 0;
+	bf_set(lpfc_mq_doorbell_num_posted, &doorbell, 1);
+	bf_set(lpfc_mq_doorbell_id, &doorbell, q->queue_id);
+	writel(doorbell.word0, q->phba->sli4_hba.MQDBregaddr);
+	readl(q->phba->sli4_hba.MQDBregaddr); /* Flush */
+	return 0;
+}
+
+/**
+ * lpfc_sli4_mq_release - Updates internal hba index for MQ
+ * @q: The Mailbox Queue to operate on.
+ *
+ * This routine will update the HBA index of a queue to reflect consumption of
+ * a Mailbox Queue Entry by the HBA. When the HBA indicates that it has consumed
+ * an entry the host calls this function to update the queue's internal
+ * pointers. This routine returns the number of entries that were consumed by
+ * the HBA.
+ **/
+static uint32_t
+lpfc_sli4_mq_release(struct lpfc_queue *q)
+{
+	/* Clear the mailbox pointer for completion */
+	q->phba->mbox = NULL;
+	q->hba_index = ((q->hba_index + 1) % q->entry_count);
+	return 1;
+}
+
+/**
+ * lpfc_sli4_eq_get - Gets the next valid EQE from a EQ
+ * @q: The Event Queue to get the first valid EQE from
+ *
+ * This routine will get the first valid Event Queue Entry from @q, update
+ * the queue's internal hba index, and return the EQE. If no valid EQEs are in
+ * the Queue (no more work to do), or the Queue is full of EQEs that have been
+ * processed, but not popped back to the HBA then this routine will return NULL.
+ **/
+static struct lpfc_eqe *
+lpfc_sli4_eq_get(struct lpfc_queue *q)
+{
+	struct lpfc_eqe *eqe = q->qe[q->hba_index].eqe;
+
+	/* If the next EQE is not valid then we are done */
+	if (!bf_get(lpfc_eqe_valid, eqe))
+		return NULL;
+	/* If the host has not yet processed the next entry then we are done */
+	if (((q->hba_index + 1) % q->entry_count) == q->host_index)
+		return NULL;
+
+	q->hba_index = ((q->hba_index + 1) % q->entry_count);
+	return eqe;
+}
+
+/**
+ * lpfc_sli4_eq_release - Indicates the host has finished processing an EQ
+ * @q: The Event Queue that the host has completed processing for.
+ * @arm: Indicates whether the host wants to arms this CQ.
+ *
+ * This routine will mark all Event Queue Entries on @q, from the last
+ * known completed entry to the last entry that was processed, as completed
+ * by clearing the valid bit for each completion queue entry. Then it will
+ * notify the HBA, by ringing the doorbell, that the EQEs have been processed.
+ * The internal host index in the @q will be updated by this routine to indicate
+ * that the host has finished processing the entries. The @arm parameter
+ * indicates that the queue should be rearmed when ringing the doorbell.
+ *
+ * This function will return the number of EQEs that were popped.
+ **/
+uint32_t
+lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
+{
+	uint32_t released = 0;
+	struct lpfc_eqe *temp_eqe;
+	struct lpfc_register doorbell;
+
+	/* while there are valid entries */
+	while (q->hba_index != q->host_index) {
+		temp_eqe = q->qe[q->host_index].eqe;
+		bf_set(lpfc_eqe_valid, temp_eqe, 0);
+		released++;
+		q->host_index = ((q->host_index + 1) % q->entry_count);
+	}
+	if (unlikely(released == 0 && !arm))
+		return 0;
+
+	/* ring doorbell for number popped */
+	doorbell.word0 = 0;
+	if (arm) {
+		bf_set(lpfc_eqcq_doorbell_arm, &doorbell, 1);
+		bf_set(lpfc_eqcq_doorbell_eqci, &doorbell, 1);
+	}
+	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);
+	writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
+	return released;
+}
+
+/**
+ * lpfc_sli4_cq_get - Gets the next valid CQE from a CQ
+ * @q: The Completion Queue to get the first valid CQE from
+ *
+ * This routine will get the first valid Completion Queue Entry from @q, update
+ * the queue's internal hba index, and return the CQE. If no valid CQEs are in
+ * the Queue (no more work to do), or the Queue is full of CQEs that have been
+ * processed, but not popped back to the HBA then this routine will return NULL.
+ **/
+static struct lpfc_cqe *
+lpfc_sli4_cq_get(struct lpfc_queue *q)
+{
+	struct lpfc_cqe *cqe;
+
+	/* If the next CQE is not valid then we are done */
+	if (!bf_get(lpfc_cqe_valid, q->qe[q->hba_index].cqe))
+		return NULL;
+	/* If the host has not yet processed the next entry then we are done */
+	if (((q->hba_index + 1) % q->entry_count) == q->host_index)
+		return NULL;
+
+	cqe = q->qe[q->hba_index].cqe;
+	q->hba_index = ((q->hba_index + 1) % q->entry_count);
+	return cqe;
+}
+
+/**
+ * lpfc_sli4_cq_release - Indicates the host has finished processing a CQ
+ * @q: The Completion Queue that the host has completed processing for.
+ * @arm: Indicates whether the host wants to arms this CQ.
+ *
+ * This routine will mark all Completion queue entries on @q, from the last
+ * known completed entry to the last entry that was processed, as completed
+ * by clearing the valid bit for each completion queue entry. Then it will
+ * notify the HBA, by ringing the doorbell, that the CQEs have been processed.
+ * The internal host index in the @q will be updated by this routine to indicate
+ * that the host has finished processing the entries. The @arm parameter
+ * indicates that the queue should be rearmed when ringing the doorbell.
+ *
+ * This function will return the number of CQEs that were released.
+ **/
+uint32_t
+lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm)
+{
+	uint32_t released = 0;
+	struct lpfc_cqe *temp_qe;
+	struct lpfc_register doorbell;
+
+	/* while there are valid entries */
+	while (q->hba_index != q->host_index) {
+		temp_qe = q->qe[q->host_index].cqe;
+		bf_set(lpfc_cqe_valid, temp_qe, 0);
+		released++;
+		q->host_index = ((q->host_index + 1) % q->entry_count);
+	}
+	if (unlikely(released == 0 && !arm))
+		return 0;
+
+	/* ring doorbell for number popped */
+	doorbell.word0 = 0;
+	if (arm)
+		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);
+	writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
+	return released;
+}
+
+/**
+ * lpfc_sli4_rq_put - Put a Receive Buffer Queue Entry on a Receive Queue
+ * @q: The Header Receive Queue to operate on.
+ * @wqe: The Receive Queue Entry to put on the Receive queue.
+ *
+ * This routine will copy the contents of @wqe to the next available entry on
+ * the @q. This function will then ring the Receive Queue Doorbell to signal the
+ * HBA to start processing the Receive Queue Entry. This function returns the
+ * index that the rqe was copied to if successful. If no entries are available
+ * on @q then this function will return -ENOMEM.
+ * The caller is expected to hold the hbalock when calling this routine.
+ **/
+static int
+lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq,
+		 struct lpfc_rqe *hrqe, struct lpfc_rqe *drqe)
+{
+	struct lpfc_rqe *temp_hrqe = hq->qe[hq->host_index].rqe;
+	struct lpfc_rqe *temp_drqe = dq->qe[dq->host_index].rqe;
+	struct lpfc_register doorbell;
+	int put_index = hq->host_index;
+
+	if (hq->type != LPFC_HRQ || dq->type != LPFC_DRQ)
+		return -EINVAL;
+	if (hq->host_index != dq->host_index)
+		return -EINVAL;
+	/* If the host has not yet processed the next entry then we are done */
+	if (((hq->host_index + 1) % hq->entry_count) == hq->hba_index)
+		return -EBUSY;
+	lpfc_sli_pcimem_bcopy(hrqe, temp_hrqe, hq->entry_size);
+	lpfc_sli_pcimem_bcopy(drqe, temp_drqe, dq->entry_size);
+
+	/* Update the host index to point to the next slot */
+	hq->host_index = ((hq->host_index + 1) % hq->entry_count);
+	dq->host_index = ((dq->host_index + 1) % dq->entry_count);
+
+	/* Ring The Header Receive Queue Doorbell */
+	if (!(hq->host_index % LPFC_RQ_POST_BATCH)) {
+		doorbell.word0 = 0;
+		bf_set(lpfc_rq_doorbell_num_posted, &doorbell,
+		       LPFC_RQ_POST_BATCH);
+		bf_set(lpfc_rq_doorbell_id, &doorbell, hq->queue_id);
+		writel(doorbell.word0, hq->phba->sli4_hba.RQDBregaddr);
+	}
+	return put_index;
+}
+
+/**
+ * lpfc_sli4_rq_release - Updates internal hba index for RQ
+ * @q: The Header Receive Queue to operate on.
+ *
+ * This routine will update the HBA index of a queue to reflect consumption of
+ * one Receive Queue Entry by the HBA. When the HBA indicates that it has
+ * consumed an entry the host calls this function to update the queue's
+ * internal pointers. This routine returns the number of entries that were
+ * consumed by the HBA.
+ **/
+static uint32_t
+lpfc_sli4_rq_release(struct lpfc_queue *hq, struct lpfc_queue *dq)
+{
+	if ((hq->type != LPFC_HRQ) || (dq->type != LPFC_DRQ))
+		return 0;
+	hq->hba_index = ((hq->hba_index + 1) % hq->entry_count);
+	dq->hba_index = ((dq->hba_index + 1) % dq->entry_count);
+	return 1;
+}
+
 /**
  * lpfc_cmd_iocb - Get next command iocb entry in the ring
  * @phba: Pointer to HBA context object.
@@ -121,6 +451,76 @@
 }
 
 /**
+ * __lpfc_clear_active_sglq - Remove the active sglq for this XRI.
+ * @phba: Pointer to HBA context object.
+ * @xritag: XRI value.
+ *
+ * This function clears the sglq pointer from the array of acive
+ * sglq's. The xritag that is passed in is used to index into the
+ * array. Before the xritag can be used it needs to be adjusted
+ * by subtracting the xribase.
+ *
+ * Returns sglq ponter = success, NULL = Failure.
+ **/
+static struct lpfc_sglq *
+__lpfc_clear_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
+{
+	uint16_t adj_xri;
+	struct lpfc_sglq *sglq;
+	adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
+	if (adj_xri > phba->sli4_hba.max_cfg_param.max_xri)
+		return NULL;
+	sglq = phba->sli4_hba.lpfc_sglq_active_list[adj_xri];
+	phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = NULL;
+	return sglq;
+}
+
+/**
+ * __lpfc_get_active_sglq - Get the active sglq for this XRI.
+ * @phba: Pointer to HBA context object.
+ * @xritag: XRI value.
+ *
+ * This function returns the sglq pointer from the array of acive
+ * sglq's. The xritag that is passed in is used to index into the
+ * array. Before the xritag can be used it needs to be adjusted
+ * by subtracting the xribase.
+ *
+ * Returns sglq ponter = success, NULL = Failure.
+ **/
+static struct lpfc_sglq *
+__lpfc_get_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
+{
+	uint16_t adj_xri;
+	struct lpfc_sglq *sglq;
+	adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
+	if (adj_xri > phba->sli4_hba.max_cfg_param.max_xri)
+		return NULL;
+	sglq =  phba->sli4_hba.lpfc_sglq_active_list[adj_xri];
+	return sglq;
+}
+
+/**
+ * __lpfc_sli_get_sglq - Allocates an iocb object from sgl pool
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called with hbalock held. This function
+ * Gets a new driver sglq object from the sglq list. If the
+ * list is not empty then it is successful, it returns pointer to the newly
+ * allocated sglq object else it returns NULL.
+ **/
+static struct lpfc_sglq *
+__lpfc_sli_get_sglq(struct lpfc_hba *phba)
+{
+	struct list_head *lpfc_sgl_list = &phba->sli4_hba.lpfc_sgl_list;
+	struct lpfc_sglq *sglq = NULL;
+	uint16_t adj_xri;
+	list_remove_head(lpfc_sgl_list, sglq, struct lpfc_sglq, list);
+	adj_xri = sglq->sli4_xritag - phba->sli4_hba.max_cfg_param.xri_base;
+	phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = sglq;
+	return sglq;
+}
+
+/**
  * lpfc_sli_get_iocbq - Allocates an iocb object from iocb pool
  * @phba: Pointer to HBA context object.
  *
@@ -142,6 +542,82 @@
 }
 
 /**
+ * __lpfc_sli_release_iocbq_s4 - Release iocb to the iocb pool
+ * @phba: Pointer to HBA context object.
+ * @iocbq: Pointer to driver iocb object.
+ *
+ * This function is called with hbalock held to release driver
+ * iocb object to the iocb pool. The iotag in the iocb object
+ * does not change for each use of the iocb object. This function
+ * clears all other fields of the iocb object when it is freed.
+ * The sqlq structure that holds the xritag and phys and virtual
+ * mappings for the scatter gather list is retrieved from the
+ * active array of sglq. The get of the sglq pointer also clears
+ * the entry in the array. If the status of the IO indiactes that
+ * this IO was aborted then the sglq entry it put on the
+ * lpfc_abts_els_sgl_list until the CQ_ABORTED_XRI is received. If the
+ * IO has good status or fails for any other reason then the sglq
+ * entry is added to the free list (lpfc_sgl_list).
+ **/
+static void
+__lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
+{
+	struct lpfc_sglq *sglq;
+	size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
+	unsigned long iflag;
+
+	if (iocbq->sli4_xritag == NO_XRI)
+		sglq = NULL;
+	else
+		sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag);
+	if (sglq)  {
+		if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED
+			|| ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT)
+			&& (iocbq->iocb.un.ulpWord[4]
+				== IOERR_SLI_ABORTED))) {
+			spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock,
+					iflag);
+			list_add(&sglq->list,
+				&phba->sli4_hba.lpfc_abts_els_sgl_list);
+			spin_unlock_irqrestore(
+				&phba->sli4_hba.abts_sgl_list_lock, iflag);
+		} else
+			list_add(&sglq->list, &phba->sli4_hba.lpfc_sgl_list);
+	}
+
+
+	/*
+	 * Clean all volatile data fields, preserve iotag and node struct.
+	 */
+	memset((char *)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean);
+	iocbq->sli4_xritag = NO_XRI;
+	list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
+}
+
+/**
+ * __lpfc_sli_release_iocbq_s3 - Release iocb to the iocb pool
+ * @phba: Pointer to HBA context object.
+ * @iocbq: Pointer to driver iocb object.
+ *
+ * This function is called with hbalock held to release driver
+ * iocb object to the iocb pool. The iotag in the iocb object
+ * does not change for each use of the iocb object. This function
+ * clears all other fields of the iocb object when it is freed.
+ **/
+static void
+__lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
+{
+	size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
+
+	/*
+	 * Clean all volatile data fields, preserve iotag and node struct.
+	 */
+	memset((char*)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean);
+	iocbq->sli4_xritag = NO_XRI;
+	list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
+}
+
+/**
  * __lpfc_sli_release_iocbq - Release iocb to the iocb pool
  * @phba: Pointer to HBA context object.
  * @iocbq: Pointer to driver iocb object.
@@ -154,13 +630,7 @@
 static void
 __lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
 {
-	size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
-
-	/*
-	 * Clean all volatile data fields, preserve iotag and node struct.
-	 */
-	memset((char*)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean);
-	list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
+	phba->__lpfc_sli_release_iocbq(phba, iocbq);
 }
 
 /**
@@ -281,6 +751,14 @@
 	case CMD_GEN_REQUEST64_CR:
 	case CMD_GEN_REQUEST64_CX:
 	case CMD_XMIT_ELS_RSP64_CX:
+	case DSSCMD_IWRITE64_CR:
+	case DSSCMD_IWRITE64_CX:
+	case DSSCMD_IREAD64_CR:
+	case DSSCMD_IREAD64_CX:
+	case DSSCMD_INVALIDATE_DEK:
+	case DSSCMD_SET_KEK:
+	case DSSCMD_GET_KEK_ID:
+	case DSSCMD_GEN_XFER:
 		type = LPFC_SOL_IOCB;
 		break;
 	case CMD_ABORT_XRI_CN:
@@ -348,7 +826,7 @@
 	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (!pmb)
 		return -ENOMEM;
-	pmbox = &pmb->mb;
+	pmbox = &pmb->u.mb;
 	phba->link_state = LPFC_INIT_MBX_CMDS;
 	for (i = 0; i < psli->num_rings; i++) {
 		lpfc_config_ring(phba, i, pmb);
@@ -779,8 +1257,8 @@
 		phba->hbqs[i].buffer_count = 0;
 	}
 	/* Return all HBQ buffer that are in-fly */
-	list_for_each_entry_safe(dmabuf, next_dmabuf,
-			&phba->hbqbuf_in_list, list) {
+	list_for_each_entry_safe(dmabuf, next_dmabuf, &phba->rb_pend_list,
+				 list) {
 		hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf);
 		list_del(&hbq_buf->dbuf.list);
 		if (hbq_buf->tag == -1) {
@@ -814,10 +1292,28 @@
  * pointer to the hbq entry if it successfully post the buffer
  * else it will return NULL.
  **/
-static struct lpfc_hbq_entry *
+static int
 lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
 			 struct hbq_dmabuf *hbq_buf)
 {
+	return phba->lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buf);
+}
+
+/**
+ * lpfc_sli_hbq_to_firmware_s3 - Post the hbq buffer to SLI3 firmware
+ * @phba: Pointer to HBA context object.
+ * @hbqno: HBQ number.
+ * @hbq_buf: Pointer to HBQ buffer.
+ *
+ * This function is called with the hbalock held to post a hbq buffer to the
+ * firmware. If the function finds an empty slot in the HBQ, it will post the
+ * buffer and place it on the hbq_buffer_list. The function will return zero if
+ * it successfully post the buffer else it will return an error.
+ **/
+static int
+lpfc_sli_hbq_to_firmware_s3(struct lpfc_hba *phba, uint32_t hbqno,
+			    struct hbq_dmabuf *hbq_buf)
+{
 	struct lpfc_hbq_entry *hbqe;
 	dma_addr_t physaddr = hbq_buf->dbuf.phys;
 
@@ -838,8 +1334,40 @@
 				/* flush */
 		readl(phba->hbq_put + hbqno);
 		list_add_tail(&hbq_buf->dbuf.list, &hbqp->hbq_buffer_list);
-	}
-	return hbqe;
+		return 0;
+	} else
+		return -ENOMEM;
+}
+
+/**
+ * lpfc_sli_hbq_to_firmware_s4 - Post the hbq buffer to SLI4 firmware
+ * @phba: Pointer to HBA context object.
+ * @hbqno: HBQ number.
+ * @hbq_buf: Pointer to HBQ buffer.
+ *
+ * This function is called with the hbalock held to post an RQE to the SLI4
+ * firmware. If able to post the RQE to the RQ it will queue the hbq entry to
+ * the hbq_buffer_list and return zero, otherwise it will return an error.
+ **/
+static int
+lpfc_sli_hbq_to_firmware_s4(struct lpfc_hba *phba, uint32_t hbqno,
+			    struct hbq_dmabuf *hbq_buf)
+{
+	int rc;
+	struct lpfc_rqe hrqe;
+	struct lpfc_rqe drqe;
+
+	hrqe.address_lo = putPaddrLow(hbq_buf->hbuf.phys);
+	hrqe.address_hi = putPaddrHigh(hbq_buf->hbuf.phys);
+	drqe.address_lo = putPaddrLow(hbq_buf->dbuf.phys);
+	drqe.address_hi = putPaddrHigh(hbq_buf->dbuf.phys);
+	rc = lpfc_sli4_rq_put(phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq,
+			      &hrqe, &drqe);
+	if (rc < 0)
+		return rc;
+	hbq_buf->tag = rc;
+	list_add_tail(&hbq_buf->dbuf.list, &phba->hbqs[hbqno].hbq_buffer_list);
+	return 0;
 }
 
 /* HBQ for ELS and CT traffic. */
@@ -914,7 +1442,7 @@
 				 dbuf.list);
 		hbq_buffer->tag = (phba->hbqs[hbqno].buffer_count |
 				      (hbqno << 16));
-		if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) {
+		if (!lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) {
 			phba->hbqs[hbqno].buffer_count++;
 			posted++;
 		} else
@@ -965,6 +1493,25 @@
 }
 
 /**
+ * lpfc_sli_hbqbuf_get - Remove the first hbq off of an hbq list
+ * @phba: Pointer to HBA context object.
+ * @hbqno: HBQ number.
+ *
+ * This function removes the first hbq buffer on an hbq list and returns a
+ * pointer to that buffer. If it finds no buffers on the list it returns NULL.
+ **/
+static struct hbq_dmabuf *
+lpfc_sli_hbqbuf_get(struct list_head *rb_list)
+{
+	struct lpfc_dmabuf *d_buf;
+
+	list_remove_head(rb_list, d_buf, struct lpfc_dmabuf, list);
+	if (!d_buf)
+		return NULL;
+	return container_of(d_buf, struct hbq_dmabuf, dbuf);
+}
+
+/**
  * lpfc_sli_hbqbuf_find - Find the hbq buffer associated with a tag
  * @phba: Pointer to HBA context object.
  * @tag: Tag of the hbq buffer.
@@ -985,12 +1532,15 @@
 	if (hbqno >= LPFC_MAX_HBQS)
 		return NULL;
 
+	spin_lock_irq(&phba->hbalock);
 	list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) {
 		hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
 		if (hbq_buf->tag == tag) {
+			spin_unlock_irq(&phba->hbalock);
 			return hbq_buf;
 		}
 	}
+	spin_unlock_irq(&phba->hbalock);
 	lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT,
 			"1803 Bad hbq tag. Data: x%x x%x\n",
 			tag, phba->hbqs[tag >> 16].buffer_count);
@@ -1013,9 +1563,8 @@
 
 	if (hbq_buffer) {
 		hbqno = hbq_buffer->tag >> 16;
-		if (!lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) {
+		if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer))
 			(phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
-		}
 	}
 }
 
@@ -1086,6 +1635,15 @@
 	case MBX_HEARTBEAT:
 	case MBX_PORT_CAPABILITIES:
 	case MBX_PORT_IOV_CONTROL:
+	case MBX_SLI4_CONFIG:
+	case MBX_SLI4_REQ_FTRS:
+	case MBX_REG_FCFI:
+	case MBX_UNREG_FCFI:
+	case MBX_REG_VFI:
+	case MBX_UNREG_VFI:
+	case MBX_INIT_VPI:
+	case MBX_INIT_VFI:
+	case MBX_RESUME_RPI:
 		ret = mbxCommand;
 		break;
 	default:
@@ -1106,7 +1664,7 @@
  * will wake up thread waiting on the wait queue pointed by context1
  * of the mailbox.
  **/
-static void
+void
 lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
 {
 	wait_queue_head_t *pdone_q;
@@ -1140,7 +1698,7 @@
 lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
 	struct lpfc_dmabuf *mp;
-	uint16_t rpi;
+	uint16_t rpi, vpi;
 	int rc;
 
 	mp = (struct lpfc_dmabuf *) (pmb->context1);
@@ -1150,24 +1708,30 @@
 		kfree(mp);
 	}
 
+	if ((pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) &&
+	    (phba->sli_rev == LPFC_SLI_REV4))
+		lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi);
+
 	/*
 	 * If a REG_LOGIN succeeded  after node is destroyed or node
 	 * is in re-discovery driver need to cleanup the RPI.
 	 */
 	if (!(phba->pport->load_flag & FC_UNLOADING) &&
-	    pmb->mb.mbxCommand == MBX_REG_LOGIN64 &&
-	    !pmb->mb.mbxStatus) {
-
-		rpi = pmb->mb.un.varWords[0];
-		lpfc_unreg_login(phba, pmb->mb.un.varRegLogin.vpi, rpi, pmb);
+	    pmb->u.mb.mbxCommand == MBX_REG_LOGIN64 &&
+	    !pmb->u.mb.mbxStatus) {
+		rpi = pmb->u.mb.un.varWords[0];
+		vpi = pmb->u.mb.un.varRegLogin.vpi - phba->vpi_base;
+		lpfc_unreg_login(phba, vpi, rpi, pmb);
 		pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
 		if (rc != MBX_NOT_FINISHED)
 			return;
 	}
 
-	mempool_free(pmb, phba->mbox_mem_pool);
-	return;
+	if (bf_get(lpfc_mqe_command, &pmb->u.mqe) == MBX_SLI4_CONFIG)
+		lpfc_sli4_mbox_cmd_free(phba, pmb);
+	else
+		mempool_free(pmb, phba->mbox_mem_pool);
 }
 
 /**
@@ -1204,7 +1768,7 @@
 		if (pmb == NULL)
 			break;
 
-		pmbox = &pmb->mb;
+		pmbox = &pmb->u.mb;
 
 		if (pmbox->mbxCommand != MBX_HEARTBEAT) {
 			if (pmb->vport) {
@@ -1233,9 +1797,10 @@
 			/* Unknow mailbox command compl */
 			lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
 					"(%d):0323 Unknown Mailbox command "
-					"%x Cmpl\n",
+					"x%x (x%x) Cmpl\n",
 					pmb->vport ? pmb->vport->vpi : 0,
-					pmbox->mbxCommand);
+					pmbox->mbxCommand,
+					lpfc_sli4_mbox_opcode_get(phba, pmb));
 			phba->link_state = LPFC_HBA_ERROR;
 			phba->work_hs = HS_FFER3;
 			lpfc_handle_eratt(phba);
@@ -1250,29 +1815,29 @@
 						LOG_MBOX | LOG_SLI,
 						"(%d):0305 Mbox cmd cmpl "
 						"error - RETRYing Data: x%x "
-						"x%x x%x x%x\n",
+						"(x%x) x%x x%x x%x\n",
 						pmb->vport ? pmb->vport->vpi :0,
 						pmbox->mbxCommand,
+						lpfc_sli4_mbox_opcode_get(phba,
+									  pmb),
 						pmbox->mbxStatus,
 						pmbox->un.varWords[0],
 						pmb->vport->port_state);
 				pmbox->mbxStatus = 0;
 				pmbox->mbxOwner = OWN_HOST;
-				spin_lock_irq(&phba->hbalock);
-				phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
-				spin_unlock_irq(&phba->hbalock);
 				rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
-				if (rc == MBX_SUCCESS)
+				if (rc != MBX_NOT_FINISHED)
 					continue;
 			}
 		}
 
 		/* Mailbox cmd <cmd> Cmpl <cmpl> */
 		lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
-				"(%d):0307 Mailbox cmd x%x Cmpl x%p "
+				"(%d):0307 Mailbox cmd x%x (x%x) Cmpl x%p "
 				"Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x\n",
 				pmb->vport ? pmb->vport->vpi : 0,
 				pmbox->mbxCommand,
+				lpfc_sli4_mbox_opcode_get(phba, pmb),
 				pmb->mbox_cmpl,
 				*((uint32_t *) pmbox),
 				pmbox->un.varWords[0],
@@ -1317,6 +1882,45 @@
 	return &hbq_entry->dbuf;
 }
 
+/**
+ * lpfc_complete_unsol_iocb - Complete an unsolicited sequence
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @saveq: Pointer to the iocbq struct representing the sequence starting frame.
+ * @fch_r_ctl: the r_ctl for the first frame of the sequence.
+ * @fch_type: the type for the first frame of the sequence.
+ *
+ * This function is called with no lock held. This function uses the r_ctl and
+ * type of the received sequence to find the correct callback function to call
+ * to process the sequence.
+ **/
+static int
+lpfc_complete_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+			 struct lpfc_iocbq *saveq, uint32_t fch_r_ctl,
+			 uint32_t fch_type)
+{
+	int i;
+
+	/* unSolicited Responses */
+	if (pring->prt[0].profile) {
+		if (pring->prt[0].lpfc_sli_rcv_unsol_event)
+			(pring->prt[0].lpfc_sli_rcv_unsol_event) (phba, pring,
+									saveq);
+		return 1;
+	}
+	/* We must search, based on rctl / type
+	   for the right routine */
+	for (i = 0; i < pring->num_mask; i++) {
+		if ((pring->prt[i].rctl == fch_r_ctl) &&
+		    (pring->prt[i].type == fch_type)) {
+			if (pring->prt[i].lpfc_sli_rcv_unsol_event)
+				(pring->prt[i].lpfc_sli_rcv_unsol_event)
+						(phba, pring, saveq);
+			return 1;
+		}
+	}
+	return 0;
+}
 
 /**
  * lpfc_sli_process_unsol_iocb - Unsolicited iocb handler
@@ -1339,7 +1943,7 @@
 	IOCB_t           * irsp;
 	WORD5            * w5p;
 	uint32_t           Rctl, Type;
-	uint32_t           match, i;
+	uint32_t           match;
 	struct lpfc_iocbq *iocbq;
 	struct lpfc_dmabuf *dmzbuf;
 
@@ -1482,35 +2086,12 @@
 		}
 	}
 
-	/* unSolicited Responses */
-	if (pring->prt[0].profile) {
-		if (pring->prt[0].lpfc_sli_rcv_unsol_event)
-			(pring->prt[0].lpfc_sli_rcv_unsol_event) (phba, pring,
-									saveq);
-		match = 1;
-	} else {
-		/* We must search, based on rctl / type
-		   for the right routine */
-		for (i = 0; i < pring->num_mask; i++) {
-			if ((pring->prt[i].rctl == Rctl)
-			    && (pring->prt[i].type == Type)) {
-				if (pring->prt[i].lpfc_sli_rcv_unsol_event)
-					(pring->prt[i].lpfc_sli_rcv_unsol_event)
-							(phba, pring, saveq);
-				match = 1;
-				break;
-			}
-		}
-	}
-	if (match == 0) {
-		/* Unexpected Rctl / Type received */
-		/* Ring <ringno> handler: unexpected
-		   Rctl <Rctl> Type <Type> received */
+	if (!lpfc_complete_unsol_iocb(phba, pring, saveq, Rctl, Type))
 		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
 				"0313 Ring %d handler: unexpected Rctl x%x "
 				"Type x%x received\n",
 				pring->ringno, Rctl, Type);
-	}
+
 	return 1;
 }
 
@@ -1552,6 +2133,37 @@
 }
 
 /**
+ * lpfc_sli_iocbq_lookup_by_tag - Find command iocb for the iotag
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @iotag: IOCB tag.
+ *
+ * This function looks up the iocb_lookup table to get the command iocb
+ * corresponding to the given iotag. This function is called with the
+ * hbalock held.
+ * This function returns the command iocb object if it finds the command
+ * iocb else returns NULL.
+ **/
+static struct lpfc_iocbq *
+lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
+			     struct lpfc_sli_ring *pring, uint16_t iotag)
+{
+	struct lpfc_iocbq *cmd_iocb;
+
+	if (iotag != 0 && iotag <= phba->sli.last_iotag) {
+		cmd_iocb = phba->sli.iocbq_lookup[iotag];
+		list_del_init(&cmd_iocb->list);
+		pring->txcmplq_cnt--;
+		return cmd_iocb;
+	}
+
+	lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+			"0372 iotag x%x is out off range: max iotag (x%x)\n",
+			iotag, phba->sli.last_iotag);
+	return NULL;
+}
+
+/**
  * lpfc_sli_process_sol_iocb - process solicited iocb completion
  * @phba: Pointer to HBA context object.
  * @pring: Pointer to driver SLI ring object.
@@ -1954,7 +2566,7 @@
 			if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
 				(irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) {
 				spin_unlock_irqrestore(&phba->hbalock, iflag);
-				lpfc_rampdown_queue_depth(phba);
+				phba->lpfc_rampdown_queue_depth(phba);
 				spin_lock_irqsave(&phba->hbalock, iflag);
 			}
 
@@ -2068,39 +2680,215 @@
 }
 
 /**
- * lpfc_sli_handle_slow_ring_event - Handle ring events for non-FCP rings
+ * lpfc_sli_sp_handle_rspiocb - Handle slow-path response iocb
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @rspiocbp: Pointer to driver response IOCB object.
+ *
+ * This function is called from the worker thread when there is a slow-path
+ * response IOCB to process. This function chains all the response iocbs until
+ * seeing the iocb with the LE bit set. The function will call
+ * lpfc_sli_process_sol_iocb function if the response iocb indicates a
+ * completion of a command iocb. The function will call the
+ * lpfc_sli_process_unsol_iocb function if this is an unsolicited iocb.
+ * The function frees the resources or calls the completion handler if this
+ * iocb is an abort completion. The function returns NULL when the response
+ * iocb has the LE bit set and all the chained iocbs are processed, otherwise
+ * this function shall chain the iocb on to the iocb_continueq and return the
+ * response iocb passed in.
+ **/
+static struct lpfc_iocbq *
+lpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+			struct lpfc_iocbq *rspiocbp)
+{
+	struct lpfc_iocbq *saveq;
+	struct lpfc_iocbq *cmdiocbp;
+	struct lpfc_iocbq *next_iocb;
+	IOCB_t *irsp = NULL;
+	uint32_t free_saveq;
+	uint8_t iocb_cmd_type;
+	lpfc_iocb_type type;
+	unsigned long iflag;
+	int rc;
+
+	spin_lock_irqsave(&phba->hbalock, iflag);
+	/* First add the response iocb to the countinueq list */
+	list_add_tail(&rspiocbp->list, &(pring->iocb_continueq));
+	pring->iocb_continueq_cnt++;
+
+	/* Now, determine whetehr the list is completed for processing */
+	irsp = &rspiocbp->iocb;
+	if (irsp->ulpLe) {
+		/*
+		 * By default, the driver expects to free all resources
+		 * associated with this iocb completion.
+		 */
+		free_saveq = 1;
+		saveq = list_get_first(&pring->iocb_continueq,
+				       struct lpfc_iocbq, list);
+		irsp = &(saveq->iocb);
+		list_del_init(&pring->iocb_continueq);
+		pring->iocb_continueq_cnt = 0;
+
+		pring->stats.iocb_rsp++;
+
+		/*
+		 * If resource errors reported from HBA, reduce
+		 * queuedepths of the SCSI device.
+		 */
+		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+		    (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) {
+			spin_unlock_irqrestore(&phba->hbalock, iflag);
+			phba->lpfc_rampdown_queue_depth(phba);
+			spin_lock_irqsave(&phba->hbalock, iflag);
+		}
+
+		if (irsp->ulpStatus) {
+			/* Rsp ring <ringno> error: IOCB */
+			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+					"0328 Rsp Ring %d error: "
+					"IOCB Data: "
+					"x%x x%x x%x x%x "
+					"x%x x%x x%x x%x "
+					"x%x x%x x%x x%x "
+					"x%x x%x x%x x%x\n",
+					pring->ringno,
+					irsp->un.ulpWord[0],
+					irsp->un.ulpWord[1],
+					irsp->un.ulpWord[2],
+					irsp->un.ulpWord[3],
+					irsp->un.ulpWord[4],
+					irsp->un.ulpWord[5],
+					*(((uint32_t *) irsp) + 6),
+					*(((uint32_t *) irsp) + 7),
+					*(((uint32_t *) irsp) + 8),
+					*(((uint32_t *) irsp) + 9),
+					*(((uint32_t *) irsp) + 10),
+					*(((uint32_t *) irsp) + 11),
+					*(((uint32_t *) irsp) + 12),
+					*(((uint32_t *) irsp) + 13),
+					*(((uint32_t *) irsp) + 14),
+					*(((uint32_t *) irsp) + 15));
+		}
+
+		/*
+		 * Fetch the IOCB command type and call the correct completion
+		 * routine. Solicited and Unsolicited IOCBs on the ELS ring
+		 * get freed back to the lpfc_iocb_list by the discovery
+		 * kernel thread.
+		 */
+		iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK;
+		type = lpfc_sli_iocb_cmd_type(iocb_cmd_type);
+		switch (type) {
+		case LPFC_SOL_IOCB:
+			spin_unlock_irqrestore(&phba->hbalock, iflag);
+			rc = lpfc_sli_process_sol_iocb(phba, pring, saveq);
+			spin_lock_irqsave(&phba->hbalock, iflag);
+			break;
+
+		case LPFC_UNSOL_IOCB:
+			spin_unlock_irqrestore(&phba->hbalock, iflag);
+			rc = lpfc_sli_process_unsol_iocb(phba, pring, saveq);
+			spin_lock_irqsave(&phba->hbalock, iflag);
+			if (!rc)
+				free_saveq = 0;
+			break;
+
+		case LPFC_ABORT_IOCB:
+			cmdiocbp = NULL;
+			if (irsp->ulpCommand != CMD_XRI_ABORTED_CX)
+				cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring,
+								 saveq);
+			if (cmdiocbp) {
+				/* Call the specified completion routine */
+				if (cmdiocbp->iocb_cmpl) {
+					spin_unlock_irqrestore(&phba->hbalock,
+							       iflag);
+					(cmdiocbp->iocb_cmpl)(phba, cmdiocbp,
+							      saveq);
+					spin_lock_irqsave(&phba->hbalock,
+							  iflag);
+				} else
+					__lpfc_sli_release_iocbq(phba,
+								 cmdiocbp);
+			}
+			break;
+
+		case LPFC_UNKNOWN_IOCB:
+			if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
+				char adaptermsg[LPFC_MAX_ADPTMSG];
+				memset(adaptermsg, 0, LPFC_MAX_ADPTMSG);
+				memcpy(&adaptermsg[0], (uint8_t *)irsp,
+				       MAX_MSG_DATA);
+				dev_warn(&((phba->pcidev)->dev),
+					 "lpfc%d: %s\n",
+					 phba->brd_no, adaptermsg);
+			} else {
+				/* Unknown IOCB command */
+				lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+						"0335 Unknown IOCB "
+						"command Data: x%x "
+						"x%x x%x x%x\n",
+						irsp->ulpCommand,
+						irsp->ulpStatus,
+						irsp->ulpIoTag,
+						irsp->ulpContext);
+			}
+			break;
+		}
+
+		if (free_saveq) {
+			list_for_each_entry_safe(rspiocbp, next_iocb,
+						 &saveq->list, list) {
+				list_del(&rspiocbp->list);
+				__lpfc_sli_release_iocbq(phba, rspiocbp);
+			}
+			__lpfc_sli_release_iocbq(phba, saveq);
+		}
+		rspiocbp = NULL;
+	}
+	spin_unlock_irqrestore(&phba->hbalock, iflag);
+	return rspiocbp;
+}
+
+/**
+ * lpfc_sli_handle_slow_ring_event - Wrapper func for handling slow-path iocbs
  * @phba: Pointer to HBA context object.
  * @pring: Pointer to driver SLI ring object.
  * @mask: Host attention register mask for this ring.
  *
- * This function is called from the worker thread when there is a ring
- * event for non-fcp rings. The caller does not hold any lock .
- * The function processes each response iocb in the response ring until it
- * finds an iocb with LE bit set and chains all the iocbs upto the iocb with
- * LE bit set. The function will call lpfc_sli_process_sol_iocb function if the
- * response iocb indicates a completion of a command iocb. The function
- * will call lpfc_sli_process_unsol_iocb function if this is an unsolicited
- * iocb. The function frees the resources or calls the completion handler if
- * this iocb is an abort completion. The function returns 0 when the allocated
- * iocbs are not freed, otherwise returns 1.
+ * This routine wraps the actual slow_ring event process routine from the
+ * API jump table function pointer from the lpfc_hba struct.
  **/
-int
+void
 lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 				struct lpfc_sli_ring *pring, uint32_t mask)
 {
+	phba->lpfc_sli_handle_slow_ring_event(phba, pring, mask);
+}
+
+/**
+ * lpfc_sli_handle_slow_ring_event_s3 - Handle SLI3 ring event for non-FCP rings
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @mask: Host attention register mask for this ring.
+ *
+ * This function is called from the worker thread when there is a ring event
+ * for non-fcp rings. The caller does not hold any lock. The function will
+ * remove each response iocb in the response ring and calls the handle
+ * response iocb routine (lpfc_sli_sp_handle_rspiocb) to process it.
+ **/
+static void
+lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba,
+				   struct lpfc_sli_ring *pring, uint32_t mask)
+{
 	struct lpfc_pgp *pgp;
 	IOCB_t *entry;
 	IOCB_t *irsp = NULL;
 	struct lpfc_iocbq *rspiocbp = NULL;
-	struct lpfc_iocbq *next_iocb;
-	struct lpfc_iocbq *cmdiocbp;
-	struct lpfc_iocbq *saveq;
-	uint8_t iocb_cmd_type;
-	lpfc_iocb_type type;
-	uint32_t status, free_saveq;
 	uint32_t portRspPut, portRspMax;
-	int rc = 1;
 	unsigned long iflag;
+	uint32_t status;
 
 	pgp = &phba->port_gp[pring->ringno];
 	spin_lock_irqsave(&phba->hbalock, iflag);
@@ -2128,7 +2916,7 @@
 		phba->work_hs = HS_FFER3;
 		lpfc_handle_eratt(phba);
 
-		return 1;
+		return;
 	}
 
 	rmb();
@@ -2173,138 +2961,10 @@
 
 		writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
 
-		list_add_tail(&rspiocbp->list, &(pring->iocb_continueq));
-
-		pring->iocb_continueq_cnt++;
-		if (irsp->ulpLe) {
-			/*
-			 * By default, the driver expects to free all resources
-			 * associated with this iocb completion.
-			 */
-			free_saveq = 1;
-			saveq = list_get_first(&pring->iocb_continueq,
-					       struct lpfc_iocbq, list);
-			irsp = &(saveq->iocb);
-			list_del_init(&pring->iocb_continueq);
-			pring->iocb_continueq_cnt = 0;
-
-			pring->stats.iocb_rsp++;
-
-			/*
-			 * If resource errors reported from HBA, reduce
-			 * queuedepths of the SCSI device.
-			 */
-			if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
-			     (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) {
-				spin_unlock_irqrestore(&phba->hbalock, iflag);
-				lpfc_rampdown_queue_depth(phba);
-				spin_lock_irqsave(&phba->hbalock, iflag);
-			}
-
-			if (irsp->ulpStatus) {
-				/* Rsp ring <ringno> error: IOCB */
-				lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
-						"0328 Rsp Ring %d error: "
-						"IOCB Data: "
-						"x%x x%x x%x x%x "
-						"x%x x%x x%x x%x "
-						"x%x x%x x%x x%x "
-						"x%x x%x x%x x%x\n",
-						pring->ringno,
-						irsp->un.ulpWord[0],
-						irsp->un.ulpWord[1],
-						irsp->un.ulpWord[2],
-						irsp->un.ulpWord[3],
-						irsp->un.ulpWord[4],
-						irsp->un.ulpWord[5],
-						*(((uint32_t *) irsp) + 6),
-						*(((uint32_t *) irsp) + 7),
-						*(((uint32_t *) irsp) + 8),
-						*(((uint32_t *) irsp) + 9),
-						*(((uint32_t *) irsp) + 10),
-						*(((uint32_t *) irsp) + 11),
-						*(((uint32_t *) irsp) + 12),
-						*(((uint32_t *) irsp) + 13),
-						*(((uint32_t *) irsp) + 14),
-						*(((uint32_t *) irsp) + 15));
-			}
-
-			/*
-			 * Fetch the IOCB command type and call the correct
-			 * completion routine.  Solicited and Unsolicited
-			 * IOCBs on the ELS ring get freed back to the
-			 * lpfc_iocb_list by the discovery kernel thread.
-			 */
-			iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK;
-			type = lpfc_sli_iocb_cmd_type(iocb_cmd_type);
-			if (type == LPFC_SOL_IOCB) {
-				spin_unlock_irqrestore(&phba->hbalock, iflag);
-				rc = lpfc_sli_process_sol_iocb(phba, pring,
-							       saveq);
-				spin_lock_irqsave(&phba->hbalock, iflag);
-			} else if (type == LPFC_UNSOL_IOCB) {
-				spin_unlock_irqrestore(&phba->hbalock, iflag);
-				rc = lpfc_sli_process_unsol_iocb(phba, pring,
-								 saveq);
-				spin_lock_irqsave(&phba->hbalock, iflag);
-				if (!rc)
-					free_saveq = 0;
-			} else if (type == LPFC_ABORT_IOCB) {
-				if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) &&
-				    ((cmdiocbp =
-				      lpfc_sli_iocbq_lookup(phba, pring,
-							    saveq)))) {
-					/* Call the specified completion
-					   routine */
-					if (cmdiocbp->iocb_cmpl) {
-						spin_unlock_irqrestore(
-						       &phba->hbalock,
-						       iflag);
-						(cmdiocbp->iocb_cmpl) (phba,
-							     cmdiocbp, saveq);
-						spin_lock_irqsave(
-							  &phba->hbalock,
-							  iflag);
-					} else
-						__lpfc_sli_release_iocbq(phba,
-								      cmdiocbp);
-				}
-			} else if (type == LPFC_UNKNOWN_IOCB) {
-				if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
-
-					char adaptermsg[LPFC_MAX_ADPTMSG];
-
-					memset(adaptermsg, 0,
-					       LPFC_MAX_ADPTMSG);
-					memcpy(&adaptermsg[0], (uint8_t *) irsp,
-					       MAX_MSG_DATA);
-					dev_warn(&((phba->pcidev)->dev),
-						 "lpfc%d: %s\n",
-						 phba->brd_no, adaptermsg);
-				} else {
-					/* Unknown IOCB command */
-					lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-							"0335 Unknown IOCB "
-							"command Data: x%x "
-							"x%x x%x x%x\n",
-							irsp->ulpCommand,
-							irsp->ulpStatus,
-							irsp->ulpIoTag,
-							irsp->ulpContext);
-				}
-			}
-
-			if (free_saveq) {
-				list_for_each_entry_safe(rspiocbp, next_iocb,
-							 &saveq->list, list) {
-					list_del(&rspiocbp->list);
-					__lpfc_sli_release_iocbq(phba,
-								 rspiocbp);
-				}
-				__lpfc_sli_release_iocbq(phba, saveq);
-			}
-			rspiocbp = NULL;
-		}
+		spin_unlock_irqrestore(&phba->hbalock, iflag);
+		/* Handle the response IOCB */
+		rspiocbp = lpfc_sli_sp_handle_rspiocb(phba, pring, rspiocbp);
+		spin_lock_irqsave(&phba->hbalock, iflag);
 
 		/*
 		 * If the port response put pointer has not been updated, sync
@@ -2338,7 +2998,37 @@
 	}
 
 	spin_unlock_irqrestore(&phba->hbalock, iflag);
-	return rc;
+	return;
+}
+
+/**
+ * lpfc_sli_handle_slow_ring_event_s4 - Handle SLI4 slow-path els events
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @mask: Host attention register mask for this ring.
+ *
+ * This function is called from the worker thread when there is a pending
+ * ELS response iocb on the driver internal slow-path response iocb worker
+ * queue. The caller does not hold any lock. The function will remove each
+ * response iocb from the response worker queue and calls the handle
+ * response iocb routine (lpfc_sli_sp_handle_rspiocb) to process it.
+ **/
+static void
+lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba,
+				   struct lpfc_sli_ring *pring, uint32_t mask)
+{
+	struct lpfc_iocbq *irspiocbq;
+	unsigned long iflag;
+
+	while (!list_empty(&phba->sli4_hba.sp_rspiocb_work_queue)) {
+		/* Get the response iocb from the head of work queue */
+		spin_lock_irqsave(&phba->hbalock, iflag);
+		list_remove_head(&phba->sli4_hba.sp_rspiocb_work_queue,
+				 irspiocbq, struct lpfc_iocbq, list);
+		spin_unlock_irqrestore(&phba->hbalock, iflag);
+		/* Process the response iocb */
+		lpfc_sli_sp_handle_rspiocb(phba, pring, irspiocbq);
+	}
 }
 
 /**
@@ -2420,7 +3110,7 @@
 }
 
 /**
- * lpfc_sli_brdready - Check for host status bits
+ * lpfc_sli_brdready_s3 - Check for sli3 host ready status
  * @phba: Pointer to HBA context object.
  * @mask: Bit mask to be checked.
  *
@@ -2432,8 +3122,8 @@
  * function returns 1 when HBA fail to restart otherwise returns
  * zero.
  **/
-int
-lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask)
+static int
+lpfc_sli_brdready_s3(struct lpfc_hba *phba, uint32_t mask)
 {
 	uint32_t status;
 	int i = 0;
@@ -2477,6 +3167,56 @@
 	return retval;
 }
 
+/**
+ * lpfc_sli_brdready_s4 - Check for sli4 host ready status
+ * @phba: Pointer to HBA context object.
+ * @mask: Bit mask to be checked.
+ *
+ * This function checks the host status register to check if HBA is
+ * ready. This function will wait in a loop for the HBA to be ready
+ * If the HBA is not ready , the function will will reset the HBA PCI
+ * function again. The function returns 1 when HBA fail to be ready
+ * otherwise returns zero.
+ **/
+static int
+lpfc_sli_brdready_s4(struct lpfc_hba *phba, uint32_t mask)
+{
+	uint32_t status;
+	int retval = 0;
+
+	/* Read the HBA Host Status Register */
+	status = lpfc_sli4_post_status_check(phba);
+
+	if (status) {
+		phba->pport->port_state = LPFC_VPORT_UNKNOWN;
+		lpfc_sli_brdrestart(phba);
+		status = lpfc_sli4_post_status_check(phba);
+	}
+
+	/* Check to see if any errors occurred during init */
+	if (status) {
+		phba->link_state = LPFC_HBA_ERROR;
+		retval = 1;
+	} else
+		phba->sli4_hba.intr_enable = 0;
+
+	return retval;
+}
+
+/**
+ * lpfc_sli_brdready - Wrapper func for checking the hba readyness
+ * @phba: Pointer to HBA context object.
+ * @mask: Bit mask to be checked.
+ *
+ * This routine wraps the actual SLI3 or SLI4 hba readyness check routine
+ * from the API jump table function pointer from the lpfc_hba struct.
+ **/
+int
+lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask)
+{
+	return phba->lpfc_sli_brdready(phba, mask);
+}
+
 #define BARRIER_TEST_PATTERN (0xdeadbeef)
 
 /**
@@ -2532,7 +3272,7 @@
 		mdelay(1);
 
 	if (readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN)) {
-		if (phba->sli.sli_flag & LPFC_SLI2_ACTIVE ||
+		if (phba->sli.sli_flag & LPFC_SLI_ACTIVE ||
 		    phba->pport->stopped)
 			goto restore_hc;
 		else
@@ -2613,7 +3353,9 @@
 		return 1;
 	}
 
-	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+	spin_lock_irq(&phba->hbalock);
+	psli->sli_flag &= ~LPFC_SLI_ACTIVE;
+	spin_unlock_irq(&phba->hbalock);
 
 	mempool_free(pmb, phba->mbox_mem_pool);
 
@@ -2636,10 +3378,10 @@
 	}
 	spin_lock_irq(&phba->hbalock);
 	psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+	psli->mbox_active = NULL;
 	phba->link_flag &= ~LS_IGNORE_ERATT;
 	spin_unlock_irq(&phba->hbalock);
 
-	psli->mbox_active = NULL;
 	lpfc_hba_down_post(phba);
 	phba->link_state = LPFC_HBA_ERROR;
 
@@ -2647,7 +3389,7 @@
 }
 
 /**
- * lpfc_sli_brdreset - Reset the HBA
+ * lpfc_sli_brdreset - Reset a sli-2 or sli-3 HBA
  * @phba: Pointer to HBA context object.
  *
  * This function resets the HBA by writing HC_INITFF to the control
@@ -2683,7 +3425,8 @@
 			      (cfg_value &
 			       ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
 
-	psli->sli_flag &= ~(LPFC_SLI2_ACTIVE | LPFC_PROCESS_LA);
+	psli->sli_flag &= ~(LPFC_SLI_ACTIVE | LPFC_PROCESS_LA);
+
 	/* Now toggle INITFF bit in the Host Control Register */
 	writel(HC_INITFF, phba->HCregaddr);
 	mdelay(1);
@@ -2710,7 +3453,66 @@
 }
 
 /**
- * lpfc_sli_brdrestart - Restart the HBA
+ * lpfc_sli4_brdreset - Reset a sli-4 HBA
+ * @phba: Pointer to HBA context object.
+ *
+ * This function resets a SLI4 HBA. This function disables PCI layer parity
+ * checking during resets the device. The caller is not required to hold
+ * any locks.
+ *
+ * This function returns 0 always.
+ **/
+int
+lpfc_sli4_brdreset(struct lpfc_hba *phba)
+{
+	struct lpfc_sli *psli = &phba->sli;
+	uint16_t cfg_value;
+	uint8_t qindx;
+
+	/* Reset HBA */
+	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+			"0295 Reset HBA Data: x%x x%x\n",
+			phba->pport->port_state, psli->sli_flag);
+
+	/* perform board reset */
+	phba->fc_eventTag = 0;
+	phba->pport->fc_myDID = 0;
+	phba->pport->fc_prevDID = 0;
+
+	/* Turn off parity checking and serr during the physical reset */
+	pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);
+	pci_write_config_word(phba->pcidev, PCI_COMMAND,
+			      (cfg_value &
+			      ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
+
+	spin_lock_irq(&phba->hbalock);
+	psli->sli_flag &= ~(LPFC_PROCESS_LA);
+	phba->fcf.fcf_flag = 0;
+	/* Clean up the child queue list for the CQs */
+	list_del_init(&phba->sli4_hba.mbx_wq->list);
+	list_del_init(&phba->sli4_hba.els_wq->list);
+	list_del_init(&phba->sli4_hba.hdr_rq->list);
+	list_del_init(&phba->sli4_hba.dat_rq->list);
+	list_del_init(&phba->sli4_hba.mbx_cq->list);
+	list_del_init(&phba->sli4_hba.els_cq->list);
+	list_del_init(&phba->sli4_hba.rxq_cq->list);
+	for (qindx = 0; qindx < phba->cfg_fcp_wq_count; qindx++)
+		list_del_init(&phba->sli4_hba.fcp_wq[qindx]->list);
+	for (qindx = 0; qindx < phba->cfg_fcp_eq_count; qindx++)
+		list_del_init(&phba->sli4_hba.fcp_cq[qindx]->list);
+	spin_unlock_irq(&phba->hbalock);
+
+	/* Now physically reset the device */
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"0389 Performing PCI function reset!\n");
+	/* Perform FCoE PCI function reset */
+	lpfc_pci_function_reset(phba);
+
+	return 0;
+}
+
+/**
+ * lpfc_sli_brdrestart_s3 - Restart a sli-3 hba
  * @phba: Pointer to HBA context object.
  *
  * This function is called in the SLI initialization code path to
@@ -2722,8 +3524,8 @@
  * The function does not guarantee completion of MBX_RESTART mailbox
  * command before the return of this function.
  **/
-int
-lpfc_sli_brdrestart(struct lpfc_hba *phba)
+static int
+lpfc_sli_brdrestart_s3(struct lpfc_hba *phba)
 {
 	MAILBOX_t *mb;
 	struct lpfc_sli *psli;
@@ -2762,7 +3564,7 @@
 	lpfc_sli_brdreset(phba);
 	phba->pport->stopped = 0;
 	phba->link_state = LPFC_INIT_START;
-
+	phba->hba_flag = 0;
 	spin_unlock_irq(&phba->hbalock);
 
 	memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
@@ -2777,6 +3579,55 @@
 }
 
 /**
+ * lpfc_sli_brdrestart_s4 - Restart the sli-4 hba
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called in the SLI initialization code path to restart
+ * a SLI4 HBA. The caller is not required to hold any lock.
+ * At the end of the function, it calls lpfc_hba_down_post function to
+ * free any pending commands.
+ **/
+static int
+lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
+{
+	struct lpfc_sli *psli = &phba->sli;
+
+
+	/* Restart HBA */
+	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+			"0296 Restart HBA Data: x%x x%x\n",
+			phba->pport->port_state, psli->sli_flag);
+
+	lpfc_sli4_brdreset(phba);
+
+	spin_lock_irq(&phba->hbalock);
+	phba->pport->stopped = 0;
+	phba->link_state = LPFC_INIT_START;
+	phba->hba_flag = 0;
+	spin_unlock_irq(&phba->hbalock);
+
+	memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
+	psli->stats_start = get_seconds();
+
+	lpfc_hba_down_post(phba);
+
+	return 0;
+}
+
+/**
+ * lpfc_sli_brdrestart - Wrapper func for restarting hba
+ * @phba: Pointer to HBA context object.
+ *
+ * This routine wraps the actual SLI3 or SLI4 hba restart routine from the
+ * API jump table function pointer from the lpfc_hba struct.
+**/
+int
+lpfc_sli_brdrestart(struct lpfc_hba *phba)
+{
+	return phba->lpfc_sli_brdrestart(phba);
+}
+
+/**
  * lpfc_sli_chipset_init - Wait for the restart of the HBA after a restart
  * @phba: Pointer to HBA context object.
  *
@@ -2940,7 +3791,7 @@
 	if (!pmb)
 		return -ENOMEM;
 
-	pmbox = &pmb->mb;
+	pmbox = &pmb->u.mb;
 
 	/* Initialize the struct lpfc_sli_hbq structure for each hbq */
 	phba->link_state = LPFC_INIT_MBX_CMDS;
@@ -2984,6 +3835,26 @@
 }
 
 /**
+ * lpfc_sli4_rb_setup - Initialize and post RBs to HBA
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called during the SLI initialization to configure
+ * all the HBQs and post buffers to the HBQ. The caller is not
+ * required to hold any locks. This function will return zero if successful
+ * else it will return negative error code.
+ **/
+static int
+lpfc_sli4_rb_setup(struct lpfc_hba *phba)
+{
+	phba->hbq_in_use = 1;
+	phba->hbqs[0].entry_count = lpfc_hbq_defs[0]->entry_count;
+	phba->hbq_count = 1;
+	/* Initially populate or replenish the HBQs */
+	lpfc_sli_hbqbuf_init_hbqs(phba, 0);
+	return 0;
+}
+
+/**
  * lpfc_sli_config_port - Issue config port mailbox command
  * @phba: Pointer to HBA context object.
  * @sli_mode: sli mode - 2/3
@@ -3047,33 +3918,43 @@
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"0442 Adapter failed to init, mbxCmd x%x "
 				"CONFIG_PORT, mbxStatus x%x Data: x%x\n",
-				pmb->mb.mbxCommand, pmb->mb.mbxStatus, 0);
+				pmb->u.mb.mbxCommand, pmb->u.mb.mbxStatus, 0);
 			spin_lock_irq(&phba->hbalock);
-			phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;
+			phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE;
 			spin_unlock_irq(&phba->hbalock);
 			rc = -ENXIO;
-		} else
+		} else {
+			/* Allow asynchronous mailbox command to go through */
+			spin_lock_irq(&phba->hbalock);
+			phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK;
+			spin_unlock_irq(&phba->hbalock);
 			done = 1;
+		}
 	}
 	if (!done) {
 		rc = -EINVAL;
 		goto do_prep_failed;
 	}
-	if (pmb->mb.un.varCfgPort.sli_mode == 3) {
-		if (!pmb->mb.un.varCfgPort.cMA) {
+	if (pmb->u.mb.un.varCfgPort.sli_mode == 3) {
+		if (!pmb->u.mb.un.varCfgPort.cMA) {
 			rc = -ENXIO;
 			goto do_prep_failed;
 		}
-		if (phba->max_vpi && pmb->mb.un.varCfgPort.gmv) {
+		if (phba->max_vpi && pmb->u.mb.un.varCfgPort.gmv) {
 			phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
-			phba->max_vpi = pmb->mb.un.varCfgPort.max_vpi;
+			phba->max_vpi = pmb->u.mb.un.varCfgPort.max_vpi;
+			phba->max_vports = (phba->max_vpi > phba->max_vports) ?
+				phba->max_vpi : phba->max_vports;
+
 		} else
 			phba->max_vpi = 0;
-		if (pmb->mb.un.varCfgPort.gerbm)
+		if (pmb->u.mb.un.varCfgPort.gdss)
+			phba->sli3_options |= LPFC_SLI3_DSS_ENABLED;
+		if (pmb->u.mb.un.varCfgPort.gerbm)
 			phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED;
-		if (pmb->mb.un.varCfgPort.gcrp)
+		if (pmb->u.mb.un.varCfgPort.gcrp)
 			phba->sli3_options |= LPFC_SLI3_CRP_ENABLED;
-		if (pmb->mb.un.varCfgPort.ginb) {
+		if (pmb->u.mb.un.varCfgPort.ginb) {
 			phba->sli3_options |= LPFC_SLI3_INB_ENABLED;
 			phba->hbq_get = phba->mbox->us.s3_inb_pgp.hbq_get;
 			phba->port_gp = phba->mbox->us.s3_inb_pgp.port;
@@ -3089,7 +3970,7 @@
 		}
 
 		if (phba->cfg_enable_bg) {
-			if (pmb->mb.un.varCfgPort.gbg)
+			if (pmb->u.mb.un.varCfgPort.gbg)
 				phba->sli3_options |= LPFC_SLI3_BG_ENABLED;
 			else
 				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -3184,8 +4065,9 @@
 		if (rc)
 			goto lpfc_sli_hba_setup_error;
 	}
-
+	spin_lock_irq(&phba->hbalock);
 	phba->sli.sli_flag |= LPFC_PROCESS_LA;
+	spin_unlock_irq(&phba->hbalock);
 
 	rc = lpfc_config_port_post(phba);
 	if (rc)
@@ -3200,6 +4082,488 @@
 	return rc;
 }
 
+/**
+ * lpfc_sli4_read_fcoe_params - Read fcoe params from conf region
+ * @phba: Pointer to HBA context object.
+ * @mboxq: mailbox pointer.
+ * This function issue a dump mailbox command to read config region
+ * 23 and parse the records in the region and populate driver
+ * data structure.
+ **/
+static int
+lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba,
+		LPFC_MBOXQ_t *mboxq)
+{
+	struct lpfc_dmabuf *mp;
+	struct lpfc_mqe *mqe;
+	uint32_t data_length;
+	int rc;
+
+	/* Program the default value of vlan_id and fc_map */
+	phba->valid_vlan = 0;
+	phba->fc_map[0] = LPFC_FCOE_FCF_MAP0;
+	phba->fc_map[1] = LPFC_FCOE_FCF_MAP1;
+	phba->fc_map[2] = LPFC_FCOE_FCF_MAP2;
+
+	mqe = &mboxq->u.mqe;
+	if (lpfc_dump_fcoe_param(phba, mboxq))
+		return -ENOMEM;
+
+	mp = (struct lpfc_dmabuf *) mboxq->context1;
+	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+			"(%d):2571 Mailbox cmd x%x Status x%x "
+			"Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x "
+			"x%x x%x x%x x%x x%x x%x x%x x%x x%x "
+			"CQ: x%x x%x x%x x%x\n",
+			mboxq->vport ? mboxq->vport->vpi : 0,
+			bf_get(lpfc_mqe_command, mqe),
+			bf_get(lpfc_mqe_status, mqe),
+			mqe->un.mb_words[0], mqe->un.mb_words[1],
+			mqe->un.mb_words[2], mqe->un.mb_words[3],
+			mqe->un.mb_words[4], mqe->un.mb_words[5],
+			mqe->un.mb_words[6], mqe->un.mb_words[7],
+			mqe->un.mb_words[8], mqe->un.mb_words[9],
+			mqe->un.mb_words[10], mqe->un.mb_words[11],
+			mqe->un.mb_words[12], mqe->un.mb_words[13],
+			mqe->un.mb_words[14], mqe->un.mb_words[15],
+			mqe->un.mb_words[16], mqe->un.mb_words[50],
+			mboxq->mcqe.word0,
+			mboxq->mcqe.mcqe_tag0, 	mboxq->mcqe.mcqe_tag1,
+			mboxq->mcqe.trailer);
+
+	if (rc) {
+		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+		kfree(mp);
+		return -EIO;
+	}
+	data_length = mqe->un.mb_words[5];
+	if (data_length > DMP_FCOEPARAM_RGN_SIZE)
+		return -EIO;
+
+	lpfc_parse_fcoe_conf(phba, mp->virt, data_length);
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+	kfree(mp);
+	return 0;
+}
+
+/**
+ * lpfc_sli4_read_rev - Issue READ_REV and collect vpd data
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: pointer to the LPFC_MBOXQ_t structure.
+ * @vpd: pointer to the memory to hold resulting port vpd data.
+ * @vpd_size: On input, the number of bytes allocated to @vpd.
+ *	      On output, the number of data bytes in @vpd.
+ *
+ * This routine executes a READ_REV SLI4 mailbox command.  In
+ * addition, this routine gets the port vpd data.
+ *
+ * Return codes
+ * 	0 - sucessful
+ * 	ENOMEM - could not allocated memory.
+ **/
+static int
+lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
+		    uint8_t *vpd, uint32_t *vpd_size)
+{
+	int rc = 0;
+	uint32_t dma_size;
+	struct lpfc_dmabuf *dmabuf;
+	struct lpfc_mqe *mqe;
+
+	dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+	if (!dmabuf)
+		return -ENOMEM;
+
+	/*
+	 * Get a DMA buffer for the vpd data resulting from the READ_REV
+	 * mailbox command.
+	 */
+	dma_size = *vpd_size;
+	dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
+					  dma_size,
+					  &dmabuf->phys,
+					  GFP_KERNEL);
+	if (!dmabuf->virt) {
+		kfree(dmabuf);
+		return -ENOMEM;
+	}
+	memset(dmabuf->virt, 0, dma_size);
+
+	/*
+	 * The SLI4 implementation of READ_REV conflicts at word1,
+	 * bits 31:16 and SLI4 adds vpd functionality not present
+	 * in SLI3.  This code corrects the conflicts.
+	 */
+	lpfc_read_rev(phba, mboxq);
+	mqe = &mboxq->u.mqe;
+	mqe->un.read_rev.vpd_paddr_high = putPaddrHigh(dmabuf->phys);
+	mqe->un.read_rev.vpd_paddr_low = putPaddrLow(dmabuf->phys);
+	mqe->un.read_rev.word1 &= 0x0000FFFF;
+	bf_set(lpfc_mbx_rd_rev_vpd, &mqe->un.read_rev, 1);
+	bf_set(lpfc_mbx_rd_rev_avail_len, &mqe->un.read_rev, dma_size);
+
+	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+	if (rc) {
+		dma_free_coherent(&phba->pcidev->dev, dma_size,
+				  dmabuf->virt, dmabuf->phys);
+		return -EIO;
+	}
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+			"(%d):0380 Mailbox cmd x%x Status x%x "
+			"Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x "
+			"x%x x%x x%x x%x x%x x%x x%x x%x x%x "
+			"CQ: x%x x%x x%x x%x\n",
+			mboxq->vport ? mboxq->vport->vpi : 0,
+			bf_get(lpfc_mqe_command, mqe),
+			bf_get(lpfc_mqe_status, mqe),
+			mqe->un.mb_words[0], mqe->un.mb_words[1],
+			mqe->un.mb_words[2], mqe->un.mb_words[3],
+			mqe->un.mb_words[4], mqe->un.mb_words[5],
+			mqe->un.mb_words[6], mqe->un.mb_words[7],
+			mqe->un.mb_words[8], mqe->un.mb_words[9],
+			mqe->un.mb_words[10], mqe->un.mb_words[11],
+			mqe->un.mb_words[12], mqe->un.mb_words[13],
+			mqe->un.mb_words[14], mqe->un.mb_words[15],
+			mqe->un.mb_words[16], mqe->un.mb_words[50],
+			mboxq->mcqe.word0,
+			mboxq->mcqe.mcqe_tag0, 	mboxq->mcqe.mcqe_tag1,
+			mboxq->mcqe.trailer);
+
+	/*
+	 * The available vpd length cannot be bigger than the
+	 * DMA buffer passed to the port.  Catch the less than
+	 * case and update the caller's size.
+	 */
+	if (mqe->un.read_rev.avail_vpd_len < *vpd_size)
+		*vpd_size = mqe->un.read_rev.avail_vpd_len;
+
+	lpfc_sli_pcimem_bcopy(dmabuf->virt, vpd, *vpd_size);
+	dma_free_coherent(&phba->pcidev->dev, dma_size,
+			  dmabuf->virt, dmabuf->phys);
+	kfree(dmabuf);
+	return 0;
+}
+
+/**
+ * lpfc_sli4_arm_cqeq_intr - Arm sli-4 device completion and event queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to explicitly arm the SLI4 device's completion and
+ * event queues
+ **/
+static void
+lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
+{
+	uint8_t fcp_eqidx;
+
+	lpfc_sli4_cq_release(phba->sli4_hba.mbx_cq, LPFC_QUEUE_REARM);
+	lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM);
+	lpfc_sli4_cq_release(phba->sli4_hba.rxq_cq, LPFC_QUEUE_REARM);
+	for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++)
+		lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[fcp_eqidx],
+				     LPFC_QUEUE_REARM);
+	lpfc_sli4_eq_release(phba->sli4_hba.sp_eq, LPFC_QUEUE_REARM);
+	for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++)
+		lpfc_sli4_eq_release(phba->sli4_hba.fp_eq[fcp_eqidx],
+				     LPFC_QUEUE_REARM);
+}
+
+/**
+ * lpfc_sli4_hba_setup - SLI4 device intialization PCI function
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is the main SLI4 device intialization PCI function. This
+ * function is called by the HBA intialization code, HBA reset code and
+ * HBA error attention handler code. Caller is not required to hold any
+ * locks.
+ **/
+int
+lpfc_sli4_hba_setup(struct lpfc_hba *phba)
+{
+	int rc;
+	LPFC_MBOXQ_t *mboxq;
+	struct lpfc_mqe *mqe;
+	uint8_t *vpd;
+	uint32_t vpd_size;
+	uint32_t ftr_rsp = 0;
+	struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport);
+	struct lpfc_vport *vport = phba->pport;
+	struct lpfc_dmabuf *mp;
+
+	/* Perform a PCI function reset to start from clean */
+	rc = lpfc_pci_function_reset(phba);
+	if (unlikely(rc))
+		return -ENODEV;
+
+	/* Check the HBA Host Status Register for readyness */
+	rc = lpfc_sli4_post_status_check(phba);
+	if (unlikely(rc))
+		return -ENODEV;
+	else {
+		spin_lock_irq(&phba->hbalock);
+		phba->sli.sli_flag |= LPFC_SLI_ACTIVE;
+		spin_unlock_irq(&phba->hbalock);
+	}
+
+	/*
+	 * Allocate a single mailbox container for initializing the
+	 * port.
+	 */
+	mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mboxq)
+		return -ENOMEM;
+
+	/*
+	 * Continue initialization with default values even if driver failed
+	 * to read FCoE param config regions
+	 */
+	if (lpfc_sli4_read_fcoe_params(phba, mboxq))
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT,
+			"2570 Failed to read FCoE parameters \n");
+
+	/* Issue READ_REV to collect vpd and FW information. */
+	vpd_size = PAGE_SIZE;
+	vpd = kzalloc(vpd_size, GFP_KERNEL);
+	if (!vpd) {
+		rc = -ENOMEM;
+		goto out_free_mbox;
+	}
+
+	rc = lpfc_sli4_read_rev(phba, mboxq, vpd, &vpd_size);
+	if (unlikely(rc))
+		goto out_free_vpd;
+
+	mqe = &mboxq->u.mqe;
+	if ((bf_get(lpfc_mbx_rd_rev_sli_lvl,
+		    &mqe->un.read_rev) != LPFC_SLI_REV4) ||
+	    (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev) == 0)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+			"0376 READ_REV Error. SLI Level %d "
+			"FCoE enabled %d\n",
+			bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev),
+			bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev));
+		rc = -EIO;
+		goto out_free_vpd;
+	}
+	/* Single threaded at this point, no need for lock */
+	spin_lock_irq(&phba->hbalock);
+	phba->hba_flag |= HBA_FCOE_SUPPORT;
+	spin_unlock_irq(&phba->hbalock);
+	/*
+	 * Evaluate the read rev and vpd data. Populate the driver
+	 * state with the results. If this routine fails, the failure
+	 * is not fatal as the driver will use generic values.
+	 */
+	rc = lpfc_parse_vpd(phba, vpd, vpd_size);
+	if (unlikely(!rc)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+				"0377 Error %d parsing vpd. "
+				"Using defaults.\n", rc);
+		rc = 0;
+	}
+
+	/* By now, we should determine the SLI revision, hard code for now */
+	phba->sli_rev = LPFC_SLI_REV4;
+
+	/*
+	 * Discover the port's supported feature set and match it against the
+	 * hosts requests.
+	 */
+	lpfc_request_features(phba, mboxq);
+	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+	if (unlikely(rc)) {
+		rc = -EIO;
+		goto out_free_vpd;
+	}
+
+	/*
+	 * The port must support FCP initiator mode as this is the
+	 * only mode running in the host.
+	 */
+	if (!(bf_get(lpfc_mbx_rq_ftr_rsp_fcpi, &mqe->un.req_ftrs))) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
+				"0378 No support for fcpi mode.\n");
+		ftr_rsp++;
+	}
+
+	/*
+	 * If the port cannot support the host's requested features
+	 * then turn off the global config parameters to disable the
+	 * feature in the driver.  This is not a fatal error.
+	 */
+	if ((phba->cfg_enable_bg) &&
+	    !(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs)))
+		ftr_rsp++;
+
+	if (phba->max_vpi && phba->cfg_enable_npiv &&
+	    !(bf_get(lpfc_mbx_rq_ftr_rsp_npiv, &mqe->un.req_ftrs)))
+		ftr_rsp++;
+
+	if (ftr_rsp) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
+				"0379 Feature Mismatch Data: x%08x %08x "
+				"x%x x%x x%x\n", mqe->un.req_ftrs.word2,
+				mqe->un.req_ftrs.word3, phba->cfg_enable_bg,
+				phba->cfg_enable_npiv, phba->max_vpi);
+		if (!(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs)))
+			phba->cfg_enable_bg = 0;
+		if (!(bf_get(lpfc_mbx_rq_ftr_rsp_npiv, &mqe->un.req_ftrs)))
+			phba->cfg_enable_npiv = 0;
+	}
+
+	/* These SLI3 features are assumed in SLI4 */
+	spin_lock_irq(&phba->hbalock);
+	phba->sli3_options |= (LPFC_SLI3_NPIV_ENABLED | LPFC_SLI3_HBQ_ENABLED);
+	spin_unlock_irq(&phba->hbalock);
+
+	/* Read the port's service parameters. */
+	lpfc_read_sparam(phba, mboxq, vport->vpi);
+	mboxq->vport = vport;
+	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+	mp = (struct lpfc_dmabuf *) mboxq->context1;
+	if (rc == MBX_SUCCESS) {
+		memcpy(&vport->fc_sparam, mp->virt, sizeof(struct serv_parm));
+		rc = 0;
+	}
+
+	/*
+	 * This memory was allocated by the lpfc_read_sparam routine. Release
+	 * it to the mbuf pool.
+	 */
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+	kfree(mp);
+	mboxq->context1 = NULL;
+	if (unlikely(rc)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+				"0382 READ_SPARAM command failed "
+				"status %d, mbxStatus x%x\n",
+				rc, bf_get(lpfc_mqe_status, mqe));
+		phba->link_state = LPFC_HBA_ERROR;
+		rc = -EIO;
+		goto out_free_vpd;
+	}
+
+	if (phba->cfg_soft_wwnn)
+		u64_to_wwn(phba->cfg_soft_wwnn,
+			   vport->fc_sparam.nodeName.u.wwn);
+	if (phba->cfg_soft_wwpn)
+		u64_to_wwn(phba->cfg_soft_wwpn,
+			   vport->fc_sparam.portName.u.wwn);
+	memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
+	       sizeof(struct lpfc_name));
+	memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
+	       sizeof(struct lpfc_name));
+
+	/* Update the fc_host data structures with new wwn. */
+	fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn);
+	fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn);
+
+	/* Register SGL pool to the device using non-embedded mailbox command */
+	rc = lpfc_sli4_post_sgl_list(phba);
+	if (unlikely(rc)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+				"0582 Error %d during sgl post operation", rc);
+		rc = -ENODEV;
+		goto out_free_vpd;
+	}
+
+	/* Register SCSI SGL pool to the device */
+	rc = lpfc_sli4_repost_scsi_sgl_list(phba);
+	if (unlikely(rc)) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
+				"0383 Error %d during scsi sgl post opeation",
+				rc);
+		/* Some Scsi buffers were moved to the abort scsi list */
+		/* A pci function reset will repost them */
+		rc = -ENODEV;
+		goto out_free_vpd;
+	}
+
+	/* Post the rpi header region to the device. */
+	rc = lpfc_sli4_post_all_rpi_hdrs(phba);
+	if (unlikely(rc)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+				"0393 Error %d during rpi post operation\n",
+				rc);
+		rc = -ENODEV;
+		goto out_free_vpd;
+	}
+	/* Temporary initialization of lpfc_fip_flag to non-fip */
+	bf_set(lpfc_fip_flag, &phba->sli4_hba.sli4_flags, 0);
+
+	/* Set up all the queues to the device */
+	rc = lpfc_sli4_queue_setup(phba);
+	if (unlikely(rc)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+				"0381 Error %d during queue setup.\n ", rc);
+		goto out_stop_timers;
+	}
+
+	/* Arm the CQs and then EQs on device */
+	lpfc_sli4_arm_cqeq_intr(phba);
+
+	/* Indicate device interrupt mode */
+	phba->sli4_hba.intr_enable = 1;
+
+	/* Allow asynchronous mailbox command to go through */
+	spin_lock_irq(&phba->hbalock);
+	phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK;
+	spin_unlock_irq(&phba->hbalock);
+
+	/* Post receive buffers to the device */
+	lpfc_sli4_rb_setup(phba);
+
+	/* Start the ELS watchdog timer */
+	/*
+	 * The driver for SLI4 is not yet ready to process timeouts
+	 * or interrupts.  Once it is, the comment bars can be removed.
+	 */
+	/* mod_timer(&vport->els_tmofunc,
+	 *           jiffies + HZ * (phba->fc_ratov*2)); */
+
+	/* Start heart beat timer */
+	mod_timer(&phba->hb_tmofunc,
+		  jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+	phba->hb_outstanding = 0;
+	phba->last_completion_time = jiffies;
+
+	/* Start error attention (ERATT) polling timer */
+	mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL);
+
+	/*
+	 * The port is ready, set the host's link state to LINK_DOWN
+	 * in preparation for link interrupts.
+	 */
+	lpfc_init_link(phba, mboxq, phba->cfg_topology, phba->cfg_link_speed);
+	mboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+	lpfc_set_loopback_flag(phba);
+	/* Change driver state to LPFC_LINK_DOWN right before init link */
+	spin_lock_irq(&phba->hbalock);
+	phba->link_state = LPFC_LINK_DOWN;
+	spin_unlock_irq(&phba->hbalock);
+	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+	if (unlikely(rc != MBX_NOT_FINISHED)) {
+		kfree(vpd);
+		return 0;
+	} else
+		rc = -EIO;
+
+	/* Unset all the queues set up in this routine when error out */
+	if (rc)
+		lpfc_sli4_queue_unset(phba);
+
+out_stop_timers:
+	if (rc)
+		lpfc_stop_hba_timers(phba);
+out_free_vpd:
+	kfree(vpd);
+out_free_mbox:
+	mempool_free(mboxq, phba->mbox_mem_pool);
+	return rc;
+}
 
 /**
  * lpfc_mbox_timeout - Timeout call back function for mbox timer
@@ -3244,7 +4608,7 @@
 lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
 {
 	LPFC_MBOXQ_t *pmbox = phba->sli.mbox_active;
-	MAILBOX_t *mb = &pmbox->mb;
+	MAILBOX_t *mb = &pmbox->u.mb;
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring *pring;
 
@@ -3281,7 +4645,7 @@
 	spin_unlock_irq(&phba->pport->work_port_lock);
 	spin_lock_irq(&phba->hbalock);
 	phba->link_state = LPFC_LINK_UNKNOWN;
-	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+	psli->sli_flag &= ~LPFC_SLI_ACTIVE;
 	spin_unlock_irq(&phba->hbalock);
 
 	pring = &psli->ring[psli->fcp_ring];
@@ -3289,32 +4653,20 @@
 
 	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
 			"0345 Resetting board due to mailbox timeout\n");
-	/*
-	 * lpfc_offline calls lpfc_sli_hba_down which will clean up
-	 * on oustanding mailbox commands.
-	 */
-	/* If resets are disabled then set error state and return. */
-	if (!phba->cfg_enable_hba_reset) {
-		phba->link_state = LPFC_HBA_ERROR;
-		return;
-	}
-	lpfc_offline_prep(phba);
-	lpfc_offline(phba);
-	lpfc_sli_brdrestart(phba);
-	lpfc_online(phba);
-	lpfc_unblock_mgmt_io(phba);
-	return;
+
+	/* Reset the HBA device */
+	lpfc_reset_hba(phba);
 }
 
 /**
- * lpfc_sli_issue_mbox - Issue a mailbox command to firmware
+ * lpfc_sli_issue_mbox_s3 - Issue an SLI3 mailbox command to firmware
  * @phba: Pointer to HBA context object.
  * @pmbox: Pointer to mailbox object.
  * @flag: Flag indicating how the mailbox need to be processed.
  *
  * This function is called by discovery code and HBA management code
- * to submit a mailbox command to firmware. This function gets the
- * hbalock to protect the data structures.
+ * to submit a mailbox command to firmware with SLI-3 interface spec. This
+ * function gets the hbalock to protect the data structures.
  * The mailbox command can be submitted in polling mode, in which case
  * this function will wait in a polling loop for the completion of the
  * mailbox.
@@ -3332,8 +4684,9 @@
  * return codes the caller owns the mailbox command after the return of
  * the function.
  **/
-int
-lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
+static int
+lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,
+		       uint32_t flag)
 {
 	MAILBOX_t *mb;
 	struct lpfc_sli *psli = &phba->sli;
@@ -3349,6 +4702,10 @@
 	spin_lock_irqsave(&phba->hbalock, drvr_flag);
 	if (!pmbox) {
 		/* processing mbox queue from intr_handler */
+		if (unlikely(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) {
+			spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
+			return MBX_SUCCESS;
+		}
 		processing_queue = 1;
 		phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
 		pmbox = lpfc_mbox_get(phba);
@@ -3365,7 +4722,7 @@
 			lpfc_printf_log(phba, KERN_ERR,
 					LOG_MBOX | LOG_VPORT,
 					"1806 Mbox x%x failed. No vport\n",
-					pmbox->mb.mbxCommand);
+					pmbox->u.mb.mbxCommand);
 			dump_stack();
 			goto out_not_finished;
 		}
@@ -3385,21 +4742,29 @@
 
 	psli = &phba->sli;
 
-	mb = &pmbox->mb;
+	mb = &pmbox->u.mb;
 	status = MBX_SUCCESS;
 
 	if (phba->link_state == LPFC_HBA_ERROR) {
 		spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
 
 		/* Mbox command <mbxCommand> cannot issue */
-		LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+				"(%d):0311 Mailbox command x%x cannot "
+				"issue Data: x%x x%x\n",
+				pmbox->vport ? pmbox->vport->vpi : 0,
+				pmbox->u.mb.mbxCommand, psli->sli_flag, flag);
 		goto out_not_finished;
 	}
 
 	if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT &&
 	    !(readl(phba->HCregaddr) & HC_MBINT_ENA)) {
 		spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
-		LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+				"(%d):2528 Mailbox command x%x cannot "
+				"issue Data: x%x x%x\n",
+				pmbox->vport ? pmbox->vport->vpi : 0,
+				pmbox->u.mb.mbxCommand, psli->sli_flag, flag);
 		goto out_not_finished;
 	}
 
@@ -3413,14 +4778,24 @@
 			spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
 
 			/* Mbox command <mbxCommand> cannot issue */
-			LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+			lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+					"(%d):2529 Mailbox command x%x "
+					"cannot issue Data: x%x x%x\n",
+					pmbox->vport ? pmbox->vport->vpi : 0,
+					pmbox->u.mb.mbxCommand,
+					psli->sli_flag, flag);
 			goto out_not_finished;
 		}
 
-		if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) {
+		if (!(psli->sli_flag & LPFC_SLI_ACTIVE)) {
 			spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
 			/* Mbox command <mbxCommand> cannot issue */
-			LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+			lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+					"(%d):2530 Mailbox command x%x "
+					"cannot issue Data: x%x x%x\n",
+					pmbox->vport ? pmbox->vport->vpi : 0,
+					pmbox->u.mb.mbxCommand,
+					psli->sli_flag, flag);
 			goto out_not_finished;
 		}
 
@@ -3462,12 +4837,17 @@
 
 	/* If we are not polling, we MUST be in SLI2 mode */
 	if (flag != MBX_POLL) {
-		if (!(psli->sli_flag & LPFC_SLI2_ACTIVE) &&
+		if (!(psli->sli_flag & LPFC_SLI_ACTIVE) &&
 		    (mb->mbxCommand != MBX_KILL_BOARD)) {
 			psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
 			spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
 			/* Mbox command <mbxCommand> cannot issue */
-			LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+			lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+					"(%d):2531 Mailbox command x%x "
+					"cannot issue Data: x%x x%x\n",
+					pmbox->vport ? pmbox->vport->vpi : 0,
+					pmbox->u.mb.mbxCommand,
+					psli->sli_flag, flag);
 			goto out_not_finished;
 		}
 		/* timeout active mbox command */
@@ -3506,7 +4886,7 @@
 	/* next set own bit for the adapter and copy over command word */
 	mb->mbxOwner = OWN_CHIP;
 
-	if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
+	if (psli->sli_flag & LPFC_SLI_ACTIVE) {
 		/* First copy command data to host SLIM area */
 		lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);
 	} else {
@@ -3529,7 +4909,7 @@
 
 		if (mb->mbxCommand == MBX_CONFIG_PORT) {
 			/* switch over to host mailbox */
-			psli->sli_flag |= LPFC_SLI2_ACTIVE;
+			psli->sli_flag |= LPFC_SLI_ACTIVE;
 		}
 	}
 
@@ -3552,7 +4932,7 @@
 		writel(CA_MBATT, phba->CAregaddr);
 		readl(phba->CAregaddr); /* flush */
 
-		if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
+		if (psli->sli_flag & LPFC_SLI_ACTIVE) {
 			/* First read mbox status word */
 			word0 = *((uint32_t *)phba->mbox);
 			word0 = le32_to_cpu(word0);
@@ -3591,7 +4971,7 @@
 				spin_lock_irqsave(&phba->hbalock, drvr_flag);
 			}
 
-			if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
+			if (psli->sli_flag & LPFC_SLI_ACTIVE) {
 				/* First copy command data */
 				word0 = *((uint32_t *)phba->mbox);
 				word0 = le32_to_cpu(word0);
@@ -3604,7 +4984,7 @@
 					if (((slimword0 & OWN_CHIP) != OWN_CHIP)
 					    && slimmb->mbxStatus) {
 						psli->sli_flag &=
-						    ~LPFC_SLI2_ACTIVE;
+						    ~LPFC_SLI_ACTIVE;
 						word0 = slimword0;
 					}
 				}
@@ -3616,7 +4996,7 @@
 			ha_copy = readl(phba->HAregaddr);
 		}
 
-		if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
+		if (psli->sli_flag & LPFC_SLI_ACTIVE) {
 			/* copy results back to user */
 			lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE);
 		} else {
@@ -3643,13 +5023,420 @@
 
 out_not_finished:
 	if (processing_queue) {
-		pmbox->mb.mbxStatus = MBX_NOT_FINISHED;
+		pmbox->u.mb.mbxStatus = MBX_NOT_FINISHED;
 		lpfc_mbox_cmpl_put(phba, pmbox);
 	}
 	return MBX_NOT_FINISHED;
 }
 
 /**
+ * lpfc_sli4_post_sync_mbox - Post an SLI4 mailbox to the bootstrap mailbox
+ * @phba: Pointer to HBA context object.
+ * @mboxq: Pointer to mailbox object.
+ *
+ * The function posts a mailbox to the port.  The mailbox is expected
+ * to be comletely filled in and ready for the port to operate on it.
+ * This routine executes a synchronous completion operation on the
+ * mailbox by polling for its completion.
+ *
+ * The caller must not be holding any locks when calling this routine.
+ *
+ * Returns:
+ *	MBX_SUCCESS - mailbox posted successfully
+ *	Any of the MBX error values.
+ **/
+static int
+lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+	int rc = MBX_SUCCESS;
+	unsigned long iflag;
+	uint32_t db_ready;
+	uint32_t mcqe_status;
+	uint32_t mbx_cmnd;
+	unsigned long timeout;
+	struct lpfc_sli *psli = &phba->sli;
+	struct lpfc_mqe *mb = &mboxq->u.mqe;
+	struct lpfc_bmbx_create *mbox_rgn;
+	struct dma_address *dma_address;
+	struct lpfc_register bmbx_reg;
+
+	/*
+	 * Only one mailbox can be active to the bootstrap mailbox region
+	 * at a time and there is no queueing provided.
+	 */
+	spin_lock_irqsave(&phba->hbalock, iflag);
+	if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) {
+		spin_unlock_irqrestore(&phba->hbalock, iflag);
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+				"(%d):2532 Mailbox command x%x (x%x) "
+				"cannot issue Data: x%x x%x\n",
+				mboxq->vport ? mboxq->vport->vpi : 0,
+				mboxq->u.mb.mbxCommand,
+				lpfc_sli4_mbox_opcode_get(phba, mboxq),
+				psli->sli_flag, MBX_POLL);
+		return MBXERR_ERROR;
+	}
+	/* The server grabs the token and owns it until release */
+	psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE;
+	phba->sli.mbox_active = mboxq;
+	spin_unlock_irqrestore(&phba->hbalock, iflag);
+
+	/*
+	 * Initialize the bootstrap memory region to avoid stale data areas
+	 * in the mailbox post.  Then copy the caller's mailbox contents to
+	 * the bmbx mailbox region.
+	 */
+	mbx_cmnd = bf_get(lpfc_mqe_command, mb);
+	memset(phba->sli4_hba.bmbx.avirt, 0, sizeof(struct lpfc_bmbx_create));
+	lpfc_sli_pcimem_bcopy(mb, phba->sli4_hba.bmbx.avirt,
+			      sizeof(struct lpfc_mqe));
+
+	/* Post the high mailbox dma address to the port and wait for ready. */
+	dma_address = &phba->sli4_hba.bmbx.dma_address;
+	writel(dma_address->addr_hi, phba->sli4_hba.BMBXregaddr);
+
+	timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mbx_cmnd)
+				   * 1000) + jiffies;
+	do {
+		bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr);
+		db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg);
+		if (!db_ready)
+			msleep(2);
+
+		if (time_after(jiffies, timeout)) {
+			rc = MBXERR_ERROR;
+			goto exit;
+		}
+	} while (!db_ready);
+
+	/* Post the low mailbox dma address to the port. */
+	writel(dma_address->addr_lo, phba->sli4_hba.BMBXregaddr);
+	timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mbx_cmnd)
+				   * 1000) + jiffies;
+	do {
+		bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr);
+		db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg);
+		if (!db_ready)
+			msleep(2);
+
+		if (time_after(jiffies, timeout)) {
+			rc = MBXERR_ERROR;
+			goto exit;
+		}
+	} while (!db_ready);
+
+	/*
+	 * Read the CQ to ensure the mailbox has completed.
+	 * If so, update the mailbox status so that the upper layers
+	 * can complete the request normally.
+	 */
+	lpfc_sli_pcimem_bcopy(phba->sli4_hba.bmbx.avirt, mb,
+			      sizeof(struct lpfc_mqe));
+	mbox_rgn = (struct lpfc_bmbx_create *) phba->sli4_hba.bmbx.avirt;
+	lpfc_sli_pcimem_bcopy(&mbox_rgn->mcqe, &mboxq->mcqe,
+			      sizeof(struct lpfc_mcqe));
+	mcqe_status = bf_get(lpfc_mcqe_status, &mbox_rgn->mcqe);
+
+	/* Prefix the mailbox status with range x4000 to note SLI4 status. */
+	if (mcqe_status != MB_CQE_STATUS_SUCCESS) {
+		bf_set(lpfc_mqe_status, mb, LPFC_MBX_ERROR_RANGE | mcqe_status);
+		rc = MBXERR_ERROR;
+	}
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+			"(%d):0356 Mailbox cmd x%x (x%x) Status x%x "
+			"Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x x%x x%x"
+			" x%x x%x CQ: x%x x%x x%x x%x\n",
+			mboxq->vport ? mboxq->vport->vpi : 0,
+			mbx_cmnd, lpfc_sli4_mbox_opcode_get(phba, mboxq),
+			bf_get(lpfc_mqe_status, mb),
+			mb->un.mb_words[0], mb->un.mb_words[1],
+			mb->un.mb_words[2], mb->un.mb_words[3],
+			mb->un.mb_words[4], mb->un.mb_words[5],
+			mb->un.mb_words[6], mb->un.mb_words[7],
+			mb->un.mb_words[8], mb->un.mb_words[9],
+			mb->un.mb_words[10], mb->un.mb_words[11],
+			mb->un.mb_words[12], mboxq->mcqe.word0,
+			mboxq->mcqe.mcqe_tag0, 	mboxq->mcqe.mcqe_tag1,
+			mboxq->mcqe.trailer);
+exit:
+	/* We are holding the token, no needed for lock when release */
+	spin_lock_irqsave(&phba->hbalock, iflag);
+	psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+	phba->sli.mbox_active = NULL;
+	spin_unlock_irqrestore(&phba->hbalock, iflag);
+	return rc;
+}
+
+/**
+ * lpfc_sli_issue_mbox_s4 - Issue an SLI4 mailbox command to firmware
+ * @phba: Pointer to HBA context object.
+ * @pmbox: Pointer to mailbox object.
+ * @flag: Flag indicating how the mailbox need to be processed.
+ *
+ * This function is called by discovery code and HBA management code to submit
+ * a mailbox command to firmware with SLI-4 interface spec.
+ *
+ * Return codes the caller owns the mailbox command after the return of the
+ * function.
+ **/
+static int
+lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
+		       uint32_t flag)
+{
+	struct lpfc_sli *psli = &phba->sli;
+	unsigned long iflags;
+	int rc;
+
+	/* Detect polling mode and jump to a handler */
+	if (!phba->sli4_hba.intr_enable) {
+		if (flag == MBX_POLL)
+			rc = lpfc_sli4_post_sync_mbox(phba, mboxq);
+		else
+			rc = -EIO;
+		if (rc != MBX_SUCCESS)
+			lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+					"(%d):2541 Mailbox command x%x "
+					"(x%x) cannot issue Data: x%x x%x\n",
+					mboxq->vport ? mboxq->vport->vpi : 0,
+					mboxq->u.mb.mbxCommand,
+					lpfc_sli4_mbox_opcode_get(phba, mboxq),
+					psli->sli_flag, flag);
+		return rc;
+	} else if (flag == MBX_POLL) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+				"(%d):2542 Mailbox command x%x (x%x) "
+				"cannot issue Data: x%x x%x\n",
+				mboxq->vport ? mboxq->vport->vpi : 0,
+				mboxq->u.mb.mbxCommand,
+				lpfc_sli4_mbox_opcode_get(phba, mboxq),
+				psli->sli_flag, flag);
+		return -EIO;
+	}
+
+	/* Now, interrupt mode asynchrous mailbox command */
+	rc = lpfc_mbox_cmd_check(phba, mboxq);
+	if (rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+				"(%d):2543 Mailbox command x%x (x%x) "
+				"cannot issue Data: x%x x%x\n",
+				mboxq->vport ? mboxq->vport->vpi : 0,
+				mboxq->u.mb.mbxCommand,
+				lpfc_sli4_mbox_opcode_get(phba, mboxq),
+				psli->sli_flag, flag);
+		goto out_not_finished;
+	}
+	rc = lpfc_mbox_dev_check(phba);
+	if (unlikely(rc)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+				"(%d):2544 Mailbox command x%x (x%x) "
+				"cannot issue Data: x%x x%x\n",
+				mboxq->vport ? mboxq->vport->vpi : 0,
+				mboxq->u.mb.mbxCommand,
+				lpfc_sli4_mbox_opcode_get(phba, mboxq),
+				psli->sli_flag, flag);
+		goto out_not_finished;
+	}
+
+	/* Put the mailbox command to the driver internal FIFO */
+	psli->slistat.mbox_busy++;
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	lpfc_mbox_put(phba, mboxq);
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+			"(%d):0354 Mbox cmd issue - Enqueue Data: "
+			"x%x (x%x) x%x x%x x%x\n",
+			mboxq->vport ? mboxq->vport->vpi : 0xffffff,
+			bf_get(lpfc_mqe_command, &mboxq->u.mqe),
+			lpfc_sli4_mbox_opcode_get(phba, mboxq),
+			phba->pport->port_state,
+			psli->sli_flag, MBX_NOWAIT);
+	/* Wake up worker thread to transport mailbox command from head */
+	lpfc_worker_wake_up(phba);
+
+	return MBX_BUSY;
+
+out_not_finished:
+	return MBX_NOT_FINISHED;
+}
+
+/**
+ * lpfc_sli4_post_async_mbox - Post an SLI4 mailbox command to device
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called by worker thread to send a mailbox command to
+ * SLI4 HBA firmware.
+ *
+ **/
+int
+lpfc_sli4_post_async_mbox(struct lpfc_hba *phba)
+{
+	struct lpfc_sli *psli = &phba->sli;
+	LPFC_MBOXQ_t *mboxq;
+	int rc = MBX_SUCCESS;
+	unsigned long iflags;
+	struct lpfc_mqe *mqe;
+	uint32_t mbx_cmnd;
+
+	/* Check interrupt mode before post async mailbox command */
+	if (unlikely(!phba->sli4_hba.intr_enable))
+		return MBX_NOT_FINISHED;
+
+	/* Check for mailbox command service token */
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	if (unlikely(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) {
+		spin_unlock_irqrestore(&phba->hbalock, iflags);
+		return MBX_NOT_FINISHED;
+	}
+	if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) {
+		spin_unlock_irqrestore(&phba->hbalock, iflags);
+		return MBX_NOT_FINISHED;
+	}
+	if (unlikely(phba->sli.mbox_active)) {
+		spin_unlock_irqrestore(&phba->hbalock, iflags);
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+				"0384 There is pending active mailbox cmd\n");
+		return MBX_NOT_FINISHED;
+	}
+	/* Take the mailbox command service token */
+	psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE;
+
+	/* Get the next mailbox command from head of queue */
+	mboxq = lpfc_mbox_get(phba);
+
+	/* If no more mailbox command waiting for post, we're done */
+	if (!mboxq) {
+		psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+		spin_unlock_irqrestore(&phba->hbalock, iflags);
+		return MBX_SUCCESS;
+	}
+	phba->sli.mbox_active = mboxq;
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+	/* Check device readiness for posting mailbox command */
+	rc = lpfc_mbox_dev_check(phba);
+	if (unlikely(rc))
+		/* Driver clean routine will clean up pending mailbox */
+		goto out_not_finished;
+
+	/* Prepare the mbox command to be posted */
+	mqe = &mboxq->u.mqe;
+	mbx_cmnd = bf_get(lpfc_mqe_command, mqe);
+
+	/* Start timer for the mbox_tmo and log some mailbox post messages */
+	mod_timer(&psli->mbox_tmo, (jiffies +
+		  (HZ * lpfc_mbox_tmo_val(phba, mbx_cmnd))));
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+			"(%d):0355 Mailbox cmd x%x (x%x) issue Data: "
+			"x%x x%x\n",
+			mboxq->vport ? mboxq->vport->vpi : 0, mbx_cmnd,
+			lpfc_sli4_mbox_opcode_get(phba, mboxq),
+			phba->pport->port_state, psli->sli_flag);
+
+	if (mbx_cmnd != MBX_HEARTBEAT) {
+		if (mboxq->vport) {
+			lpfc_debugfs_disc_trc(mboxq->vport,
+				LPFC_DISC_TRC_MBOX_VPORT,
+				"MBOX Send vport: cmd:x%x mb:x%x x%x",
+				mbx_cmnd, mqe->un.mb_words[0],
+				mqe->un.mb_words[1]);
+		} else {
+			lpfc_debugfs_disc_trc(phba->pport,
+				LPFC_DISC_TRC_MBOX,
+				"MBOX Send: cmd:x%x mb:x%x x%x",
+				mbx_cmnd, mqe->un.mb_words[0],
+				mqe->un.mb_words[1]);
+		}
+	}
+	psli->slistat.mbox_cmd++;
+
+	/* Post the mailbox command to the port */
+	rc = lpfc_sli4_mq_put(phba->sli4_hba.mbx_wq, mqe);
+	if (rc != MBX_SUCCESS) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+				"(%d):2533 Mailbox command x%x (x%x) "
+				"cannot issue Data: x%x x%x\n",
+				mboxq->vport ? mboxq->vport->vpi : 0,
+				mboxq->u.mb.mbxCommand,
+				lpfc_sli4_mbox_opcode_get(phba, mboxq),
+				psli->sli_flag, MBX_NOWAIT);
+		goto out_not_finished;
+	}
+
+	return rc;
+
+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;
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+	return MBX_NOT_FINISHED;
+}
+
+/**
+ * lpfc_sli_issue_mbox - Wrapper func for issuing mailbox command
+ * @phba: Pointer to HBA context object.
+ * @pmbox: Pointer to mailbox object.
+ * @flag: Flag indicating how the mailbox need to be processed.
+ *
+ * This routine wraps the actual SLI3 or SLI4 mailbox issuing routine from
+ * the API jump table function pointer from the lpfc_hba struct.
+ *
+ * Return codes the caller owns the mailbox command after the return of the
+ * function.
+ **/
+int
+lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
+{
+	return phba->lpfc_sli_issue_mbox(phba, pmbox, flag);
+}
+
+/**
+ * lpfc_mbox_api_table_setup - Set up mbox api fucntion jump table
+ * @phba: The hba struct for which this call is being executed.
+ * @dev_grp: The HBA PCI-Device group number.
+ *
+ * This routine sets up the mbox interface API function jump table in @phba
+ * struct.
+ * Returns: 0 - success, -ENODEV - failure.
+ **/
+int
+lpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
+{
+
+	switch (dev_grp) {
+	case LPFC_PCI_DEV_LP:
+		phba->lpfc_sli_issue_mbox = lpfc_sli_issue_mbox_s3;
+		phba->lpfc_sli_handle_slow_ring_event =
+				lpfc_sli_handle_slow_ring_event_s3;
+		phba->lpfc_sli_hbq_to_firmware = lpfc_sli_hbq_to_firmware_s3;
+		phba->lpfc_sli_brdrestart = lpfc_sli_brdrestart_s3;
+		phba->lpfc_sli_brdready = lpfc_sli_brdready_s3;
+		break;
+	case LPFC_PCI_DEV_OC:
+		phba->lpfc_sli_issue_mbox = lpfc_sli_issue_mbox_s4;
+		phba->lpfc_sli_handle_slow_ring_event =
+				lpfc_sli_handle_slow_ring_event_s4;
+		phba->lpfc_sli_hbq_to_firmware = lpfc_sli_hbq_to_firmware_s4;
+		phba->lpfc_sli_brdrestart = lpfc_sli_brdrestart_s4;
+		phba->lpfc_sli_brdready = lpfc_sli_brdready_s4;
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1420 Invalid HBA PCI-device group: 0x%x\n",
+				dev_grp);
+		return -ENODEV;
+		break;
+	}
+	return 0;
+}
+
+/**
  * __lpfc_sli_ringtx_put - Add an iocb to the txq
  * @phba: Pointer to HBA context object.
  * @pring: Pointer to driver SLI ring object.
@@ -3701,35 +5488,34 @@
 }
 
 /**
- * __lpfc_sli_issue_iocb - Lockless version of lpfc_sli_issue_iocb
+ * __lpfc_sli_issue_iocb_s3 - SLI3 device lockless ver of lpfc_sli_issue_iocb
  * @phba: Pointer to HBA context object.
- * @pring: Pointer to driver SLI ring object.
+ * @ring_number: SLI ring number to issue iocb on.
  * @piocb: Pointer to command iocb.
  * @flag: Flag indicating if this command can be put into txq.
  *
- * __lpfc_sli_issue_iocb is used by other functions in the driver
- * to issue an iocb command to the HBA. If the PCI slot is recovering
- * from error state or if HBA is resetting or if LPFC_STOP_IOCB_EVENT
- * flag is turned on, the function returns IOCB_ERROR.
- * When the link is down, this function allows only iocbs for
- * posting buffers.
- * This function finds next available slot in the command ring and
- * posts the command to the available slot and writes the port
- * attention register to request HBA start processing new iocb.
- * If there is no slot available in the ring and
- * flag & SLI_IOCB_RET_IOCB is set, the new iocb is added to the
- * txq, otherwise the function returns IOCB_BUSY.
+ * __lpfc_sli_issue_iocb_s3 is used by other functions in the driver to issue
+ * an iocb command to an HBA with SLI-3 interface spec. If the PCI slot is
+ * recovering from error state, if HBA is resetting or if LPFC_STOP_IOCB_EVENT
+ * flag is turned on, the function returns IOCB_ERROR. When the link is down,
+ * this function allows only iocbs for posting buffers. This function finds
+ * next available slot in the command ring and posts the command to the
+ * available slot and writes the port attention register to request HBA start
+ * processing new iocb. If there is no slot available in the ring and
+ * flag & SLI_IOCB_RET_IOCB is set, the new iocb is added to the txq, otherwise
+ * the function returns IOCB_BUSY.
  *
- * This function is called with hbalock held.
- * The function will return success after it successfully submit the
- * iocb to firmware or after adding to the txq.
+ * This function is called with hbalock held. The function will return success
+ * after it successfully submit the iocb to firmware or after adding to the
+ * txq.
  **/
 static int
-__lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+__lpfc_sli_issue_iocb_s3(struct lpfc_hba *phba, uint32_t ring_number,
 		    struct lpfc_iocbq *piocb, uint32_t flag)
 {
 	struct lpfc_iocbq *nextiocb;
 	IOCB_t *iocb;
+	struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
 
 	if (piocb->iocb_cmpl && (!piocb->vport) &&
 	   (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
@@ -3833,6 +5619,498 @@
 	return IOCB_BUSY;
 }
 
+/**
+ * lpfc_sli4_bpl2sgl - Convert the bpl/bde to a sgl.
+ * @phba: Pointer to HBA context object.
+ * @piocb: Pointer to command iocb.
+ * @sglq: Pointer to the scatter gather queue object.
+ *
+ * This routine converts the bpl or bde that is in the IOCB
+ * to a sgl list for the sli4 hardware. The physical address
+ * of the bpl/bde is converted back to a virtual address.
+ * If the IOCB contains a BPL then the list of BDE's is
+ * converted to sli4_sge's. If the IOCB contains a single
+ * BDE then it is converted to a single sli_sge.
+ * The IOCB is still in cpu endianess so the contents of
+ * the bpl can be used without byte swapping.
+ *
+ * Returns valid XRI = Success, NO_XRI = Failure.
+**/
+static uint16_t
+lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+		struct lpfc_sglq *sglq)
+{
+	uint16_t xritag = NO_XRI;
+	struct ulp_bde64 *bpl = NULL;
+	struct ulp_bde64 bde;
+	struct sli4_sge *sgl  = NULL;
+	IOCB_t *icmd;
+	int numBdes = 0;
+	int i = 0;
+
+	if (!piocbq || !sglq)
+		return xritag;
+
+	sgl  = (struct sli4_sge *)sglq->sgl;
+	icmd = &piocbq->iocb;
+	if (icmd->un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) {
+		numBdes = icmd->un.genreq64.bdl.bdeSize /
+				sizeof(struct ulp_bde64);
+		/* The addrHigh and addrLow fields within the IOCB
+		 * have not been byteswapped yet so there is no
+		 * need to swap them back.
+		 */
+		bpl  = (struct ulp_bde64 *)
+			((struct lpfc_dmabuf *)piocbq->context3)->virt;
+
+		if (!bpl)
+			return xritag;
+
+		for (i = 0; i < numBdes; i++) {
+			/* Should already be byte swapped. */
+			sgl->addr_hi =  bpl->addrHigh;
+			sgl->addr_lo =  bpl->addrLow;
+			/* swap the size field back to the cpu so we
+			 * can assign it to the sgl.
+			 */
+			bde.tus.w  = le32_to_cpu(bpl->tus.w);
+			bf_set(lpfc_sli4_sge_len, sgl, bde.tus.f.bdeSize);
+			if ((i+1) == numBdes)
+				bf_set(lpfc_sli4_sge_last, sgl, 1);
+			else
+				bf_set(lpfc_sli4_sge_last, sgl, 0);
+			sgl->word2 = cpu_to_le32(sgl->word2);
+			sgl->word3 = cpu_to_le32(sgl->word3);
+			bpl++;
+			sgl++;
+		}
+	} else if (icmd->un.genreq64.bdl.bdeFlags == BUFF_TYPE_BDE_64) {
+			/* The addrHigh and addrLow fields of the BDE have not
+			 * been byteswapped yet so they need to be swapped
+			 * before putting them in the sgl.
+			 */
+			sgl->addr_hi =
+				cpu_to_le32(icmd->un.genreq64.bdl.addrHigh);
+			sgl->addr_lo =
+				cpu_to_le32(icmd->un.genreq64.bdl.addrLow);
+			bf_set(lpfc_sli4_sge_len, sgl,
+				icmd->un.genreq64.bdl.bdeSize);
+			bf_set(lpfc_sli4_sge_last, sgl, 1);
+			sgl->word2 = cpu_to_le32(sgl->word2);
+			sgl->word3 = cpu_to_le32(sgl->word3);
+	}
+	return sglq->sli4_xritag;
+}
+
+/**
+ * lpfc_sli4_scmd_to_wqidx_distr - scsi command to SLI4 WQ index distribution
+ * @phba: Pointer to HBA context object.
+ * @piocb: Pointer to command iocb.
+ *
+ * This routine performs a round robin SCSI command to SLI4 FCP WQ index
+ * distribution.
+ *
+ * Return: index into SLI4 fast-path FCP queue index.
+ **/
+static uint32_t
+lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba, struct lpfc_iocbq *piocb)
+{
+	static uint32_t fcp_qidx;
+
+	return fcp_qidx++ % phba->cfg_fcp_wq_count;
+}
+
+/**
+ * lpfc_sli_iocb2wqe - Convert the IOCB to a work queue entry.
+ * @phba: Pointer to HBA context object.
+ * @piocb: Pointer to command iocb.
+ * @wqe: Pointer to the work queue entry.
+ *
+ * This routine converts the iocb command to its Work Queue Entry
+ * equivalent. The wqe pointer should not have any fields set when
+ * this routine is called because it will memcpy over them.
+ * This routine does not set the CQ_ID or the WQEC bits in the
+ * wqe.
+ *
+ * Returns: 0 = Success, IOCB_ERROR = Failure.
+ **/
+static int
+lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
+		union lpfc_wqe *wqe)
+{
+	uint32_t payload_len = 0;
+	uint8_t ct = 0;
+	uint32_t fip;
+	uint32_t abort_tag;
+	uint8_t command_type = ELS_COMMAND_NON_FIP;
+	uint8_t cmnd;
+	uint16_t xritag;
+	struct ulp_bde64 *bpl = NULL;
+
+	fip = bf_get(lpfc_fip_flag, &phba->sli4_hba.sli4_flags);
+	/* The fcp commands will set command type */
+	if ((!(iocbq->iocb_flag &  LPFC_IO_FCP)) && (!fip))
+		command_type = ELS_COMMAND_NON_FIP;
+	else if (!(iocbq->iocb_flag &  LPFC_IO_FCP))
+		command_type = ELS_COMMAND_FIP;
+	else if (iocbq->iocb_flag &  LPFC_IO_FCP)
+		command_type = FCP_COMMAND;
+	else {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+			"2019 Invalid cmd 0x%x\n",
+			iocbq->iocb.ulpCommand);
+		return IOCB_ERROR;
+	}
+	/* Some of the fields are in the right position already */
+	memcpy(wqe, &iocbq->iocb, sizeof(union lpfc_wqe));
+	abort_tag = (uint32_t) iocbq->iotag;
+	xritag = iocbq->sli4_xritag;
+	wqe->words[7] = 0; /* The ct field has moved so reset */
+	/* words0-2 bpl convert bde */
+	if (iocbq->iocb.un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) {
+		bpl  = (struct ulp_bde64 *)
+			((struct lpfc_dmabuf *)iocbq->context3)->virt;
+		if (!bpl)
+			return IOCB_ERROR;
+
+		/* Should already be byte swapped. */
+		wqe->generic.bde.addrHigh =  le32_to_cpu(bpl->addrHigh);
+		wqe->generic.bde.addrLow =  le32_to_cpu(bpl->addrLow);
+		/* swap the size field back to the cpu so we
+		 * can assign it to the sgl.
+		 */
+		wqe->generic.bde.tus.w  = le32_to_cpu(bpl->tus.w);
+		payload_len = wqe->generic.bde.tus.f.bdeSize;
+	} else
+		payload_len = iocbq->iocb.un.fcpi64.bdl.bdeSize;
+
+	iocbq->iocb.ulpIoTag = iocbq->iotag;
+	cmnd = iocbq->iocb.ulpCommand;
+
+	switch (iocbq->iocb.ulpCommand) {
+	case CMD_ELS_REQUEST64_CR:
+		if (!iocbq->iocb.ulpLe) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2007 Only Limited Edition cmd Format"
+				" supported 0x%x\n",
+				iocbq->iocb.ulpCommand);
+			return IOCB_ERROR;
+		}
+		wqe->els_req.payload_len = payload_len;
+		/* Els_reguest64 has a TMO */
+		bf_set(wqe_tmo, &wqe->els_req.wqe_com,
+			iocbq->iocb.ulpTimeout);
+		/* Need a VF for word 4 set the vf bit*/
+		bf_set(els_req64_vf, &wqe->els_req, 0);
+		/* And a VFID for word 12 */
+		bf_set(els_req64_vfid, &wqe->els_req, 0);
+		/*
+		 * Set ct field to 3, indicates that the context_tag field
+		 * contains the FCFI and remote N_Port_ID is
+		 * in word 5.
+		 */
+
+		ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l);
+		bf_set(lpfc_wqe_gen_context, &wqe->generic,
+				iocbq->iocb.ulpContext);
+
+		if (iocbq->vport->fc_myDID != 0) {
+			bf_set(els_req64_sid, &wqe->els_req,
+				 iocbq->vport->fc_myDID);
+			bf_set(els_req64_sp, &wqe->els_req, 1);
+		}
+		bf_set(lpfc_wqe_gen_ct, &wqe->generic, ct);
+		bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0);
+		/* CCP CCPE PV PRI in word10 were set in the memcpy */
+	break;
+	case CMD_XMIT_SEQUENCE64_CR:
+		/* word3 iocb=io_tag32 wqe=payload_offset */
+		/* payload offset used for multilpe outstanding
+		 * sequences on the same exchange
+		 */
+		wqe->words[3] = 0;
+		/* word4 relative_offset memcpy */
+		/* word5 r_ctl/df_ctl memcpy */
+		bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0);
+		wqe->xmit_sequence.xmit_len = payload_len;
+	break;
+	case CMD_XMIT_BCAST64_CN:
+		/* word3 iocb=iotag32 wqe=payload_len */
+		wqe->words[3] = 0; /* no definition for this in wqe */
+		/* word4 iocb=rsvd wqe=rsvd */
+		/* word5 iocb=rctl/type/df_ctl wqe=rctl/type/df_ctl memcpy */
+		/* word6 iocb=ctxt_tag/io_tag wqe=ctxt_tag/xri */
+		bf_set(lpfc_wqe_gen_ct, &wqe->generic,
+			((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
+	break;
+	case CMD_FCP_IWRITE64_CR:
+		command_type = FCP_COMMAND_DATA_OUT;
+		/* The struct for wqe fcp_iwrite has 3 fields that are somewhat
+		 * confusing.
+		 * word3 is payload_len: byte offset to the sgl entry for the
+		 * fcp_command.
+		 * word4 is total xfer len, same as the IOCB->ulpParameter.
+		 * word5 is initial xfer len 0 = wait for xfer-ready
+		 */
+
+		/* Always wait for xfer-ready before sending data */
+		wqe->fcp_iwrite.initial_xfer_len = 0;
+		/* word 4 (xfer length) should have been set on the memcpy */
+
+	/* allow write to fall through to read */
+	case CMD_FCP_IREAD64_CR:
+		/* FCP_CMD is always the 1st sgl entry */
+		wqe->fcp_iread.payload_len =
+			payload_len + sizeof(struct fcp_rsp);
+
+		/* word 4 (xfer length) should have been set on the memcpy */
+
+		bf_set(lpfc_wqe_gen_erp, &wqe->generic,
+			iocbq->iocb.ulpFCP2Rcvy);
+		bf_set(lpfc_wqe_gen_lnk, &wqe->generic, iocbq->iocb.ulpXS);
+		/* The XC bit and the XS bit are similar. The driver never
+		 * tracked whether or not the exchange was previouslly open.
+		 * XC = Exchange create, 0 is create. 1 is already open.
+		 * XS = link cmd: 1 do not close the exchange after command.
+		 * XS = 0 close exchange when command completes.
+		 * The only time we would not set the XC bit is when the XS bit
+		 * is set and we are sending our 2nd or greater command on
+		 * this exchange.
+		 */
+
+	/* ALLOW read & write to fall through to ICMD64 */
+	case CMD_FCP_ICMND64_CR:
+		/* Always open the exchange */
+		bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0);
+
+		wqe->words[10] &= 0xffff0000; /* zero out ebde count */
+		bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU);
+	break;
+	case CMD_GEN_REQUEST64_CR:
+		/* word3 command length is described as byte offset to the
+		 * rsp_data. Would always be 16, sizeof(struct sli4_sge)
+		 * sgl[0] = cmnd
+		 * sgl[1] = rsp.
+		 *
+		 */
+		wqe->gen_req.command_len = payload_len;
+		/* Word4 parameter  copied in the memcpy */
+		/* Word5 [rctl, type, df_ctl, la] copied in memcpy */
+		/* word6 context tag copied in memcpy */
+		if (iocbq->iocb.ulpCt_h  || iocbq->iocb.ulpCt_l) {
+			ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l);
+			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2015 Invalid CT %x command 0x%x\n",
+				ct, iocbq->iocb.ulpCommand);
+			return IOCB_ERROR;
+		}
+		bf_set(lpfc_wqe_gen_ct, &wqe->generic, 0);
+		bf_set(wqe_tmo, &wqe->gen_req.wqe_com,
+			iocbq->iocb.ulpTimeout);
+
+		bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU);
+		command_type = OTHER_COMMAND;
+	break;
+	case CMD_XMIT_ELS_RSP64_CX:
+		/* words0-2 BDE memcpy */
+		/* word3 iocb=iotag32 wqe=rsvd */
+		wqe->words[3] = 0;
+		/* word4 iocb=did wge=rsvd. */
+		wqe->words[4] = 0;
+		/* word5 iocb=rsvd wge=did */
+		bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest,
+			 iocbq->iocb.un.elsreq64.remoteID);
+
+		bf_set(lpfc_wqe_gen_ct, &wqe->generic,
+			((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
+
+		bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU);
+		bf_set(wqe_rcvoxid, &wqe->generic, iocbq->iocb.ulpContext);
+		if (!iocbq->iocb.ulpCt_h && iocbq->iocb.ulpCt_l)
+			bf_set(lpfc_wqe_gen_context, &wqe->generic,
+			       iocbq->vport->vpi + phba->vpi_base);
+		command_type = OTHER_COMMAND;
+	break;
+	case CMD_CLOSE_XRI_CN:
+	case CMD_ABORT_XRI_CN:
+	case CMD_ABORT_XRI_CX:
+		/* words 0-2 memcpy should be 0 rserved */
+		/* port will send abts */
+		if (iocbq->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
+			/*
+			 * The link is down so the fw does not need to send abts
+			 * on the wire.
+			 */
+			bf_set(abort_cmd_ia, &wqe->abort_cmd, 1);
+		else
+			bf_set(abort_cmd_ia, &wqe->abort_cmd, 0);
+		bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG);
+		abort_tag = iocbq->iocb.un.acxri.abortIoTag;
+		wqe->words[5] = 0;
+		bf_set(lpfc_wqe_gen_ct, &wqe->generic,
+			((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
+		abort_tag = iocbq->iocb.un.acxri.abortIoTag;
+		wqe->generic.abort_tag = abort_tag;
+		/*
+		 * The abort handler will send us CMD_ABORT_XRI_CN or
+		 * CMD_CLOSE_XRI_CN and the fw only accepts CMD_ABORT_XRI_CX
+		 */
+		bf_set(lpfc_wqe_gen_command, &wqe->generic, CMD_ABORT_XRI_CX);
+		cmnd = CMD_ABORT_XRI_CX;
+		command_type = OTHER_COMMAND;
+		xritag = 0;
+	break;
+	case CMD_XRI_ABORTED_CX:
+	case CMD_CREATE_XRI_CR: /* Do we expect to use this? */
+		/* words0-2 are all 0's no bde */
+		/* word3 and word4 are rsvrd */
+		wqe->words[3] = 0;
+		wqe->words[4] = 0;
+		/* word5 iocb=rsvd wge=did */
+		/* There is no remote port id in the IOCB? */
+		/* Let this fall through and fail */
+	case CMD_IOCB_FCP_IBIDIR64_CR: /* bidirectional xfer */
+	case CMD_FCP_TSEND64_CX: /* Target mode send xfer-ready */
+	case CMD_FCP_TRSP64_CX: /* Target mode rcv */
+	case CMD_FCP_AUTO_TRSP_CX: /* Auto target rsp */
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2014 Invalid command 0x%x\n",
+				iocbq->iocb.ulpCommand);
+		return IOCB_ERROR;
+	break;
+
+	}
+	bf_set(lpfc_wqe_gen_xri, &wqe->generic, xritag);
+	bf_set(lpfc_wqe_gen_request_tag, &wqe->generic, iocbq->iotag);
+	wqe->generic.abort_tag = abort_tag;
+	bf_set(lpfc_wqe_gen_cmd_type, &wqe->generic, command_type);
+	bf_set(lpfc_wqe_gen_command, &wqe->generic, cmnd);
+	bf_set(lpfc_wqe_gen_class, &wqe->generic, iocbq->iocb.ulpClass);
+	bf_set(lpfc_wqe_gen_cq_id, &wqe->generic, LPFC_WQE_CQ_ID_DEFAULT);
+
+	return 0;
+}
+
+/**
+ * __lpfc_sli_issue_iocb_s4 - SLI4 device lockless ver of lpfc_sli_issue_iocb
+ * @phba: Pointer to HBA context object.
+ * @ring_number: SLI ring number to issue iocb on.
+ * @piocb: Pointer to command iocb.
+ * @flag: Flag indicating if this command can be put into txq.
+ *
+ * __lpfc_sli_issue_iocb_s4 is used by other functions in the driver to issue
+ * an iocb command to an HBA with SLI-4 interface spec.
+ *
+ * This function is called with hbalock held. The function will return success
+ * after it successfully submit the iocb to firmware or after adding to the
+ * txq.
+ **/
+static int
+__lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
+			 struct lpfc_iocbq *piocb, uint32_t flag)
+{
+	struct lpfc_sglq *sglq;
+	uint16_t xritag;
+	union lpfc_wqe wqe;
+	struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
+	uint32_t fcp_wqidx;
+
+	if (piocb->sli4_xritag == NO_XRI) {
+		if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
+			piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
+			sglq = NULL;
+		else {
+			sglq = __lpfc_sli_get_sglq(phba);
+			if (!sglq)
+				return IOCB_ERROR;
+			piocb->sli4_xritag = sglq->sli4_xritag;
+		}
+	} else if (piocb->iocb_flag &  LPFC_IO_FCP) {
+		sglq = NULL; /* These IO's already have an XRI and
+			      * a mapped sgl.
+			      */
+	} else {
+		/* This is a continuation of a commandi,(CX) so this
+		 * sglq is on the active list
+		 */
+		sglq = __lpfc_get_active_sglq(phba, piocb->sli4_xritag);
+		if (!sglq)
+			return IOCB_ERROR;
+	}
+
+	if (sglq) {
+		xritag = lpfc_sli4_bpl2sgl(phba, piocb, sglq);
+		if (xritag != sglq->sli4_xritag)
+			return IOCB_ERROR;
+	}
+
+	if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe))
+		return IOCB_ERROR;
+
+	if (piocb->iocb_flag &  LPFC_IO_FCP) {
+		fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba, piocb);
+		if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[fcp_wqidx], &wqe))
+			return IOCB_ERROR;
+	} else {
+		if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe))
+			return IOCB_ERROR;
+	}
+	lpfc_sli_ringtxcmpl_put(phba, pring, piocb);
+
+	return 0;
+}
+
+/**
+ * __lpfc_sli_issue_iocb - Wrapper func of lockless version for issuing iocb
+ *
+ * This routine wraps the actual lockless version for issusing IOCB function
+ * pointer from the lpfc_hba struct.
+ *
+ * Return codes:
+ * 	IOCB_ERROR - Error
+ * 	IOCB_SUCCESS - Success
+ * 	IOCB_BUSY - Busy
+ **/
+static inline int
+__lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
+		struct lpfc_iocbq *piocb, uint32_t flag)
+{
+	return phba->__lpfc_sli_issue_iocb(phba, ring_number, piocb, flag);
+}
+
+/**
+ * lpfc_sli_api_table_setup - Set up sli api fucntion jump table
+ * @phba: The hba struct for which this call is being executed.
+ * @dev_grp: The HBA PCI-Device group number.
+ *
+ * This routine sets up the SLI interface API function jump table in @phba
+ * struct.
+ * Returns: 0 - success, -ENODEV - failure.
+ **/
+int
+lpfc_sli_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
+{
+
+	switch (dev_grp) {
+	case LPFC_PCI_DEV_LP:
+		phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s3;
+		phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s3;
+		break;
+	case LPFC_PCI_DEV_OC:
+		phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s4;
+		phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s4;
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"1419 Invalid HBA PCI-device group: 0x%x\n",
+				dev_grp);
+		return -ENODEV;
+		break;
+	}
+	phba->lpfc_get_iocb_from_iocbq = lpfc_get_iocb_from_iocbq;
+	return 0;
+}
 
 /**
  * lpfc_sli_issue_iocb - Wrapper function for __lpfc_sli_issue_iocb
@@ -3848,14 +6126,14 @@
  * functions which do not hold hbalock.
  **/
 int
-lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
 		    struct lpfc_iocbq *piocb, uint32_t flag)
 {
 	unsigned long iflags;
 	int rc;
 
 	spin_lock_irqsave(&phba->hbalock, iflags);
-	rc = __lpfc_sli_issue_iocb(phba, pring, piocb, flag);
+	rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag);
 	spin_unlock_irqrestore(&phba->hbalock, iflags);
 
 	return rc;
@@ -4148,6 +6426,52 @@
 }
 
 /**
+ * lpfc_sli_mbox_sys_flush - Flush mailbox command sub-system
+ * @phba: Pointer to HBA context object.
+ *
+ * This routine flushes the mailbox command subsystem. It will unconditionally
+ * flush all the mailbox commands in the three possible stages in the mailbox
+ * command sub-system: pending mailbox command queue; the outstanding mailbox
+ * command; and completed mailbox command queue. It is caller's responsibility
+ * to make sure that the driver is in the proper state to flush the mailbox
+ * command sub-system. Namely, the posting of mailbox commands into the
+ * pending mailbox command queue from the various clients must be stopped;
+ * either the HBA is in a state that it will never works on the outstanding
+ * mailbox command (such as in EEH or ERATT conditions) or the outstanding
+ * mailbox command has been completed.
+ **/
+static void
+lpfc_sli_mbox_sys_flush(struct lpfc_hba *phba)
+{
+	LIST_HEAD(completions);
+	struct lpfc_sli *psli = &phba->sli;
+	LPFC_MBOXQ_t *pmb;
+	unsigned long iflag;
+
+	/* Flush all the mailbox commands in the mbox system */
+	spin_lock_irqsave(&phba->hbalock, iflag);
+	/* The pending mailbox command queue */
+	list_splice_init(&phba->sli.mboxq, &completions);
+	/* The outstanding active mailbox command */
+	if (psli->mbox_active) {
+		list_add_tail(&psli->mbox_active->list, &completions);
+		psli->mbox_active = NULL;
+		psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+	}
+	/* The completed mailbox command queue */
+	list_splice_init(&phba->sli.mboxq_cmpl, &completions);
+	spin_unlock_irqrestore(&phba->hbalock, iflag);
+
+	/* Return all flushed mailbox commands with MBX_NOT_FINISHED status */
+	while (!list_empty(&completions)) {
+		list_remove_head(&completions, pmb, LPFC_MBOXQ_t, list);
+		pmb->u.mb.mbxStatus = MBX_NOT_FINISHED;
+		if (pmb->mbox_cmpl)
+			pmb->mbox_cmpl(phba, pmb);
+	}
+}
+
+/**
  * lpfc_sli_host_down - Vport cleanup function
  * @vport: Pointer to virtual port object.
  *
@@ -4240,9 +6564,11 @@
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring *pring;
 	struct lpfc_dmabuf *buf_ptr;
-	LPFC_MBOXQ_t *pmb;
-	int i;
 	unsigned long flags = 0;
+	int i;
+
+	/* Shutdown the mailbox command sub-system */
+	lpfc_sli_mbox_sys_shutdown(phba);
 
 	lpfc_hba_down_prep(phba);
 
@@ -4287,28 +6613,42 @@
 
 	/* Return any active mbox cmds */
 	del_timer_sync(&psli->mbox_tmo);
-	spin_lock_irqsave(&phba->hbalock, flags);
 
-	spin_lock(&phba->pport->work_port_lock);
+	spin_lock_irqsave(&phba->pport->work_port_lock, flags);
 	phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
-	spin_unlock(&phba->pport->work_port_lock);
+	spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
 
-	/* Return any pending or completed mbox cmds */
-	list_splice_init(&phba->sli.mboxq, &completions);
-	if (psli->mbox_active) {
-		list_add_tail(&psli->mbox_active->list, &completions);
-		psli->mbox_active = NULL;
-		psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
-	}
-	list_splice_init(&phba->sli.mboxq_cmpl, &completions);
-	spin_unlock_irqrestore(&phba->hbalock, flags);
+	return 1;
+}
 
-	while (!list_empty(&completions)) {
-		list_remove_head(&completions, pmb, LPFC_MBOXQ_t, list);
-		pmb->mb.mbxStatus = MBX_NOT_FINISHED;
-		if (pmb->mbox_cmpl)
-			pmb->mbox_cmpl(phba,pmb);
-	}
+/**
+ * lpfc_sli4_hba_down - PCI function resource cleanup for the SLI4 HBA
+ * @phba: Pointer to HBA context object.
+ *
+ * This function cleans up all queues, iocb, buffers, mailbox commands while
+ * shutting down the SLI4 HBA FCoE function. This function is called with no
+ * lock held and always returns 1.
+ *
+ * This function does the following to cleanup driver FCoE function resources:
+ * - Free discovery resources for each virtual port
+ * - Cleanup any pending fabric iocbs
+ * - Iterate through the iocb txq and free each entry in the list.
+ * - Free up any buffer posted to the HBA.
+ * - Clean up all the queue entries: WQ, RQ, MQ, EQ, CQ, etc.
+ * - Free mailbox commands in the mailbox queue.
+ **/
+int
+lpfc_sli4_hba_down(struct lpfc_hba *phba)
+{
+	/* Stop the SLI4 device port */
+	lpfc_stop_port(phba);
+
+	/* Tear down the queues in the HBA */
+	lpfc_sli4_queue_unset(phba);
+
+	/* unregister default FCFI from the HBA */
+	lpfc_sli4_fcfi_unreg(phba, phba->fcf.fcfi);
+
 	return 1;
 }
 
@@ -4639,7 +6979,10 @@
 	iabt = &abtsiocbp->iocb;
 	iabt->un.acxri.abortType = ABORT_TYPE_ABTS;
 	iabt->un.acxri.abortContextTag = icmd->ulpContext;
-	iabt->un.acxri.abortIoTag = icmd->ulpIoTag;
+	if (phba->sli_rev == LPFC_SLI_REV4)
+		iabt->un.acxri.abortIoTag = cmdiocb->sli4_xritag;
+	else
+		iabt->un.acxri.abortIoTag = icmd->ulpIoTag;
 	iabt->ulpLe = 1;
 	iabt->ulpClass = icmd->ulpClass;
 
@@ -4655,7 +6998,7 @@
 			 "abort cmd iotag x%x\n",
 			 iabt->un.acxri.abortContextTag,
 			 iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
-	retval = __lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
+	retval = __lpfc_sli_issue_iocb(phba, pring->ringno, abtsiocbp, 0);
 
 	if (retval)
 		__lpfc_sli_release_iocbq(phba, abtsiocbp);
@@ -4838,7 +7181,10 @@
 		cmd = &iocbq->iocb;
 		abtsiocb->iocb.un.acxri.abortType = ABORT_TYPE_ABTS;
 		abtsiocb->iocb.un.acxri.abortContextTag = cmd->ulpContext;
-		abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag;
+		if (phba->sli_rev == LPFC_SLI_REV4)
+			abtsiocb->iocb.un.acxri.abortIoTag = iocbq->sli4_xritag;
+		else
+			abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag;
 		abtsiocb->iocb.ulpLe = 1;
 		abtsiocb->iocb.ulpClass = cmd->ulpClass;
 		abtsiocb->vport = phba->pport;
@@ -4850,7 +7196,8 @@
 
 		/* Setup callback routine and issue the command. */
 		abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;
-		ret_val = lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0);
+		ret_val = lpfc_sli_issue_iocb(phba, pring->ringno,
+					      abtsiocb, 0);
 		if (ret_val == IOCB_ERROR) {
 			lpfc_sli_release_iocbq(phba, abtsiocb);
 			errcnt++;
@@ -4931,7 +7278,7 @@
  **/
 int
 lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
-			 struct lpfc_sli_ring *pring,
+			 uint32_t ring_number,
 			 struct lpfc_iocbq *piocb,
 			 struct lpfc_iocbq *prspiocbq,
 			 uint32_t timeout)
@@ -4962,7 +7309,7 @@
 		readl(phba->HCregaddr); /* flush */
 	}
 
-	retval = lpfc_sli_issue_iocb(phba, pring, piocb, 0);
+	retval = lpfc_sli_issue_iocb(phba, ring_number, piocb, 0);
 	if (retval == IOCB_SUCCESS) {
 		timeout_req = timeout * HZ;
 		timeleft = wait_event_timeout(done_q,
@@ -5077,53 +7424,156 @@
 }
 
 /**
- * lpfc_sli_flush_mbox_queue - mailbox queue cleanup function
+ * lpfc_sli_mbox_sys_shutdown - shutdown mailbox command sub-system
  * @phba: Pointer to HBA context.
  *
- * This function is called to cleanup any pending mailbox
- * objects in the driver queue before bringing the HBA offline.
- * This function is called while resetting the HBA.
- * The function is called without any lock held. The function
- * takes hbalock to update SLI data structure.
- * This function returns 1 when there is an active mailbox
- * command pending else returns 0.
+ * This function is called to shutdown the driver's mailbox sub-system.
+ * It first marks the mailbox sub-system is in a block state to prevent
+ * the asynchronous mailbox command from issued off the pending mailbox
+ * command queue. If the mailbox command sub-system shutdown is due to
+ * HBA error conditions such as EEH or ERATT, this routine shall invoke
+ * the mailbox sub-system flush routine to forcefully bring down the
+ * mailbox sub-system. Otherwise, if it is due to normal condition (such
+ * as with offline or HBA function reset), this routine will wait for the
+ * outstanding mailbox command to complete before invoking the mailbox
+ * sub-system flush routine to gracefully bring down mailbox sub-system.
  **/
-int
-lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba)
+void
+lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba)
 {
-	struct lpfc_vport *vport = phba->pport;
-	int i = 0;
+	struct lpfc_sli *psli = &phba->sli;
+	uint8_t actcmd = MBX_HEARTBEAT;
+	unsigned long timeout;
+
+	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);
+		if (phba->sli.mbox_active)
+			actcmd = phba->sli.mbox_active->u.mb.mbxCommand;
+		spin_unlock_irq(&phba->hbalock);
+		/* Determine how long we might wait for the active mailbox
+		 * command to be gracefully completed by firmware.
+		 */
+		timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, actcmd) *
+					   1000) + jiffies;
+		while (phba->sli.mbox_active) {
+			/* Check active mailbox complete status every 2ms */
+			msleep(2);
+			if (time_after(jiffies, timeout))
+				/* Timeout, let the mailbox flush routine to
+				 * forcefully release active mailbox command
+				 */
+				break;
+		}
+	}
+	lpfc_sli_mbox_sys_flush(phba);
+}
+
+/**
+ * lpfc_sli_eratt_read - read sli-3 error attention events
+ * @phba: Pointer to HBA context.
+ *
+ * This function is called to read the SLI3 device error attention registers
+ * for possible error attention events. The caller must hold the hostlock
+ * with spin_lock_irq().
+ *
+ * This fucntion returns 1 when there is Error Attention in the Host Attention
+ * Register and returns 0 otherwise.
+ **/
+static int
+lpfc_sli_eratt_read(struct lpfc_hba *phba)
+{
 	uint32_t ha_copy;
 
-	while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE && !vport->stopped) {
-		if (i++ > LPFC_MBOX_TMO * 1000)
-			return 1;
+	/* Read chip Host Attention (HA) register */
+	ha_copy = readl(phba->HAregaddr);
+	if (ha_copy & HA_ERATT) {
+		/* Read host status register to retrieve error event */
+		lpfc_sli_read_hs(phba);
 
-		/*
-		 * Call lpfc_sli_handle_mb_event only if a mailbox cmd
-		 * did finish. This way we won't get the misleading
-		 * "Stray Mailbox Interrupt" message.
-		 */
+		/* Check if there is a deferred error condition is active */
+		if ((HS_FFER1 & phba->work_hs) &&
+		    ((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 |
+		     HS_FFER6 | HS_FFER7) & phba->work_hs)) {
+			spin_lock_irq(&phba->hbalock);
+			phba->hba_flag |= DEFER_ERATT;
+			spin_unlock_irq(&phba->hbalock);
+			/* Clear all interrupt enable conditions */
+			writel(0, phba->HCregaddr);
+			readl(phba->HCregaddr);
+		}
+
+		/* Set the driver HA work bitmap */
 		spin_lock_irq(&phba->hbalock);
-		ha_copy = phba->work_ha;
-		phba->work_ha &= ~HA_MBATT;
+		phba->work_ha |= HA_ERATT;
+		/* Indicate polling handles this ERATT */
+		phba->hba_flag |= HBA_ERATT_HANDLED;
 		spin_unlock_irq(&phba->hbalock);
-
-		if (ha_copy & HA_MBATT)
-			if (lpfc_sli_handle_mb_event(phba) == 0)
-				i = 0;
-
-		msleep(1);
+		return 1;
 	}
+	return 0;
+}
 
-	return (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) ? 1 : 0;
+/**
+ * lpfc_sli4_eratt_read - read sli-4 error attention events
+ * @phba: Pointer to HBA context.
+ *
+ * This function is called to read the SLI4 device error attention registers
+ * for possible error attention events. The caller must hold the hostlock
+ * with spin_lock_irq().
+ *
+ * This fucntion returns 1 when there is Error Attention in the Host Attention
+ * Register and returns 0 otherwise.
+ **/
+static int
+lpfc_sli4_eratt_read(struct lpfc_hba *phba)
+{
+	uint32_t uerr_sta_hi, uerr_sta_lo;
+	uint32_t onlnreg0, onlnreg1;
+
+	/* For now, use the SLI4 device internal unrecoverable error
+	 * registers for error attention. This can be changed later.
+	 */
+	onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr);
+	onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr);
+	if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) {
+		uerr_sta_lo = readl(phba->sli4_hba.UERRLOregaddr);
+		uerr_sta_hi = readl(phba->sli4_hba.UERRHIregaddr);
+		if (uerr_sta_lo || uerr_sta_hi) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"1423 HBA Unrecoverable error: "
+					"uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
+					"online0_reg=0x%x, online1_reg=0x%x\n",
+					uerr_sta_lo, uerr_sta_hi,
+					onlnreg0, onlnreg1);
+			/* TEMP: as the driver error recover logic is not
+			 * fully developed, we just log the error message
+			 * and the device error attention action is now
+			 * temporarily disabled.
+			 */
+			return 0;
+			phba->work_status[0] = uerr_sta_lo;
+			phba->work_status[1] = uerr_sta_hi;
+			spin_lock_irq(&phba->hbalock);
+			/* Set the driver HA work bitmap */
+			phba->work_ha |= HA_ERATT;
+			/* Indicate polling handles this ERATT */
+			phba->hba_flag |= HBA_ERATT_HANDLED;
+			spin_unlock_irq(&phba->hbalock);
+			return 1;
+		}
+	}
+	return 0;
 }
 
 /**
  * lpfc_sli_check_eratt - check error attention events
  * @phba: Pointer to HBA context.
  *
- * This function is called form timer soft interrupt context to check HBA's
+ * This function is called from timer soft interrupt context to check HBA's
  * error attention register bit for error attention events.
  *
  * This fucntion returns 1 when there is Error Attention in the Host Attention
@@ -5134,10 +7584,6 @@
 {
 	uint32_t ha_copy;
 
-	/* If PCI channel is offline, don't process it */
-	if (unlikely(pci_channel_offline(phba->pcidev)))
-		return 0;
-
 	/* If somebody is waiting to handle an eratt, don't process it
 	 * here. The brdkill function will do this.
 	 */
@@ -5161,56 +7607,84 @@
 		return 0;
 	}
 
-	/* Read chip Host Attention (HA) register */
-	ha_copy = readl(phba->HAregaddr);
-	if (ha_copy & HA_ERATT) {
-		/* Read host status register to retrieve error event */
-		lpfc_sli_read_hs(phba);
-
-		/* Check if there is a deferred error condition is active */
-		if ((HS_FFER1 & phba->work_hs) &&
-			((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 |
-			HS_FFER6 | HS_FFER7) & phba->work_hs)) {
-			phba->hba_flag |= DEFER_ERATT;
-			/* Clear all interrupt enable conditions */
-			writel(0, phba->HCregaddr);
-			readl(phba->HCregaddr);
-		}
-
-		/* Set the driver HA work bitmap */
-		phba->work_ha |= HA_ERATT;
-		/* Indicate polling handles this ERATT */
-		phba->hba_flag |= HBA_ERATT_HANDLED;
+	/* If PCI channel is offline, don't process it */
+	if (unlikely(pci_channel_offline(phba->pcidev))) {
 		spin_unlock_irq(&phba->hbalock);
-		return 1;
+		return 0;
+	}
+
+	switch (phba->sli_rev) {
+	case LPFC_SLI_REV2:
+	case LPFC_SLI_REV3:
+		/* Read chip Host Attention (HA) register */
+		ha_copy = lpfc_sli_eratt_read(phba);
+		break;
+	case LPFC_SLI_REV4:
+		/* Read devcie Uncoverable Error (UERR) registers */
+		ha_copy = lpfc_sli4_eratt_read(phba);
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0299 Invalid SLI revision (%d)\n",
+				phba->sli_rev);
+		ha_copy = 0;
+		break;
 	}
 	spin_unlock_irq(&phba->hbalock);
+
+	return ha_copy;
+}
+
+/**
+ * lpfc_intr_state_check - Check device state for interrupt handling
+ * @phba: Pointer to HBA context.
+ *
+ * This inline routine checks whether a device or its PCI slot is in a state
+ * that the interrupt should be handled.
+ *
+ * This function returns 0 if the device or the PCI slot is in a state that
+ * interrupt should be handled, otherwise -EIO.
+ */
+static inline int
+lpfc_intr_state_check(struct lpfc_hba *phba)
+{
+	/* If the pci channel is offline, ignore all the interrupts */
+	if (unlikely(pci_channel_offline(phba->pcidev)))
+		return -EIO;
+
+	/* Update device level interrupt statistics */
+	phba->sli.slistat.sli_intr++;
+
+	/* Ignore all interrupts during initialization. */
+	if (unlikely(phba->link_state < LPFC_LINK_DOWN))
+		return -EIO;
+
 	return 0;
 }
 
 /**
- * lpfc_sp_intr_handler - The slow-path interrupt handler of lpfc driver
+ * lpfc_sli_sp_intr_handler - Slow-path interrupt handler to SLI-3 device
  * @irq: Interrupt number.
  * @dev_id: The device context pointer.
  *
  * This function is directly called from the PCI layer as an interrupt
- * service routine when the device is enabled with MSI-X multi-message
- * interrupt mode and there are slow-path events in the HBA. However,
- * when the device is enabled with either MSI or Pin-IRQ interrupt mode,
- * this function is called as part of the device-level interrupt handler.
- * When the PCI slot is in error recovery or the HBA is undergoing
- * initialization, the interrupt handler will not process the interrupt.
- * The link attention and ELS ring attention events are handled by the
- * worker thread. The interrupt handler signals the worker thread and
- * and returns for these events. This function is called without any
- * lock held. It gets the hbalock to access and update SLI data
+ * service routine when device with SLI-3 interface spec is enabled with
+ * MSI-X multi-message interrupt mode and there are slow-path events in
+ * the HBA. However, when the device is enabled with either MSI or Pin-IRQ
+ * interrupt mode, this function is called as part of the device-level
+ * interrupt handler. When the PCI slot is in error recovery or the HBA
+ * is undergoing initialization, the interrupt handler will not process
+ * the interrupt. The link attention and ELS ring attention events are
+ * handled by the worker thread. The interrupt handler signals the worker
+ * thread and returns for these events. This function is called without
+ * any lock held. It gets the hbalock to access and update SLI data
  * structures.
  *
  * This function returns IRQ_HANDLED when interrupt is handled else it
  * returns IRQ_NONE.
  **/
 irqreturn_t
-lpfc_sp_intr_handler(int irq, void *dev_id)
+lpfc_sli_sp_intr_handler(int irq, void *dev_id)
 {
 	struct lpfc_hba  *phba;
 	uint32_t ha_copy;
@@ -5240,13 +7714,8 @@
 	 * individual interrupt handler in MSI-X multi-message interrupt mode
 	 */
 	if (phba->intr_type == MSIX) {
-		/* If the pci channel is offline, ignore all the interrupts */
-		if (unlikely(pci_channel_offline(phba->pcidev)))
-			return IRQ_NONE;
-		/* Update device-level interrupt statistics */
-		phba->sli.slistat.sli_intr++;
-		/* Ignore all interrupts during initialization. */
-		if (unlikely(phba->link_state < LPFC_LINK_DOWN))
+		/* Check device state for handling interrupt */
+		if (lpfc_intr_state_check(phba))
 			return IRQ_NONE;
 		/* Need to read HA REG for slow-path events */
 		spin_lock_irqsave(&phba->hbalock, iflag);
@@ -5271,7 +7740,7 @@
 		 * interrupt.
 		 */
 		if (unlikely(phba->hba_flag & DEFER_ERATT)) {
-			spin_unlock_irq(&phba->hbalock);
+			spin_unlock_irqrestore(&phba->hbalock, iflag);
 			return IRQ_NONE;
 		}
 
@@ -5364,7 +7833,7 @@
 
 		if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active)) {
 			pmb = phba->sli.mbox_active;
-			pmbox = &pmb->mb;
+			pmbox = &pmb->u.mb;
 			mbox = phba->mbox;
 			vport = pmb->vport;
 
@@ -5434,7 +7903,8 @@
 							LOG_MBOX | LOG_SLI,
 							"0350 rc should have"
 							"been MBX_BUSY");
-						goto send_current_mbox;
+						if (rc != MBX_NOT_FINISHED)
+							goto send_current_mbox;
 					}
 				}
 				spin_lock_irqsave(
@@ -5471,29 +7941,29 @@
 	}
 	return IRQ_HANDLED;
 
-} /* lpfc_sp_intr_handler */
+} /* lpfc_sli_sp_intr_handler */
 
 /**
- * lpfc_fp_intr_handler - The fast-path interrupt handler of lpfc driver
+ * lpfc_sli_fp_intr_handler - Fast-path interrupt handler to SLI-3 device.
  * @irq: Interrupt number.
  * @dev_id: The device context pointer.
  *
  * This function is directly called from the PCI layer as an interrupt
- * service routine when the device is enabled with MSI-X multi-message
- * interrupt mode and there is a fast-path FCP IOCB ring event in the
- * HBA. However, when the device is enabled with either MSI or Pin-IRQ
- * interrupt mode, this function is called as part of the device-level
- * interrupt handler. When the PCI slot is in error recovery or the HBA
- * is undergoing initialization, the interrupt handler will not process
- * the interrupt. The SCSI FCP fast-path ring event are handled in the
- * intrrupt context. This function is called without any lock held. It
- * gets the hbalock to access and update SLI data structures.
+ * service routine when device with SLI-3 interface spec is enabled with
+ * MSI-X multi-message interrupt mode and there is a fast-path FCP IOCB
+ * ring event in the HBA. However, when the device is enabled with either
+ * MSI or Pin-IRQ interrupt mode, this function is called as part of the
+ * device-level interrupt handler. When the PCI slot is in error recovery
+ * or the HBA is undergoing initialization, the interrupt handler will not
+ * process the interrupt. The SCSI FCP fast-path ring event are handled in
+ * the intrrupt context. This function is called without any lock held.
+ * It gets the hbalock to access and update SLI data structures.
  *
  * This function returns IRQ_HANDLED when interrupt is handled else it
  * returns IRQ_NONE.
  **/
 irqreturn_t
-lpfc_fp_intr_handler(int irq, void *dev_id)
+lpfc_sli_fp_intr_handler(int irq, void *dev_id)
 {
 	struct lpfc_hba  *phba;
 	uint32_t ha_copy;
@@ -5513,13 +7983,8 @@
 	 * individual interrupt handler in MSI-X multi-message interrupt mode
 	 */
 	if (phba->intr_type == MSIX) {
-		/* If pci channel is offline, ignore all the interrupts */
-		if (unlikely(pci_channel_offline(phba->pcidev)))
-			return IRQ_NONE;
-		/* Update device-level interrupt statistics */
-		phba->sli.slistat.sli_intr++;
-		/* Ignore all interrupts during initialization. */
-		if (unlikely(phba->link_state < LPFC_LINK_DOWN))
+		/* Check device state for handling interrupt */
+		if (lpfc_intr_state_check(phba))
 			return IRQ_NONE;
 		/* Need to read HA REG for FCP ring and other ring events */
 		ha_copy = readl(phba->HAregaddr);
@@ -5530,7 +7995,7 @@
 		 * any interrupt.
 		 */
 		if (unlikely(phba->hba_flag & DEFER_ERATT)) {
-			spin_unlock_irq(&phba->hbalock);
+			spin_unlock_irqrestore(&phba->hbalock, iflag);
 			return IRQ_NONE;
 		}
 		writel((ha_copy & (HA_R0_CLR_MSK | HA_R1_CLR_MSK)),
@@ -5566,26 +8031,27 @@
 		}
 	}
 	return IRQ_HANDLED;
-}  /* lpfc_fp_intr_handler */
+}  /* lpfc_sli_fp_intr_handler */
 
 /**
- * lpfc_intr_handler - The device-level interrupt handler of lpfc driver
+ * lpfc_sli_intr_handler - Device-level interrupt handler to SLI-3 device
  * @irq: Interrupt number.
  * @dev_id: The device context pointer.
  *
- * This function is the device-level interrupt handler called from the PCI
- * layer when either MSI or Pin-IRQ interrupt mode is enabled and there is
- * an event in the HBA which requires driver attention. This function
- * invokes the slow-path interrupt attention handling function and fast-path
- * interrupt attention handling function in turn to process the relevant
- * HBA attention events. This function is called without any lock held. It
- * gets the hbalock to access and update SLI data structures.
+ * This function is the HBA device-level interrupt handler to device with
+ * SLI-3 interface spec, called from the PCI layer when either MSI or
+ * Pin-IRQ interrupt mode is enabled and there is an event in the HBA which
+ * requires driver attention. This function invokes the slow-path interrupt
+ * attention handling function and fast-path interrupt attention handling
+ * function in turn to process the relevant HBA attention events. This
+ * function is called without any lock held. It gets the hbalock to access
+ * and update SLI data structures.
  *
  * This function returns IRQ_HANDLED when interrupt is handled, else it
  * returns IRQ_NONE.
  **/
 irqreturn_t
-lpfc_intr_handler(int irq, void *dev_id)
+lpfc_sli_intr_handler(int irq, void *dev_id)
 {
 	struct lpfc_hba  *phba;
 	irqreturn_t sp_irq_rc, fp_irq_rc;
@@ -5600,15 +8066,8 @@
 	if (unlikely(!phba))
 		return IRQ_NONE;
 
-	/* If the pci channel is offline, ignore all the interrupts. */
-	if (unlikely(pci_channel_offline(phba->pcidev)))
-		return IRQ_NONE;
-
-	/* Update device level interrupt statistics */
-	phba->sli.slistat.sli_intr++;
-
-	/* Ignore all interrupts during initialization. */
-	if (unlikely(phba->link_state < LPFC_LINK_DOWN))
+	/* Check device state for handling interrupt */
+	if (lpfc_intr_state_check(phba))
 		return IRQ_NONE;
 
 	spin_lock(&phba->hbalock);
@@ -5650,7 +8109,7 @@
 	status2 >>= (4*LPFC_ELS_RING);
 
 	if (status1 || (status2 & HA_RXMASK))
-		sp_irq_rc = lpfc_sp_intr_handler(irq, dev_id);
+		sp_irq_rc = lpfc_sli_sp_intr_handler(irq, dev_id);
 	else
 		sp_irq_rc = IRQ_NONE;
 
@@ -5670,10 +8129,3322 @@
 		status2 = 0;
 
 	if ((status1 & HA_RXMASK) || (status2 & HA_RXMASK))
-		fp_irq_rc = lpfc_fp_intr_handler(irq, dev_id);
+		fp_irq_rc = lpfc_sli_fp_intr_handler(irq, dev_id);
 	else
 		fp_irq_rc = IRQ_NONE;
 
 	/* Return device-level interrupt handling status */
 	return (sp_irq_rc == IRQ_HANDLED) ? sp_irq_rc : fp_irq_rc;
-}  /* lpfc_intr_handler */
+}  /* lpfc_sli_intr_handler */
+
+/**
+ * lpfc_sli4_fcp_xri_abort_event_proc - Process fcp xri abort event
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked by the worker thread to process all the pending
+ * SLI4 FCP abort XRI events.
+ **/
+void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *phba)
+{
+	struct lpfc_cq_event *cq_event;
+
+	/* First, declare the fcp xri abort event has been handled */
+	spin_lock_irq(&phba->hbalock);
+	phba->hba_flag &= ~FCP_XRI_ABORT_EVENT;
+	spin_unlock_irq(&phba->hbalock);
+	/* Now, handle all the fcp xri abort events */
+	while (!list_empty(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue)) {
+		/* Get the first event from the head of the event queue */
+		spin_lock_irq(&phba->hbalock);
+		list_remove_head(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue,
+				 cq_event, struct lpfc_cq_event, list);
+		spin_unlock_irq(&phba->hbalock);
+		/* Notify aborted XRI for FCP work queue */
+		lpfc_sli4_fcp_xri_aborted(phba, &cq_event->cqe.wcqe_axri);
+		/* Free the event processed back to the free pool */
+		lpfc_sli4_cq_event_release(phba, cq_event);
+	}
+}
+
+/**
+ * lpfc_sli4_els_xri_abort_event_proc - Process els xri abort event
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked by the worker thread to process all the pending
+ * SLI4 els abort xri events.
+ **/
+void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba)
+{
+	struct lpfc_cq_event *cq_event;
+
+	/* First, declare the els xri abort event has been handled */
+	spin_lock_irq(&phba->hbalock);
+	phba->hba_flag &= ~ELS_XRI_ABORT_EVENT;
+	spin_unlock_irq(&phba->hbalock);
+	/* Now, handle all the els xri abort events */
+	while (!list_empty(&phba->sli4_hba.sp_els_xri_aborted_work_queue)) {
+		/* Get the first event from the head of the event queue */
+		spin_lock_irq(&phba->hbalock);
+		list_remove_head(&phba->sli4_hba.sp_els_xri_aborted_work_queue,
+				 cq_event, struct lpfc_cq_event, list);
+		spin_unlock_irq(&phba->hbalock);
+		/* Notify aborted XRI for ELS work queue */
+		lpfc_sli4_els_xri_aborted(phba, &cq_event->cqe.wcqe_axri);
+		/* Free the event processed back to the free pool */
+		lpfc_sli4_cq_event_release(phba, cq_event);
+	}
+}
+
+static void
+lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn,
+			      struct lpfc_iocbq *pIocbOut,
+			      struct lpfc_wcqe_complete *wcqe)
+{
+	size_t offset = offsetof(struct lpfc_iocbq, iocb);
+
+	memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset,
+	       sizeof(struct lpfc_iocbq) - offset);
+	memset(&pIocbIn->sli4_info, 0,
+	       sizeof(struct lpfc_sli4_rspiocb_info));
+	/* Map WCQE parameters into irspiocb parameters */
+	pIocbIn->iocb.ulpStatus = bf_get(lpfc_wcqe_c_status, wcqe);
+	if (pIocbOut->iocb_flag & LPFC_IO_FCP)
+		if (pIocbIn->iocb.ulpStatus == IOSTAT_FCP_RSP_ERROR)
+			pIocbIn->iocb.un.fcpi.fcpi_parm =
+					pIocbOut->iocb.un.fcpi.fcpi_parm -
+					wcqe->total_data_placed;
+		else
+			pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter;
+	else
+		pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter;
+	/* Load in additional WCQE parameters */
+	pIocbIn->sli4_info.hw_status = bf_get(lpfc_wcqe_c_hw_status, wcqe);
+	pIocbIn->sli4_info.bfield = 0;
+	if (bf_get(lpfc_wcqe_c_xb, wcqe))
+		pIocbIn->sli4_info.bfield |= LPFC_XB;
+	if (bf_get(lpfc_wcqe_c_pv, wcqe)) {
+		pIocbIn->sli4_info.bfield |= LPFC_PV;
+		pIocbIn->sli4_info.priority =
+					bf_get(lpfc_wcqe_c_priority, wcqe);
+	}
+}
+
+/**
+ * lpfc_sli4_sp_handle_async_event - Handle an asynchroous event
+ * @phba: Pointer to HBA context object.
+ * @cqe: Pointer to mailbox completion queue entry.
+ *
+ * This routine process a mailbox completion queue entry with asynchrous
+ * event.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_async_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe)
+{
+	struct lpfc_cq_event *cq_event;
+	unsigned long iflags;
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+			"0392 Async Event: word0:x%x, word1:x%x, "
+			"word2:x%x, word3:x%x\n", mcqe->word0,
+			mcqe->mcqe_tag0, mcqe->mcqe_tag1, mcqe->trailer);
+
+	/* Allocate a new internal CQ_EVENT entry */
+	cq_event = lpfc_sli4_cq_event_alloc(phba);
+	if (!cq_event) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0394 Failed to allocate CQ_EVENT entry\n");
+		return false;
+	}
+
+	/* Move the CQE into an asynchronous event entry */
+	memcpy(&cq_event->cqe, mcqe, sizeof(struct lpfc_mcqe));
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	list_add_tail(&cq_event->list, &phba->sli4_hba.sp_asynce_work_queue);
+	/* Set the async event flag */
+	phba->hba_flag |= ASYNC_EVENT;
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+	return true;
+}
+
+/**
+ * lpfc_sli4_sp_handle_mbox_event - Handle a mailbox completion event
+ * @phba: Pointer to HBA context object.
+ * @cqe: Pointer to mailbox completion queue entry.
+ *
+ * This routine process a mailbox completion queue entry with mailbox
+ * completion event.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe)
+{
+	uint32_t mcqe_status;
+	MAILBOX_t *mbox, *pmbox;
+	struct lpfc_mqe *mqe;
+	struct lpfc_vport *vport;
+	struct lpfc_nodelist *ndlp;
+	struct lpfc_dmabuf *mp;
+	unsigned long iflags;
+	LPFC_MBOXQ_t *pmb;
+	bool workposted = false;
+	int rc;
+
+	/* If not a mailbox complete MCQE, out by checking mailbox consume */
+	if (!bf_get(lpfc_trailer_completed, mcqe))
+		goto out_no_mqe_complete;
+
+	/* Get the reference to the active mbox command */
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	pmb = phba->sli.mbox_active;
+	if (unlikely(!pmb)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+				"1832 No pending MBOX command to handle\n");
+		spin_unlock_irqrestore(&phba->hbalock, iflags);
+		goto out_no_mqe_complete;
+	}
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+	mqe = &pmb->u.mqe;
+	pmbox = (MAILBOX_t *)&pmb->u.mqe;
+	mbox = phba->mbox;
+	vport = pmb->vport;
+
+	/* Reset heartbeat timer */
+	phba->last_completion_time = jiffies;
+	del_timer(&phba->sli.mbox_tmo);
+
+	/* Move mbox data to caller's mailbox region, do endian swapping */
+	if (pmb->mbox_cmpl && mbox)
+		lpfc_sli_pcimem_bcopy(mbox, mqe, sizeof(struct lpfc_mqe));
+	/* Set the mailbox status with SLI4 range 0x4000 */
+	mcqe_status = bf_get(lpfc_mcqe_status, mcqe);
+	if (mcqe_status != MB_CQE_STATUS_SUCCESS)
+		bf_set(lpfc_mqe_status, mqe,
+		       (LPFC_MBX_ERROR_RANGE | mcqe_status));
+
+	if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
+		pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_MBOX_VPORT,
+				      "MBOX dflt rpi: status:x%x rpi:x%x",
+				      mcqe_status,
+				      pmbox->un.varWords[0], 0);
+		if (mcqe_status == MB_CQE_STATUS_SUCCESS) {
+			mp = (struct lpfc_dmabuf *)(pmb->context1);
+			ndlp = (struct lpfc_nodelist *)pmb->context2;
+			/* Reg_LOGIN of dflt RPI was successful. Now lets get
+			 * RID of the PPI using the same mbox buffer.
+			 */
+			lpfc_unreg_login(phba, vport->vpi,
+					 pmbox->un.varWords[0], pmb);
+			pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
+			pmb->context1 = mp;
+			pmb->context2 = ndlp;
+			pmb->vport = vport;
+			rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+			if (rc != MBX_BUSY)
+				lpfc_printf_log(phba, KERN_ERR, LOG_MBOX |
+						LOG_SLI, "0385 rc should "
+						"have been MBX_BUSY\n");
+			if (rc != MBX_NOT_FINISHED)
+				goto send_current_mbox;
+		}
+	}
+	spin_lock_irqsave(&phba->pport->work_port_lock, iflags);
+	phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
+	spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags);
+
+	/* There is mailbox completion work to do */
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	__lpfc_mbox_cmpl_put(phba, pmb);
+	phba->work_ha |= HA_MBATT;
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+	workposted = true;
+
+send_current_mbox:
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	/* Release the mailbox command posting token */
+	phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+	/* Setting active mailbox pointer need to be in sync to flag clear */
+	phba->sli.mbox_active = NULL;
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+	/* Wake up worker thread to post the next pending mailbox command */
+	lpfc_worker_wake_up(phba);
+out_no_mqe_complete:
+	if (bf_get(lpfc_trailer_consumed, mcqe))
+		lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq);
+	return workposted;
+}
+
+/**
+ * lpfc_sli4_sp_handle_mcqe - Process a mailbox completion queue entry
+ * @phba: Pointer to HBA context object.
+ * @cqe: Pointer to mailbox completion queue entry.
+ *
+ * This routine process a mailbox completion queue entry, it invokes the
+ * proper mailbox complete handling or asynchrous event handling routine
+ * according to the MCQE's async bit.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_mcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe)
+{
+	struct lpfc_mcqe mcqe;
+	bool workposted;
+
+	/* Copy the mailbox MCQE and convert endian order as needed */
+	lpfc_sli_pcimem_bcopy(cqe, &mcqe, sizeof(struct lpfc_mcqe));
+
+	/* Invoke the proper event handling routine */
+	if (!bf_get(lpfc_trailer_async, &mcqe))
+		workposted = lpfc_sli4_sp_handle_mbox_event(phba, &mcqe);
+	else
+		workposted = lpfc_sli4_sp_handle_async_event(phba, &mcqe);
+	return workposted;
+}
+
+/**
+ * lpfc_sli4_sp_handle_els_wcqe - Handle els work-queue completion event
+ * @phba: Pointer to HBA context object.
+ * @wcqe: Pointer to work-queue completion queue entry.
+ *
+ * This routine handles an ELS work-queue completion event.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba,
+			     struct lpfc_wcqe_complete *wcqe)
+{
+	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+	struct lpfc_iocbq *cmdiocbq;
+	struct lpfc_iocbq *irspiocbq;
+	unsigned long iflags;
+	bool workposted = false;
+
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	pring->stats.iocb_event++;
+	/* Look up the ELS command IOCB and create pseudo response IOCB */
+	cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring,
+				bf_get(lpfc_wcqe_c_request_tag, wcqe));
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+	if (unlikely(!cmdiocbq)) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+				"0386 ELS complete with no corresponding "
+				"cmdiocb: iotag (%d)\n",
+				bf_get(lpfc_wcqe_c_request_tag, wcqe));
+		return workposted;
+	}
+
+	/* Fake the irspiocbq and copy necessary response information */
+	irspiocbq = lpfc_sli_get_iocbq(phba);
+	if (!irspiocbq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0387 Failed to allocate an iocbq\n");
+		return workposted;
+	}
+	lpfc_sli4_iocb_param_transfer(irspiocbq, cmdiocbq, wcqe);
+
+	/* Add the irspiocb to the response IOCB work list */
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	list_add_tail(&irspiocbq->list, &phba->sli4_hba.sp_rspiocb_work_queue);
+	/* Indicate ELS ring attention */
+	phba->work_ha |= (HA_R0ATT << (4*LPFC_ELS_RING));
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+	workposted = true;
+
+	return workposted;
+}
+
+/**
+ * lpfc_sli4_sp_handle_rel_wcqe - Handle slow-path WQ entry consumed event
+ * @phba: Pointer to HBA context object.
+ * @wcqe: Pointer to work-queue completion queue entry.
+ *
+ * This routine handles slow-path WQ entry comsumed event by invoking the
+ * proper WQ release routine to the slow-path WQ.
+ **/
+static void
+lpfc_sli4_sp_handle_rel_wcqe(struct lpfc_hba *phba,
+			     struct lpfc_wcqe_release *wcqe)
+{
+	/* Check for the slow-path ELS work queue */
+	if (bf_get(lpfc_wcqe_r_wq_id, wcqe) == phba->sli4_hba.els_wq->queue_id)
+		lpfc_sli4_wq_release(phba->sli4_hba.els_wq,
+				     bf_get(lpfc_wcqe_r_wqe_index, wcqe));
+	else
+		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+				"2579 Slow-path wqe consume event carries "
+				"miss-matched qid: wcqe-qid=x%x, sp-qid=x%x\n",
+				bf_get(lpfc_wcqe_r_wqe_index, wcqe),
+				phba->sli4_hba.els_wq->queue_id);
+}
+
+/**
+ * lpfc_sli4_sp_handle_abort_xri_wcqe - Handle a xri abort event
+ * @phba: Pointer to HBA context object.
+ * @cq: Pointer to a WQ completion queue.
+ * @wcqe: Pointer to work-queue completion queue entry.
+ *
+ * This routine handles an XRI abort event.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba,
+				   struct lpfc_queue *cq,
+				   struct sli4_wcqe_xri_aborted *wcqe)
+{
+	bool workposted = false;
+	struct lpfc_cq_event *cq_event;
+	unsigned long iflags;
+
+	/* Allocate a new internal CQ_EVENT entry */
+	cq_event = lpfc_sli4_cq_event_alloc(phba);
+	if (!cq_event) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0602 Failed to allocate CQ_EVENT entry\n");
+		return false;
+	}
+
+	/* Move the CQE into the proper xri abort event list */
+	memcpy(&cq_event->cqe, wcqe, sizeof(struct sli4_wcqe_xri_aborted));
+	switch (cq->subtype) {
+	case LPFC_FCP:
+		spin_lock_irqsave(&phba->hbalock, iflags);
+		list_add_tail(&cq_event->list,
+			      &phba->sli4_hba.sp_fcp_xri_aborted_work_queue);
+		/* Set the fcp xri abort event flag */
+		phba->hba_flag |= FCP_XRI_ABORT_EVENT;
+		spin_unlock_irqrestore(&phba->hbalock, iflags);
+		workposted = true;
+		break;
+	case LPFC_ELS:
+		spin_lock_irqsave(&phba->hbalock, iflags);
+		list_add_tail(&cq_event->list,
+			      &phba->sli4_hba.sp_els_xri_aborted_work_queue);
+		/* Set the els xri abort event flag */
+		phba->hba_flag |= ELS_XRI_ABORT_EVENT;
+		spin_unlock_irqrestore(&phba->hbalock, iflags);
+		workposted = true;
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0603 Invalid work queue CQE subtype (x%x)\n",
+				cq->subtype);
+		workposted = false;
+		break;
+	}
+	return workposted;
+}
+
+/**
+ * lpfc_sli4_sp_handle_wcqe - Process a work-queue completion queue entry
+ * @phba: Pointer to HBA context object.
+ * @cq: Pointer to the completion queue.
+ * @wcqe: Pointer to a completion queue entry.
+ *
+ * This routine process a slow-path work-queue completion queue entry.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
+			 struct lpfc_cqe *cqe)
+{
+	struct lpfc_wcqe_complete wcqe;
+	bool workposted = false;
+
+	/* Copy the work queue CQE and convert endian order if needed */
+	lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe));
+
+	/* Check and process for different type of WCQE and dispatch */
+	switch (bf_get(lpfc_wcqe_c_code, &wcqe)) {
+	case CQE_CODE_COMPL_WQE:
+		/* Process the WQ complete event */
+		workposted = lpfc_sli4_sp_handle_els_wcqe(phba,
+					(struct lpfc_wcqe_complete *)&wcqe);
+		break;
+	case CQE_CODE_RELEASE_WQE:
+		/* Process the WQ release event */
+		lpfc_sli4_sp_handle_rel_wcqe(phba,
+					(struct lpfc_wcqe_release *)&wcqe);
+		break;
+	case CQE_CODE_XRI_ABORTED:
+		/* Process the WQ XRI abort event */
+		workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq,
+					(struct sli4_wcqe_xri_aborted *)&wcqe);
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0388 Not a valid WCQE code: x%x\n",
+				bf_get(lpfc_wcqe_c_code, &wcqe));
+		break;
+	}
+	return workposted;
+}
+
+/**
+ * lpfc_sli4_sp_handle_rcqe - Process a receive-queue completion queue entry
+ * @phba: Pointer to HBA context object.
+ * @rcqe: Pointer to receive-queue completion queue entry.
+ *
+ * This routine process a receive-queue completion queue entry.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe)
+{
+	struct lpfc_rcqe rcqe;
+	bool workposted = false;
+	struct lpfc_queue *hrq = phba->sli4_hba.hdr_rq;
+	struct lpfc_queue *drq = phba->sli4_hba.dat_rq;
+	struct hbq_dmabuf *dma_buf;
+	uint32_t status;
+	unsigned long iflags;
+
+	/* Copy the receive queue CQE and convert endian order if needed */
+	lpfc_sli_pcimem_bcopy(cqe, &rcqe, sizeof(struct lpfc_rcqe));
+	lpfc_sli4_rq_release(hrq, drq);
+	if (bf_get(lpfc_rcqe_code, &rcqe) != CQE_CODE_RECEIVE)
+		goto out;
+	if (bf_get(lpfc_rcqe_rq_id, &rcqe) != hrq->queue_id)
+		goto out;
+
+	status = bf_get(lpfc_rcqe_status, &rcqe);
+	switch (status) {
+	case FC_STATUS_RQ_BUF_LEN_EXCEEDED:
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2537 Receive Frame Truncated!!\n");
+	case FC_STATUS_RQ_SUCCESS:
+		spin_lock_irqsave(&phba->hbalock, iflags);
+		dma_buf = lpfc_sli_hbqbuf_get(&phba->hbqs[0].hbq_buffer_list);
+		if (!dma_buf) {
+			spin_unlock_irqrestore(&phba->hbalock, iflags);
+			goto out;
+		}
+		memcpy(&dma_buf->rcqe, &rcqe, sizeof(rcqe));
+		/* save off the frame for the word thread to process */
+		list_add_tail(&dma_buf->dbuf.list, &phba->rb_pend_list);
+		/* Frame received */
+		phba->hba_flag |= HBA_RECEIVE_BUFFER;
+		spin_unlock_irqrestore(&phba->hbalock, iflags);
+		workposted = true;
+		break;
+	case FC_STATUS_INSUFF_BUF_NEED_BUF:
+	case FC_STATUS_INSUFF_BUF_FRM_DISC:
+		/* Post more buffers if possible */
+		spin_lock_irqsave(&phba->hbalock, iflags);
+		phba->hba_flag |= HBA_POST_RECEIVE_BUFFER;
+		spin_unlock_irqrestore(&phba->hbalock, iflags);
+		workposted = true;
+		break;
+	}
+out:
+	return workposted;
+
+}
+
+/**
+ * lpfc_sli4_sp_handle_eqe - Process a slow-path event queue entry
+ * @phba: Pointer to HBA context object.
+ * @eqe: Pointer to fast-path event queue entry.
+ *
+ * This routine process a event queue entry from the slow-path event queue.
+ * It will check the MajorCode and MinorCode to determine this is for a
+ * completion event on a completion queue, if not, an error shall be logged
+ * and just return. Otherwise, it will get to the corresponding completion
+ * queue and process all the entries on that completion queue, rearm the
+ * completion queue, and then return.
+ *
+ **/
+static void
+lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe)
+{
+	struct lpfc_queue *cq = NULL, *childq, *speq;
+	struct lpfc_cqe *cqe;
+	bool workposted = false;
+	int ecount = 0;
+	uint16_t cqid;
+
+	if (bf_get(lpfc_eqe_major_code, eqe) != 0 ||
+	    bf_get(lpfc_eqe_minor_code, eqe) != 0) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0359 Not a valid slow-path completion "
+				"event: majorcode=x%x, minorcode=x%x\n",
+				bf_get(lpfc_eqe_major_code, eqe),
+				bf_get(lpfc_eqe_minor_code, eqe));
+		return;
+	}
+
+	/* Get the reference to the corresponding CQ */
+	cqid = bf_get(lpfc_eqe_resource_id, eqe);
+
+	/* Search for completion queue pointer matching this cqid */
+	speq = phba->sli4_hba.sp_eq;
+	list_for_each_entry(childq, &speq->child_list, list) {
+		if (childq->queue_id == cqid) {
+			cq = childq;
+			break;
+		}
+	}
+	if (unlikely(!cq)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0365 Slow-path CQ identifier (%d) does "
+				"not exist\n", cqid);
+		return;
+	}
+
+	/* Process all the entries to the CQ */
+	switch (cq->type) {
+	case LPFC_MCQ:
+		while ((cqe = lpfc_sli4_cq_get(cq))) {
+			workposted |= lpfc_sli4_sp_handle_mcqe(phba, cqe);
+			if (!(++ecount % LPFC_GET_QE_REL_INT))
+				lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM);
+		}
+		break;
+	case LPFC_WCQ:
+		while ((cqe = lpfc_sli4_cq_get(cq))) {
+			workposted |= lpfc_sli4_sp_handle_wcqe(phba, cq, cqe);
+			if (!(++ecount % LPFC_GET_QE_REL_INT))
+				lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM);
+		}
+		break;
+	case LPFC_RCQ:
+		while ((cqe = lpfc_sli4_cq_get(cq))) {
+			workposted |= lpfc_sli4_sp_handle_rcqe(phba, cqe);
+			if (!(++ecount % LPFC_GET_QE_REL_INT))
+				lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM);
+		}
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0370 Invalid completion queue type (%d)\n",
+				cq->type);
+		return;
+	}
+
+	/* Catch the no cq entry condition, log an error */
+	if (unlikely(ecount == 0))
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0371 No entry from the CQ: identifier "
+				"(x%x), type (%d)\n", cq->queue_id, cq->type);
+
+	/* In any case, flash and re-arm the RCQ */
+	lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM);
+
+	/* wake up worker thread if there are works to be done */
+	if (workposted)
+		lpfc_worker_wake_up(phba);
+}
+
+/**
+ * lpfc_sli4_fp_handle_fcp_wcqe - Process fast-path work queue completion entry
+ * @eqe: Pointer to fast-path completion queue entry.
+ *
+ * This routine process a fast-path work queue completion entry from fast-path
+ * event queue for FCP command response completion.
+ **/
+static void
+lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba,
+			     struct lpfc_wcqe_complete *wcqe)
+{
+	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_FCP_RING];
+	struct lpfc_iocbq *cmdiocbq;
+	struct lpfc_iocbq irspiocbq;
+	unsigned long iflags;
+
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	pring->stats.iocb_event++;
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+	/* Check for response status */
+	if (unlikely(bf_get(lpfc_wcqe_c_status, wcqe))) {
+		/* If resource errors reported from HBA, reduce queue
+		 * depth of the SCSI device.
+		 */
+		if ((bf_get(lpfc_wcqe_c_status, wcqe) ==
+		     IOSTAT_LOCAL_REJECT) &&
+		    (wcqe->parameter == IOERR_NO_RESOURCES)) {
+			phba->lpfc_rampdown_queue_depth(phba);
+		}
+		/* Log the error status */
+		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+				"0373 FCP complete error: status=x%x, "
+				"hw_status=x%x, total_data_specified=%d, "
+				"parameter=x%x, word3=x%x\n",
+				bf_get(lpfc_wcqe_c_status, wcqe),
+				bf_get(lpfc_wcqe_c_hw_status, wcqe),
+				wcqe->total_data_placed, wcqe->parameter,
+				wcqe->word3);
+	}
+
+	/* Look up the FCP command IOCB and create pseudo response IOCB */
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring,
+				bf_get(lpfc_wcqe_c_request_tag, wcqe));
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+	if (unlikely(!cmdiocbq)) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+				"0374 FCP complete with no corresponding "
+				"cmdiocb: iotag (%d)\n",
+				bf_get(lpfc_wcqe_c_request_tag, wcqe));
+		return;
+	}
+	if (unlikely(!cmdiocbq->iocb_cmpl)) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+				"0375 FCP cmdiocb not callback function "
+				"iotag: (%d)\n",
+				bf_get(lpfc_wcqe_c_request_tag, wcqe));
+		return;
+	}
+
+	/* Fake the irspiocb and copy necessary response information */
+	lpfc_sli4_iocb_param_transfer(&irspiocbq, cmdiocbq, wcqe);
+
+	/* Pass the cmd_iocb and the rsp state to the upper layer */
+	(cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq);
+}
+
+/**
+ * lpfc_sli4_fp_handle_rel_wcqe - Handle fast-path WQ entry consumed event
+ * @phba: Pointer to HBA context object.
+ * @cq: Pointer to completion queue.
+ * @wcqe: Pointer to work-queue completion queue entry.
+ *
+ * This routine handles an fast-path WQ entry comsumed event by invoking the
+ * proper WQ release routine to the slow-path WQ.
+ **/
+static void
+lpfc_sli4_fp_handle_rel_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
+			     struct lpfc_wcqe_release *wcqe)
+{
+	struct lpfc_queue *childwq;
+	bool wqid_matched = false;
+	uint16_t fcp_wqid;
+
+	/* Check for fast-path FCP work queue release */
+	fcp_wqid = bf_get(lpfc_wcqe_r_wq_id, wcqe);
+	list_for_each_entry(childwq, &cq->child_list, list) {
+		if (childwq->queue_id == fcp_wqid) {
+			lpfc_sli4_wq_release(childwq,
+					bf_get(lpfc_wcqe_r_wqe_index, wcqe));
+			wqid_matched = true;
+			break;
+		}
+	}
+	/* Report warning log message if no match found */
+	if (wqid_matched != true)
+		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+				"2580 Fast-path wqe consume event carries "
+				"miss-matched qid: wcqe-qid=x%x\n", fcp_wqid);
+}
+
+/**
+ * lpfc_sli4_fp_handle_wcqe - Process fast-path work queue completion entry
+ * @cq: Pointer to the completion queue.
+ * @eqe: Pointer to fast-path completion queue entry.
+ *
+ * This routine process a fast-path work queue completion entry from fast-path
+ * event queue for FCP command response completion.
+ **/
+static int
+lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
+			 struct lpfc_cqe *cqe)
+{
+	struct lpfc_wcqe_release wcqe;
+	bool workposted = false;
+
+	/* Copy the work queue CQE and convert endian order if needed */
+	lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe));
+
+	/* Check and process for different type of WCQE and dispatch */
+	switch (bf_get(lpfc_wcqe_c_code, &wcqe)) {
+	case CQE_CODE_COMPL_WQE:
+		/* Process the WQ complete event */
+		lpfc_sli4_fp_handle_fcp_wcqe(phba,
+				(struct lpfc_wcqe_complete *)&wcqe);
+		break;
+	case CQE_CODE_RELEASE_WQE:
+		/* Process the WQ release event */
+		lpfc_sli4_fp_handle_rel_wcqe(phba, cq,
+				(struct lpfc_wcqe_release *)&wcqe);
+		break;
+	case CQE_CODE_XRI_ABORTED:
+		/* Process the WQ XRI abort event */
+		workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq,
+				(struct sli4_wcqe_xri_aborted *)&wcqe);
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0144 Not a valid WCQE code: x%x\n",
+				bf_get(lpfc_wcqe_c_code, &wcqe));
+		break;
+	}
+	return workposted;
+}
+
+/**
+ * lpfc_sli4_fp_handle_eqe - Process a fast-path event queue entry
+ * @phba: Pointer to HBA context object.
+ * @eqe: Pointer to fast-path event queue entry.
+ *
+ * This routine process a event queue entry from the fast-path event queue.
+ * It will check the MajorCode and MinorCode to determine this is for a
+ * completion event on a completion queue, if not, an error shall be logged
+ * and just return. Otherwise, it will get to the corresponding completion
+ * queue and process all the entries on the completion queue, rearm the
+ * completion queue, and then return.
+ **/
+static void
+lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
+			uint32_t fcp_cqidx)
+{
+	struct lpfc_queue *cq;
+	struct lpfc_cqe *cqe;
+	bool workposted = false;
+	uint16_t cqid;
+	int ecount = 0;
+
+	if (unlikely(bf_get(lpfc_eqe_major_code, eqe) != 0) ||
+	    unlikely(bf_get(lpfc_eqe_minor_code, eqe) != 0)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0366 Not a valid fast-path completion "
+				"event: majorcode=x%x, minorcode=x%x\n",
+				bf_get(lpfc_eqe_major_code, eqe),
+				bf_get(lpfc_eqe_minor_code, eqe));
+		return;
+	}
+
+	cq = phba->sli4_hba.fcp_cq[fcp_cqidx];
+	if (unlikely(!cq)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0367 Fast-path completion queue does not "
+				"exist\n");
+		return;
+	}
+
+	/* Get the reference to the corresponding CQ */
+	cqid = bf_get(lpfc_eqe_resource_id, eqe);
+	if (unlikely(cqid != cq->queue_id)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0368 Miss-matched fast-path completion "
+				"queue identifier: eqcqid=%d, fcpcqid=%d\n",
+				cqid, cq->queue_id);
+		return;
+	}
+
+	/* Process all the entries to the CQ */
+	while ((cqe = lpfc_sli4_cq_get(cq))) {
+		workposted |= lpfc_sli4_fp_handle_wcqe(phba, cq, cqe);
+		if (!(++ecount % LPFC_GET_QE_REL_INT))
+			lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM);
+	}
+
+	/* Catch the no cq entry condition */
+	if (unlikely(ecount == 0))
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0369 No entry from fast-path completion "
+				"queue fcpcqid=%d\n", cq->queue_id);
+
+	/* In any case, flash and re-arm the CQ */
+	lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM);
+
+	/* wake up worker thread if there are works to be done */
+	if (workposted)
+		lpfc_worker_wake_up(phba);
+}
+
+static void
+lpfc_sli4_eq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq)
+{
+	struct lpfc_eqe *eqe;
+
+	/* walk all the EQ entries and drop on the floor */
+	while ((eqe = lpfc_sli4_eq_get(eq)))
+		;
+
+	/* Clear and re-arm the EQ */
+	lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM);
+}
+
+/**
+ * lpfc_sli4_sp_intr_handler - Slow-path interrupt handler to SLI-4 device
+ * @irq: Interrupt number.
+ * @dev_id: The device context pointer.
+ *
+ * This function is directly called from the PCI layer as an interrupt
+ * service routine when device with SLI-4 interface spec is enabled with
+ * MSI-X multi-message interrupt mode and there are slow-path events in
+ * the HBA. However, when the device is enabled with either MSI or Pin-IRQ
+ * interrupt mode, this function is called as part of the device-level
+ * interrupt handler. When the PCI slot is in error recovery or the HBA is
+ * undergoing initialization, the interrupt handler will not process the
+ * interrupt. The link attention and ELS ring attention events are handled
+ * by the worker thread. The interrupt handler signals the worker thread
+ * and returns for these events. This function is called without any lock
+ * held. It gets the hbalock to access and update SLI data structures.
+ *
+ * This function returns IRQ_HANDLED when interrupt is handled else it
+ * returns IRQ_NONE.
+ **/
+irqreturn_t
+lpfc_sli4_sp_intr_handler(int irq, void *dev_id)
+{
+	struct lpfc_hba *phba;
+	struct lpfc_queue *speq;
+	struct lpfc_eqe *eqe;
+	unsigned long iflag;
+	int ecount = 0;
+
+	/*
+	 * Get the driver's phba structure from the dev_id
+	 */
+	phba = (struct lpfc_hba *)dev_id;
+
+	if (unlikely(!phba))
+		return IRQ_NONE;
+
+	/* Get to the EQ struct associated with this vector */
+	speq = phba->sli4_hba.sp_eq;
+
+	/* Check device state for handling interrupt */
+	if (unlikely(lpfc_intr_state_check(phba))) {
+		/* Check again for link_state with lock held */
+		spin_lock_irqsave(&phba->hbalock, iflag);
+		if (phba->link_state < LPFC_LINK_DOWN)
+			/* Flush, clear interrupt, and rearm the EQ */
+			lpfc_sli4_eq_flush(phba, speq);
+		spin_unlock_irqrestore(&phba->hbalock, iflag);
+		return IRQ_NONE;
+	}
+
+	/*
+	 * Process all the event on FCP slow-path EQ
+	 */
+	while ((eqe = lpfc_sli4_eq_get(speq))) {
+		lpfc_sli4_sp_handle_eqe(phba, eqe);
+		if (!(++ecount % LPFC_GET_QE_REL_INT))
+			lpfc_sli4_eq_release(speq, LPFC_QUEUE_NOARM);
+	}
+
+	/* Always clear and re-arm the slow-path EQ */
+	lpfc_sli4_eq_release(speq, LPFC_QUEUE_REARM);
+
+	/* Catch the no cq entry condition */
+	if (unlikely(ecount == 0)) {
+		if (phba->intr_type == MSIX)
+			/* MSI-X treated interrupt served as no EQ share INT */
+			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+					"0357 MSI-X interrupt with no EQE\n");
+		else
+			/* Non MSI-X treated on interrupt as EQ share INT */
+			return IRQ_NONE;
+	}
+
+	return IRQ_HANDLED;
+} /* lpfc_sli4_sp_intr_handler */
+
+/**
+ * lpfc_sli4_fp_intr_handler - Fast-path interrupt handler to SLI-4 device
+ * @irq: Interrupt number.
+ * @dev_id: The device context pointer.
+ *
+ * This function is directly called from the PCI layer as an interrupt
+ * service routine when device with SLI-4 interface spec is enabled with
+ * MSI-X multi-message interrupt mode and there is a fast-path FCP IOCB
+ * ring event in the HBA. However, when the device is enabled with either
+ * MSI or Pin-IRQ interrupt mode, this function is called as part of the
+ * device-level interrupt handler. When the PCI slot is in error recovery
+ * or the HBA is undergoing initialization, the interrupt handler will not
+ * process the interrupt. The SCSI FCP fast-path ring event are handled in
+ * the intrrupt context. This function is called without any lock held.
+ * It gets the hbalock to access and update SLI data structures. Note that,
+ * the FCP EQ to FCP CQ are one-to-one map such that the FCP EQ index is
+ * equal to that of FCP CQ index.
+ *
+ * This function returns IRQ_HANDLED when interrupt is handled else it
+ * returns IRQ_NONE.
+ **/
+irqreturn_t
+lpfc_sli4_fp_intr_handler(int irq, void *dev_id)
+{
+	struct lpfc_hba *phba;
+	struct lpfc_fcp_eq_hdl *fcp_eq_hdl;
+	struct lpfc_queue *fpeq;
+	struct lpfc_eqe *eqe;
+	unsigned long iflag;
+	int ecount = 0;
+	uint32_t fcp_eqidx;
+
+	/* Get the driver's phba structure from the dev_id */
+	fcp_eq_hdl = (struct lpfc_fcp_eq_hdl *)dev_id;
+	phba = fcp_eq_hdl->phba;
+	fcp_eqidx = fcp_eq_hdl->idx;
+
+	if (unlikely(!phba))
+		return IRQ_NONE;
+
+	/* Get to the EQ struct associated with this vector */
+	fpeq = phba->sli4_hba.fp_eq[fcp_eqidx];
+
+	/* Check device state for handling interrupt */
+	if (unlikely(lpfc_intr_state_check(phba))) {
+		/* Check again for link_state with lock held */
+		spin_lock_irqsave(&phba->hbalock, iflag);
+		if (phba->link_state < LPFC_LINK_DOWN)
+			/* Flush, clear interrupt, and rearm the EQ */
+			lpfc_sli4_eq_flush(phba, fpeq);
+		spin_unlock_irqrestore(&phba->hbalock, iflag);
+		return IRQ_NONE;
+	}
+
+	/*
+	 * Process all the event on FCP fast-path EQ
+	 */
+	while ((eqe = lpfc_sli4_eq_get(fpeq))) {
+		lpfc_sli4_fp_handle_eqe(phba, eqe, fcp_eqidx);
+		if (!(++ecount % LPFC_GET_QE_REL_INT))
+			lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_NOARM);
+	}
+
+	/* Always clear and re-arm the fast-path EQ */
+	lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_REARM);
+
+	if (unlikely(ecount == 0)) {
+		if (phba->intr_type == MSIX)
+			/* MSI-X treated interrupt served as no EQ share INT */
+			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+					"0358 MSI-X interrupt with no EQE\n");
+		else
+			/* Non MSI-X treated on interrupt as EQ share INT */
+			return IRQ_NONE;
+	}
+
+	return IRQ_HANDLED;
+} /* lpfc_sli4_fp_intr_handler */
+
+/**
+ * lpfc_sli4_intr_handler - Device-level interrupt handler for SLI-4 device
+ * @irq: Interrupt number.
+ * @dev_id: The device context pointer.
+ *
+ * This function is the device-level interrupt handler to device with SLI-4
+ * interface spec, called from the PCI layer when either MSI or Pin-IRQ
+ * interrupt mode is enabled and there is an event in the HBA which requires
+ * driver attention. This function invokes the slow-path interrupt attention
+ * handling function and fast-path interrupt attention handling function in
+ * turn to process the relevant HBA attention events. This function is called
+ * without any lock held. It gets the hbalock to access and update SLI data
+ * structures.
+ *
+ * This function returns IRQ_HANDLED when interrupt is handled, else it
+ * returns IRQ_NONE.
+ **/
+irqreturn_t
+lpfc_sli4_intr_handler(int irq, void *dev_id)
+{
+	struct lpfc_hba  *phba;
+	irqreturn_t sp_irq_rc, fp_irq_rc;
+	bool fp_handled = false;
+	uint32_t fcp_eqidx;
+
+	/* Get the driver's phba structure from the dev_id */
+	phba = (struct lpfc_hba *)dev_id;
+
+	if (unlikely(!phba))
+		return IRQ_NONE;
+
+	/*
+	 * Invokes slow-path host attention interrupt handling as appropriate.
+	 */
+	sp_irq_rc = lpfc_sli4_sp_intr_handler(irq, dev_id);
+
+	/*
+	 * Invoke fast-path host attention interrupt handling as appropriate.
+	 */
+	for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) {
+		fp_irq_rc = lpfc_sli4_fp_intr_handler(irq,
+					&phba->sli4_hba.fcp_eq_hdl[fcp_eqidx]);
+		if (fp_irq_rc == IRQ_HANDLED)
+			fp_handled |= true;
+	}
+
+	return (fp_handled == true) ? IRQ_HANDLED : sp_irq_rc;
+} /* lpfc_sli4_intr_handler */
+
+/**
+ * lpfc_sli4_queue_free - free a queue structure and associated memory
+ * @queue: The queue structure to free.
+ *
+ * This function frees a queue structure and the DMAable memeory used for
+ * the host resident queue. This function must be called after destroying the
+ * queue on the HBA.
+ **/
+void
+lpfc_sli4_queue_free(struct lpfc_queue *queue)
+{
+	struct lpfc_dmabuf *dmabuf;
+
+	if (!queue)
+		return;
+
+	while (!list_empty(&queue->page_list)) {
+		list_remove_head(&queue->page_list, dmabuf, struct lpfc_dmabuf,
+				 list);
+		dma_free_coherent(&queue->phba->pcidev->dev, PAGE_SIZE,
+				  dmabuf->virt, dmabuf->phys);
+		kfree(dmabuf);
+	}
+	kfree(queue);
+	return;
+}
+
+/**
+ * lpfc_sli4_queue_alloc - Allocate and initialize a queue structure
+ * @phba: The HBA that this queue is being created on.
+ * @entry_size: The size of each queue entry for this queue.
+ * @entry count: The number of entries that this queue will handle.
+ *
+ * This function allocates a queue structure and the DMAable memory used for
+ * the host resident queue. This function must be called before creating the
+ * queue on the HBA.
+ **/
+struct lpfc_queue *
+lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size,
+		      uint32_t entry_count)
+{
+	struct lpfc_queue *queue;
+	struct lpfc_dmabuf *dmabuf;
+	int x, total_qe_count;
+	void *dma_pointer;
+
+
+	queue = kzalloc(sizeof(struct lpfc_queue) +
+			(sizeof(union sli4_qe) * entry_count), GFP_KERNEL);
+	if (!queue)
+		return NULL;
+	queue->page_count = (PAGE_ALIGN(entry_size * entry_count))/PAGE_SIZE;
+	INIT_LIST_HEAD(&queue->list);
+	INIT_LIST_HEAD(&queue->page_list);
+	INIT_LIST_HEAD(&queue->child_list);
+	for (x = 0, total_qe_count = 0; x < queue->page_count; x++) {
+		dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+		if (!dmabuf)
+			goto out_fail;
+		dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
+						  PAGE_SIZE, &dmabuf->phys,
+						  GFP_KERNEL);
+		if (!dmabuf->virt) {
+			kfree(dmabuf);
+			goto out_fail;
+		}
+		dmabuf->buffer_tag = x;
+		list_add_tail(&dmabuf->list, &queue->page_list);
+		/* initialize queue's entry array */
+		dma_pointer = dmabuf->virt;
+		for (; total_qe_count < entry_count &&
+		     dma_pointer < (PAGE_SIZE + dmabuf->virt);
+		     total_qe_count++, dma_pointer += entry_size) {
+			queue->qe[total_qe_count].address = dma_pointer;
+		}
+	}
+	queue->entry_size = entry_size;
+	queue->entry_count = entry_count;
+	queue->phba = phba;
+
+	return queue;
+out_fail:
+	lpfc_sli4_queue_free(queue);
+	return NULL;
+}
+
+/**
+ * lpfc_eq_create - Create an Event Queue on the HBA
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @eq: The queue structure to use to create the event queue.
+ * @imax: The maximum interrupt per second limit.
+ *
+ * This function creates an event queue, as detailed in @eq, on a port,
+ * described by @phba by sending an EQ_CREATE mailbox command to the HBA.
+ *
+ * The @phba struct is used to send mailbox command to HBA. The @eq struct
+ * is used to get the entry count and entry size that are necessary to
+ * determine the number of pages to allocate and use for this queue. This
+ * function will send the EQ_CREATE mailbox command to the HBA to setup the
+ * event queue. This function is asynchronous and will wait for the mailbox
+ * command to finish before continuing.
+ *
+ * On success this function will return a zero. If unable to allocate enough
+ * memory this function will return ENOMEM. If the queue create mailbox command
+ * fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax)
+{
+	struct lpfc_mbx_eq_create *eq_create;
+	LPFC_MBOXQ_t *mbox;
+	int rc, length, status = 0;
+	struct lpfc_dmabuf *dmabuf;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+	uint16_t dmult;
+
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+	length = (sizeof(struct lpfc_mbx_eq_create) -
+		  sizeof(struct lpfc_sli4_cfg_mhdr));
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+			 LPFC_MBOX_OPCODE_EQ_CREATE,
+			 length, LPFC_SLI4_MBX_EMBED);
+	eq_create = &mbox->u.mqe.un.eq_create;
+	bf_set(lpfc_mbx_eq_create_num_pages, &eq_create->u.request,
+	       eq->page_count);
+	bf_set(lpfc_eq_context_size, &eq_create->u.request.context,
+	       LPFC_EQE_SIZE);
+	bf_set(lpfc_eq_context_valid, &eq_create->u.request.context, 1);
+	/* Calculate delay multiper from maximum interrupt per second */
+	dmult = LPFC_DMULT_CONST/imax - 1;
+	bf_set(lpfc_eq_context_delay_multi, &eq_create->u.request.context,
+	       dmult);
+	switch (eq->entry_count) {
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0360 Unsupported EQ count. (%d)\n",
+				eq->entry_count);
+		if (eq->entry_count < 256)
+			return -EINVAL;
+		/* otherwise default to smallest count (drop through) */
+	case 256:
+		bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
+		       LPFC_EQ_CNT_256);
+		break;
+	case 512:
+		bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
+		       LPFC_EQ_CNT_512);
+		break;
+	case 1024:
+		bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
+		       LPFC_EQ_CNT_1024);
+		break;
+	case 2048:
+		bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
+		       LPFC_EQ_CNT_2048);
+		break;
+	case 4096:
+		bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
+		       LPFC_EQ_CNT_4096);
+		break;
+	}
+	list_for_each_entry(dmabuf, &eq->page_list, list) {
+		eq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+					putPaddrLow(dmabuf->phys);
+		eq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+					putPaddrHigh(dmabuf->phys);
+	}
+	mbox->vport = phba->pport;
+	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+	mbox->context1 = NULL;
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+	shdr = (union lpfc_sli4_cfg_shdr *) &eq_create->header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2500 EQ_CREATE mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		status = -ENXIO;
+	}
+	eq->type = LPFC_EQ;
+	eq->subtype = LPFC_NONE;
+	eq->queue_id = bf_get(lpfc_mbx_eq_create_q_id, &eq_create->u.response);
+	if (eq->queue_id == 0xFFFF)
+		status = -ENXIO;
+	eq->host_index = 0;
+	eq->hba_index = 0;
+
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mbox, phba->mbox_mem_pool);
+	return status;
+}
+
+/**
+ * lpfc_cq_create - Create a Completion Queue on the HBA
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @cq: The queue structure to use to create the completion queue.
+ * @eq: The event queue to bind this completion queue to.
+ *
+ * This function creates a completion queue, as detailed in @wq, on a port,
+ * described by @phba by sending a CQ_CREATE mailbox command to the HBA.
+ *
+ * The @phba struct is used to send mailbox command to HBA. The @cq struct
+ * is used to get the entry count and entry size that are necessary to
+ * determine the number of pages to allocate and use for this queue. The @eq
+ * is used to indicate which event queue to bind this completion queue to. This
+ * function will send the CQ_CREATE mailbox command to the HBA to setup the
+ * completion queue. This function is asynchronous and will wait for the mailbox
+ * command to finish before continuing.
+ *
+ * On success this function will return a zero. If unable to allocate enough
+ * memory this function will return ENOMEM. If the queue create mailbox command
+ * fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
+	       struct lpfc_queue *eq, uint32_t type, uint32_t subtype)
+{
+	struct lpfc_mbx_cq_create *cq_create;
+	struct lpfc_dmabuf *dmabuf;
+	LPFC_MBOXQ_t *mbox;
+	int rc, length, status = 0;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+	length = (sizeof(struct lpfc_mbx_cq_create) -
+		  sizeof(struct lpfc_sli4_cfg_mhdr));
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+			 LPFC_MBOX_OPCODE_CQ_CREATE,
+			 length, LPFC_SLI4_MBX_EMBED);
+	cq_create = &mbox->u.mqe.un.cq_create;
+	bf_set(lpfc_mbx_cq_create_num_pages, &cq_create->u.request,
+		    cq->page_count);
+	bf_set(lpfc_cq_context_event, &cq_create->u.request.context, 1);
+	bf_set(lpfc_cq_context_valid, &cq_create->u.request.context, 1);
+	bf_set(lpfc_cq_eq_id, &cq_create->u.request.context, eq->queue_id);
+	switch (cq->entry_count) {
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0361 Unsupported CQ count. (%d)\n",
+				cq->entry_count);
+		if (cq->entry_count < 256)
+			return -EINVAL;
+		/* otherwise default to smallest count (drop through) */
+	case 256:
+		bf_set(lpfc_cq_context_count, &cq_create->u.request.context,
+		       LPFC_CQ_CNT_256);
+		break;
+	case 512:
+		bf_set(lpfc_cq_context_count, &cq_create->u.request.context,
+		       LPFC_CQ_CNT_512);
+		break;
+	case 1024:
+		bf_set(lpfc_cq_context_count, &cq_create->u.request.context,
+		       LPFC_CQ_CNT_1024);
+		break;
+	}
+	list_for_each_entry(dmabuf, &cq->page_list, list) {
+		cq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+					putPaddrLow(dmabuf->phys);
+		cq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+					putPaddrHigh(dmabuf->phys);
+	}
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+
+	/* The IOCTL status is embedded in the mailbox subheader. */
+	shdr = (union lpfc_sli4_cfg_shdr *) &cq_create->header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2501 CQ_CREATE mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		status = -ENXIO;
+		goto out;
+	}
+	cq->queue_id = bf_get(lpfc_mbx_cq_create_q_id, &cq_create->u.response);
+	if (cq->queue_id == 0xFFFF) {
+		status = -ENXIO;
+		goto out;
+	}
+	/* link the cq onto the parent eq child list */
+	list_add_tail(&cq->list, &eq->child_list);
+	/* Set up completion queue's type and subtype */
+	cq->type = type;
+	cq->subtype = subtype;
+	cq->queue_id = bf_get(lpfc_mbx_cq_create_q_id, &cq_create->u.response);
+	cq->host_index = 0;
+	cq->hba_index = 0;
+out:
+
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mbox, phba->mbox_mem_pool);
+	return status;
+}
+
+/**
+ * lpfc_mq_create - Create a mailbox Queue on the HBA
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @mq: The queue structure to use to create the mailbox queue.
+ *
+ * This function creates a mailbox queue, as detailed in @mq, on a port,
+ * described by @phba by sending a MQ_CREATE mailbox command to the HBA.
+ *
+ * The @phba struct is used to send mailbox command to HBA. The @cq struct
+ * is used to get the entry count and entry size that are necessary to
+ * determine the number of pages to allocate and use for this queue. This
+ * function will send the MQ_CREATE mailbox command to the HBA to setup the
+ * mailbox queue. This function is asynchronous and will wait for the mailbox
+ * command to finish before continuing.
+ *
+ * On success this function will return a zero. If unable to allocate enough
+ * memory this function will return ENOMEM. If the queue create mailbox command
+ * fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
+	       struct lpfc_queue *cq, uint32_t subtype)
+{
+	struct lpfc_mbx_mq_create *mq_create;
+	struct lpfc_dmabuf *dmabuf;
+	LPFC_MBOXQ_t *mbox;
+	int rc, length, status = 0;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+	length = (sizeof(struct lpfc_mbx_mq_create) -
+		  sizeof(struct lpfc_sli4_cfg_mhdr));
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+			 LPFC_MBOX_OPCODE_MQ_CREATE,
+			 length, LPFC_SLI4_MBX_EMBED);
+	mq_create = &mbox->u.mqe.un.mq_create;
+	bf_set(lpfc_mbx_mq_create_num_pages, &mq_create->u.request,
+		    mq->page_count);
+	bf_set(lpfc_mq_context_cq_id, &mq_create->u.request.context,
+		    cq->queue_id);
+	bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1);
+	switch (mq->entry_count) {
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0362 Unsupported MQ count. (%d)\n",
+				mq->entry_count);
+		if (mq->entry_count < 16)
+			return -EINVAL;
+		/* otherwise default to smallest count (drop through) */
+	case 16:
+		bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+		       LPFC_MQ_CNT_16);
+		break;
+	case 32:
+		bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+		       LPFC_MQ_CNT_32);
+		break;
+	case 64:
+		bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+		       LPFC_MQ_CNT_64);
+		break;
+	case 128:
+		bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+		       LPFC_MQ_CNT_128);
+		break;
+	}
+	list_for_each_entry(dmabuf, &mq->page_list, list) {
+		mq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+					putPaddrLow(dmabuf->phys);
+		mq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+					putPaddrHigh(dmabuf->phys);
+	}
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+	/* The IOCTL status is embedded in the mailbox subheader. */
+	shdr = (union lpfc_sli4_cfg_shdr *) &mq_create->header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2502 MQ_CREATE mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		status = -ENXIO;
+		goto out;
+	}
+	mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id, &mq_create->u.response);
+	if (mq->queue_id == 0xFFFF) {
+		status = -ENXIO;
+		goto out;
+	}
+	mq->type = LPFC_MQ;
+	mq->subtype = subtype;
+	mq->host_index = 0;
+	mq->hba_index = 0;
+
+	/* link the mq onto the parent cq child list */
+	list_add_tail(&mq->list, &cq->child_list);
+out:
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mbox, phba->mbox_mem_pool);
+	return status;
+}
+
+/**
+ * lpfc_wq_create - Create a Work Queue on the HBA
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @wq: The queue structure to use to create the work queue.
+ * @cq: The completion queue to bind this work queue to.
+ * @subtype: The subtype of the work queue indicating its functionality.
+ *
+ * This function creates a work queue, as detailed in @wq, on a port, described
+ * by @phba by sending a WQ_CREATE mailbox command to the HBA.
+ *
+ * The @phba struct is used to send mailbox command to HBA. The @wq struct
+ * is used to get the entry count and entry size that are necessary to
+ * determine the number of pages to allocate and use for this queue. The @cq
+ * is used to indicate which completion queue to bind this work queue to. This
+ * function will send the WQ_CREATE mailbox command to the HBA to setup the
+ * work queue. This function is asynchronous and will wait for the mailbox
+ * command to finish before continuing.
+ *
+ * On success this function will return a zero. If unable to allocate enough
+ * memory this function will return ENOMEM. If the queue create mailbox command
+ * fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
+	       struct lpfc_queue *cq, uint32_t subtype)
+{
+	struct lpfc_mbx_wq_create *wq_create;
+	struct lpfc_dmabuf *dmabuf;
+	LPFC_MBOXQ_t *mbox;
+	int rc, length, status = 0;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+	length = (sizeof(struct lpfc_mbx_wq_create) -
+		  sizeof(struct lpfc_sli4_cfg_mhdr));
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+			 LPFC_MBOX_OPCODE_FCOE_WQ_CREATE,
+			 length, LPFC_SLI4_MBX_EMBED);
+	wq_create = &mbox->u.mqe.un.wq_create;
+	bf_set(lpfc_mbx_wq_create_num_pages, &wq_create->u.request,
+		    wq->page_count);
+	bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request,
+		    cq->queue_id);
+	list_for_each_entry(dmabuf, &wq->page_list, list) {
+		wq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+					putPaddrLow(dmabuf->phys);
+		wq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+					putPaddrHigh(dmabuf->phys);
+	}
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+	/* The IOCTL status is embedded in the mailbox subheader. */
+	shdr = (union lpfc_sli4_cfg_shdr *) &wq_create->header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2503 WQ_CREATE mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		status = -ENXIO;
+		goto out;
+	}
+	wq->queue_id = bf_get(lpfc_mbx_wq_create_q_id, &wq_create->u.response);
+	if (wq->queue_id == 0xFFFF) {
+		status = -ENXIO;
+		goto out;
+	}
+	wq->type = LPFC_WQ;
+	wq->subtype = subtype;
+	wq->host_index = 0;
+	wq->hba_index = 0;
+
+	/* link the wq onto the parent cq child list */
+	list_add_tail(&wq->list, &cq->child_list);
+out:
+	if (rc == MBX_TIMEOUT)
+		mempool_free(mbox, phba->mbox_mem_pool);
+	return status;
+}
+
+/**
+ * lpfc_rq_create - Create a Receive Queue on the HBA
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @hrq: The queue structure to use to create the header receive queue.
+ * @drq: The queue structure to use to create the data receive queue.
+ * @cq: The completion queue to bind this work queue to.
+ *
+ * This function creates a receive buffer queue pair , as detailed in @hrq and
+ * @drq, on a port, described by @phba by sending a RQ_CREATE mailbox command
+ * to the HBA.
+ *
+ * The @phba struct is used to send mailbox command to HBA. The @drq and @hrq
+ * struct is used to get the entry count that is necessary to determine the
+ * number of pages to use for this queue. The @cq is used to indicate which
+ * completion queue to bind received buffers that are posted to these queues to.
+ * This function will send the RQ_CREATE mailbox command to the HBA to setup the
+ * receive queue pair. This function is asynchronous and will wait for the
+ * mailbox command to finish before continuing.
+ *
+ * On success this function will return a zero. If unable to allocate enough
+ * memory this function will return ENOMEM. If the queue create mailbox command
+ * fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
+	       struct lpfc_queue *drq, struct lpfc_queue *cq, uint32_t subtype)
+{
+	struct lpfc_mbx_rq_create *rq_create;
+	struct lpfc_dmabuf *dmabuf;
+	LPFC_MBOXQ_t *mbox;
+	int rc, length, status = 0;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	if (hrq->entry_count != drq->entry_count)
+		return -EINVAL;
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+	length = (sizeof(struct lpfc_mbx_rq_create) -
+		  sizeof(struct lpfc_sli4_cfg_mhdr));
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+			 LPFC_MBOX_OPCODE_FCOE_RQ_CREATE,
+			 length, LPFC_SLI4_MBX_EMBED);
+	rq_create = &mbox->u.mqe.un.rq_create;
+	switch (hrq->entry_count) {
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2535 Unsupported RQ count. (%d)\n",
+				hrq->entry_count);
+		if (hrq->entry_count < 512)
+			return -EINVAL;
+		/* otherwise default to smallest count (drop through) */
+	case 512:
+		bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+		       LPFC_RQ_RING_SIZE_512);
+		break;
+	case 1024:
+		bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+		       LPFC_RQ_RING_SIZE_1024);
+		break;
+	case 2048:
+		bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+		       LPFC_RQ_RING_SIZE_2048);
+		break;
+	case 4096:
+		bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+		       LPFC_RQ_RING_SIZE_4096);
+		break;
+	}
+	bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context,
+	       cq->queue_id);
+	bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request,
+	       hrq->page_count);
+	bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context,
+	       LPFC_HDR_BUF_SIZE);
+	list_for_each_entry(dmabuf, &hrq->page_list, list) {
+		rq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+					putPaddrLow(dmabuf->phys);
+		rq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+					putPaddrHigh(dmabuf->phys);
+	}
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+	/* The IOCTL status is embedded in the mailbox subheader. */
+	shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2504 RQ_CREATE mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		status = -ENXIO;
+		goto out;
+	}
+	hrq->queue_id = bf_get(lpfc_mbx_rq_create_q_id, &rq_create->u.response);
+	if (hrq->queue_id == 0xFFFF) {
+		status = -ENXIO;
+		goto out;
+	}
+	hrq->type = LPFC_HRQ;
+	hrq->subtype = subtype;
+	hrq->host_index = 0;
+	hrq->hba_index = 0;
+
+	/* now create the data queue */
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+			 LPFC_MBOX_OPCODE_FCOE_RQ_CREATE,
+			 length, LPFC_SLI4_MBX_EMBED);
+	switch (drq->entry_count) {
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2536 Unsupported RQ count. (%d)\n",
+				drq->entry_count);
+		if (drq->entry_count < 512)
+			return -EINVAL;
+		/* otherwise default to smallest count (drop through) */
+	case 512:
+		bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+		       LPFC_RQ_RING_SIZE_512);
+		break;
+	case 1024:
+		bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+		       LPFC_RQ_RING_SIZE_1024);
+		break;
+	case 2048:
+		bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+		       LPFC_RQ_RING_SIZE_2048);
+		break;
+	case 4096:
+		bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+		       LPFC_RQ_RING_SIZE_4096);
+		break;
+	}
+	bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context,
+	       cq->queue_id);
+	bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request,
+	       drq->page_count);
+	bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context,
+	       LPFC_DATA_BUF_SIZE);
+	list_for_each_entry(dmabuf, &drq->page_list, list) {
+		rq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+					putPaddrLow(dmabuf->phys);
+		rq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+					putPaddrHigh(dmabuf->phys);
+	}
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+	/* The IOCTL status is embedded in the mailbox subheader. */
+	shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (shdr_status || shdr_add_status || rc) {
+		status = -ENXIO;
+		goto out;
+	}
+	drq->queue_id = bf_get(lpfc_mbx_rq_create_q_id, &rq_create->u.response);
+	if (drq->queue_id == 0xFFFF) {
+		status = -ENXIO;
+		goto out;
+	}
+	drq->type = LPFC_DRQ;
+	drq->subtype = subtype;
+	drq->host_index = 0;
+	drq->hba_index = 0;
+
+	/* link the header and data RQs onto the parent cq child list */
+	list_add_tail(&hrq->list, &cq->child_list);
+	list_add_tail(&drq->list, &cq->child_list);
+
+out:
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mbox, phba->mbox_mem_pool);
+	return status;
+}
+
+/**
+ * lpfc_eq_destroy - Destroy an event Queue on the HBA
+ * @eq: The queue structure associated with the queue to destroy.
+ *
+ * This function destroys a queue, as detailed in @eq by sending an mailbox
+ * command, specific to the type of queue, to the HBA.
+ *
+ * The @eq struct is used to get the queue ID of the queue to destroy.
+ *
+ * On success this function will return a zero. If the queue destroy mailbox
+ * command fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq)
+{
+	LPFC_MBOXQ_t *mbox;
+	int rc, length, status = 0;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	if (!eq)
+		return -ENODEV;
+	mbox = mempool_alloc(eq->phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+	length = (sizeof(struct lpfc_mbx_eq_destroy) -
+		  sizeof(struct lpfc_sli4_cfg_mhdr));
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+			 LPFC_MBOX_OPCODE_EQ_DESTROY,
+			 length, LPFC_SLI4_MBX_EMBED);
+	bf_set(lpfc_mbx_eq_destroy_q_id, &mbox->u.mqe.un.eq_destroy.u.request,
+	       eq->queue_id);
+	mbox->vport = eq->phba->pport;
+	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+
+	rc = lpfc_sli_issue_mbox(eq->phba, mbox, MBX_POLL);
+	/* The IOCTL status is embedded in the mailbox subheader. */
+	shdr = (union lpfc_sli4_cfg_shdr *)
+		&mbox->u.mqe.un.eq_destroy.header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2505 EQ_DESTROY mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		status = -ENXIO;
+	}
+
+	/* Remove eq from any list */
+	list_del_init(&eq->list);
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mbox, eq->phba->mbox_mem_pool);
+	return status;
+}
+
+/**
+ * lpfc_cq_destroy - Destroy a Completion Queue on the HBA
+ * @cq: The queue structure associated with the queue to destroy.
+ *
+ * This function destroys a queue, as detailed in @cq by sending an mailbox
+ * command, specific to the type of queue, to the HBA.
+ *
+ * The @cq struct is used to get the queue ID of the queue to destroy.
+ *
+ * On success this function will return a zero. If the queue destroy mailbox
+ * command fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq)
+{
+	LPFC_MBOXQ_t *mbox;
+	int rc, length, status = 0;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	if (!cq)
+		return -ENODEV;
+	mbox = mempool_alloc(cq->phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+	length = (sizeof(struct lpfc_mbx_cq_destroy) -
+		  sizeof(struct lpfc_sli4_cfg_mhdr));
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+			 LPFC_MBOX_OPCODE_CQ_DESTROY,
+			 length, LPFC_SLI4_MBX_EMBED);
+	bf_set(lpfc_mbx_cq_destroy_q_id, &mbox->u.mqe.un.cq_destroy.u.request,
+	       cq->queue_id);
+	mbox->vport = cq->phba->pport;
+	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+	rc = lpfc_sli_issue_mbox(cq->phba, mbox, MBX_POLL);
+	/* The IOCTL status is embedded in the mailbox subheader. */
+	shdr = (union lpfc_sli4_cfg_shdr *)
+		&mbox->u.mqe.un.wq_create.header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2506 CQ_DESTROY mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		status = -ENXIO;
+	}
+	/* Remove cq from any list */
+	list_del_init(&cq->list);
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mbox, cq->phba->mbox_mem_pool);
+	return status;
+}
+
+/**
+ * lpfc_mq_destroy - Destroy a Mailbox Queue on the HBA
+ * @qm: The queue structure associated with the queue to destroy.
+ *
+ * This function destroys a queue, as detailed in @mq by sending an mailbox
+ * command, specific to the type of queue, to the HBA.
+ *
+ * The @mq struct is used to get the queue ID of the queue to destroy.
+ *
+ * On success this function will return a zero. If the queue destroy mailbox
+ * command fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq)
+{
+	LPFC_MBOXQ_t *mbox;
+	int rc, length, status = 0;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	if (!mq)
+		return -ENODEV;
+	mbox = mempool_alloc(mq->phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+	length = (sizeof(struct lpfc_mbx_mq_destroy) -
+		  sizeof(struct lpfc_sli4_cfg_mhdr));
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+			 LPFC_MBOX_OPCODE_MQ_DESTROY,
+			 length, LPFC_SLI4_MBX_EMBED);
+	bf_set(lpfc_mbx_mq_destroy_q_id, &mbox->u.mqe.un.mq_destroy.u.request,
+	       mq->queue_id);
+	mbox->vport = mq->phba->pport;
+	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+	rc = lpfc_sli_issue_mbox(mq->phba, mbox, MBX_POLL);
+	/* The IOCTL status is embedded in the mailbox subheader. */
+	shdr = (union lpfc_sli4_cfg_shdr *)
+		&mbox->u.mqe.un.mq_destroy.header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2507 MQ_DESTROY mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		status = -ENXIO;
+	}
+	/* Remove mq from any list */
+	list_del_init(&mq->list);
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mbox, mq->phba->mbox_mem_pool);
+	return status;
+}
+
+/**
+ * lpfc_wq_destroy - Destroy a Work Queue on the HBA
+ * @wq: The queue structure associated with the queue to destroy.
+ *
+ * This function destroys a queue, as detailed in @wq by sending an mailbox
+ * command, specific to the type of queue, to the HBA.
+ *
+ * The @wq struct is used to get the queue ID of the queue to destroy.
+ *
+ * On success this function will return a zero. If the queue destroy mailbox
+ * command fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq)
+{
+	LPFC_MBOXQ_t *mbox;
+	int rc, length, status = 0;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	if (!wq)
+		return -ENODEV;
+	mbox = mempool_alloc(wq->phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+	length = (sizeof(struct lpfc_mbx_wq_destroy) -
+		  sizeof(struct lpfc_sli4_cfg_mhdr));
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+			 LPFC_MBOX_OPCODE_FCOE_WQ_DESTROY,
+			 length, LPFC_SLI4_MBX_EMBED);
+	bf_set(lpfc_mbx_wq_destroy_q_id, &mbox->u.mqe.un.wq_destroy.u.request,
+	       wq->queue_id);
+	mbox->vport = wq->phba->pport;
+	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+	rc = lpfc_sli_issue_mbox(wq->phba, mbox, MBX_POLL);
+	shdr = (union lpfc_sli4_cfg_shdr *)
+		&mbox->u.mqe.un.wq_destroy.header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2508 WQ_DESTROY mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		status = -ENXIO;
+	}
+	/* Remove wq from any list */
+	list_del_init(&wq->list);
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mbox, wq->phba->mbox_mem_pool);
+	return status;
+}
+
+/**
+ * lpfc_rq_destroy - Destroy a Receive Queue on the HBA
+ * @rq: The queue structure associated with the queue to destroy.
+ *
+ * This function destroys a queue, as detailed in @rq by sending an mailbox
+ * command, specific to the type of queue, to the HBA.
+ *
+ * The @rq struct is used to get the queue ID of the queue to destroy.
+ *
+ * On success this function will return a zero. If the queue destroy mailbox
+ * command fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq,
+		struct lpfc_queue *drq)
+{
+	LPFC_MBOXQ_t *mbox;
+	int rc, length, status = 0;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	if (!hrq || !drq)
+		return -ENODEV;
+	mbox = mempool_alloc(hrq->phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+	length = (sizeof(struct lpfc_mbx_rq_destroy) -
+		  sizeof(struct mbox_header));
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+			 LPFC_MBOX_OPCODE_FCOE_RQ_DESTROY,
+			 length, LPFC_SLI4_MBX_EMBED);
+	bf_set(lpfc_mbx_rq_destroy_q_id, &mbox->u.mqe.un.rq_destroy.u.request,
+	       hrq->queue_id);
+	mbox->vport = hrq->phba->pport;
+	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+	rc = lpfc_sli_issue_mbox(hrq->phba, mbox, MBX_POLL);
+	/* The IOCTL status is embedded in the mailbox subheader. */
+	shdr = (union lpfc_sli4_cfg_shdr *)
+		&mbox->u.mqe.un.rq_destroy.header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2509 RQ_DESTROY mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		if (rc != MBX_TIMEOUT)
+			mempool_free(mbox, hrq->phba->mbox_mem_pool);
+		return -ENXIO;
+	}
+	bf_set(lpfc_mbx_rq_destroy_q_id, &mbox->u.mqe.un.rq_destroy.u.request,
+	       drq->queue_id);
+	rc = lpfc_sli_issue_mbox(drq->phba, mbox, MBX_POLL);
+	shdr = (union lpfc_sli4_cfg_shdr *)
+		&mbox->u.mqe.un.rq_destroy.header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2510 RQ_DESTROY mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		status = -ENXIO;
+	}
+	list_del_init(&hrq->list);
+	list_del_init(&drq->list);
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mbox, hrq->phba->mbox_mem_pool);
+	return status;
+}
+
+/**
+ * lpfc_sli4_post_sgl - Post scatter gather list for an XRI to HBA
+ * @phba: The virtual port for which this call being executed.
+ * @pdma_phys_addr0: Physical address of the 1st SGL page.
+ * @pdma_phys_addr1: Physical address of the 2nd SGL page.
+ * @xritag: the xritag that ties this io to the SGL pages.
+ *
+ * This routine will post the sgl pages for the IO that has the xritag
+ * that is in the iocbq structure. The xritag is assigned during iocbq
+ * creation and persists for as long as the driver is loaded.
+ * if the caller has fewer than 256 scatter gather segments to map then
+ * pdma_phys_addr1 should be 0.
+ * If the caller needs to map more than 256 scatter gather segment then
+ * pdma_phys_addr1 should be a valid physical address.
+ * physical address for SGLs must be 64 byte aligned.
+ * If you are going to map 2 SGL's then the first one must have 256 entries
+ * the second sgl can have between 1 and 256 entries.
+ *
+ * Return codes:
+ * 	0 - Success
+ * 	-ENXIO, -ENOMEM - Failure
+ **/
+int
+lpfc_sli4_post_sgl(struct lpfc_hba *phba,
+		dma_addr_t pdma_phys_addr0,
+		dma_addr_t pdma_phys_addr1,
+		uint16_t xritag)
+{
+	struct lpfc_mbx_post_sgl_pages *post_sgl_pages;
+	LPFC_MBOXQ_t *mbox;
+	int rc;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	if (xritag == NO_XRI) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"0364 Invalid param:\n");
+		return -EINVAL;
+	}
+
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+			LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES,
+			sizeof(struct lpfc_mbx_post_sgl_pages) -
+			sizeof(struct mbox_header), LPFC_SLI4_MBX_EMBED);
+
+	post_sgl_pages = (struct lpfc_mbx_post_sgl_pages *)
+				&mbox->u.mqe.un.post_sgl_pages;
+	bf_set(lpfc_post_sgl_pages_xri, post_sgl_pages, xritag);
+	bf_set(lpfc_post_sgl_pages_xricnt, post_sgl_pages, 1);
+
+	post_sgl_pages->sgl_pg_pairs[0].sgl_pg0_addr_lo	=
+				cpu_to_le32(putPaddrLow(pdma_phys_addr0));
+	post_sgl_pages->sgl_pg_pairs[0].sgl_pg0_addr_hi =
+				cpu_to_le32(putPaddrHigh(pdma_phys_addr0));
+
+	post_sgl_pages->sgl_pg_pairs[0].sgl_pg1_addr_lo	=
+				cpu_to_le32(putPaddrLow(pdma_phys_addr1));
+	post_sgl_pages->sgl_pg_pairs[0].sgl_pg1_addr_hi =
+				cpu_to_le32(putPaddrHigh(pdma_phys_addr1));
+	if (!phba->sli4_hba.intr_enable)
+		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+	else
+		rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
+	/* The IOCTL status is embedded in the mailbox subheader. */
+	shdr = (union lpfc_sli4_cfg_shdr *) &post_sgl_pages->header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mbox, phba->mbox_mem_pool);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2511 POST_SGL mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		rc = -ENXIO;
+	}
+	return 0;
+}
+/**
+ * lpfc_sli4_remove_all_sgl_pages - Post scatter gather list for an XRI to HBA
+ * @phba: The virtual port for which this call being executed.
+ *
+ * This routine will remove all of the sgl pages registered with the hba.
+ *
+ * Return codes:
+ * 	0 - Success
+ * 	-ENXIO, -ENOMEM - Failure
+ **/
+int
+lpfc_sli4_remove_all_sgl_pages(struct lpfc_hba *phba)
+{
+	LPFC_MBOXQ_t *mbox;
+	int rc;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+			LPFC_MBOX_OPCODE_FCOE_REMOVE_SGL_PAGES, 0,
+			LPFC_SLI4_MBX_EMBED);
+	if (!phba->sli4_hba.intr_enable)
+		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+	else
+		rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
+	/* The IOCTL status is embedded in the mailbox subheader. */
+	shdr = (union lpfc_sli4_cfg_shdr *)
+		&mbox->u.mqe.un.sli4_config.header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mbox, phba->mbox_mem_pool);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2512 REMOVE_ALL_SGL_PAGES mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		rc = -ENXIO;
+	}
+	return rc;
+}
+
+/**
+ * lpfc_sli4_next_xritag - Get an xritag for the io
+ * @phba: Pointer to HBA context object.
+ *
+ * This function gets an xritag for the iocb. If there is no unused xritag
+ * it will return 0xffff.
+ * The function returns the allocated xritag if successful, else returns zero.
+ * Zero is not a valid xritag.
+ * The caller is not required to hold any lock.
+ **/
+uint16_t
+lpfc_sli4_next_xritag(struct lpfc_hba *phba)
+{
+	uint16_t xritag;
+
+	spin_lock_irq(&phba->hbalock);
+	xritag = phba->sli4_hba.next_xri;
+	if ((xritag != (uint16_t) -1) && xritag <
+		(phba->sli4_hba.max_cfg_param.max_xri
+			+ phba->sli4_hba.max_cfg_param.xri_base)) {
+		phba->sli4_hba.next_xri++;
+		phba->sli4_hba.max_cfg_param.xri_used++;
+		spin_unlock_irq(&phba->hbalock);
+		return xritag;
+	}
+	spin_unlock_irq(&phba->hbalock);
+
+	lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+			"2004 Failed to allocate XRI.last XRITAG is %d"
+			" Max XRI is %d, Used XRI is %d\n",
+			phba->sli4_hba.next_xri,
+			phba->sli4_hba.max_cfg_param.max_xri,
+			phba->sli4_hba.max_cfg_param.xri_used);
+	return -1;
+}
+
+/**
+ * lpfc_sli4_post_sgl_list - post a block of sgl list to the firmware.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to post a block of driver's sgl pages to the
+ * HBA using non-embedded mailbox command. No Lock is held. This routine
+ * is only called when the driver is loading and after all IO has been
+ * stopped.
+ **/
+int
+lpfc_sli4_post_sgl_list(struct lpfc_hba *phba)
+{
+	struct lpfc_sglq *sglq_entry;
+	struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
+	struct sgl_page_pairs *sgl_pg_pairs;
+	void *viraddr;
+	LPFC_MBOXQ_t *mbox;
+	uint32_t reqlen, alloclen, pg_pairs;
+	uint32_t mbox_tmo;
+	uint16_t xritag_start = 0;
+	int els_xri_cnt, rc = 0;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	/* The number of sgls to be posted */
+	els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
+
+	reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) +
+		 sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
+	if (reqlen > PAGE_SIZE) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"2559 Block sgl registration required DMA "
+				"size (%d) great than a page\n", reqlen);
+		return -ENOMEM;
+	}
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2560 Failed to allocate mbox cmd memory\n");
+		return -ENOMEM;
+	}
+
+	/* Allocate DMA memory and set up the non-embedded mailbox command */
+	alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+			 LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, reqlen,
+			 LPFC_SLI4_MBX_NEMBED);
+
+	if (alloclen < reqlen) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0285 Allocated DMA memory size (%d) is "
+				"less than the requested DMA memory "
+				"size (%d)\n", alloclen, reqlen);
+		lpfc_sli4_mbox_cmd_free(phba, mbox);
+		return -ENOMEM;
+	}
+
+	/* Get the first SGE entry from the non-embedded DMA memory */
+	if (unlikely(!mbox->sge_array)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+				"2525 Failed to get the non-embedded SGE "
+				"virtual address\n");
+		lpfc_sli4_mbox_cmd_free(phba, mbox);
+		return -ENOMEM;
+	}
+	viraddr = mbox->sge_array->addr[0];
+
+	/* Set up the SGL pages in the non-embedded DMA pages */
+	sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
+	sgl_pg_pairs = &sgl->sgl_pg_pairs;
+
+	for (pg_pairs = 0; pg_pairs < els_xri_cnt; pg_pairs++) {
+		sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[pg_pairs];
+		/* Set up the sge entry */
+		sgl_pg_pairs->sgl_pg0_addr_lo =
+				cpu_to_le32(putPaddrLow(sglq_entry->phys));
+		sgl_pg_pairs->sgl_pg0_addr_hi =
+				cpu_to_le32(putPaddrHigh(sglq_entry->phys));
+		sgl_pg_pairs->sgl_pg1_addr_lo =
+				cpu_to_le32(putPaddrLow(0));
+		sgl_pg_pairs->sgl_pg1_addr_hi =
+				cpu_to_le32(putPaddrHigh(0));
+		/* Keep the first xritag on the list */
+		if (pg_pairs == 0)
+			xritag_start = sglq_entry->sli4_xritag;
+		sgl_pg_pairs++;
+	}
+	bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start);
+	pg_pairs = (pg_pairs > 0) ? (pg_pairs - 1) : pg_pairs;
+	bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs);
+	/* Perform endian conversion if necessary */
+	sgl->word0 = cpu_to_le32(sgl->word0);
+
+	if (!phba->sli4_hba.intr_enable)
+		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+	else {
+		mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+		rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+	}
+	shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (rc != MBX_TIMEOUT)
+		lpfc_sli4_mbox_cmd_free(phba, mbox);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2513 POST_SGL_BLOCK mailbox command failed "
+				"status x%x add_status x%x mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		rc = -ENXIO;
+	}
+	return rc;
+}
+
+/**
+ * lpfc_sli4_post_scsi_sgl_block - post a block of scsi sgl list to firmware
+ * @phba: pointer to lpfc hba data structure.
+ * @sblist: pointer to scsi buffer list.
+ * @count: number of scsi buffers on the list.
+ *
+ * This routine is invoked to post a block of @count scsi sgl pages from a
+ * SCSI buffer list @sblist to the HBA using non-embedded mailbox command.
+ * No Lock is held.
+ *
+ **/
+int
+lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
+			      int cnt)
+{
+	struct lpfc_scsi_buf *psb;
+	struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
+	struct sgl_page_pairs *sgl_pg_pairs;
+	void *viraddr;
+	LPFC_MBOXQ_t *mbox;
+	uint32_t reqlen, alloclen, pg_pairs;
+	uint32_t mbox_tmo;
+	uint16_t xritag_start = 0;
+	int rc = 0;
+	uint32_t shdr_status, shdr_add_status;
+	dma_addr_t pdma_phys_bpl1;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	/* Calculate the requested length of the dma memory */
+	reqlen = cnt * sizeof(struct sgl_page_pairs) +
+		 sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
+	if (reqlen > PAGE_SIZE) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"0217 Block sgl registration required DMA "
+				"size (%d) great than a page\n", reqlen);
+		return -ENOMEM;
+	}
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0283 Failed to allocate mbox cmd memory\n");
+		return -ENOMEM;
+	}
+
+	/* Allocate DMA memory and set up the non-embedded mailbox command */
+	alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+				LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, reqlen,
+				LPFC_SLI4_MBX_NEMBED);
+
+	if (alloclen < reqlen) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2561 Allocated DMA memory size (%d) is "
+				"less than the requested DMA memory "
+				"size (%d)\n", alloclen, reqlen);
+		lpfc_sli4_mbox_cmd_free(phba, mbox);
+		return -ENOMEM;
+	}
+
+	/* Get the first SGE entry from the non-embedded DMA memory */
+	if (unlikely(!mbox->sge_array)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+				"2565 Failed to get the non-embedded SGE "
+				"virtual address\n");
+		lpfc_sli4_mbox_cmd_free(phba, mbox);
+		return -ENOMEM;
+	}
+	viraddr = mbox->sge_array->addr[0];
+
+	/* Set up the SGL pages in the non-embedded DMA pages */
+	sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
+	sgl_pg_pairs = &sgl->sgl_pg_pairs;
+
+	pg_pairs = 0;
+	list_for_each_entry(psb, sblist, list) {
+		/* Set up the sge entry */
+		sgl_pg_pairs->sgl_pg0_addr_lo =
+			cpu_to_le32(putPaddrLow(psb->dma_phys_bpl));
+		sgl_pg_pairs->sgl_pg0_addr_hi =
+			cpu_to_le32(putPaddrHigh(psb->dma_phys_bpl));
+		if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE)
+			pdma_phys_bpl1 = psb->dma_phys_bpl + SGL_PAGE_SIZE;
+		else
+			pdma_phys_bpl1 = 0;
+		sgl_pg_pairs->sgl_pg1_addr_lo =
+			cpu_to_le32(putPaddrLow(pdma_phys_bpl1));
+		sgl_pg_pairs->sgl_pg1_addr_hi =
+			cpu_to_le32(putPaddrHigh(pdma_phys_bpl1));
+		/* Keep the first xritag on the list */
+		if (pg_pairs == 0)
+			xritag_start = psb->cur_iocbq.sli4_xritag;
+		sgl_pg_pairs++;
+		pg_pairs++;
+	}
+	bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start);
+	bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs);
+	/* Perform endian conversion if necessary */
+	sgl->word0 = cpu_to_le32(sgl->word0);
+
+	if (!phba->sli4_hba.intr_enable)
+		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+	else {
+		mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+		rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+	}
+	shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (rc != MBX_TIMEOUT)
+		lpfc_sli4_mbox_cmd_free(phba, mbox);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2564 POST_SGL_BLOCK mailbox command failed "
+				"status x%x add_status x%x mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		rc = -ENXIO;
+	}
+	return rc;
+}
+
+/**
+ * lpfc_fc_frame_check - Check that this frame is a valid frame to handle
+ * @phba: pointer to lpfc_hba struct that the frame was received on
+ * @fc_hdr: A pointer to the FC Header data (In Big Endian Format)
+ *
+ * This function checks the fields in the @fc_hdr to see if the FC frame is a
+ * valid type of frame that the LPFC driver will handle. This function will
+ * return a zero if the frame is a valid frame or a non zero value when the
+ * frame does not pass the check.
+ **/
+static int
+lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr)
+{
+	char *rctl_names[] = FC_RCTL_NAMES_INIT;
+	char *type_names[] = FC_TYPE_NAMES_INIT;
+	struct fc_vft_header *fc_vft_hdr;
+
+	switch (fc_hdr->fh_r_ctl) {
+	case FC_RCTL_DD_UNCAT:		/* uncategorized information */
+	case FC_RCTL_DD_SOL_DATA:	/* solicited data */
+	case FC_RCTL_DD_UNSOL_CTL:	/* unsolicited control */
+	case FC_RCTL_DD_SOL_CTL:	/* solicited control or reply */
+	case FC_RCTL_DD_UNSOL_DATA:	/* unsolicited data */
+	case FC_RCTL_DD_DATA_DESC:	/* data descriptor */
+	case FC_RCTL_DD_UNSOL_CMD:	/* unsolicited command */
+	case FC_RCTL_DD_CMD_STATUS:	/* command status */
+	case FC_RCTL_ELS_REQ:	/* extended link services request */
+	case FC_RCTL_ELS_REP:	/* extended link services reply */
+	case FC_RCTL_ELS4_REQ:	/* FC-4 ELS request */
+	case FC_RCTL_ELS4_REP:	/* FC-4 ELS reply */
+	case FC_RCTL_BA_NOP:  	/* basic link service NOP */
+	case FC_RCTL_BA_ABTS: 	/* basic link service abort */
+	case FC_RCTL_BA_RMC: 	/* remove connection */
+	case FC_RCTL_BA_ACC:	/* basic accept */
+	case FC_RCTL_BA_RJT:	/* basic reject */
+	case FC_RCTL_BA_PRMT:
+	case FC_RCTL_ACK_1:	/* acknowledge_1 */
+	case FC_RCTL_ACK_0:	/* acknowledge_0 */
+	case FC_RCTL_P_RJT:	/* port reject */
+	case FC_RCTL_F_RJT:	/* fabric reject */
+	case FC_RCTL_P_BSY:	/* port busy */
+	case FC_RCTL_F_BSY:	/* fabric busy to data frame */
+	case FC_RCTL_F_BSYL:	/* fabric busy to link control frame */
+	case FC_RCTL_LCR:	/* link credit reset */
+	case FC_RCTL_END:	/* end */
+		break;
+	case FC_RCTL_VFTH:	/* Virtual Fabric tagging Header */
+		fc_vft_hdr = (struct fc_vft_header *)fc_hdr;
+		fc_hdr = &((struct fc_frame_header *)fc_vft_hdr)[1];
+		return lpfc_fc_frame_check(phba, fc_hdr);
+	default:
+		goto drop;
+	}
+	switch (fc_hdr->fh_type) {
+	case FC_TYPE_BLS:
+	case FC_TYPE_ELS:
+	case FC_TYPE_FCP:
+	case FC_TYPE_CT:
+		break;
+	case FC_TYPE_IP:
+	case FC_TYPE_ILS:
+	default:
+		goto drop;
+	}
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"2538 Received frame rctl:%s type:%s\n",
+			rctl_names[fc_hdr->fh_r_ctl],
+			type_names[fc_hdr->fh_type]);
+	return 0;
+drop:
+	lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
+			"2539 Dropped frame rctl:%s type:%s\n",
+			rctl_names[fc_hdr->fh_r_ctl],
+			type_names[fc_hdr->fh_type]);
+	return 1;
+}
+
+/**
+ * lpfc_fc_hdr_get_vfi - Get the VFI from an FC frame
+ * @fc_hdr: A pointer to the FC Header data (In Big Endian Format)
+ *
+ * This function processes the FC header to retrieve the VFI from the VF
+ * header, if one exists. This function will return the VFI if one exists
+ * or 0 if no VSAN Header exists.
+ **/
+static uint32_t
+lpfc_fc_hdr_get_vfi(struct fc_frame_header *fc_hdr)
+{
+	struct fc_vft_header *fc_vft_hdr = (struct fc_vft_header *)fc_hdr;
+
+	if (fc_hdr->fh_r_ctl != FC_RCTL_VFTH)
+		return 0;
+	return bf_get(fc_vft_hdr_vf_id, fc_vft_hdr);
+}
+
+/**
+ * lpfc_fc_frame_to_vport - Finds the vport that a frame is destined to
+ * @phba: Pointer to the HBA structure to search for the vport on
+ * @fc_hdr: A pointer to the FC Header data (In Big Endian Format)
+ * @fcfi: The FC Fabric ID that the frame came from
+ *
+ * This function searches the @phba for a vport that matches the content of the
+ * @fc_hdr passed in and the @fcfi. This function uses the @fc_hdr to fetch the
+ * VFI, if the Virtual Fabric Tagging Header exists, and the DID. This function
+ * returns the matching vport pointer or NULL if unable to match frame to a
+ * vport.
+ **/
+static struct lpfc_vport *
+lpfc_fc_frame_to_vport(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr,
+		       uint16_t fcfi)
+{
+	struct lpfc_vport **vports;
+	struct lpfc_vport *vport = NULL;
+	int i;
+	uint32_t did = (fc_hdr->fh_d_id[0] << 16 |
+			fc_hdr->fh_d_id[1] << 8 |
+			fc_hdr->fh_d_id[2]);
+
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL)
+		for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+			if (phba->fcf.fcfi == fcfi &&
+			    vports[i]->vfi == lpfc_fc_hdr_get_vfi(fc_hdr) &&
+			    vports[i]->fc_myDID == did) {
+				vport = vports[i];
+				break;
+			}
+		}
+	lpfc_destroy_vport_work_array(phba, vports);
+	return vport;
+}
+
+/**
+ * lpfc_fc_frame_add - Adds a frame to the vport's list of received sequences
+ * @dmabuf: pointer to a dmabuf that describes the hdr and data of the FC frame
+ *
+ * This function searches through the existing incomplete sequences that have
+ * been sent to this @vport. If the frame matches one of the incomplete
+ * sequences then the dbuf in the @dmabuf is added to the list of frames that
+ * make up that sequence. If no sequence is found that matches this frame then
+ * the function will add the hbuf in the @dmabuf to the @vport's rcv_buffer_list
+ * This function returns a pointer to the first dmabuf in the sequence list that
+ * the frame was linked to.
+ **/
+static struct hbq_dmabuf *
+lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
+{
+	struct fc_frame_header *new_hdr;
+	struct fc_frame_header *temp_hdr;
+	struct lpfc_dmabuf *d_buf;
+	struct lpfc_dmabuf *h_buf;
+	struct hbq_dmabuf *seq_dmabuf = NULL;
+	struct hbq_dmabuf *temp_dmabuf = NULL;
+
+	new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
+	/* Use the hdr_buf to find the sequence that this frame belongs to */
+	list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) {
+		temp_hdr = (struct fc_frame_header *)h_buf->virt;
+		if ((temp_hdr->fh_seq_id != new_hdr->fh_seq_id) ||
+		    (temp_hdr->fh_ox_id != new_hdr->fh_ox_id) ||
+		    (memcmp(&temp_hdr->fh_s_id, &new_hdr->fh_s_id, 3)))
+			continue;
+		/* found a pending sequence that matches this frame */
+		seq_dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf);
+		break;
+	}
+	if (!seq_dmabuf) {
+		/*
+		 * This indicates first frame received for this sequence.
+		 * Queue the buffer on the vport's rcv_buffer_list.
+		 */
+		list_add_tail(&dmabuf->hbuf.list, &vport->rcv_buffer_list);
+		return dmabuf;
+	}
+	temp_hdr = seq_dmabuf->hbuf.virt;
+	if (new_hdr->fh_seq_cnt < temp_hdr->fh_seq_cnt) {
+		list_add(&seq_dmabuf->dbuf.list, &dmabuf->dbuf.list);
+		return dmabuf;
+	}
+	/* find the correct place in the sequence to insert this frame */
+	list_for_each_entry_reverse(d_buf, &seq_dmabuf->dbuf.list, list) {
+		temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+		temp_hdr = (struct fc_frame_header *)temp_dmabuf->hbuf.virt;
+		/*
+		 * If the frame's sequence count is greater than the frame on
+		 * the list then insert the frame right after this frame
+		 */
+		if (new_hdr->fh_seq_cnt > temp_hdr->fh_seq_cnt) {
+			list_add(&dmabuf->dbuf.list, &temp_dmabuf->dbuf.list);
+			return seq_dmabuf;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * lpfc_seq_complete - Indicates if a sequence is complete
+ * @dmabuf: pointer to a dmabuf that describes the FC sequence
+ *
+ * This function checks the sequence, starting with the frame described by
+ * @dmabuf, to see if all the frames associated with this sequence are present.
+ * the frames associated with this sequence are linked to the @dmabuf using the
+ * dbuf list. This function looks for two major things. 1) That the first frame
+ * has a sequence count of zero. 2) There is a frame with last frame of sequence
+ * set. 3) That there are no holes in the sequence count. The function will
+ * return 1 when the sequence is complete, otherwise it will return 0.
+ **/
+static int
+lpfc_seq_complete(struct hbq_dmabuf *dmabuf)
+{
+	struct fc_frame_header *hdr;
+	struct lpfc_dmabuf *d_buf;
+	struct hbq_dmabuf *seq_dmabuf;
+	uint32_t fctl;
+	int seq_count = 0;
+
+	hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
+	/* make sure first fame of sequence has a sequence count of zero */
+	if (hdr->fh_seq_cnt != seq_count)
+		return 0;
+	fctl = (hdr->fh_f_ctl[0] << 16 |
+		hdr->fh_f_ctl[1] << 8 |
+		hdr->fh_f_ctl[2]);
+	/* If last frame of sequence we can return success. */
+	if (fctl & FC_FC_END_SEQ)
+		return 1;
+	list_for_each_entry(d_buf, &dmabuf->dbuf.list, list) {
+		seq_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+		hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
+		/* If there is a hole in the sequence count then fail. */
+		if (++seq_count != hdr->fh_seq_cnt)
+			return 0;
+		fctl = (hdr->fh_f_ctl[0] << 16 |
+			hdr->fh_f_ctl[1] << 8 |
+			hdr->fh_f_ctl[2]);
+		/* If last frame of sequence we can return success. */
+		if (fctl & FC_FC_END_SEQ)
+			return 1;
+	}
+	return 0;
+}
+
+/**
+ * lpfc_prep_seq - Prep sequence for ULP processing
+ * @vport: Pointer to the vport on which this sequence was received
+ * @dmabuf: pointer to a dmabuf that describes the FC sequence
+ *
+ * This function takes a sequence, described by a list of frames, and creates
+ * a list of iocbq structures to describe the sequence. This iocbq list will be
+ * used to issue to the generic unsolicited sequence handler. This routine
+ * returns a pointer to the first iocbq in the list. If the function is unable
+ * to allocate an iocbq then it throw out the received frames that were not
+ * able to be described and return a pointer to the first iocbq. If unable to
+ * allocate any iocbqs (including the first) this function will return NULL.
+ **/
+static struct lpfc_iocbq *
+lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
+{
+	struct lpfc_dmabuf *d_buf, *n_buf;
+	struct lpfc_iocbq *first_iocbq, *iocbq;
+	struct fc_frame_header *fc_hdr;
+	uint32_t sid;
+
+	fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
+	/* remove from receive buffer list */
+	list_del_init(&seq_dmabuf->hbuf.list);
+	/* get the Remote Port's SID */
+	sid = (fc_hdr->fh_s_id[0] << 16 |
+	       fc_hdr->fh_s_id[1] << 8 |
+	       fc_hdr->fh_s_id[2]);
+	/* Get an iocbq struct to fill in. */
+	first_iocbq = lpfc_sli_get_iocbq(vport->phba);
+	if (first_iocbq) {
+		/* Initialize the first IOCB. */
+		first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS;
+		first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX;
+		first_iocbq->iocb.ulpContext = be16_to_cpu(fc_hdr->fh_ox_id);
+		first_iocbq->iocb.unsli3.rcvsli3.vpi =
+					vport->vpi + vport->phba->vpi_base;
+		/* put the first buffer into the first IOCBq */
+		first_iocbq->context2 = &seq_dmabuf->dbuf;
+		first_iocbq->context3 = NULL;
+		first_iocbq->iocb.ulpBdeCount = 1;
+		first_iocbq->iocb.un.cont64[0].tus.f.bdeSize =
+							LPFC_DATA_BUF_SIZE;
+		first_iocbq->iocb.un.rcvels.remoteID = sid;
+	}
+	iocbq = first_iocbq;
+	/*
+	 * Each IOCBq can have two Buffers assigned, so go through the list
+	 * of buffers for this sequence and save two buffers in each IOCBq
+	 */
+	list_for_each_entry_safe(d_buf, n_buf, &seq_dmabuf->dbuf.list, list) {
+		if (!iocbq) {
+			lpfc_in_buf_free(vport->phba, d_buf);
+			continue;
+		}
+		if (!iocbq->context3) {
+			iocbq->context3 = d_buf;
+			iocbq->iocb.ulpBdeCount++;
+			iocbq->iocb.unsli3.rcvsli3.bde2.tus.f.bdeSize =
+							LPFC_DATA_BUF_SIZE;
+		} else {
+			iocbq = lpfc_sli_get_iocbq(vport->phba);
+			if (!iocbq) {
+				if (first_iocbq) {
+					first_iocbq->iocb.ulpStatus =
+							IOSTAT_FCP_RSP_ERROR;
+					first_iocbq->iocb.un.ulpWord[4] =
+							IOERR_NO_RESOURCES;
+				}
+				lpfc_in_buf_free(vport->phba, d_buf);
+				continue;
+			}
+			iocbq->context2 = d_buf;
+			iocbq->context3 = NULL;
+			iocbq->iocb.ulpBdeCount = 1;
+			iocbq->iocb.un.cont64[0].tus.f.bdeSize =
+							LPFC_DATA_BUF_SIZE;
+			iocbq->iocb.un.rcvels.remoteID = sid;
+			list_add_tail(&iocbq->list, &first_iocbq->list);
+		}
+	}
+	return first_iocbq;
+}
+
+/**
+ * lpfc_sli4_handle_received_buffer - Handle received buffers from firmware
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called with no lock held. This function processes all
+ * the received buffers and gives it to upper layers when a received buffer
+ * indicates that it is the final frame in the sequence. The interrupt
+ * service routine processes received buffers at interrupt contexts and adds
+ * received dma buffers to the rb_pend_list queue and signals the worker thread.
+ * Worker thread calls lpfc_sli4_handle_received_buffer, which will call the
+ * appropriate receive function when the final frame in a sequence is received.
+ **/
+int
+lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba)
+{
+	LIST_HEAD(cmplq);
+	struct hbq_dmabuf *dmabuf, *seq_dmabuf;
+	struct fc_frame_header *fc_hdr;
+	struct lpfc_vport *vport;
+	uint32_t fcfi;
+	struct lpfc_iocbq *iocbq;
+
+	/* Clear hba flag and get all received buffers into the cmplq */
+	spin_lock_irq(&phba->hbalock);
+	phba->hba_flag &= ~HBA_RECEIVE_BUFFER;
+	list_splice_init(&phba->rb_pend_list, &cmplq);
+	spin_unlock_irq(&phba->hbalock);
+
+	/* Process each received buffer */
+	while ((dmabuf = lpfc_sli_hbqbuf_get(&cmplq)) != NULL) {
+		fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
+		/* check to see if this a valid type of frame */
+		if (lpfc_fc_frame_check(phba, fc_hdr)) {
+			lpfc_in_buf_free(phba, &dmabuf->dbuf);
+			continue;
+		}
+		fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->rcqe);
+		vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi);
+		if (!vport) {
+			/* throw out the frame */
+			lpfc_in_buf_free(phba, &dmabuf->dbuf);
+			continue;
+		}
+		/* Link this frame */
+		seq_dmabuf = lpfc_fc_frame_add(vport, dmabuf);
+		if (!seq_dmabuf) {
+			/* unable to add frame to vport - throw it out */
+			lpfc_in_buf_free(phba, &dmabuf->dbuf);
+			continue;
+		}
+		/* If not last frame in sequence continue processing frames. */
+		if (!lpfc_seq_complete(seq_dmabuf)) {
+			/*
+			 * When saving off frames post a new one and mark this
+			 * frame to be freed when it is finished.
+			 **/
+			lpfc_sli_hbqbuf_fill_hbqs(phba, LPFC_ELS_HBQ, 1);
+			dmabuf->tag = -1;
+			continue;
+		}
+		fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
+		iocbq = lpfc_prep_seq(vport, seq_dmabuf);
+		if (!lpfc_complete_unsol_iocb(phba,
+					      &phba->sli.ring[LPFC_ELS_RING],
+					      iocbq, fc_hdr->fh_r_ctl,
+					      fc_hdr->fh_type))
+			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+					"2540 Ring %d handler: unexpected Rctl "
+					"x%x Type x%x received\n",
+					LPFC_ELS_RING,
+					fc_hdr->fh_r_ctl, fc_hdr->fh_type);
+	};
+	return 0;
+}
+
+/**
+ * lpfc_sli4_post_all_rpi_hdrs - Post the rpi header memory region to the port
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to post rpi header templates to the
+ * HBA consistent with the SLI-4 interface spec.  This routine
+ * posts a PAGE_SIZE memory region to the port to hold up to
+ * PAGE_SIZE modulo 64 rpi context headers.
+ *
+ * This routine does not require any locks.  It's usage is expected
+ * to be driver load or reset recovery when the driver is
+ * sequential.
+ *
+ * Return codes
+ * 	0 - sucessful
+ *      EIO - The mailbox failed to complete successfully.
+ * 	When this error occurs, the driver is not guaranteed
+ *	to have any rpi regions posted to the device and
+ *	must either attempt to repost the regions or take a
+ *	fatal error.
+ **/
+int
+lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *phba)
+{
+	struct lpfc_rpi_hdr *rpi_page;
+	uint32_t rc = 0;
+
+	/* Post all rpi memory regions to the port. */
+	list_for_each_entry(rpi_page, &phba->sli4_hba.lpfc_rpi_hdr_list, list) {
+		rc = lpfc_sli4_post_rpi_hdr(phba, rpi_page);
+		if (rc != MBX_SUCCESS) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+					"2008 Error %d posting all rpi "
+					"headers\n", rc);
+			rc = -EIO;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+/**
+ * lpfc_sli4_post_rpi_hdr - Post an rpi header memory region to the port
+ * @phba: pointer to lpfc hba data structure.
+ * @rpi_page:  pointer to the rpi memory region.
+ *
+ * This routine is invoked to post a single rpi header to the
+ * HBA consistent with the SLI-4 interface spec.  This memory region
+ * maps up to 64 rpi context regions.
+ *
+ * Return codes
+ * 	0 - sucessful
+ * 	ENOMEM - No available memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+int
+lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page)
+{
+	LPFC_MBOXQ_t *mboxq;
+	struct lpfc_mbx_post_hdr_tmpl *hdr_tmpl;
+	uint32_t rc = 0;
+	uint32_t mbox_tmo;
+	uint32_t shdr_status, shdr_add_status;
+	union lpfc_sli4_cfg_shdr *shdr;
+
+	/* The port is notified of the header region via a mailbox command. */
+	mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mboxq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2001 Unable to allocate memory for issuing "
+				"SLI_CONFIG_SPECIAL mailbox command\n");
+		return -ENOMEM;
+	}
+
+	/* Post all rpi memory regions to the port. */
+	hdr_tmpl = &mboxq->u.mqe.un.hdr_tmpl;
+	mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+	lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
+			 LPFC_MBOX_OPCODE_FCOE_POST_HDR_TEMPLATE,
+			 sizeof(struct lpfc_mbx_post_hdr_tmpl) -
+			 sizeof(struct mbox_header), LPFC_SLI4_MBX_EMBED);
+	bf_set(lpfc_mbx_post_hdr_tmpl_page_cnt,
+	       hdr_tmpl, rpi_page->page_count);
+	bf_set(lpfc_mbx_post_hdr_tmpl_rpi_offset, hdr_tmpl,
+	       rpi_page->start_rpi);
+	hdr_tmpl->rpi_paddr_lo = putPaddrLow(rpi_page->dmabuf->phys);
+	hdr_tmpl->rpi_paddr_hi = putPaddrHigh(rpi_page->dmabuf->phys);
+	if (!phba->sli4_hba.intr_enable)
+		rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+	else
+		rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
+	shdr = (union lpfc_sli4_cfg_shdr *) &hdr_tmpl->header.cfg_shdr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mboxq, phba->mbox_mem_pool);
+	if (shdr_status || shdr_add_status || rc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2514 POST_RPI_HDR mailbox failed with "
+				"status x%x add_status x%x, mbx status x%x\n",
+				shdr_status, shdr_add_status, rc);
+		rc = -ENXIO;
+	}
+	return rc;
+}
+
+/**
+ * lpfc_sli4_alloc_rpi - Get an available rpi in the device's range
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to post rpi header templates to the
+ * HBA consistent with the SLI-4 interface spec.  This routine
+ * posts a PAGE_SIZE memory region to the port to hold up to
+ * PAGE_SIZE modulo 64 rpi context headers.
+ *
+ * Returns
+ * 	A nonzero rpi defined as rpi_base <= rpi < max_rpi if sucessful
+ * 	LPFC_RPI_ALLOC_ERROR if no rpis are available.
+ **/
+int
+lpfc_sli4_alloc_rpi(struct lpfc_hba *phba)
+{
+	int rpi;
+	uint16_t max_rpi, rpi_base, rpi_limit;
+	uint16_t rpi_remaining;
+	struct lpfc_rpi_hdr *rpi_hdr;
+
+	max_rpi = phba->sli4_hba.max_cfg_param.max_rpi;
+	rpi_base = phba->sli4_hba.max_cfg_param.rpi_base;
+	rpi_limit = phba->sli4_hba.next_rpi;
+
+	/*
+	 * The valid rpi range is not guaranteed to be zero-based.  Start
+	 * the search at the rpi_base as reported by the port.
+	 */
+	spin_lock_irq(&phba->hbalock);
+	rpi = find_next_zero_bit(phba->sli4_hba.rpi_bmask, rpi_limit, rpi_base);
+	if (rpi >= rpi_limit || rpi < rpi_base)
+		rpi = LPFC_RPI_ALLOC_ERROR;
+	else {
+		set_bit(rpi, phba->sli4_hba.rpi_bmask);
+		phba->sli4_hba.max_cfg_param.rpi_used++;
+		phba->sli4_hba.rpi_count++;
+	}
+
+	/*
+	 * Don't try to allocate more rpi header regions if the device limit
+	 * on available rpis max has been exhausted.
+	 */
+	if ((rpi == LPFC_RPI_ALLOC_ERROR) &&
+	    (phba->sli4_hba.rpi_count >= max_rpi)) {
+		spin_unlock_irq(&phba->hbalock);
+		return rpi;
+	}
+
+	/*
+	 * If the driver is running low on rpi resources, allocate another
+	 * page now.  Note that the next_rpi value is used because
+	 * it represents how many are actually in use whereas max_rpi notes
+	 * how many are supported max by the device.
+	 */
+	rpi_remaining = phba->sli4_hba.next_rpi - rpi_base -
+		phba->sli4_hba.rpi_count;
+	spin_unlock_irq(&phba->hbalock);
+	if (rpi_remaining < LPFC_RPI_LOW_WATER_MARK) {
+		rpi_hdr = lpfc_sli4_create_rpi_hdr(phba);
+		if (!rpi_hdr) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+					"2002 Error Could not grow rpi "
+					"count\n");
+		} else {
+			lpfc_sli4_post_rpi_hdr(phba, rpi_hdr);
+		}
+	}
+
+	return rpi;
+}
+
+/**
+ * lpfc_sli4_free_rpi - Release an rpi for reuse.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release an rpi to the pool of
+ * available rpis maintained by the driver.
+ **/
+void
+lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
+{
+	spin_lock_irq(&phba->hbalock);
+	clear_bit(rpi, phba->sli4_hba.rpi_bmask);
+	phba->sli4_hba.rpi_count--;
+	phba->sli4_hba.max_cfg_param.rpi_used--;
+	spin_unlock_irq(&phba->hbalock);
+}
+
+/**
+ * lpfc_sli4_remove_rpis - Remove the rpi bitmask region
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to remove the memory region that
+ * provided rpi via a bitmask.
+ **/
+void
+lpfc_sli4_remove_rpis(struct lpfc_hba *phba)
+{
+	kfree(phba->sli4_hba.rpi_bmask);
+}
+
+/**
+ * lpfc_sli4_resume_rpi - Remove the rpi bitmask region
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to remove the memory region that
+ * provided rpi via a bitmask.
+ **/
+int
+lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp)
+{
+	LPFC_MBOXQ_t *mboxq;
+	struct lpfc_hba *phba = ndlp->phba;
+	int rc;
+
+	/* The port is notified of the header region via a mailbox command. */
+	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mboxq)
+		return -ENOMEM;
+
+	/* Post all rpi memory regions to the port. */
+	lpfc_resume_rpi(mboxq, ndlp);
+	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+	if (rc == MBX_NOT_FINISHED) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2010 Resume RPI Mailbox failed "
+				"status %d, mbxStatus x%x\n", rc,
+				bf_get(lpfc_mqe_status, &mboxq->u.mqe));
+		mempool_free(mboxq, phba->mbox_mem_pool);
+		return -EIO;
+	}
+	return 0;
+}
+
+/**
+ * lpfc_sli4_init_vpi - Initialize a vpi with the port
+ * @phba: pointer to lpfc hba data structure.
+ * @vpi: vpi value to activate with the port.
+ *
+ * This routine is invoked to activate a vpi with the
+ * port when the host intends to use vports with a
+ * nonzero vpi.
+ *
+ * Returns:
+ *    0 success
+ *    -Evalue otherwise
+ **/
+int
+lpfc_sli4_init_vpi(struct lpfc_hba *phba, uint16_t vpi)
+{
+	LPFC_MBOXQ_t *mboxq;
+	int rc = 0;
+	uint32_t mbox_tmo;
+
+	if (vpi == 0)
+		return -EINVAL;
+	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mboxq)
+		return -ENOMEM;
+	lpfc_init_vpi(mboxq, vpi);
+	mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_INIT_VPI);
+	rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
+	if (rc != MBX_TIMEOUT)
+		mempool_free(mboxq, phba->mbox_mem_pool);
+	if (rc != MBX_SUCCESS) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2022 INIT VPI Mailbox failed "
+				"status %d, mbxStatus x%x\n", rc,
+				bf_get(lpfc_mqe_status, &mboxq->u.mqe));
+		rc = -EIO;
+	}
+	return rc;
+}
+
+/**
+ * lpfc_mbx_cmpl_add_fcf_record - add fcf mbox completion handler.
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: Pointer to mailbox object.
+ *
+ * This routine is invoked to manually add a single FCF record. The caller
+ * must pass a completely initialized FCF_Record.  This routine takes
+ * care of the nonembedded mailbox operations.
+ **/
+static void
+lpfc_mbx_cmpl_add_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+	void *virt_addr;
+	union lpfc_sli4_cfg_shdr *shdr;
+	uint32_t shdr_status, shdr_add_status;
+
+	virt_addr = mboxq->sge_array->addr[0];
+	/* The IOCTL status is embedded in the mailbox subheader. */
+	shdr = (union lpfc_sli4_cfg_shdr *) virt_addr;
+	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+
+	if ((shdr_status || shdr_add_status) &&
+		(shdr_status != STATUS_FCF_IN_USE))
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"2558 ADD_FCF_RECORD mailbox failed with "
+			"status x%x add_status x%x\n",
+			shdr_status, shdr_add_status);
+
+	lpfc_sli4_mbox_cmd_free(phba, mboxq);
+}
+
+/**
+ * lpfc_sli4_add_fcf_record - Manually add an FCF Record.
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_record:  pointer to the initialized fcf record to add.
+ *
+ * This routine is invoked to manually add a single FCF record. The caller
+ * must pass a completely initialized FCF_Record.  This routine takes
+ * care of the nonembedded mailbox operations.
+ **/
+int
+lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record)
+{
+	int rc = 0;
+	LPFC_MBOXQ_t *mboxq;
+	uint8_t *bytep;
+	void *virt_addr;
+	dma_addr_t phys_addr;
+	struct lpfc_mbx_sge sge;
+	uint32_t alloc_len, req_len;
+	uint32_t fcfindex;
+
+	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mboxq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"2009 Failed to allocate mbox for ADD_FCF cmd\n");
+		return -ENOMEM;
+	}
+
+	req_len = sizeof(struct fcf_record) + sizeof(union lpfc_sli4_cfg_shdr) +
+		  sizeof(uint32_t);
+
+	/* Allocate DMA memory and set up the non-embedded mailbox command */
+	alloc_len = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
+				     LPFC_MBOX_OPCODE_FCOE_ADD_FCF,
+				     req_len, LPFC_SLI4_MBX_NEMBED);
+	if (alloc_len < req_len) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"2523 Allocated DMA memory size (x%x) is "
+			"less than the requested DMA memory "
+			"size (x%x)\n", alloc_len, req_len);
+		lpfc_sli4_mbox_cmd_free(phba, mboxq);
+		return -ENOMEM;
+	}
+
+	/*
+	 * Get the first SGE entry from the non-embedded DMA memory.  This
+	 * routine only uses a single SGE.
+	 */
+	lpfc_sli4_mbx_sge_get(mboxq, 0, &sge);
+	phys_addr = getPaddr(sge.pa_hi, sge.pa_lo);
+	if (unlikely(!mboxq->sge_array)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+				"2526 Failed to get the non-embedded SGE "
+				"virtual address\n");
+		lpfc_sli4_mbox_cmd_free(phba, mboxq);
+		return -ENOMEM;
+	}
+	virt_addr = mboxq->sge_array->addr[0];
+	/*
+	 * Configure the FCF record for FCFI 0.  This is the driver's
+	 * hardcoded default and gets used in nonFIP mode.
+	 */
+	fcfindex = bf_get(lpfc_fcf_record_fcf_index, fcf_record);
+	bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr);
+	lpfc_sli_pcimem_bcopy(&fcfindex, bytep, sizeof(uint32_t));
+
+	/*
+	 * Copy the fcf_index and the FCF Record Data. The data starts after
+	 * the FCoE header plus word10. The data copy needs to be endian
+	 * correct.
+	 */
+	bytep += sizeof(uint32_t);
+	lpfc_sli_pcimem_bcopy(fcf_record, bytep, sizeof(struct fcf_record));
+	mboxq->vport = phba->pport;
+	mboxq->mbox_cmpl = lpfc_mbx_cmpl_add_fcf_record;
+	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+	if (rc == MBX_NOT_FINISHED) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"2515 ADD_FCF_RECORD mailbox failed with "
+			"status 0x%x\n", rc);
+		lpfc_sli4_mbox_cmd_free(phba, mboxq);
+		rc = -EIO;
+	} else
+		rc = 0;
+
+	return rc;
+}
+
+/**
+ * lpfc_sli4_build_dflt_fcf_record - Build the driver's default FCF Record.
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_record:  pointer to the fcf record to write the default data.
+ * @fcf_index: FCF table entry index.
+ *
+ * This routine is invoked to build the driver's default FCF record.  The
+ * values used are hardcoded.  This routine handles memory initialization.
+ *
+ **/
+void
+lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *phba,
+				struct fcf_record *fcf_record,
+				uint16_t fcf_index)
+{
+	memset(fcf_record, 0, sizeof(struct fcf_record));
+	fcf_record->max_rcv_size = LPFC_FCOE_MAX_RCV_SIZE;
+	fcf_record->fka_adv_period = LPFC_FCOE_FKA_ADV_PER;
+	fcf_record->fip_priority = LPFC_FCOE_FIP_PRIORITY;
+	bf_set(lpfc_fcf_record_mac_0, fcf_record, phba->fc_map[0]);
+	bf_set(lpfc_fcf_record_mac_1, fcf_record, phba->fc_map[1]);
+	bf_set(lpfc_fcf_record_mac_2, fcf_record, phba->fc_map[2]);
+	bf_set(lpfc_fcf_record_mac_3, fcf_record, LPFC_FCOE_FCF_MAC3);
+	bf_set(lpfc_fcf_record_mac_4, fcf_record, LPFC_FCOE_FCF_MAC4);
+	bf_set(lpfc_fcf_record_mac_5, fcf_record, LPFC_FCOE_FCF_MAC5);
+	bf_set(lpfc_fcf_record_fc_map_0, fcf_record, phba->fc_map[0]);
+	bf_set(lpfc_fcf_record_fc_map_1, fcf_record, phba->fc_map[1]);
+	bf_set(lpfc_fcf_record_fc_map_2, fcf_record, phba->fc_map[2]);
+	bf_set(lpfc_fcf_record_fcf_valid, fcf_record, 1);
+	bf_set(lpfc_fcf_record_fcf_index, fcf_record, fcf_index);
+	bf_set(lpfc_fcf_record_mac_addr_prov, fcf_record,
+		LPFC_FCF_FPMA | LPFC_FCF_SPMA);
+	/* Set the VLAN bit map */
+	if (phba->valid_vlan) {
+		fcf_record->vlan_bitmap[phba->vlan_id / 8]
+			= 1 << (phba->vlan_id % 8);
+	}
+}
+
+/**
+ * lpfc_sli4_read_fcf_record - Read the driver's default FCF Record.
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index: FCF table entry offset.
+ *
+ * This routine is invoked to read up to @fcf_num of FCF record from the
+ * device starting with the given @fcf_index.
+ **/
+int
+lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
+{
+	int rc = 0, error;
+	LPFC_MBOXQ_t *mboxq;
+	void *virt_addr;
+	dma_addr_t phys_addr;
+	uint8_t *bytep;
+	struct lpfc_mbx_sge sge;
+	uint32_t alloc_len, req_len;
+	struct lpfc_mbx_read_fcf_tbl *read_fcf;
+
+	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mboxq) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2000 Failed to allocate mbox for "
+				"READ_FCF cmd\n");
+		return -ENOMEM;
+	}
+
+	req_len = sizeof(struct fcf_record) +
+		  sizeof(union lpfc_sli4_cfg_shdr) + 2 * sizeof(uint32_t);
+
+	/* Set up READ_FCF SLI4_CONFIG mailbox-ioctl command */
+	alloc_len = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
+			 LPFC_MBOX_OPCODE_FCOE_READ_FCF_TABLE, req_len,
+			 LPFC_SLI4_MBX_NEMBED);
+
+	if (alloc_len < req_len) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0291 Allocated DMA memory size (x%x) is "
+				"less than the requested DMA memory "
+				"size (x%x)\n", alloc_len, req_len);
+		lpfc_sli4_mbox_cmd_free(phba, mboxq);
+		return -ENOMEM;
+	}
+
+	/* Get the first SGE entry from the non-embedded DMA memory. This
+	 * routine only uses a single SGE.
+	 */
+	lpfc_sli4_mbx_sge_get(mboxq, 0, &sge);
+	phys_addr = getPaddr(sge.pa_hi, sge.pa_lo);
+	if (unlikely(!mboxq->sge_array)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+				"2527 Failed to get the non-embedded SGE "
+				"virtual address\n");
+		lpfc_sli4_mbox_cmd_free(phba, mboxq);
+		return -ENOMEM;
+	}
+	virt_addr = mboxq->sge_array->addr[0];
+	read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr;
+
+	/* Set up command fields */
+	bf_set(lpfc_mbx_read_fcf_tbl_indx, &read_fcf->u.request, fcf_index);
+	/* Perform necessary endian conversion */
+	bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr);
+	lpfc_sli_pcimem_bcopy(bytep, bytep, sizeof(uint32_t));
+	mboxq->vport = phba->pport;
+	mboxq->mbox_cmpl = lpfc_mbx_cmpl_read_fcf_record;
+	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+	if (rc == MBX_NOT_FINISHED) {
+		lpfc_sli4_mbox_cmd_free(phba, mboxq);
+		error = -EIO;
+	} else
+		error = 0;
+	return error;
+}
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 8839386..7d37eb7 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -29,13 +29,23 @@
 	LPFC_CTX_HOST
 } lpfc_ctx_cmd;
 
+/* This structure is used to carry the needed response IOCB states */
+struct lpfc_sli4_rspiocb_info {
+	uint8_t hw_status;
+	uint8_t bfield;
+#define LPFC_XB	0x1
+#define LPFC_PV	0x2
+	uint8_t priority;
+	uint8_t reserved;
+};
+
 /* This structure is used to handle IOCB requests / responses */
 struct lpfc_iocbq {
 	/* lpfc_iocbqs are used in double linked lists */
 	struct list_head list;
 	struct list_head clist;
 	uint16_t iotag;         /* pre-assigned IO tag */
-	uint16_t rsvd1;
+	uint16_t sli4_xritag;   /* pre-assigned XRI, (OXID) tag. */
 
 	IOCB_t iocb;		/* IOCB cmd */
 	uint8_t retry;		/* retry counter for IOCB cmd - if needed */
@@ -65,7 +75,7 @@
 			   struct lpfc_iocbq *);
 	void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
 			   struct lpfc_iocbq *);
-
+	struct lpfc_sli4_rspiocb_info sli4_info;
 };
 
 #define SLI_IOCB_RET_IOCB      1	/* Return IOCB if cmd ring full */
@@ -81,14 +91,18 @@
 typedef struct lpfcMboxq {
 	/* MBOXQs are used in single linked lists */
 	struct list_head list;	/* ptr to next mailbox command */
-	MAILBOX_t mb;		/* Mailbox cmd */
-	struct lpfc_vport *vport;/* virutal port pointer */
+	union {
+		MAILBOX_t mb;		/* Mailbox cmd */
+		struct lpfc_mqe mqe;
+	} u;
+	struct lpfc_vport *vport;/* virtual port pointer */
 	void *context1;		/* caller context information */
 	void *context2;		/* caller context information */
 
 	void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
 	uint8_t mbox_flag;
-
+	struct lpfc_mcqe mcqe;
+	struct lpfc_mbx_nembed_sge_virt *sge_array;
 } LPFC_MBOXQ_t;
 
 #define MBX_POLL        1	/* poll mailbox till command done, then
@@ -230,10 +244,11 @@
 
 	/* Additional sli_flags */
 #define LPFC_SLI_MBOX_ACTIVE      0x100	/* HBA mailbox is currently active */
-#define LPFC_SLI2_ACTIVE          0x200	/* SLI2 overlay in firmware is active */
+#define LPFC_SLI_ACTIVE           0x200	/* SLI in firmware is active */
 #define LPFC_PROCESS_LA           0x400	/* Able to process link attention */
 #define LPFC_BLOCK_MGMT_IO        0x800	/* Don't allow mgmt mbx or iocb cmds */
 #define LPFC_MENLO_MAINT          0x1000 /* need for menl fw download */
+#define LPFC_SLI_ASYNC_MBX_BLK    0x2000 /* Async mailbox is blocked */
 
 	struct lpfc_sli_ring ring[LPFC_MAX_RING];
 	int fcp_ring;		/* ring used for FCP initiator commands */
@@ -261,6 +276,8 @@
 
 #define LPFC_MBOX_TMO           30	/* Sec tmo for outstanding mbox
 					   command */
+#define LPFC_MBOX_SLI4_CONFIG_TMO 60	/* Sec tmo for outstanding mbox
+					   command */
 #define LPFC_MBOX_TMO_FLASH_CMD 300     /* Sec tmo for outstanding FLASH write
 					 * or erase cmds. This is especially
 					 * long because of the potential of
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
new file mode 100644
index 0000000..5196b46
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -0,0 +1,467 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2009 Emulex.  All rights reserved.                *
+ * EMULEX and SLI are trademarks of Emulex.                        *
+ * www.emulex.com                                                  *
+ *                                                                 *
+ * 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. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
+ *******************************************************************/
+
+#define LPFC_ACTIVE_MBOX_WAIT_CNT               100
+#define LPFC_RELEASE_NOTIFICATION_INTERVAL	32
+#define LPFC_GET_QE_REL_INT			32
+#define LPFC_RPI_LOW_WATER_MARK			10
+/* Number of SGL entries can be posted in a 4KB nonembedded mbox command */
+#define LPFC_NEMBED_MBOX_SGL_CNT		254
+
+/* Multi-queue arrangement for fast-path FCP work queues */
+#define LPFC_FN_EQN_MAX       8
+#define LPFC_SP_EQN_DEF       1
+#define LPFC_FP_EQN_DEF       1
+#define LPFC_FP_EQN_MIN       1
+#define LPFC_FP_EQN_MAX       (LPFC_FN_EQN_MAX - LPFC_SP_EQN_DEF)
+
+#define LPFC_FN_WQN_MAX       32
+#define LPFC_SP_WQN_DEF       1
+#define LPFC_FP_WQN_DEF       4
+#define LPFC_FP_WQN_MIN       1
+#define LPFC_FP_WQN_MAX       (LPFC_FN_WQN_MAX - LPFC_SP_WQN_DEF)
+
+/*
+ * Provide the default FCF Record attributes used by the driver
+ * when nonFIP mode is configured and there is no other default
+ * FCF Record attributes.
+ */
+#define LPFC_FCOE_FCF_DEF_INDEX	0
+#define LPFC_FCOE_FCF_GET_FIRST	0xFFFF
+#define LPFC_FCOE_FCF_NEXT_NONE	0xFFFF
+
+/* First 3 bytes of default FCF MAC is specified by FC_MAP */
+#define LPFC_FCOE_FCF_MAC3	0xFF
+#define LPFC_FCOE_FCF_MAC4	0xFF
+#define LPFC_FCOE_FCF_MAC5	0xFE
+#define LPFC_FCOE_FCF_MAP0	0x0E
+#define LPFC_FCOE_FCF_MAP1	0xFC
+#define LPFC_FCOE_FCF_MAP2	0x00
+#define LPFC_FCOE_MAX_RCV_SIZE	0x5AC
+#define LPFC_FCOE_FKA_ADV_PER	0
+#define LPFC_FCOE_FIP_PRIORITY	0x80
+
+enum lpfc_sli4_queue_type {
+	LPFC_EQ,
+	LPFC_GCQ,
+	LPFC_MCQ,
+	LPFC_WCQ,
+	LPFC_RCQ,
+	LPFC_MQ,
+	LPFC_WQ,
+	LPFC_HRQ,
+	LPFC_DRQ
+};
+
+/* The queue sub-type defines the functional purpose of the queue */
+enum lpfc_sli4_queue_subtype {
+	LPFC_NONE,
+	LPFC_MBOX,
+	LPFC_FCP,
+	LPFC_ELS,
+	LPFC_USOL
+};
+
+union sli4_qe {
+	void *address;
+	struct lpfc_eqe *eqe;
+	struct lpfc_cqe *cqe;
+	struct lpfc_mcqe *mcqe;
+	struct lpfc_wcqe_complete *wcqe_complete;
+	struct lpfc_wcqe_release *wcqe_release;
+	struct sli4_wcqe_xri_aborted *wcqe_xri_aborted;
+	struct lpfc_rcqe_complete *rcqe_complete;
+	struct lpfc_mqe *mqe;
+	union  lpfc_wqe *wqe;
+	struct lpfc_rqe *rqe;
+};
+
+struct lpfc_queue {
+	struct list_head list;
+	enum lpfc_sli4_queue_type type;
+	enum lpfc_sli4_queue_subtype subtype;
+	struct lpfc_hba *phba;
+	struct list_head child_list;
+	uint32_t entry_count;	/* Number of entries to support on the queue */
+	uint32_t entry_size;	/* Size of each queue entry. */
+	uint32_t queue_id;	/* Queue ID assigned by the hardware */
+	struct list_head page_list;
+	uint32_t page_count;	/* Number of pages allocated for this queue */
+
+	uint32_t host_index;	/* The host's index for putting or getting */
+	uint32_t hba_index;	/* The last known hba index for get or put */
+	union sli4_qe qe[1];	/* array to index entries (must be last) */
+};
+
+struct lpfc_cq_event {
+	struct list_head list;
+	union {
+		struct lpfc_mcqe		mcqe_cmpl;
+		struct lpfc_acqe_link		acqe_link;
+		struct lpfc_acqe_fcoe		acqe_fcoe;
+		struct lpfc_acqe_dcbx		acqe_dcbx;
+		struct lpfc_rcqe		rcqe_cmpl;
+		struct sli4_wcqe_xri_aborted	wcqe_axri;
+	} cqe;
+};
+
+struct lpfc_sli4_link {
+	uint8_t speed;
+	uint8_t duplex;
+	uint8_t status;
+	uint8_t physical;
+	uint8_t fault;
+};
+
+struct lpfc_fcf {
+	uint8_t	 fabric_name[8];
+	uint8_t  mac_addr[6];
+	uint16_t fcf_indx;
+	uint16_t fcfi;
+	uint32_t fcf_flag;
+#define FCF_AVAILABLE	0x01 /* FCF available for discovery */
+#define FCF_REGISTERED	0x02 /* FCF registered with FW */
+#define FCF_DISCOVERED	0x04 /* FCF discovery started  */
+#define FCF_BOOT_ENABLE 0x08 /* Boot bios use this FCF */
+#define FCF_IN_USE	0x10 /* Atleast one discovery completed */
+#define FCF_VALID_VLAN	0x20 /* Use the vlan id specified */
+	uint32_t priority;
+	uint32_t addr_mode;
+	uint16_t vlan_id;
+};
+
+#define LPFC_REGION23_SIGNATURE "RG23"
+#define LPFC_REGION23_VERSION	1
+#define LPFC_REGION23_LAST_REC  0xff
+struct lpfc_fip_param_hdr {
+	uint8_t type;
+#define FCOE_PARAM_TYPE		0xA0
+	uint8_t length;
+#define FCOE_PARAM_LENGTH	2
+	uint8_t parm_version;
+#define FIPP_VERSION		0x01
+	uint8_t parm_flags;
+#define	lpfc_fip_param_hdr_fipp_mode_SHIFT	6
+#define	lpfc_fip_param_hdr_fipp_mode_MASK	0x3
+#define lpfc_fip_param_hdr_fipp_mode_WORD	parm_flags
+#define	FIPP_MODE_ON				0x2
+#define	FIPP_MODE_OFF				0x0
+#define FIPP_VLAN_VALID				0x1
+};
+
+struct lpfc_fcoe_params {
+	uint8_t fc_map[3];
+	uint8_t reserved1;
+	uint16_t vlan_tag;
+	uint8_t reserved[2];
+};
+
+struct lpfc_fcf_conn_hdr {
+	uint8_t type;
+#define FCOE_CONN_TBL_TYPE		0xA1
+	uint8_t length;   /* words */
+	uint8_t reserved[2];
+};
+
+struct lpfc_fcf_conn_rec {
+	uint16_t flags;
+#define	FCFCNCT_VALID		0x0001
+#define	FCFCNCT_BOOT		0x0002
+#define	FCFCNCT_PRIMARY		0x0004   /* if not set, Secondary */
+#define	FCFCNCT_FBNM_VALID	0x0008
+#define	FCFCNCT_SWNM_VALID	0x0010
+#define	FCFCNCT_VLAN_VALID	0x0020
+#define	FCFCNCT_AM_VALID	0x0040
+#define	FCFCNCT_AM_PREFERRED	0x0080   /* if not set, AM Required */
+#define	FCFCNCT_AM_SPMA		0x0100	 /* if not set, FPMA */
+
+	uint16_t vlan_tag;
+	uint8_t fabric_name[8];
+	uint8_t switch_name[8];
+};
+
+struct lpfc_fcf_conn_entry {
+	struct list_head list;
+	struct lpfc_fcf_conn_rec conn_rec;
+};
+
+/*
+ * Define the host's bootstrap mailbox.  This structure contains
+ * the member attributes needed to create, use, and destroy the
+ * bootstrap mailbox region.
+ *
+ * The macro definitions for the bmbx data structure are defined
+ * in lpfc_hw4.h with the register definition.
+ */
+struct lpfc_bmbx {
+	struct lpfc_dmabuf *dmabuf;
+	struct dma_address dma_address;
+	void *avirt;
+	dma_addr_t aphys;
+	uint32_t bmbx_size;
+};
+
+#define LPFC_EQE_SIZE LPFC_EQE_SIZE_4
+
+#define LPFC_EQE_SIZE_4B 	4
+#define LPFC_EQE_SIZE_16B	16
+#define LPFC_CQE_SIZE		16
+#define LPFC_WQE_SIZE		64
+#define LPFC_MQE_SIZE		256
+#define LPFC_RQE_SIZE		8
+
+#define LPFC_EQE_DEF_COUNT	1024
+#define LPFC_CQE_DEF_COUNT      256
+#define LPFC_WQE_DEF_COUNT      64
+#define LPFC_MQE_DEF_COUNT      16
+#define LPFC_RQE_DEF_COUNT	512
+
+#define LPFC_QUEUE_NOARM	false
+#define LPFC_QUEUE_REARM	true
+
+
+/*
+ * SLI4 CT field defines
+ */
+#define SLI4_CT_RPI 0
+#define SLI4_CT_VPI 1
+#define SLI4_CT_VFI 2
+#define SLI4_CT_FCFI 3
+
+#define LPFC_SLI4_MAX_SEGMENT_SIZE 0x10000
+
+/*
+ * SLI4 specific data structures
+ */
+struct lpfc_max_cfg_param {
+	uint16_t max_xri;
+	uint16_t xri_base;
+	uint16_t xri_used;
+	uint16_t max_rpi;
+	uint16_t rpi_base;
+	uint16_t rpi_used;
+	uint16_t max_vpi;
+	uint16_t vpi_base;
+	uint16_t vpi_used;
+	uint16_t max_vfi;
+	uint16_t vfi_base;
+	uint16_t vfi_used;
+	uint16_t max_fcfi;
+	uint16_t fcfi_base;
+	uint16_t fcfi_used;
+	uint16_t max_eq;
+	uint16_t max_rq;
+	uint16_t max_cq;
+	uint16_t max_wq;
+};
+
+struct lpfc_hba;
+/* SLI4 HBA multi-fcp queue handler struct */
+struct lpfc_fcp_eq_hdl {
+	uint32_t idx;
+	struct lpfc_hba *phba;
+};
+
+/* SLI4 HBA data structure entries */
+struct lpfc_sli4_hba {
+	void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for
+					     PCI BAR0, config space registers */
+	void __iomem *ctrl_regs_memmap_p; /* Kernel memory mapped address for
+					     PCI BAR1, control registers */
+	void __iomem *drbl_regs_memmap_p; /* Kernel memory mapped address for
+					     PCI BAR2, doorbell registers */
+	/* BAR0 PCI config space register memory map */
+	void __iomem *UERRLOregaddr; /* Address to UERR_STATUS_LO register */
+	void __iomem *UERRHIregaddr; /* Address to UERR_STATUS_HI register */
+	void __iomem *ONLINE0regaddr; /* Address to components of internal UE */
+	void __iomem *ONLINE1regaddr; /* Address to components of internal UE */
+#define LPFC_ONLINE_NERR	0xFFFFFFFF
+	void __iomem *SCRATCHPADregaddr; /* Address to scratchpad register */
+	/* BAR1 FCoE function CSR register memory map */
+	void __iomem *STAregaddr;    /* Address to HST_STATE register */
+	void __iomem *ISRregaddr;    /* Address to HST_ISR register */
+	void __iomem *IMRregaddr;    /* Address to HST_IMR register */
+	void __iomem *ISCRregaddr;   /* Address to HST_ISCR register */
+	/* BAR2 VF-0 doorbell register memory map */
+	void __iomem *RQDBregaddr;   /* Address to RQ_DOORBELL register */
+	void __iomem *WQDBregaddr;   /* Address to WQ_DOORBELL register */
+	void __iomem *EQCQDBregaddr; /* Address to EQCQ_DOORBELL register */
+	void __iomem *MQDBregaddr;   /* Address to MQ_DOORBELL register */
+	void __iomem *BMBXregaddr;   /* Address to BootStrap MBX register */
+
+	struct msix_entry *msix_entries;
+	uint32_t cfg_eqn;
+	struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */
+	/* Pointers to the constructed SLI4 queues */
+	struct lpfc_queue **fp_eq; /* Fast-path event queue */
+	struct lpfc_queue *sp_eq;  /* Slow-path event queue */
+	struct lpfc_queue **fcp_wq;/* Fast-path FCP work queue */
+	struct lpfc_queue *mbx_wq; /* Slow-path MBOX work queue */
+	struct lpfc_queue *els_wq; /* Slow-path ELS work queue */
+	struct lpfc_queue *hdr_rq; /* Slow-path Header Receive queue */
+	struct lpfc_queue *dat_rq; /* Slow-path Data Receive queue */
+	struct lpfc_queue **fcp_cq;/* Fast-path FCP compl queue */
+	struct lpfc_queue *mbx_cq; /* Slow-path mailbox complete queue */
+	struct lpfc_queue *els_cq; /* Slow-path ELS response complete queue */
+	struct lpfc_queue *rxq_cq; /* Slow-path unsolicited complete queue */
+
+	/* Setup information for various queue parameters */
+	int eq_esize;
+	int eq_ecount;
+	int cq_esize;
+	int cq_ecount;
+	int wq_esize;
+	int wq_ecount;
+	int mq_esize;
+	int mq_ecount;
+	int rq_esize;
+	int rq_ecount;
+#define LPFC_SP_EQ_MAX_INTR_SEC         10000
+#define LPFC_FP_EQ_MAX_INTR_SEC         10000
+
+	uint32_t intr_enable;
+	struct lpfc_bmbx bmbx;
+	struct lpfc_max_cfg_param max_cfg_param;
+	uint16_t next_xri; /* last_xri - max_cfg_param.xri_base = used */
+	uint16_t next_rpi;
+	uint16_t scsi_xri_max;
+	uint16_t scsi_xri_cnt;
+	struct list_head lpfc_free_sgl_list;
+	struct list_head lpfc_sgl_list;
+	struct lpfc_sglq **lpfc_els_sgl_array;
+	struct list_head lpfc_abts_els_sgl_list;
+	struct lpfc_scsi_buf **lpfc_scsi_psb_array;
+	struct list_head lpfc_abts_scsi_buf_list;
+	uint32_t total_sglq_bufs;
+	struct lpfc_sglq **lpfc_sglq_active_list;
+	struct list_head lpfc_rpi_hdr_list;
+	unsigned long *rpi_bmask;
+	uint16_t rpi_count;
+	struct lpfc_sli4_flags sli4_flags;
+	struct list_head sp_rspiocb_work_queue;
+	struct list_head sp_cqe_event_pool;
+	struct list_head sp_asynce_work_queue;
+	struct list_head sp_fcp_xri_aborted_work_queue;
+	struct list_head sp_els_xri_aborted_work_queue;
+	struct list_head sp_unsol_work_queue;
+	struct lpfc_sli4_link link_state;
+	spinlock_t abts_scsi_buf_list_lock; /* list of aborted SCSI IOs */
+	spinlock_t abts_sgl_list_lock; /* list of aborted els IOs */
+};
+
+enum lpfc_sge_type {
+	GEN_BUFF_TYPE,
+	SCSI_BUFF_TYPE
+};
+
+struct lpfc_sglq {
+	/* lpfc_sglqs are used in double linked lists */
+	struct list_head list;
+	struct list_head clist;
+	enum lpfc_sge_type buff_type; /* is this a scsi sgl */
+	uint16_t iotag;         /* pre-assigned IO tag */
+	uint16_t sli4_xritag;   /* pre-assigned XRI, (OXID) tag. */
+	struct sli4_sge *sgl;	/* pre-assigned SGL */
+	void *virt;		/* virtual address. */
+	dma_addr_t phys;	/* physical address */
+};
+
+struct lpfc_rpi_hdr {
+	struct list_head list;
+	uint32_t len;
+	struct lpfc_dmabuf *dmabuf;
+	uint32_t page_count;
+	uint32_t start_rpi;
+};
+
+/*
+ * SLI4 specific function prototypes
+ */
+int lpfc_pci_function_reset(struct lpfc_hba *);
+int lpfc_sli4_hba_setup(struct lpfc_hba *);
+int lpfc_sli4_hba_down(struct lpfc_hba *);
+int lpfc_sli4_config(struct lpfc_hba *, struct lpfcMboxq *, uint8_t,
+		     uint8_t, uint32_t, bool);
+void lpfc_sli4_mbox_cmd_free(struct lpfc_hba *, struct lpfcMboxq *);
+void lpfc_sli4_mbx_sge_set(struct lpfcMboxq *, uint32_t, dma_addr_t, uint32_t);
+void lpfc_sli4_mbx_sge_get(struct lpfcMboxq *, uint32_t,
+			   struct lpfc_mbx_sge *);
+
+void lpfc_sli4_hba_reset(struct lpfc_hba *);
+struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *, uint32_t,
+			uint32_t);
+void lpfc_sli4_queue_free(struct lpfc_queue *);
+uint32_t lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint16_t);
+uint32_t lpfc_cq_create(struct lpfc_hba *, struct lpfc_queue *,
+			struct lpfc_queue *, uint32_t, uint32_t);
+uint32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *,
+			struct lpfc_queue *, uint32_t);
+uint32_t lpfc_wq_create(struct lpfc_hba *, struct lpfc_queue *,
+			struct lpfc_queue *, uint32_t);
+uint32_t lpfc_rq_create(struct lpfc_hba *, struct lpfc_queue *,
+			struct lpfc_queue *, struct lpfc_queue *, uint32_t);
+uint32_t lpfc_eq_destroy(struct lpfc_hba *, struct lpfc_queue *);
+uint32_t lpfc_cq_destroy(struct lpfc_hba *, struct lpfc_queue *);
+uint32_t lpfc_mq_destroy(struct lpfc_hba *, struct lpfc_queue *);
+uint32_t lpfc_wq_destroy(struct lpfc_hba *, struct lpfc_queue *);
+uint32_t lpfc_rq_destroy(struct lpfc_hba *, struct lpfc_queue *,
+			 struct lpfc_queue *);
+int lpfc_sli4_queue_setup(struct lpfc_hba *);
+void lpfc_sli4_queue_unset(struct lpfc_hba *);
+int lpfc_sli4_post_sgl(struct lpfc_hba *, dma_addr_t, dma_addr_t, uint16_t);
+int lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *);
+int lpfc_sli4_remove_all_sgl_pages(struct lpfc_hba *);
+uint16_t lpfc_sli4_next_xritag(struct lpfc_hba *);
+int lpfc_sli4_post_async_mbox(struct lpfc_hba *);
+int lpfc_sli4_post_sgl_list(struct lpfc_hba *phba);
+int lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *, struct list_head *, int);
+struct lpfc_cq_event *__lpfc_sli4_cq_event_alloc(struct lpfc_hba *);
+struct lpfc_cq_event *lpfc_sli4_cq_event_alloc(struct lpfc_hba *);
+void __lpfc_sli4_cq_event_release(struct lpfc_hba *, struct lpfc_cq_event *);
+void lpfc_sli4_cq_event_release(struct lpfc_hba *, struct lpfc_cq_event *);
+int lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *);
+int lpfc_sli4_post_rpi_hdr(struct lpfc_hba *, struct lpfc_rpi_hdr *);
+int lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *);
+struct lpfc_rpi_hdr *lpfc_sli4_create_rpi_hdr(struct lpfc_hba *);
+void lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *);
+int lpfc_sli4_alloc_rpi(struct lpfc_hba *);
+void lpfc_sli4_free_rpi(struct lpfc_hba *, int);
+void lpfc_sli4_remove_rpis(struct lpfc_hba *);
+void lpfc_sli4_async_event_proc(struct lpfc_hba *);
+int lpfc_sli4_resume_rpi(struct lpfc_nodelist *);
+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 *,
+			       struct sli4_wcqe_xri_aborted *);
+void lpfc_sli4_els_xri_aborted(struct lpfc_hba *,
+			       struct sli4_wcqe_xri_aborted *);
+int lpfc_sli4_brdreset(struct lpfc_hba *);
+int lpfc_sli4_add_fcf_record(struct lpfc_hba *, struct fcf_record *);
+void lpfc_sli_remove_dflt_fcf(struct lpfc_hba *);
+int lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *);
+int lpfc_sli4_init_vpi(struct lpfc_hba *, uint16_t);
+uint32_t lpfc_sli4_cq_release(struct lpfc_queue *, bool);
+uint32_t lpfc_sli4_eq_release(struct lpfc_queue *, bool);
+void lpfc_sli4_fcfi_unreg(struct lpfc_hba *, uint16_t);
+int lpfc_sli4_read_fcf_record(struct lpfc_hba *, uint16_t);
+void lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_sli4_post_status_check(struct lpfc_hba *);
+uint8_t lpfc_sli4_mbox_opcode_get(struct lpfc_hba *, struct lpfcMboxq *);
+
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index e599519..6b8a148 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.3.1"
+#define LPFC_DRIVER_VERSION "8.3.2"
 
 #define LPFC_DRIVER_NAME		"lpfc"
 #define LPFC_SP_DRIVER_HANDLER_NAME	"lpfc:sp"
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index 917ad56..a6313ee 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -32,8 +32,10 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -89,6 +91,8 @@
 		vpi = 0;
 	else
 		set_bit(vpi, phba->vpi_bmask);
+	if (phba->sli_rev == LPFC_SLI_REV4)
+		phba->sli4_hba.max_cfg_param.vpi_used++;
 	spin_unlock_irq(&phba->hbalock);
 	return vpi;
 }
@@ -96,8 +100,12 @@
 static void
 lpfc_free_vpi(struct lpfc_hba *phba, int vpi)
 {
+	if (vpi == 0)
+		return;
 	spin_lock_irq(&phba->hbalock);
 	clear_bit(vpi, phba->vpi_bmask);
+	if (phba->sli_rev == LPFC_SLI_REV4)
+		phba->sli4_hba.max_cfg_param.vpi_used--;
 	spin_unlock_irq(&phba->hbalock);
 }
 
@@ -113,7 +121,7 @@
 	if (!pmb) {
 		return -ENOMEM;
 	}
-	mb = &pmb->mb;
+	mb = &pmb->u.mb;
 
 	lpfc_read_sparam(phba, pmb, vport->vpi);
 	/*
@@ -243,23 +251,22 @@
 		    (vport->fc_flag & wait_flags)  ||
 		    ((vport->port_state > LPFC_VPORT_FAILED) &&
 		     (vport->port_state < LPFC_VPORT_READY))) {
-			lpfc_printf_log(phba, KERN_INFO, LOG_VPORT,
+			lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT,
 					"1833 Vport discovery quiesce Wait:"
-					" vpi x%x state x%x fc_flags x%x"
+					" state x%x fc_flags x%x"
 					" num_nodes x%x, waiting 1000 msecs"
 					" total wait msecs x%x\n",
-					vport->vpi, vport->port_state,
-					vport->fc_flag, vport->num_disc_nodes,
+					vport->port_state, vport->fc_flag,
+					vport->num_disc_nodes,
 					jiffies_to_msecs(jiffies - start_time));
 			msleep(1000);
 		} else {
 			/* Base case.  Wait variants satisfied.  Break out */
-			lpfc_printf_log(phba, KERN_INFO, LOG_VPORT,
+			lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT,
 					 "1834 Vport discovery quiesced:"
-					 " vpi x%x state x%x fc_flags x%x"
+					 " state x%x fc_flags x%x"
 					 " wait msecs x%x\n",
-					 vport->vpi, vport->port_state,
-					 vport->fc_flag,
+					 vport->port_state, vport->fc_flag,
 					 jiffies_to_msecs(jiffies
 						- start_time));
 			break;
@@ -267,12 +274,10 @@
 	}
 
 	if (time_after(jiffies, wait_time_max))
-		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
 				"1835 Vport discovery quiesce failed:"
-				" vpi x%x state x%x fc_flags x%x"
-				" wait msecs x%x\n",
-				vport->vpi, vport->port_state,
-				vport->fc_flag,
+				" state x%x fc_flags x%x wait msecs x%x\n",
+				vport->port_state, vport->fc_flag,
 				jiffies_to_msecs(jiffies - start_time));
 }
 
@@ -308,6 +313,21 @@
 		goto error_out;
 	}
 
+	/*
+	 * In SLI4, the vpi must be activated before it can be used
+	 * by the port.
+	 */
+	if (phba->sli_rev == LPFC_SLI_REV4) {
+		rc = lpfc_sli4_init_vpi(phba, vpi);
+		if (rc) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+					"1838 Failed to INIT_VPI on vpi %d "
+					"status %d\n", vpi, rc);
+			rc = VPORT_NORESOURCES;
+			lpfc_free_vpi(phba, vpi);
+			goto error_out;
+		}
+	}
 
 	/* Assign an unused board number */
 	if ((instance = lpfc_get_instance()) < 0) {
@@ -535,6 +555,16 @@
 				 "physical host\n");
 		return VPORT_ERROR;
 	}
+
+	/* If the vport is a static vport fail the deletion. */
+	if ((vport->vport_flag & STATIC_VPORT) &&
+		!(phba->pport->load_flag & FC_UNLOADING)) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+				 "1837 vport_delete failed: Cannot delete "
+				 "static vport.\n");
+		return VPORT_ERROR;
+	}
+
 	/*
 	 * If we are not unloading the driver then prevent the vport_delete
 	 * from happening until after this vport's discovery is finished.
@@ -710,7 +740,7 @@
 	struct lpfc_vport *port_iterator;
 	struct lpfc_vport **vports;
 	int index = 0;
-	vports = kzalloc((phba->max_vpi + 1) * sizeof(struct lpfc_vport *),
+	vports = kzalloc((phba->max_vports + 1) * sizeof(struct lpfc_vport *),
 			 GFP_KERNEL);
 	if (vports == NULL)
 		return NULL;
@@ -734,7 +764,7 @@
 	int i;
 	if (vports == NULL)
 		return;
-	for (i=0; vports[i] != NULL && i <= phba->max_vpi; i++)
+	for (i = 0; vports[i] != NULL && i <= phba->max_vports; i++)
 		scsi_host_put(lpfc_shost_from_vport(vports[i]));
 	kfree(vports);
 }
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 36b1d10..286c185 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -61,6 +61,7 @@
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_transport_sas.h>
 #include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.h>
 
 #include "mpt2sas_debug.h"
 
@@ -68,10 +69,10 @@
 #define MPT2SAS_DRIVER_NAME		"mpt2sas"
 #define MPT2SAS_AUTHOR	"LSI Corporation <DL-MPTFusionLinux@lsi.com>"
 #define MPT2SAS_DESCRIPTION	"LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION		"01.100.02.00"
+#define MPT2SAS_DRIVER_VERSION		"01.100.03.00"
 #define MPT2SAS_MAJOR_VERSION		01
 #define MPT2SAS_MINOR_VERSION		100
-#define MPT2SAS_BUILD_VERSION		02
+#define MPT2SAS_BUILD_VERSION		03
 #define MPT2SAS_RELEASE_VERSION		00
 
 /*
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index ba6ab17..14e473d 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -473,7 +473,7 @@
 }
 
 /**
- * _ctl_do_task_abort - assign an active smid to the abort_task
+ * _ctl_set_task_mid - assign an active smid to tm request
  * @ioc: per adapter object
  * @karg - (struct mpt2_ioctl_command)
  * @tm_request - pointer to mf from user space
@@ -482,7 +482,7 @@
  * during failure, the reply frame is filled.
  */
 static int
-_ctl_do_task_abort(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
+_ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
     Mpi2SCSITaskManagementRequest_t *tm_request)
 {
 	u8 found = 0;
@@ -494,6 +494,14 @@
 	Mpi2SCSITaskManagementReply_t *tm_reply;
 	u32 sz;
 	u32 lun;
+	char *desc = NULL;
+
+	if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
+		desc = "abort_task";
+	else if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK)
+		desc = "query_task";
+	else
+		return 0;
 
 	lun = scsilun_to_int((struct scsi_lun *)tm_request->LUN);
 
@@ -517,13 +525,13 @@
 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
 
 	if (!found) {
-		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ABORT_TASK: "
-		    "DevHandle(0x%04x), lun(%d), no active mid!!\n", ioc->name,
-		    tm_request->DevHandle, lun));
+		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+		    "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name,
+		    desc, tm_request->DevHandle, lun));
 		tm_reply = ioc->ctl_cmds.reply;
 		tm_reply->DevHandle = tm_request->DevHandle;
 		tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
-		tm_reply->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+		tm_reply->TaskType = tm_request->TaskType;
 		tm_reply->MsgLength = sizeof(Mpi2SCSITaskManagementReply_t)/4;
 		tm_reply->VP_ID = tm_request->VP_ID;
 		tm_reply->VF_ID = tm_request->VF_ID;
@@ -535,9 +543,9 @@
 		return 1;
 	}
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ABORT_TASK: "
-	    "DevHandle(0x%04x), lun(%d), smid(%d)\n", ioc->name,
-	    tm_request->DevHandle, lun, tm_request->TaskMID));
+	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+	    "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name,
+	    desc, tm_request->DevHandle, lun, tm_request->TaskMID));
 	return 0;
 }
 
@@ -739,8 +747,10 @@
 		    (Mpi2SCSITaskManagementRequest_t *)mpi_request;
 
 		if (tm_request->TaskType ==
-		    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
-			if (_ctl_do_task_abort(ioc, &karg, tm_request)) {
+		    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK ||
+		    tm_request->TaskType ==
+		    MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) {
+			if (_ctl_set_task_mid(ioc, &karg, tm_request)) {
 				mpt2sas_base_free_smid(ioc, smid);
 				goto out;
 			}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index e3a7967..2a01a5f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -197,12 +197,12 @@
 MODULE_DEVICE_TABLE(pci, scsih_pci_table);
 
 /**
- * scsih_set_debug_level - global setting of ioc->logging_level.
+ * _scsih_set_debug_level - global setting of ioc->logging_level.
  *
  * Note: The logging levels are defined in mpt2sas_debug.h.
  */
 static int
-scsih_set_debug_level(const char *val, struct kernel_param *kp)
+_scsih_set_debug_level(const char *val, struct kernel_param *kp)
 {
 	int ret = param_set_int(val, kp);
 	struct MPT2SAS_ADAPTER *ioc;
@@ -215,7 +215,7 @@
 		ioc->logging_level = logging_level;
 	return 0;
 }
-module_param_call(logging_level, scsih_set_debug_level, param_get_int,
+module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
     &logging_level, 0644);
 
 /**
@@ -884,6 +884,41 @@
 }
 
 /**
+ * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun
+ * @ioc: per adapter object
+ * @id: target id
+ * @lun: lun number
+ * @channel: channel
+ * Context: This function will acquire ioc->scsi_lookup_lock.
+ *
+ * This will search for a matching channel:id:lun in the scsi_lookup array,
+ * returning 1 if found.
+ */
+static u8
+_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
+    unsigned int lun, int channel)
+{
+	u8 found;
+	unsigned long	flags;
+	int i;
+
+	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+	found = 0;
+	for (i = 0 ; i < ioc->request_depth; i++) {
+		if (ioc->scsi_lookup[i].scmd &&
+		    (ioc->scsi_lookup[i].scmd->device->id == id &&
+		    ioc->scsi_lookup[i].scmd->device->channel == channel &&
+		    ioc->scsi_lookup[i].scmd->device->lun == lun)) {
+			found = 1;
+			goto out;
+		}
+	}
+ out:
+	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+	return found;
+}
+
+/**
  * _scsih_get_chain_buffer_dma - obtain block of chains (dma address)
  * @ioc: per adapter object
  * @smid: system request message index
@@ -1047,14 +1082,14 @@
 }
 
 /**
- * scsih_change_queue_depth - setting device queue depth
+ * _scsih_change_queue_depth - setting device queue depth
  * @sdev: scsi device struct
  * @qdepth: requested queue depth
  *
  * Returns queue depth.
  */
 static int
-scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
+_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
 {
 	struct Scsi_Host *shost = sdev->host;
 	int max_depth;
@@ -1079,14 +1114,14 @@
 }
 
 /**
- * scsih_change_queue_depth - changing device queue tag type
+ * _scsih_change_queue_depth - changing device queue tag type
  * @sdev: scsi device struct
  * @tag_type: requested tag type
  *
  * Returns queue tag type.
  */
 static int
-scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
+_scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
 {
 	if (sdev->tagged_supported) {
 		scsi_set_tag_type(sdev, tag_type);
@@ -1101,14 +1136,14 @@
 }
 
 /**
- * scsih_target_alloc - target add routine
+ * _scsih_target_alloc - target add routine
  * @starget: scsi target struct
  *
  * Returns 0 if ok. Any other return is assumed to be an error and
  * the device is ignored.
  */
 static int
-scsih_target_alloc(struct scsi_target *starget)
+_scsih_target_alloc(struct scsi_target *starget)
 {
 	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
 	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
@@ -1163,13 +1198,13 @@
 }
 
 /**
- * scsih_target_destroy - target destroy routine
+ * _scsih_target_destroy - target destroy routine
  * @starget: scsi target struct
  *
  * Returns nothing.
  */
 static void
-scsih_target_destroy(struct scsi_target *starget)
+_scsih_target_destroy(struct scsi_target *starget)
 {
 	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
 	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
@@ -1212,14 +1247,14 @@
 }
 
 /**
- * scsih_slave_alloc - device add routine
+ * _scsih_slave_alloc - device add routine
  * @sdev: scsi device struct
  *
  * Returns 0 if ok. Any other return is assumed to be an error and
  * the device is ignored.
  */
 static int
-scsih_slave_alloc(struct scsi_device *sdev)
+_scsih_slave_alloc(struct scsi_device *sdev)
 {
 	struct Scsi_Host *shost;
 	struct MPT2SAS_ADAPTER *ioc;
@@ -1273,13 +1308,13 @@
 }
 
 /**
- * scsih_slave_destroy - device destroy routine
+ * _scsih_slave_destroy - device destroy routine
  * @sdev: scsi device struct
  *
  * Returns nothing.
  */
 static void
-scsih_slave_destroy(struct scsi_device *sdev)
+_scsih_slave_destroy(struct scsi_device *sdev)
 {
 	struct MPT2SAS_TARGET *sas_target_priv_data;
 	struct scsi_target *starget;
@@ -1295,13 +1330,13 @@
 }
 
 /**
- * scsih_display_sata_capabilities - sata capabilities
+ * _scsih_display_sata_capabilities - sata capabilities
  * @ioc: per adapter object
  * @sas_device: the sas_device object
  * @sdev: scsi device struct
  */
 static void
-scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
+_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
     struct _sas_device *sas_device, struct scsi_device *sdev)
 {
 	Mpi2ConfigReply_t mpi_reply;
@@ -1401,14 +1436,14 @@
 }
 
 /**
- * scsih_slave_configure - device configure routine.
+ * _scsih_slave_configure - device configure routine.
  * @sdev: scsi device struct
  *
  * Returns 0 if ok. Any other return is assumed to be an error and
  * the device is ignored.
  */
 static int
-scsih_slave_configure(struct scsi_device *sdev)
+_scsih_slave_configure(struct scsi_device *sdev)
 {
 	struct Scsi_Host *shost = sdev->host;
 	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
@@ -1489,7 +1524,7 @@
 		    r_level, raid_device->handle,
 		    (unsigned long long)raid_device->wwid,
 		    raid_device->num_pds, ds);
-		scsih_change_queue_depth(sdev, qdepth);
+		_scsih_change_queue_depth(sdev, qdepth);
 		return 0;
 	}
 
@@ -1532,10 +1567,10 @@
 		    sas_device->slot);
 
 		if (!ssp_target)
-			scsih_display_sata_capabilities(ioc, sas_device, sdev);
+			_scsih_display_sata_capabilities(ioc, sas_device, sdev);
 	}
 
-	scsih_change_queue_depth(sdev, qdepth);
+	_scsih_change_queue_depth(sdev, qdepth);
 
 	if (ssp_target)
 		sas_read_port_mode_page(sdev);
@@ -1543,7 +1578,7 @@
 }
 
 /**
- * scsih_bios_param - fetch head, sector, cylinder info for a disk
+ * _scsih_bios_param - fetch head, sector, cylinder info for a disk
  * @sdev: scsi device struct
  * @bdev: pointer to block device context
  * @capacity: device size (in 512 byte sectors)
@@ -1555,7 +1590,7 @@
  * Return nothing.
  */
 static int
-scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
+_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
     sector_t capacity, int params[])
 {
 	int		heads;
@@ -1636,7 +1671,7 @@
 }
 
 /**
- * scsih_tm_done - tm completion routine
+ * _scsih_tm_done - tm completion routine
  * @ioc: per adapter object
  * @smid: system request message index
  * @VF_ID: virtual function id
@@ -1648,7 +1683,7 @@
  * Return nothing.
  */
 static void
-scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
 {
 	MPI2DefaultReply_t *mpi_reply;
 
@@ -1823,13 +1858,13 @@
 }
 
 /**
- * scsih_abort - eh threads main abort routine
+ * _scsih_abort - eh threads main abort routine
  * @sdev: scsi device struct
  *
  * Returns SUCCESS if command aborted else FAILED
  */
 static int
-scsih_abort(struct scsi_cmnd *scmd)
+_scsih_abort(struct scsi_cmnd *scmd)
 {
 	struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
 	struct MPT2SAS_DEVICE *sas_device_priv_data;
@@ -1889,15 +1924,86 @@
 	return r;
 }
 
-
 /**
- * scsih_dev_reset - eh threads main device reset routine
+ * _scsih_dev_reset - eh threads main device reset routine
  * @sdev: scsi device struct
  *
  * Returns SUCCESS if command aborted else FAILED
  */
 static int
-scsih_dev_reset(struct scsi_cmnd *scmd)
+_scsih_dev_reset(struct scsi_cmnd *scmd)
+{
+	struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
+	struct MPT2SAS_DEVICE *sas_device_priv_data;
+	struct _sas_device *sas_device;
+	unsigned long flags;
+	u16	handle;
+	int r;
+
+	printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n",
+	    ioc->name, scmd);
+	scsi_print_command(scmd);
+
+	sas_device_priv_data = scmd->device->hostdata;
+	if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
+		printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
+		    ioc->name, scmd);
+		scmd->result = DID_NO_CONNECT << 16;
+		scmd->scsi_done(scmd);
+		r = SUCCESS;
+		goto out;
+	}
+
+	/* for hidden raid components obtain the volume_handle */
+	handle = 0;
+	if (sas_device_priv_data->sas_target->flags &
+	    MPT_TARGET_FLAGS_RAID_COMPONENT) {
+		spin_lock_irqsave(&ioc->sas_device_lock, flags);
+		sas_device = _scsih_sas_device_find_by_handle(ioc,
+		   sas_device_priv_data->sas_target->handle);
+		if (sas_device)
+			handle = sas_device->volume_handle;
+		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+	} else
+		handle = sas_device_priv_data->sas_target->handle;
+
+	if (!handle) {
+		scmd->result = DID_RESET << 16;
+		r = FAILED;
+		goto out;
+	}
+
+	mutex_lock(&ioc->tm_cmds.mutex);
+	mpt2sas_scsih_issue_tm(ioc, handle, 0,
+	    MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, scmd->device->lun,
+	    30);
+
+	/*
+	 *  sanity check see whether all commands to this device been
+	 *  completed
+	 */
+	if (_scsih_scsi_lookup_find_by_lun(ioc, scmd->device->id,
+	    scmd->device->lun, scmd->device->channel))
+		r = FAILED;
+	else
+		r = SUCCESS;
+	ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
+	mutex_unlock(&ioc->tm_cmds.mutex);
+
+ out:
+	printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n",
+	    ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+	return r;
+}
+
+/**
+ * _scsih_target_reset - eh threads main target reset routine
+ * @sdev: scsi device struct
+ *
+ * Returns SUCCESS if command aborted else FAILED
+ */
+static int
+_scsih_target_reset(struct scsi_cmnd *scmd)
 {
 	struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
 	struct MPT2SAS_DEVICE *sas_device_priv_data;
@@ -1912,7 +2018,7 @@
 
 	sas_device_priv_data = scmd->device->hostdata;
 	if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
-		printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
+		printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n",
 		    ioc->name, scmd);
 		scmd->result = DID_NO_CONNECT << 16;
 		scmd->scsi_done(scmd);
@@ -1962,13 +2068,13 @@
 }
 
 /**
- * scsih_abort - eh threads main host reset routine
+ * _scsih_abort - eh threads main host reset routine
  * @sdev: scsi device struct
  *
  * Returns SUCCESS if command aborted else FAILED
  */
 static int
-scsih_host_reset(struct scsi_cmnd *scmd)
+_scsih_host_reset(struct scsi_cmnd *scmd)
 {
 	struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
 	int r, retval;
@@ -2390,7 +2496,107 @@
 }
 
 /**
- * scsih_qcmd - main scsi request entry point
+ * _scsih_setup_eedp - setup MPI request for EEDP transfer
+ * @scmd: pointer to scsi command object
+ * @mpi_request: pointer to the SCSI_IO reqest message frame
+ *
+ * Supporting protection 1 and 3.
+ *
+ * Returns nothing
+ */
+static void
+_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
+{
+	u16 eedp_flags;
+	unsigned char prot_op = scsi_get_prot_op(scmd);
+	unsigned char prot_type = scsi_get_prot_type(scmd);
+
+	if (prot_type == SCSI_PROT_DIF_TYPE0 ||
+	   prot_type == SCSI_PROT_DIF_TYPE2 ||
+	   prot_op == SCSI_PROT_NORMAL)
+		return;
+
+	if (prot_op ==  SCSI_PROT_READ_STRIP)
+		eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
+	else if (prot_op ==  SCSI_PROT_WRITE_INSERT)
+		eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
+	else
+		return;
+
+	mpi_request->EEDPBlockSize = scmd->device->sector_size;
+
+	switch (prot_type) {
+	case SCSI_PROT_DIF_TYPE1:
+
+		/*
+		* enable ref/guard checking
+		* auto increment ref tag
+		*/
+		mpi_request->EEDPFlags = eedp_flags |
+		    MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
+		    MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
+		    MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
+		mpi_request->CDB.EEDP32.PrimaryReferenceTag =
+		    cpu_to_be32(scsi_get_lba(scmd));
+
+		break;
+
+	case SCSI_PROT_DIF_TYPE3:
+
+		/*
+		* enable guard checking
+		*/
+		mpi_request->EEDPFlags = eedp_flags |
+		    MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
+
+		break;
+	}
+}
+
+/**
+ * _scsih_eedp_error_handling - return sense code for EEDP errors
+ * @scmd: pointer to scsi command object
+ * @ioc_status: ioc status
+ *
+ * Returns nothing
+ */
+static void
+_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
+{
+	u8 ascq;
+	u8 sk;
+	u8 host_byte;
+
+	switch (ioc_status) {
+	case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
+		ascq = 0x01;
+		break;
+	case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
+		ascq = 0x02;
+		break;
+	case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
+		ascq = 0x03;
+		break;
+	default:
+		ascq = 0x00;
+		break;
+	}
+
+	if (scmd->sc_data_direction == DMA_TO_DEVICE) {
+		sk = ILLEGAL_REQUEST;
+		host_byte = DID_ABORT;
+	} else {
+		sk = ABORTED_COMMAND;
+		host_byte = DID_OK;
+	}
+
+	scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
+	scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
+	    SAM_STAT_CHECK_CONDITION;
+}
+
+/**
+ * _scsih_qcmd - main scsi request entry point
  * @scmd: pointer to scsi command object
  * @done: function pointer to be invoked on completion
  *
@@ -2401,7 +2607,7 @@
  * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
  */
 static int
-scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
+_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
 {
 	struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
 	struct MPT2SAS_DEVICE *sas_device_priv_data;
@@ -2470,6 +2676,7 @@
 	}
 	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
 	memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
+	_scsih_setup_eedp(scmd, mpi_request);
 	mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
 	if (sas_device_priv_data->sas_target->flags &
 	    MPT_TARGET_FLAGS_RAID_COMPONENT)
@@ -2604,6 +2811,15 @@
 	case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
 		desc_ioc_state = "scsi ext terminated";
 		break;
+	case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
+		desc_ioc_state = "eedp guard error";
+		break;
+	case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
+		desc_ioc_state = "eedp ref tag error";
+		break;
+	case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
+		desc_ioc_state = "eedp app tag error";
+		break;
 	default:
 		desc_ioc_state = "unknown";
 		break;
@@ -2783,7 +2999,7 @@
 }
 
 /**
- * scsih_io_done - scsi request callback
+ * _scsih_io_done - scsi request callback
  * @ioc: per adapter object
  * @smid: system request message index
  * @VF_ID: virtual function id
@@ -2794,7 +3010,7 @@
  * Return nothing.
  */
 static void
-scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
 {
 	Mpi2SCSIIORequest_t *mpi_request;
 	Mpi2SCSIIOReply_t *mpi_reply;
@@ -2939,6 +3155,11 @@
 			scmd->result = DID_RESET << 16;
 		break;
 
+	case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
+	case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
+	case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
+		_scsih_eedp_error_handling(scmd, ioc_status);
+		break;
 	case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
 	case MPI2_IOCSTATUS_INVALID_FUNCTION:
 	case MPI2_IOCSTATUS_INVALID_SGL:
@@ -5130,18 +5351,19 @@
 	.module				= THIS_MODULE,
 	.name				= "Fusion MPT SAS Host",
 	.proc_name			= MPT2SAS_DRIVER_NAME,
-	.queuecommand			= scsih_qcmd,
-	.target_alloc			= scsih_target_alloc,
-	.slave_alloc			= scsih_slave_alloc,
-	.slave_configure		= scsih_slave_configure,
-	.target_destroy			= scsih_target_destroy,
-	.slave_destroy			= scsih_slave_destroy,
-	.change_queue_depth 		= scsih_change_queue_depth,
-	.change_queue_type		= scsih_change_queue_type,
-	.eh_abort_handler		= scsih_abort,
-	.eh_device_reset_handler	= scsih_dev_reset,
-	.eh_host_reset_handler		= scsih_host_reset,
-	.bios_param			= scsih_bios_param,
+	.queuecommand			= _scsih_qcmd,
+	.target_alloc			= _scsih_target_alloc,
+	.slave_alloc			= _scsih_slave_alloc,
+	.slave_configure		= _scsih_slave_configure,
+	.target_destroy			= _scsih_target_destroy,
+	.slave_destroy			= _scsih_slave_destroy,
+	.change_queue_depth 		= _scsih_change_queue_depth,
+	.change_queue_type		= _scsih_change_queue_type,
+	.eh_abort_handler		= _scsih_abort,
+	.eh_device_reset_handler	= _scsih_dev_reset,
+	.eh_target_reset_handler	= _scsih_target_reset,
+	.eh_host_reset_handler		= _scsih_host_reset,
+	.bios_param			= _scsih_bios_param,
 	.can_queue			= 1,
 	.this_id			= -1,
 	.sg_tablesize			= MPT2SAS_SG_DEPTH,
@@ -5228,13 +5450,13 @@
 }
 
 /**
- * scsih_remove - detach and remove add host
+ * _scsih_remove - detach and remove add host
  * @pdev: PCI device struct
  *
  * Return nothing.
  */
 static void __devexit
-scsih_remove(struct pci_dev *pdev)
+_scsih_remove(struct pci_dev *pdev)
 {
 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
 	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
@@ -5442,14 +5664,14 @@
 }
 
 /**
- * scsih_probe - attach and add scsi host
+ * _scsih_probe - attach and add scsi host
  * @pdev: PCI device struct
  * @id: pci device id
  *
  * Returns 0 success, anything else error.
  */
 static int
-scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct MPT2SAS_ADAPTER *ioc;
 	struct Scsi_Host *shost;
@@ -5503,6 +5725,9 @@
 		goto out_add_shost_fail;
 	}
 
+	scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
+	    | SHOST_DIF_TYPE3_PROTECTION);
+
 	/* event thread */
 	snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
 	    "fw_event%d", ioc->id);
@@ -5536,14 +5761,14 @@
 
 #ifdef CONFIG_PM
 /**
- * scsih_suspend - power management suspend main entry point
+ * _scsih_suspend - power management suspend main entry point
  * @pdev: PCI device struct
  * @state: PM state change to (usually PCI_D3)
  *
  * Returns 0 success, anything else error.
  */
 static int
-scsih_suspend(struct pci_dev *pdev, pm_message_t state)
+_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
 	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
@@ -5564,13 +5789,13 @@
 }
 
 /**
- * scsih_resume - power management resume main entry point
+ * _scsih_resume - power management resume main entry point
  * @pdev: PCI device struct
  *
  * Returns 0 success, anything else error.
  */
 static int
-scsih_resume(struct pci_dev *pdev)
+_scsih_resume(struct pci_dev *pdev)
 {
 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
 	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
@@ -5599,22 +5824,22 @@
 static struct pci_driver scsih_driver = {
 	.name		= MPT2SAS_DRIVER_NAME,
 	.id_table	= scsih_pci_table,
-	.probe		= scsih_probe,
-	.remove		= __devexit_p(scsih_remove),
+	.probe		= _scsih_probe,
+	.remove		= __devexit_p(_scsih_remove),
 #ifdef CONFIG_PM
-	.suspend	= scsih_suspend,
-	.resume		= scsih_resume,
+	.suspend	= _scsih_suspend,
+	.resume		= _scsih_resume,
 #endif
 };
 
 
 /**
- * scsih_init - main entry point for this driver.
+ * _scsih_init - main entry point for this driver.
  *
  * Returns 0 success, anything else error.
  */
 static int __init
-scsih_init(void)
+_scsih_init(void)
 {
 	int error;
 
@@ -5630,10 +5855,10 @@
 	mpt2sas_base_initialize_callback_handler();
 
 	 /* queuecommand callback hander */
-	scsi_io_cb_idx = mpt2sas_base_register_callback_handler(scsih_io_done);
+	scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
 
 	/* task managment callback handler */
-	tm_cb_idx = mpt2sas_base_register_callback_handler(scsih_tm_done);
+	tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
 
 	/* base internal commands callback handler */
 	base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
@@ -5659,12 +5884,12 @@
 }
 
 /**
- * scsih_exit - exit point for this driver (when it is a module).
+ * _scsih_exit - exit point for this driver (when it is a module).
  *
  * Returns 0 success, anything else error.
  */
 static void __exit
-scsih_exit(void)
+_scsih_exit(void)
 {
 	printk(KERN_INFO "mpt2sas version %s unloading\n",
 	    MPT2SAS_DRIVER_VERSION);
@@ -5682,5 +5907,5 @@
 	mpt2sas_ctl_exit();
 }
 
-module_init(scsih_init);
-module_exit(scsih_exit);
+module_init(_scsih_init);
+module_exit(_scsih_exit);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index 5c65da5..686695b 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -264,7 +264,7 @@
 };
 
 /**
- * transport_expander_report_manufacture - obtain SMP report_manufacture
+ * _transport_expander_report_manufacture - obtain SMP report_manufacture
  * @ioc: per adapter object
  * @sas_address: expander sas address
  * @edev: the sas_expander_device object
@@ -274,7 +274,7 @@
  * Returns 0 for success, non-zero for failure.
  */
 static int
-transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
+_transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
     u64 sas_address, struct sas_expander_device *edev)
 {
 	Mpi2SmpPassthroughRequest_t *mpi_request;
@@ -578,7 +578,7 @@
 	    MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
 	    mpt2sas_port->remote_identify.device_type ==
 	    MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
-		transport_expander_report_manufacture(ioc,
+		_transport_expander_report_manufacture(ioc,
 		    mpt2sas_port->remote_identify.sas_address,
 		    rphy_to_expander_device(rphy));
 
@@ -852,7 +852,7 @@
 }
 
 /**
- * transport_get_linkerrors -
+ * _transport_get_linkerrors -
  * @phy: The sas phy object
  *
  * Only support sas_host direct attached phys.
@@ -860,7 +860,7 @@
  *
  */
 static int
-transport_get_linkerrors(struct sas_phy *phy)
+_transport_get_linkerrors(struct sas_phy *phy)
 {
 	struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
 	struct _sas_phy *mpt2sas_phy;
@@ -903,14 +903,14 @@
 }
 
 /**
- * transport_get_enclosure_identifier -
+ * _transport_get_enclosure_identifier -
  * @phy: The sas phy object
  *
  * Obtain the enclosure logical id for an expander.
  * Returns 0 for success, non-zero for failure.
  */
 static int
-transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
+_transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
 {
 	struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
 	struct _sas_node *sas_expander;
@@ -929,13 +929,13 @@
 }
 
 /**
- * transport_get_bay_identifier -
+ * _transport_get_bay_identifier -
  * @phy: The sas phy object
  *
  * Returns the slot id for a device that resides inside an enclosure.
  */
 static int
-transport_get_bay_identifier(struct sas_rphy *rphy)
+_transport_get_bay_identifier(struct sas_rphy *rphy)
 {
 	struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
 	struct _sas_device *sas_device;
@@ -953,7 +953,7 @@
 }
 
 /**
- * transport_phy_reset -
+ * _transport_phy_reset -
  * @phy: The sas phy object
  * @hard_reset:
  *
@@ -961,7 +961,7 @@
  * Returns 0 for success, non-zero for failure.
  */
 static int
-transport_phy_reset(struct sas_phy *phy, int hard_reset)
+_transport_phy_reset(struct sas_phy *phy, int hard_reset)
 {
 	struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
 	struct _sas_phy *mpt2sas_phy;
@@ -1002,7 +1002,7 @@
 }
 
 /**
- * transport_smp_handler - transport portal for smp passthru
+ * _transport_smp_handler - transport portal for smp passthru
  * @shost: shost object
  * @rphy: sas transport rphy object
  * @req:
@@ -1012,7 +1012,7 @@
  *           smp_rep_general /sys/class/bsg/expander-5:0
  */
 static int
-transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+_transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
     struct request *req)
 {
 	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
@@ -1200,11 +1200,11 @@
 }
 
 struct sas_function_template mpt2sas_transport_functions = {
-	.get_linkerrors		= transport_get_linkerrors,
-	.get_enclosure_identifier = transport_get_enclosure_identifier,
-	.get_bay_identifier	= transport_get_bay_identifier,
-	.phy_reset		= transport_phy_reset,
-	.smp_handler		= transport_smp_handler,
+	.get_linkerrors		= _transport_get_linkerrors,
+	.get_enclosure_identifier = _transport_get_enclosure_identifier,
+	.get_bay_identifier	= _transport_get_bay_identifier,
+	.phy_reset		= _transport_phy_reset,
+	.smp_handler		= _transport_smp_handler,
 };
 
 struct scsi_transport_template *mpt2sas_transport_template;
diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c
deleted file mode 100644
index e4acebd..0000000
--- a/drivers/scsi/mvsas.c
+++ /dev/null
@@ -1,3222 +0,0 @@
-/*
-	mvsas.c - Marvell 88SE6440 SAS/SATA support
-
-	Copyright 2007 Red Hat, Inc.
-	Copyright 2008 Marvell. <kewei@marvell.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; see the file COPYING.	If not,
-	write to the Free Software Foundation, 675 Mass Ave, Cambridge,
-	MA 02139, USA.
-
-	---------------------------------------------------------------
-
-	Random notes:
-	* hardware supports controlling the endian-ness of data
-	  structures.  this permits elimination of all the le32_to_cpu()
-	  and cpu_to_le32() conversions.
-
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/ctype.h>
-#include <scsi/libsas.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/sas_ata.h>
-#include <asm/io.h>
-
-#define DRV_NAME	"mvsas"
-#define DRV_VERSION	"0.5.2"
-#define _MV_DUMP	0
-#define MVS_DISABLE_NVRAM
-#define MVS_DISABLE_MSI
-
-#define mr32(reg)	readl(regs + MVS_##reg)
-#define mw32(reg,val)	writel((val), regs + MVS_##reg)
-#define mw32_f(reg,val)	do {			\
-	writel((val), regs + MVS_##reg);	\
-	readl(regs + MVS_##reg);		\
-	} while (0)
-
-#define MVS_ID_NOT_MAPPED	0x7f
-#define MVS_CHIP_SLOT_SZ	(1U << mvi->chip->slot_width)
-
-/* offset for D2H FIS in the Received FIS List Structure */
-#define SATA_RECEIVED_D2H_FIS(reg_set)	\
-	((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
-#define SATA_RECEIVED_PIO_FIS(reg_set)	\
-	((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20)
-#define UNASSOC_D2H_FIS(id)		\
-	((void *) mvi->rx_fis + 0x100 * id)
-
-#define for_each_phy(__lseq_mask, __mc, __lseq, __rest)			\
-	for ((__mc) = (__lseq_mask), (__lseq) = 0;			\
-					(__mc) != 0 && __rest;		\
-					(++__lseq), (__mc) >>= 1)
-
-/* driver compile-time configuration */
-enum driver_configuration {
-	MVS_TX_RING_SZ		= 1024,	/* TX ring size (12-bit) */
-	MVS_RX_RING_SZ		= 1024, /* RX ring size (12-bit) */
-					/* software requires power-of-2
-					   ring size */
-
-	MVS_SLOTS		= 512,	/* command slots */
-	MVS_SLOT_BUF_SZ		= 8192, /* cmd tbl + IU + status + PRD */
-	MVS_SSP_CMD_SZ		= 64,	/* SSP command table buffer size */
-	MVS_ATA_CMD_SZ		= 96,	/* SATA command table buffer size */
-	MVS_OAF_SZ		= 64,	/* Open address frame buffer size */
-
-	MVS_RX_FIS_COUNT	= 17,	/* Optional rx'd FISs (max 17) */
-
-	MVS_QUEUE_SIZE		= 30,	/* Support Queue depth */
-	MVS_CAN_QUEUE		= MVS_SLOTS - 1,	/* SCSI Queue depth */
-};
-
-/* unchangeable hardware details */
-enum hardware_details {
-	MVS_MAX_PHYS		= 8,	/* max. possible phys */
-	MVS_MAX_PORTS		= 8,	/* max. possible ports */
-	MVS_RX_FISL_SZ		= 0x400 + (MVS_RX_FIS_COUNT * 0x100),
-};
-
-/* peripheral registers (BAR2) */
-enum peripheral_registers {
-	SPI_CTL			= 0x10,	/* EEPROM control */
-	SPI_CMD			= 0x14,	/* EEPROM command */
-	SPI_DATA		= 0x18, /* EEPROM data */
-};
-
-enum peripheral_register_bits {
-	TWSI_RDY		= (1U << 7),	/* EEPROM interface ready */
-	TWSI_RD			= (1U << 4),	/* EEPROM read access */
-
-	SPI_ADDR_MASK		= 0x3ffff,	/* bits 17:0 */
-};
-
-/* enhanced mode registers (BAR4) */
-enum hw_registers {
-	MVS_GBL_CTL		= 0x04,  /* global control */
-	MVS_GBL_INT_STAT	= 0x08,  /* global irq status */
-	MVS_GBL_PI		= 0x0C,  /* ports implemented bitmask */
-	MVS_GBL_PORT_TYPE	= 0xa0,  /* port type */
-
-	MVS_CTL			= 0x100, /* SAS/SATA port configuration */
-	MVS_PCS			= 0x104, /* SAS/SATA port control/status */
-	MVS_CMD_LIST_LO		= 0x108, /* cmd list addr */
-	MVS_CMD_LIST_HI		= 0x10C,
-	MVS_RX_FIS_LO		= 0x110, /* RX FIS list addr */
-	MVS_RX_FIS_HI		= 0x114,
-
-	MVS_TX_CFG		= 0x120, /* TX configuration */
-	MVS_TX_LO		= 0x124, /* TX (delivery) ring addr */
-	MVS_TX_HI		= 0x128,
-
-	MVS_TX_PROD_IDX		= 0x12C, /* TX producer pointer */
-	MVS_TX_CONS_IDX		= 0x130, /* TX consumer pointer (RO) */
-	MVS_RX_CFG		= 0x134, /* RX configuration */
-	MVS_RX_LO		= 0x138, /* RX (completion) ring addr */
-	MVS_RX_HI		= 0x13C,
-	MVS_RX_CONS_IDX		= 0x140, /* RX consumer pointer (RO) */
-
-	MVS_INT_COAL		= 0x148, /* Int coalescing config */
-	MVS_INT_COAL_TMOUT	= 0x14C, /* Int coalescing timeout */
-	MVS_INT_STAT		= 0x150, /* Central int status */
-	MVS_INT_MASK		= 0x154, /* Central int enable */
-	MVS_INT_STAT_SRS	= 0x158, /* SATA register set status */
-	MVS_INT_MASK_SRS	= 0x15C,
-
-					 /* ports 1-3 follow after this */
-	MVS_P0_INT_STAT		= 0x160, /* port0 interrupt status */
-	MVS_P0_INT_MASK		= 0x164, /* port0 interrupt mask */
-	MVS_P4_INT_STAT		= 0x200, /* Port 4 interrupt status */
-	MVS_P4_INT_MASK		= 0x204, /* Port 4 interrupt enable mask */
-
-					 /* ports 1-3 follow after this */
-	MVS_P0_SER_CTLSTAT	= 0x180, /* port0 serial control/status */
-	MVS_P4_SER_CTLSTAT	= 0x220, /* port4 serial control/status */
-
-	MVS_CMD_ADDR		= 0x1B8, /* Command register port (addr) */
-	MVS_CMD_DATA		= 0x1BC, /* Command register port (data) */
-
-					 /* ports 1-3 follow after this */
-	MVS_P0_CFG_ADDR		= 0x1C0, /* port0 phy register address */
-	MVS_P0_CFG_DATA		= 0x1C4, /* port0 phy register data */
-	MVS_P4_CFG_ADDR		= 0x230, /* Port 4 config address */
-	MVS_P4_CFG_DATA		= 0x234, /* Port 4 config data */
-
-					 /* ports 1-3 follow after this */
-	MVS_P0_VSR_ADDR		= 0x1E0, /* port0 VSR address */
-	MVS_P0_VSR_DATA		= 0x1E4, /* port0 VSR data */
-	MVS_P4_VSR_ADDR		= 0x250, /* port 4 VSR addr */
-	MVS_P4_VSR_DATA		= 0x254, /* port 4 VSR data */
-};
-
-enum hw_register_bits {
-	/* MVS_GBL_CTL */
-	INT_EN			= (1U << 1),	/* Global int enable */
-	HBA_RST			= (1U << 0),	/* HBA reset */
-
-	/* MVS_GBL_INT_STAT */
-	INT_XOR			= (1U << 4),	/* XOR engine event */
-	INT_SAS_SATA		= (1U << 0),	/* SAS/SATA event */
-
-	/* MVS_GBL_PORT_TYPE */			/* shl for ports 1-3 */
-	SATA_TARGET		= (1U << 16),	/* port0 SATA target enable */
-	MODE_AUTO_DET_PORT7 = (1U << 15),	/* port0 SAS/SATA autodetect */
-	MODE_AUTO_DET_PORT6 = (1U << 14),
-	MODE_AUTO_DET_PORT5 = (1U << 13),
-	MODE_AUTO_DET_PORT4 = (1U << 12),
-	MODE_AUTO_DET_PORT3 = (1U << 11),
-	MODE_AUTO_DET_PORT2 = (1U << 10),
-	MODE_AUTO_DET_PORT1 = (1U << 9),
-	MODE_AUTO_DET_PORT0 = (1U << 8),
-	MODE_AUTO_DET_EN    =	MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 |
-				MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 |
-				MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 |
-				MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7,
-	MODE_SAS_PORT7_MASK = (1U << 7),  /* port0 SAS(1), SATA(0) mode */
-	MODE_SAS_PORT6_MASK = (1U << 6),
-	MODE_SAS_PORT5_MASK = (1U << 5),
-	MODE_SAS_PORT4_MASK = (1U << 4),
-	MODE_SAS_PORT3_MASK = (1U << 3),
-	MODE_SAS_PORT2_MASK = (1U << 2),
-	MODE_SAS_PORT1_MASK = (1U << 1),
-	MODE_SAS_PORT0_MASK = (1U << 0),
-	MODE_SAS_SATA	=	MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK |
-				MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK |
-				MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK |
-				MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK,
-
-				/* SAS_MODE value may be
-				 * dictated (in hw) by values
-				 * of SATA_TARGET & AUTO_DET
-				 */
-
-	/* MVS_TX_CFG */
-	TX_EN			= (1U << 16),	/* Enable TX */
-	TX_RING_SZ_MASK		= 0xfff,	/* TX ring size, bits 11:0 */
-
-	/* MVS_RX_CFG */
-	RX_EN			= (1U << 16),	/* Enable RX */
-	RX_RING_SZ_MASK		= 0xfff,	/* RX ring size, bits 11:0 */
-
-	/* MVS_INT_COAL */
-	COAL_EN			= (1U << 16),	/* Enable int coalescing */
-
-	/* MVS_INT_STAT, MVS_INT_MASK */
-	CINT_I2C		= (1U << 31),	/* I2C event */
-	CINT_SW0		= (1U << 30),	/* software event 0 */
-	CINT_SW1		= (1U << 29),	/* software event 1 */
-	CINT_PRD_BC		= (1U << 28),	/* PRD BC err for read cmd */
-	CINT_DMA_PCIE		= (1U << 27),	/* DMA to PCIE timeout */
-	CINT_MEM		= (1U << 26),	/* int mem parity err */
-	CINT_I2C_SLAVE		= (1U << 25),	/* slave I2C event */
-	CINT_SRS		= (1U << 3),	/* SRS event */
-	CINT_CI_STOP		= (1U << 1),	/* cmd issue stopped */
-	CINT_DONE		= (1U << 0),	/* cmd completion */
-
-						/* shl for ports 1-3 */
-	CINT_PORT_STOPPED	= (1U << 16),	/* port0 stopped */
-	CINT_PORT		= (1U << 8),	/* port0 event */
-	CINT_PORT_MASK_OFFSET	= 8,
-	CINT_PORT_MASK		= (0xFF << CINT_PORT_MASK_OFFSET),
-
-	/* TX (delivery) ring bits */
-	TXQ_CMD_SHIFT		= 29,
-	TXQ_CMD_SSP		= 1,		/* SSP protocol */
-	TXQ_CMD_SMP		= 2,		/* SMP protocol */
-	TXQ_CMD_STP		= 3,		/* STP/SATA protocol */
-	TXQ_CMD_SSP_FREE_LIST	= 4,		/* add to SSP targ free list */
-	TXQ_CMD_SLOT_RESET	= 7,		/* reset command slot */
-	TXQ_MODE_I		= (1U << 28),	/* mode: 0=target,1=initiator */
-	TXQ_PRIO_HI		= (1U << 27),	/* priority: 0=normal, 1=high */
-	TXQ_SRS_SHIFT		= 20,		/* SATA register set */
-	TXQ_SRS_MASK		= 0x7f,
-	TXQ_PHY_SHIFT		= 12,		/* PHY bitmap */
-	TXQ_PHY_MASK		= 0xff,
-	TXQ_SLOT_MASK		= 0xfff,	/* slot number */
-
-	/* RX (completion) ring bits */
-	RXQ_GOOD		= (1U << 23),	/* Response good */
-	RXQ_SLOT_RESET		= (1U << 21),	/* Slot reset complete */
-	RXQ_CMD_RX		= (1U << 20),	/* target cmd received */
-	RXQ_ATTN		= (1U << 19),	/* attention */
-	RXQ_RSP			= (1U << 18),	/* response frame xfer'd */
-	RXQ_ERR			= (1U << 17),	/* err info rec xfer'd */
-	RXQ_DONE		= (1U << 16),	/* cmd complete */
-	RXQ_SLOT_MASK		= 0xfff,	/* slot number */
-
-	/* mvs_cmd_hdr bits */
-	MCH_PRD_LEN_SHIFT	= 16,		/* 16-bit PRD table len */
-	MCH_SSP_FR_TYPE_SHIFT	= 13,		/* SSP frame type */
-
-						/* SSP initiator only */
-	MCH_SSP_FR_CMD		= 0x0,		/* COMMAND frame */
-
-						/* SSP initiator or target */
-	MCH_SSP_FR_TASK		= 0x1,		/* TASK frame */
-
-						/* SSP target only */
-	MCH_SSP_FR_XFER_RDY	= 0x4,		/* XFER_RDY frame */
-	MCH_SSP_FR_RESP		= 0x5,		/* RESPONSE frame */
-	MCH_SSP_FR_READ		= 0x6,		/* Read DATA frame(s) */
-	MCH_SSP_FR_READ_RESP	= 0x7,		/* ditto, plus RESPONSE */
-
-	MCH_PASSTHRU		= (1U << 12),	/* pass-through (SSP) */
-	MCH_FBURST		= (1U << 11),	/* first burst (SSP) */
-	MCH_CHK_LEN		= (1U << 10),	/* chk xfer len (SSP) */
-	MCH_RETRY		= (1U << 9),	/* tport layer retry (SSP) */
-	MCH_PROTECTION		= (1U << 8),	/* protection info rec (SSP) */
-	MCH_RESET		= (1U << 7),	/* Reset (STP/SATA) */
-	MCH_FPDMA		= (1U << 6),	/* First party DMA (STP/SATA) */
-	MCH_ATAPI		= (1U << 5),	/* ATAPI (STP/SATA) */
-	MCH_BIST		= (1U << 4),	/* BIST activate (STP/SATA) */
-	MCH_PMP_MASK		= 0xf,		/* PMP from cmd FIS (STP/SATA)*/
-
-	CCTL_RST		= (1U << 5),	/* port logic reset */
-
-						/* 0(LSB first), 1(MSB first) */
-	CCTL_ENDIAN_DATA	= (1U << 3),	/* PRD data */
-	CCTL_ENDIAN_RSP		= (1U << 2),	/* response frame */
-	CCTL_ENDIAN_OPEN	= (1U << 1),	/* open address frame */
-	CCTL_ENDIAN_CMD		= (1U << 0),	/* command table */
-
-	/* MVS_Px_SER_CTLSTAT (per-phy control) */
-	PHY_SSP_RST		= (1U << 3),	/* reset SSP link layer */
-	PHY_BCAST_CHG		= (1U << 2),	/* broadcast(change) notif */
-	PHY_RST_HARD		= (1U << 1),	/* hard reset + phy reset */
-	PHY_RST			= (1U << 0),	/* phy reset */
-	PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8),
-	PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12),
-	PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16),
-	PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
-			(0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
-	PHY_READY_MASK		= (1U << 20),
-
-	/* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */
-	PHYEV_DEC_ERR		= (1U << 24),	/* Phy Decoding Error */
-	PHYEV_UNASSOC_FIS	= (1U << 19),	/* unassociated FIS rx'd */
-	PHYEV_AN		= (1U << 18),	/* SATA async notification */
-	PHYEV_BIST_ACT		= (1U << 17),	/* BIST activate FIS */
-	PHYEV_SIG_FIS		= (1U << 16),	/* signature FIS */
-	PHYEV_POOF		= (1U << 12),	/* phy ready from 1 -> 0 */
-	PHYEV_IU_BIG		= (1U << 11),	/* IU too long err */
-	PHYEV_IU_SMALL		= (1U << 10),	/* IU too short err */
-	PHYEV_UNK_TAG		= (1U << 9),	/* unknown tag */
-	PHYEV_BROAD_CH		= (1U << 8),	/* broadcast(CHANGE) */
-	PHYEV_COMWAKE		= (1U << 7),	/* COMWAKE rx'd */
-	PHYEV_PORT_SEL		= (1U << 6),	/* port selector present */
-	PHYEV_HARD_RST		= (1U << 5),	/* hard reset rx'd */
-	PHYEV_ID_TMOUT		= (1U << 4),	/* identify timeout */
-	PHYEV_ID_FAIL		= (1U << 3),	/* identify failed */
-	PHYEV_ID_DONE		= (1U << 2),	/* identify done */
-	PHYEV_HARD_RST_DONE	= (1U << 1),	/* hard reset done */
-	PHYEV_RDY_CH		= (1U << 0),	/* phy ready changed state */
-
-	/* MVS_PCS */
-	PCS_EN_SATA_REG_SHIFT	= (16),		/* Enable SATA Register Set */
-	PCS_EN_PORT_XMT_SHIFT	= (12),		/* Enable Port Transmit */
-	PCS_EN_PORT_XMT_SHIFT2	= (8),		/* For 6480 */
-	PCS_SATA_RETRY		= (1U << 8),	/* retry ctl FIS on R_ERR */
-	PCS_RSP_RX_EN		= (1U << 7),	/* raw response rx */
-	PCS_SELF_CLEAR		= (1U << 5),	/* self-clearing int mode */
-	PCS_FIS_RX_EN		= (1U << 4),	/* FIS rx enable */
-	PCS_CMD_STOP_ERR	= (1U << 3),	/* cmd stop-on-err enable */
-	PCS_CMD_RST		= (1U << 1),	/* reset cmd issue */
-	PCS_CMD_EN		= (1U << 0),	/* enable cmd issue */
-
-	/* Port n Attached Device Info */
-	PORT_DEV_SSP_TRGT	= (1U << 19),
-	PORT_DEV_SMP_TRGT	= (1U << 18),
-	PORT_DEV_STP_TRGT	= (1U << 17),
-	PORT_DEV_SSP_INIT	= (1U << 11),
-	PORT_DEV_SMP_INIT	= (1U << 10),
-	PORT_DEV_STP_INIT	= (1U << 9),
-	PORT_PHY_ID_MASK	= (0xFFU << 24),
-	PORT_DEV_TRGT_MASK	= (0x7U << 17),
-	PORT_DEV_INIT_MASK	= (0x7U << 9),
-	PORT_DEV_TYPE_MASK	= (0x7U << 0),
-
-	/* Port n PHY Status */
-	PHY_RDY			= (1U << 2),
-	PHY_DW_SYNC		= (1U << 1),
-	PHY_OOB_DTCTD		= (1U << 0),
-
-	/* VSR */
-	/* PHYMODE 6 (CDB) */
-	PHY_MODE6_LATECLK	= (1U << 29),	/* Lock Clock */
-	PHY_MODE6_DTL_SPEED	= (1U << 27),	/* Digital Loop Speed */
-	PHY_MODE6_FC_ORDER	= (1U << 26),	/* Fibre Channel Mode Order*/
-	PHY_MODE6_MUCNT_EN	= (1U << 24),	/* u Count Enable */
-	PHY_MODE6_SEL_MUCNT_LEN	= (1U << 22),	/* Training Length Select */
-	PHY_MODE6_SELMUPI	= (1U << 20),	/* Phase Multi Select (init) */
-	PHY_MODE6_SELMUPF	= (1U << 18),	/* Phase Multi Select (final) */
-	PHY_MODE6_SELMUFF	= (1U << 16),	/* Freq Loop Multi Sel(final) */
-	PHY_MODE6_SELMUFI	= (1U << 14),	/* Freq Loop Multi Sel(init) */
-	PHY_MODE6_FREEZE_LOOP	= (1U << 12),	/* Freeze Rx CDR Loop */
-	PHY_MODE6_INT_RXFOFFS	= (1U << 3),	/* Rx CDR Freq Loop Enable */
-	PHY_MODE6_FRC_RXFOFFS	= (1U << 2),	/* Initial Rx CDR Offset */
-	PHY_MODE6_STAU_0D8	= (1U << 1),	/* Rx CDR Freq Loop Saturate */
-	PHY_MODE6_RXSAT_DIS	= (1U << 0),	/* Saturate Ctl */
-};
-
-enum mvs_info_flags {
-	MVF_MSI			= (1U << 0),	/* MSI is enabled */
-	MVF_PHY_PWR_FIX		= (1U << 1),	/* bug workaround */
-};
-
-enum sas_cmd_port_registers {
-	CMD_CMRST_OOB_DET	= 0x100, /* COMRESET OOB detect register */
-	CMD_CMWK_OOB_DET	= 0x104, /* COMWAKE OOB detect register */
-	CMD_CMSAS_OOB_DET	= 0x108, /* COMSAS OOB detect register */
-	CMD_BRST_OOB_DET	= 0x10c, /* burst OOB detect register */
-	CMD_OOB_SPACE		= 0x110, /* OOB space control register */
-	CMD_OOB_BURST		= 0x114, /* OOB burst control register */
-	CMD_PHY_TIMER		= 0x118, /* PHY timer control register */
-	CMD_PHY_CONFIG0		= 0x11c, /* PHY config register 0 */
-	CMD_PHY_CONFIG1		= 0x120, /* PHY config register 1 */
-	CMD_SAS_CTL0		= 0x124, /* SAS control register 0 */
-	CMD_SAS_CTL1		= 0x128, /* SAS control register 1 */
-	CMD_SAS_CTL2		= 0x12c, /* SAS control register 2 */
-	CMD_SAS_CTL3		= 0x130, /* SAS control register 3 */
-	CMD_ID_TEST		= 0x134, /* ID test register */
-	CMD_PL_TIMER		= 0x138, /* PL timer register */
-	CMD_WD_TIMER		= 0x13c, /* WD timer register */
-	CMD_PORT_SEL_COUNT	= 0x140, /* port selector count register */
-	CMD_APP_MEM_CTL		= 0x144, /* Application Memory Control */
-	CMD_XOR_MEM_CTL		= 0x148, /* XOR Block Memory Control */
-	CMD_DMA_MEM_CTL		= 0x14c, /* DMA Block Memory Control */
-	CMD_PORT_MEM_CTL0	= 0x150, /* Port Memory Control 0 */
-	CMD_PORT_MEM_CTL1	= 0x154, /* Port Memory Control 1 */
-	CMD_SATA_PORT_MEM_CTL0	= 0x158, /* SATA Port Memory Control 0 */
-	CMD_SATA_PORT_MEM_CTL1	= 0x15c, /* SATA Port Memory Control 1 */
-	CMD_XOR_MEM_BIST_CTL	= 0x160, /* XOR Memory BIST Control */
-	CMD_XOR_MEM_BIST_STAT	= 0x164, /* XOR Memroy BIST Status */
-	CMD_DMA_MEM_BIST_CTL	= 0x168, /* DMA Memory BIST Control */
-	CMD_DMA_MEM_BIST_STAT	= 0x16c, /* DMA Memory BIST Status */
-	CMD_PORT_MEM_BIST_CTL	= 0x170, /* Port Memory BIST Control */
-	CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */
-	CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */
-	CMD_STP_MEM_BIST_CTL	= 0x17c, /* STP Memory BIST Control */
-	CMD_STP_MEM_BIST_STAT0	= 0x180, /* STP Memory BIST Status 0 */
-	CMD_STP_MEM_BIST_STAT1	= 0x184, /* STP Memory BIST Status 1 */
-	CMD_RESET_COUNT		= 0x188, /* Reset Count */
-	CMD_MONTR_DATA_SEL	= 0x18C, /* Monitor Data/Select */
-	CMD_PLL_PHY_CONFIG	= 0x190, /* PLL/PHY Configuration */
-	CMD_PHY_CTL		= 0x194, /* PHY Control and Status */
-	CMD_PHY_TEST_COUNT0	= 0x198, /* Phy Test Count 0 */
-	CMD_PHY_TEST_COUNT1	= 0x19C, /* Phy Test Count 1 */
-	CMD_PHY_TEST_COUNT2	= 0x1A0, /* Phy Test Count 2 */
-	CMD_APP_ERR_CONFIG	= 0x1A4, /* Application Error Configuration */
-	CMD_PND_FIFO_CTL0	= 0x1A8, /* Pending FIFO Control 0 */
-	CMD_HOST_CTL		= 0x1AC, /* Host Control Status */
-	CMD_HOST_WR_DATA	= 0x1B0, /* Host Write Data */
-	CMD_HOST_RD_DATA	= 0x1B4, /* Host Read Data */
-	CMD_PHY_MODE_21		= 0x1B8, /* Phy Mode 21 */
-	CMD_SL_MODE0		= 0x1BC, /* SL Mode 0 */
-	CMD_SL_MODE1		= 0x1C0, /* SL Mode 1 */
-	CMD_PND_FIFO_CTL1	= 0x1C4, /* Pending FIFO Control 1 */
-};
-
-/* SAS/SATA configuration port registers, aka phy registers */
-enum sas_sata_config_port_regs {
-	PHYR_IDENTIFY		= 0x00,	/* info for IDENTIFY frame */
-	PHYR_ADDR_LO		= 0x04,	/* my SAS address (low) */
-	PHYR_ADDR_HI		= 0x08,	/* my SAS address (high) */
-	PHYR_ATT_DEV_INFO	= 0x0C,	/* attached device info */
-	PHYR_ATT_ADDR_LO	= 0x10,	/* attached dev SAS addr (low) */
-	PHYR_ATT_ADDR_HI	= 0x14,	/* attached dev SAS addr (high) */
-	PHYR_SATA_CTL		= 0x18,	/* SATA control */
-	PHYR_PHY_STAT		= 0x1C,	/* PHY status */
-	PHYR_SATA_SIG0		= 0x20,	/*port SATA signature FIS(Byte 0-3) */
-	PHYR_SATA_SIG1		= 0x24,	/*port SATA signature FIS(Byte 4-7) */
-	PHYR_SATA_SIG2		= 0x28,	/*port SATA signature FIS(Byte 8-11) */
-	PHYR_SATA_SIG3		= 0x2c,	/*port SATA signature FIS(Byte 12-15) */
-	PHYR_R_ERR_COUNT	= 0x30, /* port R_ERR count register */
-	PHYR_CRC_ERR_COUNT	= 0x34, /* port CRC error count register */
-	PHYR_WIDE_PORT		= 0x38,	/* wide port participating */
-	PHYR_CURRENT0		= 0x80,	/* current connection info 0 */
-	PHYR_CURRENT1		= 0x84,	/* current connection info 1 */
-	PHYR_CURRENT2		= 0x88,	/* current connection info 2 */
-};
-
-/*  SAS/SATA Vendor Specific Port Registers */
-enum sas_sata_vsp_regs {
-	VSR_PHY_STAT		= 0x00, /* Phy Status */
-	VSR_PHY_MODE1		= 0x01, /* phy tx */
-	VSR_PHY_MODE2		= 0x02, /* tx scc */
-	VSR_PHY_MODE3		= 0x03, /* pll */
-	VSR_PHY_MODE4		= 0x04, /* VCO */
-	VSR_PHY_MODE5		= 0x05, /* Rx */
-	VSR_PHY_MODE6		= 0x06, /* CDR */
-	VSR_PHY_MODE7		= 0x07, /* Impedance */
-	VSR_PHY_MODE8		= 0x08, /* Voltage */
-	VSR_PHY_MODE9		= 0x09, /* Test */
-	VSR_PHY_MODE10		= 0x0A, /* Power */
-	VSR_PHY_MODE11		= 0x0B, /* Phy Mode */
-	VSR_PHY_VS0		= 0x0C, /* Vednor Specific 0 */
-	VSR_PHY_VS1		= 0x0D, /* Vednor Specific 1 */
-};
-
-enum pci_cfg_registers {
-	PCR_PHY_CTL	= 0x40,
-	PCR_PHY_CTL2	= 0x90,
-	PCR_DEV_CTRL	= 0xE8,
-};
-
-enum pci_cfg_register_bits {
-	PCTL_PWR_ON	= (0xFU << 24),
-	PCTL_OFF	= (0xFU << 12),
-	PRD_REQ_SIZE	= (0x4000),
-	PRD_REQ_MASK	= (0x00007000),
-};
-
-enum nvram_layout_offsets {
-	NVR_SIG		= 0x00,		/* 0xAA, 0x55 */
-	NVR_SAS_ADDR	= 0x02,		/* 8-byte SAS address */
-};
-
-enum chip_flavors {
-	chip_6320,
-	chip_6440,
-	chip_6480,
-};
-
-enum port_type {
-	PORT_TYPE_SAS	=  (1L << 1),
-	PORT_TYPE_SATA	=  (1L << 0),
-};
-
-/* Command Table Format */
-enum ct_format {
-	/* SSP */
-	SSP_F_H		=  0x00,
-	SSP_F_IU	=  0x18,
-	SSP_F_MAX	=  0x4D,
-	/* STP */
-	STP_CMD_FIS	=  0x00,
-	STP_ATAPI_CMD	=  0x40,
-	STP_F_MAX	=  0x10,
-	/* SMP */
-	SMP_F_T		=  0x00,
-	SMP_F_DEP	=  0x01,
-	SMP_F_MAX	=  0x101,
-};
-
-enum status_buffer {
-	SB_EIR_OFF	=  0x00,	/* Error Information Record */
-	SB_RFB_OFF	=  0x08,	/* Response Frame Buffer */
-	SB_RFB_MAX	=  0x400,	/* RFB size*/
-};
-
-enum error_info_rec {
-	CMD_ISS_STPD	= (1U << 31),	/* Cmd Issue Stopped */
-	CMD_PI_ERR	= (1U << 30),	/* Protection info error.  see flags2 */
-	RSP_OVER	= (1U << 29),	/* rsp buffer overflow */
-	RETRY_LIM	= (1U << 28),	/* FIS/frame retry limit exceeded */
-	UNK_FIS 	= (1U << 27),	/* unknown FIS */
-	DMA_TERM	= (1U << 26),	/* DMA terminate primitive rx'd */
-	SYNC_ERR	= (1U << 25),	/* SYNC rx'd during frame xmit */
-	TFILE_ERR	= (1U << 24),	/* SATA taskfile Error bit set */
-	R_ERR		= (1U << 23),	/* SATA returned R_ERR prim */
-	RD_OFS		= (1U << 20),	/* Read DATA frame invalid offset */
-	XFER_RDY_OFS	= (1U << 19),	/* XFER_RDY offset error */
-	UNEXP_XFER_RDY	= (1U << 18),	/* unexpected XFER_RDY error */
-	DATA_OVER_UNDER = (1U << 16),	/* data overflow/underflow */
-	INTERLOCK	= (1U << 15),	/* interlock error */
-	NAK		= (1U << 14),	/* NAK rx'd */
-	ACK_NAK_TO	= (1U << 13),	/* ACK/NAK timeout */
-	CXN_CLOSED	= (1U << 12),	/* cxn closed w/out ack/nak */
-	OPEN_TO 	= (1U << 11),	/* I_T nexus lost, open cxn timeout */
-	PATH_BLOCKED	= (1U << 10),	/* I_T nexus lost, pathway blocked */
-	NO_DEST 	= (1U << 9),	/* I_T nexus lost, no destination */
-	STP_RES_BSY	= (1U << 8),	/* STP resources busy */
-	BREAK		= (1U << 7),	/* break received */
-	BAD_DEST	= (1U << 6),	/* bad destination */
-	BAD_PROTO	= (1U << 5),	/* protocol not supported */
-	BAD_RATE	= (1U << 4),	/* cxn rate not supported */
-	WRONG_DEST	= (1U << 3),	/* wrong destination error */
-	CREDIT_TO	= (1U << 2),	/* credit timeout */
-	WDOG_TO 	= (1U << 1),	/* watchdog timeout */
-	BUF_PAR 	= (1U << 0),	/* buffer parity error */
-};
-
-enum error_info_rec_2 {
-	SLOT_BSY_ERR	= (1U << 31),	/* Slot Busy Error */
-	GRD_CHK_ERR	= (1U << 14),	/* Guard Check Error */
-	APP_CHK_ERR	= (1U << 13),	/* Application Check error */
-	REF_CHK_ERR	= (1U << 12),	/* Reference Check Error */
-	USR_BLK_NM	= (1U << 0),	/* User Block Number */
-};
-
-struct mvs_chip_info {
-	u32		n_phy;
-	u32		srs_sz;
-	u32		slot_width;
-};
-
-struct mvs_err_info {
-	__le32			flags;
-	__le32			flags2;
-};
-
-struct mvs_prd {
-	__le64			addr;		/* 64-bit buffer address */
-	__le32			reserved;
-	__le32			len;		/* 16-bit length */
-};
-
-struct mvs_cmd_hdr {
-	__le32			flags;		/* PRD tbl len; SAS, SATA ctl */
-	__le32			lens;		/* cmd, max resp frame len */
-	__le32			tags;		/* targ port xfer tag; tag */
-	__le32			data_len;	/* data xfer len */
-	__le64			cmd_tbl;	/* command table address */
-	__le64			open_frame;	/* open addr frame address */
-	__le64			status_buf;	/* status buffer address */
-	__le64			prd_tbl;	/* PRD tbl address */
-	__le32			reserved[4];
-};
-
-struct mvs_port {
-	struct asd_sas_port	sas_port;
-	u8			port_attached;
-	u8			taskfileset;
-	u8			wide_port_phymap;
-	struct list_head	list;
-};
-
-struct mvs_phy {
-	struct mvs_port		*port;
-	struct asd_sas_phy	sas_phy;
-	struct sas_identify	identify;
-	struct scsi_device	*sdev;
-	u64		dev_sas_addr;
-	u64		att_dev_sas_addr;
-	u32		att_dev_info;
-	u32		dev_info;
-	u32		phy_type;
-	u32		phy_status;
-	u32		irq_status;
-	u32		frame_rcvd_size;
-	u8		frame_rcvd[32];
-	u8		phy_attached;
-	enum sas_linkrate	minimum_linkrate;
-	enum sas_linkrate	maximum_linkrate;
-};
-
-struct mvs_slot_info {
-	struct list_head	list;
-	struct sas_task		*task;
-	u32			n_elem;
-	u32			tx;
-
-	/* DMA buffer for storing cmd tbl, open addr frame, status buffer,
-	 * and PRD table
-	 */
-	void			*buf;
-	dma_addr_t		buf_dma;
-#if _MV_DUMP
-	u32			cmd_size;
-#endif
-
-	void			*response;
-	struct mvs_port		*port;
-};
-
-struct mvs_info {
-	unsigned long		flags;
-
-	spinlock_t		lock;		/* host-wide lock */
-	struct pci_dev		*pdev;		/* our device */
-	void __iomem		*regs;		/* enhanced mode registers */
-	void __iomem		*peri_regs;	/* peripheral registers */
-
-	u8			sas_addr[SAS_ADDR_SIZE];
-	struct sas_ha_struct	sas;		/* SCSI/SAS glue */
-	struct Scsi_Host	*shost;
-
-	__le32			*tx;		/* TX (delivery) DMA ring */
-	dma_addr_t		tx_dma;
-	u32			tx_prod;	/* cached next-producer idx */
-
-	__le32			*rx;		/* RX (completion) DMA ring */
-	dma_addr_t		rx_dma;
-	u32			rx_cons;	/* RX consumer idx */
-
-	__le32			*rx_fis;	/* RX'd FIS area */
-	dma_addr_t		rx_fis_dma;
-
-	struct mvs_cmd_hdr	*slot;	/* DMA command header slots */
-	dma_addr_t		slot_dma;
-
-	const struct mvs_chip_info *chip;
-
-	u8			tags[MVS_SLOTS];
-	struct mvs_slot_info	slot_info[MVS_SLOTS];
-				/* further per-slot information */
-	struct mvs_phy		phy[MVS_MAX_PHYS];
-	struct mvs_port		port[MVS_MAX_PHYS];
-#ifdef MVS_USE_TASKLET
-	struct tasklet_struct	tasklet;
-#endif
-};
-
-static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
-			   void *funcdata);
-static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port);
-static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val);
-static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port);
-static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val);
-static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val);
-static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port);
-
-static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i);
-static void mvs_detect_porttype(struct mvs_info *mvi, int i);
-static void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
-static void mvs_release_task(struct mvs_info *mvi, int phy_no);
-
-static int mvs_scan_finished(struct Scsi_Host *, unsigned long);
-static void mvs_scan_start(struct Scsi_Host *);
-static int mvs_slave_configure(struct scsi_device *sdev);
-
-static struct scsi_transport_template *mvs_stt;
-
-static const struct mvs_chip_info mvs_chips[] = {
-	[chip_6320] =		{ 2, 16, 9  },
-	[chip_6440] =		{ 4, 16, 9  },
-	[chip_6480] =		{ 8, 32, 10 },
-};
-
-static struct scsi_host_template mvs_sht = {
-	.module			= THIS_MODULE,
-	.name			= DRV_NAME,
-	.queuecommand		= sas_queuecommand,
-	.target_alloc		= sas_target_alloc,
-	.slave_configure	= mvs_slave_configure,
-	.slave_destroy		= sas_slave_destroy,
-	.scan_finished		= mvs_scan_finished,
-	.scan_start		= mvs_scan_start,
-	.change_queue_depth	= sas_change_queue_depth,
-	.change_queue_type	= sas_change_queue_type,
-	.bios_param		= sas_bios_param,
-	.can_queue		= 1,
-	.cmd_per_lun		= 1,
-	.this_id		= -1,
-	.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	= sas_eh_bus_reset_handler,
-	.slave_alloc		= sas_slave_alloc,
-	.target_destroy		= sas_target_destroy,
-	.ioctl			= sas_ioctl,
-};
-
-static void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
-{
-	u32 i;
-	u32 run;
-	u32 offset;
-
-	offset = 0;
-	while (size) {
-		printk("%08X : ", baseaddr + offset);
-		if (size >= 16)
-			run = 16;
-		else
-			run = size;
-		size -= run;
-		for (i = 0; i < 16; i++) {
-			if (i < run)
-				printk("%02X ", (u32)data[i]);
-			else
-				printk("   ");
-		}
-		printk(": ");
-		for (i = 0; i < run; i++)
-			printk("%c", isalnum(data[i]) ? data[i] : '.');
-		printk("\n");
-		data = &data[16];
-		offset += run;
-	}
-	printk("\n");
-}
-
-#if _MV_DUMP
-static void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
-				   enum sas_protocol proto)
-{
-	u32 offset;
-	struct pci_dev *pdev = mvi->pdev;
-	struct mvs_slot_info *slot = &mvi->slot_info[tag];
-
-	offset = slot->cmd_size + MVS_OAF_SZ +
-	    sizeof(struct mvs_prd) * slot->n_elem;
-	dev_printk(KERN_DEBUG, &pdev->dev, "+---->Status buffer[%d] :\n",
-			tag);
-	mvs_hexdump(32, (u8 *) slot->response,
-		    (u32) slot->buf_dma + offset);
-}
-#endif
-
-static void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag,
-				enum sas_protocol proto)
-{
-#if _MV_DUMP
-	u32 sz, w_ptr;
-	u64 addr;
-	void __iomem *regs = mvi->regs;
-	struct pci_dev *pdev = mvi->pdev;
-	struct mvs_slot_info *slot = &mvi->slot_info[tag];
-
-	/*Delivery Queue */
-	sz = mr32(TX_CFG) & TX_RING_SZ_MASK;
-	w_ptr = slot->tx;
-	addr = mr32(TX_HI) << 16 << 16 | mr32(TX_LO);
-	dev_printk(KERN_DEBUG, &pdev->dev,
-		"Delivery Queue Size=%04d , WRT_PTR=%04X\n", sz, w_ptr);
-	dev_printk(KERN_DEBUG, &pdev->dev,
-		"Delivery Queue Base Address=0x%llX (PA)"
-		"(tx_dma=0x%llX), Entry=%04d\n",
-		addr, mvi->tx_dma, w_ptr);
-	mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]),
-			(u32) mvi->tx_dma + sizeof(u32) * w_ptr);
-	/*Command List */
-	addr = mvi->slot_dma;
-	dev_printk(KERN_DEBUG, &pdev->dev,
-		"Command List Base Address=0x%llX (PA)"
-		"(slot_dma=0x%llX), Header=%03d\n",
-		addr, slot->buf_dma, tag);
-	dev_printk(KERN_DEBUG, &pdev->dev, "Command Header[%03d]:\n", tag);
-	/*mvs_cmd_hdr */
-	mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]),
-		(u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr));
-	/*1.command table area */
-	dev_printk(KERN_DEBUG, &pdev->dev, "+---->Command Table :\n");
-	mvs_hexdump(slot->cmd_size, (u8 *) slot->buf, (u32) slot->buf_dma);
-	/*2.open address frame area */
-	dev_printk(KERN_DEBUG, &pdev->dev, "+---->Open Address Frame :\n");
-	mvs_hexdump(MVS_OAF_SZ, (u8 *) slot->buf + slot->cmd_size,
-				(u32) slot->buf_dma + slot->cmd_size);
-	/*3.status buffer */
-	mvs_hba_sb_dump(mvi, tag, proto);
-	/*4.PRD table */
-	dev_printk(KERN_DEBUG, &pdev->dev, "+---->PRD table :\n");
-	mvs_hexdump(sizeof(struct mvs_prd) * slot->n_elem,
-		(u8 *) slot->buf + slot->cmd_size + MVS_OAF_SZ,
-		(u32) slot->buf_dma + slot->cmd_size + MVS_OAF_SZ);
-#endif
-}
-
-static void mvs_hba_cq_dump(struct mvs_info *mvi)
-{
-#if (_MV_DUMP > 2)
-	u64 addr;
-	void __iomem *regs = mvi->regs;
-	struct pci_dev *pdev = mvi->pdev;
-	u32 entry = mvi->rx_cons + 1;
-	u32 rx_desc = le32_to_cpu(mvi->rx[entry]);
-
-	/*Completion Queue */
-	addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO);
-	dev_printk(KERN_DEBUG, &pdev->dev, "Completion Task = 0x%p\n",
-		   mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task);
-	dev_printk(KERN_DEBUG, &pdev->dev,
-		"Completion List Base Address=0x%llX (PA), "
-		"CQ_Entry=%04d, CQ_WP=0x%08X\n",
-		addr, entry - 1, mvi->rx[0]);
-	mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc),
-		    mvi->rx_dma + sizeof(u32) * entry);
-#endif
-}
-
-static void mvs_hba_interrupt_enable(struct mvs_info *mvi)
-{
-	void __iomem *regs = mvi->regs;
-	u32 tmp;
-
-	tmp = mr32(GBL_CTL);
-
-	mw32(GBL_CTL, tmp | INT_EN);
-}
-
-static void mvs_hba_interrupt_disable(struct mvs_info *mvi)
-{
-	void __iomem *regs = mvi->regs;
-	u32 tmp;
-
-	tmp = mr32(GBL_CTL);
-
-	mw32(GBL_CTL, tmp & ~INT_EN);
-}
-
-static int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
-
-/* move to PCI layer or libata core? */
-static int pci_go_64(struct pci_dev *pdev)
-{
-	int rc;
-
-	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
-		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
-		if (rc) {
-			rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-			if (rc) {
-				dev_printk(KERN_ERR, &pdev->dev,
-					   "64-bit DMA enable failed\n");
-				return rc;
-			}
-		}
-	} else {
-		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-		if (rc) {
-			dev_printk(KERN_ERR, &pdev->dev,
-				   "32-bit DMA enable failed\n");
-			return rc;
-		}
-		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-		if (rc) {
-			dev_printk(KERN_ERR, &pdev->dev,
-				   "32-bit consistent DMA enable failed\n");
-			return rc;
-		}
-	}
-
-	return rc;
-}
-
-static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag)
-{
-	if (task->lldd_task) {
-		struct mvs_slot_info *slot;
-		slot = (struct mvs_slot_info *) task->lldd_task;
-		*tag = slot - mvi->slot_info;
-		return 1;
-	}
-	return 0;
-}
-
-static void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
-{
-	void *bitmap = (void *) &mvi->tags;
-	clear_bit(tag, bitmap);
-}
-
-static void mvs_tag_free(struct mvs_info *mvi, u32 tag)
-{
-	mvs_tag_clear(mvi, tag);
-}
-
-static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
-{
-	void *bitmap = (void *) &mvi->tags;
-	set_bit(tag, bitmap);
-}
-
-static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
-{
-	unsigned int index, tag;
-	void *bitmap = (void *) &mvi->tags;
-
-	index = find_first_zero_bit(bitmap, MVS_SLOTS);
-	tag = index;
-	if (tag >= MVS_SLOTS)
-		return -SAS_QUEUE_FULL;
-	mvs_tag_set(mvi, tag);
-	*tag_out = tag;
-	return 0;
-}
-
-static void mvs_tag_init(struct mvs_info *mvi)
-{
-	int i;
-	for (i = 0; i < MVS_SLOTS; ++i)
-		mvs_tag_clear(mvi, i);
-}
-
-#ifndef MVS_DISABLE_NVRAM
-static int mvs_eep_read(void __iomem *regs, u32 addr, u32 *data)
-{
-	int timeout = 1000;
-
-	if (addr & ~SPI_ADDR_MASK)
-		return -EINVAL;
-
-	writel(addr, regs + SPI_CMD);
-	writel(TWSI_RD, regs + SPI_CTL);
-
-	while (timeout-- > 0) {
-		if (readl(regs + SPI_CTL) & TWSI_RDY) {
-			*data = readl(regs + SPI_DATA);
-			return 0;
-		}
-
-		udelay(10);
-	}
-
-	return -EBUSY;
-}
-
-static int mvs_eep_read_buf(void __iomem *regs, u32 addr,
-			    void *buf, u32 buflen)
-{
-	u32 addr_end, tmp_addr, i, j;
-	u32 tmp = 0;
-	int rc;
-	u8 *tmp8, *buf8 = buf;
-
-	addr_end = addr + buflen;
-	tmp_addr = ALIGN(addr, 4);
-	if (addr > 0xff)
-		return -EINVAL;
-
-	j = addr & 0x3;
-	if (j) {
-		rc = mvs_eep_read(regs, tmp_addr, &tmp);
-		if (rc)
-			return rc;
-
-		tmp8 = (u8 *)&tmp;
-		for (i = j; i < 4; i++)
-			*buf8++ = tmp8[i];
-
-		tmp_addr += 4;
-	}
-
-	for (j = ALIGN(addr_end, 4); tmp_addr < j; tmp_addr += 4) {
-		rc = mvs_eep_read(regs, tmp_addr, &tmp);
-		if (rc)
-			return rc;
-
-		memcpy(buf8, &tmp, 4);
-		buf8 += 4;
-	}
-
-	if (tmp_addr < addr_end) {
-		rc = mvs_eep_read(regs, tmp_addr, &tmp);
-		if (rc)
-			return rc;
-
-		tmp8 = (u8 *)&tmp;
-		j = addr_end - tmp_addr;
-		for (i = 0; i < j; i++)
-			*buf8++ = tmp8[i];
-
-		tmp_addr += 4;
-	}
-
-	return 0;
-}
-#endif
-
-static int mvs_nvram_read(struct mvs_info *mvi, u32 addr,
-			  void *buf, u32 buflen)
-{
-#ifndef MVS_DISABLE_NVRAM
-	void __iomem *regs = mvi->regs;
-	int rc, i;
-	u32 sum;
-	u8 hdr[2], *tmp;
-	const char *msg;
-
-	rc = mvs_eep_read_buf(regs, addr, &hdr, 2);
-	if (rc) {
-		msg = "nvram hdr read failed";
-		goto err_out;
-	}
-	rc = mvs_eep_read_buf(regs, addr + 2, buf, buflen);
-	if (rc) {
-		msg = "nvram read failed";
-		goto err_out;
-	}
-
-	if (hdr[0] != 0x5A) {
-		/* entry id */
-		msg = "invalid nvram entry id";
-		rc = -ENOENT;
-		goto err_out;
-	}
-
-	tmp = buf;
-	sum = ((u32)hdr[0]) + ((u32)hdr[1]);
-	for (i = 0; i < buflen; i++)
-		sum += ((u32)tmp[i]);
-
-	if (sum) {
-		msg = "nvram checksum failure";
-		rc = -EILSEQ;
-		goto err_out;
-	}
-
-	return 0;
-
-err_out:
-	dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
-	return rc;
-#else
-	/* FIXME , For SAS target mode */
-	memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
-	return 0;
-#endif
-}
-
-static void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
-{
-	struct mvs_phy *phy = &mvi->phy[i];
-	struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
-
-	if (!phy->phy_attached)
-		return;
-
-	if (sas_phy->phy) {
-		struct sas_phy *sphy = sas_phy->phy;
-
-		sphy->negotiated_linkrate = sas_phy->linkrate;
-		sphy->minimum_linkrate = phy->minimum_linkrate;
-		sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
-		sphy->maximum_linkrate = phy->maximum_linkrate;
-		sphy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
-	}
-
-	if (phy->phy_type & PORT_TYPE_SAS) {
-		struct sas_identify_frame *id;
-
-		id = (struct sas_identify_frame *)phy->frame_rcvd;
-		id->dev_type = phy->identify.device_type;
-		id->initiator_bits = SAS_PROTOCOL_ALL;
-		id->target_bits = phy->identify.target_port_protocols;
-	} else if (phy->phy_type & PORT_TYPE_SATA) {
-		/* TODO */
-	}
-	mvi->sas.sas_phy[i]->frame_rcvd_size = phy->frame_rcvd_size;
-	mvi->sas.notify_port_event(mvi->sas.sas_phy[i],
-				   PORTE_BYTES_DMAED);
-}
-
-static int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
-{
-	/* 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);
-	return 1;
-}
-
-static void mvs_scan_start(struct Scsi_Host *shost)
-{
-	int i;
-	struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha;
-
-	for (i = 0; i < mvi->chip->n_phy; ++i) {
-		mvs_bytes_dmaed(mvi, i);
-	}
-}
-
-static int mvs_slave_configure(struct scsi_device *sdev)
-{
-	struct domain_device *dev = sdev_to_domain_dev(sdev);
-	int ret = sas_slave_configure(sdev);
-
-	if (ret)
-		return ret;
-
-	if (dev_is_sata(dev)) {
-		/* struct ata_port *ap = dev->sata_dev.ap; */
-		/* struct ata_device *adev = ap->link.device; */
-
-		/* clamp at no NCQ for the time being */
-		/* adev->flags |= ATA_DFLAG_NCQ_OFF; */
-		scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1);
-	}
-	return 0;
-}
-
-static void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
-{
-	struct pci_dev *pdev = mvi->pdev;
-	struct sas_ha_struct *sas_ha = &mvi->sas;
-	struct mvs_phy *phy = &mvi->phy[phy_no];
-	struct asd_sas_phy *sas_phy = &phy->sas_phy;
-
-	phy->irq_status = mvs_read_port_irq_stat(mvi, phy_no);
-	/*
-	* events is port event now ,
-	* we need check the interrupt status which belongs to per port.
-	*/
-	dev_printk(KERN_DEBUG, &pdev->dev,
-		"Port %d Event = %X\n",
-		phy_no, phy->irq_status);
-
-	if (phy->irq_status & (PHYEV_POOF | PHYEV_DEC_ERR)) {
-		mvs_release_task(mvi, phy_no);
-		if (!mvs_is_phy_ready(mvi, phy_no)) {
-			sas_phy_disconnected(sas_phy);
-			sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
-			dev_printk(KERN_INFO, &pdev->dev,
-				"Port %d Unplug Notice\n", phy_no);
-
-		} else
-			mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, NULL);
-	}
-	if (!(phy->irq_status & PHYEV_DEC_ERR)) {
-		if (phy->irq_status & PHYEV_COMWAKE) {
-			u32 tmp = mvs_read_port_irq_mask(mvi, phy_no);
-			mvs_write_port_irq_mask(mvi, phy_no,
-						tmp | PHYEV_SIG_FIS);
-		}
-		if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) {
-			phy->phy_status = mvs_is_phy_ready(mvi, phy_no);
-			if (phy->phy_status) {
-				mvs_detect_porttype(mvi, phy_no);
-
-				if (phy->phy_type & PORT_TYPE_SATA) {
-					u32 tmp = mvs_read_port_irq_mask(mvi,
-								phy_no);
-					tmp &= ~PHYEV_SIG_FIS;
-					mvs_write_port_irq_mask(mvi,
-								phy_no, tmp);
-				}
-
-				mvs_update_phyinfo(mvi, phy_no, 0);
-				sas_ha->notify_phy_event(sas_phy,
-							PHYE_OOB_DONE);
-				mvs_bytes_dmaed(mvi, phy_no);
-			} else {
-				dev_printk(KERN_DEBUG, &pdev->dev,
-					"plugin interrupt but phy is gone\n");
-				mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET,
-							NULL);
-			}
-		} else if (phy->irq_status & PHYEV_BROAD_CH) {
-			mvs_release_task(mvi, phy_no);
-			sas_ha->notify_port_event(sas_phy,
-						PORTE_BROADCAST_RCVD);
-		}
-	}
-	mvs_write_port_irq_stat(mvi, phy_no, phy->irq_status);
-}
-
-static void mvs_int_sata(struct mvs_info *mvi)
-{
-	u32 tmp;
-	void __iomem *regs = mvi->regs;
-	tmp = mr32(INT_STAT_SRS);
-	mw32(INT_STAT_SRS, tmp & 0xFFFF);
-}
-
-static void mvs_slot_reset(struct mvs_info *mvi, struct sas_task *task,
-				u32 slot_idx)
-{
-	void __iomem *regs = mvi->regs;
-	struct domain_device *dev = task->dev;
-	struct asd_sas_port *sas_port = dev->port;
-	struct mvs_port *port = mvi->slot_info[slot_idx].port;
-	u32 reg_set, phy_mask;
-
-	if (!sas_protocol_ata(task->task_proto)) {
-		reg_set = 0;
-		phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap :
-				sas_port->phy_mask;
-	} else {
-		reg_set = port->taskfileset;
-		phy_mask = sas_port->phy_mask;
-	}
-	mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | slot_idx |
-					(TXQ_CMD_SLOT_RESET << TXQ_CMD_SHIFT) |
-					(phy_mask << TXQ_PHY_SHIFT) |
-					(reg_set << TXQ_SRS_SHIFT));
-
-	mw32(TX_PROD_IDX, mvi->tx_prod);
-	mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
-}
-
-static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
-			u32 slot_idx, int err)
-{
-	struct mvs_port *port = mvi->slot_info[slot_idx].port;
-	struct task_status_struct *tstat = &task->task_status;
-	struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf;
-	int stat = SAM_GOOD;
-
-	resp->frame_len = sizeof(struct dev_to_host_fis);
-	memcpy(&resp->ending_fis[0],
-	       SATA_RECEIVED_D2H_FIS(port->taskfileset),
-	       sizeof(struct dev_to_host_fis));
-	tstat->buf_valid_size = sizeof(*resp);
-	if (unlikely(err))
-		stat = SAS_PROTO_RESPONSE;
-	return stat;
-}
-
-static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
-{
-	u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
-	mvs_tag_clear(mvi, slot_idx);
-}
-
-static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
-			  struct mvs_slot_info *slot, u32 slot_idx)
-{
-	if (!sas_protocol_ata(task->task_proto))
-		if (slot->n_elem)
-			pci_unmap_sg(mvi->pdev, task->scatter,
-				     slot->n_elem, task->data_dir);
-
-	switch (task->task_proto) {
-	case SAS_PROTOCOL_SMP:
-		pci_unmap_sg(mvi->pdev, &task->smp_task.smp_resp, 1,
-			     PCI_DMA_FROMDEVICE);
-		pci_unmap_sg(mvi->pdev, &task->smp_task.smp_req, 1,
-			     PCI_DMA_TODEVICE);
-		break;
-
-	case SAS_PROTOCOL_SATA:
-	case SAS_PROTOCOL_STP:
-	case SAS_PROTOCOL_SSP:
-	default:
-		/* do nothing */
-		break;
-	}
-	list_del(&slot->list);
-	task->lldd_task = NULL;
-	slot->task = NULL;
-	slot->port = NULL;
-}
-
-static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
-			 u32 slot_idx)
-{
-	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
-	u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response));
-	u32 err_dw1 = le32_to_cpu(*(u32 *) (slot->response + 4));
-	int stat = SAM_CHECK_COND;
-
-	if (err_dw1 & SLOT_BSY_ERR) {
-		stat = SAS_QUEUE_FULL;
-		mvs_slot_reset(mvi, task, slot_idx);
-	}
-	switch (task->task_proto) {
-	case SAS_PROTOCOL_SSP:
-		break;
-	case SAS_PROTOCOL_SMP:
-		break;
-	case SAS_PROTOCOL_SATA:
-	case SAS_PROTOCOL_STP:
-	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
-		if (err_dw0 & TFILE_ERR)
-			stat = mvs_sata_done(mvi, task, slot_idx, 1);
-		break;
-	default:
-		break;
-	}
-
-	mvs_hexdump(16, (u8 *) slot->response, 0);
-	return stat;
-}
-
-static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
-{
-	u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
-	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
-	struct sas_task *task = slot->task;
-	struct task_status_struct *tstat;
-	struct mvs_port *port;
-	bool aborted;
-	void *to;
-
-	if (unlikely(!task || !task->lldd_task))
-		return -1;
-
-	mvs_hba_cq_dump(mvi);
-
-	spin_lock(&task->task_state_lock);
-	aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
-	if (!aborted) {
-		task->task_state_flags &=
-		    ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
-		task->task_state_flags |= SAS_TASK_STATE_DONE;
-	}
-	spin_unlock(&task->task_state_lock);
-
-	if (aborted) {
-		mvs_slot_task_free(mvi, task, slot, slot_idx);
-		mvs_slot_free(mvi, rx_desc);
-		return -1;
-	}
-
-	port = slot->port;
-	tstat = &task->task_status;
-	memset(tstat, 0, sizeof(*tstat));
-	tstat->resp = SAS_TASK_COMPLETE;
-
-	if (unlikely(!port->port_attached || flags)) {
-		mvs_slot_err(mvi, task, slot_idx);
-		if (!sas_protocol_ata(task->task_proto))
-			tstat->stat = SAS_PHY_DOWN;
-		goto out;
-	}
-
-	/* error info record present */
-	if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
-		tstat->stat = mvs_slot_err(mvi, task, slot_idx);
-		goto out;
-	}
-
-	switch (task->task_proto) {
-	case SAS_PROTOCOL_SSP:
-		/* hw says status == 0, datapres == 0 */
-		if (rx_desc & RXQ_GOOD) {
-			tstat->stat = SAM_GOOD;
-			tstat->resp = SAS_TASK_COMPLETE;
-		}
-		/* response frame present */
-		else if (rx_desc & RXQ_RSP) {
-			struct ssp_response_iu *iu =
-			    slot->response + sizeof(struct mvs_err_info);
-			sas_ssp_task_response(&mvi->pdev->dev, task, iu);
-		}
-
-		/* should never happen? */
-		else
-			tstat->stat = SAM_CHECK_COND;
-		break;
-
-	case SAS_PROTOCOL_SMP: {
-			struct scatterlist *sg_resp = &task->smp_task.smp_resp;
-			tstat->stat = SAM_GOOD;
-			to = kmap_atomic(sg_page(sg_resp), KM_IRQ0);
-			memcpy(to + sg_resp->offset,
-				slot->response + sizeof(struct mvs_err_info),
-				sg_dma_len(sg_resp));
-			kunmap_atomic(to, KM_IRQ0);
-			break;
-		}
-
-	case SAS_PROTOCOL_SATA:
-	case SAS_PROTOCOL_STP:
-	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: {
-			tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0);
-			break;
-		}
-
-	default:
-		tstat->stat = SAM_CHECK_COND;
-		break;
-	}
-
-out:
-	mvs_slot_task_free(mvi, task, slot, slot_idx);
-	if (unlikely(tstat->stat != SAS_QUEUE_FULL))
-		mvs_slot_free(mvi, rx_desc);
-
-	spin_unlock(&mvi->lock);
-	task->task_done(task);
-	spin_lock(&mvi->lock);
-	return tstat->stat;
-}
-
-static void mvs_release_task(struct mvs_info *mvi, int phy_no)
-{
-	struct list_head *pos, *n;
-	struct mvs_slot_info *slot;
-	struct mvs_phy *phy = &mvi->phy[phy_no];
-	struct mvs_port *port = phy->port;
-	u32 rx_desc;
-
-	if (!port)
-		return;
-
-	list_for_each_safe(pos, n, &port->list) {
-		slot = container_of(pos, struct mvs_slot_info, list);
-		rx_desc = (u32) (slot - mvi->slot_info);
-		mvs_slot_complete(mvi, rx_desc, 1);
-	}
-}
-
-static void mvs_int_full(struct mvs_info *mvi)
-{
-	void __iomem *regs = mvi->regs;
-	u32 tmp, stat;
-	int i;
-
-	stat = mr32(INT_STAT);
-
-	mvs_int_rx(mvi, false);
-
-	for (i = 0; i < MVS_MAX_PORTS; i++) {
-		tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED);
-		if (tmp)
-			mvs_int_port(mvi, i, tmp);
-	}
-
-	if (stat & CINT_SRS)
-		mvs_int_sata(mvi);
-
-	mw32(INT_STAT, stat);
-}
-
-static int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
-{
-	void __iomem *regs = mvi->regs;
-	u32 rx_prod_idx, rx_desc;
-	bool attn = false;
-	struct pci_dev *pdev = mvi->pdev;
-
-	/* the first dword in the RX ring is special: it contains
-	 * a mirror of the hardware's RX producer index, so that
-	 * we don't have to stall the CPU reading that register.
-	 * The actual RX ring is offset by one dword, due to this.
-	 */
-	rx_prod_idx = mvi->rx_cons;
-	mvi->rx_cons = le32_to_cpu(mvi->rx[0]);
-	if (mvi->rx_cons == 0xfff)	/* h/w hasn't touched RX ring yet */
-		return 0;
-
-	/* The CMPL_Q may come late, read from register and try again
-	* note: if coalescing is enabled,
-	* it will need to read from register every time for sure
-	*/
-	if (mvi->rx_cons == rx_prod_idx)
-		mvi->rx_cons = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK;
-
-	if (mvi->rx_cons == rx_prod_idx)
-		return 0;
-
-	while (mvi->rx_cons != rx_prod_idx) {
-
-		/* increment our internal RX consumer pointer */
-		rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1);
-
-		rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]);
-
-		if (likely(rx_desc & RXQ_DONE))
-			mvs_slot_complete(mvi, rx_desc, 0);
-		if (rx_desc & RXQ_ATTN) {
-			attn = true;
-			dev_printk(KERN_DEBUG, &pdev->dev, "ATTN %X\n",
-				rx_desc);
-		} else if (rx_desc & RXQ_ERR) {
-			if (!(rx_desc & RXQ_DONE))
-				mvs_slot_complete(mvi, rx_desc, 0);
-			dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR %X\n",
-				rx_desc);
-		} else if (rx_desc & RXQ_SLOT_RESET) {
-			dev_printk(KERN_DEBUG, &pdev->dev, "Slot reset[%X]\n",
-				rx_desc);
-			mvs_slot_free(mvi, rx_desc);
-		}
-	}
-
-	if (attn && self_clear)
-		mvs_int_full(mvi);
-
-	return 0;
-}
-
-#ifdef MVS_USE_TASKLET
-static void mvs_tasklet(unsigned long data)
-{
-	struct mvs_info *mvi = (struct mvs_info *) data;
-	unsigned long flags;
-
-	spin_lock_irqsave(&mvi->lock, flags);
-
-#ifdef MVS_DISABLE_MSI
-	mvs_int_full(mvi);
-#else
-	mvs_int_rx(mvi, true);
-#endif
-	spin_unlock_irqrestore(&mvi->lock, flags);
-}
-#endif
-
-static irqreturn_t mvs_interrupt(int irq, void *opaque)
-{
-	struct mvs_info *mvi = opaque;
-	void __iomem *regs = mvi->regs;
-	u32 stat;
-
-	stat = mr32(GBL_INT_STAT);
-
-	if (stat == 0 || stat == 0xffffffff)
-		return IRQ_NONE;
-
-	/* clear CMD_CMPLT ASAP */
-	mw32_f(INT_STAT, CINT_DONE);
-
-#ifndef MVS_USE_TASKLET
-	spin_lock(&mvi->lock);
-
-	mvs_int_full(mvi);
-
-	spin_unlock(&mvi->lock);
-#else
-	tasklet_schedule(&mvi->tasklet);
-#endif
-	return IRQ_HANDLED;
-}
-
-#ifndef MVS_DISABLE_MSI
-static irqreturn_t mvs_msi_interrupt(int irq, void *opaque)
-{
-	struct mvs_info *mvi = opaque;
-
-#ifndef MVS_USE_TASKLET
-	spin_lock(&mvi->lock);
-
-	mvs_int_rx(mvi, true);
-
-	spin_unlock(&mvi->lock);
-#else
-	tasklet_schedule(&mvi->tasklet);
-#endif
-	return IRQ_HANDLED;
-}
-#endif
-
-struct mvs_task_exec_info {
-	struct sas_task *task;
-	struct mvs_cmd_hdr *hdr;
-	struct mvs_port *port;
-	u32 tag;
-	int n_elem;
-};
-
-static int mvs_task_prep_smp(struct mvs_info *mvi,
-			     struct mvs_task_exec_info *tei)
-{
-	int elem, rc, i;
-	struct sas_task *task = tei->task;
-	struct mvs_cmd_hdr *hdr = tei->hdr;
-	struct scatterlist *sg_req, *sg_resp;
-	u32 req_len, resp_len, tag = tei->tag;
-	void *buf_tmp;
-	u8 *buf_oaf;
-	dma_addr_t buf_tmp_dma;
-	struct mvs_prd *buf_prd;
-	struct scatterlist *sg;
-	struct mvs_slot_info *slot = &mvi->slot_info[tag];
-	struct asd_sas_port *sas_port = task->dev->port;
-	u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
-#if _MV_DUMP
-	u8 *buf_cmd;
-	void *from;
-#endif
-	/*
-	 * DMA-map SMP request, response buffers
-	 */
-	sg_req = &task->smp_task.smp_req;
-	elem = pci_map_sg(mvi->pdev, sg_req, 1, PCI_DMA_TODEVICE);
-	if (!elem)
-		return -ENOMEM;
-	req_len = sg_dma_len(sg_req);
-
-	sg_resp = &task->smp_task.smp_resp;
-	elem = pci_map_sg(mvi->pdev, sg_resp, 1, PCI_DMA_FROMDEVICE);
-	if (!elem) {
-		rc = -ENOMEM;
-		goto err_out;
-	}
-	resp_len = sg_dma_len(sg_resp);
-
-	/* must be in dwords */
-	if ((req_len & 0x3) || (resp_len & 0x3)) {
-		rc = -EINVAL;
-		goto err_out_2;
-	}
-
-	/*
-	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
-	 */
-
-	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
-	buf_tmp = slot->buf;
-	buf_tmp_dma = slot->buf_dma;
-
-#if _MV_DUMP
-	buf_cmd = buf_tmp;
-	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
-	buf_tmp += req_len;
-	buf_tmp_dma += req_len;
-	slot->cmd_size = req_len;
-#else
-	hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
-#endif
-
-	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
-	buf_oaf = buf_tmp;
-	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
-
-	buf_tmp += MVS_OAF_SZ;
-	buf_tmp_dma += MVS_OAF_SZ;
-
-	/* region 3: PRD table ********************************************* */
-	buf_prd = buf_tmp;
-	if (tei->n_elem)
-		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
-	else
-		hdr->prd_tbl = 0;
-
-	i = sizeof(struct mvs_prd) * tei->n_elem;
-	buf_tmp += i;
-	buf_tmp_dma += i;
-
-	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
-	slot->response = buf_tmp;
-	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
-
-	/*
-	 * Fill in TX ring and command slot header
-	 */
-	slot->tx = mvi->tx_prod;
-	mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
-					TXQ_MODE_I | tag |
-					(sas_port->phy_mask << TXQ_PHY_SHIFT));
-
-	hdr->flags |= flags;
-	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4));
-	hdr->tags = cpu_to_le32(tag);
-	hdr->data_len = 0;
-
-	/* generate open address frame hdr (first 12 bytes) */
-	buf_oaf[0] = (1 << 7) | (0 << 4) | 0x01; /* initiator, SMP, ftype 1h */
-	buf_oaf[1] = task->dev->linkrate & 0xf;
-	*(u16 *)(buf_oaf + 2) = 0xFFFF;		/* SAS SPEC */
-	memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
-
-	/* fill in PRD (scatter/gather) table, if any */
-	for_each_sg(task->scatter, sg, tei->n_elem, i) {
-		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
-		buf_prd->len = cpu_to_le32(sg_dma_len(sg));
-		buf_prd++;
-	}
-
-#if _MV_DUMP
-	/* copy cmd table */
-	from = kmap_atomic(sg_page(sg_req), KM_IRQ0);
-	memcpy(buf_cmd, from + sg_req->offset, req_len);
-	kunmap_atomic(from, KM_IRQ0);
-#endif
-	return 0;
-
-err_out_2:
-	pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_resp, 1,
-		     PCI_DMA_FROMDEVICE);
-err_out:
-	pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_req, 1,
-		     PCI_DMA_TODEVICE);
-	return rc;
-}
-
-static void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
-{
-	void __iomem *regs = mvi->regs;
-	u32 tmp, offs;
-	u8 *tfs = &port->taskfileset;
-
-	if (*tfs == MVS_ID_NOT_MAPPED)
-		return;
-
-	offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT);
-	if (*tfs < 16) {
-		tmp = mr32(PCS);
-		mw32(PCS, tmp & ~offs);
-	} else {
-		tmp = mr32(CTL);
-		mw32(CTL, tmp & ~offs);
-	}
-
-	tmp = mr32(INT_STAT_SRS) & (1U << *tfs);
-	if (tmp)
-		mw32(INT_STAT_SRS, tmp);
-
-	*tfs = MVS_ID_NOT_MAPPED;
-}
-
-static u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
-{
-	int i;
-	u32 tmp, offs;
-	void __iomem *regs = mvi->regs;
-
-	if (port->taskfileset != MVS_ID_NOT_MAPPED)
-		return 0;
-
-	tmp = mr32(PCS);
-
-	for (i = 0; i < mvi->chip->srs_sz; i++) {
-		if (i == 16)
-			tmp = mr32(CTL);
-		offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT);
-		if (!(tmp & offs)) {
-			port->taskfileset = i;
-
-			if (i < 16)
-				mw32(PCS, tmp | offs);
-			else
-				mw32(CTL, tmp | offs);
-			tmp = mr32(INT_STAT_SRS) & (1U << i);
-			if (tmp)
-				mw32(INT_STAT_SRS, tmp);
-			return 0;
-		}
-	}
-	return MVS_ID_NOT_MAPPED;
-}
-
-static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag)
-{
-	struct ata_queued_cmd *qc = task->uldd_task;
-
-	if (qc) {
-		if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
-			qc->tf.command == ATA_CMD_FPDMA_READ) {
-			*tag = qc->tag;
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-static int mvs_task_prep_ata(struct mvs_info *mvi,
-			     struct mvs_task_exec_info *tei)
-{
-	struct sas_task *task = tei->task;
-	struct domain_device *dev = task->dev;
-	struct mvs_cmd_hdr *hdr = tei->hdr;
-	struct asd_sas_port *sas_port = dev->port;
-	struct mvs_slot_info *slot;
-	struct scatterlist *sg;
-	struct mvs_prd *buf_prd;
-	struct mvs_port *port = tei->port;
-	u32 tag = tei->tag;
-	u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
-	void *buf_tmp;
-	u8 *buf_cmd, *buf_oaf;
-	dma_addr_t buf_tmp_dma;
-	u32 i, req_len, resp_len;
-	const u32 max_resp_len = SB_RFB_MAX;
-
-	if (mvs_assign_reg_set(mvi, port) == MVS_ID_NOT_MAPPED)
-		return -EBUSY;
-
-	slot = &mvi->slot_info[tag];
-	slot->tx = mvi->tx_prod;
-	mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
-					(TXQ_CMD_STP << TXQ_CMD_SHIFT) |
-					(sas_port->phy_mask << TXQ_PHY_SHIFT) |
-					(port->taskfileset << TXQ_SRS_SHIFT));
-
-	if (task->ata_task.use_ncq)
-		flags |= MCH_FPDMA;
-	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
-		if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI)
-			flags |= MCH_ATAPI;
-	}
-
-	/* FIXME: fill in port multiplier number */
-
-	hdr->flags = cpu_to_le32(flags);
-
-	/* FIXME: the low order order 5 bits for the TAG if enable NCQ */
-	if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr->tags))
-		task->ata_task.fis.sector_count |= hdr->tags << 3;
-	else
-		hdr->tags = cpu_to_le32(tag);
-	hdr->data_len = cpu_to_le32(task->total_xfer_len);
-
-	/*
-	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
-	 */
-
-	/* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
-	buf_cmd = buf_tmp = slot->buf;
-	buf_tmp_dma = slot->buf_dma;
-
-	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
-
-	buf_tmp += MVS_ATA_CMD_SZ;
-	buf_tmp_dma += MVS_ATA_CMD_SZ;
-#if _MV_DUMP
-	slot->cmd_size = MVS_ATA_CMD_SZ;
-#endif
-
-	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
-	/* used for STP.  unused for SATA? */
-	buf_oaf = buf_tmp;
-	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
-
-	buf_tmp += MVS_OAF_SZ;
-	buf_tmp_dma += MVS_OAF_SZ;
-
-	/* region 3: PRD table ********************************************* */
-	buf_prd = buf_tmp;
-	if (tei->n_elem)
-		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
-	else
-		hdr->prd_tbl = 0;
-
-	i = sizeof(struct mvs_prd) * tei->n_elem;
-	buf_tmp += i;
-	buf_tmp_dma += i;
-
-	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
-	/* FIXME: probably unused, for SATA.  kept here just in case
-	 * we get a STP/SATA error information record
-	 */
-	slot->response = buf_tmp;
-	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
-
-	req_len = sizeof(struct host_to_dev_fis);
-	resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
-	    sizeof(struct mvs_err_info) - i;
-
-	/* request, response lengths */
-	resp_len = min(resp_len, max_resp_len);
-	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
-
-	task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
-	/* fill in command FIS and ATAPI CDB */
-	memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
-	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
-		memcpy(buf_cmd + STP_ATAPI_CMD,
-			task->ata_task.atapi_packet, 16);
-
-	/* generate open address frame hdr (first 12 bytes) */
-	buf_oaf[0] = (1 << 7) | (2 << 4) | 0x1;	/* initiator, STP, ftype 1h */
-	buf_oaf[1] = task->dev->linkrate & 0xf;
-	*(u16 *)(buf_oaf + 2) = cpu_to_be16(tag);
-	memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
-
-	/* fill in PRD (scatter/gather) table, if any */
-	for_each_sg(task->scatter, sg, tei->n_elem, i) {
-		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
-		buf_prd->len = cpu_to_le32(sg_dma_len(sg));
-		buf_prd++;
-	}
-
-	return 0;
-}
-
-static int mvs_task_prep_ssp(struct mvs_info *mvi,
-			     struct mvs_task_exec_info *tei)
-{
-	struct sas_task *task = tei->task;
-	struct mvs_cmd_hdr *hdr = tei->hdr;
-	struct mvs_port *port = tei->port;
-	struct mvs_slot_info *slot;
-	struct scatterlist *sg;
-	struct mvs_prd *buf_prd;
-	struct ssp_frame_hdr *ssp_hdr;
-	void *buf_tmp;
-	u8 *buf_cmd, *buf_oaf, fburst = 0;
-	dma_addr_t buf_tmp_dma;
-	u32 flags;
-	u32 resp_len, req_len, i, tag = tei->tag;
-	const u32 max_resp_len = SB_RFB_MAX;
-	u8 phy_mask;
-
-	slot = &mvi->slot_info[tag];
-
-	phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap :
-		task->dev->port->phy_mask;
-	slot->tx = mvi->tx_prod;
-	mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
-				(TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
-				(phy_mask << TXQ_PHY_SHIFT));
-
-	flags = MCH_RETRY;
-	if (task->ssp_task.enable_first_burst) {
-		flags |= MCH_FBURST;
-		fburst = (1 << 7);
-	}
-	hdr->flags = cpu_to_le32(flags |
-				 (tei->n_elem << MCH_PRD_LEN_SHIFT) |
-				 (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT));
-
-	hdr->tags = cpu_to_le32(tag);
-	hdr->data_len = cpu_to_le32(task->total_xfer_len);
-
-	/*
-	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
-	 */
-
-	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
-	buf_cmd = buf_tmp = slot->buf;
-	buf_tmp_dma = slot->buf_dma;
-
-	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
-
-	buf_tmp += MVS_SSP_CMD_SZ;
-	buf_tmp_dma += MVS_SSP_CMD_SZ;
-#if _MV_DUMP
-	slot->cmd_size = MVS_SSP_CMD_SZ;
-#endif
-
-	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
-	buf_oaf = buf_tmp;
-	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
-
-	buf_tmp += MVS_OAF_SZ;
-	buf_tmp_dma += MVS_OAF_SZ;
-
-	/* region 3: PRD table ********************************************* */
-	buf_prd = buf_tmp;
-	if (tei->n_elem)
-		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
-	else
-		hdr->prd_tbl = 0;
-
-	i = sizeof(struct mvs_prd) * tei->n_elem;
-	buf_tmp += i;
-	buf_tmp_dma += i;
-
-	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
-	slot->response = buf_tmp;
-	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
-
-	resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
-	    sizeof(struct mvs_err_info) - i;
-	resp_len = min(resp_len, max_resp_len);
-
-	req_len = sizeof(struct ssp_frame_hdr) + 28;
-
-	/* request, response lengths */
-	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
-
-	/* generate open address frame hdr (first 12 bytes) */
-	buf_oaf[0] = (1 << 7) | (1 << 4) | 0x1;	/* initiator, SSP, ftype 1h */
-	buf_oaf[1] = task->dev->linkrate & 0xf;
-	*(u16 *)(buf_oaf + 2) = cpu_to_be16(tag);
-	memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
-
-	/* fill in SSP frame header (Command Table.SSP frame header) */
-	ssp_hdr = (struct ssp_frame_hdr *)buf_cmd;
-	ssp_hdr->frame_type = SSP_COMMAND;
-	memcpy(ssp_hdr->hashed_dest_addr, task->dev->hashed_sas_addr,
-	       HASHED_SAS_ADDR_SIZE);
-	memcpy(ssp_hdr->hashed_src_addr,
-	       task->dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
-	ssp_hdr->tag = cpu_to_be16(tag);
-
-	/* fill in command frame IU */
-	buf_cmd += sizeof(*ssp_hdr);
-	memcpy(buf_cmd, &task->ssp_task.LUN, 8);
-	buf_cmd[9] = fburst | task->ssp_task.task_attr |
-			(task->ssp_task.task_prio << 3);
-	memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
-
-	/* fill in PRD (scatter/gather) table, if any */
-	for_each_sg(task->scatter, sg, tei->n_elem, i) {
-		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
-		buf_prd->len = cpu_to_le32(sg_dma_len(sg));
-		buf_prd++;
-	}
-
-	return 0;
-}
-
-static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
-{
-	struct domain_device *dev = task->dev;
-	struct mvs_info *mvi = dev->port->ha->lldd_ha;
-	struct pci_dev *pdev = mvi->pdev;
-	void __iomem *regs = mvi->regs;
-	struct mvs_task_exec_info tei;
-	struct sas_task *t = task;
-	struct mvs_slot_info *slot;
-	u32 tag = 0xdeadbeef, rc, n_elem = 0;
-	unsigned long flags;
-	u32 n = num, pass = 0;
-
-	spin_lock_irqsave(&mvi->lock, flags);
-	do {
-		dev = t->dev;
-		tei.port = &mvi->port[dev->port->id];
-
-		if (!tei.port->port_attached) {
-			if (sas_protocol_ata(t->task_proto)) {
-				rc = SAS_PHY_DOWN;
-				goto out_done;
-			} else {
-				struct task_status_struct *ts = &t->task_status;
-				ts->resp = SAS_TASK_UNDELIVERED;
-				ts->stat = SAS_PHY_DOWN;
-				t->task_done(t);
-				if (n > 1)
-					t = list_entry(t->list.next,
-							struct sas_task, list);
-				continue;
-			}
-		}
-
-		if (!sas_protocol_ata(t->task_proto)) {
-			if (t->num_scatter) {
-				n_elem = pci_map_sg(mvi->pdev, t->scatter,
-						    t->num_scatter,
-						    t->data_dir);
-				if (!n_elem) {
-					rc = -ENOMEM;
-					goto err_out;
-				}
-			}
-		} else {
-			n_elem = t->num_scatter;
-		}
-
-		rc = mvs_tag_alloc(mvi, &tag);
-		if (rc)
-			goto err_out;
-
-		slot = &mvi->slot_info[tag];
-		t->lldd_task = NULL;
-		slot->n_elem = n_elem;
-		memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
-		tei.task = t;
-		tei.hdr = &mvi->slot[tag];
-		tei.tag = tag;
-		tei.n_elem = n_elem;
-
-		switch (t->task_proto) {
-		case SAS_PROTOCOL_SMP:
-			rc = mvs_task_prep_smp(mvi, &tei);
-			break;
-		case SAS_PROTOCOL_SSP:
-			rc = mvs_task_prep_ssp(mvi, &tei);
-			break;
-		case SAS_PROTOCOL_SATA:
-		case SAS_PROTOCOL_STP:
-		case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
-			rc = mvs_task_prep_ata(mvi, &tei);
-			break;
-		default:
-			dev_printk(KERN_ERR, &pdev->dev,
-				"unknown sas_task proto: 0x%x\n",
-				t->task_proto);
-			rc = -EINVAL;
-			break;
-		}
-
-		if (rc)
-			goto err_out_tag;
-
-		slot->task = t;
-		slot->port = tei.port;
-		t->lldd_task = (void *) slot;
-		list_add_tail(&slot->list, &slot->port->list);
-		/* TODO: select normal or high priority */
-
-		spin_lock(&t->task_state_lock);
-		t->task_state_flags |= SAS_TASK_AT_INITIATOR;
-		spin_unlock(&t->task_state_lock);
-
-		mvs_hba_memory_dump(mvi, tag, t->task_proto);
-
-		++pass;
-		mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
-		if (n > 1)
-			t = list_entry(t->list.next, struct sas_task, list);
-	} while (--n);
-
-	rc = 0;
-	goto out_done;
-
-err_out_tag:
-	mvs_tag_free(mvi, tag);
-err_out:
-	dev_printk(KERN_ERR, &pdev->dev, "mvsas exec failed[%d]!\n", rc);
-	if (!sas_protocol_ata(t->task_proto))
-		if (n_elem)
-			pci_unmap_sg(mvi->pdev, t->scatter, n_elem,
-				     t->data_dir);
-out_done:
-	if (pass)
-		mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
-	spin_unlock_irqrestore(&mvi->lock, flags);
-	return rc;
-}
-
-static int mvs_task_abort(struct sas_task *task)
-{
-	int rc;
-	unsigned long flags;
-	struct mvs_info *mvi = task->dev->port->ha->lldd_ha;
-	struct pci_dev *pdev = mvi->pdev;
-	int tag;
-
-	spin_lock_irqsave(&task->task_state_lock, flags);
-	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
-		rc = TMF_RESP_FUNC_COMPLETE;
-		spin_unlock_irqrestore(&task->task_state_lock, flags);
-		goto out_done;
-	}
-	spin_unlock_irqrestore(&task->task_state_lock, flags);
-
-	switch (task->task_proto) {
-	case SAS_PROTOCOL_SMP:
-		dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! \n");
-		break;
-	case SAS_PROTOCOL_SSP:
-		dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! \n");
-		break;
-	case SAS_PROTOCOL_SATA:
-	case SAS_PROTOCOL_STP:
-	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:{
-		dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! \n");
-#if _MV_DUMP
-		dev_printk(KERN_DEBUG, &pdev->dev, "Dump D2H FIS: \n");
-		mvs_hexdump(sizeof(struct host_to_dev_fis),
-				(void *)&task->ata_task.fis, 0);
-		dev_printk(KERN_DEBUG, &pdev->dev, "Dump ATAPI Cmd : \n");
-		mvs_hexdump(16, task->ata_task.atapi_packet, 0);
-#endif
-		spin_lock_irqsave(&task->task_state_lock, flags);
-		if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) {
-			/* TODO */
-			;
-		}
-		spin_unlock_irqrestore(&task->task_state_lock, flags);
-		break;
-	}
-	default:
-		break;
-	}
-
-	if (mvs_find_tag(mvi, task, &tag)) {
-		spin_lock_irqsave(&mvi->lock, flags);
-		mvs_slot_task_free(mvi, task, &mvi->slot_info[tag], tag);
-		spin_unlock_irqrestore(&mvi->lock, flags);
-	}
-	if (!mvs_task_exec(task, 1, GFP_ATOMIC))
-		rc = TMF_RESP_FUNC_COMPLETE;
-	else
-		rc = TMF_RESP_FUNC_FAILED;
-out_done:
-	return rc;
-}
-
-static void mvs_free(struct mvs_info *mvi)
-{
-	int i;
-
-	if (!mvi)
-		return;
-
-	for (i = 0; i < MVS_SLOTS; i++) {
-		struct mvs_slot_info *slot = &mvi->slot_info[i];
-
-		if (slot->buf)
-			dma_free_coherent(&mvi->pdev->dev, MVS_SLOT_BUF_SZ,
-					  slot->buf, slot->buf_dma);
-	}
-
-	if (mvi->tx)
-		dma_free_coherent(&mvi->pdev->dev,
-				  sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
-				  mvi->tx, mvi->tx_dma);
-	if (mvi->rx_fis)
-		dma_free_coherent(&mvi->pdev->dev, MVS_RX_FISL_SZ,
-				  mvi->rx_fis, mvi->rx_fis_dma);
-	if (mvi->rx)
-		dma_free_coherent(&mvi->pdev->dev,
-				  sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1),
-				  mvi->rx, mvi->rx_dma);
-	if (mvi->slot)
-		dma_free_coherent(&mvi->pdev->dev,
-				  sizeof(*mvi->slot) * MVS_SLOTS,
-				  mvi->slot, mvi->slot_dma);
-#ifdef MVS_ENABLE_PERI
-	if (mvi->peri_regs)
-		iounmap(mvi->peri_regs);
-#endif
-	if (mvi->regs)
-		iounmap(mvi->regs);
-	if (mvi->shost)
-		scsi_host_put(mvi->shost);
-	kfree(mvi->sas.sas_port);
-	kfree(mvi->sas.sas_phy);
-	kfree(mvi);
-}
-
-/* FIXME: locking? */
-static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
-			   void *funcdata)
-{
-	struct mvs_info *mvi = sas_phy->ha->lldd_ha;
-	int rc = 0, phy_id = sas_phy->id;
-	u32 tmp;
-
-	tmp = mvs_read_phy_ctl(mvi, phy_id);
-
-	switch (func) {
-	case PHY_FUNC_SET_LINK_RATE:{
-			struct sas_phy_linkrates *rates = funcdata;
-			u32 lrmin = 0, lrmax = 0;
-
-			lrmin = (rates->minimum_linkrate << 8);
-			lrmax = (rates->maximum_linkrate << 12);
-
-			if (lrmin) {
-				tmp &= ~(0xf << 8);
-				tmp |= lrmin;
-			}
-			if (lrmax) {
-				tmp &= ~(0xf << 12);
-				tmp |= lrmax;
-			}
-			mvs_write_phy_ctl(mvi, phy_id, tmp);
-			break;
-		}
-
-	case PHY_FUNC_HARD_RESET:
-		if (tmp & PHY_RST_HARD)
-			break;
-		mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST_HARD);
-		break;
-
-	case PHY_FUNC_LINK_RESET:
-		mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST);
-		break;
-
-	case PHY_FUNC_DISABLE:
-	case PHY_FUNC_RELEASE_SPINUP_HOLD:
-	default:
-		rc = -EOPNOTSUPP;
-	}
-
-	return rc;
-}
-
-static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
-{
-	struct mvs_phy *phy = &mvi->phy[phy_id];
-	struct asd_sas_phy *sas_phy = &phy->sas_phy;
-
-	sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0;
-	sas_phy->class = SAS;
-	sas_phy->iproto = SAS_PROTOCOL_ALL;
-	sas_phy->tproto = 0;
-	sas_phy->type = PHY_TYPE_PHYSICAL;
-	sas_phy->role = PHY_ROLE_INITIATOR;
-	sas_phy->oob_mode = OOB_NOT_CONNECTED;
-	sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
-
-	sas_phy->id = phy_id;
-	sas_phy->sas_addr = &mvi->sas_addr[0];
-	sas_phy->frame_rcvd = &phy->frame_rcvd[0];
-	sas_phy->ha = &mvi->sas;
-	sas_phy->lldd_phy = phy;
-}
-
-static struct mvs_info *__devinit mvs_alloc(struct pci_dev *pdev,
-					    const struct pci_device_id *ent)
-{
-	struct mvs_info *mvi;
-	unsigned long res_start, res_len, res_flag;
-	struct asd_sas_phy **arr_phy;
-	struct asd_sas_port **arr_port;
-	const struct mvs_chip_info *chip = &mvs_chips[ent->driver_data];
-	int i;
-
-	/*
-	 * alloc and init our per-HBA mvs_info struct
-	 */
-
-	mvi = kzalloc(sizeof(*mvi), GFP_KERNEL);
-	if (!mvi)
-		return NULL;
-
-	spin_lock_init(&mvi->lock);
-#ifdef MVS_USE_TASKLET
-	tasklet_init(&mvi->tasklet, mvs_tasklet, (unsigned long)mvi);
-#endif
-	mvi->pdev = pdev;
-	mvi->chip = chip;
-
-	if (pdev->device == 0x6440 && pdev->revision == 0)
-		mvi->flags |= MVF_PHY_PWR_FIX;
-
-	/*
-	 * alloc and init SCSI, SAS glue
-	 */
-
-	mvi->shost = scsi_host_alloc(&mvs_sht, sizeof(void *));
-	if (!mvi->shost)
-		goto err_out;
-
-	arr_phy = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL);
-	arr_port = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL);
-	if (!arr_phy || !arr_port)
-		goto err_out;
-
-	for (i = 0; i < MVS_MAX_PHYS; i++) {
-		mvs_phy_init(mvi, i);
-		arr_phy[i] = &mvi->phy[i].sas_phy;
-		arr_port[i] = &mvi->port[i].sas_port;
-		mvi->port[i].taskfileset = MVS_ID_NOT_MAPPED;
-		mvi->port[i].wide_port_phymap = 0;
-		mvi->port[i].port_attached = 0;
-		INIT_LIST_HEAD(&mvi->port[i].list);
-	}
-
-	SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas;
-	mvi->shost->transportt = mvs_stt;
-	mvi->shost->max_id = 21;
-	mvi->shost->max_lun = ~0;
-	mvi->shost->max_channel = 0;
-	mvi->shost->max_cmd_len = 16;
-
-	mvi->sas.sas_ha_name = DRV_NAME;
-	mvi->sas.dev = &pdev->dev;
-	mvi->sas.lldd_module = THIS_MODULE;
-	mvi->sas.sas_addr = &mvi->sas_addr[0];
-	mvi->sas.sas_phy = arr_phy;
-	mvi->sas.sas_port = arr_port;
-	mvi->sas.num_phys = chip->n_phy;
-	mvi->sas.lldd_max_execute_num = 1;
-	mvi->sas.lldd_queue_size = MVS_QUEUE_SIZE;
-	mvi->shost->can_queue = MVS_CAN_QUEUE;
-	mvi->shost->cmd_per_lun = MVS_SLOTS / mvi->sas.num_phys;
-	mvi->sas.lldd_ha = mvi;
-	mvi->sas.core.shost = mvi->shost;
-
-	mvs_tag_init(mvi);
-
-	/*
-	 * ioremap main and peripheral registers
-	 */
-
-#ifdef MVS_ENABLE_PERI
-	res_start = pci_resource_start(pdev, 2);
-	res_len = pci_resource_len(pdev, 2);
-	if (!res_start || !res_len)
-		goto err_out;
-
-	mvi->peri_regs = ioremap_nocache(res_start, res_len);
-	if (!mvi->peri_regs)
-		goto err_out;
-#endif
-
-	res_start = pci_resource_start(pdev, 4);
-	res_len = pci_resource_len(pdev, 4);
-	if (!res_start || !res_len)
-		goto err_out;
-
-	res_flag = pci_resource_flags(pdev, 4);
-	if (res_flag & IORESOURCE_CACHEABLE)
-		mvi->regs = ioremap(res_start, res_len);
-	else
-		mvi->regs = ioremap_nocache(res_start, res_len);
-
-	if (!mvi->regs)
-		goto err_out;
-
-	/*
-	 * alloc and init our DMA areas
-	 */
-
-	mvi->tx = dma_alloc_coherent(&pdev->dev,
-				     sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
-				     &mvi->tx_dma, GFP_KERNEL);
-	if (!mvi->tx)
-		goto err_out;
-	memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ);
-
-	mvi->rx_fis = dma_alloc_coherent(&pdev->dev, MVS_RX_FISL_SZ,
-					 &mvi->rx_fis_dma, GFP_KERNEL);
-	if (!mvi->rx_fis)
-		goto err_out;
-	memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ);
-
-	mvi->rx = dma_alloc_coherent(&pdev->dev,
-				     sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1),
-				     &mvi->rx_dma, GFP_KERNEL);
-	if (!mvi->rx)
-		goto err_out;
-	memset(mvi->rx, 0, sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1));
-
-	mvi->rx[0] = cpu_to_le32(0xfff);
-	mvi->rx_cons = 0xfff;
-
-	mvi->slot = dma_alloc_coherent(&pdev->dev,
-				       sizeof(*mvi->slot) * MVS_SLOTS,
-				       &mvi->slot_dma, GFP_KERNEL);
-	if (!mvi->slot)
-		goto err_out;
-	memset(mvi->slot, 0, sizeof(*mvi->slot) * MVS_SLOTS);
-
-	for (i = 0; i < MVS_SLOTS; i++) {
-		struct mvs_slot_info *slot = &mvi->slot_info[i];
-
-		slot->buf = dma_alloc_coherent(&pdev->dev, MVS_SLOT_BUF_SZ,
-					       &slot->buf_dma, GFP_KERNEL);
-		if (!slot->buf)
-			goto err_out;
-		memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
-	}
-
-	/* finally, read NVRAM to get our SAS address */
-	if (mvs_nvram_read(mvi, NVR_SAS_ADDR, &mvi->sas_addr, 8))
-		goto err_out;
-	return mvi;
-
-err_out:
-	mvs_free(mvi);
-	return NULL;
-}
-
-static u32 mvs_cr32(void __iomem *regs, u32 addr)
-{
-	mw32(CMD_ADDR, addr);
-	return mr32(CMD_DATA);
-}
-
-static void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
-{
-	mw32(CMD_ADDR, addr);
-	mw32(CMD_DATA, val);
-}
-
-static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port)
-{
-	void __iomem *regs = mvi->regs;
-	return (port < 4)?mr32(P0_SER_CTLSTAT + port * 4):
-		mr32(P4_SER_CTLSTAT + (port - 4) * 4);
-}
-
-static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val)
-{
-	void __iomem *regs = mvi->regs;
-	if (port < 4)
-		mw32(P0_SER_CTLSTAT + port * 4, val);
-	else
-		mw32(P4_SER_CTLSTAT + (port - 4) * 4, val);
-}
-
-static u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port)
-{
-	void __iomem *regs = mvi->regs + off;
-	void __iomem *regs2 = mvi->regs + off2;
-	return (port < 4)?readl(regs + port * 8):
-		readl(regs2 + (port - 4) * 8);
-}
-
-static void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2,
-				u32 port, u32 val)
-{
-	void __iomem *regs = mvi->regs + off;
-	void __iomem *regs2 = mvi->regs + off2;
-	if (port < 4)
-		writel(val, regs + port * 8);
-	else
-		writel(val, regs2 + (port - 4) * 8);
-}
-
-static u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port)
-{
-	return mvs_read_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port);
-}
-
-static void mvs_write_port_cfg_data(struct mvs_info *mvi, u32 port, u32 val)
-{
-	mvs_write_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port, val);
-}
-
-static void mvs_write_port_cfg_addr(struct mvs_info *mvi, u32 port, u32 addr)
-{
-	mvs_write_port(mvi, MVS_P0_CFG_ADDR, MVS_P4_CFG_ADDR, port, addr);
-}
-
-static u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port)
-{
-	return mvs_read_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port);
-}
-
-static void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val)
-{
-	mvs_write_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port, val);
-}
-
-static void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr)
-{
-	mvs_write_port(mvi, MVS_P0_VSR_ADDR, MVS_P4_VSR_ADDR, port, addr);
-}
-
-static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port)
-{
-	return mvs_read_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port);
-}
-
-static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val)
-{
-	mvs_write_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port, val);
-}
-
-static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port)
-{
-	return mvs_read_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port);
-}
-
-static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val)
-{
-	mvs_write_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port, val);
-}
-
-static void __devinit mvs_phy_hacks(struct mvs_info *mvi)
-{
-	void __iomem *regs = mvi->regs;
-	u32 tmp;
-
-	/* workaround for SATA R-ERR, to ignore phy glitch */
-	tmp = mvs_cr32(regs, CMD_PHY_TIMER);
-	tmp &= ~(1 << 9);
-	tmp |= (1 << 10);
-	mvs_cw32(regs, CMD_PHY_TIMER, tmp);
-
-	/* enable retry 127 times */
-	mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f);
-
-	/* extend open frame timeout to max */
-	tmp = mvs_cr32(regs, CMD_SAS_CTL0);
-	tmp &= ~0xffff;
-	tmp |= 0x3fff;
-	mvs_cw32(regs, CMD_SAS_CTL0, tmp);
-
-	/* workaround for WDTIMEOUT , set to 550 ms */
-	mvs_cw32(regs, CMD_WD_TIMER, 0x86470);
-
-	/* not to halt for different port op during wideport link change */
-	mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d);
-
-	/* workaround for Seagate disk not-found OOB sequence, recv
-	 * COMINIT before sending out COMWAKE */
-	tmp = mvs_cr32(regs, CMD_PHY_MODE_21);
-	tmp &= 0x0000ffff;
-	tmp |= 0x00fa0000;
-	mvs_cw32(regs, CMD_PHY_MODE_21, tmp);
-
-	tmp = mvs_cr32(regs, CMD_PHY_TIMER);
-	tmp &= 0x1fffffff;
-	tmp |= (2U << 29);	/* 8 ms retry */
-	mvs_cw32(regs, CMD_PHY_TIMER, tmp);
-
-	/* TEST - for phy decoding error, adjust voltage levels */
-	mw32(P0_VSR_ADDR + 0, 0x8);
-	mw32(P0_VSR_DATA + 0, 0x2F0);
-
-	mw32(P0_VSR_ADDR + 8, 0x8);
-	mw32(P0_VSR_DATA + 8, 0x2F0);
-
-	mw32(P0_VSR_ADDR + 16, 0x8);
-	mw32(P0_VSR_DATA + 16, 0x2F0);
-
-	mw32(P0_VSR_ADDR + 24, 0x8);
-	mw32(P0_VSR_DATA + 24, 0x2F0);
-
-}
-
-static void mvs_enable_xmt(struct mvs_info *mvi, int PhyId)
-{
-	void __iomem *regs = mvi->regs;
-	u32 tmp;
-
-	tmp = mr32(PCS);
-	if (mvi->chip->n_phy <= 4)
-		tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT);
-	else
-		tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2);
-	mw32(PCS, tmp);
-}
-
-static void mvs_detect_porttype(struct mvs_info *mvi, int i)
-{
-	void __iomem *regs = mvi->regs;
-	u32 reg;
-	struct mvs_phy *phy = &mvi->phy[i];
-
-	/* TODO check & save device type */
-	reg = mr32(GBL_PORT_TYPE);
-
-	if (reg & MODE_SAS_SATA & (1 << i))
-		phy->phy_type |= PORT_TYPE_SAS;
-	else
-		phy->phy_type |= PORT_TYPE_SATA;
-}
-
-static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
-{
-	u32 *s = (u32 *) buf;
-
-	if (!s)
-		return NULL;
-
-	mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
-	s[3] = mvs_read_port_cfg_data(mvi, i);
-
-	mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
-	s[2] = mvs_read_port_cfg_data(mvi, i);
-
-	mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
-	s[1] = mvs_read_port_cfg_data(mvi, i);
-
-	mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
-	s[0] = mvs_read_port_cfg_data(mvi, i);
-
-	return (void *)s;
-}
-
-static u32 mvs_is_sig_fis_received(u32 irq_status)
-{
-	return irq_status & PHYEV_SIG_FIS;
-}
-
-static void mvs_update_wideport(struct mvs_info *mvi, int i)
-{
-	struct mvs_phy *phy = &mvi->phy[i];
-	struct mvs_port *port = phy->port;
-	int j, no;
-
-	for_each_phy(port->wide_port_phymap, no, j, mvi->chip->n_phy)
-		if (no & 1) {
-			mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
-			mvs_write_port_cfg_data(mvi, no,
-						port->wide_port_phymap);
-		} else {
-			mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
-			mvs_write_port_cfg_data(mvi, no, 0);
-		}
-}
-
-static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i)
-{
-	u32 tmp;
-	struct mvs_phy *phy = &mvi->phy[i];
-	struct mvs_port *port = phy->port;;
-
-	tmp = mvs_read_phy_ctl(mvi, i);
-
-	if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) {
-		if (!port)
-			phy->phy_attached = 1;
-		return tmp;
-	}
-
-	if (port) {
-		if (phy->phy_type & PORT_TYPE_SAS) {
-			port->wide_port_phymap &= ~(1U << i);
-			if (!port->wide_port_phymap)
-				port->port_attached = 0;
-			mvs_update_wideport(mvi, i);
-		} else if (phy->phy_type & PORT_TYPE_SATA)
-			port->port_attached = 0;
-		mvs_free_reg_set(mvi, phy->port);
-		phy->port = NULL;
-		phy->phy_attached = 0;
-		phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
-	}
-	return 0;
-}
-
-static void mvs_update_phyinfo(struct mvs_info *mvi, int i,
-					int get_st)
-{
-	struct mvs_phy *phy = &mvi->phy[i];
-	struct pci_dev *pdev = mvi->pdev;
-	u32 tmp;
-	u64 tmp64;
-
-	mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
-	phy->dev_info = mvs_read_port_cfg_data(mvi, i);
-
-	mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
-	phy->dev_sas_addr = (u64) mvs_read_port_cfg_data(mvi, i) << 32;
-
-	mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
-	phy->dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
-
-	if (get_st) {
-		phy->irq_status = mvs_read_port_irq_stat(mvi, i);
-		phy->phy_status = mvs_is_phy_ready(mvi, i);
-	}
-
-	if (phy->phy_status) {
-		u32 phy_st;
-		struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
-
-		mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT);
-		phy_st = mvs_read_port_cfg_data(mvi, i);
-
-		sas_phy->linkrate =
-			(phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
-				PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
-		phy->minimum_linkrate =
-			(phy->phy_status &
-				PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8;
-		phy->maximum_linkrate =
-			(phy->phy_status &
-				PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12;
-
-		if (phy->phy_type & PORT_TYPE_SAS) {
-			/* Updated attached_sas_addr */
-			mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
-			phy->att_dev_sas_addr =
-				(u64) mvs_read_port_cfg_data(mvi, i) << 32;
-			mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
-			phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
-			mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO);
-			phy->att_dev_info = mvs_read_port_cfg_data(mvi, i);
-			phy->identify.device_type =
-			    phy->att_dev_info & PORT_DEV_TYPE_MASK;
-
-			if (phy->identify.device_type == SAS_END_DEV)
-				phy->identify.target_port_protocols =
-							SAS_PROTOCOL_SSP;
-			else if (phy->identify.device_type != NO_DEVICE)
-				phy->identify.target_port_protocols =
-							SAS_PROTOCOL_SMP;
-			if (phy_st & PHY_OOB_DTCTD)
-				sas_phy->oob_mode = SAS_OOB_MODE;
-			phy->frame_rcvd_size =
-			    sizeof(struct sas_identify_frame);
-		} else if (phy->phy_type & PORT_TYPE_SATA) {
-			phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
-			if (mvs_is_sig_fis_received(phy->irq_status)) {
-				phy->att_dev_sas_addr = i;	/* temp */
-				if (phy_st & PHY_OOB_DTCTD)
-					sas_phy->oob_mode = SATA_OOB_MODE;
-				phy->frame_rcvd_size =
-				    sizeof(struct dev_to_host_fis);
-				mvs_get_d2h_reg(mvi, i,
-						(void *)sas_phy->frame_rcvd);
-			} else {
-				dev_printk(KERN_DEBUG, &pdev->dev,
-					"No sig fis\n");
-				phy->phy_type &= ~(PORT_TYPE_SATA);
-				goto out_done;
-			}
-		}
-		tmp64 = cpu_to_be64(phy->att_dev_sas_addr);
-		memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE);
-
-		dev_printk(KERN_DEBUG, &pdev->dev,
-			"phy[%d] Get Attached Address 0x%llX ,"
-			" SAS Address 0x%llX\n",
-			i,
-			(unsigned long long)phy->att_dev_sas_addr,
-			(unsigned long long)phy->dev_sas_addr);
-		dev_printk(KERN_DEBUG, &pdev->dev,
-			"Rate = %x , type = %d\n",
-			sas_phy->linkrate, phy->phy_type);
-
-		/* workaround for HW phy decoding error on 1.5g disk drive */
-		mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
-		tmp = mvs_read_port_vsr_data(mvi, i);
-		if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
-		     PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
-			SAS_LINK_RATE_1_5_GBPS)
-			tmp &= ~PHY_MODE6_LATECLK;
-		else
-			tmp |= PHY_MODE6_LATECLK;
-		mvs_write_port_vsr_data(mvi, i, tmp);
-
-	}
-out_done:
-	if (get_st)
-		mvs_write_port_irq_stat(mvi, i, phy->irq_status);
-}
-
-static void mvs_port_formed(struct asd_sas_phy *sas_phy)
-{
-	struct sas_ha_struct *sas_ha = sas_phy->ha;
-	struct mvs_info *mvi = sas_ha->lldd_ha;
-	struct asd_sas_port *sas_port = sas_phy->port;
-	struct mvs_phy *phy = sas_phy->lldd_phy;
-	struct mvs_port *port = &mvi->port[sas_port->id];
-	unsigned long flags;
-
-	spin_lock_irqsave(&mvi->lock, flags);
-	port->port_attached = 1;
-	phy->port = port;
-	port->taskfileset = MVS_ID_NOT_MAPPED;
-	if (phy->phy_type & PORT_TYPE_SAS) {
-		port->wide_port_phymap = sas_port->phy_mask;
-		mvs_update_wideport(mvi, sas_phy->id);
-	}
-	spin_unlock_irqrestore(&mvi->lock, flags);
-}
-
-static int mvs_I_T_nexus_reset(struct domain_device *dev)
-{
-	return TMF_RESP_FUNC_FAILED;
-}
-
-static int __devinit mvs_hw_init(struct mvs_info *mvi)
-{
-	void __iomem *regs = mvi->regs;
-	int i;
-	u32 tmp, cctl;
-
-	/* make sure interrupts are masked immediately (paranoia) */
-	mw32(GBL_CTL, 0);
-	tmp = mr32(GBL_CTL);
-
-	/* Reset Controller */
-	if (!(tmp & HBA_RST)) {
-		if (mvi->flags & MVF_PHY_PWR_FIX) {
-			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
-			tmp &= ~PCTL_PWR_ON;
-			tmp |= PCTL_OFF;
-			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
-
-			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
-			tmp &= ~PCTL_PWR_ON;
-			tmp |= PCTL_OFF;
-			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
-		}
-
-		/* global reset, incl. COMRESET/H_RESET_N (self-clearing) */
-		mw32_f(GBL_CTL, HBA_RST);
-	}
-
-	/* wait for reset to finish; timeout is just a guess */
-	i = 1000;
-	while (i-- > 0) {
-		msleep(10);
-
-		if (!(mr32(GBL_CTL) & HBA_RST))
-			break;
-	}
-	if (mr32(GBL_CTL) & HBA_RST) {
-		dev_printk(KERN_ERR, &mvi->pdev->dev, "HBA reset failed\n");
-		return -EBUSY;
-	}
-
-	/* Init Chip */
-	/* make sure RST is set; HBA_RST /should/ have done that for us */
-	cctl = mr32(CTL);
-	if (cctl & CCTL_RST)
-		cctl &= ~CCTL_RST;
-	else
-		mw32_f(CTL, cctl | CCTL_RST);
-
-	/* write to device control _AND_ device status register? - A.C. */
-	pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp);
-	tmp &= ~PRD_REQ_MASK;
-	tmp |= PRD_REQ_SIZE;
-	pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp);
-
-	pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
-	tmp |= PCTL_PWR_ON;
-	tmp &= ~PCTL_OFF;
-	pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
-
-	pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
-	tmp |= PCTL_PWR_ON;
-	tmp &= ~PCTL_OFF;
-	pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
-
-	mw32_f(CTL, cctl);
-
-	/* reset control */
-	mw32(PCS, 0);		/*MVS_PCS */
-
-	mvs_phy_hacks(mvi);
-
-	mw32(CMD_LIST_LO, mvi->slot_dma);
-	mw32(CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16);
-
-	mw32(RX_FIS_LO, mvi->rx_fis_dma);
-	mw32(RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16);
-
-	mw32(TX_CFG, MVS_CHIP_SLOT_SZ);
-	mw32(TX_LO, mvi->tx_dma);
-	mw32(TX_HI, (mvi->tx_dma >> 16) >> 16);
-
-	mw32(RX_CFG, MVS_RX_RING_SZ);
-	mw32(RX_LO, mvi->rx_dma);
-	mw32(RX_HI, (mvi->rx_dma >> 16) >> 16);
-
-	/* enable auto port detection */
-	mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN);
-	msleep(1100);
-	/* init and reset phys */
-	for (i = 0; i < mvi->chip->n_phy; i++) {
-		u32 lo = be32_to_cpu(*(u32 *)&mvi->sas_addr[4]);
-		u32 hi = be32_to_cpu(*(u32 *)&mvi->sas_addr[0]);
-
-		mvs_detect_porttype(mvi, i);
-
-		/* set phy local SAS address */
-		mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
-		mvs_write_port_cfg_data(mvi, i, lo);
-		mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
-		mvs_write_port_cfg_data(mvi, i, hi);
-
-		/* reset phy */
-		tmp = mvs_read_phy_ctl(mvi, i);
-		tmp |= PHY_RST;
-		mvs_write_phy_ctl(mvi, i, tmp);
-	}
-
-	msleep(100);
-
-	for (i = 0; i < mvi->chip->n_phy; i++) {
-		/* clear phy int status */
-		tmp = mvs_read_port_irq_stat(mvi, i);
-		tmp &= ~PHYEV_SIG_FIS;
-		mvs_write_port_irq_stat(mvi, i, tmp);
-
-		/* set phy int mask */
-		tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS |
-			PHYEV_ID_DONE | PHYEV_DEC_ERR;
-		mvs_write_port_irq_mask(mvi, i, tmp);
-
-		msleep(100);
-		mvs_update_phyinfo(mvi, i, 1);
-		mvs_enable_xmt(mvi, i);
-	}
-
-	/* FIXME: update wide port bitmaps */
-
-	/* little endian for open address and command table, etc. */
-	/* A.C.
-	 * it seems that ( from the spec ) turning on big-endian won't
-	 * do us any good on big-endian machines, need further confirmation
-	 */
-	cctl = mr32(CTL);
-	cctl |= CCTL_ENDIAN_CMD;
-	cctl |= CCTL_ENDIAN_DATA;
-	cctl &= ~CCTL_ENDIAN_OPEN;
-	cctl |= CCTL_ENDIAN_RSP;
-	mw32_f(CTL, cctl);
-
-	/* reset CMD queue */
-	tmp = mr32(PCS);
-	tmp |= PCS_CMD_RST;
-	mw32(PCS, tmp);
-	/* interrupt coalescing may cause missing HW interrput in some case,
-	 * and the max count is 0x1ff, while our max slot is 0x200,
-	 * it will make count 0.
-	 */
-	tmp = 0;
-	mw32(INT_COAL, tmp);
-
-	tmp = 0x100;
-	mw32(INT_COAL_TMOUT, tmp);
-
-	/* ladies and gentlemen, start your engines */
-	mw32(TX_CFG, 0);
-	mw32(TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN);
-	mw32(RX_CFG, MVS_RX_RING_SZ | RX_EN);
-	/* enable CMD/CMPL_Q/RESP mode */
-	mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN);
-
-	/* enable completion queue interrupt */
-	tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS);
-	mw32(INT_MASK, tmp);
-
-	/* Enable SRS interrupt */
-	mw32(INT_MASK_SRS, 0xFF);
-	return 0;
-}
-
-static void __devinit mvs_print_info(struct mvs_info *mvi)
-{
-	struct pci_dev *pdev = mvi->pdev;
-	static int printed_version;
-
-	if (!printed_version++)
-		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
-
-	dev_printk(KERN_INFO, &pdev->dev, "%u phys, addr %llx\n",
-		   mvi->chip->n_phy, SAS_ADDR(mvi->sas_addr));
-}
-
-static int __devinit mvs_pci_init(struct pci_dev *pdev,
-				  const struct pci_device_id *ent)
-{
-	int rc;
-	struct mvs_info *mvi;
-	irq_handler_t irq_handler = mvs_interrupt;
-
-	rc = pci_enable_device(pdev);
-	if (rc)
-		return rc;
-
-	pci_set_master(pdev);
-
-	rc = pci_request_regions(pdev, DRV_NAME);
-	if (rc)
-		goto err_out_disable;
-
-	rc = pci_go_64(pdev);
-	if (rc)
-		goto err_out_regions;
-
-	mvi = mvs_alloc(pdev, ent);
-	if (!mvi) {
-		rc = -ENOMEM;
-		goto err_out_regions;
-	}
-
-	rc = mvs_hw_init(mvi);
-	if (rc)
-		goto err_out_mvi;
-
-#ifndef MVS_DISABLE_MSI
-	if (!pci_enable_msi(pdev)) {
-		u32 tmp;
-		void __iomem *regs = mvi->regs;
-		mvi->flags |= MVF_MSI;
-		irq_handler = mvs_msi_interrupt;
-		tmp = mr32(PCS);
-		mw32(PCS, tmp | PCS_SELF_CLEAR);
-	}
-#endif
-
-	rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, mvi);
-	if (rc)
-		goto err_out_msi;
-
-	rc = scsi_add_host(mvi->shost, &pdev->dev);
-	if (rc)
-		goto err_out_irq;
-
-	rc = sas_register_ha(&mvi->sas);
-	if (rc)
-		goto err_out_shost;
-
-	pci_set_drvdata(pdev, mvi);
-
-	mvs_print_info(mvi);
-
-	mvs_hba_interrupt_enable(mvi);
-
-	scsi_scan_host(mvi->shost);
-
-	return 0;
-
-err_out_shost:
-	scsi_remove_host(mvi->shost);
-err_out_irq:
-	free_irq(pdev->irq, mvi);
-err_out_msi:
-	if (mvi->flags |= MVF_MSI)
-		pci_disable_msi(pdev);
-err_out_mvi:
-	mvs_free(mvi);
-err_out_regions:
-	pci_release_regions(pdev);
-err_out_disable:
-	pci_disable_device(pdev);
-	return rc;
-}
-
-static void __devexit mvs_pci_remove(struct pci_dev *pdev)
-{
-	struct mvs_info *mvi = pci_get_drvdata(pdev);
-
-	pci_set_drvdata(pdev, NULL);
-
-	if (mvi) {
-		sas_unregister_ha(&mvi->sas);
-		mvs_hba_interrupt_disable(mvi);
-		sas_remove_host(mvi->shost);
-		scsi_remove_host(mvi->shost);
-
-		free_irq(pdev->irq, mvi);
-		if (mvi->flags & MVF_MSI)
-			pci_disable_msi(pdev);
-		mvs_free(mvi);
-		pci_release_regions(pdev);
-	}
-	pci_disable_device(pdev);
-}
-
-static struct sas_domain_function_template mvs_transport_ops = {
-	.lldd_execute_task	= mvs_task_exec,
-	.lldd_control_phy	= mvs_phy_control,
-	.lldd_abort_task	= mvs_task_abort,
-	.lldd_port_formed	= mvs_port_formed,
-	.lldd_I_T_nexus_reset	= mvs_I_T_nexus_reset,
-};
-
-static struct pci_device_id __devinitdata mvs_pci_table[] = {
-	{ PCI_VDEVICE(MARVELL, 0x6320), chip_6320 },
-	{ PCI_VDEVICE(MARVELL, 0x6340), chip_6440 },
-	{
-		.vendor 	= PCI_VENDOR_ID_MARVELL,
-		.device 	= 0x6440,
-		.subvendor	= PCI_ANY_ID,
-		.subdevice	= 0x6480,
-		.class		= 0,
-		.class_mask	= 0,
-		.driver_data	= chip_6480,
-	},
-	{ PCI_VDEVICE(MARVELL, 0x6440), chip_6440 },
-	{ PCI_VDEVICE(MARVELL, 0x6480), chip_6480 },
-
-	{ }	/* terminate list */
-};
-
-static struct pci_driver mvs_pci_driver = {
-	.name		= DRV_NAME,
-	.id_table	= mvs_pci_table,
-	.probe		= mvs_pci_init,
-	.remove		= __devexit_p(mvs_pci_remove),
-};
-
-static int __init mvs_init(void)
-{
-	int rc;
-
-	mvs_stt = sas_domain_attach_transport(&mvs_transport_ops);
-	if (!mvs_stt)
-		return -ENOMEM;
-
-	rc = pci_register_driver(&mvs_pci_driver);
-	if (rc)
-		goto err_out;
-
-	return 0;
-
-err_out:
-	sas_release_transport(mvs_stt);
-	return rc;
-}
-
-static void __exit mvs_exit(void)
-{
-	pci_unregister_driver(&mvs_pci_driver);
-	sas_release_transport(mvs_stt);
-}
-
-module_init(mvs_init);
-module_exit(mvs_exit);
-
-MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
-MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver");
-MODULE_VERSION(DRV_VERSION);
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, mvs_pci_table);
diff --git a/drivers/scsi/mvsas/Kconfig b/drivers/scsi/mvsas/Kconfig
new file mode 100644
index 0000000..6de7af2
--- /dev/null
+++ b/drivers/scsi/mvsas/Kconfig
@@ -0,0 +1,42 @@
+#
+# Kernel configuration file for 88SE64XX/88SE94XX SAS/SATA driver.
+#
+# Copyright 2007 Red Hat, Inc.
+# Copyright 2008 Marvell. <kewei@marvell.com>
+#
+# This file is licensed under GPLv2.
+#
+# This file is part of the 88SE64XX/88SE94XX driver.
+#
+# The 88SE64XX/88SE94XX driver is free software; 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.
+#
+# The 88SE64XX/88SE94XX driver is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with 88SE64XX/88SE94XX Driver; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+#
+
+config SCSI_MVSAS
+	tristate "Marvell 88SE64XX/88SE94XX SAS/SATA support"
+	depends on PCI
+	select SCSI_SAS_LIBSAS
+	select FW_LOADER
+	help
+		This driver supports Marvell's SAS/SATA 3Gb/s PCI-E 88SE64XX and 6Gb/s
+		PCI-E 88SE94XX chip based host adapters.
+
+config SCSI_MVSAS_DEBUG
+	bool "Compile in debug mode"
+	default y
+	depends on SCSI_MVSAS
+	help
+		Compiles the 88SE64XX/88SE94XX driver in debug mode.  In debug mode,
+		the driver prints some messages to the console.
diff --git a/drivers/scsi/mvsas/Makefile b/drivers/scsi/mvsas/Makefile
new file mode 100644
index 0000000..52ac426
--- /dev/null
+++ b/drivers/scsi/mvsas/Makefile
@@ -0,0 +1,32 @@
+#
+# Makefile for Marvell 88SE64xx/88SE84xx SAS/SATA driver.
+#
+# Copyright 2007 Red Hat, Inc.
+# Copyright 2008 Marvell. <kewei@marvell.com>
+#
+# This file is licensed under GPLv2.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+
+ifeq ($(CONFIG_SCSI_MVSAS_DEBUG),y)
+	EXTRA_CFLAGS += -DMV_DEBUG
+endif
+
+obj-$(CONFIG_SCSI_MVSAS) += mvsas.o
+mvsas-y +=  mv_init.o  \
+           mv_sas.o   \
+           mv_64xx.o  \
+           mv_94xx.o
diff --git a/drivers/scsi/mvsas/mv_64xx.c b/drivers/scsi/mvsas/mv_64xx.c
new file mode 100644
index 0000000..10a5077
--- /dev/null
+++ b/drivers/scsi/mvsas/mv_64xx.c
@@ -0,0 +1,793 @@
+/*
+ * Marvell 88SE64xx hardware specific
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+#include "mv_sas.h"
+#include "mv_64xx.h"
+#include "mv_chips.h"
+
+static void mvs_64xx_detect_porttype(struct mvs_info *mvi, int i)
+{
+	void __iomem *regs = mvi->regs;
+	u32 reg;
+	struct mvs_phy *phy = &mvi->phy[i];
+
+	/* TODO check & save device type */
+	reg = mr32(MVS_GBL_PORT_TYPE);
+	phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+	if (reg & MODE_SAS_SATA & (1 << i))
+		phy->phy_type |= PORT_TYPE_SAS;
+	else
+		phy->phy_type |= PORT_TYPE_SATA;
+}
+
+static void __devinit mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id)
+{
+	void __iomem *regs = mvi->regs;
+	u32 tmp;
+
+	tmp = mr32(MVS_PCS);
+	if (mvi->chip->n_phy <= 4)
+		tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT);
+	else
+		tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2);
+	mw32(MVS_PCS, tmp);
+}
+
+static void __devinit mvs_64xx_phy_hacks(struct mvs_info *mvi)
+{
+	void __iomem *regs = mvi->regs;
+
+	mvs_phy_hacks(mvi);
+
+	if (!(mvi->flags & MVF_FLAG_SOC)) {
+		/* TEST - for phy decoding error, adjust voltage levels */
+		mw32(MVS_P0_VSR_ADDR + 0, 0x8);
+		mw32(MVS_P0_VSR_DATA + 0, 0x2F0);
+
+		mw32(MVS_P0_VSR_ADDR + 8, 0x8);
+		mw32(MVS_P0_VSR_DATA + 8, 0x2F0);
+
+		mw32(MVS_P0_VSR_ADDR + 16, 0x8);
+		mw32(MVS_P0_VSR_DATA + 16, 0x2F0);
+
+		mw32(MVS_P0_VSR_ADDR + 24, 0x8);
+		mw32(MVS_P0_VSR_DATA + 24, 0x2F0);
+	} else {
+		int i;
+		/* disable auto port detection */
+		mw32(MVS_GBL_PORT_TYPE, 0);
+		for (i = 0; i < mvi->chip->n_phy; i++) {
+			mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE7);
+			mvs_write_port_vsr_data(mvi, i, 0x90000000);
+			mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE9);
+			mvs_write_port_vsr_data(mvi, i, 0x50f2);
+			mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE11);
+			mvs_write_port_vsr_data(mvi, i, 0x0e);
+		}
+	}
+}
+
+static void mvs_64xx_stp_reset(struct mvs_info *mvi, u32 phy_id)
+{
+	void __iomem *regs = mvi->regs;
+	u32 reg, tmp;
+
+	if (!(mvi->flags & MVF_FLAG_SOC)) {
+		if (phy_id < 4)
+			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &reg);
+		else
+			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &reg);
+
+	} else
+		reg = mr32(MVS_PHY_CTL);
+
+	tmp = reg;
+	if (phy_id < 4)
+		tmp |= (1U << phy_id) << PCTL_LINK_OFFS;
+	else
+		tmp |= (1U << (phy_id - 4)) << PCTL_LINK_OFFS;
+
+	if (!(mvi->flags & MVF_FLAG_SOC)) {
+		if (phy_id < 4) {
+			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
+			mdelay(10);
+			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, reg);
+		} else {
+			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
+			mdelay(10);
+			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, reg);
+		}
+	} else {
+		mw32(MVS_PHY_CTL, tmp);
+		mdelay(10);
+		mw32(MVS_PHY_CTL, reg);
+	}
+}
+
+static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
+{
+	u32 tmp;
+	tmp = mvs_read_port_irq_stat(mvi, phy_id);
+	tmp &= ~PHYEV_RDY_CH;
+	mvs_write_port_irq_stat(mvi, phy_id, tmp);
+	tmp = mvs_read_phy_ctl(mvi, phy_id);
+	if (hard)
+		tmp |= PHY_RST_HARD;
+	else
+		tmp |= PHY_RST;
+	mvs_write_phy_ctl(mvi, phy_id, tmp);
+	if (hard) {
+		do {
+			tmp = mvs_read_phy_ctl(mvi, phy_id);
+		} while (tmp & PHY_RST_HARD);
+	}
+}
+
+static int __devinit mvs_64xx_chip_reset(struct mvs_info *mvi)
+{
+	void __iomem *regs = mvi->regs;
+	u32 tmp;
+	int i;
+
+	/* make sure interrupts are masked immediately (paranoia) */
+	mw32(MVS_GBL_CTL, 0);
+	tmp = mr32(MVS_GBL_CTL);
+
+	/* Reset Controller */
+	if (!(tmp & HBA_RST)) {
+		if (mvi->flags & MVF_PHY_PWR_FIX) {
+			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
+			tmp &= ~PCTL_PWR_OFF;
+			tmp |= PCTL_PHY_DSBL;
+			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
+
+			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
+			tmp &= ~PCTL_PWR_OFF;
+			tmp |= PCTL_PHY_DSBL;
+			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
+		}
+	}
+
+	/* make sure interrupts are masked immediately (paranoia) */
+	mw32(MVS_GBL_CTL, 0);
+	tmp = mr32(MVS_GBL_CTL);
+
+	/* Reset Controller */
+	if (!(tmp & HBA_RST)) {
+		/* global reset, incl. COMRESET/H_RESET_N (self-clearing) */
+		mw32_f(MVS_GBL_CTL, HBA_RST);
+	}
+
+	/* wait for reset to finish; timeout is just a guess */
+	i = 1000;
+	while (i-- > 0) {
+		msleep(10);
+
+		if (!(mr32(MVS_GBL_CTL) & HBA_RST))
+			break;
+	}
+	if (mr32(MVS_GBL_CTL) & HBA_RST) {
+		dev_printk(KERN_ERR, mvi->dev, "HBA reset failed\n");
+		return -EBUSY;
+	}
+	return 0;
+}
+
+static void mvs_64xx_phy_disable(struct mvs_info *mvi, u32 phy_id)
+{
+	void __iomem *regs = mvi->regs;
+	u32 tmp;
+	if (!(mvi->flags & MVF_FLAG_SOC)) {
+		u32 offs;
+		if (phy_id < 4)
+			offs = PCR_PHY_CTL;
+		else {
+			offs = PCR_PHY_CTL2;
+			phy_id -= 4;
+		}
+		pci_read_config_dword(mvi->pdev, offs, &tmp);
+		tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id);
+		pci_write_config_dword(mvi->pdev, offs, tmp);
+	} else {
+		tmp = mr32(MVS_PHY_CTL);
+		tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id);
+		mw32(MVS_PHY_CTL, tmp);
+	}
+}
+
+static void mvs_64xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
+{
+	void __iomem *regs = mvi->regs;
+	u32 tmp;
+	if (!(mvi->flags & MVF_FLAG_SOC)) {
+		u32 offs;
+		if (phy_id < 4)
+			offs = PCR_PHY_CTL;
+		else {
+			offs = PCR_PHY_CTL2;
+			phy_id -= 4;
+		}
+		pci_read_config_dword(mvi->pdev, offs, &tmp);
+		tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id));
+		pci_write_config_dword(mvi->pdev, offs, tmp);
+	} else {
+		tmp = mr32(MVS_PHY_CTL);
+		tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id));
+		mw32(MVS_PHY_CTL, tmp);
+	}
+}
+
+static int __devinit mvs_64xx_init(struct mvs_info *mvi)
+{
+	void __iomem *regs = mvi->regs;
+	int i;
+	u32 tmp, cctl;
+
+	if (mvi->pdev && mvi->pdev->revision == 0)
+		mvi->flags |= MVF_PHY_PWR_FIX;
+	if (!(mvi->flags & MVF_FLAG_SOC)) {
+		mvs_show_pcie_usage(mvi);
+		tmp = mvs_64xx_chip_reset(mvi);
+		if (tmp)
+			return tmp;
+	} else {
+		tmp = mr32(MVS_PHY_CTL);
+		tmp &= ~PCTL_PWR_OFF;
+		tmp |= PCTL_PHY_DSBL;
+		mw32(MVS_PHY_CTL, tmp);
+	}
+
+	/* Init Chip */
+	/* make sure RST is set; HBA_RST /should/ have done that for us */
+	cctl = mr32(MVS_CTL) & 0xFFFF;
+	if (cctl & CCTL_RST)
+		cctl &= ~CCTL_RST;
+	else
+		mw32_f(MVS_CTL, cctl | CCTL_RST);
+
+	if (!(mvi->flags & MVF_FLAG_SOC)) {
+		/* write to device control _AND_ device status register */
+		pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp);
+		tmp &= ~PRD_REQ_MASK;
+		tmp |= PRD_REQ_SIZE;
+		pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp);
+
+		pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
+		tmp &= ~PCTL_PWR_OFF;
+		tmp &= ~PCTL_PHY_DSBL;
+		pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
+
+		pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
+		tmp &= PCTL_PWR_OFF;
+		tmp &= ~PCTL_PHY_DSBL;
+		pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
+	} else {
+		tmp = mr32(MVS_PHY_CTL);
+		tmp &= ~PCTL_PWR_OFF;
+		tmp |= PCTL_COM_ON;
+		tmp &= ~PCTL_PHY_DSBL;
+		tmp |= PCTL_LINK_RST;
+		mw32(MVS_PHY_CTL, tmp);
+		msleep(100);
+		tmp &= ~PCTL_LINK_RST;
+		mw32(MVS_PHY_CTL, tmp);
+		msleep(100);
+	}
+
+	/* reset control */
+	mw32(MVS_PCS, 0);		/* MVS_PCS */
+	/* init phys */
+	mvs_64xx_phy_hacks(mvi);
+
+	/* enable auto port detection */
+	mw32(MVS_GBL_PORT_TYPE, MODE_AUTO_DET_EN);
+
+	mw32(MVS_CMD_LIST_LO, mvi->slot_dma);
+	mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16);
+
+	mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma);
+	mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16);
+
+	mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ);
+	mw32(MVS_TX_LO, mvi->tx_dma);
+	mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16);
+
+	mw32(MVS_RX_CFG, MVS_RX_RING_SZ);
+	mw32(MVS_RX_LO, mvi->rx_dma);
+	mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16);
+
+	for (i = 0; i < mvi->chip->n_phy; i++) {
+		/* set phy local SAS address */
+		/* should set little endian SAS address to 64xx chip */
+		mvs_set_sas_addr(mvi, i, PHYR_ADDR_LO, PHYR_ADDR_HI,
+				cpu_to_be64(mvi->phy[i].dev_sas_addr));
+
+		mvs_64xx_enable_xmt(mvi, i);
+
+		mvs_64xx_phy_reset(mvi, i, 1);
+		msleep(500);
+		mvs_64xx_detect_porttype(mvi, i);
+	}
+	if (mvi->flags & MVF_FLAG_SOC) {
+		/* set select registers */
+		writel(0x0E008000, regs + 0x000);
+		writel(0x59000008, regs + 0x004);
+		writel(0x20, regs + 0x008);
+		writel(0x20, regs + 0x00c);
+		writel(0x20, regs + 0x010);
+		writel(0x20, regs + 0x014);
+		writel(0x20, regs + 0x018);
+		writel(0x20, regs + 0x01c);
+	}
+	for (i = 0; i < mvi->chip->n_phy; i++) {
+		/* clear phy int status */
+		tmp = mvs_read_port_irq_stat(mvi, i);
+		tmp &= ~PHYEV_SIG_FIS;
+		mvs_write_port_irq_stat(mvi, i, tmp);
+
+		/* set phy int mask */
+		tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS |
+			PHYEV_ID_DONE | PHYEV_DCDR_ERR | PHYEV_CRC_ERR |
+			PHYEV_DEC_ERR;
+		mvs_write_port_irq_mask(mvi, i, tmp);
+
+		msleep(100);
+		mvs_update_phyinfo(mvi, i, 1);
+	}
+
+	/* FIXME: update wide port bitmaps */
+
+	/* little endian for open address and command table, etc. */
+	/*
+	 * it seems that ( from the spec ) turning on big-endian won't
+	 * do us any good on big-endian machines, need further confirmation
+	 */
+	cctl = mr32(MVS_CTL);
+	cctl |= CCTL_ENDIAN_CMD;
+	cctl |= CCTL_ENDIAN_DATA;
+	cctl &= ~CCTL_ENDIAN_OPEN;
+	cctl |= CCTL_ENDIAN_RSP;
+	mw32_f(MVS_CTL, cctl);
+
+	/* reset CMD queue */
+	tmp = mr32(MVS_PCS);
+	tmp |= PCS_CMD_RST;
+	mw32(MVS_PCS, tmp);
+	/* interrupt coalescing may cause missing HW interrput in some case,
+	 * and the max count is 0x1ff, while our max slot is 0x200,
+	 * it will make count 0.
+	 */
+	tmp = 0;
+	mw32(MVS_INT_COAL, tmp);
+
+	tmp = 0x100;
+	mw32(MVS_INT_COAL_TMOUT, tmp);
+
+	/* ladies and gentlemen, start your engines */
+	mw32(MVS_TX_CFG, 0);
+	mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN);
+	mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN);
+	/* enable CMD/CMPL_Q/RESP mode */
+	mw32(MVS_PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN |
+		PCS_CMD_EN | PCS_CMD_STOP_ERR);
+
+	/* enable completion queue interrupt */
+	tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP |
+		CINT_DMA_PCIE);
+
+	mw32(MVS_INT_MASK, tmp);
+
+	/* Enable SRS interrupt */
+	mw32(MVS_INT_MASK_SRS_0, 0xFFFF);
+
+	return 0;
+}
+
+static int mvs_64xx_ioremap(struct mvs_info *mvi)
+{
+	if (!mvs_ioremap(mvi, 4, 2))
+		return 0;
+	return -1;
+}
+
+static void mvs_64xx_iounmap(struct mvs_info *mvi)
+{
+	mvs_iounmap(mvi->regs);
+	mvs_iounmap(mvi->regs_ex);
+}
+
+static void mvs_64xx_interrupt_enable(struct mvs_info *mvi)
+{
+	void __iomem *regs = mvi->regs;
+	u32 tmp;
+
+	tmp = mr32(MVS_GBL_CTL);
+	mw32(MVS_GBL_CTL, tmp | INT_EN);
+}
+
+static void mvs_64xx_interrupt_disable(struct mvs_info *mvi)
+{
+	void __iomem *regs = mvi->regs;
+	u32 tmp;
+
+	tmp = mr32(MVS_GBL_CTL);
+	mw32(MVS_GBL_CTL, tmp & ~INT_EN);
+}
+
+static u32 mvs_64xx_isr_status(struct mvs_info *mvi, int irq)
+{
+	void __iomem *regs = mvi->regs;
+	u32 stat;
+
+	if (!(mvi->flags & MVF_FLAG_SOC)) {
+		stat = mr32(MVS_GBL_INT_STAT);
+
+		if (stat == 0 || stat == 0xffffffff)
+			return 0;
+	} else
+		stat = 1;
+	return stat;
+}
+
+static irqreturn_t mvs_64xx_isr(struct mvs_info *mvi, int irq, u32 stat)
+{
+	void __iomem *regs = mvi->regs;
+
+	/* clear CMD_CMPLT ASAP */
+	mw32_f(MVS_INT_STAT, CINT_DONE);
+#ifndef MVS_USE_TASKLET
+	spin_lock(&mvi->lock);
+#endif
+	mvs_int_full(mvi);
+#ifndef MVS_USE_TASKLET
+	spin_unlock(&mvi->lock);
+#endif
+	return IRQ_HANDLED;
+}
+
+static void mvs_64xx_command_active(struct mvs_info *mvi, u32 slot_idx)
+{
+	u32 tmp;
+	mvs_cw32(mvi, 0x40 + (slot_idx >> 3), 1 << (slot_idx % 32));
+	mvs_cw32(mvi, 0x00 + (slot_idx >> 3), 1 << (slot_idx % 32));
+	do {
+		tmp = mvs_cr32(mvi, 0x00 + (slot_idx >> 3));
+	} while (tmp & 1 << (slot_idx % 32));
+	do {
+		tmp = mvs_cr32(mvi, 0x40 + (slot_idx >> 3));
+	} while (tmp & 1 << (slot_idx % 32));
+}
+
+static void mvs_64xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type,
+				u32 tfs)
+{
+	void __iomem *regs = mvi->regs;
+	u32 tmp;
+
+	if (type == PORT_TYPE_SATA) {
+		tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs);
+		mw32(MVS_INT_STAT_SRS_0, tmp);
+	}
+	mw32(MVS_INT_STAT, CINT_CI_STOP);
+	tmp = mr32(MVS_PCS) | 0xFF00;
+	mw32(MVS_PCS, tmp);
+}
+
+static void mvs_64xx_free_reg_set(struct mvs_info *mvi, u8 *tfs)
+{
+	void __iomem *regs = mvi->regs;
+	u32 tmp, offs;
+
+	if (*tfs == MVS_ID_NOT_MAPPED)
+		return;
+
+	offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT);
+	if (*tfs < 16) {
+		tmp = mr32(MVS_PCS);
+		mw32(MVS_PCS, tmp & ~offs);
+	} else {
+		tmp = mr32(MVS_CTL);
+		mw32(MVS_CTL, tmp & ~offs);
+	}
+
+	tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << *tfs);
+	if (tmp)
+		mw32(MVS_INT_STAT_SRS_0, tmp);
+
+	*tfs = MVS_ID_NOT_MAPPED;
+	return;
+}
+
+static u8 mvs_64xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs)
+{
+	int i;
+	u32 tmp, offs;
+	void __iomem *regs = mvi->regs;
+
+	if (*tfs != MVS_ID_NOT_MAPPED)
+		return 0;
+
+	tmp = mr32(MVS_PCS);
+
+	for (i = 0; i < mvi->chip->srs_sz; i++) {
+		if (i == 16)
+			tmp = mr32(MVS_CTL);
+		offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT);
+		if (!(tmp & offs)) {
+			*tfs = i;
+
+			if (i < 16)
+				mw32(MVS_PCS, tmp | offs);
+			else
+				mw32(MVS_CTL, tmp | offs);
+			tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << i);
+			if (tmp)
+				mw32(MVS_INT_STAT_SRS_0, tmp);
+			return 0;
+		}
+	}
+	return MVS_ID_NOT_MAPPED;
+}
+
+void mvs_64xx_make_prd(struct scatterlist *scatter, int nr, void *prd)
+{
+	int i;
+	struct scatterlist *sg;
+	struct mvs_prd *buf_prd = prd;
+	for_each_sg(scatter, sg, nr, i) {
+		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
+		buf_prd->len = cpu_to_le32(sg_dma_len(sg));
+		buf_prd++;
+	}
+}
+
+static int mvs_64xx_oob_done(struct mvs_info *mvi, int i)
+{
+	u32 phy_st;
+	mvs_write_port_cfg_addr(mvi, i,
+			PHYR_PHY_STAT);
+	phy_st = mvs_read_port_cfg_data(mvi, i);
+	if (phy_st & PHY_OOB_DTCTD)
+		return 1;
+	return 0;
+}
+
+static void mvs_64xx_fix_phy_info(struct mvs_info *mvi, int i,
+				struct sas_identify_frame *id)
+
+{
+	struct mvs_phy *phy = &mvi->phy[i];
+	struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+	sas_phy->linkrate =
+		(phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+			PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
+
+	phy->minimum_linkrate =
+		(phy->phy_status &
+			PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8;
+	phy->maximum_linkrate =
+		(phy->phy_status &
+			PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12;
+
+	mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
+	phy->dev_info = mvs_read_port_cfg_data(mvi, i);
+
+	mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO);
+	phy->att_dev_info = mvs_read_port_cfg_data(mvi, i);
+
+	mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
+	phy->att_dev_sas_addr =
+	     (u64) mvs_read_port_cfg_data(mvi, i) << 32;
+	mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
+	phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
+	phy->att_dev_sas_addr = SAS_ADDR(&phy->att_dev_sas_addr);
+}
+
+static void mvs_64xx_phy_work_around(struct mvs_info *mvi, int i)
+{
+	u32 tmp;
+	struct mvs_phy *phy = &mvi->phy[i];
+	/* workaround for HW phy decoding error on 1.5g disk drive */
+	mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
+	tmp = mvs_read_port_vsr_data(mvi, i);
+	if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+	     PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
+		SAS_LINK_RATE_1_5_GBPS)
+		tmp &= ~PHY_MODE6_LATECLK;
+	else
+		tmp |= PHY_MODE6_LATECLK;
+	mvs_write_port_vsr_data(mvi, i, tmp);
+}
+
+void mvs_64xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
+			struct sas_phy_linkrates *rates)
+{
+	u32 lrmin = 0, lrmax = 0;
+	u32 tmp;
+
+	tmp = mvs_read_phy_ctl(mvi, phy_id);
+	lrmin = (rates->minimum_linkrate << 8);
+	lrmax = (rates->maximum_linkrate << 12);
+
+	if (lrmin) {
+		tmp &= ~(0xf << 8);
+		tmp |= lrmin;
+	}
+	if (lrmax) {
+		tmp &= ~(0xf << 12);
+		tmp |= lrmax;
+	}
+	mvs_write_phy_ctl(mvi, phy_id, tmp);
+	mvs_64xx_phy_reset(mvi, phy_id, 1);
+}
+
+static void mvs_64xx_clear_active_cmds(struct mvs_info *mvi)
+{
+	u32 tmp;
+	void __iomem *regs = mvi->regs;
+	tmp = mr32(MVS_PCS);
+	mw32(MVS_PCS, tmp & 0xFFFF);
+	mw32(MVS_PCS, tmp);
+	tmp = mr32(MVS_CTL);
+	mw32(MVS_CTL, tmp & 0xFFFF);
+	mw32(MVS_CTL, tmp);
+}
+
+
+u32 mvs_64xx_spi_read_data(struct mvs_info *mvi)
+{
+	void __iomem *regs = mvi->regs_ex;
+	return ior32(SPI_DATA_REG_64XX);
+}
+
+void mvs_64xx_spi_write_data(struct mvs_info *mvi, u32 data)
+{
+	void __iomem *regs = mvi->regs_ex;
+	 iow32(SPI_DATA_REG_64XX, data);
+}
+
+
+int mvs_64xx_spi_buildcmd(struct mvs_info *mvi,
+			u32      *dwCmd,
+			u8       cmd,
+			u8       read,
+			u8       length,
+			u32      addr
+			)
+{
+	u32  dwTmp;
+
+	dwTmp = ((u32)cmd << 24) | ((u32)length << 19);
+	if (read)
+		dwTmp |= 1U<<23;
+
+	if (addr != MV_MAX_U32) {
+		dwTmp |= 1U<<22;
+		dwTmp |= (addr & 0x0003FFFF);
+	}
+
+	*dwCmd = dwTmp;
+	return 0;
+}
+
+
+int mvs_64xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd)
+{
+	void __iomem *regs = mvi->regs_ex;
+	int     retry;
+
+	for (retry = 0; retry < 1; retry++) {
+		iow32(SPI_CTRL_REG_64XX, SPI_CTRL_VENDOR_ENABLE);
+		iow32(SPI_CMD_REG_64XX, cmd);
+		iow32(SPI_CTRL_REG_64XX,
+			SPI_CTRL_VENDOR_ENABLE | SPI_CTRL_SPISTART);
+	}
+
+	return 0;
+}
+
+int mvs_64xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
+{
+	void __iomem *regs = mvi->regs_ex;
+	u32 i, dwTmp;
+
+	for (i = 0; i < timeout; i++) {
+		dwTmp = ior32(SPI_CTRL_REG_64XX);
+		if (!(dwTmp & SPI_CTRL_SPISTART))
+			return 0;
+		msleep(10);
+	}
+
+	return -1;
+}
+
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+void mvs_64xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)
+{
+	int i;
+	struct mvs_prd *buf_prd = prd;
+	buf_prd	+= from;
+	for (i = 0; i < MAX_SG_ENTRY - from; i++) {
+		buf_prd->addr = cpu_to_le64(buf_dma);
+		buf_prd->len = cpu_to_le32(buf_len);
+		++buf_prd;
+	}
+}
+#endif
+
+const struct mvs_dispatch mvs_64xx_dispatch = {
+	"mv64xx",
+	mvs_64xx_init,
+	NULL,
+	mvs_64xx_ioremap,
+	mvs_64xx_iounmap,
+	mvs_64xx_isr,
+	mvs_64xx_isr_status,
+	mvs_64xx_interrupt_enable,
+	mvs_64xx_interrupt_disable,
+	mvs_read_phy_ctl,
+	mvs_write_phy_ctl,
+	mvs_read_port_cfg_data,
+	mvs_write_port_cfg_data,
+	mvs_write_port_cfg_addr,
+	mvs_read_port_vsr_data,
+	mvs_write_port_vsr_data,
+	mvs_write_port_vsr_addr,
+	mvs_read_port_irq_stat,
+	mvs_write_port_irq_stat,
+	mvs_read_port_irq_mask,
+	mvs_write_port_irq_mask,
+	mvs_get_sas_addr,
+	mvs_64xx_command_active,
+	mvs_64xx_issue_stop,
+	mvs_start_delivery,
+	mvs_rx_update,
+	mvs_int_full,
+	mvs_64xx_assign_reg_set,
+	mvs_64xx_free_reg_set,
+	mvs_get_prd_size,
+	mvs_get_prd_count,
+	mvs_64xx_make_prd,
+	mvs_64xx_detect_porttype,
+	mvs_64xx_oob_done,
+	mvs_64xx_fix_phy_info,
+	mvs_64xx_phy_work_around,
+	mvs_64xx_phy_set_link_rate,
+	mvs_hw_max_link_rate,
+	mvs_64xx_phy_disable,
+	mvs_64xx_phy_enable,
+	mvs_64xx_phy_reset,
+	mvs_64xx_stp_reset,
+	mvs_64xx_clear_active_cmds,
+	mvs_64xx_spi_read_data,
+	mvs_64xx_spi_write_data,
+	mvs_64xx_spi_buildcmd,
+	mvs_64xx_spi_issuecmd,
+	mvs_64xx_spi_waitdataready,
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+	mvs_64xx_fix_dma,
+#endif
+};
+
diff --git a/drivers/scsi/mvsas/mv_64xx.h b/drivers/scsi/mvsas/mv_64xx.h
new file mode 100644
index 0000000..42e947d
--- /dev/null
+++ b/drivers/scsi/mvsas/mv_64xx.h
@@ -0,0 +1,151 @@
+/*
+ * Marvell 88SE64xx hardware specific head file
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+#ifndef _MVS64XX_REG_H_
+#define _MVS64XX_REG_H_
+
+#include <linux/types.h>
+
+#define MAX_LINK_RATE		SAS_LINK_RATE_3_0_GBPS
+
+/* enhanced mode registers (BAR4) */
+enum hw_registers {
+	MVS_GBL_CTL		= 0x04,  /* global control */
+	MVS_GBL_INT_STAT	= 0x08,  /* global irq status */
+	MVS_GBL_PI		= 0x0C,  /* ports implemented bitmask */
+
+	MVS_PHY_CTL		= 0x40,  /* SOC PHY Control */
+	MVS_PORTS_IMP		= 0x9C,  /* SOC Port Implemented */
+
+	MVS_GBL_PORT_TYPE	= 0xa0,  /* port type */
+
+	MVS_CTL			= 0x100, /* SAS/SATA port configuration */
+	MVS_PCS			= 0x104, /* SAS/SATA port control/status */
+	MVS_CMD_LIST_LO		= 0x108, /* cmd list addr */
+	MVS_CMD_LIST_HI		= 0x10C,
+	MVS_RX_FIS_LO		= 0x110, /* RX FIS list addr */
+	MVS_RX_FIS_HI		= 0x114,
+
+	MVS_TX_CFG		= 0x120, /* TX configuration */
+	MVS_TX_LO		= 0x124, /* TX (delivery) ring addr */
+	MVS_TX_HI		= 0x128,
+
+	MVS_TX_PROD_IDX		= 0x12C, /* TX producer pointer */
+	MVS_TX_CONS_IDX		= 0x130, /* TX consumer pointer (RO) */
+	MVS_RX_CFG		= 0x134, /* RX configuration */
+	MVS_RX_LO		= 0x138, /* RX (completion) ring addr */
+	MVS_RX_HI		= 0x13C,
+	MVS_RX_CONS_IDX		= 0x140, /* RX consumer pointer (RO) */
+
+	MVS_INT_COAL		= 0x148, /* Int coalescing config */
+	MVS_INT_COAL_TMOUT	= 0x14C, /* Int coalescing timeout */
+	MVS_INT_STAT		= 0x150, /* Central int status */
+	MVS_INT_MASK		= 0x154, /* Central int enable */
+	MVS_INT_STAT_SRS_0	= 0x158, /* SATA register set status */
+	MVS_INT_MASK_SRS_0	= 0x15C,
+
+					 /* ports 1-3 follow after this */
+	MVS_P0_INT_STAT		= 0x160, /* port0 interrupt status */
+	MVS_P0_INT_MASK		= 0x164, /* port0 interrupt mask */
+					 /* ports 5-7 follow after this */
+	MVS_P4_INT_STAT		= 0x200, /* Port4 interrupt status */
+	MVS_P4_INT_MASK		= 0x204, /* Port4 interrupt enable mask */
+
+					 /* ports 1-3 follow after this */
+	MVS_P0_SER_CTLSTAT	= 0x180, /* port0 serial control/status */
+					 /* ports 5-7 follow after this */
+	MVS_P4_SER_CTLSTAT	= 0x220, /* port4 serial control/status */
+
+	MVS_CMD_ADDR		= 0x1B8, /* Command register port (addr) */
+	MVS_CMD_DATA		= 0x1BC, /* Command register port (data) */
+
+					 /* ports 1-3 follow after this */
+	MVS_P0_CFG_ADDR		= 0x1C0, /* port0 phy register address */
+	MVS_P0_CFG_DATA		= 0x1C4, /* port0 phy register data */
+					 /* ports 5-7 follow after this */
+	MVS_P4_CFG_ADDR		= 0x230, /* Port4 config address */
+	MVS_P4_CFG_DATA		= 0x234, /* Port4 config data */
+
+					 /* ports 1-3 follow after this */
+	MVS_P0_VSR_ADDR		= 0x1E0, /* port0 VSR address */
+	MVS_P0_VSR_DATA		= 0x1E4, /* port0 VSR data */
+					 /* ports 5-7 follow after this */
+	MVS_P4_VSR_ADDR		= 0x250, /* port4 VSR addr */
+	MVS_P4_VSR_DATA		= 0x254, /* port4 VSR data */
+};
+
+enum pci_cfg_registers {
+	PCR_PHY_CTL		= 0x40,
+	PCR_PHY_CTL2		= 0x90,
+	PCR_DEV_CTRL		= 0xE8,
+	PCR_LINK_STAT		= 0xF2,
+};
+
+/*  SAS/SATA Vendor Specific Port Registers */
+enum sas_sata_vsp_regs {
+	VSR_PHY_STAT		= 0x00, /* Phy Status */
+	VSR_PHY_MODE1		= 0x01, /* phy tx */
+	VSR_PHY_MODE2		= 0x02, /* tx scc */
+	VSR_PHY_MODE3		= 0x03, /* pll */
+	VSR_PHY_MODE4		= 0x04, /* VCO */
+	VSR_PHY_MODE5		= 0x05, /* Rx */
+	VSR_PHY_MODE6		= 0x06, /* CDR */
+	VSR_PHY_MODE7		= 0x07, /* Impedance */
+	VSR_PHY_MODE8		= 0x08, /* Voltage */
+	VSR_PHY_MODE9		= 0x09, /* Test */
+	VSR_PHY_MODE10		= 0x0A, /* Power */
+	VSR_PHY_MODE11		= 0x0B, /* Phy Mode */
+	VSR_PHY_VS0		= 0x0C, /* Vednor Specific 0 */
+	VSR_PHY_VS1		= 0x0D, /* Vednor Specific 1 */
+};
+
+enum chip_register_bits {
+	PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8),
+	PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12),
+	PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16),
+	PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
+			(0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
+};
+
+#define MAX_SG_ENTRY		64
+
+struct mvs_prd {
+	__le64			addr;		/* 64-bit buffer address */
+	__le32			reserved;
+	__le32			len;		/* 16-bit length */
+};
+
+#define SPI_CTRL_REG				0xc0
+#define SPI_CTRL_VENDOR_ENABLE		(1U<<29)
+#define SPI_CTRL_SPIRDY         		(1U<<22)
+#define SPI_CTRL_SPISTART			(1U<<20)
+
+#define SPI_CMD_REG		0xc4
+#define SPI_DATA_REG		0xc8
+
+#define SPI_CTRL_REG_64XX		0x10
+#define SPI_CMD_REG_64XX		0x14
+#define SPI_DATA_REG_64XX		0x18
+
+#endif
diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c
new file mode 100644
index 0000000..0940fae
--- /dev/null
+++ b/drivers/scsi/mvsas/mv_94xx.c
@@ -0,0 +1,672 @@
+/*
+ * Marvell 88SE94xx hardware specific
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+#include "mv_sas.h"
+#include "mv_94xx.h"
+#include "mv_chips.h"
+
+static void mvs_94xx_detect_porttype(struct mvs_info *mvi, int i)
+{
+	u32 reg;
+	struct mvs_phy *phy = &mvi->phy[i];
+	u32 phy_status;
+
+	mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE3);
+	reg = mvs_read_port_vsr_data(mvi, i);
+	phy_status = ((reg & 0x3f0000) >> 16) & 0xff;
+	phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+	switch (phy_status) {
+	case 0x10:
+		phy->phy_type |= PORT_TYPE_SAS;
+		break;
+	case 0x1d:
+	default:
+		phy->phy_type |= PORT_TYPE_SATA;
+		break;
+	}
+}
+
+static void __devinit mvs_94xx_enable_xmt(struct mvs_info *mvi, int phy_id)
+{
+	void __iomem *regs = mvi->regs;
+	u32 tmp;
+
+	tmp = mr32(MVS_PCS);
+	tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2);
+	mw32(MVS_PCS, tmp);
+}
+
+static void mvs_94xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
+{
+	u32 tmp;
+
+	tmp = mvs_read_port_irq_stat(mvi, phy_id);
+	tmp &= ~PHYEV_RDY_CH;
+	mvs_write_port_irq_stat(mvi, phy_id, tmp);
+	if (hard) {
+		tmp = mvs_read_phy_ctl(mvi, phy_id);
+		tmp |= PHY_RST_HARD;
+		mvs_write_phy_ctl(mvi, phy_id, tmp);
+		do {
+			tmp = mvs_read_phy_ctl(mvi, phy_id);
+		} while (tmp & PHY_RST_HARD);
+	} else {
+		mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_STAT);
+		tmp = mvs_read_port_vsr_data(mvi, phy_id);
+		tmp |= PHY_RST;
+		mvs_write_port_vsr_data(mvi, phy_id, tmp);
+	}
+}
+
+static void mvs_94xx_phy_disable(struct mvs_info *mvi, u32 phy_id)
+{
+	u32 tmp;
+	mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2);
+	tmp = mvs_read_port_vsr_data(mvi, phy_id);
+	mvs_write_port_vsr_data(mvi, phy_id, tmp | 0x00800000);
+}
+
+static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
+{
+	mvs_write_port_vsr_addr(mvi, phy_id, 0x1B4);
+	mvs_write_port_vsr_data(mvi, phy_id, 0x8300ffc1);
+	mvs_write_port_vsr_addr(mvi, phy_id, 0x104);
+	mvs_write_port_vsr_data(mvi, phy_id, 0x00018080);
+	mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2);
+	mvs_write_port_vsr_data(mvi, phy_id, 0x00207fff);
+}
+
+static int __devinit mvs_94xx_init(struct mvs_info *mvi)
+{
+	void __iomem *regs = mvi->regs;
+	int i;
+	u32 tmp, cctl;
+
+	mvs_show_pcie_usage(mvi);
+	if (mvi->flags & MVF_FLAG_SOC) {
+		tmp = mr32(MVS_PHY_CTL);
+		tmp &= ~PCTL_PWR_OFF;
+		tmp |= PCTL_PHY_DSBL;
+		mw32(MVS_PHY_CTL, tmp);
+	}
+
+	/* Init Chip */
+	/* make sure RST is set; HBA_RST /should/ have done that for us */
+	cctl = mr32(MVS_CTL) & 0xFFFF;
+	if (cctl & CCTL_RST)
+		cctl &= ~CCTL_RST;
+	else
+		mw32_f(MVS_CTL, cctl | CCTL_RST);
+
+	if (mvi->flags & MVF_FLAG_SOC) {
+		tmp = mr32(MVS_PHY_CTL);
+		tmp &= ~PCTL_PWR_OFF;
+		tmp |= PCTL_COM_ON;
+		tmp &= ~PCTL_PHY_DSBL;
+		tmp |= PCTL_LINK_RST;
+		mw32(MVS_PHY_CTL, tmp);
+		msleep(100);
+		tmp &= ~PCTL_LINK_RST;
+		mw32(MVS_PHY_CTL, tmp);
+		msleep(100);
+	}
+
+	/* reset control */
+	mw32(MVS_PCS, 0);		/* MVS_PCS */
+	mw32(MVS_STP_REG_SET_0, 0);
+	mw32(MVS_STP_REG_SET_1, 0);
+
+	/* init phys */
+	mvs_phy_hacks(mvi);
+
+	/* disable Multiplexing, enable phy implemented */
+	mw32(MVS_PORTS_IMP, 0xFF);
+
+
+	mw32(MVS_PA_VSR_ADDR, 0x00000104);
+	mw32(MVS_PA_VSR_PORT, 0x00018080);
+	mw32(MVS_PA_VSR_ADDR, VSR_PHY_MODE8);
+	mw32(MVS_PA_VSR_PORT, 0x0084ffff);
+
+	/* set LED blink when IO*/
+	mw32(MVS_PA_VSR_ADDR, 0x00000030);
+	tmp = mr32(MVS_PA_VSR_PORT);
+	tmp &= 0xFFFF00FF;
+	tmp |= 0x00003300;
+	mw32(MVS_PA_VSR_PORT, tmp);
+
+	mw32(MVS_CMD_LIST_LO, mvi->slot_dma);
+	mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16);
+
+	mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma);
+	mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16);
+
+	mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ);
+	mw32(MVS_TX_LO, mvi->tx_dma);
+	mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16);
+
+	mw32(MVS_RX_CFG, MVS_RX_RING_SZ);
+	mw32(MVS_RX_LO, mvi->rx_dma);
+	mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16);
+
+	for (i = 0; i < mvi->chip->n_phy; i++) {
+		mvs_94xx_phy_disable(mvi, i);
+		/* set phy local SAS address */
+		mvs_set_sas_addr(mvi, i, CONFIG_ID_FRAME3, CONFIG_ID_FRAME4,
+						(mvi->phy[i].dev_sas_addr));
+
+		mvs_94xx_enable_xmt(mvi, i);
+		mvs_94xx_phy_enable(mvi, i);
+
+		mvs_94xx_phy_reset(mvi, i, 1);
+		msleep(500);
+		mvs_94xx_detect_porttype(mvi, i);
+	}
+
+	if (mvi->flags & MVF_FLAG_SOC) {
+		/* set select registers */
+		writel(0x0E008000, regs + 0x000);
+		writel(0x59000008, regs + 0x004);
+		writel(0x20, regs + 0x008);
+		writel(0x20, regs + 0x00c);
+		writel(0x20, regs + 0x010);
+		writel(0x20, regs + 0x014);
+		writel(0x20, regs + 0x018);
+		writel(0x20, regs + 0x01c);
+	}
+	for (i = 0; i < mvi->chip->n_phy; i++) {
+		/* clear phy int status */
+		tmp = mvs_read_port_irq_stat(mvi, i);
+		tmp &= ~PHYEV_SIG_FIS;
+		mvs_write_port_irq_stat(mvi, i, tmp);
+
+		/* set phy int mask */
+		tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH |
+			PHYEV_ID_DONE  | PHYEV_DCDR_ERR | PHYEV_CRC_ERR ;
+		mvs_write_port_irq_mask(mvi, i, tmp);
+
+		msleep(100);
+		mvs_update_phyinfo(mvi, i, 1);
+	}
+
+	/* FIXME: update wide port bitmaps */
+
+	/* little endian for open address and command table, etc. */
+	/*
+	 * it seems that ( from the spec ) turning on big-endian won't
+	 * do us any good on big-endian machines, need further confirmation
+	 */
+	cctl = mr32(MVS_CTL);
+	cctl |= CCTL_ENDIAN_CMD;
+	cctl |= CCTL_ENDIAN_DATA;
+	cctl &= ~CCTL_ENDIAN_OPEN;
+	cctl |= CCTL_ENDIAN_RSP;
+	mw32_f(MVS_CTL, cctl);
+
+	/* reset CMD queue */
+	tmp = mr32(MVS_PCS);
+	tmp |= PCS_CMD_RST;
+	mw32(MVS_PCS, tmp);
+	/* interrupt coalescing may cause missing HW interrput in some case,
+	 * and the max count is 0x1ff, while our max slot is 0x200,
+	 * it will make count 0.
+	 */
+	tmp = 0;
+	mw32(MVS_INT_COAL, tmp);
+
+	tmp = 0x100;
+	mw32(MVS_INT_COAL_TMOUT, tmp);
+
+	/* ladies and gentlemen, start your engines */
+	mw32(MVS_TX_CFG, 0);
+	mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN);
+	mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN);
+	/* enable CMD/CMPL_Q/RESP mode */
+	mw32(MVS_PCS, PCS_SATA_RETRY_2 | PCS_FIS_RX_EN |
+		PCS_CMD_EN | PCS_CMD_STOP_ERR);
+
+	/* enable completion queue interrupt */
+	tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP |
+		CINT_DMA_PCIE);
+	tmp |= CINT_PHY_MASK;
+	mw32(MVS_INT_MASK, tmp);
+
+	/* Enable SRS interrupt */
+	mw32(MVS_INT_MASK_SRS_0, 0xFFFF);
+
+	return 0;
+}
+
+static int mvs_94xx_ioremap(struct mvs_info *mvi)
+{
+	if (!mvs_ioremap(mvi, 2, -1)) {
+		mvi->regs_ex = mvi->regs + 0x10200;
+		mvi->regs += 0x20000;
+		if (mvi->id == 1)
+			mvi->regs += 0x4000;
+		return 0;
+	}
+	return -1;
+}
+
+static void mvs_94xx_iounmap(struct mvs_info *mvi)
+{
+	if (mvi->regs) {
+		mvi->regs -= 0x20000;
+		if (mvi->id == 1)
+			mvi->regs -= 0x4000;
+		mvs_iounmap(mvi->regs);
+	}
+}
+
+static void mvs_94xx_interrupt_enable(struct mvs_info *mvi)
+{
+	void __iomem *regs = mvi->regs_ex;
+	u32 tmp;
+
+	tmp = mr32(MVS_GBL_CTL);
+	tmp |= (IRQ_SAS_A | IRQ_SAS_B);
+	mw32(MVS_GBL_INT_STAT, tmp);
+	writel(tmp, regs + 0x0C);
+	writel(tmp, regs + 0x10);
+	writel(tmp, regs + 0x14);
+	writel(tmp, regs + 0x18);
+	mw32(MVS_GBL_CTL, tmp);
+}
+
+static void mvs_94xx_interrupt_disable(struct mvs_info *mvi)
+{
+	void __iomem *regs = mvi->regs_ex;
+	u32 tmp;
+
+	tmp = mr32(MVS_GBL_CTL);
+
+	tmp &= ~(IRQ_SAS_A | IRQ_SAS_B);
+	mw32(MVS_GBL_INT_STAT, tmp);
+	writel(tmp, regs + 0x0C);
+	writel(tmp, regs + 0x10);
+	writel(tmp, regs + 0x14);
+	writel(tmp, regs + 0x18);
+	mw32(MVS_GBL_CTL, tmp);
+}
+
+static u32 mvs_94xx_isr_status(struct mvs_info *mvi, int irq)
+{
+	void __iomem *regs = mvi->regs_ex;
+	u32 stat = 0;
+	if (!(mvi->flags & MVF_FLAG_SOC)) {
+		stat = mr32(MVS_GBL_INT_STAT);
+
+		if (!(stat & (IRQ_SAS_A | IRQ_SAS_B)))
+			return 0;
+	}
+	return stat;
+}
+
+static irqreturn_t mvs_94xx_isr(struct mvs_info *mvi, int irq, u32 stat)
+{
+	void __iomem *regs = mvi->regs;
+
+	if (((stat & IRQ_SAS_A) && mvi->id == 0) ||
+			((stat & IRQ_SAS_B) && mvi->id == 1)) {
+		mw32_f(MVS_INT_STAT, CINT_DONE);
+	#ifndef MVS_USE_TASKLET
+		spin_lock(&mvi->lock);
+	#endif
+		mvs_int_full(mvi);
+	#ifndef MVS_USE_TASKLET
+		spin_unlock(&mvi->lock);
+	#endif
+	}
+	return IRQ_HANDLED;
+}
+
+static void mvs_94xx_command_active(struct mvs_info *mvi, u32 slot_idx)
+{
+	u32 tmp;
+	mvs_cw32(mvi, 0x300 + (slot_idx >> 3), 1 << (slot_idx % 32));
+	do {
+		tmp = mvs_cr32(mvi, 0x300 + (slot_idx >> 3));
+	} while (tmp & 1 << (slot_idx % 32));
+}
+
+static void mvs_94xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type,
+				u32 tfs)
+{
+	void __iomem *regs = mvi->regs;
+	u32 tmp;
+
+	if (type == PORT_TYPE_SATA) {
+		tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs);
+		mw32(MVS_INT_STAT_SRS_0, tmp);
+	}
+	mw32(MVS_INT_STAT, CINT_CI_STOP);
+	tmp = mr32(MVS_PCS) | 0xFF00;
+	mw32(MVS_PCS, tmp);
+}
+
+static void mvs_94xx_free_reg_set(struct mvs_info *mvi, u8 *tfs)
+{
+	void __iomem *regs = mvi->regs;
+	u32 tmp;
+	u8 reg_set = *tfs;
+
+	if (*tfs == MVS_ID_NOT_MAPPED)
+		return;
+
+	mvi->sata_reg_set &= ~bit(reg_set);
+	if (reg_set < 32) {
+		w_reg_set_enable(reg_set, (u32)mvi->sata_reg_set);
+		tmp = mr32(MVS_INT_STAT_SRS_0) & (u32)mvi->sata_reg_set;
+		if (tmp)
+			mw32(MVS_INT_STAT_SRS_0, tmp);
+	} else {
+		w_reg_set_enable(reg_set, mvi->sata_reg_set);
+		tmp = mr32(MVS_INT_STAT_SRS_1) & mvi->sata_reg_set;
+		if (tmp)
+			mw32(MVS_INT_STAT_SRS_1, tmp);
+	}
+
+	*tfs = MVS_ID_NOT_MAPPED;
+
+	return;
+}
+
+static u8 mvs_94xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs)
+{
+	int i;
+	void __iomem *regs = mvi->regs;
+
+	if (*tfs != MVS_ID_NOT_MAPPED)
+		return 0;
+
+	i = mv_ffc64(mvi->sata_reg_set);
+	if (i > 32) {
+		mvi->sata_reg_set |= bit(i);
+		w_reg_set_enable(i, (u32)(mvi->sata_reg_set >> 32));
+		*tfs = i;
+		return 0;
+	} else if (i >= 0) {
+		mvi->sata_reg_set |= bit(i);
+		w_reg_set_enable(i, (u32)mvi->sata_reg_set);
+		*tfs = i;
+		return 0;
+	}
+	return MVS_ID_NOT_MAPPED;
+}
+
+static void mvs_94xx_make_prd(struct scatterlist *scatter, int nr, void *prd)
+{
+	int i;
+	struct scatterlist *sg;
+	struct mvs_prd *buf_prd = prd;
+	for_each_sg(scatter, sg, nr, i) {
+		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
+		buf_prd->im_len.len = cpu_to_le32(sg_dma_len(sg));
+		buf_prd++;
+	}
+}
+
+static int mvs_94xx_oob_done(struct mvs_info *mvi, int i)
+{
+	u32 phy_st;
+	phy_st = mvs_read_phy_ctl(mvi, i);
+	if (phy_st & PHY_READY_MASK)	/* phy ready */
+		return 1;
+	return 0;
+}
+
+static void mvs_94xx_get_dev_identify_frame(struct mvs_info *mvi, int port_id,
+					struct sas_identify_frame *id)
+{
+	int i;
+	u32 id_frame[7];
+
+	for (i = 0; i < 7; i++) {
+		mvs_write_port_cfg_addr(mvi, port_id,
+					CONFIG_ID_FRAME0 + i * 4);
+		id_frame[i] = mvs_read_port_cfg_data(mvi, port_id);
+	}
+	memcpy(id, id_frame, 28);
+}
+
+static void mvs_94xx_get_att_identify_frame(struct mvs_info *mvi, int port_id,
+					struct sas_identify_frame *id)
+{
+	int i;
+	u32 id_frame[7];
+
+	/* mvs_hexdump(28, (u8 *)id_frame, 0); */
+	for (i = 0; i < 7; i++) {
+		mvs_write_port_cfg_addr(mvi, port_id,
+					CONFIG_ATT_ID_FRAME0 + i * 4);
+		id_frame[i] = mvs_read_port_cfg_data(mvi, port_id);
+		mv_dprintk("94xx phy %d atta frame %d %x.\n",
+			port_id + mvi->id * mvi->chip->n_phy, i, id_frame[i]);
+	}
+	/* mvs_hexdump(28, (u8 *)id_frame, 0); */
+	memcpy(id, id_frame, 28);
+}
+
+static u32 mvs_94xx_make_dev_info(struct sas_identify_frame *id)
+{
+	u32 att_dev_info = 0;
+
+	att_dev_info |= id->dev_type;
+	if (id->stp_iport)
+		att_dev_info |= PORT_DEV_STP_INIT;
+	if (id->smp_iport)
+		att_dev_info |= PORT_DEV_SMP_INIT;
+	if (id->ssp_iport)
+		att_dev_info |= PORT_DEV_SSP_INIT;
+	if (id->stp_tport)
+		att_dev_info |= PORT_DEV_STP_TRGT;
+	if (id->smp_tport)
+		att_dev_info |= PORT_DEV_SMP_TRGT;
+	if (id->ssp_tport)
+		att_dev_info |= PORT_DEV_SSP_TRGT;
+
+	att_dev_info |= (u32)id->phy_id<<24;
+	return att_dev_info;
+}
+
+static u32 mvs_94xx_make_att_info(struct sas_identify_frame *id)
+{
+	return mvs_94xx_make_dev_info(id);
+}
+
+static void mvs_94xx_fix_phy_info(struct mvs_info *mvi, int i,
+				struct sas_identify_frame *id)
+{
+	struct mvs_phy *phy = &mvi->phy[i];
+	struct asd_sas_phy *sas_phy = &phy->sas_phy;
+	mv_dprintk("get all reg link rate is 0x%x\n", phy->phy_status);
+	sas_phy->linkrate =
+		(phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+			PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
+	sas_phy->linkrate += 0x8;
+	mv_dprintk("get link rate is %d\n", sas_phy->linkrate);
+	phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+	phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS;
+	mvs_94xx_get_dev_identify_frame(mvi, i, id);
+	phy->dev_info = mvs_94xx_make_dev_info(id);
+
+	if (phy->phy_type & PORT_TYPE_SAS) {
+		mvs_94xx_get_att_identify_frame(mvi, i, id);
+		phy->att_dev_info = mvs_94xx_make_att_info(id);
+		phy->att_dev_sas_addr = *(u64 *)id->sas_addr;
+	} else {
+		phy->att_dev_info = PORT_DEV_STP_TRGT | 1;
+	}
+
+}
+
+void mvs_94xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
+			struct sas_phy_linkrates *rates)
+{
+	/* TODO */
+}
+
+static void mvs_94xx_clear_active_cmds(struct mvs_info *mvi)
+{
+	u32 tmp;
+	void __iomem *regs = mvi->regs;
+	tmp = mr32(MVS_STP_REG_SET_0);
+	mw32(MVS_STP_REG_SET_0, 0);
+	mw32(MVS_STP_REG_SET_0, tmp);
+	tmp = mr32(MVS_STP_REG_SET_1);
+	mw32(MVS_STP_REG_SET_1, 0);
+	mw32(MVS_STP_REG_SET_1, tmp);
+}
+
+
+u32 mvs_94xx_spi_read_data(struct mvs_info *mvi)
+{
+	void __iomem *regs = mvi->regs_ex - 0x10200;
+	return mr32(SPI_RD_DATA_REG_94XX);
+}
+
+void mvs_94xx_spi_write_data(struct mvs_info *mvi, u32 data)
+{
+	void __iomem *regs = mvi->regs_ex - 0x10200;
+	 mw32(SPI_RD_DATA_REG_94XX, data);
+}
+
+
+int mvs_94xx_spi_buildcmd(struct mvs_info *mvi,
+				u32      *dwCmd,
+				u8       cmd,
+				u8       read,
+				u8       length,
+				u32      addr
+				)
+{
+	void __iomem *regs = mvi->regs_ex - 0x10200;
+	u32  dwTmp;
+
+	dwTmp = ((u32)cmd << 8) | ((u32)length << 4);
+	if (read)
+		dwTmp |= SPI_CTRL_READ_94XX;
+
+	if (addr != MV_MAX_U32) {
+		mw32(SPI_ADDR_REG_94XX, (addr & 0x0003FFFFL));
+		dwTmp |= SPI_ADDR_VLD_94XX;
+	}
+
+	*dwCmd = dwTmp;
+	return 0;
+}
+
+
+int mvs_94xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd)
+{
+	void __iomem *regs = mvi->regs_ex - 0x10200;
+	mw32(SPI_CTRL_REG_94XX, cmd | SPI_CTRL_SpiStart_94XX);
+
+	return 0;
+}
+
+int mvs_94xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
+{
+	void __iomem *regs = mvi->regs_ex - 0x10200;
+	u32   i, dwTmp;
+
+	for (i = 0; i < timeout; i++) {
+		dwTmp = mr32(SPI_CTRL_REG_94XX);
+		if (!(dwTmp & SPI_CTRL_SpiStart_94XX))
+			return 0;
+		msleep(10);
+	}
+
+	return -1;
+}
+
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+void mvs_94xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)
+{
+	int i;
+	struct mvs_prd *buf_prd = prd;
+	buf_prd += from;
+	for (i = 0; i < MAX_SG_ENTRY - from; i++) {
+		buf_prd->addr = cpu_to_le64(buf_dma);
+		buf_prd->im_len.len = cpu_to_le32(buf_len);
+		++buf_prd;
+	}
+}
+#endif
+
+const struct mvs_dispatch mvs_94xx_dispatch = {
+	"mv94xx",
+	mvs_94xx_init,
+	NULL,
+	mvs_94xx_ioremap,
+	mvs_94xx_iounmap,
+	mvs_94xx_isr,
+	mvs_94xx_isr_status,
+	mvs_94xx_interrupt_enable,
+	mvs_94xx_interrupt_disable,
+	mvs_read_phy_ctl,
+	mvs_write_phy_ctl,
+	mvs_read_port_cfg_data,
+	mvs_write_port_cfg_data,
+	mvs_write_port_cfg_addr,
+	mvs_read_port_vsr_data,
+	mvs_write_port_vsr_data,
+	mvs_write_port_vsr_addr,
+	mvs_read_port_irq_stat,
+	mvs_write_port_irq_stat,
+	mvs_read_port_irq_mask,
+	mvs_write_port_irq_mask,
+	mvs_get_sas_addr,
+	mvs_94xx_command_active,
+	mvs_94xx_issue_stop,
+	mvs_start_delivery,
+	mvs_rx_update,
+	mvs_int_full,
+	mvs_94xx_assign_reg_set,
+	mvs_94xx_free_reg_set,
+	mvs_get_prd_size,
+	mvs_get_prd_count,
+	mvs_94xx_make_prd,
+	mvs_94xx_detect_porttype,
+	mvs_94xx_oob_done,
+	mvs_94xx_fix_phy_info,
+	NULL,
+	mvs_94xx_phy_set_link_rate,
+	mvs_hw_max_link_rate,
+	mvs_94xx_phy_disable,
+	mvs_94xx_phy_enable,
+	mvs_94xx_phy_reset,
+	NULL,
+	mvs_94xx_clear_active_cmds,
+	mvs_94xx_spi_read_data,
+	mvs_94xx_spi_write_data,
+	mvs_94xx_spi_buildcmd,
+	mvs_94xx_spi_issuecmd,
+	mvs_94xx_spi_waitdataready,
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+	mvs_94xx_fix_dma,
+#endif
+};
+
diff --git a/drivers/scsi/mvsas/mv_94xx.h b/drivers/scsi/mvsas/mv_94xx.h
new file mode 100644
index 0000000..23ed9b1
--- /dev/null
+++ b/drivers/scsi/mvsas/mv_94xx.h
@@ -0,0 +1,222 @@
+/*
+ * Marvell 88SE94xx hardware specific head file
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+#ifndef _MVS94XX_REG_H_
+#define _MVS94XX_REG_H_
+
+#include <linux/types.h>
+
+#define MAX_LINK_RATE		SAS_LINK_RATE_6_0_GBPS
+
+enum hw_registers {
+	MVS_GBL_CTL		= 0x04,  /* global control */
+	MVS_GBL_INT_STAT	= 0x00,  /* global irq status */
+	MVS_GBL_PI		= 0x0C,  /* ports implemented bitmask */
+
+	MVS_PHY_CTL		= 0x40,  /* SOC PHY Control */
+	MVS_PORTS_IMP		= 0x9C,  /* SOC Port Implemented */
+
+	MVS_GBL_PORT_TYPE	= 0xa0,  /* port type */
+
+	MVS_CTL			= 0x100, /* SAS/SATA port configuration */
+	MVS_PCS			= 0x104, /* SAS/SATA port control/status */
+	MVS_CMD_LIST_LO		= 0x108, /* cmd list addr */
+	MVS_CMD_LIST_HI		= 0x10C,
+	MVS_RX_FIS_LO		= 0x110, /* RX FIS list addr */
+	MVS_RX_FIS_HI		= 0x114,
+	MVS_STP_REG_SET_0	= 0x118, /* STP/SATA Register Set Enable */
+	MVS_STP_REG_SET_1	= 0x11C,
+	MVS_TX_CFG		= 0x120, /* TX configuration */
+	MVS_TX_LO		= 0x124, /* TX (delivery) ring addr */
+	MVS_TX_HI		= 0x128,
+
+	MVS_TX_PROD_IDX		= 0x12C, /* TX producer pointer */
+	MVS_TX_CONS_IDX		= 0x130, /* TX consumer pointer (RO) */
+	MVS_RX_CFG		= 0x134, /* RX configuration */
+	MVS_RX_LO		= 0x138, /* RX (completion) ring addr */
+	MVS_RX_HI		= 0x13C,
+	MVS_RX_CONS_IDX		= 0x140, /* RX consumer pointer (RO) */
+
+	MVS_INT_COAL		= 0x148, /* Int coalescing config */
+	MVS_INT_COAL_TMOUT	= 0x14C, /* Int coalescing timeout */
+	MVS_INT_STAT		= 0x150, /* Central int status */
+	MVS_INT_MASK		= 0x154, /* Central int enable */
+	MVS_INT_STAT_SRS_0	= 0x158, /* SATA register set status */
+	MVS_INT_MASK_SRS_0	= 0x15C,
+	MVS_INT_STAT_SRS_1	= 0x160,
+	MVS_INT_MASK_SRS_1	= 0x164,
+	MVS_NON_NCQ_ERR_0	= 0x168, /* SRS Non-specific NCQ Error */
+	MVS_NON_NCQ_ERR_1	= 0x16C,
+	MVS_CMD_ADDR		= 0x170, /* Command register port (addr) */
+	MVS_CMD_DATA		= 0x174, /* Command register port (data) */
+	MVS_MEM_PARITY_ERR	= 0x178, /* Memory parity error */
+
+					 /* ports 1-3 follow after this */
+	MVS_P0_INT_STAT		= 0x180, /* port0 interrupt status */
+	MVS_P0_INT_MASK		= 0x184, /* port0 interrupt mask */
+					 /* ports 5-7 follow after this */
+	MVS_P4_INT_STAT		= 0x1A0, /* Port4 interrupt status */
+	MVS_P4_INT_MASK		= 0x1A4, /* Port4 interrupt enable mask */
+
+					 /* ports 1-3 follow after this */
+	MVS_P0_SER_CTLSTAT	= 0x1D0, /* port0 serial control/status */
+					 /* ports 5-7 follow after this */
+	MVS_P4_SER_CTLSTAT	= 0x1E0, /* port4 serial control/status */
+
+					 /* ports 1-3 follow after this */
+	MVS_P0_CFG_ADDR		= 0x200, /* port0 phy register address */
+	MVS_P0_CFG_DATA		= 0x204, /* port0 phy register data */
+					 /* ports 5-7 follow after this */
+	MVS_P4_CFG_ADDR		= 0x220, /* Port4 config address */
+	MVS_P4_CFG_DATA		= 0x224, /* Port4 config data */
+
+					 /* phys 1-3 follow after this */
+	MVS_P0_VSR_ADDR		= 0x250, /* phy0 VSR address */
+	MVS_P0_VSR_DATA		= 0x254, /* phy0 VSR data */
+					 /* phys 1-3 follow after this */
+					 /* multiplexing */
+	MVS_P4_VSR_ADDR 	= 0x250, /* phy4 VSR address */
+	MVS_P4_VSR_DATA 	= 0x254, /* phy4 VSR data */
+	MVS_PA_VSR_ADDR		= 0x290, /* All port VSR addr */
+	MVS_PA_VSR_PORT		= 0x294, /* All port VSR data */
+};
+
+enum pci_cfg_registers {
+	PCR_PHY_CTL		= 0x40,
+	PCR_PHY_CTL2		= 0x90,
+	PCR_DEV_CTRL		= 0x78,
+	PCR_LINK_STAT		= 0x82,
+};
+
+/*  SAS/SATA Vendor Specific Port Registers */
+enum sas_sata_vsp_regs {
+	VSR_PHY_STAT		= 0x00 * 4, /* Phy Status */
+	VSR_PHY_MODE1		= 0x01 * 4, /* phy tx */
+	VSR_PHY_MODE2		= 0x02 * 4, /* tx scc */
+	VSR_PHY_MODE3		= 0x03 * 4, /* pll */
+	VSR_PHY_MODE4		= 0x04 * 4, /* VCO */
+	VSR_PHY_MODE5		= 0x05 * 4, /* Rx */
+	VSR_PHY_MODE6		= 0x06 * 4, /* CDR */
+	VSR_PHY_MODE7		= 0x07 * 4, /* Impedance */
+	VSR_PHY_MODE8		= 0x08 * 4, /* Voltage */
+	VSR_PHY_MODE9		= 0x09 * 4, /* Test */
+	VSR_PHY_MODE10		= 0x0A * 4, /* Power */
+	VSR_PHY_MODE11		= 0x0B * 4, /* Phy Mode */
+	VSR_PHY_VS0		= 0x0C * 4, /* Vednor Specific 0 */
+	VSR_PHY_VS1		= 0x0D * 4, /* Vednor Specific 1 */
+};
+
+enum chip_register_bits {
+	PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0x7 << 8),
+	PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0x7 << 8),
+	PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (12),
+	PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
+			(0x3 << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
+};
+
+enum pci_interrupt_cause {
+	/*  MAIN_IRQ_CAUSE (R10200) Bits*/
+	IRQ_COM_IN_I2O_IOP0            = (1 << 0),
+	IRQ_COM_IN_I2O_IOP1            = (1 << 1),
+	IRQ_COM_IN_I2O_IOP2            = (1 << 2),
+	IRQ_COM_IN_I2O_IOP3            = (1 << 3),
+	IRQ_COM_OUT_I2O_HOS0           = (1 << 4),
+	IRQ_COM_OUT_I2O_HOS1           = (1 << 5),
+	IRQ_COM_OUT_I2O_HOS2           = (1 << 6),
+	IRQ_COM_OUT_I2O_HOS3           = (1 << 7),
+	IRQ_PCIF_TO_CPU_DRBL0          = (1 << 8),
+	IRQ_PCIF_TO_CPU_DRBL1          = (1 << 9),
+	IRQ_PCIF_TO_CPU_DRBL2          = (1 << 10),
+	IRQ_PCIF_TO_CPU_DRBL3          = (1 << 11),
+	IRQ_PCIF_DRBL0                 = (1 << 12),
+	IRQ_PCIF_DRBL1                 = (1 << 13),
+	IRQ_PCIF_DRBL2                 = (1 << 14),
+	IRQ_PCIF_DRBL3                 = (1 << 15),
+	IRQ_XOR_A                      = (1 << 16),
+	IRQ_XOR_B                      = (1 << 17),
+	IRQ_SAS_A                      = (1 << 18),
+	IRQ_SAS_B                      = (1 << 19),
+	IRQ_CPU_CNTRL                  = (1 << 20),
+	IRQ_GPIO                       = (1 << 21),
+	IRQ_UART                       = (1 << 22),
+	IRQ_SPI                        = (1 << 23),
+	IRQ_I2C                        = (1 << 24),
+	IRQ_SGPIO                      = (1 << 25),
+	IRQ_COM_ERR                    = (1 << 29),
+	IRQ_I2O_ERR                    = (1 << 30),
+	IRQ_PCIE_ERR                   = (1 << 31),
+};
+
+#define MAX_SG_ENTRY		255
+
+struct mvs_prd_imt {
+	__le32			len:22;
+	u8			_r_a:2;
+	u8			misc_ctl:4;
+	u8			inter_sel:4;
+};
+
+struct mvs_prd {
+	/* 64-bit buffer address */
+	__le64			addr;
+	/* 22-bit length */
+	struct mvs_prd_imt	im_len;
+} __attribute__ ((packed));
+
+#define SPI_CTRL_REG_94XX           	0xc800
+#define SPI_ADDR_REG_94XX            	0xc804
+#define SPI_WR_DATA_REG_94XX         0xc808
+#define SPI_RD_DATA_REG_94XX         	0xc80c
+#define SPI_CTRL_READ_94XX         	(1U << 2)
+#define SPI_ADDR_VLD_94XX         	(1U << 1)
+#define SPI_CTRL_SpiStart_94XX     	(1U << 0)
+
+#define mv_ffc(x)   ffz(x)
+
+static inline int
+mv_ffc64(u64 v)
+{
+	int i;
+	i = mv_ffc((u32)v);
+	if (i >= 0)
+		return i;
+	i = mv_ffc((u32)(v>>32));
+
+	if (i != 0)
+		return 32 + i;
+
+	return -1;
+}
+
+#define r_reg_set_enable(i) \
+	(((i) > 31) ? mr32(MVS_STP_REG_SET_1) : \
+	mr32(MVS_STP_REG_SET_0))
+
+#define w_reg_set_enable(i, tmp) \
+	(((i) > 31) ? mw32(MVS_STP_REG_SET_1, tmp) : \
+	mw32(MVS_STP_REG_SET_0, tmp))
+
+extern const struct mvs_dispatch mvs_94xx_dispatch;
+#endif
+
diff --git a/drivers/scsi/mvsas/mv_chips.h b/drivers/scsi/mvsas/mv_chips.h
new file mode 100644
index 0000000..a67e1c4
--- /dev/null
+++ b/drivers/scsi/mvsas/mv_chips.h
@@ -0,0 +1,280 @@
+/*
+ * Marvell 88SE64xx/88SE94xx register IO interface
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+
+#ifndef _MV_CHIPS_H_
+#define _MV_CHIPS_H_
+
+#define mr32(reg)	readl(regs + reg)
+#define mw32(reg, val)	writel((val), regs + reg)
+#define mw32_f(reg, val)	do {			\
+				mw32(reg, val);	\
+				mr32(reg);	\
+			} while (0)
+
+#define iow32(reg, val) 	outl(val, (unsigned long)(regs + reg))
+#define ior32(reg) 		inl((unsigned long)(regs + reg))
+#define iow16(reg, val) 	outw((unsigned long)(val, regs + reg))
+#define ior16(reg) 		inw((unsigned long)(regs + reg))
+#define iow8(reg, val) 		outb((unsigned long)(val, regs + reg))
+#define ior8(reg) 		inb((unsigned long)(regs + reg))
+
+static inline u32 mvs_cr32(struct mvs_info *mvi, u32 addr)
+{
+	void __iomem *regs = mvi->regs;
+	mw32(MVS_CMD_ADDR, addr);
+	return mr32(MVS_CMD_DATA);
+}
+
+static inline void mvs_cw32(struct mvs_info *mvi, u32 addr, u32 val)
+{
+	void __iomem *regs = mvi->regs;
+	mw32(MVS_CMD_ADDR, addr);
+	mw32(MVS_CMD_DATA, val);
+}
+
+static inline u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port)
+{
+	void __iomem *regs = mvi->regs;
+	return (port < 4) ? mr32(MVS_P0_SER_CTLSTAT + port * 4) :
+		mr32(MVS_P4_SER_CTLSTAT + (port - 4) * 4);
+}
+
+static inline void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val)
+{
+	void __iomem *regs = mvi->regs;
+	if (port < 4)
+		mw32(MVS_P0_SER_CTLSTAT + port * 4, val);
+	else
+		mw32(MVS_P4_SER_CTLSTAT + (port - 4) * 4, val);
+}
+
+static inline u32 mvs_read_port(struct mvs_info *mvi, u32 off,
+				u32 off2, u32 port)
+{
+	void __iomem *regs = mvi->regs + off;
+	void __iomem *regs2 = mvi->regs + off2;
+	return (port < 4) ? readl(regs + port * 8) :
+		readl(regs2 + (port - 4) * 8);
+}
+
+static inline void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2,
+				u32 port, u32 val)
+{
+	void __iomem *regs = mvi->regs + off;
+	void __iomem *regs2 = mvi->regs + off2;
+	if (port < 4)
+		writel(val, regs + port * 8);
+	else
+		writel(val, regs2 + (port - 4) * 8);
+}
+
+static inline u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port)
+{
+	return mvs_read_port(mvi, MVS_P0_CFG_DATA,
+			MVS_P4_CFG_DATA, port);
+}
+
+static inline void mvs_write_port_cfg_data(struct mvs_info *mvi,
+						u32 port, u32 val)
+{
+	mvs_write_port(mvi, MVS_P0_CFG_DATA,
+			MVS_P4_CFG_DATA, port, val);
+}
+
+static inline void mvs_write_port_cfg_addr(struct mvs_info *mvi,
+						u32 port, u32 addr)
+{
+	mvs_write_port(mvi, MVS_P0_CFG_ADDR,
+			MVS_P4_CFG_ADDR, port, addr);
+	mdelay(10);
+}
+
+static inline u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port)
+{
+	return mvs_read_port(mvi, MVS_P0_VSR_DATA,
+			MVS_P4_VSR_DATA, port);
+}
+
+static inline void mvs_write_port_vsr_data(struct mvs_info *mvi,
+						u32 port, u32 val)
+{
+	mvs_write_port(mvi, MVS_P0_VSR_DATA,
+			MVS_P4_VSR_DATA, port, val);
+}
+
+static inline void mvs_write_port_vsr_addr(struct mvs_info *mvi,
+						u32 port, u32 addr)
+{
+	mvs_write_port(mvi, MVS_P0_VSR_ADDR,
+			MVS_P4_VSR_ADDR, port, addr);
+	mdelay(10);
+}
+
+static inline u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port)
+{
+	return mvs_read_port(mvi, MVS_P0_INT_STAT,
+			MVS_P4_INT_STAT, port);
+}
+
+static inline void mvs_write_port_irq_stat(struct mvs_info *mvi,
+						u32 port, u32 val)
+{
+	mvs_write_port(mvi, MVS_P0_INT_STAT,
+			MVS_P4_INT_STAT, port, val);
+}
+
+static inline u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port)
+{
+	return mvs_read_port(mvi, MVS_P0_INT_MASK,
+			MVS_P4_INT_MASK, port);
+
+}
+
+static inline void mvs_write_port_irq_mask(struct mvs_info *mvi,
+						u32 port, u32 val)
+{
+	mvs_write_port(mvi, MVS_P0_INT_MASK,
+			MVS_P4_INT_MASK, port, val);
+}
+
+static inline void __devinit mvs_phy_hacks(struct mvs_info *mvi)
+{
+	u32 tmp;
+
+	/* workaround for SATA R-ERR, to ignore phy glitch */
+	tmp = mvs_cr32(mvi, CMD_PHY_TIMER);
+	tmp &= ~(1 << 9);
+	tmp |= (1 << 10);
+	mvs_cw32(mvi, CMD_PHY_TIMER, tmp);
+
+	/* enable retry 127 times */
+	mvs_cw32(mvi, CMD_SAS_CTL1, 0x7f7f);
+
+	/* extend open frame timeout to max */
+	tmp = mvs_cr32(mvi, CMD_SAS_CTL0);
+	tmp &= ~0xffff;
+	tmp |= 0x3fff;
+	mvs_cw32(mvi, CMD_SAS_CTL0, tmp);
+
+	/* workaround for WDTIMEOUT , set to 550 ms */
+	mvs_cw32(mvi, CMD_WD_TIMER, 0x7a0000);
+
+	/* not to halt for different port op during wideport link change */
+	mvs_cw32(mvi, CMD_APP_ERR_CONFIG, 0xffefbf7d);
+
+	/* workaround for Seagate disk not-found OOB sequence, recv
+	 * COMINIT before sending out COMWAKE */
+	tmp = mvs_cr32(mvi, CMD_PHY_MODE_21);
+	tmp &= 0x0000ffff;
+	tmp |= 0x00fa0000;
+	mvs_cw32(mvi, CMD_PHY_MODE_21, tmp);
+
+	tmp = mvs_cr32(mvi, CMD_PHY_TIMER);
+	tmp &= 0x1fffffff;
+	tmp |= (2U << 29);	/* 8 ms retry */
+	mvs_cw32(mvi, CMD_PHY_TIMER, tmp);
+}
+
+static inline void mvs_int_sata(struct mvs_info *mvi)
+{
+	u32 tmp;
+	void __iomem *regs = mvi->regs;
+	tmp = mr32(MVS_INT_STAT_SRS_0);
+	if (tmp)
+		mw32(MVS_INT_STAT_SRS_0, tmp);
+	MVS_CHIP_DISP->clear_active_cmds(mvi);
+}
+
+static inline void mvs_int_full(struct mvs_info *mvi)
+{
+	void __iomem *regs = mvi->regs;
+	u32 tmp, stat;
+	int i;
+
+	stat = mr32(MVS_INT_STAT);
+	mvs_int_rx(mvi, false);
+
+	for (i = 0; i < mvi->chip->n_phy; i++) {
+		tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED);
+		if (tmp)
+			mvs_int_port(mvi, i, tmp);
+	}
+
+	if (stat & CINT_SRS)
+		mvs_int_sata(mvi);
+
+	mw32(MVS_INT_STAT, stat);
+}
+
+static inline void mvs_start_delivery(struct mvs_info *mvi, u32 tx)
+{
+	void __iomem *regs = mvi->regs;
+	mw32(MVS_TX_PROD_IDX, tx);
+}
+
+static inline u32 mvs_rx_update(struct mvs_info *mvi)
+{
+	void __iomem *regs = mvi->regs;
+	return mr32(MVS_RX_CONS_IDX);
+}
+
+static inline u32 mvs_get_prd_size(void)
+{
+	return sizeof(struct mvs_prd);
+}
+
+static inline u32 mvs_get_prd_count(void)
+{
+	return MAX_SG_ENTRY;
+}
+
+static inline void mvs_show_pcie_usage(struct mvs_info *mvi)
+{
+	u16 link_stat, link_spd;
+	const char *spd[] = {
+		"UnKnown",
+		"2.5",
+		"5.0",
+	};
+	if (mvi->flags & MVF_FLAG_SOC || mvi->id > 0)
+		return;
+
+	pci_read_config_word(mvi->pdev, PCR_LINK_STAT, &link_stat);
+	link_spd = (link_stat & PLS_LINK_SPD) >> PLS_LINK_SPD_OFFS;
+	if (link_spd >= 3)
+		link_spd = 0;
+	dev_printk(KERN_INFO, mvi->dev,
+		"mvsas: PCI-E x%u, Bandwidth Usage: %s Gbps\n",
+	       (link_stat & PLS_NEG_LINK_WD) >> PLS_NEG_LINK_WD_OFFS,
+	       spd[link_spd]);
+}
+
+static inline u32 mvs_hw_max_link_rate(void)
+{
+	return MAX_LINK_RATE;
+}
+
+#endif  /* _MV_CHIPS_H_ */
+
diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h
new file mode 100644
index 0000000..f8cb9de
--- /dev/null
+++ b/drivers/scsi/mvsas/mv_defs.h
@@ -0,0 +1,502 @@
+/*
+ * Marvell 88SE64xx/88SE94xx const head file
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+#ifndef _MV_DEFS_H_
+#define _MV_DEFS_H_
+
+
+enum chip_flavors {
+	chip_6320,
+	chip_6440,
+	chip_6485,
+	chip_9480,
+	chip_9180,
+};
+
+/* driver compile-time configuration */
+enum driver_configuration {
+	MVS_SLOTS		= 512,	/* command slots */
+	MVS_TX_RING_SZ		= 1024,	/* TX ring size (12-bit) */
+	MVS_RX_RING_SZ		= 1024, /* RX ring size (12-bit) */
+					/* software requires power-of-2
+					   ring size */
+	MVS_SOC_SLOTS		= 64,
+	MVS_SOC_TX_RING_SZ	= MVS_SOC_SLOTS * 2,
+	MVS_SOC_RX_RING_SZ	= MVS_SOC_SLOTS * 2,
+
+	MVS_SLOT_BUF_SZ		= 8192, /* cmd tbl + IU + status + PRD */
+	MVS_SSP_CMD_SZ		= 64,	/* SSP command table buffer size */
+	MVS_ATA_CMD_SZ		= 96,	/* SATA command table buffer size */
+	MVS_OAF_SZ		= 64,	/* Open address frame buffer size */
+	MVS_QUEUE_SIZE	= 32,	/* Support Queue depth */
+	MVS_CAN_QUEUE		= MVS_SLOTS - 2,	/* SCSI Queue depth */
+	MVS_SOC_CAN_QUEUE	= MVS_SOC_SLOTS - 2,
+};
+
+/* unchangeable hardware details */
+enum hardware_details {
+	MVS_MAX_PHYS		= 8,	/* max. possible phys */
+	MVS_MAX_PORTS		= 8,	/* max. possible ports */
+	MVS_SOC_PHYS		= 4,	/* soc phys */
+	MVS_SOC_PORTS		= 4,	/* soc phys */
+	MVS_MAX_DEVICES	= 1024,	/* max supported device */
+};
+
+/* peripheral registers (BAR2) */
+enum peripheral_registers {
+	SPI_CTL			= 0x10,	/* EEPROM control */
+	SPI_CMD			= 0x14,	/* EEPROM command */
+	SPI_DATA		= 0x18, /* EEPROM data */
+};
+
+enum peripheral_register_bits {
+	TWSI_RDY		= (1U << 7),	/* EEPROM interface ready */
+	TWSI_RD			= (1U << 4),	/* EEPROM read access */
+
+	SPI_ADDR_MASK		= 0x3ffff,	/* bits 17:0 */
+};
+
+enum hw_register_bits {
+	/* MVS_GBL_CTL */
+	INT_EN			= (1U << 1),	/* Global int enable */
+	HBA_RST			= (1U << 0),	/* HBA reset */
+
+	/* MVS_GBL_INT_STAT */
+	INT_XOR			= (1U << 4),	/* XOR engine event */
+	INT_SAS_SATA		= (1U << 0),	/* SAS/SATA event */
+
+	/* MVS_GBL_PORT_TYPE */			/* shl for ports 1-3 */
+	SATA_TARGET		= (1U << 16),	/* port0 SATA target enable */
+	MODE_AUTO_DET_PORT7 = (1U << 15),	/* port0 SAS/SATA autodetect */
+	MODE_AUTO_DET_PORT6 = (1U << 14),
+	MODE_AUTO_DET_PORT5 = (1U << 13),
+	MODE_AUTO_DET_PORT4 = (1U << 12),
+	MODE_AUTO_DET_PORT3 = (1U << 11),
+	MODE_AUTO_DET_PORT2 = (1U << 10),
+	MODE_AUTO_DET_PORT1 = (1U << 9),
+	MODE_AUTO_DET_PORT0 = (1U << 8),
+	MODE_AUTO_DET_EN    =	MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 |
+				MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 |
+				MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 |
+				MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7,
+	MODE_SAS_PORT7_MASK = (1U << 7),  /* port0 SAS(1), SATA(0) mode */
+	MODE_SAS_PORT6_MASK = (1U << 6),
+	MODE_SAS_PORT5_MASK = (1U << 5),
+	MODE_SAS_PORT4_MASK = (1U << 4),
+	MODE_SAS_PORT3_MASK = (1U << 3),
+	MODE_SAS_PORT2_MASK = (1U << 2),
+	MODE_SAS_PORT1_MASK = (1U << 1),
+	MODE_SAS_PORT0_MASK = (1U << 0),
+	MODE_SAS_SATA	=	MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK |
+				MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK |
+				MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK |
+				MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK,
+
+				/* SAS_MODE value may be
+				 * dictated (in hw) by values
+				 * of SATA_TARGET & AUTO_DET
+				 */
+
+	/* MVS_TX_CFG */
+	TX_EN			= (1U << 16),	/* Enable TX */
+	TX_RING_SZ_MASK		= 0xfff,	/* TX ring size, bits 11:0 */
+
+	/* MVS_RX_CFG */
+	RX_EN			= (1U << 16),	/* Enable RX */
+	RX_RING_SZ_MASK		= 0xfff,	/* RX ring size, bits 11:0 */
+
+	/* MVS_INT_COAL */
+	COAL_EN			= (1U << 16),	/* Enable int coalescing */
+
+	/* MVS_INT_STAT, MVS_INT_MASK */
+	CINT_I2C		= (1U << 31),	/* I2C event */
+	CINT_SW0		= (1U << 30),	/* software event 0 */
+	CINT_SW1		= (1U << 29),	/* software event 1 */
+	CINT_PRD_BC		= (1U << 28),	/* PRD BC err for read cmd */
+	CINT_DMA_PCIE		= (1U << 27),	/* DMA to PCIE timeout */
+	CINT_MEM		= (1U << 26),	/* int mem parity err */
+	CINT_I2C_SLAVE		= (1U << 25),	/* slave I2C event */
+	CINT_SRS		= (1U << 3),	/* SRS event */
+	CINT_CI_STOP		= (1U << 1),	/* cmd issue stopped */
+	CINT_DONE		= (1U << 0),	/* cmd completion */
+
+						/* shl for ports 1-3 */
+	CINT_PORT_STOPPED	= (1U << 16),	/* port0 stopped */
+	CINT_PORT		= (1U << 8),	/* port0 event */
+	CINT_PORT_MASK_OFFSET	= 8,
+	CINT_PORT_MASK		= (0xFF << CINT_PORT_MASK_OFFSET),
+	CINT_PHY_MASK_OFFSET	= 4,
+	CINT_PHY_MASK		= (0x0F << CINT_PHY_MASK_OFFSET),
+
+	/* TX (delivery) ring bits */
+	TXQ_CMD_SHIFT		= 29,
+	TXQ_CMD_SSP		= 1,		/* SSP protocol */
+	TXQ_CMD_SMP		= 2,		/* SMP protocol */
+	TXQ_CMD_STP		= 3,		/* STP/SATA protocol */
+	TXQ_CMD_SSP_FREE_LIST	= 4,		/* add to SSP targ free list */
+	TXQ_CMD_SLOT_RESET	= 7,		/* reset command slot */
+	TXQ_MODE_I		= (1U << 28),	/* mode: 0=target,1=initiator */
+	TXQ_MODE_TARGET 	= 0,
+	TXQ_MODE_INITIATOR	= 1,
+	TXQ_PRIO_HI		= (1U << 27),	/* priority: 0=normal, 1=high */
+	TXQ_PRI_NORMAL		= 0,
+	TXQ_PRI_HIGH		= 1,
+	TXQ_SRS_SHIFT		= 20,		/* SATA register set */
+	TXQ_SRS_MASK		= 0x7f,
+	TXQ_PHY_SHIFT		= 12,		/* PHY bitmap */
+	TXQ_PHY_MASK		= 0xff,
+	TXQ_SLOT_MASK		= 0xfff,	/* slot number */
+
+	/* RX (completion) ring bits */
+	RXQ_GOOD		= (1U << 23),	/* Response good */
+	RXQ_SLOT_RESET		= (1U << 21),	/* Slot reset complete */
+	RXQ_CMD_RX		= (1U << 20),	/* target cmd received */
+	RXQ_ATTN		= (1U << 19),	/* attention */
+	RXQ_RSP			= (1U << 18),	/* response frame xfer'd */
+	RXQ_ERR			= (1U << 17),	/* err info rec xfer'd */
+	RXQ_DONE		= (1U << 16),	/* cmd complete */
+	RXQ_SLOT_MASK		= 0xfff,	/* slot number */
+
+	/* mvs_cmd_hdr bits */
+	MCH_PRD_LEN_SHIFT	= 16,		/* 16-bit PRD table len */
+	MCH_SSP_FR_TYPE_SHIFT	= 13,		/* SSP frame type */
+
+						/* SSP initiator only */
+	MCH_SSP_FR_CMD		= 0x0,		/* COMMAND frame */
+
+						/* SSP initiator or target */
+	MCH_SSP_FR_TASK		= 0x1,		/* TASK frame */
+
+						/* SSP target only */
+	MCH_SSP_FR_XFER_RDY	= 0x4,		/* XFER_RDY frame */
+	MCH_SSP_FR_RESP		= 0x5,		/* RESPONSE frame */
+	MCH_SSP_FR_READ		= 0x6,		/* Read DATA frame(s) */
+	MCH_SSP_FR_READ_RESP	= 0x7,		/* ditto, plus RESPONSE */
+
+	MCH_SSP_MODE_PASSTHRU	= 1,
+	MCH_SSP_MODE_NORMAL	= 0,
+	MCH_PASSTHRU		= (1U << 12),	/* pass-through (SSP) */
+	MCH_FBURST		= (1U << 11),	/* first burst (SSP) */
+	MCH_CHK_LEN		= (1U << 10),	/* chk xfer len (SSP) */
+	MCH_RETRY		= (1U << 9),	/* tport layer retry (SSP) */
+	MCH_PROTECTION		= (1U << 8),	/* protection info rec (SSP) */
+	MCH_RESET		= (1U << 7),	/* Reset (STP/SATA) */
+	MCH_FPDMA		= (1U << 6),	/* First party DMA (STP/SATA) */
+	MCH_ATAPI		= (1U << 5),	/* ATAPI (STP/SATA) */
+	MCH_BIST		= (1U << 4),	/* BIST activate (STP/SATA) */
+	MCH_PMP_MASK		= 0xf,		/* PMP from cmd FIS (STP/SATA)*/
+
+	CCTL_RST		= (1U << 5),	/* port logic reset */
+
+						/* 0(LSB first), 1(MSB first) */
+	CCTL_ENDIAN_DATA	= (1U << 3),	/* PRD data */
+	CCTL_ENDIAN_RSP		= (1U << 2),	/* response frame */
+	CCTL_ENDIAN_OPEN	= (1U << 1),	/* open address frame */
+	CCTL_ENDIAN_CMD		= (1U << 0),	/* command table */
+
+	/* MVS_Px_SER_CTLSTAT (per-phy control) */
+	PHY_SSP_RST		= (1U << 3),	/* reset SSP link layer */
+	PHY_BCAST_CHG		= (1U << 2),	/* broadcast(change) notif */
+	PHY_RST_HARD		= (1U << 1),	/* hard reset + phy reset */
+	PHY_RST			= (1U << 0),	/* phy reset */
+	PHY_READY_MASK		= (1U << 20),
+
+	/* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */
+	PHYEV_DEC_ERR		= (1U << 24),	/* Phy Decoding Error */
+	PHYEV_DCDR_ERR		= (1U << 23),	/* STP Deocder Error */
+	PHYEV_CRC_ERR		= (1U << 22),	/* STP CRC Error */
+	PHYEV_UNASSOC_FIS	= (1U << 19),	/* unassociated FIS rx'd */
+	PHYEV_AN		= (1U << 18),	/* SATA async notification */
+	PHYEV_BIST_ACT		= (1U << 17),	/* BIST activate FIS */
+	PHYEV_SIG_FIS		= (1U << 16),	/* signature FIS */
+	PHYEV_POOF		= (1U << 12),	/* phy ready from 1 -> 0 */
+	PHYEV_IU_BIG		= (1U << 11),	/* IU too long err */
+	PHYEV_IU_SMALL		= (1U << 10),	/* IU too short err */
+	PHYEV_UNK_TAG		= (1U << 9),	/* unknown tag */
+	PHYEV_BROAD_CH		= (1U << 8),	/* broadcast(CHANGE) */
+	PHYEV_COMWAKE		= (1U << 7),	/* COMWAKE rx'd */
+	PHYEV_PORT_SEL		= (1U << 6),	/* port selector present */
+	PHYEV_HARD_RST		= (1U << 5),	/* hard reset rx'd */
+	PHYEV_ID_TMOUT		= (1U << 4),	/* identify timeout */
+	PHYEV_ID_FAIL		= (1U << 3),	/* identify failed */
+	PHYEV_ID_DONE		= (1U << 2),	/* identify done */
+	PHYEV_HARD_RST_DONE	= (1U << 1),	/* hard reset done */
+	PHYEV_RDY_CH		= (1U << 0),	/* phy ready changed state */
+
+	/* MVS_PCS */
+	PCS_EN_SATA_REG_SHIFT	= (16),		/* Enable SATA Register Set */
+	PCS_EN_PORT_XMT_SHIFT	= (12),		/* Enable Port Transmit */
+	PCS_EN_PORT_XMT_SHIFT2	= (8),		/* For 6485 */
+	PCS_SATA_RETRY		= (1U << 8),	/* retry ctl FIS on R_ERR */
+	PCS_RSP_RX_EN		= (1U << 7),	/* raw response rx */
+	PCS_SATA_RETRY_2	= (1U << 6),	/* For 9180 */
+	PCS_SELF_CLEAR		= (1U << 5),	/* self-clearing int mode */
+	PCS_FIS_RX_EN		= (1U << 4),	/* FIS rx enable */
+	PCS_CMD_STOP_ERR	= (1U << 3),	/* cmd stop-on-err enable */
+	PCS_CMD_RST		= (1U << 1),	/* reset cmd issue */
+	PCS_CMD_EN		= (1U << 0),	/* enable cmd issue */
+
+	/* Port n Attached Device Info */
+	PORT_DEV_SSP_TRGT	= (1U << 19),
+	PORT_DEV_SMP_TRGT	= (1U << 18),
+	PORT_DEV_STP_TRGT	= (1U << 17),
+	PORT_DEV_SSP_INIT	= (1U << 11),
+	PORT_DEV_SMP_INIT	= (1U << 10),
+	PORT_DEV_STP_INIT	= (1U << 9),
+	PORT_PHY_ID_MASK	= (0xFFU << 24),
+	PORT_SSP_TRGT_MASK	= (0x1U << 19),
+	PORT_SSP_INIT_MASK	= (0x1U << 11),
+	PORT_DEV_TRGT_MASK	= (0x7U << 17),
+	PORT_DEV_INIT_MASK	= (0x7U << 9),
+	PORT_DEV_TYPE_MASK	= (0x7U << 0),
+
+	/* Port n PHY Status */
+	PHY_RDY			= (1U << 2),
+	PHY_DW_SYNC		= (1U << 1),
+	PHY_OOB_DTCTD		= (1U << 0),
+
+	/* VSR */
+	/* PHYMODE 6 (CDB) */
+	PHY_MODE6_LATECLK	= (1U << 29),	/* Lock Clock */
+	PHY_MODE6_DTL_SPEED	= (1U << 27),	/* Digital Loop Speed */
+	PHY_MODE6_FC_ORDER	= (1U << 26),	/* Fibre Channel Mode Order*/
+	PHY_MODE6_MUCNT_EN	= (1U << 24),	/* u Count Enable */
+	PHY_MODE6_SEL_MUCNT_LEN	= (1U << 22),	/* Training Length Select */
+	PHY_MODE6_SELMUPI	= (1U << 20),	/* Phase Multi Select (init) */
+	PHY_MODE6_SELMUPF	= (1U << 18),	/* Phase Multi Select (final) */
+	PHY_MODE6_SELMUFF	= (1U << 16),	/* Freq Loop Multi Sel(final) */
+	PHY_MODE6_SELMUFI	= (1U << 14),	/* Freq Loop Multi Sel(init) */
+	PHY_MODE6_FREEZE_LOOP	= (1U << 12),	/* Freeze Rx CDR Loop */
+	PHY_MODE6_INT_RXFOFFS	= (1U << 3),	/* Rx CDR Freq Loop Enable */
+	PHY_MODE6_FRC_RXFOFFS	= (1U << 2),	/* Initial Rx CDR Offset */
+	PHY_MODE6_STAU_0D8	= (1U << 1),	/* Rx CDR Freq Loop Saturate */
+	PHY_MODE6_RXSAT_DIS	= (1U << 0),	/* Saturate Ctl */
+};
+
+/* SAS/SATA configuration port registers, aka phy registers */
+enum sas_sata_config_port_regs {
+	PHYR_IDENTIFY		= 0x00,	/* info for IDENTIFY frame */
+	PHYR_ADDR_LO		= 0x04,	/* my SAS address (low) */
+	PHYR_ADDR_HI		= 0x08,	/* my SAS address (high) */
+	PHYR_ATT_DEV_INFO	= 0x0C,	/* attached device info */
+	PHYR_ATT_ADDR_LO	= 0x10,	/* attached dev SAS addr (low) */
+	PHYR_ATT_ADDR_HI	= 0x14,	/* attached dev SAS addr (high) */
+	PHYR_SATA_CTL		= 0x18,	/* SATA control */
+	PHYR_PHY_STAT		= 0x1C,	/* PHY status */
+	PHYR_SATA_SIG0	= 0x20,	/*port SATA signature FIS(Byte 0-3) */
+	PHYR_SATA_SIG1	= 0x24,	/*port SATA signature FIS(Byte 4-7) */
+	PHYR_SATA_SIG2	= 0x28,	/*port SATA signature FIS(Byte 8-11) */
+	PHYR_SATA_SIG3	= 0x2c,	/*port SATA signature FIS(Byte 12-15) */
+	PHYR_R_ERR_COUNT	= 0x30, /* port R_ERR count register */
+	PHYR_CRC_ERR_COUNT	= 0x34, /* port CRC error count register */
+	PHYR_WIDE_PORT	= 0x38,	/* wide port participating */
+	PHYR_CURRENT0		= 0x80,	/* current connection info 0 */
+	PHYR_CURRENT1		= 0x84,	/* current connection info 1 */
+	PHYR_CURRENT2		= 0x88,	/* current connection info 2 */
+	CONFIG_ID_FRAME0       = 0x100, /* Port device ID frame register 0 */
+	CONFIG_ID_FRAME1       = 0x104, /* Port device ID frame register 1 */
+	CONFIG_ID_FRAME2       = 0x108, /* Port device ID frame register 2 */
+	CONFIG_ID_FRAME3       = 0x10c, /* Port device ID frame register 3 */
+	CONFIG_ID_FRAME4       = 0x110, /* Port device ID frame register 4 */
+	CONFIG_ID_FRAME5       = 0x114, /* Port device ID frame register 5 */
+	CONFIG_ID_FRAME6       = 0x118, /* Port device ID frame register 6 */
+	CONFIG_ATT_ID_FRAME0   = 0x11c, /* attached ID frame register 0 */
+	CONFIG_ATT_ID_FRAME1   = 0x120, /* attached ID frame register 1 */
+	CONFIG_ATT_ID_FRAME2   = 0x124, /* attached ID frame register 2 */
+	CONFIG_ATT_ID_FRAME3   = 0x128, /* attached ID frame register 3 */
+	CONFIG_ATT_ID_FRAME4   = 0x12c, /* attached ID frame register 4 */
+	CONFIG_ATT_ID_FRAME5   = 0x130, /* attached ID frame register 5 */
+	CONFIG_ATT_ID_FRAME6   = 0x134, /* attached ID frame register 6 */
+};
+
+enum sas_cmd_port_registers {
+	CMD_CMRST_OOB_DET	= 0x100, /* COMRESET OOB detect register */
+	CMD_CMWK_OOB_DET	= 0x104, /* COMWAKE OOB detect register */
+	CMD_CMSAS_OOB_DET	= 0x108, /* COMSAS OOB detect register */
+	CMD_BRST_OOB_DET	= 0x10c, /* burst OOB detect register */
+	CMD_OOB_SPACE	= 0x110, /* OOB space control register */
+	CMD_OOB_BURST	= 0x114, /* OOB burst control register */
+	CMD_PHY_TIMER		= 0x118, /* PHY timer control register */
+	CMD_PHY_CONFIG0	= 0x11c, /* PHY config register 0 */
+	CMD_PHY_CONFIG1	= 0x120, /* PHY config register 1 */
+	CMD_SAS_CTL0		= 0x124, /* SAS control register 0 */
+	CMD_SAS_CTL1		= 0x128, /* SAS control register 1 */
+	CMD_SAS_CTL2		= 0x12c, /* SAS control register 2 */
+	CMD_SAS_CTL3		= 0x130, /* SAS control register 3 */
+	CMD_ID_TEST		= 0x134, /* ID test register */
+	CMD_PL_TIMER		= 0x138, /* PL timer register */
+	CMD_WD_TIMER		= 0x13c, /* WD timer register */
+	CMD_PORT_SEL_COUNT	= 0x140, /* port selector count register */
+	CMD_APP_MEM_CTL	= 0x144, /* Application Memory Control */
+	CMD_XOR_MEM_CTL	= 0x148, /* XOR Block Memory Control */
+	CMD_DMA_MEM_CTL	= 0x14c, /* DMA Block Memory Control */
+	CMD_PORT_MEM_CTL0	= 0x150, /* Port Memory Control 0 */
+	CMD_PORT_MEM_CTL1	= 0x154, /* Port Memory Control 1 */
+	CMD_SATA_PORT_MEM_CTL0	= 0x158, /* SATA Port Memory Control 0 */
+	CMD_SATA_PORT_MEM_CTL1	= 0x15c, /* SATA Port Memory Control 1 */
+	CMD_XOR_MEM_BIST_CTL	= 0x160, /* XOR Memory BIST Control */
+	CMD_XOR_MEM_BIST_STAT	= 0x164, /* XOR Memroy BIST Status */
+	CMD_DMA_MEM_BIST_CTL	= 0x168, /* DMA Memory BIST Control */
+	CMD_DMA_MEM_BIST_STAT	= 0x16c, /* DMA Memory BIST Status */
+	CMD_PORT_MEM_BIST_CTL	= 0x170, /* Port Memory BIST Control */
+	CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */
+	CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */
+	CMD_STP_MEM_BIST_CTL	= 0x17c, /* STP Memory BIST Control */
+	CMD_STP_MEM_BIST_STAT0	= 0x180, /* STP Memory BIST Status 0 */
+	CMD_STP_MEM_BIST_STAT1	= 0x184, /* STP Memory BIST Status 1 */
+	CMD_RESET_COUNT		= 0x188, /* Reset Count */
+	CMD_MONTR_DATA_SEL	= 0x18C, /* Monitor Data/Select */
+	CMD_PLL_PHY_CONFIG	= 0x190, /* PLL/PHY Configuration */
+	CMD_PHY_CTL		= 0x194, /* PHY Control and Status */
+	CMD_PHY_TEST_COUNT0	= 0x198, /* Phy Test Count 0 */
+	CMD_PHY_TEST_COUNT1	= 0x19C, /* Phy Test Count 1 */
+	CMD_PHY_TEST_COUNT2	= 0x1A0, /* Phy Test Count 2 */
+	CMD_APP_ERR_CONFIG	= 0x1A4, /* Application Error Configuration */
+	CMD_PND_FIFO_CTL0	= 0x1A8, /* Pending FIFO Control 0 */
+	CMD_HOST_CTL		= 0x1AC, /* Host Control Status */
+	CMD_HOST_WR_DATA	= 0x1B0, /* Host Write Data */
+	CMD_HOST_RD_DATA	= 0x1B4, /* Host Read Data */
+	CMD_PHY_MODE_21		= 0x1B8, /* Phy Mode 21 */
+	CMD_SL_MODE0		= 0x1BC, /* SL Mode 0 */
+	CMD_SL_MODE1		= 0x1C0, /* SL Mode 1 */
+	CMD_PND_FIFO_CTL1	= 0x1C4, /* Pending FIFO Control 1 */
+};
+
+enum mvs_info_flags {
+	MVF_MSI		= (1U << 0),	/* MSI is enabled */
+	MVF_PHY_PWR_FIX	= (1U << 1),	/* bug workaround */
+	MVF_FLAG_SOC		= (1U << 2),	/* SoC integrated controllers */
+};
+
+enum mvs_event_flags {
+	PHY_PLUG_EVENT	= (3U),
+	PHY_PLUG_IN		= (1U << 0),	/* phy plug in */
+	PHY_PLUG_OUT		= (1U << 1),	/* phy plug out */
+};
+
+enum mvs_port_type {
+	PORT_TGT_MASK	=  (1U << 5),
+	PORT_INIT_PORT	=  (1U << 4),
+	PORT_TGT_PORT	=  (1U << 3),
+	PORT_INIT_TGT_PORT = (PORT_INIT_PORT | PORT_TGT_PORT),
+	PORT_TYPE_SAS	=  (1U << 1),
+	PORT_TYPE_SATA	=  (1U << 0),
+};
+
+/* Command Table Format */
+enum ct_format {
+	/* SSP */
+	SSP_F_H		=  0x00,
+	SSP_F_IU	=  0x18,
+	SSP_F_MAX	=  0x4D,
+	/* STP */
+	STP_CMD_FIS	=  0x00,
+	STP_ATAPI_CMD	=  0x40,
+	STP_F_MAX	=  0x10,
+	/* SMP */
+	SMP_F_T		=  0x00,
+	SMP_F_DEP	=  0x01,
+	SMP_F_MAX	=  0x101,
+};
+
+enum status_buffer {
+	SB_EIR_OFF	=  0x00,	/* Error Information Record */
+	SB_RFB_OFF	=  0x08,	/* Response Frame Buffer */
+	SB_RFB_MAX	=  0x400,	/* RFB size*/
+};
+
+enum error_info_rec {
+	CMD_ISS_STPD	= (1U << 31),	/* Cmd Issue Stopped */
+	CMD_PI_ERR	= (1U << 30),	/* Protection info error.  see flags2 */
+	RSP_OVER	= (1U << 29),	/* rsp buffer overflow */
+	RETRY_LIM	= (1U << 28),	/* FIS/frame retry limit exceeded */
+	UNK_FIS 	= (1U << 27),	/* unknown FIS */
+	DMA_TERM	= (1U << 26),	/* DMA terminate primitive rx'd */
+	SYNC_ERR	= (1U << 25),	/* SYNC rx'd during frame xmit */
+	TFILE_ERR	= (1U << 24),	/* SATA taskfile Error bit set */
+	R_ERR		= (1U << 23),	/* SATA returned R_ERR prim */
+	RD_OFS		= (1U << 20),	/* Read DATA frame invalid offset */
+	XFER_RDY_OFS	= (1U << 19),	/* XFER_RDY offset error */
+	UNEXP_XFER_RDY	= (1U << 18),	/* unexpected XFER_RDY error */
+	DATA_OVER_UNDER = (1U << 16),	/* data overflow/underflow */
+	INTERLOCK	= (1U << 15),	/* interlock error */
+	NAK		= (1U << 14),	/* NAK rx'd */
+	ACK_NAK_TO	= (1U << 13),	/* ACK/NAK timeout */
+	CXN_CLOSED	= (1U << 12),	/* cxn closed w/out ack/nak */
+	OPEN_TO 	= (1U << 11),	/* I_T nexus lost, open cxn timeout */
+	PATH_BLOCKED	= (1U << 10),	/* I_T nexus lost, pathway blocked */
+	NO_DEST 	= (1U << 9),	/* I_T nexus lost, no destination */
+	STP_RES_BSY	= (1U << 8),	/* STP resources busy */
+	BREAK		= (1U << 7),	/* break received */
+	BAD_DEST	= (1U << 6),	/* bad destination */
+	BAD_PROTO	= (1U << 5),	/* protocol not supported */
+	BAD_RATE	= (1U << 4),	/* cxn rate not supported */
+	WRONG_DEST	= (1U << 3),	/* wrong destination error */
+	CREDIT_TO	= (1U << 2),	/* credit timeout */
+	WDOG_TO 	= (1U << 1),	/* watchdog timeout */
+	BUF_PAR 	= (1U << 0),	/* buffer parity error */
+};
+
+enum error_info_rec_2 {
+	SLOT_BSY_ERR	= (1U << 31),	/* Slot Busy Error */
+	GRD_CHK_ERR	= (1U << 14),	/* Guard Check Error */
+	APP_CHK_ERR	= (1U << 13),	/* Application Check error */
+	REF_CHK_ERR	= (1U << 12),	/* Reference Check Error */
+	USR_BLK_NM	= (1U << 0),	/* User Block Number */
+};
+
+enum pci_cfg_register_bits {
+	PCTL_PWR_OFF	= (0xFU << 24),
+	PCTL_COM_ON	= (0xFU << 20),
+	PCTL_LINK_RST	= (0xFU << 16),
+	PCTL_LINK_OFFS	= (16),
+	PCTL_PHY_DSBL	= (0xFU << 12),
+	PCTL_PHY_DSBL_OFFS	= (12),
+	PRD_REQ_SIZE	= (0x4000),
+	PRD_REQ_MASK	= (0x00007000),
+	PLS_NEG_LINK_WD		= (0x3FU << 4),
+	PLS_NEG_LINK_WD_OFFS	= 4,
+	PLS_LINK_SPD		= (0x0FU << 0),
+	PLS_LINK_SPD_OFFS	= 0,
+};
+
+enum open_frame_protocol {
+	PROTOCOL_SMP	= 0x0,
+	PROTOCOL_SSP	= 0x1,
+	PROTOCOL_STP	= 0x2,
+};
+
+/* define for response frame datapres field */
+enum datapres_field {
+	NO_DATA		= 0,
+	RESPONSE_DATA	= 1,
+	SENSE_DATA	= 2,
+};
+
+/* define task management IU */
+struct mvs_tmf_task{
+	u8 tmf;
+	u16 tag_of_task_to_be_managed;
+};
+#endif
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
new file mode 100644
index 0000000..8646a19
--- /dev/null
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -0,0 +1,703 @@
+/*
+ * Marvell 88SE64xx/88SE94xx pci init
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+
+#include "mv_sas.h"
+
+static struct scsi_transport_template *mvs_stt;
+static const struct mvs_chip_info mvs_chips[] = {
+	[chip_6320] =	{ 1, 2, 0x400, 17, 16,  9, &mvs_64xx_dispatch, },
+	[chip_6440] =	{ 1, 4, 0x400, 17, 16,  9, &mvs_64xx_dispatch, },
+	[chip_6485] =	{ 1, 8, 0x800, 33, 32, 10, &mvs_64xx_dispatch, },
+	[chip_9180] =	{ 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
+	[chip_9480] =	{ 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
+};
+
+#define SOC_SAS_NUM 2
+
+static struct scsi_host_template mvs_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.queuecommand		= sas_queuecommand,
+	.target_alloc		= sas_target_alloc,
+	.slave_configure	= mvs_slave_configure,
+	.slave_destroy		= sas_slave_destroy,
+	.scan_finished		= mvs_scan_finished,
+	.scan_start		= mvs_scan_start,
+	.change_queue_depth	= sas_change_queue_depth,
+	.change_queue_type	= sas_change_queue_type,
+	.bios_param		= sas_bios_param,
+	.can_queue		= 1,
+	.cmd_per_lun		= 1,
+	.this_id		= -1,
+	.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	= sas_eh_bus_reset_handler,
+	.slave_alloc		= mvs_slave_alloc,
+	.target_destroy		= sas_target_destroy,
+	.ioctl			= sas_ioctl,
+};
+
+static struct sas_domain_function_template mvs_transport_ops = {
+	.lldd_dev_found 	= mvs_dev_found,
+	.lldd_dev_gone	= mvs_dev_gone,
+
+	.lldd_execute_task	= mvs_queue_command,
+	.lldd_control_phy	= mvs_phy_control,
+
+	.lldd_abort_task	= mvs_abort_task,
+	.lldd_abort_task_set    = mvs_abort_task_set,
+	.lldd_clear_aca         = mvs_clear_aca,
+       .lldd_clear_task_set    = mvs_clear_task_set,
+	.lldd_I_T_nexus_reset	= mvs_I_T_nexus_reset,
+	.lldd_lu_reset 		= mvs_lu_reset,
+	.lldd_query_task	= mvs_query_task,
+
+	.lldd_port_formed	= mvs_port_formed,
+	.lldd_port_deformed     = mvs_port_deformed,
+
+};
+
+static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
+{
+	struct mvs_phy *phy = &mvi->phy[phy_id];
+	struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+	phy->mvi = mvi;
+	init_timer(&phy->timer);
+	sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0;
+	sas_phy->class = SAS;
+	sas_phy->iproto = SAS_PROTOCOL_ALL;
+	sas_phy->tproto = 0;
+	sas_phy->type = PHY_TYPE_PHYSICAL;
+	sas_phy->role = PHY_ROLE_INITIATOR;
+	sas_phy->oob_mode = OOB_NOT_CONNECTED;
+	sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
+
+	sas_phy->id = phy_id;
+	sas_phy->sas_addr = &mvi->sas_addr[0];
+	sas_phy->frame_rcvd = &phy->frame_rcvd[0];
+	sas_phy->ha = (struct sas_ha_struct *)mvi->shost->hostdata;
+	sas_phy->lldd_phy = phy;
+}
+
+static void mvs_free(struct mvs_info *mvi)
+{
+	int i;
+	struct mvs_wq *mwq;
+	int slot_nr;
+
+	if (!mvi)
+		return;
+
+	if (mvi->flags & MVF_FLAG_SOC)
+		slot_nr = MVS_SOC_SLOTS;
+	else
+		slot_nr = MVS_SLOTS;
+
+	for (i = 0; i < mvi->tags_num; i++) {
+		struct mvs_slot_info *slot = &mvi->slot_info[i];
+		if (slot->buf)
+			dma_free_coherent(mvi->dev, MVS_SLOT_BUF_SZ,
+					  slot->buf, slot->buf_dma);
+	}
+
+	if (mvi->tx)
+		dma_free_coherent(mvi->dev,
+				  sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
+				  mvi->tx, mvi->tx_dma);
+	if (mvi->rx_fis)
+		dma_free_coherent(mvi->dev, MVS_RX_FISL_SZ,
+				  mvi->rx_fis, mvi->rx_fis_dma);
+	if (mvi->rx)
+		dma_free_coherent(mvi->dev,
+				  sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1),
+				  mvi->rx, mvi->rx_dma);
+	if (mvi->slot)
+		dma_free_coherent(mvi->dev,
+				  sizeof(*mvi->slot) * slot_nr,
+				  mvi->slot, mvi->slot_dma);
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+	if (mvi->bulk_buffer)
+		dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE,
+				  mvi->bulk_buffer, mvi->bulk_buffer_dma);
+#endif
+
+	MVS_CHIP_DISP->chip_iounmap(mvi);
+	if (mvi->shost)
+		scsi_host_put(mvi->shost);
+	list_for_each_entry(mwq, &mvi->wq_list, entry)
+		cancel_delayed_work(&mwq->work_q);
+	kfree(mvi);
+}
+
+#ifdef MVS_USE_TASKLET
+struct tasklet_struct	mv_tasklet;
+static void mvs_tasklet(unsigned long opaque)
+{
+	unsigned long flags;
+	u32 stat;
+	u16 core_nr, i = 0;
+
+	struct mvs_info *mvi;
+	struct sas_ha_struct *sha = (struct sas_ha_struct *)opaque;
+
+	core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
+	mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
+
+	if (unlikely(!mvi))
+		BUG_ON(1);
+
+	for (i = 0; i < core_nr; i++) {
+		mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
+		stat = MVS_CHIP_DISP->isr_status(mvi, mvi->irq);
+		if (stat)
+			MVS_CHIP_DISP->isr(mvi, mvi->irq, stat);
+	}
+
+}
+#endif
+
+static irqreturn_t mvs_interrupt(int irq, void *opaque)
+{
+	u32 core_nr, i = 0;
+	u32 stat;
+	struct mvs_info *mvi;
+	struct sas_ha_struct *sha = opaque;
+
+	core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
+	mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
+
+	if (unlikely(!mvi))
+		return IRQ_NONE;
+
+	stat = MVS_CHIP_DISP->isr_status(mvi, irq);
+	if (!stat)
+		return IRQ_NONE;
+
+#ifdef MVS_USE_TASKLET
+	tasklet_schedule(&mv_tasklet);
+#else
+	for (i = 0; i < core_nr; i++) {
+		mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
+		MVS_CHIP_DISP->isr(mvi, irq, stat);
+	}
+#endif
+	return IRQ_HANDLED;
+}
+
+static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
+{
+	int i, slot_nr;
+
+	if (mvi->flags & MVF_FLAG_SOC)
+		slot_nr = MVS_SOC_SLOTS;
+	else
+		slot_nr = MVS_SLOTS;
+
+	spin_lock_init(&mvi->lock);
+	for (i = 0; i < mvi->chip->n_phy; i++) {
+		mvs_phy_init(mvi, i);
+		mvi->port[i].wide_port_phymap = 0;
+		mvi->port[i].port_attached = 0;
+		INIT_LIST_HEAD(&mvi->port[i].list);
+	}
+	for (i = 0; i < MVS_MAX_DEVICES; i++) {
+		mvi->devices[i].taskfileset = MVS_ID_NOT_MAPPED;
+		mvi->devices[i].dev_type = NO_DEVICE;
+		mvi->devices[i].device_id = i;
+		mvi->devices[i].dev_status = MVS_DEV_NORMAL;
+	}
+
+	/*
+	 * alloc and init our DMA areas
+	 */
+	mvi->tx = dma_alloc_coherent(mvi->dev,
+				     sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
+				     &mvi->tx_dma, GFP_KERNEL);
+	if (!mvi->tx)
+		goto err_out;
+	memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ);
+	mvi->rx_fis = dma_alloc_coherent(mvi->dev, MVS_RX_FISL_SZ,
+					 &mvi->rx_fis_dma, GFP_KERNEL);
+	if (!mvi->rx_fis)
+		goto err_out;
+	memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ);
+
+	mvi->rx = dma_alloc_coherent(mvi->dev,
+				     sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1),
+				     &mvi->rx_dma, GFP_KERNEL);
+	if (!mvi->rx)
+		goto err_out;
+	memset(mvi->rx, 0, sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1));
+	mvi->rx[0] = cpu_to_le32(0xfff);
+	mvi->rx_cons = 0xfff;
+
+	mvi->slot = dma_alloc_coherent(mvi->dev,
+				       sizeof(*mvi->slot) * slot_nr,
+				       &mvi->slot_dma, GFP_KERNEL);
+	if (!mvi->slot)
+		goto err_out;
+	memset(mvi->slot, 0, sizeof(*mvi->slot) * slot_nr);
+
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+	mvi->bulk_buffer = dma_alloc_coherent(mvi->dev,
+				       TRASH_BUCKET_SIZE,
+				       &mvi->bulk_buffer_dma, GFP_KERNEL);
+	if (!mvi->bulk_buffer)
+		goto err_out;
+#endif
+	for (i = 0; i < slot_nr; i++) {
+		struct mvs_slot_info *slot = &mvi->slot_info[i];
+
+		slot->buf = dma_alloc_coherent(mvi->dev, MVS_SLOT_BUF_SZ,
+					       &slot->buf_dma, GFP_KERNEL);
+		if (!slot->buf) {
+			printk(KERN_DEBUG"failed to allocate slot->buf.\n");
+			goto err_out;
+		}
+		memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
+		++mvi->tags_num;
+	}
+	/* Initialize tags */
+	mvs_tag_init(mvi);
+	return 0;
+err_out:
+	return 1;
+}
+
+
+int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex)
+{
+	unsigned long res_start, res_len, res_flag, res_flag_ex = 0;
+	struct pci_dev *pdev = mvi->pdev;
+	if (bar_ex != -1) {
+		/*
+		 * ioremap main and peripheral registers
+		 */
+		res_start = pci_resource_start(pdev, bar_ex);
+		res_len = pci_resource_len(pdev, bar_ex);
+		if (!res_start || !res_len)
+			goto err_out;
+
+		res_flag_ex = pci_resource_flags(pdev, bar_ex);
+		if (res_flag_ex & IORESOURCE_MEM) {
+			if (res_flag_ex & IORESOURCE_CACHEABLE)
+				mvi->regs_ex = ioremap(res_start, res_len);
+			else
+				mvi->regs_ex = ioremap_nocache(res_start,
+						res_len);
+		} else
+			mvi->regs_ex = (void *)res_start;
+		if (!mvi->regs_ex)
+			goto err_out;
+	}
+
+	res_start = pci_resource_start(pdev, bar);
+	res_len = pci_resource_len(pdev, bar);
+	if (!res_start || !res_len)
+		goto err_out;
+
+	res_flag = pci_resource_flags(pdev, bar);
+	if (res_flag & IORESOURCE_CACHEABLE)
+		mvi->regs = ioremap(res_start, res_len);
+	else
+		mvi->regs = ioremap_nocache(res_start, res_len);
+
+	if (!mvi->regs) {
+		if (mvi->regs_ex && (res_flag_ex & IORESOURCE_MEM))
+			iounmap(mvi->regs_ex);
+		mvi->regs_ex = NULL;
+		goto err_out;
+	}
+
+	return 0;
+err_out:
+	return -1;
+}
+
+void mvs_iounmap(void __iomem *regs)
+{
+	iounmap(regs);
+}
+
+static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev,
+				const struct pci_device_id *ent,
+				struct Scsi_Host *shost, unsigned int id)
+{
+	struct mvs_info *mvi;
+	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+
+	mvi = kzalloc(sizeof(*mvi) + MVS_SLOTS * sizeof(struct mvs_slot_info),
+			GFP_KERNEL);
+	if (!mvi)
+		return NULL;
+
+	mvi->pdev = pdev;
+	mvi->dev = &pdev->dev;
+	mvi->chip_id = ent->driver_data;
+	mvi->chip = &mvs_chips[mvi->chip_id];
+	INIT_LIST_HEAD(&mvi->wq_list);
+	mvi->irq = pdev->irq;
+
+	((struct mvs_prv_info *)sha->lldd_ha)->mvi[id] = mvi;
+	((struct mvs_prv_info *)sha->lldd_ha)->n_phy = mvi->chip->n_phy;
+
+	mvi->id = id;
+	mvi->sas = sha;
+	mvi->shost = shost;
+#ifdef MVS_USE_TASKLET
+	tasklet_init(&mv_tasklet, mvs_tasklet, (unsigned long)sha);
+#endif
+
+	if (MVS_CHIP_DISP->chip_ioremap(mvi))
+		goto err_out;
+	if (!mvs_alloc(mvi, shost))
+		return mvi;
+err_out:
+	mvs_free(mvi);
+	return NULL;
+}
+
+/* move to PCI layer or libata core? */
+static int pci_go_64(struct pci_dev *pdev)
+{
+	int rc;
+
+	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+		if (rc) {
+			rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+			if (rc) {
+				dev_printk(KERN_ERR, &pdev->dev,
+					   "64-bit DMA enable failed\n");
+				return rc;
+			}
+		}
+	} else {
+		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+		if (rc) {
+			dev_printk(KERN_ERR, &pdev->dev,
+				   "32-bit DMA enable failed\n");
+			return rc;
+		}
+		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+		if (rc) {
+			dev_printk(KERN_ERR, &pdev->dev,
+				   "32-bit consistent DMA enable failed\n");
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost,
+				const struct mvs_chip_info *chip_info)
+{
+	int phy_nr, port_nr; unsigned short core_nr;
+	struct asd_sas_phy **arr_phy;
+	struct asd_sas_port **arr_port;
+	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+
+	core_nr = chip_info->n_host;
+	phy_nr  = core_nr * chip_info->n_phy;
+	port_nr = phy_nr;
+
+	memset(sha, 0x00, sizeof(struct sas_ha_struct));
+	arr_phy  = kcalloc(phy_nr, sizeof(void *), GFP_KERNEL);
+	arr_port = kcalloc(port_nr, sizeof(void *), GFP_KERNEL);
+	if (!arr_phy || !arr_port)
+		goto exit_free;
+
+	sha->sas_phy = arr_phy;
+	sha->sas_port = arr_port;
+
+	sha->lldd_ha = kzalloc(sizeof(struct mvs_prv_info), GFP_KERNEL);
+	if (!sha->lldd_ha)
+		goto exit_free;
+
+	((struct mvs_prv_info *)sha->lldd_ha)->n_host = core_nr;
+
+	shost->transportt = mvs_stt;
+	shost->max_id = 128;
+	shost->max_lun = ~0;
+	shost->max_channel = 1;
+	shost->max_cmd_len = 16;
+
+	return 0;
+exit_free:
+	kfree(arr_phy);
+	kfree(arr_port);
+	return -1;
+
+}
+
+static void  __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost,
+			const struct mvs_chip_info *chip_info)
+{
+	int can_queue, i = 0, j = 0;
+	struct mvs_info *mvi = NULL;
+	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+	unsigned short nr_core = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
+
+	for (j = 0; j < nr_core; j++) {
+		mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j];
+		for (i = 0; i < chip_info->n_phy; i++) {
+			sha->sas_phy[j * chip_info->n_phy  + i] =
+				&mvi->phy[i].sas_phy;
+			sha->sas_port[j * chip_info->n_phy + i] =
+				&mvi->port[i].sas_port;
+		}
+	}
+
+	sha->sas_ha_name = DRV_NAME;
+	sha->dev = mvi->dev;
+	sha->lldd_module = THIS_MODULE;
+	sha->sas_addr = &mvi->sas_addr[0];
+
+	sha->num_phys = nr_core * chip_info->n_phy;
+
+	sha->lldd_max_execute_num = 1;
+
+	if (mvi->flags & MVF_FLAG_SOC)
+		can_queue = MVS_SOC_CAN_QUEUE;
+	else
+		can_queue = MVS_CAN_QUEUE;
+
+	sha->lldd_queue_size = can_queue;
+	shost->can_queue = can_queue;
+	mvi->shost->cmd_per_lun = MVS_SLOTS/sha->num_phys;
+	sha->core.shost = mvi->shost;
+}
+
+static void mvs_init_sas_add(struct mvs_info *mvi)
+{
+	u8 i;
+	for (i = 0; i < mvi->chip->n_phy; i++) {
+		mvi->phy[i].dev_sas_addr = 0x5005043011ab0000ULL;
+		mvi->phy[i].dev_sas_addr =
+			cpu_to_be64((u64)(*(u64 *)&mvi->phy[i].dev_sas_addr));
+	}
+
+	memcpy(mvi->sas_addr, &mvi->phy[0].dev_sas_addr, SAS_ADDR_SIZE);
+}
+
+static int __devinit mvs_pci_init(struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	unsigned int rc, nhost = 0;
+	struct mvs_info *mvi;
+	irq_handler_t irq_handler = mvs_interrupt;
+	struct Scsi_Host *shost = NULL;
+	const struct mvs_chip_info *chip;
+
+	dev_printk(KERN_INFO, &pdev->dev,
+		"mvsas: driver version %s\n", DRV_VERSION);
+	rc = pci_enable_device(pdev);
+	if (rc)
+		goto err_out_enable;
+
+	pci_set_master(pdev);
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out_disable;
+
+	rc = pci_go_64(pdev);
+	if (rc)
+		goto err_out_regions;
+
+	shost = scsi_host_alloc(&mvs_sht, sizeof(void *));
+	if (!shost) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	chip = &mvs_chips[ent->driver_data];
+	SHOST_TO_SAS_HA(shost) =
+		kcalloc(1, sizeof(struct sas_ha_struct), GFP_KERNEL);
+	if (!SHOST_TO_SAS_HA(shost)) {
+		kfree(shost);
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	rc = mvs_prep_sas_ha_init(shost, chip);
+	if (rc) {
+		kfree(shost);
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	pci_set_drvdata(pdev, SHOST_TO_SAS_HA(shost));
+
+	do {
+		mvi = mvs_pci_alloc(pdev, ent, shost, nhost);
+		if (!mvi) {
+			rc = -ENOMEM;
+			goto err_out_regions;
+		}
+
+		mvs_init_sas_add(mvi);
+
+		mvi->instance = nhost;
+		rc = MVS_CHIP_DISP->chip_init(mvi);
+		if (rc) {
+			mvs_free(mvi);
+			goto err_out_regions;
+		}
+		nhost++;
+	} while (nhost < chip->n_host);
+
+	mvs_post_sas_ha_init(shost, chip);
+
+	rc = scsi_add_host(shost, &pdev->dev);
+	if (rc)
+		goto err_out_shost;
+
+	rc = sas_register_ha(SHOST_TO_SAS_HA(shost));
+	if (rc)
+		goto err_out_shost;
+	rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED,
+		DRV_NAME, SHOST_TO_SAS_HA(shost));
+	if (rc)
+		goto err_not_sas;
+
+	MVS_CHIP_DISP->interrupt_enable(mvi);
+
+	scsi_scan_host(mvi->shost);
+
+	return 0;
+
+err_not_sas:
+	sas_unregister_ha(SHOST_TO_SAS_HA(shost));
+err_out_shost:
+	scsi_remove_host(mvi->shost);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out_disable:
+	pci_disable_device(pdev);
+err_out_enable:
+	return rc;
+}
+
+static void __devexit mvs_pci_remove(struct pci_dev *pdev)
+{
+	unsigned short core_nr, i = 0;
+	struct sas_ha_struct *sha = pci_get_drvdata(pdev);
+	struct mvs_info *mvi = NULL;
+
+	core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
+	mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
+
+#ifdef MVS_USE_TASKLET
+	tasklet_kill(&mv_tasklet);
+#endif
+
+	pci_set_drvdata(pdev, NULL);
+	sas_unregister_ha(sha);
+	sas_remove_host(mvi->shost);
+	scsi_remove_host(mvi->shost);
+
+	MVS_CHIP_DISP->interrupt_disable(mvi);
+	free_irq(mvi->irq, sha);
+	for (i = 0; i < core_nr; i++) {
+		mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
+		mvs_free(mvi);
+	}
+	kfree(sha->sas_phy);
+	kfree(sha->sas_port);
+	kfree(sha);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	return;
+}
+
+static struct pci_device_id __devinitdata mvs_pci_table[] = {
+	{ PCI_VDEVICE(MARVELL, 0x6320), chip_6320 },
+	{ PCI_VDEVICE(MARVELL, 0x6340), chip_6440 },
+	{
+		.vendor 	= PCI_VENDOR_ID_MARVELL,
+		.device 	= 0x6440,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= 0x6480,
+		.class		= 0,
+		.class_mask	= 0,
+		.driver_data	= chip_6485,
+	},
+	{ PCI_VDEVICE(MARVELL, 0x6440), chip_6440 },
+	{ PCI_VDEVICE(MARVELL, 0x6485), chip_6485 },
+	{ PCI_VDEVICE(MARVELL, 0x9480), chip_9480 },
+	{ PCI_VDEVICE(MARVELL, 0x9180), chip_9180 },
+
+	{ }	/* terminate list */
+};
+
+static struct pci_driver mvs_pci_driver = {
+	.name		= DRV_NAME,
+	.id_table	= mvs_pci_table,
+	.probe		= mvs_pci_init,
+	.remove		= __devexit_p(mvs_pci_remove),
+};
+
+/* task handler */
+struct task_struct *mvs_th;
+static int __init mvs_init(void)
+{
+	int rc;
+	mvs_stt = sas_domain_attach_transport(&mvs_transport_ops);
+	if (!mvs_stt)
+		return -ENOMEM;
+
+	rc = pci_register_driver(&mvs_pci_driver);
+
+	if (rc)
+		goto err_out;
+
+	return 0;
+
+err_out:
+	sas_release_transport(mvs_stt);
+	return rc;
+}
+
+static void __exit mvs_exit(void)
+{
+	pci_unregister_driver(&mvs_pci_driver);
+	sas_release_transport(mvs_stt);
+}
+
+module_init(mvs_init);
+module_exit(mvs_exit);
+
+MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
+MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+#ifdef CONFIG_PCI
+MODULE_DEVICE_TABLE(pci, mvs_pci_table);
+#endif
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
new file mode 100644
index 0000000..0d21386
--- /dev/null
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -0,0 +1,2154 @@
+/*
+ * Marvell 88SE64xx/88SE94xx main function
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+#include "mv_sas.h"
+
+static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag)
+{
+	if (task->lldd_task) {
+		struct mvs_slot_info *slot;
+		slot = task->lldd_task;
+		*tag = slot->slot_tag;
+		return 1;
+	}
+	return 0;
+}
+
+void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
+{
+	void *bitmap = &mvi->tags;
+	clear_bit(tag, bitmap);
+}
+
+void mvs_tag_free(struct mvs_info *mvi, u32 tag)
+{
+	mvs_tag_clear(mvi, tag);
+}
+
+void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
+{
+	void *bitmap = &mvi->tags;
+	set_bit(tag, bitmap);
+}
+
+inline int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
+{
+	unsigned int index, tag;
+	void *bitmap = &mvi->tags;
+
+	index = find_first_zero_bit(bitmap, mvi->tags_num);
+	tag = index;
+	if (tag >= mvi->tags_num)
+		return -SAS_QUEUE_FULL;
+	mvs_tag_set(mvi, tag);
+	*tag_out = tag;
+	return 0;
+}
+
+void mvs_tag_init(struct mvs_info *mvi)
+{
+	int i;
+	for (i = 0; i < mvi->tags_num; ++i)
+		mvs_tag_clear(mvi, i);
+}
+
+void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
+{
+	u32 i;
+	u32 run;
+	u32 offset;
+
+	offset = 0;
+	while (size) {
+		printk(KERN_DEBUG"%08X : ", baseaddr + offset);
+		if (size >= 16)
+			run = 16;
+		else
+			run = size;
+		size -= run;
+		for (i = 0; i < 16; i++) {
+			if (i < run)
+				printk(KERN_DEBUG"%02X ", (u32)data[i]);
+			else
+				printk(KERN_DEBUG"   ");
+		}
+		printk(KERN_DEBUG": ");
+		for (i = 0; i < run; i++)
+			printk(KERN_DEBUG"%c",
+				isalnum(data[i]) ? data[i] : '.');
+		printk(KERN_DEBUG"\n");
+		data = &data[16];
+		offset += run;
+	}
+	printk(KERN_DEBUG"\n");
+}
+
+#if (_MV_DUMP > 1)
+static void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
+				   enum sas_protocol proto)
+{
+	u32 offset;
+	struct mvs_slot_info *slot = &mvi->slot_info[tag];
+
+	offset = slot->cmd_size + MVS_OAF_SZ +
+	    MVS_CHIP_DISP->prd_size() * slot->n_elem;
+	dev_printk(KERN_DEBUG, mvi->dev, "+---->Status buffer[%d] :\n",
+			tag);
+	mvs_hexdump(32, (u8 *) slot->response,
+		    (u32) slot->buf_dma + offset);
+}
+#endif
+
+static void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag,
+				enum sas_protocol proto)
+{
+#if (_MV_DUMP > 1)
+	u32 sz, w_ptr;
+	u64 addr;
+	struct mvs_slot_info *slot = &mvi->slot_info[tag];
+
+	/*Delivery Queue */
+	sz = MVS_CHIP_SLOT_SZ;
+	w_ptr = slot->tx;
+	addr = mvi->tx_dma;
+	dev_printk(KERN_DEBUG, mvi->dev,
+		"Delivery Queue Size=%04d , WRT_PTR=%04X\n", sz, w_ptr);
+	dev_printk(KERN_DEBUG, mvi->dev,
+		"Delivery Queue Base Address=0x%llX (PA)"
+		"(tx_dma=0x%llX), Entry=%04d\n",
+		addr, (unsigned long long)mvi->tx_dma, w_ptr);
+	mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]),
+			(u32) mvi->tx_dma + sizeof(u32) * w_ptr);
+	/*Command List */
+	addr = mvi->slot_dma;
+	dev_printk(KERN_DEBUG, mvi->dev,
+		"Command List Base Address=0x%llX (PA)"
+		"(slot_dma=0x%llX), Header=%03d\n",
+		addr, (unsigned long long)slot->buf_dma, tag);
+	dev_printk(KERN_DEBUG, mvi->dev, "Command Header[%03d]:\n", tag);
+	/*mvs_cmd_hdr */
+	mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]),
+		(u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr));
+	/*1.command table area */
+	dev_printk(KERN_DEBUG, mvi->dev, "+---->Command Table :\n");
+	mvs_hexdump(slot->cmd_size, (u8 *) slot->buf, (u32) slot->buf_dma);
+	/*2.open address frame area */
+	dev_printk(KERN_DEBUG, mvi->dev, "+---->Open Address Frame :\n");
+	mvs_hexdump(MVS_OAF_SZ, (u8 *) slot->buf + slot->cmd_size,
+				(u32) slot->buf_dma + slot->cmd_size);
+	/*3.status buffer */
+	mvs_hba_sb_dump(mvi, tag, proto);
+	/*4.PRD table */
+	dev_printk(KERN_DEBUG, mvi->dev, "+---->PRD table :\n");
+	mvs_hexdump(MVS_CHIP_DISP->prd_size() * slot->n_elem,
+		(u8 *) slot->buf + slot->cmd_size + MVS_OAF_SZ,
+		(u32) slot->buf_dma + slot->cmd_size + MVS_OAF_SZ);
+#endif
+}
+
+static void mvs_hba_cq_dump(struct mvs_info *mvi)
+{
+#if (_MV_DUMP > 2)
+	u64 addr;
+	void __iomem *regs = mvi->regs;
+	u32 entry = mvi->rx_cons + 1;
+	u32 rx_desc = le32_to_cpu(mvi->rx[entry]);
+
+	/*Completion Queue */
+	addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO);
+	dev_printk(KERN_DEBUG, mvi->dev, "Completion Task = 0x%p\n",
+		   mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task);
+	dev_printk(KERN_DEBUG, mvi->dev,
+		"Completion List Base Address=0x%llX (PA), "
+		"CQ_Entry=%04d, CQ_WP=0x%08X\n",
+		addr, entry - 1, mvi->rx[0]);
+	mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc),
+		    mvi->rx_dma + sizeof(u32) * entry);
+#endif
+}
+
+void mvs_get_sas_addr(void *buf, u32 buflen)
+{
+	/*memcpy(buf, "\x50\x05\x04\x30\x11\xab\x64\x40", 8);*/
+}
+
+struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev)
+{
+	unsigned long i = 0, j = 0, hi = 0;
+	struct sas_ha_struct *sha = dev->port->ha;
+	struct mvs_info *mvi = NULL;
+	struct asd_sas_phy *phy;
+
+	while (sha->sas_port[i]) {
+		if (sha->sas_port[i] == dev->port) {
+			phy =  container_of(sha->sas_port[i]->phy_list.next,
+				struct asd_sas_phy, port_phy_el);
+			j = 0;
+			while (sha->sas_phy[j]) {
+				if (sha->sas_phy[j] == phy)
+					break;
+				j++;
+			}
+			break;
+		}
+		i++;
+	}
+	hi = j/((struct mvs_prv_info *)sha->lldd_ha)->n_phy;
+	mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi];
+
+	return mvi;
+
+}
+
+/* FIXME */
+int mvs_find_dev_phyno(struct domain_device *dev, int *phyno)
+{
+	unsigned long i = 0, j = 0, n = 0, num = 0;
+	struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
+	struct mvs_info *mvi = mvi_dev->mvi_info;
+	struct sas_ha_struct *sha = dev->port->ha;
+
+	while (sha->sas_port[i]) {
+		if (sha->sas_port[i] == dev->port) {
+			struct asd_sas_phy *phy;
+			list_for_each_entry(phy,
+				&sha->sas_port[i]->phy_list, port_phy_el) {
+				j = 0;
+				while (sha->sas_phy[j]) {
+					if (sha->sas_phy[j] == phy)
+						break;
+					j++;
+				}
+				phyno[n] = (j >= mvi->chip->n_phy) ?
+					(j - mvi->chip->n_phy) : j;
+				num++;
+				n++;
+			}
+			break;
+		}
+		i++;
+	}
+	return num;
+}
+
+static inline void mvs_free_reg_set(struct mvs_info *mvi,
+				struct mvs_device *dev)
+{
+	if (!dev) {
+		mv_printk("device has been free.\n");
+		return;
+	}
+	if (dev->runing_req != 0)
+		return;
+	if (dev->taskfileset == MVS_ID_NOT_MAPPED)
+		return;
+	MVS_CHIP_DISP->free_reg_set(mvi, &dev->taskfileset);
+}
+
+static inline u8 mvs_assign_reg_set(struct mvs_info *mvi,
+				struct mvs_device *dev)
+{
+	if (dev->taskfileset != MVS_ID_NOT_MAPPED)
+		return 0;
+	return MVS_CHIP_DISP->assign_reg_set(mvi, &dev->taskfileset);
+}
+
+void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard)
+{
+	u32 no;
+	for_each_phy(phy_mask, phy_mask, no) {
+		if (!(phy_mask & 1))
+			continue;
+		MVS_CHIP_DISP->phy_reset(mvi, no, hard);
+	}
+}
+
+/* FIXME: locking? */
+int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
+			void *funcdata)
+{
+	int rc = 0, phy_id = sas_phy->id;
+	u32 tmp, i = 0, hi;
+	struct sas_ha_struct *sha = sas_phy->ha;
+	struct mvs_info *mvi = NULL;
+
+	while (sha->sas_phy[i]) {
+		if (sha->sas_phy[i] == sas_phy)
+			break;
+		i++;
+	}
+	hi = i/((struct mvs_prv_info *)sha->lldd_ha)->n_phy;
+	mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi];
+
+	switch (func) {
+	case PHY_FUNC_SET_LINK_RATE:
+		MVS_CHIP_DISP->phy_set_link_rate(mvi, phy_id, funcdata);
+		break;
+
+	case PHY_FUNC_HARD_RESET:
+		tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id);
+		if (tmp & PHY_RST_HARD)
+			break;
+		MVS_CHIP_DISP->phy_reset(mvi, phy_id, 1);
+		break;
+
+	case PHY_FUNC_LINK_RESET:
+		MVS_CHIP_DISP->phy_enable(mvi, phy_id);
+		MVS_CHIP_DISP->phy_reset(mvi, phy_id, 0);
+		break;
+
+	case PHY_FUNC_DISABLE:
+		MVS_CHIP_DISP->phy_disable(mvi, phy_id);
+		break;
+	case PHY_FUNC_RELEASE_SPINUP_HOLD:
+	default:
+		rc = -EOPNOTSUPP;
+	}
+	msleep(200);
+	return rc;
+}
+
+void __devinit mvs_set_sas_addr(struct mvs_info *mvi, int port_id,
+				u32 off_lo, u32 off_hi, u64 sas_addr)
+{
+	u32 lo = (u32)sas_addr;
+	u32 hi = (u32)(sas_addr>>32);
+
+	MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_lo);
+	MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, lo);
+	MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_hi);
+	MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, hi);
+}
+
+static void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
+{
+	struct mvs_phy *phy = &mvi->phy[i];
+	struct asd_sas_phy *sas_phy = &phy->sas_phy;
+	struct sas_ha_struct *sas_ha;
+	if (!phy->phy_attached)
+		return;
+
+	if (!(phy->att_dev_info & PORT_DEV_TRGT_MASK)
+		&& phy->phy_type & PORT_TYPE_SAS) {
+		return;
+	}
+
+	sas_ha = mvi->sas;
+	sas_ha->notify_phy_event(sas_phy, PHYE_OOB_DONE);
+
+	if (sas_phy->phy) {
+		struct sas_phy *sphy = sas_phy->phy;
+
+		sphy->negotiated_linkrate = sas_phy->linkrate;
+		sphy->minimum_linkrate = phy->minimum_linkrate;
+		sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+		sphy->maximum_linkrate = phy->maximum_linkrate;
+		sphy->maximum_linkrate_hw = MVS_CHIP_DISP->phy_max_link_rate();
+	}
+
+	if (phy->phy_type & PORT_TYPE_SAS) {
+		struct sas_identify_frame *id;
+
+		id = (struct sas_identify_frame *)phy->frame_rcvd;
+		id->dev_type = phy->identify.device_type;
+		id->initiator_bits = SAS_PROTOCOL_ALL;
+		id->target_bits = phy->identify.target_port_protocols;
+	} else if (phy->phy_type & PORT_TYPE_SATA) {
+		/*Nothing*/
+	}
+	mv_dprintk("phy %d byte dmaded.\n", i + mvi->id * mvi->chip->n_phy);
+
+	sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
+
+	mvi->sas->notify_port_event(sas_phy,
+				   PORTE_BYTES_DMAED);
+}
+
+int mvs_slave_alloc(struct scsi_device *scsi_dev)
+{
+	struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+	if (dev_is_sata(dev)) {
+		/* We don't need to rescan targets
+		 * if REPORT_LUNS request is failed
+		 */
+		if (scsi_dev->lun > 0)
+			return -ENXIO;
+		scsi_dev->tagged_supported = 1;
+	}
+
+	return sas_slave_alloc(scsi_dev);
+}
+
+int mvs_slave_configure(struct scsi_device *sdev)
+{
+	struct domain_device *dev = sdev_to_domain_dev(sdev);
+	int ret = sas_slave_configure(sdev);
+
+	if (ret)
+		return ret;
+	if (dev_is_sata(dev)) {
+		/* may set PIO mode */
+	#if MV_DISABLE_NCQ
+		struct ata_port *ap = dev->sata_dev.ap;
+		struct ata_device *adev = ap->link.device;
+		adev->flags |= ATA_DFLAG_NCQ_OFF;
+		scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1);
+	#endif
+	}
+	return 0;
+}
+
+void mvs_scan_start(struct Scsi_Host *shost)
+{
+	int i, j;
+	unsigned short core_nr;
+	struct mvs_info *mvi;
+	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+
+	core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
+
+	for (j = 0; j < core_nr; j++) {
+		mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j];
+		for (i = 0; i < mvi->chip->n_phy; ++i)
+			mvs_bytes_dmaed(mvi, i);
+	}
+}
+
+int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+	/* 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);
+	return 1;
+}
+
+static int mvs_task_prep_smp(struct mvs_info *mvi,
+			     struct mvs_task_exec_info *tei)
+{
+	int elem, rc, i;
+	struct sas_task *task = tei->task;
+	struct mvs_cmd_hdr *hdr = tei->hdr;
+	struct domain_device *dev = task->dev;
+	struct asd_sas_port *sas_port = dev->port;
+	struct scatterlist *sg_req, *sg_resp;
+	u32 req_len, resp_len, tag = tei->tag;
+	void *buf_tmp;
+	u8 *buf_oaf;
+	dma_addr_t buf_tmp_dma;
+	void *buf_prd;
+	struct mvs_slot_info *slot = &mvi->slot_info[tag];
+	u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
+#if _MV_DUMP
+	u8 *buf_cmd;
+	void *from;
+#endif
+	/*
+	 * DMA-map SMP request, response buffers
+	 */
+	sg_req = &task->smp_task.smp_req;
+	elem = dma_map_sg(mvi->dev, sg_req, 1, PCI_DMA_TODEVICE);
+	if (!elem)
+		return -ENOMEM;
+	req_len = sg_dma_len(sg_req);
+
+	sg_resp = &task->smp_task.smp_resp;
+	elem = dma_map_sg(mvi->dev, sg_resp, 1, PCI_DMA_FROMDEVICE);
+	if (!elem) {
+		rc = -ENOMEM;
+		goto err_out;
+	}
+	resp_len = SB_RFB_MAX;
+
+	/* must be in dwords */
+	if ((req_len & 0x3) || (resp_len & 0x3)) {
+		rc = -EINVAL;
+		goto err_out_2;
+	}
+
+	/*
+	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
+	 */
+
+	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***** */
+	buf_tmp = slot->buf;
+	buf_tmp_dma = slot->buf_dma;
+
+#if _MV_DUMP
+	buf_cmd = buf_tmp;
+	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
+	buf_tmp += req_len;
+	buf_tmp_dma += req_len;
+	slot->cmd_size = req_len;
+#else
+	hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
+#endif
+
+	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
+	buf_oaf = buf_tmp;
+	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
+
+	buf_tmp += MVS_OAF_SZ;
+	buf_tmp_dma += MVS_OAF_SZ;
+
+	/* region 3: PRD table *********************************** */
+	buf_prd = buf_tmp;
+	if (tei->n_elem)
+		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+	else
+		hdr->prd_tbl = 0;
+
+	i = MVS_CHIP_DISP->prd_size() * tei->n_elem;
+	buf_tmp += i;
+	buf_tmp_dma += i;
+
+	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
+	slot->response = buf_tmp;
+	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
+	if (mvi->flags & MVF_FLAG_SOC)
+		hdr->reserved[0] = 0;
+
+	/*
+	 * Fill in TX ring and command slot header
+	 */
+	slot->tx = mvi->tx_prod;
+	mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
+					TXQ_MODE_I | tag |
+					(sas_port->phy_mask << TXQ_PHY_SHIFT));
+
+	hdr->flags |= flags;
+	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4));
+	hdr->tags = cpu_to_le32(tag);
+	hdr->data_len = 0;
+
+	/* generate open address frame hdr (first 12 bytes) */
+	/* initiator, SMP, ftype 1h */
+	buf_oaf[0] = (1 << 7) | (PROTOCOL_SMP << 4) | 0x01;
+	buf_oaf[1] = dev->linkrate & 0xf;
+	*(u16 *)(buf_oaf + 2) = 0xFFFF;		/* SAS SPEC */
+	memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
+
+	/* fill in PRD (scatter/gather) table, if any */
+	MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
+
+#if _MV_DUMP
+	/* copy cmd table */
+	from = kmap_atomic(sg_page(sg_req), KM_IRQ0);
+	memcpy(buf_cmd, from + sg_req->offset, req_len);
+	kunmap_atomic(from, KM_IRQ0);
+#endif
+	return 0;
+
+err_out_2:
+	dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_resp, 1,
+		     PCI_DMA_FROMDEVICE);
+err_out:
+	dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_req, 1,
+		     PCI_DMA_TODEVICE);
+	return rc;
+}
+
+static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag)
+{
+	struct ata_queued_cmd *qc = task->uldd_task;
+
+	if (qc) {
+		if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+			qc->tf.command == ATA_CMD_FPDMA_READ) {
+			*tag = qc->tag;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int mvs_task_prep_ata(struct mvs_info *mvi,
+			     struct mvs_task_exec_info *tei)
+{
+	struct sas_task *task = tei->task;
+	struct domain_device *dev = task->dev;
+	struct mvs_device *mvi_dev = dev->lldd_dev;
+	struct mvs_cmd_hdr *hdr = tei->hdr;
+	struct asd_sas_port *sas_port = dev->port;
+	struct mvs_slot_info *slot;
+	void *buf_prd;
+	u32 tag = tei->tag, hdr_tag;
+	u32 flags, del_q;
+	void *buf_tmp;
+	u8 *buf_cmd, *buf_oaf;
+	dma_addr_t buf_tmp_dma;
+	u32 i, req_len, resp_len;
+	const u32 max_resp_len = SB_RFB_MAX;
+
+	if (mvs_assign_reg_set(mvi, mvi_dev) == MVS_ID_NOT_MAPPED) {
+		mv_dprintk("Have not enough regiset for dev %d.\n",
+			mvi_dev->device_id);
+		return -EBUSY;
+	}
+	slot = &mvi->slot_info[tag];
+	slot->tx = mvi->tx_prod;
+	del_q = TXQ_MODE_I | tag |
+		(TXQ_CMD_STP << TXQ_CMD_SHIFT) |
+		(sas_port->phy_mask << TXQ_PHY_SHIFT) |
+		(mvi_dev->taskfileset << TXQ_SRS_SHIFT);
+	mvi->tx[mvi->tx_prod] = cpu_to_le32(del_q);
+
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+	if (task->data_dir == DMA_FROM_DEVICE)
+		flags = (MVS_CHIP_DISP->prd_count() << MCH_PRD_LEN_SHIFT);
+	else
+		flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
+#else
+	flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
+#endif
+	if (task->ata_task.use_ncq)
+		flags |= MCH_FPDMA;
+	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
+		if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI)
+			flags |= MCH_ATAPI;
+	}
+
+	/* FIXME: fill in port multiplier number */
+
+	hdr->flags = cpu_to_le32(flags);
+
+	/* FIXME: the low order order 5 bits for the TAG if enable NCQ */
+	if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr_tag))
+		task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
+	else
+		hdr_tag = tag;
+
+	hdr->tags = cpu_to_le32(hdr_tag);
+
+	hdr->data_len = cpu_to_le32(task->total_xfer_len);
+
+	/*
+	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
+	 */
+
+	/* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
+	buf_cmd = buf_tmp = slot->buf;
+	buf_tmp_dma = slot->buf_dma;
+
+	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
+
+	buf_tmp += MVS_ATA_CMD_SZ;
+	buf_tmp_dma += MVS_ATA_CMD_SZ;
+#if _MV_DUMP
+	slot->cmd_size = MVS_ATA_CMD_SZ;
+#endif
+
+	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
+	/* used for STP.  unused for SATA? */
+	buf_oaf = buf_tmp;
+	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
+
+	buf_tmp += MVS_OAF_SZ;
+	buf_tmp_dma += MVS_OAF_SZ;
+
+	/* region 3: PRD table ********************************************* */
+	buf_prd = buf_tmp;
+
+	if (tei->n_elem)
+		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+	else
+		hdr->prd_tbl = 0;
+	i = MVS_CHIP_DISP->prd_size() * MVS_CHIP_DISP->prd_count();
+
+	buf_tmp += i;
+	buf_tmp_dma += i;
+
+	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
+	/* FIXME: probably unused, for SATA.  kept here just in case
+	 * we get a STP/SATA error information record
+	 */
+	slot->response = buf_tmp;
+	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
+	if (mvi->flags & MVF_FLAG_SOC)
+		hdr->reserved[0] = 0;
+
+	req_len = sizeof(struct host_to_dev_fis);
+	resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
+	    sizeof(struct mvs_err_info) - i;
+
+	/* request, response lengths */
+	resp_len = min(resp_len, max_resp_len);
+	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
+
+	if (likely(!task->ata_task.device_control_reg_update))
+		task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
+	/* fill in command FIS and ATAPI CDB */
+	memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
+	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
+		memcpy(buf_cmd + STP_ATAPI_CMD,
+			task->ata_task.atapi_packet, 16);
+
+	/* generate open address frame hdr (first 12 bytes) */
+	/* initiator, STP, ftype 1h */
+	buf_oaf[0] = (1 << 7) | (PROTOCOL_STP << 4) | 0x1;
+	buf_oaf[1] = dev->linkrate & 0xf;
+	*(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1);
+	memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
+
+	/* fill in PRD (scatter/gather) table, if any */
+	MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+	if (task->data_dir == DMA_FROM_DEVICE)
+		MVS_CHIP_DISP->dma_fix(mvi->bulk_buffer_dma,
+				TRASH_BUCKET_SIZE, tei->n_elem, buf_prd);
+#endif
+	return 0;
+}
+
+static int mvs_task_prep_ssp(struct mvs_info *mvi,
+			     struct mvs_task_exec_info *tei, int is_tmf,
+			     struct mvs_tmf_task *tmf)
+{
+	struct sas_task *task = tei->task;
+	struct mvs_cmd_hdr *hdr = tei->hdr;
+	struct mvs_port *port = tei->port;
+	struct domain_device *dev = task->dev;
+	struct mvs_device *mvi_dev = dev->lldd_dev;
+	struct asd_sas_port *sas_port = dev->port;
+	struct mvs_slot_info *slot;
+	void *buf_prd;
+	struct ssp_frame_hdr *ssp_hdr;
+	void *buf_tmp;
+	u8 *buf_cmd, *buf_oaf, fburst = 0;
+	dma_addr_t buf_tmp_dma;
+	u32 flags;
+	u32 resp_len, req_len, i, tag = tei->tag;
+	const u32 max_resp_len = SB_RFB_MAX;
+	u32 phy_mask;
+
+	slot = &mvi->slot_info[tag];
+
+	phy_mask = ((port->wide_port_phymap) ? port->wide_port_phymap :
+		sas_port->phy_mask) & TXQ_PHY_MASK;
+
+	slot->tx = mvi->tx_prod;
+	mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
+				(TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
+				(phy_mask << TXQ_PHY_SHIFT));
+
+	flags = MCH_RETRY;
+	if (task->ssp_task.enable_first_burst) {
+		flags |= MCH_FBURST;
+		fburst = (1 << 7);
+	}
+	if (is_tmf)
+		flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT);
+	else
+		flags |= (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT);
+	hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT));
+	hdr->tags = cpu_to_le32(tag);
+	hdr->data_len = cpu_to_le32(task->total_xfer_len);
+
+	/*
+	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
+	 */
+
+	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
+	buf_cmd = buf_tmp = slot->buf;
+	buf_tmp_dma = slot->buf_dma;
+
+	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
+
+	buf_tmp += MVS_SSP_CMD_SZ;
+	buf_tmp_dma += MVS_SSP_CMD_SZ;
+#if _MV_DUMP
+	slot->cmd_size = MVS_SSP_CMD_SZ;
+#endif
+
+	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
+	buf_oaf = buf_tmp;
+	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
+
+	buf_tmp += MVS_OAF_SZ;
+	buf_tmp_dma += MVS_OAF_SZ;
+
+	/* region 3: PRD table ********************************************* */
+	buf_prd = buf_tmp;
+	if (tei->n_elem)
+		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+	else
+		hdr->prd_tbl = 0;
+
+	i = MVS_CHIP_DISP->prd_size() * tei->n_elem;
+	buf_tmp += i;
+	buf_tmp_dma += i;
+
+	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
+	slot->response = buf_tmp;
+	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
+	if (mvi->flags & MVF_FLAG_SOC)
+		hdr->reserved[0] = 0;
+
+	resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
+	    sizeof(struct mvs_err_info) - i;
+	resp_len = min(resp_len, max_resp_len);
+
+	req_len = sizeof(struct ssp_frame_hdr) + 28;
+
+	/* request, response lengths */
+	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
+
+	/* generate open address frame hdr (first 12 bytes) */
+	/* initiator, SSP, ftype 1h */
+	buf_oaf[0] = (1 << 7) | (PROTOCOL_SSP << 4) | 0x1;
+	buf_oaf[1] = dev->linkrate & 0xf;
+	*(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1);
+	memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
+
+	/* fill in SSP frame header (Command Table.SSP frame header) */
+	ssp_hdr = (struct ssp_frame_hdr *)buf_cmd;
+
+	if (is_tmf)
+		ssp_hdr->frame_type = SSP_TASK;
+	else
+		ssp_hdr->frame_type = SSP_COMMAND;
+
+	memcpy(ssp_hdr->hashed_dest_addr, dev->hashed_sas_addr,
+	       HASHED_SAS_ADDR_SIZE);
+	memcpy(ssp_hdr->hashed_src_addr,
+	       dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+	ssp_hdr->tag = cpu_to_be16(tag);
+
+	/* fill in IU for TASK and Command Frame */
+	buf_cmd += sizeof(*ssp_hdr);
+	memcpy(buf_cmd, &task->ssp_task.LUN, 8);
+
+	if (ssp_hdr->frame_type != SSP_TASK) {
+		buf_cmd[9] = fburst | task->ssp_task.task_attr |
+				(task->ssp_task.task_prio << 3);
+		memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
+	} else{
+		buf_cmd[10] = tmf->tmf;
+		switch (tmf->tmf) {
+		case TMF_ABORT_TASK:
+		case TMF_QUERY_TASK:
+			buf_cmd[12] =
+				(tmf->tag_of_task_to_be_managed >> 8) & 0xff;
+			buf_cmd[13] =
+				tmf->tag_of_task_to_be_managed & 0xff;
+			break;
+		default:
+			break;
+		}
+	}
+	/* fill in PRD (scatter/gather) table, if any */
+	MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
+	return 0;
+}
+
+#define	DEV_IS_GONE(mvi_dev)	((!mvi_dev || (mvi_dev->dev_type == NO_DEVICE)))
+static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
+				struct completion *completion,int is_tmf,
+				struct mvs_tmf_task *tmf)
+{
+	struct domain_device *dev = task->dev;
+	struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
+	struct mvs_info *mvi = mvi_dev->mvi_info;
+	struct mvs_task_exec_info tei;
+	struct sas_task *t = task;
+	struct mvs_slot_info *slot;
+	u32 tag = 0xdeadbeef, rc, n_elem = 0;
+	u32 n = num, pass = 0;
+	unsigned long flags = 0;
+
+	if (!dev->port) {
+		struct task_status_struct *tsm = &t->task_status;
+
+		tsm->resp = SAS_TASK_UNDELIVERED;
+		tsm->stat = SAS_PHY_DOWN;
+		t->task_done(t);
+		return 0;
+	}
+
+	spin_lock_irqsave(&mvi->lock, flags);
+	do {
+		dev = t->dev;
+		mvi_dev = dev->lldd_dev;
+		if (DEV_IS_GONE(mvi_dev)) {
+			if (mvi_dev)
+				mv_dprintk("device %d not ready.\n",
+					mvi_dev->device_id);
+			else
+				mv_dprintk("device %016llx not ready.\n",
+					SAS_ADDR(dev->sas_addr));
+
+			rc = SAS_PHY_DOWN;
+			goto out_done;
+		}
+
+		if (dev->port->id >= mvi->chip->n_phy)
+			tei.port = &mvi->port[dev->port->id - mvi->chip->n_phy];
+		else
+			tei.port = &mvi->port[dev->port->id];
+
+		if (!tei.port->port_attached) {
+			if (sas_protocol_ata(t->task_proto)) {
+				mv_dprintk("port %d does not"
+					"attached device.\n", dev->port->id);
+				rc = SAS_PHY_DOWN;
+				goto out_done;
+			} else {
+				struct task_status_struct *ts = &t->task_status;
+				ts->resp = SAS_TASK_UNDELIVERED;
+				ts->stat = SAS_PHY_DOWN;
+				t->task_done(t);
+				if (n > 1)
+					t = list_entry(t->list.next,
+							struct sas_task, list);
+				continue;
+			}
+		}
+
+		if (!sas_protocol_ata(t->task_proto)) {
+			if (t->num_scatter) {
+				n_elem = dma_map_sg(mvi->dev,
+						    t->scatter,
+						    t->num_scatter,
+						    t->data_dir);
+				if (!n_elem) {
+					rc = -ENOMEM;
+					goto err_out;
+				}
+			}
+		} else {
+			n_elem = t->num_scatter;
+		}
+
+		rc = mvs_tag_alloc(mvi, &tag);
+		if (rc)
+			goto err_out;
+
+		slot = &mvi->slot_info[tag];
+
+
+		t->lldd_task = NULL;
+		slot->n_elem = n_elem;
+		slot->slot_tag = tag;
+		memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
+
+		tei.task = t;
+		tei.hdr = &mvi->slot[tag];
+		tei.tag = tag;
+		tei.n_elem = n_elem;
+		switch (t->task_proto) {
+		case SAS_PROTOCOL_SMP:
+			rc = mvs_task_prep_smp(mvi, &tei);
+			break;
+		case SAS_PROTOCOL_SSP:
+			rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf);
+			break;
+		case SAS_PROTOCOL_SATA:
+		case SAS_PROTOCOL_STP:
+		case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+			rc = mvs_task_prep_ata(mvi, &tei);
+			break;
+		default:
+			dev_printk(KERN_ERR, mvi->dev,
+				"unknown sas_task proto: 0x%x\n",
+				t->task_proto);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (rc) {
+			mv_dprintk("rc is %x\n", rc);
+			goto err_out_tag;
+		}
+		slot->task = t;
+		slot->port = tei.port;
+		t->lldd_task = slot;
+		list_add_tail(&slot->entry, &tei.port->list);
+		/* TODO: select normal or high priority */
+		spin_lock(&t->task_state_lock);
+		t->task_state_flags |= SAS_TASK_AT_INITIATOR;
+		spin_unlock(&t->task_state_lock);
+
+		mvs_hba_memory_dump(mvi, tag, t->task_proto);
+		mvi_dev->runing_req++;
+		++pass;
+		mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
+		if (n > 1)
+			t = list_entry(t->list.next, struct sas_task, list);
+	} while (--n);
+	rc = 0;
+	goto out_done;
+
+err_out_tag:
+	mvs_tag_free(mvi, tag);
+err_out:
+
+	dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc);
+	if (!sas_protocol_ata(t->task_proto))
+		if (n_elem)
+			dma_unmap_sg(mvi->dev, t->scatter, n_elem,
+				     t->data_dir);
+out_done:
+	if (likely(pass)) {
+		MVS_CHIP_DISP->start_delivery(mvi,
+			(mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
+	}
+	spin_unlock_irqrestore(&mvi->lock, flags);
+	return rc;
+}
+
+int mvs_queue_command(struct sas_task *task, const int num,
+			gfp_t gfp_flags)
+{
+	return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL);
+}
+
+static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
+{
+	u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
+	mvs_tag_clear(mvi, slot_idx);
+}
+
+static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
+			  struct mvs_slot_info *slot, u32 slot_idx)
+{
+	if (!slot->task)
+		return;
+	if (!sas_protocol_ata(task->task_proto))
+		if (slot->n_elem)
+			dma_unmap_sg(mvi->dev, task->scatter,
+				     slot->n_elem, task->data_dir);
+
+	switch (task->task_proto) {
+	case SAS_PROTOCOL_SMP:
+		dma_unmap_sg(mvi->dev, &task->smp_task.smp_resp, 1,
+			     PCI_DMA_FROMDEVICE);
+		dma_unmap_sg(mvi->dev, &task->smp_task.smp_req, 1,
+			     PCI_DMA_TODEVICE);
+		break;
+
+	case SAS_PROTOCOL_SATA:
+	case SAS_PROTOCOL_STP:
+	case SAS_PROTOCOL_SSP:
+	default:
+		/* do nothing */
+		break;
+	}
+	list_del_init(&slot->entry);
+	task->lldd_task = NULL;
+	slot->task = NULL;
+	slot->port = NULL;
+	slot->slot_tag = 0xFFFFFFFF;
+	mvs_slot_free(mvi, slot_idx);
+}
+
+static void mvs_update_wideport(struct mvs_info *mvi, int i)
+{
+	struct mvs_phy *phy = &mvi->phy[i];
+	struct mvs_port *port = phy->port;
+	int j, no;
+
+	for_each_phy(port->wide_port_phymap, j, no) {
+		if (j & 1) {
+			MVS_CHIP_DISP->write_port_cfg_addr(mvi, no,
+						PHYR_WIDE_PORT);
+			MVS_CHIP_DISP->write_port_cfg_data(mvi, no,
+						port->wide_port_phymap);
+		} else {
+			MVS_CHIP_DISP->write_port_cfg_addr(mvi, no,
+						PHYR_WIDE_PORT);
+			MVS_CHIP_DISP->write_port_cfg_data(mvi, no,
+						0);
+		}
+	}
+}
+
+static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i)
+{
+	u32 tmp;
+	struct mvs_phy *phy = &mvi->phy[i];
+	struct mvs_port *port = phy->port;
+
+	tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, i);
+	if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) {
+		if (!port)
+			phy->phy_attached = 1;
+		return tmp;
+	}
+
+	if (port) {
+		if (phy->phy_type & PORT_TYPE_SAS) {
+			port->wide_port_phymap &= ~(1U << i);
+			if (!port->wide_port_phymap)
+				port->port_attached = 0;
+			mvs_update_wideport(mvi, i);
+		} else if (phy->phy_type & PORT_TYPE_SATA)
+			port->port_attached = 0;
+		phy->port = NULL;
+		phy->phy_attached = 0;
+		phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+	}
+	return 0;
+}
+
+static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
+{
+	u32 *s = (u32 *) buf;
+
+	if (!s)
+		return NULL;
+
+	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
+	s[3] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+
+	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
+	s[2] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+
+	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
+	s[1] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+
+	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
+	s[0] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+
+	/* Workaround: take some ATAPI devices for ATA */
+	if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01))
+		s[1] = 0x00EB1401 | (*((u8 *)&s[1] + 3) & 0x10);
+
+	return s;
+}
+
+static u32 mvs_is_sig_fis_received(u32 irq_status)
+{
+	return irq_status & PHYEV_SIG_FIS;
+}
+
+void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
+{
+	struct mvs_phy *phy = &mvi->phy[i];
+	struct sas_identify_frame *id;
+
+	id = (struct sas_identify_frame *)phy->frame_rcvd;
+
+	if (get_st) {
+		phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, i);
+		phy->phy_status = mvs_is_phy_ready(mvi, i);
+	}
+
+	if (phy->phy_status) {
+		int oob_done = 0;
+		struct asd_sas_phy *sas_phy = &mvi->phy[i].sas_phy;
+
+		oob_done = MVS_CHIP_DISP->oob_done(mvi, i);
+
+		MVS_CHIP_DISP->fix_phy_info(mvi, i, id);
+		if (phy->phy_type & PORT_TYPE_SATA) {
+			phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
+			if (mvs_is_sig_fis_received(phy->irq_status)) {
+				phy->phy_attached = 1;
+				phy->att_dev_sas_addr =
+					i + mvi->id * mvi->chip->n_phy;
+				if (oob_done)
+					sas_phy->oob_mode = SATA_OOB_MODE;
+				phy->frame_rcvd_size =
+				    sizeof(struct dev_to_host_fis);
+				mvs_get_d2h_reg(mvi, i, id);
+			} else {
+				u32 tmp;
+				dev_printk(KERN_DEBUG, mvi->dev,
+					"Phy%d : No sig fis\n", i);
+				tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, i);
+				MVS_CHIP_DISP->write_port_irq_mask(mvi, i,
+						tmp | PHYEV_SIG_FIS);
+				phy->phy_attached = 0;
+				phy->phy_type &= ~PORT_TYPE_SATA;
+				MVS_CHIP_DISP->phy_reset(mvi, i, 0);
+				goto out_done;
+			}
+		}		else if (phy->phy_type & PORT_TYPE_SAS
+			|| phy->att_dev_info & PORT_SSP_INIT_MASK) {
+			phy->phy_attached = 1;
+			phy->identify.device_type =
+				phy->att_dev_info & PORT_DEV_TYPE_MASK;
+
+			if (phy->identify.device_type == SAS_END_DEV)
+				phy->identify.target_port_protocols =
+							SAS_PROTOCOL_SSP;
+			else if (phy->identify.device_type != NO_DEVICE)
+				phy->identify.target_port_protocols =
+							SAS_PROTOCOL_SMP;
+			if (oob_done)
+				sas_phy->oob_mode = SAS_OOB_MODE;
+			phy->frame_rcvd_size =
+			    sizeof(struct sas_identify_frame);
+		}
+		memcpy(sas_phy->attached_sas_addr,
+			&phy->att_dev_sas_addr, SAS_ADDR_SIZE);
+
+		if (MVS_CHIP_DISP->phy_work_around)
+			MVS_CHIP_DISP->phy_work_around(mvi, i);
+	}
+	mv_dprintk("port %d attach dev info is %x\n",
+		i + mvi->id * mvi->chip->n_phy, phy->att_dev_info);
+	mv_dprintk("port %d attach sas addr is %llx\n",
+		i + mvi->id * mvi->chip->n_phy, phy->att_dev_sas_addr);
+out_done:
+	if (get_st)
+		MVS_CHIP_DISP->write_port_irq_stat(mvi, i, phy->irq_status);
+}
+
+static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock)
+{
+	struct sas_ha_struct *sas_ha = sas_phy->ha;
+	struct mvs_info *mvi = NULL; int i = 0, hi;
+	struct mvs_phy *phy = sas_phy->lldd_phy;
+	struct asd_sas_port *sas_port = sas_phy->port;
+	struct mvs_port *port;
+	unsigned long flags = 0;
+	if (!sas_port)
+		return;
+
+	while (sas_ha->sas_phy[i]) {
+		if (sas_ha->sas_phy[i] == sas_phy)
+			break;
+		i++;
+	}
+	hi = i/((struct mvs_prv_info *)sas_ha->lldd_ha)->n_phy;
+	mvi = ((struct mvs_prv_info *)sas_ha->lldd_ha)->mvi[hi];
+	if (sas_port->id >= mvi->chip->n_phy)
+		port = &mvi->port[sas_port->id - mvi->chip->n_phy];
+	else
+		port = &mvi->port[sas_port->id];
+	if (lock)
+		spin_lock_irqsave(&mvi->lock, flags);
+	port->port_attached = 1;
+	phy->port = port;
+	if (phy->phy_type & PORT_TYPE_SAS) {
+		port->wide_port_phymap = sas_port->phy_mask;
+		mv_printk("set wide port phy map %x\n", sas_port->phy_mask);
+		mvs_update_wideport(mvi, sas_phy->id);
+	}
+	if (lock)
+		spin_unlock_irqrestore(&mvi->lock, flags);
+}
+
+static void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock)
+{
+	/*Nothing*/
+}
+
+
+void mvs_port_formed(struct asd_sas_phy *sas_phy)
+{
+	mvs_port_notify_formed(sas_phy, 1);
+}
+
+void mvs_port_deformed(struct asd_sas_phy *sas_phy)
+{
+	mvs_port_notify_deformed(sas_phy, 1);
+}
+
+struct mvs_device *mvs_alloc_dev(struct mvs_info *mvi)
+{
+	u32 dev;
+	for (dev = 0; dev < MVS_MAX_DEVICES; dev++) {
+		if (mvi->devices[dev].dev_type == NO_DEVICE) {
+			mvi->devices[dev].device_id = dev;
+			return &mvi->devices[dev];
+		}
+	}
+
+	if (dev == MVS_MAX_DEVICES)
+		mv_printk("max support %d devices, ignore ..\n",
+			MVS_MAX_DEVICES);
+
+	return NULL;
+}
+
+void mvs_free_dev(struct mvs_device *mvi_dev)
+{
+	u32 id = mvi_dev->device_id;
+	memset(mvi_dev, 0, sizeof(*mvi_dev));
+	mvi_dev->device_id = id;
+	mvi_dev->dev_type = NO_DEVICE;
+	mvi_dev->dev_status = MVS_DEV_NORMAL;
+	mvi_dev->taskfileset = MVS_ID_NOT_MAPPED;
+}
+
+int mvs_dev_found_notify(struct domain_device *dev, int lock)
+{
+	unsigned long flags = 0;
+	int res = 0;
+	struct mvs_info *mvi = NULL;
+	struct domain_device *parent_dev = dev->parent;
+	struct mvs_device *mvi_device;
+
+	mvi = mvs_find_dev_mvi(dev);
+
+	if (lock)
+		spin_lock_irqsave(&mvi->lock, flags);
+
+	mvi_device = mvs_alloc_dev(mvi);
+	if (!mvi_device) {
+		res = -1;
+		goto found_out;
+	}
+	dev->lldd_dev = mvi_device;
+	mvi_device->dev_type = dev->dev_type;
+	mvi_device->mvi_info = mvi;
+	if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+		int phy_id;
+		u8 phy_num = parent_dev->ex_dev.num_phys;
+		struct ex_phy *phy;
+		for (phy_id = 0; phy_id < phy_num; phy_id++) {
+			phy = &parent_dev->ex_dev.ex_phy[phy_id];
+			if (SAS_ADDR(phy->attached_sas_addr) ==
+				SAS_ADDR(dev->sas_addr)) {
+				mvi_device->attached_phy = phy_id;
+				break;
+			}
+		}
+
+		if (phy_id == phy_num) {
+			mv_printk("Error: no attached dev:%016llx"
+				"at ex:%016llx.\n",
+				SAS_ADDR(dev->sas_addr),
+				SAS_ADDR(parent_dev->sas_addr));
+			res = -1;
+		}
+	}
+
+found_out:
+	if (lock)
+		spin_unlock_irqrestore(&mvi->lock, flags);
+	return res;
+}
+
+int mvs_dev_found(struct domain_device *dev)
+{
+	return mvs_dev_found_notify(dev, 1);
+}
+
+void mvs_dev_gone_notify(struct domain_device *dev, int lock)
+{
+	unsigned long flags = 0;
+	struct mvs_device *mvi_dev = dev->lldd_dev;
+	struct mvs_info *mvi = mvi_dev->mvi_info;
+
+	if (lock)
+		spin_lock_irqsave(&mvi->lock, flags);
+
+	if (mvi_dev) {
+		mv_dprintk("found dev[%d:%x] is gone.\n",
+			mvi_dev->device_id, mvi_dev->dev_type);
+		mvs_free_reg_set(mvi, mvi_dev);
+		mvs_free_dev(mvi_dev);
+	} else {
+		mv_dprintk("found dev has gone.\n");
+	}
+	dev->lldd_dev = NULL;
+
+	if (lock)
+		spin_unlock_irqrestore(&mvi->lock, flags);
+}
+
+
+void mvs_dev_gone(struct domain_device *dev)
+{
+	mvs_dev_gone_notify(dev, 1);
+}
+
+static  struct sas_task *mvs_alloc_task(void)
+{
+	struct sas_task *task = kzalloc(sizeof(struct sas_task), GFP_KERNEL);
+
+	if (task) {
+		INIT_LIST_HEAD(&task->list);
+		spin_lock_init(&task->task_state_lock);
+		task->task_state_flags = SAS_TASK_STATE_PENDING;
+		init_timer(&task->timer);
+		init_completion(&task->completion);
+	}
+	return task;
+}
+
+static  void mvs_free_task(struct sas_task *task)
+{
+	if (task) {
+		BUG_ON(!list_empty(&task->list));
+		kfree(task);
+	}
+}
+
+static void mvs_task_done(struct sas_task *task)
+{
+	if (!del_timer(&task->timer))
+		return;
+	complete(&task->completion);
+}
+
+static void mvs_tmf_timedout(unsigned long data)
+{
+	struct sas_task *task = (struct sas_task *)data;
+
+	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+	complete(&task->completion);
+}
+
+/* XXX */
+#define MVS_TASK_TIMEOUT 20
+static int mvs_exec_internal_tmf_task(struct domain_device *dev,
+			void *parameter, u32 para_len, struct mvs_tmf_task *tmf)
+{
+	int res, retry;
+	struct sas_task *task = NULL;
+
+	for (retry = 0; retry < 3; retry++) {
+		task = mvs_alloc_task();
+		if (!task)
+			return -ENOMEM;
+
+		task->dev = dev;
+		task->task_proto = dev->tproto;
+
+		memcpy(&task->ssp_task, parameter, para_len);
+		task->task_done = mvs_task_done;
+
+		task->timer.data = (unsigned long) task;
+		task->timer.function = mvs_tmf_timedout;
+		task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ;
+		add_timer(&task->timer);
+
+		res = mvs_task_exec(task, 1, GFP_KERNEL, NULL, 1, tmf);
+
+		if (res) {
+			del_timer(&task->timer);
+			mv_printk("executing internel task failed:%d\n", res);
+			goto ex_err;
+		}
+
+		wait_for_completion(&task->completion);
+		res = -TMF_RESP_FUNC_FAILED;
+		/* Even TMF timed out, return direct. */
+		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+				mv_printk("TMF task[%x] timeout.\n", tmf->tmf);
+				goto ex_err;
+			}
+		}
+
+		if (task->task_status.resp == SAS_TASK_COMPLETE &&
+		    task->task_status.stat == SAM_GOOD) {
+			res = TMF_RESP_FUNC_COMPLETE;
+			break;
+		}
+
+		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) {
+			mv_dprintk("blocked task error.\n");
+			res = -EMSGSIZE;
+			break;
+		} else {
+			mv_dprintk(" task to dev %016llx response: 0x%x "
+				    "status 0x%x\n",
+				    SAS_ADDR(dev->sas_addr),
+				    task->task_status.resp,
+				    task->task_status.stat);
+			mvs_free_task(task);
+			task = NULL;
+
+		}
+	}
+ex_err:
+	BUG_ON(retry == 3 && task != NULL);
+	if (task != NULL)
+		mvs_free_task(task);
+	return res;
+}
+
+static int mvs_debug_issue_ssp_tmf(struct domain_device *dev,
+				u8 *lun, struct mvs_tmf_task *tmf)
+{
+	struct sas_ssp_task ssp_task;
+	DECLARE_COMPLETION_ONSTACK(completion);
+	if (!(dev->tproto & SAS_PROTOCOL_SSP))
+		return TMF_RESP_FUNC_ESUPP;
+
+	strncpy((u8 *)&ssp_task.LUN, lun, 8);
+
+	return mvs_exec_internal_tmf_task(dev, &ssp_task,
+				sizeof(ssp_task), tmf);
+}
+
+
+/*  Standard mandates link reset for ATA  (type 0)
+    and hard reset for SSP (type 1) , only for RECOVERY */
+static int mvs_debug_I_T_nexus_reset(struct domain_device *dev)
+{
+	int rc;
+	struct sas_phy *phy = sas_find_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);
+	msleep(2000);
+	return rc;
+}
+
+/* mandatory SAM-3 */
+int mvs_lu_reset(struct domain_device *dev, u8 *lun)
+{
+	unsigned long flags;
+	int i, phyno[WIDE_PORT_MAX_PHY], num , rc = TMF_RESP_FUNC_FAILED;
+	struct mvs_tmf_task tmf_task;
+	struct mvs_device * mvi_dev = dev->lldd_dev;
+	struct mvs_info *mvi = mvi_dev->mvi_info;
+
+	tmf_task.tmf = TMF_LU_RESET;
+	mvi_dev->dev_status = MVS_DEV_EH;
+	rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
+	if (rc == TMF_RESP_FUNC_COMPLETE) {
+		num = mvs_find_dev_phyno(dev, phyno);
+		spin_lock_irqsave(&mvi->lock, flags);
+		for (i = 0; i < num; i++)
+			mvs_release_task(mvi, phyno[i], dev);
+		spin_unlock_irqrestore(&mvi->lock, flags);
+	}
+	/* If failed, fall-through I_T_Nexus reset */
+	mv_printk("%s for device[%x]:rc= %d\n", __func__,
+			mvi_dev->device_id, rc);
+	return rc;
+}
+
+int mvs_I_T_nexus_reset(struct domain_device *dev)
+{
+	unsigned long flags;
+	int i, phyno[WIDE_PORT_MAX_PHY], num , rc = TMF_RESP_FUNC_FAILED;
+	struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev;
+	struct mvs_info *mvi = mvi_dev->mvi_info;
+
+	if (mvi_dev->dev_status != MVS_DEV_EH)
+		return TMF_RESP_FUNC_COMPLETE;
+	rc = mvs_debug_I_T_nexus_reset(dev);
+	mv_printk("%s for device[%x]:rc= %d\n",
+		__func__, mvi_dev->device_id, rc);
+
+	/* housekeeper */
+	num = mvs_find_dev_phyno(dev, phyno);
+	spin_lock_irqsave(&mvi->lock, flags);
+	for (i = 0; i < num; i++)
+		mvs_release_task(mvi, phyno[i], dev);
+	spin_unlock_irqrestore(&mvi->lock, flags);
+
+	return rc;
+}
+/* optional SAM-3 */
+int mvs_query_task(struct sas_task *task)
+{
+	u32 tag;
+	struct scsi_lun lun;
+	struct mvs_tmf_task tmf_task;
+	int rc = TMF_RESP_FUNC_FAILED;
+
+	if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
+		struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task;
+		struct domain_device *dev = task->dev;
+		struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
+		struct mvs_info *mvi = mvi_dev->mvi_info;
+
+		int_to_scsilun(cmnd->device->lun, &lun);
+		rc = mvs_find_tag(mvi, task, &tag);
+		if (rc == 0) {
+			rc = TMF_RESP_FUNC_FAILED;
+			return rc;
+		}
+
+		tmf_task.tmf = TMF_QUERY_TASK;
+		tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+		rc = mvs_debug_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task);
+		switch (rc) {
+		/* The task is still in Lun, release it then */
+		case TMF_RESP_FUNC_SUCC:
+		/* The task is not in Lun or failed, reset the phy */
+		case TMF_RESP_FUNC_FAILED:
+		case TMF_RESP_FUNC_COMPLETE:
+			break;
+		}
+	}
+	mv_printk("%s:rc= %d\n", __func__, rc);
+	return rc;
+}
+
+/*  mandatory SAM-3, still need free task/slot info */
+int mvs_abort_task(struct sas_task *task)
+{
+	struct scsi_lun lun;
+	struct mvs_tmf_task tmf_task;
+	struct domain_device *dev = task->dev;
+	struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
+	struct mvs_info *mvi = mvi_dev->mvi_info;
+	int rc = TMF_RESP_FUNC_FAILED;
+	unsigned long flags;
+	u32 tag;
+
+	if (mvi->exp_req)
+		mvi->exp_req--;
+	spin_lock_irqsave(&task->task_state_lock, flags);
+	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+		spin_unlock_irqrestore(&task->task_state_lock, flags);
+		rc = TMF_RESP_FUNC_COMPLETE;
+		goto out;
+	}
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
+	if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
+		struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task;
+
+		int_to_scsilun(cmnd->device->lun, &lun);
+		rc = mvs_find_tag(mvi, task, &tag);
+		if (rc == 0) {
+			mv_printk("No such tag in %s\n", __func__);
+			rc = TMF_RESP_FUNC_FAILED;
+			return rc;
+		}
+
+		tmf_task.tmf = TMF_ABORT_TASK;
+		tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+		rc = mvs_debug_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task);
+
+		/* if successful, clear the task and callback forwards.*/
+		if (rc == TMF_RESP_FUNC_COMPLETE) {
+			u32 slot_no;
+			struct mvs_slot_info *slot;
+
+			if (task->lldd_task) {
+				slot = task->lldd_task;
+				slot_no = (u32) (slot - mvi->slot_info);
+				mvs_slot_complete(mvi, slot_no, 1);
+			}
+		}
+	} else if (task->task_proto & SAS_PROTOCOL_SATA ||
+		task->task_proto & SAS_PROTOCOL_STP) {
+		/* to do free register_set */
+	} else {
+		/* SMP */
+
+	}
+out:
+	if (rc != TMF_RESP_FUNC_COMPLETE)
+		mv_printk("%s:rc= %d\n", __func__, rc);
+	return rc;
+}
+
+int mvs_abort_task_set(struct domain_device *dev, u8 *lun)
+{
+	int rc = TMF_RESP_FUNC_FAILED;
+	struct mvs_tmf_task tmf_task;
+
+	tmf_task.tmf = TMF_ABORT_TASK_SET;
+	rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
+
+	return rc;
+}
+
+int mvs_clear_aca(struct domain_device *dev, u8 *lun)
+{
+	int rc = TMF_RESP_FUNC_FAILED;
+	struct mvs_tmf_task tmf_task;
+
+	tmf_task.tmf = TMF_CLEAR_ACA;
+	rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
+
+	return rc;
+}
+
+int mvs_clear_task_set(struct domain_device *dev, u8 *lun)
+{
+	int rc = TMF_RESP_FUNC_FAILED;
+	struct mvs_tmf_task tmf_task;
+
+	tmf_task.tmf = TMF_CLEAR_TASK_SET;
+	rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
+
+	return rc;
+}
+
+static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
+			u32 slot_idx, int err)
+{
+	struct mvs_device *mvi_dev = task->dev->lldd_dev;
+	struct task_status_struct *tstat = &task->task_status;
+	struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf;
+	int stat = SAM_GOOD;
+
+
+	resp->frame_len = sizeof(struct dev_to_host_fis);
+	memcpy(&resp->ending_fis[0],
+	       SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset),
+	       sizeof(struct dev_to_host_fis));
+	tstat->buf_valid_size = sizeof(*resp);
+	if (unlikely(err))
+		stat = SAS_PROTO_RESPONSE;
+	return stat;
+}
+
+static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
+			 u32 slot_idx)
+{
+	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
+	int stat;
+	u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response));
+	u32 tfs = 0;
+	enum mvs_port_type type = PORT_TYPE_SAS;
+
+	if (err_dw0 & CMD_ISS_STPD)
+		MVS_CHIP_DISP->issue_stop(mvi, type, tfs);
+
+	MVS_CHIP_DISP->command_active(mvi, slot_idx);
+
+	stat = SAM_CHECK_COND;
+	switch (task->task_proto) {
+	case SAS_PROTOCOL_SSP:
+		stat = SAS_ABORTED_TASK;
+		break;
+	case SAS_PROTOCOL_SMP:
+		stat = SAM_CHECK_COND;
+		break;
+
+	case SAS_PROTOCOL_SATA:
+	case SAS_PROTOCOL_STP:
+	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+	{
+		if (err_dw0 == 0x80400002)
+			mv_printk("find reserved error, why?\n");
+
+		task->ata_task.use_ncq = 0;
+		stat = SAS_PROTO_RESPONSE;
+		mvs_sata_done(mvi, task, slot_idx, 1);
+
+	}
+		break;
+	default:
+		break;
+	}
+
+	return stat;
+}
+
+int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
+{
+	u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
+	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
+	struct sas_task *task = slot->task;
+	struct mvs_device *mvi_dev = NULL;
+	struct task_status_struct *tstat;
+
+	bool aborted;
+	void *to;
+	enum exec_status sts;
+
+	if (mvi->exp_req)
+		mvi->exp_req--;
+	if (unlikely(!task || !task->lldd_task))
+		return -1;
+
+	tstat = &task->task_status;
+	mvi_dev = task->dev->lldd_dev;
+
+	mvs_hba_cq_dump(mvi);
+
+	spin_lock(&task->task_state_lock);
+	task->task_state_flags &=
+		~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+	task->task_state_flags |= SAS_TASK_STATE_DONE;
+	/* race condition*/
+	aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
+	spin_unlock(&task->task_state_lock);
+
+	memset(tstat, 0, sizeof(*tstat));
+	tstat->resp = SAS_TASK_COMPLETE;
+
+	if (unlikely(aborted)) {
+		tstat->stat = SAS_ABORTED_TASK;
+		if (mvi_dev)
+			mvi_dev->runing_req--;
+		if (sas_protocol_ata(task->task_proto))
+			mvs_free_reg_set(mvi, mvi_dev);
+
+		mvs_slot_task_free(mvi, task, slot, slot_idx);
+		return -1;
+	}
+
+	if (unlikely(!mvi_dev || !slot->port->port_attached || flags)) {
+		mv_dprintk("port has not device.\n");
+		tstat->stat = SAS_PHY_DOWN;
+		goto out;
+	}
+
+	/*
+	if (unlikely((rx_desc & RXQ_ERR) || (*(u64 *) slot->response))) {
+		 mv_dprintk("Find device[%016llx] RXQ_ERR %X,
+		 err info:%016llx\n",
+		 SAS_ADDR(task->dev->sas_addr),
+		 rx_desc, (u64)(*(u64 *) slot->response));
+	}
+	*/
+
+	/* error info record present */
+	if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
+		tstat->stat = mvs_slot_err(mvi, task, slot_idx);
+		goto out;
+	}
+
+	switch (task->task_proto) {
+	case SAS_PROTOCOL_SSP:
+		/* hw says status == 0, datapres == 0 */
+		if (rx_desc & RXQ_GOOD) {
+			tstat->stat = SAM_GOOD;
+			tstat->resp = SAS_TASK_COMPLETE;
+		}
+		/* response frame present */
+		else if (rx_desc & RXQ_RSP) {
+			struct ssp_response_iu *iu = slot->response +
+						sizeof(struct mvs_err_info);
+			sas_ssp_task_response(mvi->dev, task, iu);
+		} else
+			tstat->stat = SAM_CHECK_COND;
+		break;
+
+	case SAS_PROTOCOL_SMP: {
+			struct scatterlist *sg_resp = &task->smp_task.smp_resp;
+			tstat->stat = SAM_GOOD;
+			to = kmap_atomic(sg_page(sg_resp), KM_IRQ0);
+			memcpy(to + sg_resp->offset,
+				slot->response + sizeof(struct mvs_err_info),
+				sg_dma_len(sg_resp));
+			kunmap_atomic(to, KM_IRQ0);
+			break;
+		}
+
+	case SAS_PROTOCOL_SATA:
+	case SAS_PROTOCOL_STP:
+	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: {
+			tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0);
+			break;
+		}
+
+	default:
+		tstat->stat = SAM_CHECK_COND;
+		break;
+	}
+
+out:
+	if (mvi_dev) {
+		mvi_dev->runing_req--;
+		if (sas_protocol_ata(task->task_proto))
+			mvs_free_reg_set(mvi, mvi_dev);
+	}
+	mvs_slot_task_free(mvi, task, slot, slot_idx);
+	sts = tstat->stat;
+
+	spin_unlock(&mvi->lock);
+	if (task->task_done)
+		task->task_done(task);
+	else
+		mv_dprintk("why has not task_done.\n");
+	spin_lock(&mvi->lock);
+
+	return sts;
+}
+
+void mvs_release_task(struct mvs_info *mvi,
+		int phy_no, struct domain_device *dev)
+{
+	int i = 0; u32 slot_idx;
+	struct mvs_phy *phy;
+	struct mvs_port *port;
+	struct mvs_slot_info *slot, *slot2;
+
+	phy = &mvi->phy[phy_no];
+	port = phy->port;
+	if (!port)
+		return;
+
+	list_for_each_entry_safe(slot, slot2, &port->list, entry) {
+		struct sas_task *task;
+		slot_idx = (u32) (slot - mvi->slot_info);
+		task = slot->task;
+
+		if (dev && task->dev != dev)
+			continue;
+
+		mv_printk("Release slot [%x] tag[%x], task [%p]:\n",
+			slot_idx, slot->slot_tag, task);
+
+		if (task->task_proto & SAS_PROTOCOL_SSP) {
+			mv_printk("attached with SSP task CDB[");
+			for (i = 0; i < 16; i++)
+				mv_printk(" %02x", task->ssp_task.cdb[i]);
+			mv_printk(" ]\n");
+		}
+
+		mvs_slot_complete(mvi, slot_idx, 1);
+	}
+}
+
+static void mvs_phy_disconnected(struct mvs_phy *phy)
+{
+	phy->phy_attached = 0;
+	phy->att_dev_info = 0;
+	phy->att_dev_sas_addr = 0;
+}
+
+static void mvs_work_queue(struct work_struct *work)
+{
+	struct delayed_work *dw = container_of(work, struct delayed_work, work);
+	struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q);
+	struct mvs_info *mvi = mwq->mvi;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mvi->lock, flags);
+	if (mwq->handler & PHY_PLUG_EVENT) {
+		u32 phy_no = (unsigned long) mwq->data;
+		struct sas_ha_struct *sas_ha = mvi->sas;
+		struct mvs_phy *phy = &mvi->phy[phy_no];
+		struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+		if (phy->phy_event & PHY_PLUG_OUT) {
+			u32 tmp;
+			struct sas_identify_frame *id;
+			id = (struct sas_identify_frame *)phy->frame_rcvd;
+			tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no);
+			phy->phy_event &= ~PHY_PLUG_OUT;
+			if (!(tmp & PHY_READY_MASK)) {
+				sas_phy_disconnected(sas_phy);
+				mvs_phy_disconnected(phy);
+				sas_ha->notify_phy_event(sas_phy,
+					PHYE_LOSS_OF_SIGNAL);
+				mv_dprintk("phy%d Removed Device\n", phy_no);
+			} else {
+				MVS_CHIP_DISP->detect_porttype(mvi, phy_no);
+				mvs_update_phyinfo(mvi, phy_no, 1);
+				mvs_bytes_dmaed(mvi, phy_no);
+				mvs_port_notify_formed(sas_phy, 0);
+				mv_dprintk("phy%d Attached Device\n", phy_no);
+			}
+		}
+	}
+	list_del(&mwq->entry);
+	spin_unlock_irqrestore(&mvi->lock, flags);
+	kfree(mwq);
+}
+
+static int mvs_handle_event(struct mvs_info *mvi, void *data, int handler)
+{
+	struct mvs_wq *mwq;
+	int ret = 0;
+
+	mwq = kmalloc(sizeof(struct mvs_wq), GFP_ATOMIC);
+	if (mwq) {
+		mwq->mvi = mvi;
+		mwq->data = data;
+		mwq->handler = handler;
+		MV_INIT_DELAYED_WORK(&mwq->work_q, mvs_work_queue, mwq);
+		list_add_tail(&mwq->entry, &mvi->wq_list);
+		schedule_delayed_work(&mwq->work_q, HZ * 2);
+	} else
+		ret = -ENOMEM;
+
+	return ret;
+}
+
+static void mvs_sig_time_out(unsigned long tphy)
+{
+	struct mvs_phy *phy = (struct mvs_phy *)tphy;
+	struct mvs_info *mvi = phy->mvi;
+	u8 phy_no;
+
+	for (phy_no = 0; phy_no < mvi->chip->n_phy; phy_no++) {
+		if (&mvi->phy[phy_no] == phy) {
+			mv_dprintk("Get signature time out, reset phy %d\n",
+				phy_no+mvi->id*mvi->chip->n_phy);
+			MVS_CHIP_DISP->phy_reset(mvi, phy_no, 1);
+		}
+	}
+}
+
+static void mvs_sig_remove_timer(struct mvs_phy *phy)
+{
+	if (phy->timer.function)
+		del_timer(&phy->timer);
+	phy->timer.function = NULL;
+}
+
+void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
+{
+	u32 tmp;
+	struct sas_ha_struct *sas_ha = mvi->sas;
+	struct mvs_phy *phy = &mvi->phy[phy_no];
+	struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+	phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no);
+	mv_dprintk("port %d ctrl sts=0x%X.\n", phy_no+mvi->id*mvi->chip->n_phy,
+		MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no));
+	mv_dprintk("Port %d irq sts = 0x%X\n", phy_no+mvi->id*mvi->chip->n_phy,
+		phy->irq_status);
+
+	/*
+	* events is port event now ,
+	* we need check the interrupt status which belongs to per port.
+	*/
+
+	if (phy->irq_status & PHYEV_DCDR_ERR)
+		mv_dprintk("port %d STP decoding error.\n",
+		phy_no+mvi->id*mvi->chip->n_phy);
+
+	if (phy->irq_status & PHYEV_POOF) {
+		if (!(phy->phy_event & PHY_PLUG_OUT)) {
+			int dev_sata = phy->phy_type & PORT_TYPE_SATA;
+			int ready;
+			mvs_release_task(mvi, phy_no, NULL);
+			phy->phy_event |= PHY_PLUG_OUT;
+			mvs_handle_event(mvi,
+				(void *)(unsigned long)phy_no,
+				PHY_PLUG_EVENT);
+			ready = mvs_is_phy_ready(mvi, phy_no);
+			if (!ready)
+				mv_dprintk("phy%d Unplug Notice\n",
+					phy_no +
+					mvi->id * mvi->chip->n_phy);
+			if (ready || dev_sata) {
+				if (MVS_CHIP_DISP->stp_reset)
+					MVS_CHIP_DISP->stp_reset(mvi,
+							phy_no);
+				else
+					MVS_CHIP_DISP->phy_reset(mvi,
+							phy_no, 0);
+				return;
+			}
+		}
+	}
+
+	if (phy->irq_status & PHYEV_COMWAKE) {
+		tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, phy_no);
+		MVS_CHIP_DISP->write_port_irq_mask(mvi, phy_no,
+					tmp | PHYEV_SIG_FIS);
+		if (phy->timer.function == NULL) {
+			phy->timer.data = (unsigned long)phy;
+			phy->timer.function = mvs_sig_time_out;
+			phy->timer.expires = jiffies + 10*HZ;
+			add_timer(&phy->timer);
+		}
+	}
+	if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) {
+		phy->phy_status = mvs_is_phy_ready(mvi, phy_no);
+		mvs_sig_remove_timer(phy);
+		mv_dprintk("notify plug in on phy[%d]\n", phy_no);
+		if (phy->phy_status) {
+			mdelay(10);
+			MVS_CHIP_DISP->detect_porttype(mvi, phy_no);
+			if (phy->phy_type & PORT_TYPE_SATA) {
+				tmp = MVS_CHIP_DISP->read_port_irq_mask(
+						mvi, phy_no);
+				tmp &= ~PHYEV_SIG_FIS;
+				MVS_CHIP_DISP->write_port_irq_mask(mvi,
+							phy_no, tmp);
+			}
+			mvs_update_phyinfo(mvi, phy_no, 0);
+			mvs_bytes_dmaed(mvi, phy_no);
+			/* whether driver is going to handle hot plug */
+			if (phy->phy_event & PHY_PLUG_OUT) {
+				mvs_port_notify_formed(sas_phy, 0);
+				phy->phy_event &= ~PHY_PLUG_OUT;
+			}
+		} else {
+			mv_dprintk("plugin interrupt but phy%d is gone\n",
+				phy_no + mvi->id*mvi->chip->n_phy);
+		}
+	} else if (phy->irq_status & PHYEV_BROAD_CH) {
+		mv_dprintk("port %d broadcast change.\n",
+			phy_no + mvi->id*mvi->chip->n_phy);
+		/* exception for Samsung disk drive*/
+		mdelay(1000);
+		sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+	}
+	MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status);
+}
+
+int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
+{
+	u32 rx_prod_idx, rx_desc;
+	bool attn = false;
+
+	/* the first dword in the RX ring is special: it contains
+	 * a mirror of the hardware's RX producer index, so that
+	 * we don't have to stall the CPU reading that register.
+	 * The actual RX ring is offset by one dword, due to this.
+	 */
+	rx_prod_idx = mvi->rx_cons;
+	mvi->rx_cons = le32_to_cpu(mvi->rx[0]);
+	if (mvi->rx_cons == 0xfff)	/* h/w hasn't touched RX ring yet */
+		return 0;
+
+	/* The CMPL_Q may come late, read from register and try again
+	* note: if coalescing is enabled,
+	* it will need to read from register every time for sure
+	*/
+	if (unlikely(mvi->rx_cons == rx_prod_idx))
+		mvi->rx_cons = MVS_CHIP_DISP->rx_update(mvi) & RX_RING_SZ_MASK;
+
+	if (mvi->rx_cons == rx_prod_idx)
+		return 0;
+
+	while (mvi->rx_cons != rx_prod_idx) {
+		/* increment our internal RX consumer pointer */
+		rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1);
+		rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]);
+
+		if (likely(rx_desc & RXQ_DONE))
+			mvs_slot_complete(mvi, rx_desc, 0);
+		if (rx_desc & RXQ_ATTN) {
+			attn = true;
+		} else if (rx_desc & RXQ_ERR) {
+			if (!(rx_desc & RXQ_DONE))
+				mvs_slot_complete(mvi, rx_desc, 0);
+		} else if (rx_desc & RXQ_SLOT_RESET) {
+			mvs_slot_free(mvi, rx_desc);
+		}
+	}
+
+	if (attn && self_clear)
+		MVS_CHIP_DISP->int_full(mvi);
+	return 0;
+}
+
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h
new file mode 100644
index 0000000..aa2270a
--- /dev/null
+++ b/drivers/scsi/mvsas/mv_sas.h
@@ -0,0 +1,406 @@
+/*
+ * Marvell 88SE64xx/88SE94xx main function head file
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+#ifndef _MV_SAS_H_
+#define _MV_SAS_H_
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/vmalloc.h>
+#include <scsi/libsas.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/sas_ata.h>
+#include <linux/version.h>
+#include "mv_defs.h"
+
+#define DRV_NAME		"mvsas"
+#define DRV_VERSION		"0.8.2"
+#define _MV_DUMP		0
+#define MVS_ID_NOT_MAPPED	0x7f
+/* #define DISABLE_HOTPLUG_DMA_FIX */
+#define MAX_EXP_RUNNING_REQ	2
+#define WIDE_PORT_MAX_PHY		4
+#define	MV_DISABLE_NCQ	0
+#define mv_printk(fmt, arg ...)	\
+	printk(KERN_DEBUG"%s %d:" fmt, __FILE__, __LINE__, ## arg)
+#ifdef MV_DEBUG
+#define mv_dprintk(format, arg...)	\
+	printk(KERN_DEBUG"%s %d:" format, __FILE__, __LINE__, ## arg)
+#else
+#define mv_dprintk(format, arg...)
+#endif
+#define MV_MAX_U32			0xffffffff
+
+extern struct mvs_tgt_initiator mvs_tgt;
+extern struct mvs_info *tgt_mvi;
+extern const struct mvs_dispatch mvs_64xx_dispatch;
+extern const struct mvs_dispatch mvs_94xx_dispatch;
+
+#define DEV_IS_EXPANDER(type)	\
+	((type == EDGE_DEV) || (type == FANOUT_DEV))
+
+#define bit(n) ((u32)1 << n)
+
+#define for_each_phy(__lseq_mask, __mc, __lseq)			\
+	for ((__mc) = (__lseq_mask), (__lseq) = 0;		\
+					(__mc) != 0 ;		\
+					(++__lseq), (__mc) >>= 1)
+
+#define MV_INIT_DELAYED_WORK(w, f, d)	INIT_DELAYED_WORK(w, f)
+#define UNASSOC_D2H_FIS(id)		\
+	((void *) mvi->rx_fis + 0x100 * id)
+#define SATA_RECEIVED_FIS_LIST(reg_set)	\
+	((void *) mvi->rx_fis + mvi->chip->fis_offs + 0x100 * reg_set)
+#define SATA_RECEIVED_SDB_FIS(reg_set)	\
+	(SATA_RECEIVED_FIS_LIST(reg_set) + 0x58)
+#define SATA_RECEIVED_D2H_FIS(reg_set)	\
+	(SATA_RECEIVED_FIS_LIST(reg_set) + 0x40)
+#define SATA_RECEIVED_PIO_FIS(reg_set)	\
+	(SATA_RECEIVED_FIS_LIST(reg_set) + 0x20)
+#define SATA_RECEIVED_DMA_FIS(reg_set)	\
+	(SATA_RECEIVED_FIS_LIST(reg_set) + 0x00)
+
+enum dev_status {
+	MVS_DEV_NORMAL = 0x0,
+	MVS_DEV_EH	= 0x1,
+};
+
+
+struct mvs_info;
+
+struct mvs_dispatch {
+	char *name;
+	int (*chip_init)(struct mvs_info *mvi);
+	int (*spi_init)(struct mvs_info *mvi);
+	int (*chip_ioremap)(struct mvs_info *mvi);
+	void (*chip_iounmap)(struct mvs_info *mvi);
+	irqreturn_t (*isr)(struct mvs_info *mvi, int irq, u32 stat);
+	u32 (*isr_status)(struct mvs_info *mvi, int irq);
+	void (*interrupt_enable)(struct mvs_info *mvi);
+	void (*interrupt_disable)(struct mvs_info *mvi);
+
+	u32 (*read_phy_ctl)(struct mvs_info *mvi, u32 port);
+	void (*write_phy_ctl)(struct mvs_info *mvi, u32 port, u32 val);
+
+	u32 (*read_port_cfg_data)(struct mvs_info *mvi, u32 port);
+	void (*write_port_cfg_data)(struct mvs_info *mvi, u32 port, u32 val);
+	void (*write_port_cfg_addr)(struct mvs_info *mvi, u32 port, u32 addr);
+
+	u32 (*read_port_vsr_data)(struct mvs_info *mvi, u32 port);
+	void (*write_port_vsr_data)(struct mvs_info *mvi, u32 port, u32 val);
+	void (*write_port_vsr_addr)(struct mvs_info *mvi, u32 port, u32 addr);
+
+	u32 (*read_port_irq_stat)(struct mvs_info *mvi, u32 port);
+	void (*write_port_irq_stat)(struct mvs_info *mvi, u32 port, u32 val);
+
+	u32 (*read_port_irq_mask)(struct mvs_info *mvi, u32 port);
+	void (*write_port_irq_mask)(struct mvs_info *mvi, u32 port, u32 val);
+
+	void (*get_sas_addr)(void *buf, u32 buflen);
+	void (*command_active)(struct mvs_info *mvi, u32 slot_idx);
+	void (*issue_stop)(struct mvs_info *mvi, enum mvs_port_type type,
+				u32 tfs);
+	void (*start_delivery)(struct mvs_info *mvi, u32 tx);
+	u32 (*rx_update)(struct mvs_info *mvi);
+	void (*int_full)(struct mvs_info *mvi);
+	u8 (*assign_reg_set)(struct mvs_info *mvi, u8 *tfs);
+	void (*free_reg_set)(struct mvs_info *mvi, u8 *tfs);
+	u32 (*prd_size)(void);
+	u32 (*prd_count)(void);
+	void (*make_prd)(struct scatterlist *scatter, int nr, void *prd);
+	void (*detect_porttype)(struct mvs_info *mvi, int i);
+	int (*oob_done)(struct mvs_info *mvi, int i);
+	void (*fix_phy_info)(struct mvs_info *mvi, int i,
+				struct sas_identify_frame *id);
+	void (*phy_work_around)(struct mvs_info *mvi, int i);
+	void (*phy_set_link_rate)(struct mvs_info *mvi, u32 phy_id,
+				struct sas_phy_linkrates *rates);
+	u32 (*phy_max_link_rate)(void);
+	void (*phy_disable)(struct mvs_info *mvi, u32 phy_id);
+	void (*phy_enable)(struct mvs_info *mvi, u32 phy_id);
+	void (*phy_reset)(struct mvs_info *mvi, u32 phy_id, int hard);
+	void (*stp_reset)(struct mvs_info *mvi, u32 phy_id);
+	void (*clear_active_cmds)(struct mvs_info *mvi);
+	u32 (*spi_read_data)(struct mvs_info *mvi);
+	void (*spi_write_data)(struct mvs_info *mvi, u32 data);
+	int (*spi_buildcmd)(struct mvs_info *mvi,
+						u32      *dwCmd,
+						u8       cmd,
+						u8       read,
+						u8       length,
+						u32      addr
+						);
+	int (*spi_issuecmd)(struct mvs_info *mvi, u32 cmd);
+	int (*spi_waitdataready)(struct mvs_info *mvi, u32 timeout);
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+	void (*dma_fix)(dma_addr_t buf_dma, int buf_len, int from, void *prd);
+#endif
+
+};
+
+struct mvs_chip_info {
+	u32 		n_host;
+	u32 		n_phy;
+	u32 		fis_offs;
+	u32 		fis_count;
+	u32 		srs_sz;
+	u32 		slot_width;
+	const struct mvs_dispatch *dispatch;
+};
+#define MVS_CHIP_SLOT_SZ	(1U << mvi->chip->slot_width)
+#define MVS_RX_FISL_SZ		\
+	(mvi->chip->fis_offs + (mvi->chip->fis_count * 0x100))
+#define MVS_CHIP_DISP		(mvi->chip->dispatch)
+
+struct mvs_err_info {
+	__le32			flags;
+	__le32			flags2;
+};
+
+struct mvs_cmd_hdr {
+	__le32			flags;	/* PRD tbl len; SAS, SATA ctl */
+	__le32			lens;	/* cmd, max resp frame len */
+	__le32			tags;	/* targ port xfer tag; tag */
+	__le32			data_len;	/* data xfer len */
+	__le64			cmd_tbl;  	/* command table address */
+	__le64			open_frame;	/* open addr frame address */
+	__le64			status_buf;	/* status buffer address */
+	__le64			prd_tbl;		/* PRD tbl address */
+	__le32			reserved[4];
+};
+
+struct mvs_port {
+	struct asd_sas_port	sas_port;
+	u8			port_attached;
+	u8			wide_port_phymap;
+	struct list_head	list;
+};
+
+struct mvs_phy {
+	struct mvs_info 		*mvi;
+	struct mvs_port		*port;
+	struct asd_sas_phy	sas_phy;
+	struct sas_identify	identify;
+	struct scsi_device	*sdev;
+	struct timer_list timer;
+	u64		dev_sas_addr;
+	u64		att_dev_sas_addr;
+	u32		att_dev_info;
+	u32		dev_info;
+	u32		phy_type;
+	u32		phy_status;
+	u32		irq_status;
+	u32		frame_rcvd_size;
+	u8		frame_rcvd[32];
+	u8		phy_attached;
+	u8		phy_mode;
+	u8		reserved[2];
+	u32		phy_event;
+	enum sas_linkrate	minimum_linkrate;
+	enum sas_linkrate	maximum_linkrate;
+};
+
+struct mvs_device {
+	struct list_head		dev_entry;
+	enum sas_dev_type dev_type;
+	struct mvs_info *mvi_info;
+	struct domain_device *sas_device;
+	u32 attached_phy;
+	u32 device_id;
+	u32 runing_req;
+	u8 taskfileset;
+	u8 dev_status;
+	u16 reserved;
+};
+
+struct mvs_slot_info {
+	struct list_head entry;
+	union {
+		struct sas_task *task;
+		void *tdata;
+	};
+	u32 n_elem;
+	u32 tx;
+	u32 slot_tag;
+
+	/* DMA buffer for storing cmd tbl, open addr frame, status buffer,
+	 * and PRD table
+	 */
+	void *buf;
+	dma_addr_t buf_dma;
+#if _MV_DUMP
+	u32 cmd_size;
+#endif
+	void *response;
+	struct mvs_port *port;
+	struct mvs_device	*device;
+	void *open_frame;
+};
+
+struct mvs_info {
+	unsigned long flags;
+
+	/* host-wide lock */
+	spinlock_t lock;
+
+	/* our device */
+	struct pci_dev *pdev;
+	struct device *dev;
+
+	/* enhanced mode registers */
+	void __iomem *regs;
+
+	/* peripheral or soc registers */
+	void __iomem *regs_ex;
+	u8 sas_addr[SAS_ADDR_SIZE];
+
+	/* SCSI/SAS glue */
+	struct sas_ha_struct *sas;
+	struct Scsi_Host *shost;
+
+	/* TX (delivery) DMA ring */
+	__le32 *tx;
+	dma_addr_t tx_dma;
+
+	/* cached next-producer idx */
+	u32 tx_prod;
+
+	/* RX (completion) DMA ring */
+	__le32	*rx;
+	dma_addr_t rx_dma;
+
+	/* RX consumer idx */
+	u32 rx_cons;
+
+	/* RX'd FIS area */
+	__le32 *rx_fis;
+	dma_addr_t rx_fis_dma;
+
+	/* DMA command header slots */
+	struct mvs_cmd_hdr *slot;
+	dma_addr_t slot_dma;
+
+	u32 chip_id;
+	const struct mvs_chip_info *chip;
+
+	int tags_num;
+	DECLARE_BITMAP(tags, MVS_SLOTS);
+	/* further per-slot information */
+	struct mvs_phy phy[MVS_MAX_PHYS];
+	struct mvs_port port[MVS_MAX_PHYS];
+	u32 irq;
+	u32 exp_req;
+	u32 id;
+	u64 sata_reg_set;
+	struct list_head *hba_list;
+	struct list_head soc_entry;
+	struct list_head wq_list;
+	unsigned long instance;
+	u16 flashid;
+	u32 flashsize;
+	u32 flashsectSize;
+
+	void *addon;
+	struct mvs_device	devices[MVS_MAX_DEVICES];
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+	void *bulk_buffer;
+	dma_addr_t bulk_buffer_dma;
+#define TRASH_BUCKET_SIZE    	0x20000
+#endif
+	struct mvs_slot_info slot_info[0];
+};
+
+struct mvs_prv_info{
+	u8 n_host;
+	u8 n_phy;
+	u16 reserve;
+	struct mvs_info *mvi[2];
+};
+
+struct mvs_wq {
+	struct delayed_work work_q;
+	struct mvs_info *mvi;
+	void *data;
+	int handler;
+	struct list_head entry;
+};
+
+struct mvs_task_exec_info {
+	struct sas_task *task;
+	struct mvs_cmd_hdr *hdr;
+	struct mvs_port *port;
+	u32 tag;
+	int n_elem;
+};
+
+
+/******************** function prototype *********************/
+void mvs_get_sas_addr(void *buf, u32 buflen);
+void mvs_tag_clear(struct mvs_info *mvi, u32 tag);
+void mvs_tag_free(struct mvs_info *mvi, u32 tag);
+void mvs_tag_set(struct mvs_info *mvi, unsigned int tag);
+int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out);
+void mvs_tag_init(struct mvs_info *mvi);
+void mvs_iounmap(void __iomem *regs);
+int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex);
+void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard);
+int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
+			void *funcdata);
+void __devinit mvs_set_sas_addr(struct mvs_info *mvi, int port_id,
+				u32 off_lo, u32 off_hi, u64 sas_addr);
+int mvs_slave_alloc(struct scsi_device *scsi_dev);
+int mvs_slave_configure(struct scsi_device *sdev);
+void mvs_scan_start(struct Scsi_Host *shost);
+int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time);
+int mvs_queue_command(struct sas_task *task, const int num,
+			gfp_t gfp_flags);
+int mvs_abort_task(struct sas_task *task);
+int mvs_abort_task_set(struct domain_device *dev, u8 *lun);
+int mvs_clear_aca(struct domain_device *dev, u8 *lun);
+int mvs_clear_task_set(struct domain_device *dev, u8 * lun);
+void mvs_port_formed(struct asd_sas_phy *sas_phy);
+void mvs_port_deformed(struct asd_sas_phy *sas_phy);
+int mvs_dev_found(struct domain_device *dev);
+void mvs_dev_gone(struct domain_device *dev);
+int mvs_lu_reset(struct domain_device *dev, u8 *lun);
+int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags);
+int mvs_I_T_nexus_reset(struct domain_device *dev);
+int mvs_query_task(struct sas_task *task);
+void mvs_release_task(struct mvs_info *mvi, int phy_no,
+			struct domain_device *dev);
+void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events);
+void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
+int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
+void mvs_hexdump(u32 size, u8 *data, u32 baseaddr);
+#endif
+
diff --git a/drivers/scsi/osd/Kbuild b/drivers/scsi/osd/Kbuild
index 0e207aa..5fd73d77 100644
--- a/drivers/scsi/osd/Kbuild
+++ b/drivers/scsi/osd/Kbuild
@@ -11,31 +11,6 @@
 # it under the terms of the GNU General Public License version 2
 #
 
-ifneq ($(OSD_INC),)
-# we are built out-of-tree Kconfigure everything as on
-
-CONFIG_SCSI_OSD_INITIATOR=m
-ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE
-
-CONFIG_SCSI_OSD_ULD=m
-ccflags-y += -DCONFIG_SCSI_OSD_ULD -DCONFIG_SCSI_OSD_ULD_MODULE
-
-# CONFIG_SCSI_OSD_DPRINT_SENSE =
-#	0 - no print of errors
-#	1 - print errors
-#	2 - errors + warrnings
-ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1
-
-# Uncomment to turn debug on
-# ccflags-y += -DCONFIG_SCSI_OSD_DEBUG
-
-# if we are built out-of-tree and the hosting kernel has OSD headers
-# then "ccflags-y +=" will not pick the out-off-tree headers. Only by doing
-# this it will work. This might break in future kernels
-LINUXINCLUDE := -I$(OSD_INC) $(LINUXINCLUDE)
-
-endif
-
 # libosd.ko - osd-initiator library
 libosd-y := osd_initiator.o
 obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o
diff --git a/drivers/scsi/osd/Makefile b/drivers/scsi/osd/Makefile
deleted file mode 100755
index d905344..0000000
--- a/drivers/scsi/osd/Makefile
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Makefile for the OSD modules (out of tree)
-#
-# Copyright (C) 2008 Panasas Inc.  All rights reserved.
-#
-# Authors:
-#   Boaz Harrosh <bharrosh@panasas.com>
-#   Benny Halevy <bhalevy@panasas.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
-#
-# This Makefile is used to call the kernel Makefile in case of an out-of-tree
-# build.
-# $KSRC should point to a Kernel source tree otherwise host's default is
-# used. (eg. /lib/modules/`uname -r`/build)
-
-# include path for out-of-tree Headers
-OSD_INC ?= `pwd`/../../../include
-
-# allow users to override these
-# e.g. to compile for a kernel that you aren't currently running
-KSRC ?= /lib/modules/$(shell uname -r)/build
-KBUILD_OUTPUT ?=
-ARCH ?=
-V ?= 0
-
-# this is the basic Kbuild out-of-tree invocation, with the M= option
-KBUILD_BASE = +$(MAKE) -C $(KSRC) M=`pwd` KBUILD_OUTPUT=$(KBUILD_OUTPUT) ARCH=$(ARCH) V=$(V)
-
-all: libosd
-
-libosd: ;
-	$(KBUILD_BASE) OSD_INC=$(OSD_INC) modules
-
-clean:
-	$(KBUILD_BASE) clean
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 5776b2a..7a117c1 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -118,39 +118,39 @@
 		_osd_ver_desc(or));
 
 	pFirst = get_attrs[a++].val_ptr;
-	OSD_INFO("OSD_ATTR_RI_VENDOR_IDENTIFICATION [%s]\n",
+	OSD_INFO("VENDOR_IDENTIFICATION  [%s]\n",
 		(char *)pFirst);
 
 	pFirst = get_attrs[a++].val_ptr;
-	OSD_INFO("OSD_ATTR_RI_PRODUCT_IDENTIFICATION [%s]\n",
+	OSD_INFO("PRODUCT_IDENTIFICATION [%s]\n",
 		(char *)pFirst);
 
 	pFirst = get_attrs[a++].val_ptr;
-	OSD_INFO("OSD_ATTR_RI_PRODUCT_MODEL [%s]\n",
+	OSD_INFO("PRODUCT_MODEL          [%s]\n",
 		(char *)pFirst);
 
 	pFirst = get_attrs[a++].val_ptr;
-	OSD_INFO("OSD_ATTR_RI_PRODUCT_REVISION_LEVEL [%u]\n",
+	OSD_INFO("PRODUCT_REVISION_LEVEL [%u]\n",
 		pFirst ? get_unaligned_be32(pFirst) : ~0U);
 
 	pFirst = get_attrs[a++].val_ptr;
-	OSD_INFO("OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER [%s]\n",
+	OSD_INFO("PRODUCT_SERIAL_NUMBER  [%s]\n",
 		(char *)pFirst);
 
 	pFirst = get_attrs[a].val_ptr;
-	OSD_INFO("OSD_ATTR_RI_OSD_NAME [%s]\n", (char *)pFirst);
+	OSD_INFO("OSD_NAME               [%s]\n", (char *)pFirst);
 	a++;
 
 	pFirst = get_attrs[a++].val_ptr;
-	OSD_INFO("OSD_ATTR_RI_TOTAL_CAPACITY [0x%llx]\n",
+	OSD_INFO("TOTAL_CAPACITY         [0x%llx]\n",
 		pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL);
 
 	pFirst = get_attrs[a++].val_ptr;
-	OSD_INFO("OSD_ATTR_RI_USED_CAPACITY [0x%llx]\n",
+	OSD_INFO("USED_CAPACITY          [0x%llx]\n",
 		pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL);
 
 	pFirst = get_attrs[a++].val_ptr;
-	OSD_INFO("OSD_ATTR_RI_NUMBER_OF_PARTITIONS [%llu]\n",
+	OSD_INFO("NUMBER_OF_PARTITIONS   [%llu]\n",
 		pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL);
 
 	if (a >= nelem)
@@ -158,7 +158,7 @@
 
 	/* FIXME: Where are the time utilities */
 	pFirst = get_attrs[a++].val_ptr;
-	OSD_INFO("OSD_ATTR_RI_CLOCK [0x%02x%02x%02x%02x%02x%02x]\n",
+	OSD_INFO("CLOCK                  [0x%02x%02x%02x%02x%02x%02x]\n",
 		((char *)pFirst)[0], ((char *)pFirst)[1],
 		((char *)pFirst)[2], ((char *)pFirst)[3],
 		((char *)pFirst)[4], ((char *)pFirst)[5]);
@@ -169,7 +169,8 @@
 
 		hex_dump_to_buffer(get_attrs[a].val_ptr, len, 32, 1,
 				   sid_dump, sizeof(sid_dump), true);
-		OSD_INFO("OSD_ATTR_RI_OSD_SYSTEM_ID(%d) [%s]\n", len, sid_dump);
+		OSD_INFO("OSD_SYSTEM_ID(%d)\n"
+			 "        [%s]\n", len, sid_dump);
 		a++;
 	}
 out:
@@ -669,7 +670,7 @@
 	__be16 action, const struct osd_obj_id *obj, osd_id initial_id,
 	struct osd_obj_id_list *list, unsigned nelem)
 {
-	struct request_queue *q = or->osd_dev->scsi_device->request_queue;
+	struct request_queue *q = osd_request_queue(or->osd_dev);
 	u64 len = nelem * sizeof(osd_id) + sizeof(*list);
 	struct bio *bio;
 
@@ -778,16 +779,32 @@
 */
 
 void osd_req_write(struct osd_request *or,
-	const struct osd_obj_id *obj, struct bio *bio, u64 offset)
+	const struct osd_obj_id *obj, u64 offset,
+	struct bio *bio, u64 len)
 {
-	_osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, bio->bi_size);
+	_osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, len);
 	WARN_ON(or->out.bio || or->out.total_bytes);
-	bio->bi_rw |= (1 << BIO_RW);
+	WARN_ON(0 ==  bio_rw_flagged(bio, BIO_RW));
 	or->out.bio = bio;
-	or->out.total_bytes = bio->bi_size;
+	or->out.total_bytes = len;
 }
 EXPORT_SYMBOL(osd_req_write);
 
+int osd_req_write_kern(struct osd_request *or,
+	const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
+{
+	struct request_queue *req_q = osd_request_queue(or->osd_dev);
+	struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
+
+	if (IS_ERR(bio))
+		return PTR_ERR(bio);
+
+	bio->bi_rw |= (1 << BIO_RW); /* FIXME: bio_set_dir() */
+	osd_req_write(or, obj, offset, bio, len);
+	return 0;
+}
+EXPORT_SYMBOL(osd_req_write_kern);
+
 /*TODO: void osd_req_append(struct osd_request *,
 	const struct osd_obj_id *, struct bio *data_out); */
 /*TODO: void osd_req_create_write(struct osd_request *,
@@ -813,16 +830,31 @@
 EXPORT_SYMBOL(osd_req_flush_object);
 
 void osd_req_read(struct osd_request *or,
-	const struct osd_obj_id *obj, struct bio *bio, u64 offset)
+	const struct osd_obj_id *obj, u64 offset,
+	struct bio *bio, u64 len)
 {
-	_osd_req_encode_common(or, OSD_ACT_READ, obj, offset, bio->bi_size);
+	_osd_req_encode_common(or, OSD_ACT_READ, obj, offset, len);
 	WARN_ON(or->in.bio || or->in.total_bytes);
-	bio->bi_rw &= ~(1 << BIO_RW);
+	WARN_ON(1 == bio_rw_flagged(bio, BIO_RW));
 	or->in.bio = bio;
-	or->in.total_bytes = bio->bi_size;
+	or->in.total_bytes = len;
 }
 EXPORT_SYMBOL(osd_req_read);
 
+int osd_req_read_kern(struct osd_request *or,
+	const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
+{
+	struct request_queue *req_q = osd_request_queue(or->osd_dev);
+	struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
+
+	if (IS_ERR(bio))
+		return PTR_ERR(bio);
+
+	osd_req_read(or, obj, offset, bio, len);
+	return 0;
+}
+EXPORT_SYMBOL(osd_req_read_kern);
+
 void osd_req_get_attributes(struct osd_request *or,
 	const struct osd_obj_id *obj)
 {
@@ -1213,7 +1245,7 @@
 }
 
 static int _osd_req_finalize_data_integrity(struct osd_request *or,
-	bool has_in, bool has_out, const u8 *cap_key)
+	bool has_in, bool has_out, u64 out_data_bytes, const u8 *cap_key)
 {
 	struct osd_security_parameters *sec_parms = _osd_req_sec_params(or);
 	int ret;
@@ -1228,8 +1260,7 @@
 		};
 		unsigned pad;
 
-		or->out_data_integ.data_bytes = cpu_to_be64(
-			or->out.bio ? or->out.bio->bi_size : 0);
+		or->out_data_integ.data_bytes = cpu_to_be64(out_data_bytes);
 		or->out_data_integ.set_attributes_bytes = cpu_to_be64(
 			or->set_attr.total_bytes);
 		or->out_data_integ.get_attributes_bytes = cpu_to_be64(
@@ -1306,6 +1337,8 @@
 
 	or->request = req;
 	req->cmd_type = REQ_TYPE_BLOCK_PC;
+	req->cmd_flags |= REQ_QUIET;
+
 	req->timeout = or->timeout;
 	req->retries = or->retries;
 	req->sense = or->sense;
@@ -1339,6 +1372,7 @@
 {
 	struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
 	bool has_in, has_out;
+	u64 out_data_bytes = or->out.total_bytes;
 	int ret;
 
 	if (options & OSD_REQ_FUA)
@@ -1388,7 +1422,8 @@
 		}
 	}
 
-	ret = _osd_req_finalize_data_integrity(or, has_in, has_out, cap_key);
+	ret = _osd_req_finalize_data_integrity(or, has_in, has_out,
+					       out_data_bytes, cap_key);
 	if (ret)
 		return ret;
 
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
index 22b59e1..0bdef33 100644
--- a/drivers/scsi/osd/osd_uld.c
+++ b/drivers/scsi/osd/osd_uld.c
@@ -49,6 +49,7 @@
 #include <linux/device.h>
 #include <linux/idr.h>
 #include <linux/major.h>
+#include <linux/file.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_driver.h>
@@ -175,10 +176,9 @@
 
 struct osd_dev *osduld_path_lookup(const char *name)
 {
-	struct path path;
-	struct inode *inode;
-	struct cdev *cdev;
-	struct osd_uld_device *uninitialized_var(oud);
+	struct osd_uld_device *oud;
+	struct osd_dev *od;
+	struct file *file;
 	int error;
 
 	if (!name || !*name) {
@@ -186,52 +186,46 @@
 		return ERR_PTR(-EINVAL);
 	}
 
-	error = kern_path(name, LOOKUP_FOLLOW, &path);
-	if (error) {
-		OSD_ERR("path_lookup of %s failed=>%d\n", name, error);
-		return ERR_PTR(error);
+	od = kzalloc(sizeof(*od), GFP_KERNEL);
+	if (!od)
+		return ERR_PTR(-ENOMEM);
+
+	file = filp_open(name, O_RDWR, 0);
+	if (IS_ERR(file)) {
+		error = PTR_ERR(file);
+		goto free_od;
 	}
 
-	inode = path.dentry->d_inode;
-	error = -EINVAL; /* Not the right device e.g osd_uld_device */
-	if (!S_ISCHR(inode->i_mode)) {
-		OSD_DEBUG("!S_ISCHR()\n");
-		goto out;
+	if (file->f_op != &osd_fops){
+		error = -EINVAL;
+		goto close_file;
 	}
 
-	cdev = inode->i_cdev;
-	if (!cdev) {
-		OSD_ERR("Before mounting an OSD Based filesystem\n");
-		OSD_ERR("  user-mode must open+close the %s device\n", name);
-		OSD_ERR("  Example: bash: echo < %s\n", name);
-		goto out;
-	}
+	oud = file->private_data;
 
-	/* The Magic wand. Is it our char-dev */
-	/* TODO: Support sg devices */
-	if (cdev->owner != THIS_MODULE) {
-		OSD_ERR("Error mounting %s - is not an OSD device\n", name);
-		goto out;
-	}
+	*od = oud->od;
+	od->file = file;
 
-	oud = container_of(cdev, struct osd_uld_device, cdev);
+	return od;
 
-	__uld_get(oud);
-	error = 0;
-
-out:
-	path_put(&path);
-	return error ? ERR_PTR(error) : &oud->od;
+close_file:
+	fput(file);
+free_od:
+	kfree(od);
+	return ERR_PTR(error);
 }
 EXPORT_SYMBOL(osduld_path_lookup);
 
 void osduld_put_device(struct osd_dev *od)
 {
-	if (od) {
-		struct osd_uld_device *oud = container_of(od,
-						struct osd_uld_device, od);
 
-		__uld_put(oud);
+	if (od && !IS_ERR(od)) {
+		struct osd_uld_device *oud = od->file->private_data;
+
+		BUG_ON(od->scsi_device != oud->od.scsi_device);
+
+		fput(od->file);
+		kfree(od);
 	}
 }
 EXPORT_SYMBOL(osduld_put_device);
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 5defe5e..8371d91 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -17,9 +17,12 @@
 * General Public License for more details.
 *
 ******************************************************************************/
-#define QLA1280_VERSION      "3.26"
+#define QLA1280_VERSION      "3.27"
 /*****************************************************************************
     Revision History:
+    Rev  3.27, February 10, 2009, Michael Reed
+	- General code cleanup.
+	- Improve error recovery.
     Rev  3.26, January 16, 2006 Jes Sorensen
 	- Ditch all < 2.6 support
     Rev  3.25.1, February 10, 2005 Christoph Hellwig
@@ -435,7 +438,6 @@
 				   uint8_t, uint16_t *);
 static int qla1280_bus_reset(struct scsi_qla_host *, int);
 static int qla1280_device_reset(struct scsi_qla_host *, int, int);
-static int qla1280_abort_device(struct scsi_qla_host *, int, int, int);
 static int qla1280_abort_command(struct scsi_qla_host *, struct srb *, int);
 static int qla1280_abort_isp(struct scsi_qla_host *);
 #ifdef QLA_64BIT_PTR
@@ -698,7 +700,7 @@
 }
 
 /**************************************************************************
- *   qla1200_queuecommand
+ *   qla1280_queuecommand
  *     Queue a command to the controller.
  *
  * Note:
@@ -713,12 +715,14 @@
 {
 	struct Scsi_Host *host = cmd->device->host;
 	struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
-	struct srb *sp = (struct srb *)&cmd->SCp;
+	struct srb *sp = (struct srb *)CMD_SP(cmd);
 	int status;
 
 	cmd->scsi_done = fn;
 	sp->cmd = cmd;
 	sp->flags = 0;
+	sp->wait = NULL;
+	CMD_HANDLE(cmd) = (unsigned char *)NULL;
 
 	qla1280_print_scsi_cmd(5, cmd);
 
@@ -738,21 +742,11 @@
 
 enum action {
 	ABORT_COMMAND,
-	ABORT_DEVICE,
 	DEVICE_RESET,
 	BUS_RESET,
 	ADAPTER_RESET,
-	FAIL
 };
 
-/* timer action for error action processor */
-static void qla1280_error_wait_timeout(unsigned long __data)
-{
-	struct scsi_cmnd *cmd = (struct scsi_cmnd *)__data;
-	struct srb *sp = (struct srb *)CMD_SP(cmd);
-
-	complete(sp->wait);
-}
 
 static void qla1280_mailbox_timeout(unsigned long __data)
 {
@@ -767,8 +761,67 @@
 	complete(ha->mailbox_wait);
 }
 
+static int
+_qla1280_wait_for_single_command(struct scsi_qla_host *ha, struct srb *sp,
+				 struct completion *wait)
+{
+	int	status = FAILED;
+	struct scsi_cmnd *cmd = sp->cmd;
+
+	spin_unlock_irq(ha->host->host_lock);
+	wait_for_completion_timeout(wait, 4*HZ);
+	spin_lock_irq(ha->host->host_lock);
+	sp->wait = NULL;
+	if(CMD_HANDLE(cmd) == COMPLETED_HANDLE) {
+		status = SUCCESS;
+		(*cmd->scsi_done)(cmd);
+	}
+	return status;
+}
+
+static int
+qla1280_wait_for_single_command(struct scsi_qla_host *ha, struct srb *sp)
+{
+	DECLARE_COMPLETION_ONSTACK(wait);
+
+	sp->wait = &wait;
+	return _qla1280_wait_for_single_command(ha, sp, &wait);
+}
+
+static int
+qla1280_wait_for_pending_commands(struct scsi_qla_host *ha, int bus, int target)
+{
+	int		cnt;
+	int		status;
+	struct srb	*sp;
+	struct scsi_cmnd *cmd;
+
+	status = SUCCESS;
+
+	/*
+	 * Wait for all commands with the designated bus/target
+	 * to be completed by the firmware
+	 */
+	for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+		sp = ha->outstanding_cmds[cnt];
+		if (sp) {
+			cmd = sp->cmd;
+
+			if (bus >= 0 && SCSI_BUS_32(cmd) != bus)
+				continue;
+			if (target >= 0 && SCSI_TCN_32(cmd) != target)
+				continue;
+
+			status = qla1280_wait_for_single_command(ha, sp);
+			if (status == FAILED)
+				break;
+		}
+	}
+	return status;
+}
+
 /**************************************************************************
- * qla1200_error_action
+ * qla1280_error_action
  *    The function will attempt to perform a specified error action and
  *    wait for the results (or time out).
  *
@@ -780,11 +833,6 @@
  * Returns:
  *      SUCCESS or FAILED
  *
- * Note:
- *      Resetting the bus always succeeds - is has to, otherwise the
- *      kernel will panic! Try a surgical technique - sending a BUS
- *      DEVICE RESET message - on the offending target before pulling
- *      the SCSI bus reset line.
  **************************************************************************/
 static int
 qla1280_error_action(struct scsi_cmnd *cmd, enum action action)
@@ -792,13 +840,19 @@
 	struct scsi_qla_host *ha;
 	int bus, target, lun;
 	struct srb *sp;
-	uint16_t data;
-	unsigned char *handle;
-	int result, i;
+	int i, found;
+	int result=FAILED;
+	int wait_for_bus=-1;
+	int wait_for_target = -1;
 	DECLARE_COMPLETION_ONSTACK(wait);
-	struct timer_list timer;
+
+	ENTER("qla1280_error_action");
 
 	ha = (struct scsi_qla_host *)(CMD_HOST(cmd)->hostdata);
+	sp = (struct srb *)CMD_SP(cmd);
+	bus = SCSI_BUS_32(cmd);
+	target = SCSI_TCN_32(cmd);
+	lun = SCSI_LUN_32(cmd);
 
 	dprintk(4, "error_action %i, istatus 0x%04x\n", action,
 		RD_REG_WORD(&ha->iobase->istatus));
@@ -807,99 +861,47 @@
 		RD_REG_WORD(&ha->iobase->host_cmd),
 		RD_REG_WORD(&ha->iobase->ictrl), jiffies);
 
-	ENTER("qla1280_error_action");
 	if (qla1280_verbose)
 		printk(KERN_INFO "scsi(%li): Resetting Cmnd=0x%p, "
 		       "Handle=0x%p, action=0x%x\n",
 		       ha->host_no, cmd, CMD_HANDLE(cmd), action);
 
-	if (cmd == NULL) {
-		printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL "
-		       "si_Cmnd pointer, failing.\n");
-		LEAVE("qla1280_error_action");
-		return FAILED;
-	}
-
-	ha = (struct scsi_qla_host *)cmd->device->host->hostdata;
-	sp = (struct srb *)CMD_SP(cmd);
-	handle = CMD_HANDLE(cmd);
-
-	/* Check for pending interrupts. */
-	data = qla1280_debounce_register(&ha->iobase->istatus);
 	/*
-	 * The io_request_lock is held when the reset handler is called, hence
-	 * the interrupt handler cannot be running in parallel as it also
-	 * grabs the lock. /Jes
+	 * Check to see if we have the command in the outstanding_cmds[]
+	 * array.  If not then it must have completed before this error
+	 * action was initiated.  If the error_action isn't ABORT_COMMAND
+	 * then the driver must proceed with the requested action.
 	 */
-	if (data & RISC_INT)
-		qla1280_isr(ha, &ha->done_q);
-
-	/*
-	 * Determine the suggested action that the mid-level driver wants
-	 * us to perform.
-	 */
-	if (handle == (unsigned char *)INVALID_HANDLE || handle == NULL) {
-		if(action == ABORT_COMMAND) {
-			/* we never got this command */
-			printk(KERN_INFO "qla1280: Aborting a NULL handle\n");
-			return SUCCESS;	/* no action - we don't have command */
-		}
-	} else {
-		sp->wait = &wait;
-	}
-
-	bus = SCSI_BUS_32(cmd);
-	target = SCSI_TCN_32(cmd);
-	lun = SCSI_LUN_32(cmd);
-
-	/* Overloading result.  Here it means the success or fail of the
-	 * *issue* of the action.  When we return from the routine, it must
-	 * mean the actual success or fail of the action */
-	result = FAILED;
-	switch (action) {
-	case FAIL:
-		break;
-
-	case ABORT_COMMAND:
-		if ((sp->flags & SRB_ABORT_PENDING)) {
-			printk(KERN_WARNING
-			       "scsi(): Command has a pending abort "
-			       "message - ABORT_PENDING.\n");
-			/* This should technically be impossible since we
-			 * now wait for abort completion */
+	found = -1;
+	for (i = 0; i < MAX_OUTSTANDING_COMMANDS; i++) {
+		if (sp == ha->outstanding_cmds[i]) {
+			found = i;
+			sp->wait = &wait; /* we'll wait for it to complete */
 			break;
 		}
+	}
 
-		for (i = 0; i < MAX_OUTSTANDING_COMMANDS; i++) {
-			if (sp == ha->outstanding_cmds[i]) {
-				dprintk(1, "qla1280: RISC aborting command\n");
-				if (qla1280_abort_command(ha, sp, i) == 0)
-					result = SUCCESS;
-				else {
-					/*
-					 * Since we don't know what might
-					 * have happend to the command, it
-					 * is unsafe to remove it from the
-					 * device's queue at this point.
-					 * Wait and let the escalation
-					 * process take care of it.
-					 */
-					printk(KERN_WARNING
-					       "scsi(%li:%i:%i:%i): Unable"
-					       " to abort command!\n",
-					       ha->host_no, bus, target, lun);
-				}
-			}
-		}
-		break;
-
-	case ABORT_DEVICE:
-		if (qla1280_verbose)
+	if (found < 0) {	/* driver doesn't have command */
+		result = SUCCESS;
+		if (qla1280_verbose) {
 			printk(KERN_INFO
-			       "scsi(%ld:%d:%d:%d): Queueing abort device "
-			       "command.\n", ha->host_no, bus, target, lun);
-		if (qla1280_abort_device(ha, bus, target, lun) == 0)
-			result = SUCCESS;
+			       "scsi(%ld:%d:%d:%d): specified command has "
+			       "already completed.\n", ha->host_no, bus,
+				target, lun);
+		}
+	}
+
+	switch (action) {
+
+	case ABORT_COMMAND:
+		dprintk(1, "qla1280: RISC aborting command\n");
+		/*
+		 * The abort might fail due to race when the host_lock
+		 * is released to issue the abort.  As such, we
+		 * don't bother to check the return status.
+		 */
+		if (found >= 0)
+			qla1280_abort_command(ha, sp, found);
 		break;
 
 	case DEVICE_RESET:
@@ -907,16 +909,21 @@
 			printk(KERN_INFO
 			       "scsi(%ld:%d:%d:%d): Queueing device reset "
 			       "command.\n", ha->host_no, bus, target, lun);
-		if (qla1280_device_reset(ha, bus, target) == 0)
-			result = SUCCESS;
+		if (qla1280_device_reset(ha, bus, target) == 0) {
+			/* issued device reset, set wait conditions */
+			wait_for_bus = bus;
+			wait_for_target = target;
+		}
 		break;
 
 	case BUS_RESET:
 		if (qla1280_verbose)
 			printk(KERN_INFO "qla1280(%ld:%d): Issued bus "
 			       "reset.\n", ha->host_no, bus);
-		if (qla1280_bus_reset(ha, bus) == 0)
-			result = SUCCESS;
+		if (qla1280_bus_reset(ha, bus) == 0) {
+			/* issued bus reset, set wait conditions */
+			wait_for_bus = bus;
+		}
 		break;
 
 	case ADAPTER_RESET:
@@ -929,55 +936,48 @@
 			       "continue automatically\n", ha->host_no);
 		}
 		ha->flags.reset_active = 1;
-		/*
-		 * We restarted all of the commands automatically, so the
-		 * mid-level code can expect completions momentitarily.
-		 */
-		if (qla1280_abort_isp(ha) == 0)
-			result = SUCCESS;
+
+		if (qla1280_abort_isp(ha) != 0) {	/* it's dead */
+			result = FAILED;
+		}
 
 		ha->flags.reset_active = 0;
 	}
 
-	if (!list_empty(&ha->done_q))
-		qla1280_done(ha);
+	/*
+	 * At this point, the host_lock has been released and retaken
+	 * by the issuance of the mailbox command.
+	 * Wait for the command passed in by the mid-layer if it
+	 * was found by the driver.  It might have been returned
+	 * between eh recovery steps, hence the check of the "found"
+	 * variable.
+	 */
 
-	/* If we didn't manage to issue the action, or we have no
-	 * command to wait for, exit here */
-	if (result == FAILED || handle == NULL ||
-	    handle == (unsigned char *)INVALID_HANDLE) {
-		/*
-		 * Clear completion queue to avoid qla1280_done() trying
-		 * to complete the command at a later stage after we
-		 * have exited the current context
-		 */
-		sp->wait = NULL;
-		goto leave;
+	if (found >= 0)
+		result = _qla1280_wait_for_single_command(ha, sp, &wait);
+
+	if (action == ABORT_COMMAND && result != SUCCESS) {
+		printk(KERN_WARNING
+		       "scsi(%li:%i:%i:%i): "
+		       "Unable to abort command!\n",
+		       ha->host_no, bus, target, lun);
 	}
 
-	/* set up a timer just in case we're really jammed */
-	init_timer(&timer);
-	timer.expires = jiffies + 4*HZ;
-	timer.data = (unsigned long)cmd;
-	timer.function = qla1280_error_wait_timeout;
-	add_timer(&timer);
-
-	/* wait for the action to complete (or the timer to expire) */
-	spin_unlock_irq(ha->host->host_lock);
-	wait_for_completion(&wait);
-	del_timer_sync(&timer);
-	spin_lock_irq(ha->host->host_lock);
-	sp->wait = NULL;
-
-	/* the only action we might get a fail for is abort */
-	if (action == ABORT_COMMAND) {
-		if(sp->flags & SRB_ABORTED)
-			result = SUCCESS;
-		else
-			result = FAILED;
+	/*
+	 * If the command passed in by the mid-layer has been
+	 * returned by the board, then wait for any additional
+	 * commands which are supposed to complete based upon
+	 * the error action.
+	 *
+	 * All commands are unconditionally returned during a
+	 * call to qla1280_abort_isp(), ADAPTER_RESET.  No need
+	 * to wait for them.
+	 */
+	if (result == SUCCESS && wait_for_bus >= 0) {
+		result = qla1280_wait_for_pending_commands(ha,
+					wait_for_bus, wait_for_target);
 	}
 
- leave:
 	dprintk(1, "RESET returning %d\n", result);
 
 	LEAVE("qla1280_error_action");
@@ -1280,13 +1280,12 @@
 		switch ((CMD_RESULT(cmd) >> 16)) {
 		case DID_RESET:
 			/* Issue marker command. */
-			qla1280_marker(ha, bus, target, 0, MK_SYNC_ID);
+			if (!ha->flags.abort_isp_active)
+				qla1280_marker(ha, bus, target, 0, MK_SYNC_ID);
 			break;
 		case DID_ABORT:
 			sp->flags &= ~SRB_ABORT_PENDING;
 			sp->flags |= SRB_ABORTED;
-			if (sp->flags & SRB_TIMEOUT)
-				CMD_RESULT(sp->cmd) = DID_TIME_OUT << 16;
 			break;
 		default:
 			break;
@@ -1296,12 +1295,11 @@
 		scsi_dma_unmap(cmd);
 
 		/* Call the mid-level driver interrupt handler */
-		CMD_HANDLE(sp->cmd) = (unsigned char *)INVALID_HANDLE;
 		ha->actthreads--;
 
-		(*(cmd)->scsi_done)(cmd);
-
-		if(sp->wait != NULL)
+		if (sp->wait == NULL)
+			(*(cmd)->scsi_done)(cmd);
+		else
 			complete(sp->wait);
 	}
 	LEAVE("qla1280_done");
@@ -2417,9 +2415,6 @@
 qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb)
 {
 	struct device_reg __iomem *reg = ha->iobase;
-#if 0
-	LIST_HEAD(done_q);
-#endif
 	int status = 0;
 	int cnt;
 	uint16_t *optr, *iptr;
@@ -2493,19 +2488,9 @@
 	mr = MAILBOX_REGISTER_COUNT;
 	memcpy(optr, iptr, MAILBOX_REGISTER_COUNT * sizeof(uint16_t));
 
-#if 0
-	/* Go check for any response interrupts pending. */
-	qla1280_isr(ha, &done_q);
-#endif
-
 	if (ha->flags.reset_marker)
 		qla1280_rst_aen(ha);
 
-#if 0
-	if (!list_empty(&done_q))
-		qla1280_done(ha, &done_q);
-#endif
-
 	if (status)
 		dprintk(2, "qla1280_mailbox_command: **** FAILED, mailbox0 = "
 			"0x%x ****\n", mb[0]);
@@ -2641,41 +2626,6 @@
 }
 
 /*
- * qla1280_abort_device
- *      Issue an abort message to the device
- *
- * Input:
- *      ha     = adapter block pointer.
- *      bus    = SCSI BUS.
- *      target = SCSI ID.
- *      lun    = SCSI LUN.
- *
- * Returns:
- *      0 = success
- */
-static int
-qla1280_abort_device(struct scsi_qla_host *ha, int bus, int target, int lun)
-{
-	uint16_t mb[MAILBOX_REGISTER_COUNT];
-	int status;
-
-	ENTER("qla1280_abort_device");
-
-	mb[0] = MBC_ABORT_DEVICE;
-	mb[1] = (bus ? target | BIT_7 : target) << 8 | lun;
-	status = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
-
-	/* Issue marker command. */
-	qla1280_marker(ha, bus, target, lun, MK_SYNC_ID_LUN);
-
-	if (status)
-		dprintk(2, "qla1280_abort_device: **** FAILED ****\n");
-
-	LEAVE("qla1280_abort_device");
-	return status;
-}
-
-/*
  * qla1280_abort_command
  *      Abort command aborts a specified IOCB.
  *
@@ -2833,7 +2783,7 @@
 
 	/* If room for request in request ring. */
 	if ((req_cnt + 2) >= ha->req_q_cnt) {
-		status = 1;
+		status = SCSI_MLQUEUE_HOST_BUSY;
 		dprintk(2, "qla1280_start_scsi: in-ptr=0x%x  req_q_cnt="
 			"0x%xreq_cnt=0x%x", ha->req_ring_index, ha->req_q_cnt,
 			req_cnt);
@@ -2845,7 +2795,7 @@
 		     ha->outstanding_cmds[cnt] != NULL; cnt++);
 
 	if (cnt >= MAX_OUTSTANDING_COMMANDS) {
-		status = 1;
+		status = SCSI_MLQUEUE_HOST_BUSY;
 		dprintk(2, "qla1280_start_scsi: NO ROOM IN "
 			"OUTSTANDING ARRAY, req_q_cnt=0x%x", ha->req_q_cnt);
 		goto out;
@@ -3108,7 +3058,7 @@
 		ha->req_q_cnt, seg_cnt);
 	/* If room for request in request ring. */
 	if ((req_cnt + 2) >= ha->req_q_cnt) {
-		status = 1;
+		status = SCSI_MLQUEUE_HOST_BUSY;
 		dprintk(2, "qla1280_32bit_start_scsi: in-ptr=0x%x, "
 			"req_q_cnt=0x%x, req_cnt=0x%x", ha->req_ring_index,
 			ha->req_q_cnt, req_cnt);
@@ -3120,7 +3070,7 @@
 		     (ha->outstanding_cmds[cnt] != 0); cnt++) ;
 
 	if (cnt >= MAX_OUTSTANDING_COMMANDS) {
-		status = 1;
+		status = SCSI_MLQUEUE_HOST_BUSY;
 		dprintk(2, "qla1280_32bit_start_scsi: NO ROOM IN OUTSTANDING "
 			"ARRAY, req_q_cnt=0x%x\n", ha->req_q_cnt);
 		goto out;
@@ -3487,6 +3437,7 @@
 
 					/* Save ISP completion status */
 					CMD_RESULT(sp->cmd) = 0;
+					CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE;
 
 					/* Place block on done queue */
 					list_add_tail(&sp->list, done_q);
@@ -3495,7 +3446,7 @@
 					 * If we get here we have a real problem!
 					 */
 					printk(KERN_WARNING
-					       "qla1280: ISP invalid handle");
+					       "qla1280: ISP invalid handle\n");
 				}
 			}
 			break;
@@ -3753,6 +3704,8 @@
 		}
 	}
 
+	CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE;
+
 	/* Place command on done queue. */
 	list_add_tail(&sp->list, done_q);
  out:
@@ -3808,6 +3761,8 @@
 			CMD_RESULT(sp->cmd) = DID_ERROR << 16;
 		}
 
+		CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE;
+
 		/* Place command on done queue. */
 		list_add_tail(&sp->list, done_q);
 	}
@@ -3858,19 +3813,16 @@
 		struct scsi_cmnd *cmd;
 		sp = ha->outstanding_cmds[cnt];
 		if (sp) {
-
 			cmd = sp->cmd;
 			CMD_RESULT(cmd) = DID_RESET << 16;
-
-			sp->cmd = NULL;
+			CMD_HANDLE(cmd) = COMPLETED_HANDLE;
 			ha->outstanding_cmds[cnt] = NULL;
-
-			(*cmd->scsi_done)(cmd);
-
-			sp->flags = 0;
+			list_add_tail(&sp->list, &ha->done_q);
 		}
 	}
 
+	qla1280_done(ha);
+
 	status = qla1280_load_firmware(ha);
 	if (status)
 		goto out;
@@ -3955,13 +3907,6 @@
 
 		if (scsi_control == SCSI_PHASE_INVALID) {
 			ha->bus_settings[bus].scsi_bus_dead = 1;
-#if 0
-			CMD_RESULT(cp) = DID_NO_CONNECT << 16;
-			CMD_HANDLE(cp) = INVALID_HANDLE;
-			/* ha->actthreads--; */
-
-			(*(cp)->scsi_done)(cp);
-#endif
 			return 1;	/* bus is dead */
 		} else {
 			ha->bus_settings[bus].scsi_bus_dead = 0;
diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h
index d7c44b8..834884b 100644
--- a/drivers/scsi/qla1280.h
+++ b/drivers/scsi/qla1280.h
@@ -88,7 +88,8 @@
 
 /* Maximum outstanding commands in ISP queues */
 #define MAX_OUTSTANDING_COMMANDS	512
-#define INVALID_HANDLE			(MAX_OUTSTANDING_COMMANDS + 2)
+#define COMPLETED_HANDLE		((unsigned char *) \
+					(MAX_OUTSTANDING_COMMANDS + 2))
 
 /* ISP request and response entry counts (37-65535) */
 #define REQUEST_ENTRY_CNT		255 /* Number of request entries. */
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index b09993a..0f87962 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -97,7 +97,7 @@
 		return 0;
 
 	if (IS_NOCACHE_VPD_TYPE(ha))
-		ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_nvram << 2,
+		ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2,
 		    ha->nvram_size);
 	return memory_read_from_buffer(buf, count, &off, ha->nvram,
 					ha->nvram_size);
@@ -692,6 +692,109 @@
 	.read = qla2x00_sysfs_read_edc_status,
 };
 
+static ssize_t
+qla2x00_sysfs_read_xgmac_stats(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;
+	int rval;
+	uint16_t actual_size;
+
+	if (!capable(CAP_SYS_ADMIN) || off != 0 || count > XGMAC_DATA_SIZE)
+		return 0;
+
+	if (ha->xgmac_data)
+		goto do_read;
+
+	ha->xgmac_data = dma_alloc_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE,
+	    &ha->xgmac_data_dma, GFP_KERNEL);
+	if (!ha->xgmac_data) {
+		qla_printk(KERN_WARNING, ha,
+		    "Unable to allocate memory for XGMAC read-data.\n");
+		return 0;
+	}
+
+do_read:
+	actual_size = 0;
+	memset(ha->xgmac_data, 0, XGMAC_DATA_SIZE);
+
+	rval = qla2x00_get_xgmac_stats(vha, ha->xgmac_data_dma,
+	    XGMAC_DATA_SIZE, &actual_size);
+	if (rval != QLA_SUCCESS) {
+		qla_printk(KERN_WARNING, ha,
+		    "Unable to read XGMAC data (%x).\n", rval);
+		count = 0;
+	}
+
+	count = actual_size > count ? count: actual_size;
+	memcpy(buf, ha->xgmac_data, count);
+
+	return count;
+}
+
+static struct bin_attribute sysfs_xgmac_stats_attr = {
+	.attr = {
+		.name = "xgmac_stats",
+		.mode = S_IRUSR,
+	},
+	.size = 0,
+	.read = qla2x00_sysfs_read_xgmac_stats,
+};
+
+static ssize_t
+qla2x00_sysfs_read_dcbx_tlv(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;
+	int rval;
+	uint16_t actual_size;
+
+	if (!capable(CAP_SYS_ADMIN) || off != 0 || count > DCBX_TLV_DATA_SIZE)
+		return 0;
+
+	if (ha->dcbx_tlv)
+		goto do_read;
+
+	ha->dcbx_tlv = dma_alloc_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
+	    &ha->dcbx_tlv_dma, GFP_KERNEL);
+	if (!ha->dcbx_tlv) {
+		qla_printk(KERN_WARNING, ha,
+		    "Unable to allocate memory for DCBX TLV read-data.\n");
+		return 0;
+	}
+
+do_read:
+	actual_size = 0;
+	memset(ha->dcbx_tlv, 0, DCBX_TLV_DATA_SIZE);
+
+	rval = qla2x00_get_dcbx_params(vha, ha->dcbx_tlv_dma,
+	    DCBX_TLV_DATA_SIZE);
+	if (rval != QLA_SUCCESS) {
+		qla_printk(KERN_WARNING, ha,
+		    "Unable to read DCBX TLV data (%x).\n", rval);
+		count = 0;
+	}
+
+	memcpy(buf, ha->dcbx_tlv, count);
+
+	return count;
+}
+
+static struct bin_attribute sysfs_dcbx_tlv_attr = {
+	.attr = {
+		.name = "dcbx_tlv",
+		.mode = S_IRUSR,
+	},
+	.size = 0,
+	.read = qla2x00_sysfs_read_dcbx_tlv,
+};
+
 static struct sysfs_entry {
 	char *name;
 	struct bin_attribute *attr;
@@ -706,6 +809,8 @@
 	{ "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 },
 };
 
@@ -721,6 +826,8 @@
 			continue;
 		if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw))
 			continue;
+		if (iter->is4GBp_only == 3 && !IS_QLA81XX(vha->hw))
+			continue;
 
 		ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
 		    iter->attr);
@@ -743,6 +850,8 @@
 			continue;
 		if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha))
 			continue;
+		if (iter->is4GBp_only == 3 && !IS_QLA81XX(ha))
+			continue;
 
 		sysfs_remove_bin_file(&host->shost_gendev.kobj,
 		    iter->attr);
@@ -1088,6 +1197,58 @@
 	return snprintf(buf, PAGE_SIZE, "0x%x\n", ha->fdt_block_size);
 }
 
+static ssize_t
+qla2x00_vlan_id_show(struct device *dev, struct device_attribute *attr,
+    char *buf)
+{
+	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
+	if (!IS_QLA81XX(vha->hw))
+		return snprintf(buf, PAGE_SIZE, "\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", vha->fcoe_vlan_id);
+}
+
+static ssize_t
+qla2x00_vn_port_mac_address_show(struct device *dev,
+    struct device_attribute *attr, char *buf)
+{
+	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
+	if (!IS_QLA81XX(vha->hw))
+		return snprintf(buf, PAGE_SIZE, "\n");
+
+	return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+	    vha->fcoe_vn_port_mac[5], vha->fcoe_vn_port_mac[4],
+	    vha->fcoe_vn_port_mac[3], vha->fcoe_vn_port_mac[2],
+	    vha->fcoe_vn_port_mac[1], vha->fcoe_vn_port_mac[0]);
+}
+
+static ssize_t
+qla2x00_fabric_param_show(struct device *dev, struct device_attribute *attr,
+    char *buf)
+{
+	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", vha->hw->switch_cap);
+}
+
+static ssize_t
+qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr,
+    char *buf)
+{
+	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+	int rval;
+	uint16_t state[5];
+
+	rval = qla2x00_get_firmware_state(vha, state);
+	if (rval != QLA_SUCCESS)
+		memset(state, -1, sizeof(state));
+
+	return snprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x 0x%x 0x%x\n", state[0],
+	    state[1], state[2], state[3], state[4]);
+}
+
 static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
 static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
 static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
@@ -1116,6 +1277,11 @@
 static DEVICE_ATTR(phy_version, S_IRUGO, qla2x00_phy_version_show, NULL);
 static DEVICE_ATTR(flash_block_size, S_IRUGO, qla2x00_flash_block_size_show,
 		   NULL);
+static DEVICE_ATTR(vlan_id, S_IRUGO, qla2x00_vlan_id_show, NULL);
+static DEVICE_ATTR(vn_port_mac_address, S_IRUGO,
+		   qla2x00_vn_port_mac_address_show, NULL);
+static DEVICE_ATTR(fabric_param, S_IRUGO, qla2x00_fabric_param_show, NULL);
+static DEVICE_ATTR(fw_state, S_IRUGO, qla2x00_fw_state_show, NULL);
 
 struct device_attribute *qla2x00_host_attrs[] = {
 	&dev_attr_driver_version,
@@ -1138,6 +1304,10 @@
 	&dev_attr_mpi_version,
 	&dev_attr_phy_version,
 	&dev_attr_flash_block_size,
+	&dev_attr_vlan_id,
+	&dev_attr_vn_port_mac_address,
+	&dev_attr_fabric_param,
+	&dev_attr_fw_state,
 	NULL,
 };
 
@@ -1313,7 +1483,8 @@
 	 * At this point all fcport's software-states are cleared.  Perform any
 	 * final cleanup of firmware resources (PCBs and XCBs).
 	 */
-	if (fcport->loop_id != FC_NO_LOOP_ID)
+	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);
@@ -1437,11 +1608,13 @@
 qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
 {
 	int	ret = 0;
-	int	cnt = 0;
-	uint8_t	qos = QLA_DEFAULT_QUE_QOS;
+	uint8_t	qos = 0;
 	scsi_qla_host_t *base_vha = shost_priv(fc_vport->shost);
 	scsi_qla_host_t *vha = NULL;
 	struct qla_hw_data *ha = base_vha->hw;
+	uint16_t options = 0;
+	int	cnt;
+	struct req_que *req = ha->req_q_map[0];
 
 	ret = qla24xx_vport_create_req_sanity_check(fc_vport);
 	if (ret) {
@@ -1497,23 +1670,39 @@
 
 	qla24xx_vport_disable(fc_vport, disable);
 
-	/* Create a queue pair for the vport */
-	if (ha->mqenable) {
-		if (ha->npiv_info) {
-			for (; cnt < ha->nvram_npiv_size; cnt++) {
-				if (ha->npiv_info[cnt].port_name ==
-					vha->port_name &&
-					ha->npiv_info[cnt].node_name ==
-					vha->node_name) {
-					qos = ha->npiv_info[cnt].q_qos;
-					break;
-				}
-			}
+	if (ql2xmultique_tag) {
+		req = ha->req_q_map[1];
+		goto vport_queue;
+	} else if (ql2xmaxqueues == 1 || !ha->npiv_info)
+		goto vport_queue;
+	/* Create a request queue in QoS mode for the vport */
+	for (cnt = 0; cnt < ha->nvram_npiv_size; cnt++) {
+		if (memcmp(ha->npiv_info[cnt].port_name, vha->port_name, 8) == 0
+			&& memcmp(ha->npiv_info[cnt].node_name, vha->node_name,
+					8) == 0) {
+			qos = ha->npiv_info[cnt].q_qos;
+			break;
 		}
-		qla25xx_create_queues(vha, qos);
+	}
+	if (qos) {
+		ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, 0,
+			qos);
+		if (!ret)
+			qla_printk(KERN_WARNING, ha,
+			"Can't create request queue for vp_idx:%d\n",
+			vha->vp_idx);
+		else {
+			DEBUG2(qla_printk(KERN_INFO, ha,
+			"Request Que:%d (QoS: %d) created for vp_idx:%d\n",
+			ret, qos, vha->vp_idx));
+			req = ha->req_q_map[ret];
+		}
 	}
 
+vport_queue:
+	vha->req = req;
 	return 0;
+
 vport_create_failed_2:
 	qla24xx_disable_vp(vha);
 	qla24xx_deallocate_vp_id(vha);
@@ -1554,8 +1743,8 @@
 		    vha->host_no, vha->vp_idx, vha));
         }
 
-	if (ha->mqenable) {
-		if (qla25xx_delete_queues(vha, 0) != QLA_SUCCESS)
+	if (vha->req->id && !ql2xmultique_tag) {
+		if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS)
 			qla_printk(KERN_WARNING, ha,
 				"Queue delete failed.\n");
 	}
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 34760f8..4a990f4 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -149,11 +149,9 @@
 	int rval = QLA_SUCCESS;
 	uint32_t cnt;
 
-	if (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE)
-		return rval;
-
 	WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
-	for (cnt = 30000; (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
+	for (cnt = 30000;
+	    ((RD_REG_DWORD(&reg->host_status) & HSRX_RISC_PAUSED) == 0) &&
 	    rval == QLA_SUCCESS; cnt--) {
 		if (cnt)
 			udelay(100);
@@ -351,7 +349,7 @@
 qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
 {
 	uint32_t cnt, que_idx;
-	uint8_t req_cnt, rsp_cnt, que_cnt;
+	uint8_t que_cnt;
 	struct qla2xxx_mq_chain *mq = ptr;
 	struct device_reg_25xxmq __iomem *reg;
 
@@ -363,9 +361,8 @@
 	mq->type = __constant_htonl(DUMP_CHAIN_MQ);
 	mq->chain_size = __constant_htonl(sizeof(struct qla2xxx_mq_chain));
 
-	req_cnt = find_first_zero_bit(ha->req_qid_map, ha->max_queues);
-	rsp_cnt = find_first_zero_bit(ha->rsp_qid_map, ha->max_queues);
-	que_cnt = req_cnt > rsp_cnt ? req_cnt : rsp_cnt;
+	que_cnt = ha->max_req_queues > ha->max_rsp_queues ?
+		ha->max_req_queues : ha->max_rsp_queues;
 	mq->count = htonl(que_cnt);
 	for (cnt = 0; cnt < que_cnt; cnt++) {
 		reg = (struct device_reg_25xxmq *) ((void *)
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 714ee67..00aa48d 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -93,6 +93,7 @@
 #define LSD(x)	((uint32_t)((uint64_t)(x)))
 #define MSD(x)	((uint32_t)((((uint64_t)(x)) >> 16) >> 16))
 
+#define MAKE_HANDLE(x, y) ((uint32_t)((((uint32_t)(x)) << 16) | (uint32_t)(y)))
 
 /*
  * I/O register
@@ -179,6 +180,7 @@
 #define REQUEST_ENTRY_CNT_24XX		2048	/* Number of request entries. */
 #define RESPONSE_ENTRY_CNT_2100		64	/* Number of response entries.*/
 #define RESPONSE_ENTRY_CNT_2300		512	/* Number of response entries.*/
+#define RESPONSE_ENTRY_CNT_MQ		128	/* Number of response entries.*/
 
 struct req_que;
 
@@ -186,7 +188,6 @@
  * SCSI Request Block
  */
 typedef struct srb {
-	struct req_que *que;
 	struct fc_port *fcport;
 
 	struct scsi_cmnd *cmd;		/* Linux SCSI command pkt */
@@ -2008,7 +2009,7 @@
 #define VP_RET_CODE_NOT_FOUND		6
 
 struct qla_hw_data;
-
+struct rsp_que;
 /*
  * ISP operations
  */
@@ -2030,10 +2031,9 @@
 	void (*enable_intrs) (struct qla_hw_data *);
 	void (*disable_intrs) (struct qla_hw_data *);
 
-	int (*abort_command) (struct scsi_qla_host *, srb_t *,
-		struct req_que *);
-	int (*target_reset) (struct fc_port *, unsigned int);
-	int (*lun_reset) (struct fc_port *, unsigned int);
+	int (*abort_command) (srb_t *);
+	int (*target_reset) (struct fc_port *, unsigned int, int);
+	int (*lun_reset) (struct fc_port *, unsigned int, int);
 	int (*fabric_login) (struct scsi_qla_host *, uint16_t, uint8_t,
 		uint8_t, uint8_t, uint16_t *, uint8_t);
 	int (*fabric_logout) (struct scsi_qla_host *, uint16_t, uint8_t,
@@ -2079,7 +2079,6 @@
 #define QLA_PCI_MSIX_CONTROL	0xa2
 
 struct scsi_qla_host;
-struct rsp_que;
 
 struct qla_msix_entry {
 	int have_irq;
@@ -2140,7 +2139,6 @@
 #define MBC_INITIALIZE_MULTIQ 0x1f
 #define QLA_QUE_PAGE 0X1000
 #define QLA_MQ_SIZE 32
-#define QLA_MAX_HOST_QUES 16
 #define QLA_MAX_QUEUES 256
 #define ISP_QUE_REG(ha, id) \
 	((ha->mqenable) ? \
@@ -2170,6 +2168,8 @@
 	struct qla_hw_data *hw;
 	struct qla_msix_entry *msix;
 	struct req_que *req;
+	srb_t *status_srb; /* status continuation entry */
+	struct work_struct q_work;
 };
 
 /* Request queue data structure */
@@ -2222,6 +2222,8 @@
 		uint32_t	fce_enabled		:1;
 		uint32_t	fac_supported		:1;
 		uint32_t	chip_reset_done		:1;
+		uint32_t	port0			:1;
+		uint32_t	running_gold_fw		:1;
 	} flags;
 
 	/* This spinlock is used to protect "io transactions", you must
@@ -2246,7 +2248,8 @@
 	struct rsp_que **rsp_q_map;
 	unsigned long req_qid_map[(QLA_MAX_QUEUES / 8) / sizeof(unsigned long)];
 	unsigned long rsp_qid_map[(QLA_MAX_QUEUES / 8) / sizeof(unsigned long)];
-	uint16_t 	max_queues;
+	uint8_t 	max_req_queues;
+	uint8_t 	max_rsp_queues;
 	struct qla_npiv_entry *npiv_info;
 	uint16_t	nvram_npiv_size;
 
@@ -2255,6 +2258,9 @@
 #define FLOGI_MID_SUPPORT       BIT_10
 #define FLOGI_VSAN_SUPPORT      BIT_12
 #define FLOGI_SP_SUPPORT        BIT_13
+
+	uint8_t		port_no;		/* Physical port of adapter */
+
 	/* Timeout timers. */
 	uint8_t 	loop_down_abort_time;    /* port down timer */
 	atomic_t	loop_down_timer;         /* loop down timer */
@@ -2392,6 +2398,14 @@
 	dma_addr_t	edc_data_dma;
 	uint16_t	edc_data_len;
 
+#define XGMAC_DATA_SIZE	PAGE_SIZE
+	void		*xgmac_data;
+	dma_addr_t	xgmac_data_dma;
+
+#define DCBX_TLV_DATA_SIZE PAGE_SIZE
+	void		*dcbx_tlv;
+	dma_addr_t	dcbx_tlv_dma;
+
 	struct task_struct	*dpc_thread;
 	uint8_t dpc_active;                  /* DPC routine is active */
 
@@ -2510,6 +2524,7 @@
 	uint32_t        flt_region_vpd;
 	uint32_t        flt_region_nvram;
 	uint32_t        flt_region_npiv_conf;
+	uint32_t	flt_region_gold_fw;
 
 	/* Needed for BEACON */
 	uint16_t        beacon_blink_led;
@@ -2536,6 +2551,7 @@
 	struct qla_chip_state_84xx *cs84xx;
 	struct qla_statistics qla_stats;
 	struct isp_operations *isp_ops;
+	struct workqueue_struct *wq;
 };
 
 /*
@@ -2545,6 +2561,8 @@
 	struct list_head list;
 	struct list_head vp_fcports;	/* list of fcports */
 	struct list_head work_list;
+	spinlock_t work_lock;
+
 	/* Commonly used flags and state information. */
 	struct Scsi_Host *host;
 	unsigned long	host_no;
@@ -2591,8 +2609,6 @@
 #define SWITCH_FOUND		BIT_0
 #define DFLG_NO_CABLE		BIT_1
 
-	srb_t		*status_srb;	/* Status continuation entry. */
-
 	/* ISP configuration data. */
 	uint16_t	loop_id;		/* Host adapter loop id */
 
@@ -2618,6 +2634,11 @@
 	uint8_t		node_name[WWN_SIZE];
 	uint8_t		port_name[WWN_SIZE];
 	uint8_t		fabric_node_name[WWN_SIZE];
+
+	uint16_t	fcoe_vlan_id;
+	uint16_t	fcoe_fcf_idx;
+	uint8_t		fcoe_vn_port_mac[6];
+
 	uint32_t   	vp_abort_cnt;
 
 	struct fc_vport	*fc_vport;	/* holds fc_vport * for each vport */
@@ -2643,7 +2664,7 @@
 #define VP_ERR_FAB_LOGOUT	4
 #define VP_ERR_ADAP_NORESOURCES	5
 	struct qla_hw_data *hw;
-	int	req_ques[QLA_MAX_HOST_QUES];
+	struct req_que *req;
 } scsi_qla_host_t;
 
 /*
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 96ccb96..dfde2dd 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -878,7 +878,6 @@
 					/* HCCR statuses. */
 #define HCCRX_HOST_INT		BIT_6	/* Host to RISC interrupt bit. */
 #define HCCRX_RISC_RESET	BIT_5	/* RISC Reset mode bit. */
-#define HCCRX_RISC_PAUSE	BIT_4	/* RISC Pause mode bit. */
 					/* HCCR commands. */
 					/* NOOP. */
 #define HCCRX_NOOP		0x00000000
@@ -1241,6 +1240,7 @@
 #define FLT_REG_HW_EVENT_1	0x1f
 #define FLT_REG_NPIV_CONF_0	0x29
 #define FLT_REG_NPIV_CONF_1	0x2a
+#define FLT_REG_GOLD_FW		0x2f
 
 struct qla_flt_region {
 	uint32_t code;
@@ -1405,6 +1405,8 @@
 #define MBC_IDC_ACK		0x101
 #define MBC_RESTART_MPI_FW	0x3d
 #define MBC_FLASH_ACCESS_CTRL	0x3e	/* Control flash access. */
+#define MBC_GET_XGMAC_STATS	0x7a
+#define MBC_GET_DCBX_PARAMS	0x51
 
 /* Flash access control option field bit definitions */
 #define FAC_OPT_FORCE_SEMAPHORE		BIT_15
@@ -1711,7 +1713,7 @@
 #define FA_VPD0_ADDR_81		0xD0000
 #define FA_VPD1_ADDR_81		0xD0400
 #define FA_NVRAM0_ADDR_81	0xD0080
-#define FA_NVRAM1_ADDR_81	0xD0480
+#define FA_NVRAM1_ADDR_81	0xD0180
 #define FA_FEATURE_ADDR_81	0xD4000
 #define FA_FLASH_DESCR_ADDR_81	0xD8000
 #define FA_FLASH_LAYOUT_ADDR_81	0xD8400
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 528913f..65b12d8 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -65,8 +65,11 @@
 extern int ql2xallocfwdump;
 extern int ql2xextended_error_logging;
 extern int ql2xqfullrampup;
+extern int ql2xqfulltracking;
 extern int ql2xiidmaenable;
 extern int ql2xmaxqueues;
+extern int ql2xmultique_tag;
+extern int ql2xfwloadbin;
 
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -145,7 +148,7 @@
 extern int
 qla2x00_execute_fw(scsi_qla_host_t *, uint32_t);
 
-extern void
+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 *);
 
@@ -165,13 +168,13 @@
 qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t);
 
 extern int
-qla2x00_abort_command(scsi_qla_host_t *, srb_t *, struct req_que *);
+qla2x00_abort_command(srb_t *);
 
 extern int
-qla2x00_abort_target(struct fc_port *, unsigned int);
+qla2x00_abort_target(struct fc_port *, unsigned int, int);
 
 extern int
-qla2x00_lun_reset(struct fc_port *, unsigned int);
+qla2x00_lun_reset(struct fc_port *, unsigned int, int);
 
 extern int
 qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *,
@@ -236,9 +239,11 @@
 qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *,
     dma_addr_t);
 
-extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *, struct req_que *);
-extern int qla24xx_abort_target(struct fc_port *, unsigned int);
-extern int qla24xx_lun_reset(struct fc_port *, unsigned int);
+extern int qla24xx_abort_command(srb_t *);
+extern int
+qla24xx_abort_target(struct fc_port *, unsigned int, int);
+extern int
+qla24xx_lun_reset(struct fc_port *, unsigned int, int);
 
 extern int
 qla2x00_system_error(scsi_qla_host_t *);
@@ -288,6 +293,18 @@
 extern int
 qla81xx_fac_erase_sector(scsi_qla_host_t *, uint32_t, uint32_t);
 
+extern int
+qla2x00_get_xgmac_stats(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t *);
+
+extern int
+qla2x00_get_dcbx_params(scsi_qla_host_t *, dma_addr_t, uint16_t);
+
+extern int
+qla2x00_read_ram_word(scsi_qla_host_t *, uint32_t, uint32_t *);
+
+extern int
+qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t);
+
 /*
  * Global Function Prototypes in qla_isr.c source file.
  */
@@ -295,8 +312,8 @@
 extern irqreturn_t qla2300_intr_handler(int, void *);
 extern irqreturn_t qla24xx_intr_handler(int, void *);
 extern void qla2x00_process_response_queue(struct rsp_que *);
-extern void qla24xx_process_response_queue(struct rsp_que *);
-
+extern void
+qla24xx_process_response_queue(struct scsi_qla_host *, struct rsp_que *);
 extern int qla2x00_request_irqs(struct qla_hw_data *, struct rsp_que *);
 extern void qla2x00_free_irqs(scsi_qla_host_t *);
 
@@ -401,19 +418,21 @@
 extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *);
 extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *);
 extern int qla25xx_create_req_que(struct qla_hw_data *, uint16_t, uint8_t,
-	uint16_t, uint8_t, uint8_t);
+	uint16_t, int, uint8_t);
 extern int qla25xx_create_rsp_que(struct qla_hw_data *, uint16_t, uint8_t,
-	uint16_t);
+	uint16_t, int);
 extern int qla25xx_update_req_que(struct scsi_qla_host *, uint8_t, uint8_t);
 extern void qla2x00_init_response_q_entries(struct rsp_que *);
 extern int qla25xx_delete_req_que(struct scsi_qla_host *, struct req_que *);
 extern int qla25xx_delete_rsp_que(struct scsi_qla_host *, struct rsp_que *);
 extern int qla25xx_create_queues(struct scsi_qla_host *, uint8_t);
-extern int qla25xx_delete_queues(struct scsi_qla_host *, uint8_t);
+extern int qla25xx_delete_queues(struct scsi_qla_host *);
 extern uint16_t qla24xx_rd_req_reg(struct qla_hw_data *, uint16_t);
 extern uint16_t qla25xx_rd_req_reg(struct qla_hw_data *, uint16_t);
 extern void qla24xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t);
 extern void qla25xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t);
 extern void qla25xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
 extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
+extern struct scsi_qla_host * qla25xx_get_host(struct rsp_que *);
+
 #endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 557f58d..917534b 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -1107,7 +1107,7 @@
 		return ret;
 
 	ha->isp_ops->fabric_login(vha, vha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa,
-	    mb, BIT_1);
+	    mb, BIT_1|BIT_0);
 	if (mb[0] != MBS_COMMAND_COMPLETE) {
 		DEBUG2_13(printk("%s(%ld): Failed MANAGEMENT_SERVER login: "
 		    "loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x\n",
@@ -1879,6 +1879,9 @@
 			case BIT_13:
 				list[i].fp_speed = PORT_SPEED_4GB;
 				break;
+			case BIT_12:
+				list[i].fp_speed = PORT_SPEED_10GB;
+				break;
 			case BIT_11:
 				list[i].fp_speed = PORT_SPEED_8GB;
 				break;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index bd7dd84..2620261 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -634,7 +634,7 @@
 		goto chip_diag_failed;
 
 	DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n",
-	    ha->host_no));
+	    vha->host_no));
 
 	/* Reset RISC processor. */
 	WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
@@ -655,7 +655,7 @@
 		goto chip_diag_failed;
 
 	/* Check product ID of chip */
-	DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", ha->host_no));
+	DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", vha->host_no));
 
 	mb[1] = RD_MAILBOX_REG(ha, reg, 1);
 	mb[2] = RD_MAILBOX_REG(ha, reg, 2);
@@ -730,9 +730,6 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req = ha->req_q_map[0];
 
-	/* Perform RISC reset. */
-	qla24xx_reset_risc(vha);
-
 	ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
 
 	rval = qla2x00_mbx_reg_test(vha);
@@ -786,7 +783,6 @@
 		    sizeof(uint32_t);
 		if (ha->mqenable)
 			mq_size = sizeof(struct qla2xxx_mq_chain);
-
 		/* Allocate memory for Fibre Channel Event Buffer. */
 		if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
 			goto try_eft;
@@ -850,8 +846,7 @@
 	rsp_q_size = rsp->length * sizeof(response_t);
 
 	dump_size = offsetof(struct qla2xxx_fw_dump, isp);
-	dump_size += fixed_size + mem_size + req_q_size + rsp_q_size +
-	    eft_size;
+	dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + eft_size;
 	ha->chain_offset = dump_size;
 	dump_size += mq_size + fce_size;
 
@@ -891,6 +886,56 @@
 	    htonl(offsetof(struct qla2xxx_fw_dump, isp));
 }
 
+static int
+qla81xx_mpi_sync(scsi_qla_host_t *vha)
+{
+#define MPS_MASK	0xe0
+	int rval;
+	uint16_t dc;
+	uint32_t dw;
+	struct qla_hw_data *ha = vha->hw;
+
+	if (!IS_QLA81XX(vha->hw))
+		return QLA_SUCCESS;
+
+	rval = qla2x00_write_ram_word(vha, 0x7c00, 1);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2(qla_printk(KERN_WARNING, ha,
+		    "Sync-MPI: Unable to acquire semaphore.\n"));
+		goto done;
+	}
+
+	pci_read_config_word(vha->hw->pdev, 0x54, &dc);
+	rval = qla2x00_read_ram_word(vha, 0x7a15, &dw);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2(qla_printk(KERN_WARNING, ha,
+		    "Sync-MPI: Unable to read sync.\n"));
+		goto done_release;
+	}
+
+	dc &= MPS_MASK;
+	if (dc == (dw & MPS_MASK))
+		goto done_release;
+
+	dw &= ~MPS_MASK;
+	dw |= dc;
+	rval = qla2x00_write_ram_word(vha, 0x7a15, dw);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2(qla_printk(KERN_WARNING, ha,
+		    "Sync-MPI: Unable to gain sync.\n"));
+	}
+
+done_release:
+	rval = qla2x00_write_ram_word(vha, 0x7c00, 0);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2(qla_printk(KERN_WARNING, ha,
+		    "Sync-MPI: Unable to release semaphore.\n"));
+	}
+
+done:
+	return rval;
+}
+
 /**
  * qla2x00_setup_chip() - Load and start RISC firmware.
  * @ha: HA context
@@ -915,6 +960,8 @@
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 	}
 
+	qla81xx_mpi_sync(vha);
+
 	/* Load firmware sequences */
 	rval = ha->isp_ops->load_risc(vha, &srisc_address);
 	if (rval == QLA_SUCCESS) {
@@ -931,13 +978,16 @@
 			/* Retrieve firmware information. */
 			if (rval == QLA_SUCCESS) {
 				fw_major_version = ha->fw_major_version;
-				qla2x00_get_fw_version(vha,
+				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);
+				if (rval != QLA_SUCCESS)
+					goto failed;
+
 				ha->flags.npiv_supported = 0;
 				if (IS_QLA2XXX_MIDTYPE(ha) &&
 					 (ha->fw_attributes & BIT_2)) {
@@ -989,7 +1039,7 @@
 			    ha->fw_subminor_version);
 		}
 	}
-
+failed:
 	if (rval) {
 		DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n",
 		    vha->host_no));
@@ -1013,12 +1063,14 @@
 	uint16_t cnt;
 	response_t *pkt;
 
+	rsp->ring_ptr = rsp->ring;
+	rsp->ring_index    = 0;
+	rsp->status_srb = NULL;
 	pkt = rsp->ring_ptr;
 	for (cnt = 0; cnt < rsp->length; cnt++) {
 		pkt->signature = RESPONSE_PROCESSED;
 		pkt++;
 	}
-
 }
 
 /**
@@ -1176,7 +1228,7 @@
 		if (ha->flags.msix_enabled) {
 			msix = &ha->msix_entries[1];
 			DEBUG2_17(printk(KERN_INFO
-			"Reistering vector 0x%x for base que\n", msix->entry));
+			"Registering vector 0x%x for base que\n", msix->entry));
 			icb->msix = cpu_to_le16(msix->entry);
 		}
 		/* Use alternate PCI bus number */
@@ -1230,14 +1282,14 @@
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
 	/* Clear outstanding commands array. */
-	for (que = 0; que < ha->max_queues; que++) {
+	for (que = 0; que < ha->max_req_queues; que++) {
 		req = ha->req_q_map[que];
 		if (!req)
 			continue;
-		for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
+		for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
 			req->outstanding_cmds[cnt] = NULL;
 
-		req->current_outstanding_cmd = 0;
+		req->current_outstanding_cmd = 1;
 
 		/* Initialize firmware. */
 		req->ring_ptr  = req->ring;
@@ -1245,13 +1297,10 @@
 		req->cnt      = req->length;
 	}
 
-	for (que = 0; que < ha->max_queues; que++) {
+	for (que = 0; que < ha->max_rsp_queues; que++) {
 		rsp = ha->rsp_q_map[que];
 		if (!rsp)
 			continue;
-		rsp->ring_ptr = rsp->ring;
-		rsp->ring_index    = 0;
-
 		/* Initialize response queue entries */
 		qla2x00_init_response_q_entries(rsp);
 	}
@@ -1307,7 +1356,7 @@
 	unsigned long	wtime, mtime, cs84xx_time;
 	uint16_t	min_wait;	/* Minimum wait time if loop is down */
 	uint16_t	wait_time;	/* Wait time if loop is coming ready */
-	uint16_t	state[3];
+	uint16_t	state[5];
 	struct qla_hw_data *ha = vha->hw;
 
 	rval = QLA_SUCCESS;
@@ -1406,8 +1455,9 @@
 		    vha->host_no, state[0], jiffies));
 	} while (1);
 
-	DEBUG(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
-	    vha->host_no, state[0], jiffies));
+	DEBUG(printk("scsi(%ld): fw_state=%x (%x, %x, %x, %x) curr time=%lx.\n",
+	    vha->host_no, state[0], state[1], state[2], state[3], state[4],
+	    jiffies));
 
 	if (rval) {
 		DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n",
@@ -1541,6 +1591,7 @@
 	char *st, *en;
 	uint16_t index;
 	struct qla_hw_data *ha = vha->hw;
+	int use_tbl = !IS_QLA25XX(ha) && !IS_QLA81XX(ha);
 
 	if (memcmp(model, BINZERO, len) != 0) {
 		strncpy(ha->model_number, model, len);
@@ -1553,14 +1604,16 @@
 		}
 
 		index = (ha->pdev->subsystem_device & 0xff);
-		if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
+		if (use_tbl &&
+		    ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
 		    index < QLA_MODEL_NAMES)
 			strncpy(ha->model_desc,
 			    qla2x00_model_name[index * 2 + 1],
 			    sizeof(ha->model_desc) - 1);
 	} else {
 		index = (ha->pdev->subsystem_device & 0xff);
-		if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
+		if (use_tbl &&
+		    ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
 		    index < QLA_MODEL_NAMES) {
 			strcpy(ha->model_number,
 			    qla2x00_model_name[index * 2]);
@@ -2061,8 +2114,10 @@
 	if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
 		if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
 			set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
-		if (test_bit(RSCN_UPDATE, &save_flags))
+		if (test_bit(RSCN_UPDATE, &save_flags)) {
 			set_bit(RSCN_UPDATE, &vha->dpc_flags);
+			vha->flags.rscn_queue_overflow = 1;
+		}
 	}
 
 	return (rval);
@@ -2110,7 +2165,7 @@
 		goto cleanup_allocation;
 
 	DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n",
-	    ha->host_no, entries));
+	    vha->host_no, entries));
 	DEBUG3(qla2x00_dump_buffer((uint8_t *)ha->gid_list,
 	    entries * sizeof(struct gid_list_info)));
 
@@ -2243,7 +2298,8 @@
 qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
 {
 #define LS_UNKNOWN      2
-	static char *link_speeds[5] = { "1", "2", "?", "4", "8" };
+	static char *link_speeds[] = { "1", "2", "?", "4", "8", "10" };
+	char *link_speed;
 	int rval;
 	uint16_t mb[6];
 	struct qla_hw_data *ha = vha->hw;
@@ -2266,10 +2322,15 @@
 		    fcport->port_name[6], fcport->port_name[7], rval,
 		    fcport->fp_speed, mb[0], mb[1]));
 	} else {
+		link_speed = link_speeds[LS_UNKNOWN];
+		if (fcport->fp_speed < 5)
+			link_speed = link_speeds[fcport->fp_speed];
+		else if (fcport->fp_speed == 0x13)
+			link_speed = link_speeds[5];
 		DEBUG2(qla_printk(KERN_INFO, ha,
 		    "iIDMA adjusted to %s GB/s on "
 		    "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
-		    link_speeds[fcport->fp_speed], fcport->port_name[0],
+		    link_speed, fcport->port_name[0],
 		    fcport->port_name[1], fcport->port_name[2],
 		    fcport->port_name[3], fcport->port_name[4],
 		    fcport->port_name[5], fcport->port_name[6],
@@ -3180,9 +3241,14 @@
 {
 	int rval = QLA_SUCCESS;
 	uint32_t wait_time;
-	struct qla_hw_data *ha = vha->hw;
-	struct req_que *req = ha->req_q_map[vha->req_ques[0]];
-	struct rsp_que *rsp = req->rsp;
+	struct req_que *req;
+	struct rsp_que *rsp;
+
+	if (ql2xmultique_tag)
+		req = vha->hw->req_q_map[0];
+	else
+		req = vha->req;
+	rsp = req->rsp;
 
 	atomic_set(&vha->loop_state, LOOP_UPDATE);
 	clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
@@ -3448,7 +3514,7 @@
 	int ret = -1;
 	int i;
 
-	for (i = 1; i < ha->max_queues; i++) {
+	for (i = 1; i < ha->max_rsp_queues; i++) {
 		rsp = ha->rsp_q_map[i];
 		if (rsp) {
 			rsp->options &= ~BIT_0;
@@ -3462,6 +3528,8 @@
 					"%s Rsp que:%d inited\n", __func__,
 						rsp->id));
 		}
+	}
+	for (i = 1; i < ha->max_req_queues; i++) {
 		req = ha->req_q_map[i];
 		if (req) {
 		/* Clear outstanding commands array. */
@@ -3566,14 +3634,15 @@
 	nv = ha->nvram;
 
 	/* Determine NVRAM starting address. */
-	ha->nvram_size = sizeof(struct nvram_24xx);
-	ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
-	ha->vpd_size = FA_NVRAM_VPD_SIZE;
-	ha->vpd_base = FA_NVRAM_VPD0_ADDR;
-	if (PCI_FUNC(ha->pdev->devfn)) {
+	if (ha->flags.port0) {
+		ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
+		ha->vpd_base = FA_NVRAM_VPD0_ADDR;
+	} else {
 		ha->nvram_base = FA_NVRAM_FUNC1_ADDR;
 		ha->vpd_base = FA_NVRAM_VPD1_ADDR;
 	}
+	ha->nvram_size = sizeof(struct nvram_24xx);
+	ha->vpd_size = FA_NVRAM_VPD_SIZE;
 
 	/* Get VPD data into cache */
 	ha->vpd = ha->nvram + VPD_OFFSET;
@@ -3587,7 +3656,7 @@
 	for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
 		chksum += le32_to_cpu(*dptr++);
 
-	DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
+	DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
 	DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
 
 	/* Bad NVRAM data, set defaults parameters. */
@@ -3612,7 +3681,7 @@
 		nv->exchange_count = __constant_cpu_to_le16(0);
 		nv->hard_address = __constant_cpu_to_le16(124);
 		nv->port_name[0] = 0x21;
-		nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
+		nv->port_name[1] = 0x00 + ha->port_no;
 		nv->port_name[2] = 0x00;
 		nv->port_name[3] = 0xe0;
 		nv->port_name[4] = 0x8b;
@@ -3798,11 +3867,11 @@
 }
 
 static int
-qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr)
+qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
+    uint32_t faddr)
 {
 	int	rval = QLA_SUCCESS;
 	int	segments, fragment;
-	uint32_t faddr;
 	uint32_t *dcode, dlen;
 	uint32_t risc_addr;
 	uint32_t risc_size;
@@ -3811,12 +3880,11 @@
 	struct req_que *req = ha->req_q_map[0];
 
 	qla_printk(KERN_INFO, ha,
-	    "FW: Loading from flash (%x)...\n", ha->flt_region_fw);
+	    "FW: Loading from flash (%x)...\n", faddr);
 
 	rval = QLA_SUCCESS;
 
 	segments = FA_RISC_CODE_SEGMENTS;
-	faddr = ha->flt_region_fw;
 	dcode = (uint32_t *)req->ring;
 	*srisc_addr = 0;
 
@@ -4104,6 +4172,9 @@
 {
 	int rval;
 
+	if (ql2xfwloadbin == 1)
+		return qla81xx_load_risc(vha, srisc_addr);
+
 	/*
 	 * FW Load priority:
 	 * 1) Firmware via request-firmware interface (.bin file).
@@ -4113,24 +4184,45 @@
 	if (rval == QLA_SUCCESS)
 		return rval;
 
-	return qla24xx_load_risc_flash(vha, srisc_addr);
+	return qla24xx_load_risc_flash(vha, srisc_addr,
+	    vha->hw->flt_region_fw);
 }
 
 int
 qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
 {
 	int rval;
+	struct qla_hw_data *ha = vha->hw;
+
+	if (ql2xfwloadbin == 2)
+		goto try_blob_fw;
 
 	/*
 	 * FW Load priority:
 	 * 1) Firmware residing in flash.
 	 * 2) Firmware via request-firmware interface (.bin file).
+	 * 3) Golden-Firmware residing in flash -- limited operation.
 	 */
-	rval = qla24xx_load_risc_flash(vha, srisc_addr);
+	rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_fw);
 	if (rval == QLA_SUCCESS)
 		return rval;
 
-	return qla24xx_load_risc_blob(vha, srisc_addr);
+try_blob_fw:
+	rval = qla24xx_load_risc_blob(vha, srisc_addr);
+	if (rval == QLA_SUCCESS || !ha->flt_region_gold_fw)
+		return rval;
+
+	qla_printk(KERN_ERR, ha,
+	    "FW: Attempting to fallback to golden firmware...\n");
+	rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_gold_fw);
+	if (rval != QLA_SUCCESS)
+		return rval;
+
+	qla_printk(KERN_ERR, ha,
+	    "FW: Please update operational firmware...\n");
+	ha->flags.running_gold_fw = 1;
+
+	return rval;
 }
 
 void
@@ -4146,7 +4238,7 @@
 
 	ret = qla2x00_stop_firmware(vha);
 	for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
-	    retries ; retries--) {
+	    ret != QLA_INVALID_COMMAND && retries ; retries--) {
 		ha->isp_ops->reset_chip(vha);
 		if (ha->isp_ops->chip_diag(vha) != QLA_SUCCESS)
 			continue;
@@ -4165,13 +4257,19 @@
 	uint16_t mb[MAILBOX_REGISTER_COUNT];
 	struct qla_hw_data *ha = vha->hw;
 	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
-	struct req_que *req = ha->req_q_map[vha->req_ques[0]];
-	struct rsp_que *rsp = req->rsp;
+	struct req_que *req;
+	struct rsp_que *rsp;
 
 	if (!vha->vp_idx)
 		return -EINVAL;
 
 	rval = qla2x00_fw_ready(base_vha);
+	if (ql2xmultique_tag)
+		req = ha->req_q_map[0];
+	else
+		req = vha->req;
+	rsp = req->rsp;
+
 	if (rval == QLA_SUCCESS) {
 		clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
 		qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
@@ -4305,7 +4403,7 @@
 	for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
 		chksum += le32_to_cpu(*dptr++);
 
-	DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
+	DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
 	DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
 
 	/* Bad NVRAM data, set defaults parameters. */
@@ -4329,7 +4427,7 @@
 		nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
 		nv->exchange_count = __constant_cpu_to_le16(0);
 		nv->port_name[0] = 0x21;
-		nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
+		nv->port_name[1] = 0x00 + ha->port_no;
 		nv->port_name[2] = 0x00;
 		nv->port_name[3] = 0xe0;
 		nv->port_name[4] = 0x8b;
@@ -4358,12 +4456,12 @@
 		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->enode_mac[0] = 0x01;
+		nv->enode_mac[0] = 0x00;
 		nv->enode_mac[1] = 0x02;
 		nv->enode_mac[2] = 0x03;
 		nv->enode_mac[3] = 0x04;
 		nv->enode_mac[4] = 0x05;
-		nv->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn);
+		nv->enode_mac[5] = 0x06 + ha->port_no;
 
 		rval = 1;
 	}
@@ -4396,7 +4494,7 @@
 		icb->enode_mac[2] = 0x03;
 		icb->enode_mac[3] = 0x04;
 		icb->enode_mac[4] = 0x05;
-		icb->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn);
+		icb->enode_mac[5] = 0x06 + ha->port_no;
 	}
 
 	/* Use extended-initialization control block. */
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index a8abbb9..13396be 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -15,6 +15,7 @@
 							struct rsp_que *rsp);
 static void qla2x00_isp_cmd(struct scsi_qla_host *, struct req_que *);
 
+static void qla25xx_set_que(srb_t *, struct rsp_que **);
 /**
  * qla2x00_get_cmd_direction() - Determine control_flag data direction.
  * @cmd: SCSI command
@@ -92,9 +93,10 @@
  * Returns a pointer to the Continuation Type 0 IOCB packet.
  */
 static inline cont_entry_t *
-qla2x00_prep_cont_type0_iocb(struct req_que *req, struct scsi_qla_host *vha)
+qla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha)
 {
 	cont_entry_t *cont_pkt;
+	struct req_que *req = vha->req;
 	/* Adjust ring index. */
 	req->ring_index++;
 	if (req->ring_index == req->length) {
@@ -120,10 +122,11 @@
  * Returns a pointer to the continuation type 1 IOCB packet.
  */
 static inline cont_a64_entry_t *
-qla2x00_prep_cont_type1_iocb(struct req_que *req, scsi_qla_host_t *vha)
+qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha)
 {
 	cont_a64_entry_t *cont_pkt;
 
+	struct req_que *req = vha->req;
 	/* Adjust ring index. */
 	req->ring_index++;
 	if (req->ring_index == req->length) {
@@ -159,7 +162,6 @@
 	struct scsi_cmnd *cmd;
 	struct scatterlist *sg;
 	int i;
-	struct req_que *req;
 
 	cmd = sp->cmd;
 
@@ -174,8 +176,6 @@
 	}
 
 	vha = sp->fcport->vha;
-	req = sp->que;
-
 	cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp));
 
 	/* Three DSDs are available in the Command Type 2 IOCB */
@@ -192,7 +192,7 @@
 			 * Seven DSDs are available in the Continuation
 			 * Type 0 IOCB.
 			 */
-			cont_pkt = qla2x00_prep_cont_type0_iocb(req, vha);
+			cont_pkt = qla2x00_prep_cont_type0_iocb(vha);
 			cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address;
 			avail_dsds = 7;
 		}
@@ -220,7 +220,6 @@
 	struct scsi_cmnd *cmd;
 	struct scatterlist *sg;
 	int i;
-	struct req_que *req;
 
 	cmd = sp->cmd;
 
@@ -235,8 +234,6 @@
 	}
 
 	vha = sp->fcport->vha;
-	req = sp->que;
-
 	cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp));
 
 	/* Two DSDs are available in the Command Type 3 IOCB */
@@ -254,7 +251,7 @@
 			 * Five DSDs are available in the Continuation
 			 * Type 1 IOCB.
 			 */
-			cont_pkt = qla2x00_prep_cont_type1_iocb(req, vha);
+			cont_pkt = qla2x00_prep_cont_type1_iocb(vha);
 			cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
 			avail_dsds = 5;
 		}
@@ -353,7 +350,6 @@
 	/* Build command packet */
 	req->current_outstanding_cmd = handle;
 	req->outstanding_cmds[handle] = sp;
-	sp->que = req;
 	sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
 	req->cnt -= req_cnt;
 
@@ -453,6 +449,7 @@
 			mrk24->lun[2] = MSB(lun);
 			host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun));
 			mrk24->vp_index = vha->vp_idx;
+			mrk24->handle = MAKE_HANDLE(req->id, mrk24->handle);
 		} else {
 			SET_TARGET_ID(ha, mrk->target, loop_id);
 			mrk->lun = cpu_to_le16(lun);
@@ -531,9 +528,6 @@
 			for (cnt = 0; cnt < REQUEST_ENTRY_SIZE / 4; cnt++)
 				*dword_ptr++ = 0;
 
-			/* Set system defined field. */
-			pkt->sys_define = (uint8_t)req->ring_index;
-
 			/* Set entry count. */
 			pkt->entry_count = 1;
 
@@ -656,7 +650,7 @@
 	}
 
 	vha = sp->fcport->vha;
-	req = sp->que;
+	req = vha->req;
 
 	/* Set transfer direction */
 	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
@@ -687,7 +681,7 @@
 			 * Five DSDs are available in the Continuation
 			 * Type 1 IOCB.
 			 */
-			cont_pkt = qla2x00_prep_cont_type1_iocb(req, vha);
+			cont_pkt = qla2x00_prep_cont_type1_iocb(vha);
 			cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
 			avail_dsds = 5;
 		}
@@ -724,19 +718,13 @@
 	struct scsi_cmnd *cmd = sp->cmd;
 	struct scsi_qla_host *vha = sp->fcport->vha;
 	struct qla_hw_data *ha = vha->hw;
-	uint16_t que_id;
 
 	/* Setup device pointers. */
 	ret = 0;
-	que_id = vha->req_ques[0];
 
-	req = ha->req_q_map[que_id];
-	sp->que = req;
+	qla25xx_set_que(sp, &rsp);
+	req = vha->req;
 
-	if (req->rsp)
-		rsp = req->rsp;
-	else
-		rsp = ha->rsp_q_map[que_id];
 	/* So we know we haven't pci_map'ed anything yet */
 	tot_dsds = 0;
 
@@ -794,7 +782,7 @@
 	req->cnt -= req_cnt;
 
 	cmd_pkt = (struct cmd_type_7 *)req->ring_ptr;
-	cmd_pkt->handle = handle;
+	cmd_pkt->handle = MAKE_HANDLE(req->id, handle);
 
 	/* Zero out remaining portion of packet. */
 	/*    tagged queuing modifier -- default is TSK_SIMPLE (0). */
@@ -823,6 +811,8 @@
 
 	/* Set total data segment count. */
 	cmd_pkt->entry_count = (uint8_t)req_cnt;
+	/* Specify response queue number where completion should happen */
+	cmd_pkt->entry_status = (uint8_t) rsp->id;
 	wmb();
 
 	/* Adjust ring index. */
@@ -842,7 +832,7 @@
 	/* Manage unprocessed RIO/ZIO commands in response queue. */
 	if (vha->flags.process_response_queue &&
 		rsp->ring_ptr->signature != RESPONSE_PROCESSED)
-		qla24xx_process_response_queue(rsp);
+		qla24xx_process_response_queue(vha, rsp);
 
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 	return QLA_SUCCESS;
@@ -855,3 +845,16 @@
 
 	return QLA_FUNCTION_FAILED;
 }
+
+static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp)
+{
+	struct scsi_cmnd *cmd = sp->cmd;
+	struct qla_hw_data *ha = sp->fcport->vha->hw;
+	int affinity = cmd->request->cpu;
+
+	if (ql2xmultique_tag && affinity >= 0 &&
+		affinity < ha->max_rsp_queues - 1)
+		*rsp = ha->rsp_q_map[affinity + 1];
+	 else
+		*rsp = ha->rsp_q_map[0];
+}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index d049818..c8d0a17 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -13,10 +13,9 @@
 static void qla2x00_process_completed_request(struct scsi_qla_host *,
 	struct req_que *, uint32_t);
 static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
-static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *);
+static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
 static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
 	sts_entry_t *);
-static struct scsi_qla_host *qla2x00_get_rsp_host(struct rsp_que *);
 
 /**
  * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
@@ -51,7 +50,7 @@
 	status = 0;
 
 	spin_lock(&ha->hardware_lock);
-	vha = qla2x00_get_rsp_host(rsp);
+	vha = pci_get_drvdata(ha->pdev);
 	for (iter = 50; iter--; ) {
 		hccr = RD_REG_WORD(&reg->hccr);
 		if (hccr & HCCR_RISC_PAUSE) {
@@ -147,7 +146,7 @@
 	status = 0;
 
 	spin_lock(&ha->hardware_lock);
-	vha = qla2x00_get_rsp_host(rsp);
+	vha = pci_get_drvdata(ha->pdev);
 	for (iter = 50; iter--; ) {
 		stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
 		if (stat & HSR_RISC_PAUSED) {
@@ -685,7 +684,7 @@
 		    vha->host_no));
 
 		if (IS_FWI2_CAPABLE(ha))
-			qla24xx_process_response_queue(rsp);
+			qla24xx_process_response_queue(vha, rsp);
 		else
 			qla2x00_process_response_queue(rsp);
 		break;
@@ -766,7 +765,10 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req = NULL;
 
-	req = ha->req_q_map[vha->req_ques[0]];
+	if (!ql2xqfulltracking)
+		return;
+
+	req = vha->req;
 	if (!req)
 		return;
 	if (req->max_q_depth <= sdev->queue_depth)
@@ -808,6 +810,9 @@
 	fc_port_t *fcport;
 	struct scsi_device *sdev;
 
+	if (!ql2xqfulltracking)
+		return;
+
 	sdev = sp->cmd->device;
 	if (sdev->queue_depth >= req->max_q_depth)
 		return;
@@ -858,8 +863,8 @@
 		qla2x00_ramp_up_queue_depth(vha, req, sp);
 		qla2x00_sp_compl(ha, sp);
 	} else {
-		DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n",
-		    vha->host_no));
+		DEBUG2(printk("scsi(%ld) Req:%d: Invalid ISP SCSI completion"
+			" handle(%d)\n", vha->host_no, req->id, index));
 		qla_printk(KERN_WARNING, ha,
 		    "Invalid ISP SCSI completion handle\n");
 
@@ -881,7 +886,7 @@
 	uint16_t        handle_cnt;
 	uint16_t        cnt;
 
-	vha = qla2x00_get_rsp_host(rsp);
+	vha = pci_get_drvdata(ha->pdev);
 
 	if (!vha->flags.online)
 		return;
@@ -926,7 +931,7 @@
 			}
 			break;
 		case STATUS_CONT_TYPE:
-			qla2x00_status_cont_entry(vha, (sts_cont_entry_t *)pkt);
+			qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
 			break;
 		default:
 			/* Type Not Supported. */
@@ -945,7 +950,8 @@
 }
 
 static inline void
-qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len)
+qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len,
+	struct rsp_que *rsp)
 {
 	struct scsi_cmnd *cp = sp->cmd;
 
@@ -962,7 +968,7 @@
 	sp->request_sense_ptr += sense_len;
 	sp->request_sense_length -= sense_len;
 	if (sp->request_sense_length != 0)
-		sp->fcport->vha->status_srb = sp;
+		rsp->status_srb = sp;
 
 	DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
 	    "cmd=%p pid=%ld\n", __func__, sp->fcport->vha->host_no,
@@ -992,7 +998,9 @@
 	uint32_t	sense_len, rsp_info_len, resid_len, fw_resid_len;
 	uint8_t		*rsp_info, *sense_data;
 	struct qla_hw_data *ha = vha->hw;
-	struct req_que *req = rsp->req;
+	uint32_t handle;
+	uint16_t que;
+	struct req_que *req;
 
 	sts = (sts_entry_t *) pkt;
 	sts24 = (struct sts_entry_24xx *) pkt;
@@ -1003,18 +1011,20 @@
 		comp_status = le16_to_cpu(sts->comp_status);
 		scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
 	}
-
+	handle = (uint32_t) LSW(sts->handle);
+	que = MSW(sts->handle);
+	req = ha->req_q_map[que];
 	/* Fast path completion. */
 	if (comp_status == CS_COMPLETE && scsi_status == 0) {
-		qla2x00_process_completed_request(vha, req, sts->handle);
+		qla2x00_process_completed_request(vha, req, handle);
 
 		return;
 	}
 
 	/* Validate handle. */
-	if (sts->handle < MAX_OUTSTANDING_COMMANDS) {
-		sp = req->outstanding_cmds[sts->handle];
-		req->outstanding_cmds[sts->handle] = NULL;
+	if (handle < MAX_OUTSTANDING_COMMANDS) {
+		sp = req->outstanding_cmds[handle];
+		req->outstanding_cmds[handle] = NULL;
 	} else
 		sp = NULL;
 
@@ -1030,7 +1040,7 @@
 	cp = sp->cmd;
 	if (cp == NULL) {
 		DEBUG2(printk("scsi(%ld): Command already returned back to OS "
-		    "pkt->handle=%d sp=%p.\n", vha->host_no, sts->handle, sp));
+		    "pkt->handle=%d sp=%p.\n", vha->host_no, handle, sp));
 		qla_printk(KERN_WARNING, ha,
 		    "Command is NULL: already returned to OS (sp=%p)\n", sp);
 
@@ -1121,6 +1131,8 @@
 			    scsi_status));
 
 			/* Adjust queue depth for all luns on the port. */
+			if (!ql2xqfulltracking)
+				break;
 			fcport->last_queue_full = jiffies;
 			starget_for_each_device(cp->device->sdev_target,
 			    fcport, qla2x00_adjust_sdev_qdepth_down);
@@ -1133,7 +1145,7 @@
 		if (!(scsi_status & SS_SENSE_LEN_VALID))
 			break;
 
-		qla2x00_handle_sense(sp, sense_data, sense_len);
+		qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
 		break;
 
 	case CS_DATA_UNDERRUN:
@@ -1179,6 +1191,8 @@
 				 * Adjust queue depth for all luns on the
 				 * port.
 				 */
+				if (!ql2xqfulltracking)
+					break;
 				fcport->last_queue_full = jiffies;
 				starget_for_each_device(
 				    cp->device->sdev_target, fcport,
@@ -1192,12 +1206,12 @@
 			if (!(scsi_status & SS_SENSE_LEN_VALID))
 				break;
 
-			qla2x00_handle_sense(sp, sense_data, sense_len);
+			qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
 		} else {
 			/*
 			 * If RISC reports underrun and target does not report
 			 * it then we must have a lost frame, so tell upper
-			 * layer to retry it by reporting a bus busy.
+			 * layer to retry it by reporting an error.
 			 */
 			if (!(scsi_status & SS_RESIDUAL_UNDER)) {
 				DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped "
@@ -1207,7 +1221,7 @@
 					cp->device->id, cp->device->lun, resid,
 					scsi_bufflen(cp)));
 
-				cp->result = DID_BUS_BUSY << 16;
+				cp->result = DID_ERROR << 16;
 				break;
 			}
 
@@ -1334,7 +1348,7 @@
 	}
 
 	/* Place command on done queue. */
-	if (vha->status_srb == NULL)
+	if (rsp->status_srb == NULL)
 		qla2x00_sp_compl(ha, sp);
 }
 
@@ -1346,11 +1360,11 @@
  * Extended sense data.
  */
 static void
-qla2x00_status_cont_entry(scsi_qla_host_t *vha, sts_cont_entry_t *pkt)
+qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
 {
 	uint8_t		sense_sz = 0;
-	struct qla_hw_data *ha = vha->hw;
-	srb_t		*sp = vha->status_srb;
+	struct qla_hw_data *ha = rsp->hw;
+	srb_t		*sp = rsp->status_srb;
 	struct scsi_cmnd *cp;
 
 	if (sp != NULL && sp->request_sense_length != 0) {
@@ -1362,7 +1376,7 @@
 			    "cmd is NULL: already returned to OS (sp=%p)\n",
 			    sp);
 
-			vha->status_srb = NULL;
+			rsp->status_srb = NULL;
 			return;
 		}
 
@@ -1383,7 +1397,7 @@
 
 		/* Place command on done queue. */
 		if (sp->request_sense_length == 0) {
-			vha->status_srb = NULL;
+			rsp->status_srb = NULL;
 			qla2x00_sp_compl(ha, sp);
 		}
 	}
@@ -1399,7 +1413,9 @@
 {
 	srb_t *sp;
 	struct qla_hw_data *ha = vha->hw;
-	struct req_que *req = rsp->req;
+	uint32_t handle = LSW(pkt->handle);
+	uint16_t que = MSW(pkt->handle);
+	struct req_que *req = ha->req_q_map[que];
 #if defined(QL_DEBUG_LEVEL_2)
 	if (pkt->entry_status & RF_INV_E_ORDER)
 		qla_printk(KERN_ERR, ha, "%s: Invalid Entry Order\n", __func__);
@@ -1417,14 +1433,14 @@
 #endif
 
 	/* Validate handle. */
-	if (pkt->handle < MAX_OUTSTANDING_COMMANDS)
-		sp = req->outstanding_cmds[pkt->handle];
+	if (handle < MAX_OUTSTANDING_COMMANDS)
+		sp = req->outstanding_cmds[handle];
 	else
 		sp = NULL;
 
 	if (sp) {
 		/* Free outstanding command slot. */
-		req->outstanding_cmds[pkt->handle] = NULL;
+		req->outstanding_cmds[handle] = NULL;
 
 		/* Bad payload or header */
 		if (pkt->entry_status &
@@ -1486,13 +1502,10 @@
  * qla24xx_process_response_queue() - Process response queue entries.
  * @ha: SCSI driver HA context
  */
-void
-qla24xx_process_response_queue(struct rsp_que *rsp)
+void qla24xx_process_response_queue(struct scsi_qla_host *vha,
+	struct rsp_que *rsp)
 {
 	struct sts_entry_24xx *pkt;
-	struct scsi_qla_host *vha;
-
-	vha = qla2x00_get_rsp_host(rsp);
 
 	if (!vha->flags.online)
 		return;
@@ -1523,7 +1536,7 @@
 			qla2x00_status_entry(vha, rsp, pkt);
 			break;
 		case STATUS_CONT_TYPE:
-			qla2x00_status_cont_entry(vha, (sts_cont_entry_t *)pkt);
+			qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
 			break;
 		case VP_RPT_ID_IOCB_TYPE:
 			qla24xx_report_id_acquisition(vha,
@@ -1626,7 +1639,7 @@
 	status = 0;
 
 	spin_lock(&ha->hardware_lock);
-	vha = qla2x00_get_rsp_host(rsp);
+	vha = pci_get_drvdata(ha->pdev);
 	for (iter = 50; iter--; ) {
 		stat = RD_REG_DWORD(&reg->host_status);
 		if (stat & HSRX_RISC_PAUSED) {
@@ -1664,7 +1677,7 @@
 			break;
 		case 0x13:
 		case 0x14:
-			qla24xx_process_response_queue(rsp);
+			qla24xx_process_response_queue(vha, rsp);
 			break;
 		default:
 			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
@@ -1692,6 +1705,7 @@
 	struct qla_hw_data *ha;
 	struct rsp_que *rsp;
 	struct device_reg_24xx __iomem *reg;
+	struct scsi_qla_host *vha;
 
 	rsp = (struct rsp_que *) dev_id;
 	if (!rsp) {
@@ -1704,7 +1718,8 @@
 
 	spin_lock_irq(&ha->hardware_lock);
 
-	qla24xx_process_response_queue(rsp);
+	vha = qla25xx_get_host(rsp);
+	qla24xx_process_response_queue(vha, rsp);
 	WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
 
 	spin_unlock_irq(&ha->hardware_lock);
@@ -1717,7 +1732,6 @@
 {
 	struct qla_hw_data *ha;
 	struct rsp_que *rsp;
-	struct device_reg_24xx __iomem *reg;
 
 	rsp = (struct rsp_que *) dev_id;
 	if (!rsp) {
@@ -1726,13 +1740,8 @@
 		return IRQ_NONE;
 	}
 	ha = rsp->hw;
-	reg = &ha->iobase->isp24;
 
-	spin_lock_irq(&ha->hardware_lock);
-
-	qla24xx_process_response_queue(rsp);
-
-	spin_unlock_irq(&ha->hardware_lock);
+	queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work);
 
 	return IRQ_HANDLED;
 }
@@ -1760,7 +1769,7 @@
 	status = 0;
 
 	spin_lock_irq(&ha->hardware_lock);
-	vha = qla2x00_get_rsp_host(rsp);
+	vha = pci_get_drvdata(ha->pdev);
 	do {
 		stat = RD_REG_DWORD(&reg->host_status);
 		if (stat & HSRX_RISC_PAUSED) {
@@ -1798,7 +1807,7 @@
 			break;
 		case 0x13:
 		case 0x14:
-			qla24xx_process_response_queue(rsp);
+			qla24xx_process_response_queue(vha, rsp);
 			break;
 		default:
 			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
@@ -1822,31 +1831,14 @@
 /* Interrupt handling helpers. */
 
 struct qla_init_msix_entry {
-	uint16_t entry;
-	uint16_t index;
 	const char *name;
 	irq_handler_t handler;
 };
 
-static struct qla_init_msix_entry base_queue = {
-	.entry = 0,
-	.index = 0,
-	.name = "qla2xxx (default)",
-	.handler = qla24xx_msix_default,
-};
-
-static struct qla_init_msix_entry base_rsp_queue = {
-	.entry = 1,
-	.index = 1,
-	.name = "qla2xxx (rsp_q)",
-	.handler = qla24xx_msix_rsp_q,
-};
-
-static struct qla_init_msix_entry multi_rsp_queue = {
-	.entry = 1,
-	.index = 1,
-	.name = "qla2xxx (multi_q)",
-	.handler = qla25xx_msix_rsp_q,
+static struct qla_init_msix_entry msix_entries[3] = {
+	{ "qla2xxx (default)", qla24xx_msix_default },
+	{ "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
+	{ "qla2xxx (multiq)", qla25xx_msix_rsp_q },
 };
 
 static void
@@ -1873,7 +1865,6 @@
 	int i, ret;
 	struct msix_entry *entries;
 	struct qla_msix_entry *qentry;
-	struct qla_init_msix_entry *msix_queue;
 
 	entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count,
 					GFP_KERNEL);
@@ -1900,7 +1891,7 @@
 				ha->msix_count, ret);
 			goto msix_out;
 		}
-		ha->max_queues = ha->msix_count - 1;
+		ha->max_rsp_queues = ha->msix_count - 1;
 	}
 	ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) *
 				ha->msix_count, GFP_KERNEL);
@@ -1918,45 +1909,27 @@
 		qentry->rsp = NULL;
 	}
 
-	/* Enable MSI-X for AENs for queue 0 */
-	qentry = &ha->msix_entries[0];
-	ret = request_irq(qentry->vector, base_queue.handler, 0,
-					base_queue.name, rsp);
-	if (ret) {
-		qla_printk(KERN_WARNING, ha,
+	/* Enable MSI-X vectors for the base queue */
+	for (i = 0; i < 2; i++) {
+		qentry = &ha->msix_entries[i];
+		ret = request_irq(qentry->vector, msix_entries[i].handler,
+					0, msix_entries[i].name, rsp);
+		if (ret) {
+			qla_printk(KERN_WARNING, ha,
 			"MSI-X: Unable to register handler -- %x/%d.\n",
 			qentry->vector, ret);
-		qla24xx_disable_msix(ha);
-		goto msix_out;
+			qla24xx_disable_msix(ha);
+			ha->mqenable = 0;
+			goto msix_out;
+		}
+		qentry->have_irq = 1;
+		qentry->rsp = rsp;
+		rsp->msix = qentry;
 	}
-	qentry->have_irq = 1;
-	qentry->rsp = rsp;
 
 	/* Enable MSI-X vector for response queue update for queue 0 */
-	if (ha->max_queues > 1 && ha->mqiobase) {
+	if (ha->mqiobase &&  (ha->max_rsp_queues > 1 || ha->max_req_queues > 1))
 		ha->mqenable = 1;
-		msix_queue = &multi_rsp_queue;
-		qla_printk(KERN_INFO, ha,
-				"MQ enabled, Number of Queue Resources: %d \n",
-				ha->max_queues);
-	} else {
-		ha->mqenable = 0;
-		msix_queue = &base_rsp_queue;
-	}
-
-	qentry = &ha->msix_entries[1];
-	ret = request_irq(qentry->vector, msix_queue->handler, 0,
-						msix_queue->name, rsp);
-	if (ret) {
-		qla_printk(KERN_WARNING, ha,
-			"MSI-X: Unable to register handler -- %x/%d.\n",
-			qentry->vector, ret);
-		qla24xx_disable_msix(ha);
-		ha->mqenable = 0;
-		goto msix_out;
-	}
-	qentry->have_irq = 1;
-	qentry->rsp = rsp;
 
 msix_out:
 	kfree(entries);
@@ -2063,35 +2036,11 @@
 	}
 }
 
-static struct scsi_qla_host *
-qla2x00_get_rsp_host(struct rsp_que *rsp)
-{
-	srb_t *sp;
-	struct qla_hw_data *ha = rsp->hw;
-	struct scsi_qla_host *vha = NULL;
-	struct sts_entry_24xx *pkt;
-	struct req_que *req;
-
-	if (rsp->id) {
-		pkt = (struct sts_entry_24xx *) rsp->ring_ptr;
-		req = rsp->req;
-		if (pkt && pkt->handle < MAX_OUTSTANDING_COMMANDS) {
-			sp = req->outstanding_cmds[pkt->handle];
-			if (sp)
-				vha = sp->fcport->vha;
-		}
-	}
-	if (!vha)
-	/* handle it in base queue */
-		vha = pci_get_drvdata(ha->pdev);
-
-	return vha;
-}
 
 int qla25xx_request_irq(struct rsp_que *rsp)
 {
 	struct qla_hw_data *ha = rsp->hw;
-	struct qla_init_msix_entry *intr = &multi_rsp_queue;
+	struct qla_init_msix_entry *intr = &msix_entries[2];
 	struct qla_msix_entry *msix = rsp->msix;
 	int ret;
 
@@ -2106,3 +2055,30 @@
 	msix->rsp = rsp;
 	return ret;
 }
+
+struct scsi_qla_host *
+qla25xx_get_host(struct rsp_que *rsp)
+{
+	srb_t *sp;
+	struct qla_hw_data *ha = rsp->hw;
+	struct scsi_qla_host *vha = NULL;
+	struct sts_entry_24xx *pkt;
+	struct req_que *req;
+	uint16_t que;
+	uint32_t handle;
+
+	pkt = (struct sts_entry_24xx *) rsp->ring_ptr;
+	que = MSW(pkt->handle);
+	handle = (uint32_t) LSW(pkt->handle);
+	req = ha->req_q_map[que];
+	if (handle < MAX_OUTSTANDING_COMMANDS) {
+		sp = req->outstanding_cmds[handle];
+		if (sp)
+			return  sp->fcport->vha;
+		else
+			goto base_que;
+	}
+base_que:
+	vha = pci_get_drvdata(ha->pdev);
+	return vha;
+}
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index e67c166..451ece0 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -408,7 +408,7 @@
  * Context:
  *	Kernel context.
  */
-void
+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)
@@ -427,6 +427,8 @@
 	mcp->flags = 0;
 	mcp->tov = MBX_TOV_SECONDS;
 	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS)
+		goto failed;
 
 	/* Return mailbox data. */
 	*major = mcp->mb[1];
@@ -446,7 +448,7 @@
 		phy[1] = mcp->mb[9] >> 8;
 		phy[2] = mcp->mb[9] & 0xff;
 	}
-
+failed:
 	if (rval != QLA_SUCCESS) {
 		/*EMPTY*/
 		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
@@ -455,6 +457,7 @@
 		/*EMPTY*/
 		DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
 	}
+	return rval;
 }
 
 /*
@@ -748,20 +751,20 @@
  *	Kernel context.
  */
 int
-qla2x00_abort_command(scsi_qla_host_t *vha, srb_t *sp, struct req_que *req)
+qla2x00_abort_command(srb_t *sp)
 {
 	unsigned long   flags = 0;
-	fc_port_t	*fcport;
 	int		rval;
 	uint32_t	handle = 0;
 	mbx_cmd_t	mc;
 	mbx_cmd_t	*mcp = &mc;
+	fc_port_t	*fcport = sp->fcport;
+	scsi_qla_host_t *vha = fcport->vha;
 	struct qla_hw_data *ha = vha->hw;
+	struct req_que *req = vha->req;
 
 	DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", vha->host_no));
 
-	fcport = sp->fcport;
-
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
 		if (req->outstanding_cmds[handle] == sp)
@@ -800,7 +803,7 @@
 }
 
 int
-qla2x00_abort_target(struct fc_port *fcport, unsigned int l)
+qla2x00_abort_target(struct fc_port *fcport, unsigned int l, int tag)
 {
 	int rval, rval2;
 	mbx_cmd_t  mc;
@@ -813,8 +816,8 @@
 
 	l = l;
 	vha = fcport->vha;
-	req = vha->hw->req_q_map[0];
-	rsp = vha->hw->rsp_q_map[0];
+	req = vha->hw->req_q_map[tag];
+	rsp = vha->hw->rsp_q_map[tag];
 	mcp->mb[0] = MBC_ABORT_TARGET;
 	mcp->out_mb = MBX_9|MBX_2|MBX_1|MBX_0;
 	if (HAS_EXTENDED_IDS(vha->hw)) {
@@ -850,7 +853,7 @@
 }
 
 int
-qla2x00_lun_reset(struct fc_port *fcport, unsigned int l)
+qla2x00_lun_reset(struct fc_port *fcport, unsigned int l, int tag)
 {
 	int rval, rval2;
 	mbx_cmd_t  mc;
@@ -862,8 +865,8 @@
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no));
 
 	vha = fcport->vha;
-	req = vha->hw->req_q_map[0];
-	rsp = vha->hw->rsp_q_map[0];
+	req = vha->hw->req_q_map[tag];
+	rsp = vha->hw->rsp_q_map[tag];
 	mcp->mb[0] = MBC_LUN_RESET;
 	mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0;
 	if (HAS_EXTENDED_IDS(vha->hw))
@@ -931,6 +934,8 @@
 	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_QLA81XX(vha->hw))
+		mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10;
 	mcp->tov = MBX_TOV_SECONDS;
 	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(vha, mcp);
@@ -952,9 +957,19 @@
 		DEBUG2_3_11(printk("qla2x00_get_adapter_id(%ld): failed=%x.\n",
 		    vha->host_no, rval));
 	} else {
-		/*EMPTY*/
 		DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n",
 		    vha->host_no));
+
+		if (IS_QLA81XX(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;
+			vha->fcoe_vn_port_mac[4] = mcp->mb[11] & 0xff;
+			vha->fcoe_vn_port_mac[3] = mcp->mb[12] >> 8;
+			vha->fcoe_vn_port_mac[2] = mcp->mb[12] & 0xff;
+			vha->fcoe_vn_port_mac[1] = mcp->mb[13] >> 8;
+			vha->fcoe_vn_port_mac[0] = mcp->mb[13] & 0xff;
+		}
 	}
 
 	return rval;
@@ -1252,7 +1267,7 @@
 
 	mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
 	mcp->out_mb = MBX_0;
-	mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
 	mcp->tov = MBX_TOV_SECONDS;
 	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(vha, mcp);
@@ -1261,6 +1276,8 @@
 	states[0] = mcp->mb[1];
 	states[1] = mcp->mb[2];
 	states[2] = mcp->mb[3];
+	states[3] = mcp->mb[4];
+	states[4] = mcp->mb[5];
 
 	if (rval != QLA_SUCCESS) {
 		/*EMPTY*/
@@ -1480,9 +1497,17 @@
 	dma_addr_t	lg_dma;
 	uint32_t	iop[2];
 	struct qla_hw_data *ha = vha->hw;
+	struct req_que *req;
+	struct rsp_que *rsp;
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
 
+	if (ql2xmultique_tag)
+		req = ha->req_q_map[0];
+	else
+		req = vha->req;
+	rsp = req->rsp;
+
 	lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
 	if (lg == NULL) {
 		DEBUG2_3(printk("%s(%ld): failed to allocate Login IOCB.\n",
@@ -1493,6 +1518,7 @@
 
 	lg->entry_type = LOGINOUT_PORT_IOCB_TYPE;
 	lg->entry_count = 1;
+	lg->handle = MAKE_HANDLE(req->id, lg->handle);
 	lg->nport_handle = cpu_to_le16(loop_id);
 	lg->control_flags = __constant_cpu_to_le16(LCF_COMMAND_PLOGI);
 	if (opt & BIT_0)
@@ -1741,6 +1767,8 @@
 	struct logio_entry_24xx *lg;
 	dma_addr_t	lg_dma;
 	struct qla_hw_data *ha = vha->hw;
+	struct req_que *req;
+	struct rsp_que *rsp;
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
 
@@ -1752,8 +1780,14 @@
 	}
 	memset(lg, 0, sizeof(struct logio_entry_24xx));
 
+	if (ql2xmaxqueues > 1)
+		req = ha->req_q_map[0];
+	else
+		req = vha->req;
+	rsp = req->rsp;
 	lg->entry_type = LOGINOUT_PORT_IOCB_TYPE;
 	lg->entry_count = 1;
+	lg->handle = MAKE_HANDLE(req->id, lg->handle);
 	lg->nport_handle = cpu_to_le16(loop_id);
 	lg->control_flags =
 	    __constant_cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO);
@@ -1864,9 +1898,6 @@
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	if (IS_QLA81XX(vha->hw))
-	    return QLA_SUCCESS;
-
 	DEBUG11(printk("qla2x00_full_login_lip(%ld): entered.\n",
 	    vha->host_no));
 
@@ -2195,21 +2226,21 @@
 }
 
 int
-qla24xx_abort_command(scsi_qla_host_t *vha, srb_t *sp, struct req_que *req)
+qla24xx_abort_command(srb_t *sp)
 {
 	int		rval;
-	fc_port_t	*fcport;
 	unsigned long   flags = 0;
 
 	struct abort_entry_24xx *abt;
 	dma_addr_t	abt_dma;
 	uint32_t	handle;
+	fc_port_t	*fcport = sp->fcport;
+	struct scsi_qla_host *vha = fcport->vha;
 	struct qla_hw_data *ha = vha->hw;
+	struct req_que *req = vha->req;
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
 
-	fcport = sp->fcport;
-
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
 		if (req->outstanding_cmds[handle] == sp)
@@ -2231,6 +2262,7 @@
 
 	abt->entry_type = ABORT_IOCB_TYPE;
 	abt->entry_count = 1;
+	abt->handle = MAKE_HANDLE(req->id, abt->handle);
 	abt->nport_handle = cpu_to_le16(fcport->loop_id);
 	abt->handle_to_abort = handle;
 	abt->port_id[0] = fcport->d_id.b.al_pa;
@@ -2272,7 +2304,7 @@
 
 static int
 __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
-    unsigned int l)
+    unsigned int l, int tag)
 {
 	int		rval, rval2;
 	struct tsk_mgmt_cmd *tsk;
@@ -2286,8 +2318,11 @@
 
 	vha = fcport->vha;
 	ha = vha->hw;
-	req = ha->req_q_map[0];
-	rsp = ha->rsp_q_map[0];
+	req = vha->req;
+	if (ql2xmultique_tag)
+		rsp = ha->rsp_q_map[tag + 1];
+	else
+		rsp = req->rsp;
 	tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma);
 	if (tsk == NULL) {
 		DEBUG2_3(printk("%s(%ld): failed to allocate Task Management "
@@ -2298,6 +2333,7 @@
 
 	tsk->p.tsk.entry_type = TSK_MGMT_IOCB_TYPE;
 	tsk->p.tsk.entry_count = 1;
+	tsk->p.tsk.handle = MAKE_HANDLE(req->id, tsk->p.tsk.handle);
 	tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id);
 	tsk->p.tsk.timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
 	tsk->p.tsk.control_flags = cpu_to_le32(type);
@@ -2344,15 +2380,15 @@
 }
 
 int
-qla24xx_abort_target(struct fc_port *fcport, unsigned int l)
+qla24xx_abort_target(struct fc_port *fcport, unsigned int l, int tag)
 {
-	return __qla24xx_issue_tmf("Target", TCF_TARGET_RESET, fcport, l);
+	return __qla24xx_issue_tmf("Target", TCF_TARGET_RESET, fcport, l, tag);
 }
 
 int
-qla24xx_lun_reset(struct fc_port *fcport, unsigned int l)
+qla24xx_lun_reset(struct fc_port *fcport, unsigned int l, int tag)
 {
-	return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l);
+	return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l, tag);
 }
 
 int
@@ -2446,6 +2482,8 @@
 	if (rval != QLA_SUCCESS) {
 		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
 		    vha->host_no, rval));
+		if (mcp->mb[0] == MBS_INVALID_COMMAND)
+			rval = QLA_INVALID_COMMAND;
 	} else {
 		DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
 	}
@@ -2717,8 +2755,11 @@
 		if (vp_idx == 0)
 			return;
 
-		if (MSB(stat) == 1)
+		if (MSB(stat) == 1) {
+			DEBUG2(printk("scsi(%ld): Could not acquire ID for "
+			    "VP[%d].\n", vha->host_no, vp_idx));
 			return;
+		}
 
 		list_for_each_entry_safe(vp, tvp, &ha->vp_list, list)
 			if (vp_idx == vp->vp_idx)
@@ -3141,6 +3182,8 @@
 		WRT_REG_DWORD(&reg->req_q_in, 0);
 		WRT_REG_DWORD(&reg->req_q_out, 0);
 	}
+	req->req_q_in = &reg->req_q_in;
+	req->req_q_out = &reg->req_q_out;
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	rval = qla2x00_mailbox_command(vha, mcp);
@@ -3167,7 +3210,6 @@
 	mcp->mb[6] = MSW(MSD(rsp->dma));
 	mcp->mb[7] = LSW(MSD(rsp->dma));
 	mcp->mb[5] = rsp->length;
-	mcp->mb[11] = rsp->vp_idx;
 	mcp->mb[14] = rsp->msix->entry;
 	mcp->mb[13] = rsp->rid;
 
@@ -3179,7 +3221,7 @@
 	mcp->mb[8] = 0;
 	/* que out ptr index */
 	mcp->mb[9] = 0;
-	mcp->out_mb = MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8|MBX_7
+	mcp->out_mb = MBX_14|MBX_13|MBX_9|MBX_8|MBX_7
 			|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
 	mcp->in_mb = MBX_0;
 	mcp->flags = MBX_DMA_OUT;
@@ -3384,7 +3426,7 @@
 		DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
 		    vha->host_no, rval, mcp->mb[0]));
 	} else {
-		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+		DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
 	}
 
 	return rval;
@@ -3428,3 +3470,141 @@
 
 	return rval;
 }
+
+int
+qla2x00_get_xgmac_stats(scsi_qla_host_t *vha, dma_addr_t stats_dma,
+    uint16_t size_in_bytes, uint16_t *actual_size)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	if (!IS_QLA81XX(vha->hw))
+		return QLA_FUNCTION_FAILED;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+
+	mcp->mb[0] = MBC_GET_XGMAC_STATS;
+	mcp->mb[2] = MSW(stats_dma);
+	mcp->mb[3] = LSW(stats_dma);
+	mcp->mb[6] = MSW(MSD(stats_dma));
+	mcp->mb[7] = LSW(MSD(stats_dma));
+	mcp->mb[8] = size_in_bytes >> 2;
+	mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+	mcp->in_mb = MBX_2|MBX_1|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(vha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=0x%x "
+		    "mb[1]=0x%x mb[2]=0x%x.\n", __func__, vha->host_no, rval,
+		    mcp->mb[0], mcp->mb[1], mcp->mb[2]));
+	} else {
+		DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+
+		*actual_size = mcp->mb[2] << 2;
+	}
+
+	return rval;
+}
+
+int
+qla2x00_get_dcbx_params(scsi_qla_host_t *vha, dma_addr_t tlv_dma,
+    uint16_t size)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	if (!IS_QLA81XX(vha->hw))
+		return QLA_FUNCTION_FAILED;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+
+	mcp->mb[0] = MBC_GET_DCBX_PARAMS;
+	mcp->mb[1] = 0;
+	mcp->mb[2] = MSW(tlv_dma);
+	mcp->mb[3] = LSW(tlv_dma);
+	mcp->mb[6] = MSW(MSD(tlv_dma));
+	mcp->mb[7] = LSW(MSD(tlv_dma));
+	mcp->mb[8] = size;
+	mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_2|MBX_1|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(vha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=0x%x "
+		    "mb[1]=0x%x mb[2]=0x%x.\n", __func__, vha->host_no, rval,
+		    mcp->mb[0], mcp->mb[1], mcp->mb[2]));
+	} else {
+		DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+	}
+
+	return rval;
+}
+
+int
+qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	if (!IS_FWI2_CAPABLE(vha->hw))
+		return QLA_FUNCTION_FAILED;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+
+	mcp->mb[0] = MBC_READ_RAM_EXTENDED;
+	mcp->mb[1] = LSW(risc_addr);
+	mcp->mb[8] = MSW(risc_addr);
+	mcp->out_mb = MBX_8|MBX_1|MBX_0;
+	mcp->in_mb = MBX_3|MBX_2|MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
+		    vha->host_no, rval, mcp->mb[0]));
+	} else {
+		DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+		*data = mcp->mb[3] << 16 | mcp->mb[2];
+	}
+
+	return rval;
+}
+
+int
+qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	if (!IS_FWI2_CAPABLE(vha->hw))
+                return QLA_FUNCTION_FAILED;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+
+	mcp->mb[0] = MBC_WRITE_RAM_WORD_EXTENDED;
+	mcp->mb[1] = LSW(risc_addr);
+	mcp->mb[2] = LSW(data);
+	mcp->mb[3] = MSW(data);
+	mcp->mb[8] = MSW(risc_addr);
+	mcp->out_mb = MBX_8|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
+		    vha->host_no, rval, mcp->mb[0]));
+	} else {
+		DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+	}
+
+	return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 51716c7..650bcef 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -398,9 +398,8 @@
 
 	qla2x00_start_timer(vha, qla2x00_timer, WATCH_INTERVAL);
 
-	memset(vha->req_ques, 0, sizeof(vha->req_ques));
-	vha->req_ques[0] = ha->req_q_map[0]->id;
-	host->can_queue = ha->req_q_map[0]->length + 128;
+	vha->req = base_vha->req;
+	host->can_queue = base_vha->req->length + 128;
 	host->this_id = 255;
 	host->cmd_per_lun = 3;
 	host->max_cmd_len = MAX_CMDSZ;
@@ -515,76 +514,53 @@
 
 /* Delete all queues for a given vhost */
 int
-qla25xx_delete_queues(struct scsi_qla_host *vha, uint8_t que_no)
+qla25xx_delete_queues(struct scsi_qla_host *vha)
 {
 	int cnt, ret = 0;
 	struct req_que *req = NULL;
 	struct rsp_que *rsp = NULL;
 	struct qla_hw_data *ha = vha->hw;
 
-	if (que_no) {
-	/* Delete request queue */
-		req = ha->req_q_map[que_no];
+	/* Delete request queues */
+	for (cnt = 1; cnt < ha->max_req_queues; cnt++) {
+		req = ha->req_q_map[cnt];
 		if (req) {
-			rsp = req->rsp;
 			ret = qla25xx_delete_req_que(vha, req);
 			if (ret != QLA_SUCCESS) {
 				qla_printk(KERN_WARNING, ha,
-				"Couldn't delete req que %d\n", req->id);
+				"Couldn't delete req que %d\n",
+				req->id);
 				return ret;
 			}
-			/* Delete associated response queue */
-			if (rsp) {
-				ret = qla25xx_delete_rsp_que(vha, rsp);
-				if (ret != QLA_SUCCESS) {
-					qla_printk(KERN_WARNING, ha,
-						"Couldn't delete rsp que %d\n",
-						rsp->id);
-					return ret;
-				}
-			}
-		}
-	} else {  /* delete all queues of this host */
-		for (cnt = 0; cnt < QLA_MAX_HOST_QUES; cnt++) {
-			/* Delete request queues */
-			req = ha->req_q_map[vha->req_ques[cnt]];
-			if (req && req->id) {
-				rsp = req->rsp;
-				ret = qla25xx_delete_req_que(vha, req);
-				if (ret != QLA_SUCCESS) {
-					qla_printk(KERN_WARNING, ha,
-						"Couldn't delete req que %d\n",
-						vha->req_ques[cnt]);
-					return ret;
-				}
-				vha->req_ques[cnt] = ha->req_q_map[0]->id;
-			/* Delete associated response queue */
-				if (rsp && rsp->id) {
-					ret = qla25xx_delete_rsp_que(vha, rsp);
-					if (ret != QLA_SUCCESS) {
-						qla_printk(KERN_WARNING, ha,
-						"Couldn't delete rsp que %d\n",
-						rsp->id);
-						return ret;
-					}
-				}
-			}
 		}
 	}
-	qla_printk(KERN_INFO, ha, "Queues deleted for vport:%d\n",
-		vha->vp_idx);
+
+	/* Delete response queues */
+	for (cnt = 1; cnt < ha->max_rsp_queues; cnt++) {
+		rsp = ha->rsp_q_map[cnt];
+		if (rsp) {
+			ret = qla25xx_delete_rsp_que(vha, rsp);
+			if (ret != QLA_SUCCESS) {
+				qla_printk(KERN_WARNING, ha,
+				"Couldn't delete rsp que %d\n",
+				rsp->id);
+				return ret;
+			}
+		}
+	}
 	return ret;
 }
 
 int
 qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
-	uint8_t vp_idx, uint16_t rid, uint8_t rsp_que, uint8_t qos)
+	uint8_t vp_idx, uint16_t rid, int rsp_que, uint8_t qos)
 {
 	int ret = 0;
 	struct req_que *req = NULL;
 	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
 	uint16_t que_id = 0;
 	device_reg_t __iomem *reg;
+	uint32_t cnt;
 
 	req = kzalloc(sizeof(struct req_que), GFP_KERNEL);
 	if (req == NULL) {
@@ -604,8 +580,8 @@
 	}
 
 	mutex_lock(&ha->vport_lock);
-	que_id = find_first_zero_bit(ha->req_qid_map, ha->max_queues);
-	if (que_id >= ha->max_queues) {
+	que_id = find_first_zero_bit(ha->req_qid_map, ha->max_req_queues);
+	if (que_id >= ha->max_req_queues) {
 		mutex_unlock(&ha->vport_lock);
 		qla_printk(KERN_INFO, ha, "No resources to create "
 			 "additional request queue\n");
@@ -617,10 +593,10 @@
 	req->vp_idx = vp_idx;
 	req->qos = qos;
 
-	if (ha->rsp_q_map[rsp_que]) {
+	if (rsp_que < 0)
+		req->rsp = NULL;
+	else
 		req->rsp = ha->rsp_q_map[rsp_que];
-		req->rsp->req = req;
-	}
 	/* Use alternate PCI bus number */
 	if (MSB(req->rid))
 		options |= BIT_4;
@@ -628,13 +604,16 @@
 	if (LSB(req->rid))
 		options |= BIT_5;
 	req->options = options;
+
+	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
+		req->outstanding_cmds[cnt] = NULL;
+	req->current_outstanding_cmd = 1;
+
 	req->ring_ptr = req->ring;
 	req->ring_index = 0;
 	req->cnt = req->length;
 	req->id = que_id;
 	reg = ISP_QUE_REG(ha, que_id);
-	req->req_q_in = &reg->isp25mq.req_q_in;
-	req->req_q_out = &reg->isp25mq.req_q_out;
 	req->max_q_depth = ha->req_q_map[0]->max_q_depth;
 	mutex_unlock(&ha->vport_lock);
 
@@ -654,10 +633,19 @@
 	return 0;
 }
 
+static void qla_do_work(struct work_struct *work)
+{
+	struct rsp_que *rsp = container_of(work, struct rsp_que, q_work);
+	struct scsi_qla_host *vha;
+
+	vha = qla25xx_get_host(rsp);
+	qla24xx_process_response_queue(vha, rsp);
+}
+
 /* create response queue */
 int
 qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
-	uint8_t vp_idx, uint16_t rid)
+	uint8_t vp_idx, uint16_t rid, int req)
 {
 	int ret = 0;
 	struct rsp_que *rsp = NULL;
@@ -672,7 +660,7 @@
 		goto que_failed;
 	}
 
-	rsp->length = RESPONSE_ENTRY_CNT_2300;
+	rsp->length = RESPONSE_ENTRY_CNT_MQ;
 	rsp->ring = dma_alloc_coherent(&ha->pdev->dev,
 			(rsp->length + 1) * sizeof(response_t),
 			&rsp->dma, GFP_KERNEL);
@@ -683,8 +671,8 @@
 	}
 
 	mutex_lock(&ha->vport_lock);
-	que_id = find_first_zero_bit(ha->rsp_qid_map, ha->max_queues);
-	if (que_id >= ha->max_queues) {
+	que_id = find_first_zero_bit(ha->rsp_qid_map, ha->max_rsp_queues);
+	if (que_id >= ha->max_rsp_queues) {
 		mutex_unlock(&ha->vport_lock);
 		qla_printk(KERN_INFO, ha, "No resources to create "
 			 "additional response queue\n");
@@ -708,8 +696,6 @@
 	if (LSB(rsp->rid))
 		options |= BIT_5;
 	rsp->options = options;
-	rsp->ring_ptr = rsp->ring;
-	rsp->ring_index = 0;
 	rsp->id = que_id;
 	reg = ISP_QUE_REG(ha, que_id);
 	rsp->rsp_q_in = &reg->isp25mq.rsp_q_in;
@@ -728,9 +714,14 @@
 		mutex_unlock(&ha->vport_lock);
 		goto que_failed;
 	}
+	if (req >= 0)
+		rsp->req = ha->req_q_map[req];
+	else
+		rsp->req = NULL;
 
 	qla2x00_init_response_q_entries(rsp);
-
+	if (rsp->hw->wq)
+		INIT_WORK(&rsp->q_work, qla_do_work);
 	return rsp->id;
 
 que_failed:
@@ -744,14 +735,16 @@
 	uint16_t options = 0;
 	uint8_t ret = 0;
 	struct qla_hw_data *ha = vha->hw;
+	struct rsp_que *rsp;
 
 	options |= BIT_1;
-	ret = qla25xx_create_rsp_que(ha, options, vha->vp_idx, 0);
+	ret = qla25xx_create_rsp_que(ha, options, vha->vp_idx, 0, -1);
 	if (!ret) {
 		qla_printk(KERN_WARNING, ha, "Response Que create failed\n");
 		return ret;
 	} else
 		qla_printk(KERN_INFO, ha, "Response Que:%d created.\n", ret);
+	rsp = ha->rsp_q_map[ret];
 
 	options = 0;
 	if (qos & BIT_7)
@@ -759,10 +752,11 @@
 	ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, ret,
 					qos & ~BIT_7);
 	if (ret) {
-		vha->req_ques[0] = ret;
+		vha->req = ha->req_q_map[ret];
 		qla_printk(KERN_INFO, ha, "Request Que:%d created.\n", ret);
 	} else
 		qla_printk(KERN_WARNING, ha, "Request Que create failed\n");
+	rsp->req = ha->req_q_map[ret];
 
 	return ret;
 }
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index e4fdcda..dcf0116 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -77,6 +77,14 @@
 MODULE_PARM_DESC(ql2xmaxqdepth,
 		"Maximum queue depth to report for target devices.");
 
+int ql2xqfulltracking = 1;
+module_param(ql2xqfulltracking, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xqfulltracking,
+		"Controls whether the driver tracks queue full status "
+		"returns and dynamically adjusts a scsi device's queue "
+		"depth.  Default is 1, perform tracking.  Set to 0 to "
+		"disable dynamic tracking and adjustment of queue depth.");
+
 int ql2xqfullrampup = 120;
 module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xqfullrampup,
@@ -96,6 +104,23 @@
 		"Enables MQ settings "
 		"Default is 1 for single queue. Set it to number \
 			of queues in MQ mode.");
+
+int ql2xmultique_tag;
+module_param(ql2xmultique_tag, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xmultique_tag,
+		"Enables CPU affinity settings for the driver "
+		"Default is 0 for no affinity of request and response IO. "
+		"Set it to 1 to turn on the cpu affinity.");
+
+int ql2xfwloadbin;
+module_param(ql2xfwloadbin, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xfwloadbin,
+		"Option to specify location from which to load ISP firmware:\n"
+		" 2 -- load firmware via the request_firmware() (hotplug)\n"
+		"      interface.\n"
+		" 1 -- load firmware from flash.\n"
+		" 0 -- use default semantics.\n");
+
 /*
  * SCSI host template entry points
  */
@@ -187,7 +212,7 @@
 /* -------------------------------------------------------------------------- */
 static int qla2x00_alloc_queues(struct qla_hw_data *ha)
 {
-	ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_queues,
+	ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_req_queues,
 				GFP_KERNEL);
 	if (!ha->req_q_map) {
 		qla_printk(KERN_WARNING, ha,
@@ -195,7 +220,7 @@
 		goto fail_req_map;
 	}
 
-	ha->rsp_q_map = kzalloc(sizeof(struct rsp_que *) * ha->max_queues,
+	ha->rsp_q_map = kzalloc(sizeof(struct rsp_que *) * ha->max_rsp_queues,
 				GFP_KERNEL);
 	if (!ha->rsp_q_map) {
 		qla_printk(KERN_WARNING, ha,
@@ -213,16 +238,8 @@
 	return -ENOMEM;
 }
 
-static void qla2x00_free_que(struct qla_hw_data *ha, struct req_que *req,
-	struct rsp_que *rsp)
+static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
 {
-	if (rsp && rsp->ring)
-		dma_free_coherent(&ha->pdev->dev,
-		(rsp->length + 1) * sizeof(response_t),
-		rsp->ring, rsp->dma);
-
-	kfree(rsp);
-	rsp = NULL;
 	if (req && req->ring)
 		dma_free_coherent(&ha->pdev->dev,
 		(req->length + 1) * sizeof(request_t),
@@ -232,22 +249,77 @@
 	req = NULL;
 }
 
+static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
+{
+	if (rsp && rsp->ring)
+		dma_free_coherent(&ha->pdev->dev,
+		(rsp->length + 1) * sizeof(response_t),
+		rsp->ring, rsp->dma);
+
+	kfree(rsp);
+	rsp = NULL;
+}
+
 static void qla2x00_free_queues(struct qla_hw_data *ha)
 {
 	struct req_que *req;
 	struct rsp_que *rsp;
 	int cnt;
 
-	for (cnt = 0; cnt < ha->max_queues; cnt++) {
-		rsp = ha->rsp_q_map[cnt];
+	for (cnt = 0; cnt < ha->max_req_queues; cnt++) {
 		req = ha->req_q_map[cnt];
-		qla2x00_free_que(ha, req, rsp);
+		qla2x00_free_req_que(ha, req);
+	}
+	kfree(ha->req_q_map);
+	ha->req_q_map = NULL;
+
+	for (cnt = 0; cnt < ha->max_rsp_queues; cnt++) {
+		rsp = ha->rsp_q_map[cnt];
+		qla2x00_free_rsp_que(ha, rsp);
 	}
 	kfree(ha->rsp_q_map);
 	ha->rsp_q_map = NULL;
+}
 
-	kfree(ha->req_q_map);
-	ha->req_q_map = NULL;
+static int qla25xx_setup_mode(struct scsi_qla_host *vha)
+{
+	uint16_t options = 0;
+	int ques, req, ret;
+	struct qla_hw_data *ha = vha->hw;
+
+	if (ql2xmultique_tag) {
+		/* CPU affinity mode */
+		ha->wq = create_workqueue("qla2xxx_wq");
+		/* create a request queue for IO */
+		options |= BIT_7;
+		req = qla25xx_create_req_que(ha, options, 0, 0, -1,
+			QLA_DEFAULT_QUE_QOS);
+		if (!req) {
+			qla_printk(KERN_WARNING, ha,
+				"Can't create request queue\n");
+			goto fail;
+		}
+		vha->req = ha->req_q_map[req];
+		options |= BIT_1;
+		for (ques = 1; ques < ha->max_rsp_queues; ques++) {
+			ret = qla25xx_create_rsp_que(ha, options, 0, 0, req);
+			if (!ret) {
+				qla_printk(KERN_WARNING, ha,
+					"Response Queue create failed\n");
+				goto fail2;
+			}
+		}
+		DEBUG2(qla_printk(KERN_INFO, ha,
+			"CPU affinity mode enabled, no. of response"
+			" queues:%d, no. of request queues:%d\n",
+			ha->max_rsp_queues, ha->max_req_queues));
+	}
+	return 0;
+fail2:
+	qla25xx_delete_queues(vha);
+fail:
+	ha->mqenable = 0;
+	return 1;
 }
 
 static char *
@@ -387,7 +459,6 @@
 
 	sp->fcport = fcport;
 	sp->cmd = cmd;
-	sp->que = ha->req_q_map[0];
 	sp->flags = 0;
 	CMD_SP(cmd) = (void *)sp;
 	cmd->scsi_done = done;
@@ -612,7 +683,7 @@
 void
 qla2x00_abort_fcport_cmds(fc_port_t *fcport)
 {
-	int cnt, que, id;
+	int cnt;
 	unsigned long flags;
 	srb_t *sp;
 	scsi_qla_host_t *vha = fcport->vha;
@@ -620,32 +691,27 @@
 	struct req_que *req;
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	for (que = 0; que < QLA_MAX_HOST_QUES; que++) {
-		id = vha->req_ques[que];
-		req = ha->req_q_map[id];
-		if (!req)
+	req = vha->req;
+	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+		sp = req->outstanding_cmds[cnt];
+		if (!sp)
 			continue;
-		for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
-			sp = req->outstanding_cmds[cnt];
-			if (!sp)
-				continue;
-			if (sp->fcport != fcport)
-				continue;
+		if (sp->fcport != fcport)
+			continue;
 
-			spin_unlock_irqrestore(&ha->hardware_lock, flags);
-			if (ha->isp_ops->abort_command(vha, sp, req)) {
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		if (ha->isp_ops->abort_command(sp)) {
+			DEBUG2(qla_printk(KERN_WARNING, ha,
+			"Abort failed --  %lx\n",
+			sp->cmd->serial_number));
+		} else {
+			if (qla2x00_eh_wait_on_command(sp->cmd) !=
+				QLA_SUCCESS)
 				DEBUG2(qla_printk(KERN_WARNING, ha,
-				"Abort failed --  %lx\n",
+				"Abort failed while waiting --  %lx\n",
 				sp->cmd->serial_number));
-			} else {
-				if (qla2x00_eh_wait_on_command(sp->cmd) !=
-					QLA_SUCCESS)
-					DEBUG2(qla_printk(KERN_WARNING, ha,
-					"Abort failed while waiting --  %lx\n",
-					sp->cmd->serial_number));
-			}
-			spin_lock_irqsave(&ha->hardware_lock, flags);
 		}
+		spin_lock_irqsave(&ha->hardware_lock, flags);
 	}
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
@@ -693,7 +759,7 @@
 	unsigned long flags;
 	int wait = 0;
 	struct qla_hw_data *ha = vha->hw;
-	struct req_que *req;
+	struct req_que *req = vha->req;
 	srb_t *spt;
 
 	qla2x00_block_error_handler(cmd);
@@ -709,7 +775,6 @@
 	spt = (srb_t *) CMD_SP(cmd);
 	if (!spt)
 		return SUCCESS;
-	req = spt->que;
 
 	/* Check active list for command command. */
 	spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -726,7 +791,7 @@
 		" pid=%ld.\n", __func__, vha->host_no, sp, serial));
 
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
-		if (ha->isp_ops->abort_command(vha, sp, req)) {
+		if (ha->isp_ops->abort_command(sp)) {
 			DEBUG2(printk("%s(%ld): abort_command "
 			"mbx failed.\n", __func__, vha->host_no));
 			ret = FAILED;
@@ -777,7 +842,7 @@
 		return status;
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	req = sp->que;
+	req = vha->req;
 	for (cnt = 1; status == QLA_SUCCESS &&
 		cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
 		sp = req->outstanding_cmds[cnt];
@@ -820,7 +885,7 @@
 
 static int
 __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
-    struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int))
+    struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int, int))
 {
 	scsi_qla_host_t *vha = shost_priv(cmd->device->host);
 	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
@@ -841,7 +906,8 @@
 	if (qla2x00_wait_for_loop_ready(vha) != QLA_SUCCESS)
 		goto eh_reset_failed;
 	err = 2;
-	if (do_reset(fcport, cmd->device->lun) != QLA_SUCCESS)
+	if (do_reset(fcport, cmd->device->lun, cmd->request->cpu + 1)
+		!= QLA_SUCCESS)
 		goto eh_reset_failed;
 	err = 3;
 	if (qla2x00_eh_wait_for_pending_commands(vha, cmd->device->id,
@@ -996,6 +1062,9 @@
 		if (qla2x00_vp_abort_isp(vha))
 			goto eh_host_reset_lock;
 	} else {
+		if (ha->wq)
+			flush_workqueue(ha->wq);
+
 		set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
 		if (qla2x00_abort_isp(base_vha)) {
 			clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
@@ -1037,7 +1106,8 @@
 	struct fc_port *fcport;
 	struct qla_hw_data *ha = vha->hw;
 
-	if (ha->flags.enable_lip_full_login && !vha->vp_idx) {
+	if (ha->flags.enable_lip_full_login && !vha->vp_idx &&
+	    !IS_QLA81XX(ha)) {
 		ret = qla2x00_full_login_lip(vha);
 		if (ret != QLA_SUCCESS) {
 			DEBUG2_3(printk("%s(%ld): failed: "
@@ -1064,7 +1134,7 @@
 			if (fcport->port_type != FCT_TARGET)
 				continue;
 
-			ret = ha->isp_ops->target_reset(fcport, 0);
+			ret = ha->isp_ops->target_reset(fcport, 0, 0);
 			if (ret != QLA_SUCCESS) {
 				DEBUG2_3(printk("%s(%ld): bus_reset failed: "
 				    "target_reset=%d d_id=%x.\n", __func__,
@@ -1088,7 +1158,7 @@
 	struct req_que *req;
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	for (que = 0; que < ha->max_queues; que++) {
+	for (que = 0; que < ha->max_req_queues; que++) {
 		req = ha->req_q_map[que];
 		if (!req)
 			continue;
@@ -1123,7 +1193,7 @@
 	scsi_qla_host_t *vha = shost_priv(sdev->host);
 	struct qla_hw_data *ha = vha->hw;
 	struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
-	struct req_que *req = ha->req_q_map[vha->req_ques[0]];
+	struct req_que *req = vha->req;
 
 	if (sdev->tagged_supported)
 		scsi_activate_tcq(sdev, req->max_q_depth);
@@ -1511,6 +1581,13 @@
 		ha->fw_srisc_address = RISC_START_ADDRESS_2400;
 		break;
 	}
+
+	/* Get adapter physical port no from interrupt pin register. */
+	pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no);
+	if (ha->port_no & 1)
+		ha->flags.port0 = 1;
+	else
+		ha->flags.port0 = 0;
 }
 
 static int
@@ -1518,6 +1595,7 @@
 {
 	resource_size_t pio;
 	uint16_t msix;
+	int cpus;
 
 	if (pci_request_selected_regions(ha->pdev, ha->bars,
 	    QLA2XXX_DRIVER_NAME)) {
@@ -1571,8 +1649,9 @@
 	}
 
 	/* Determine queue resources */
-	ha->max_queues = 1;
-	if (ql2xmaxqueues <= 1 || (!IS_QLA25XX(ha) && !IS_QLA81XX(ha)))
+	ha->max_req_queues = ha->max_rsp_queues = 1;
+	if ((ql2xmaxqueues <= 1 || ql2xmultique_tag < 1) &&
+		(!IS_QLA25XX(ha) && !IS_QLA81XX(ha)))
 		goto mqiobase_exit;
 	ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3),
 			pci_resource_len(ha->pdev, 3));
@@ -1582,18 +1661,24 @@
 		ha->msix_count = msix;
 		/* Max queues are bounded by available msix vectors */
 		/* queue 0 uses two msix vectors */
-		if (ha->msix_count - 1 < ql2xmaxqueues)
-			ha->max_queues = ha->msix_count - 1;
-		else if (ql2xmaxqueues > QLA_MQ_SIZE)
-			ha->max_queues = QLA_MQ_SIZE;
-		else
-			ha->max_queues = ql2xmaxqueues;
+		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;
+			DEBUG2(qla_printk(KERN_INFO, ha, "QoS mode set, max no"
+			" of request queues:%d\n", ha->max_req_queues));
+		}
 		qla_printk(KERN_INFO, ha,
 			"MSI-X vector count: %d\n", msix);
-	}
+	} else
+		qla_printk(KERN_INFO, ha, "BAR 3 not enabled\n");
 
 mqiobase_exit:
-	ha->msix_count = ha->max_queues + 1;
+	ha->msix_count = ha->max_rsp_queues + 1;
 	return (0);
 
 iospace_error_exit:
@@ -1605,6 +1690,9 @@
 {
 	scsi_qla_host_t *vha = shost_priv(shost);
 
+	if (vha->hw->flags.running_gold_fw)
+		return;
+
 	set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
 	set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
 	set_bit(RSCN_UPDATE, &vha->dpc_flags);
@@ -1768,6 +1856,7 @@
 		ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
 		ha->gid_list_info_size = 8;
 		ha->optrom_size = OPTROM_SIZE_81XX;
+		ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX;
 		ha->isp_ops = &qla81xx_isp_ops;
 		ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_81XX;
 		ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX;
@@ -1803,14 +1892,15 @@
 
 		ret = -ENOMEM;
 		qla2x00_mem_free(ha);
-		qla2x00_free_que(ha, req, rsp);
+		qla2x00_free_req_que(ha, req);
+		qla2x00_free_rsp_que(ha, rsp);
 		goto probe_hw_failed;
 	}
 
 	pci_set_drvdata(pdev, base_vha);
 
 	host = base_vha->host;
-	base_vha->req_ques[0] = req->id;
+	base_vha->req = req;
 	host->can_queue = req->length + 128;
 	if (IS_QLA2XXX_MIDTYPE(ha))
 		base_vha->mgmt_svr_loop_id = 10 + base_vha->vp_idx;
@@ -1841,7 +1931,10 @@
 	}
 	ha->rsp_q_map[0] = rsp;
 	ha->req_q_map[0] = req;
-
+	rsp->req = req;
+	req->rsp = rsp;
+	set_bit(0, ha->req_qid_map);
+	set_bit(0, ha->rsp_qid_map);
 	/* FWI2-capable only. */
 	req->req_q_in = &ha->iobase->isp24.req_q_in;
 	req->req_q_out = &ha->iobase->isp24.req_q_out;
@@ -1866,6 +1959,15 @@
 		goto probe_failed;
 	}
 
+	if (ha->mqenable)
+		if (qla25xx_setup_mode(base_vha))
+			qla_printk(KERN_WARNING, ha,
+				"Can't create queues, falling back to single"
+				" queue mode\n");
+
+	if (ha->flags.running_gold_fw)
+		goto skip_dpc;
+
 	/*
 	 * Startup the kernel thread for this host adapter
 	 */
@@ -1878,6 +1980,7 @@
 		goto probe_failed;
 	}
 
+skip_dpc:
 	list_add_tail(&base_vha->list, &ha->vp_list);
 	base_vha->host->irq = ha->pdev->irq;
 
@@ -1917,8 +2020,9 @@
 	return 0;
 
 probe_init_failed:
-	qla2x00_free_que(ha, req, rsp);
-	ha->max_queues = 0;
+	qla2x00_free_req_que(ha, req);
+	qla2x00_free_rsp_que(ha, rsp);
+	ha->max_req_queues = ha->max_rsp_queues = 0;
 
 probe_failed:
 	if (base_vha->timer_active)
@@ -1976,6 +2080,13 @@
 
 	base_vha->flags.online = 0;
 
+	/* Flush the work queue and remove it */
+	if (ha->wq) {
+		flush_workqueue(ha->wq);
+		destroy_workqueue(ha->wq);
+		ha->wq = NULL;
+	}
+
 	/* Kill the kernel thread for this host */
 	if (ha->dpc_thread) {
 		struct task_struct *t = ha->dpc_thread;
@@ -2017,6 +2128,8 @@
 {
 	struct qla_hw_data *ha = vha->hw;
 
+	qla25xx_delete_queues(vha);
+
 	if (ha->flags.fce_enabled)
 		qla2x00_disable_fce_trace(vha, NULL, NULL);
 
@@ -2329,6 +2442,14 @@
 		vfree(ha->fw_dump);
 	}
 
+	if (ha->dcbx_tlv)
+		dma_free_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
+		    ha->dcbx_tlv, ha->dcbx_tlv_dma);
+
+	if (ha->xgmac_data)
+		dma_free_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE,
+		    ha->xgmac_data, ha->xgmac_data_dma);
+
 	if (ha->sns_cmd)
 		dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt),
 		ha->sns_cmd, ha->sns_cmd_dma);
@@ -2412,6 +2533,8 @@
 	INIT_LIST_HEAD(&vha->work_list);
 	INIT_LIST_HEAD(&vha->list);
 
+	spin_lock_init(&vha->work_lock);
+
 	sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no);
 	return vha;
 
@@ -2420,13 +2543,11 @@
 }
 
 static struct qla_work_evt *
-qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type,
-    int locked)
+qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type)
 {
 	struct qla_work_evt *e;
 
-	e = kzalloc(sizeof(struct qla_work_evt), locked ? GFP_ATOMIC:
-	    GFP_KERNEL);
+	e = kzalloc(sizeof(struct qla_work_evt), GFP_ATOMIC);
 	if (!e)
 		return NULL;
 
@@ -2437,17 +2558,15 @@
 }
 
 static int
-qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e, int locked)
+qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e)
 {
-	unsigned long uninitialized_var(flags);
-	struct qla_hw_data *ha = vha->hw;
+	unsigned long flags;
 
-	if (!locked)
-		spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&vha->work_lock, flags);
 	list_add_tail(&e->list, &vha->work_list);
+	spin_unlock_irqrestore(&vha->work_lock, flags);
 	qla2xxx_wake_dpc(vha);
-	if (!locked)
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
 	return QLA_SUCCESS;
 }
 
@@ -2457,13 +2576,13 @@
 {
 	struct qla_work_evt *e;
 
-	e = qla2x00_alloc_work(vha, QLA_EVT_AEN, 1);
+	e = qla2x00_alloc_work(vha, QLA_EVT_AEN);
 	if (!e)
 		return QLA_FUNCTION_FAILED;
 
 	e->u.aen.code = code;
 	e->u.aen.data = data;
-	return qla2x00_post_work(vha, e, 1);
+	return qla2x00_post_work(vha, e);
 }
 
 int
@@ -2471,25 +2590,27 @@
 {
 	struct qla_work_evt *e;
 
-	e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK, 1);
+	e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK);
 	if (!e)
 		return QLA_FUNCTION_FAILED;
 
 	memcpy(e->u.idc_ack.mb, mb, QLA_IDC_ACK_REGS * sizeof(uint16_t));
-	return qla2x00_post_work(vha, e, 1);
+	return qla2x00_post_work(vha, e);
 }
 
 static void
 qla2x00_do_work(struct scsi_qla_host *vha)
 {
-	struct qla_work_evt *e;
-	struct qla_hw_data *ha = vha->hw;
+	struct qla_work_evt *e, *tmp;
+	unsigned long flags;
+	LIST_HEAD(work);
 
-	spin_lock_irq(&ha->hardware_lock);
-	while (!list_empty(&vha->work_list)) {
-		e = list_entry(vha->work_list.next, struct qla_work_evt, list);
+	spin_lock_irqsave(&vha->work_lock, flags);
+	list_splice_init(&vha->work_list, &work);
+	spin_unlock_irqrestore(&vha->work_lock, flags);
+
+	list_for_each_entry_safe(e, tmp, &work, list) {
 		list_del_init(&e->list);
-		spin_unlock_irq(&ha->hardware_lock);
 
 		switch (e->type) {
 		case QLA_EVT_AEN:
@@ -2502,10 +2623,9 @@
 		}
 		if (e->flags & QLA_EVT_FLAG_FREE)
 			kfree(e);
-		spin_lock_irq(&ha->hardware_lock);
 	}
-	spin_unlock_irq(&ha->hardware_lock);
 }
+
 /* Relogins all the fcports of a vport
  * Context: dpc thread
  */
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 152ecfc..6260505 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -219,8 +219,8 @@
 	wait_cnt = NVR_WAIT_CNT;
 	do {
 		if (!--wait_cnt) {
-			DEBUG9_10(printk("%s(%ld): NVRAM didn't go ready...\n",
-			    __func__, vha->host_no));
+			DEBUG9_10(qla_printk(KERN_WARNING, ha,
+			    "NVRAM didn't go ready...\n"));
 			break;
 		}
 		NVRAM_DELAY();
@@ -349,7 +349,7 @@
 		wait_cnt = NVR_WAIT_CNT;
 		do {
 			if (!--wait_cnt) {
-				DEBUG9_10(qla_printk(
+				DEBUG9_10(qla_printk(KERN_WARNING, ha,
 				    "NVRAM didn't go ready...\n"));
 				break;
 			}
@@ -408,7 +408,8 @@
 	wait_cnt = NVR_WAIT_CNT;
 	do {
 		if (!--wait_cnt) {
-			DEBUG9_10(qla_printk("NVRAM didn't go ready...\n"));
+			DEBUG9_10(qla_printk(KERN_WARNING, ha,
+			    "NVRAM didn't go ready...\n"));
 			break;
 		}
 		NVRAM_DELAY();
@@ -701,32 +702,35 @@
 			break;
 		case FLT_REG_VPD_0:
 			ha->flt_region_vpd_nvram = start;
-			if (!(PCI_FUNC(ha->pdev->devfn) & 1))
+			if (ha->flags.port0)
 				ha->flt_region_vpd = start;
 			break;
 		case FLT_REG_VPD_1:
-			if (PCI_FUNC(ha->pdev->devfn) & 1)
+			if (!ha->flags.port0)
 				ha->flt_region_vpd = start;
 			break;
 		case FLT_REG_NVRAM_0:
-			if (!(PCI_FUNC(ha->pdev->devfn) & 1))
+			if (ha->flags.port0)
 				ha->flt_region_nvram = start;
 			break;
 		case FLT_REG_NVRAM_1:
-			if (PCI_FUNC(ha->pdev->devfn) & 1)
+			if (!ha->flags.port0)
 				ha->flt_region_nvram = start;
 			break;
 		case FLT_REG_FDT:
 			ha->flt_region_fdt = start;
 			break;
 		case FLT_REG_NPIV_CONF_0:
-			if (!(PCI_FUNC(ha->pdev->devfn) & 1))
+			if (ha->flags.port0)
 				ha->flt_region_npiv_conf = start;
 			break;
 		case FLT_REG_NPIV_CONF_1:
-			if (PCI_FUNC(ha->pdev->devfn) & 1)
+			if (!ha->flags.port0)
 				ha->flt_region_npiv_conf = start;
 			break;
+		case FLT_REG_GOLD_FW:
+			ha->flt_region_gold_fw = start;
+			break;
 		}
 	}
 	goto done;
@@ -744,12 +748,12 @@
 	ha->flt_region_fw = def_fw[def];
 	ha->flt_region_boot = def_boot[def];
 	ha->flt_region_vpd_nvram = def_vpd_nvram[def];
-	ha->flt_region_vpd = !(PCI_FUNC(ha->pdev->devfn) & 1) ?
+	ha->flt_region_vpd = ha->flags.port0 ?
 	    def_vpd0[def]: def_vpd1[def];
-	ha->flt_region_nvram = !(PCI_FUNC(ha->pdev->devfn) & 1) ?
+	ha->flt_region_nvram = ha->flags.port0 ?
 	    def_nvram0[def]: def_nvram1[def];
 	ha->flt_region_fdt = def_fdt[def];
-	ha->flt_region_npiv_conf = !(PCI_FUNC(ha->pdev->devfn) & 1) ?
+	ha->flt_region_npiv_conf = ha->flags.port0 ?
 	    def_npiv_conf0[def]: def_npiv_conf1[def];
 done:
 	DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x "
@@ -924,6 +928,8 @@
 		struct fc_vport_identifiers vid;
 		struct fc_vport *vport;
 
+		memcpy(&ha->npiv_info[i], entry, sizeof(struct qla_npiv_entry));
+
 		flags = le16_to_cpu(entry->flags);
 		if (flags == 0xffff)
 			continue;
@@ -937,9 +943,7 @@
 		vid.port_name = wwn_to_u64(entry->port_name);
 		vid.node_name = wwn_to_u64(entry->node_name);
 
-		memcpy(&ha->npiv_info[i], entry, sizeof(struct qla_npiv_entry));
-
-		DEBUG2(qla_printk(KERN_DEBUG, ha, "NPIV[%02x]: wwpn=%llx "
+		DEBUG2(qla_printk(KERN_INFO, ha, "NPIV[%02x]: wwpn=%llx "
 			"wwnn=%llx vf_id=0x%x Q_qos=0x%x F_qos=0x%x.\n", cnt,
 			vid.port_name, vid.node_name, le16_to_cpu(entry->vf_id),
 			entry->q_qos, entry->f_qos));
@@ -955,7 +959,6 @@
 	}
 done:
 	kfree(data);
-	ha->npiv_info = NULL;
 }
 
 static int
@@ -1079,8 +1082,9 @@
 				    0xff0000) | ((fdata >> 16) & 0xff));
 			ret = qla24xx_erase_sector(vha, fdata);
 			if (ret != QLA_SUCCESS) {
-				DEBUG9(qla_printk("Unable to erase sector: "
-				    "address=%x.\n", faddr));
+				DEBUG9(qla_printk(KERN_WARNING, ha,
+				    "Unable to erase sector: address=%x.\n",
+				    faddr));
 				break;
 			}
 		}
@@ -1240,8 +1244,9 @@
 		ret = qla24xx_write_flash_dword(ha,
 		    nvram_data_addr(ha, naddr), cpu_to_le32(*dwptr));
 		if (ret != QLA_SUCCESS) {
-			DEBUG9(qla_printk("Unable to program nvram address=%x "
-			    "data=%x.\n", naddr, *dwptr));
+			DEBUG9(qla_printk(KERN_WARNING, ha,
+			    "Unable to program nvram address=%x data=%x.\n",
+			    naddr, *dwptr));
 			break;
 		}
 	}
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 19d1afc..b63feaf 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.03.01-k1"
+#define QLA2XXX_VERSION      "8.03.01-k3"
 
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MINOR_VER	3
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 166417a..2de5f3a 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1225,8 +1225,8 @@
  * @starget:	SCSI target pointer
  * @lun:	SCSI Logical Unit Number
  *
- * Description: Looks up the scsi_device with the specified @channel, @id, @lun
- * for a given host.  The returned scsi_device has an additional reference that
+ * Description: Looks up the scsi_device with the specified @lun for a given
+ * @starget.  The returned scsi_device has an additional reference that
  * needs to be released with scsi_device_put once you're done with it.
  **/
 struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 213123b..41a2177 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -887,7 +887,7 @@
 static sector_t get_sdebug_capacity(void)
 {
 	if (scsi_debug_virtual_gb > 0)
-		return 2048 * 1024 * scsi_debug_virtual_gb;
+		return 2048 * 1024 * (sector_t)scsi_debug_virtual_gb;
 	else
 		return sdebug_store_sectors;
 }
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 0c2c73b..a168935 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -641,9 +641,9 @@
 /**
  * scsi_eh_restore_cmnd  - Restore a scsi command info as part of error recory
  * @scmd:       SCSI command structure to restore
- * @ses:        saved information from a coresponding call to scsi_prep_eh_cmnd
+ * @ses:        saved information from a coresponding call to scsi_eh_prep_cmnd
  *
- * Undo any damage done by above scsi_prep_eh_cmnd().
+ * Undo any damage done by above scsi_eh_prep_cmnd().
  */
 void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
 {
@@ -1451,28 +1451,21 @@
  * @sdev:	SCSI device to prevent medium removal
  *
  * Locking:
- * 	We must be called from process context; scsi_allocate_request()
- * 	may sleep.
+ * 	We must be called from process context.
  *
  * Notes:
  * 	We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request on the
  * 	head of the devices request queue, and continue.
- *
- * Bugs:
- * 	scsi_allocate_request() may sleep waiting for existing requests to
- * 	be processed.  However, since we haven't kicked off any request
- * 	processing for this host, this may deadlock.
- *
- *	If scsi_allocate_request() fails for what ever reason, we
- *	completely forget to lock the door.
  */
 static void scsi_eh_lock_door(struct scsi_device *sdev)
 {
 	struct request *req;
 
+	/*
+	 * blk_get_request with GFP_KERNEL (__GFP_WAIT) sleeps until a
+	 * request becomes available
+	 */
 	req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL);
-	if (!req)
-		return;
 
 	req->cmd[0] = ALLOW_MEDIUM_REMOVAL;
 	req->cmd[1] = 0;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index dd3f9d2..30f3275 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2412,20 +2412,18 @@
 scsi_internal_device_unblock(struct scsi_device *sdev)
 {
 	struct request_queue *q = sdev->request_queue; 
-	int err;
 	unsigned long flags;
 	
 	/* 
 	 * Try to transition the scsi device to SDEV_RUNNING
 	 * and goose the device queue if successful.  
 	 */
-	err = scsi_device_set_state(sdev, SDEV_RUNNING);
-	if (err) {
-		err = scsi_device_set_state(sdev, SDEV_CREATED);
-
-		if (err)
-			return err;
-	}
+	if (sdev->sdev_state == SDEV_BLOCK)
+		sdev->sdev_state = SDEV_RUNNING;
+	else if (sdev->sdev_state == SDEV_CREATED_BLOCK)
+		sdev->sdev_state = SDEV_CREATED;
+	else
+		return -EINVAL;
 
 	spin_lock_irqsave(q->queue_lock, flags);
 	blk_start_queue(q);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index e2b50d8..c447838 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -115,12 +115,12 @@
 		 "REPORT LUNS maximum number of LUNS received (should be"
 		 " between 1 and 16384)");
 
-static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ+3;
+static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ + 18;
 
 module_param_named(inq_timeout, scsi_inq_timeout, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(inq_timeout, 
 		 "Timeout (in seconds) waiting for devices to answer INQUIRY."
-		 " Default is 5. Some non-compliant devices need more.");
+		 " Default is 20. Some devices may need more; most need less.");
 
 /* This lock protects only this list */
 static DEFINE_SPINLOCK(async_scan_lock);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 0a2ce7b..f3e6646 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -37,7 +37,6 @@
 #define ISCSI_TRANSPORT_VERSION "2.0-870"
 
 struct iscsi_internal {
-	int daemon_pid;
 	struct scsi_transport_template t;
 	struct iscsi_transport *iscsi_transport;
 	struct list_head list;
@@ -938,23 +937,9 @@
 }
 
 static int
-iscsi_broadcast_skb(struct sk_buff *skb, gfp_t gfp)
+iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp)
 {
-	return netlink_broadcast(nls, skb, 0, 1, gfp);
-}
-
-static int
-iscsi_unicast_skb(struct sk_buff *skb, int pid)
-{
-	int rc;
-
-	rc = netlink_unicast(nls, skb, pid, MSG_DONTWAIT);
-	if (rc < 0) {
-		printk(KERN_ERR "iscsi: can not unicast skb (%d)\n", rc);
-		return rc;
-	}
-
-	return 0;
+	return nlmsg_multicast(nls, skb, 0, group, gfp);
 }
 
 int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
@@ -980,7 +965,7 @@
 		return -ENOMEM;
 	}
 
-	nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
+	nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
 	ev = NLMSG_DATA(nlh);
 	memset(ev, 0, sizeof(*ev));
 	ev->transport_handle = iscsi_handle(conn->transport);
@@ -991,10 +976,45 @@
 	memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
 	memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);
 
-	return iscsi_unicast_skb(skb, priv->daemon_pid);
+	return iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
 }
 EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
 
+int iscsi_offload_mesg(struct Scsi_Host *shost,
+		       struct iscsi_transport *transport, uint32_t type,
+		       char *data, uint16_t data_size)
+{
+	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 "can not deliver iscsi offload message:OOM\n");
+		return -ENOMEM;
+	}
+
+	nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
+	ev = NLMSG_DATA(nlh);
+	memset(ev, 0, sizeof(*ev));
+	ev->type = type;
+	ev->transport_handle = iscsi_handle(transport);
+	switch (type) {
+	case ISCSI_KEVENT_PATH_REQ:
+		ev->r.req_path.host_no = shost->host_no;
+		break;
+	case ISCSI_KEVENT_IF_DOWN:
+		ev->r.notify_if_down.host_no = shost->host_no;
+		break;
+	}
+
+	memcpy((char *)ev + sizeof(*ev), data, data_size);
+
+	return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_NOIO);
+}
+EXPORT_SYMBOL_GPL(iscsi_offload_mesg);
+
 void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
 {
 	struct nlmsghdr	*nlh;
@@ -1014,7 +1034,7 @@
 		return;
 	}
 
-	nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
+	nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
 	ev = NLMSG_DATA(nlh);
 	ev->transport_handle = iscsi_handle(conn->transport);
 	ev->type = ISCSI_KEVENT_CONN_ERROR;
@@ -1022,7 +1042,7 @@
 	ev->r.connerror.cid = conn->cid;
 	ev->r.connerror.sid = iscsi_conn_get_sid(conn);
 
-	iscsi_broadcast_skb(skb, GFP_ATOMIC);
+	iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
 
 	iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n",
 			      error);
@@ -1030,8 +1050,8 @@
 EXPORT_SYMBOL_GPL(iscsi_conn_error_event);
 
 static int
-iscsi_if_send_reply(int pid, int seq, int type, int done, int multi,
-		      void *payload, int size)
+iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
+		    void *payload, int size)
 {
 	struct sk_buff	*skb;
 	struct nlmsghdr	*nlh;
@@ -1045,10 +1065,10 @@
 		return -ENOMEM;
 	}
 
-	nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0);
+	nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0);
 	nlh->nlmsg_flags = flags;
 	memcpy(NLMSG_DATA(nlh), payload, size);
-	return iscsi_unicast_skb(skb, pid);
+	return iscsi_multicast_skb(skb, group, GFP_ATOMIC);
 }
 
 static int
@@ -1085,7 +1105,7 @@
 			return -ENOMEM;
 		}
 
-		nlhstat = __nlmsg_put(skbstat, priv->daemon_pid, 0, 0,
+		nlhstat = __nlmsg_put(skbstat, 0, 0, 0,
 				      (len - sizeof(*nlhstat)), 0);
 		evstat = NLMSG_DATA(nlhstat);
 		memset(evstat, 0, sizeof(*evstat));
@@ -1109,7 +1129,8 @@
 		skb_trim(skbstat, NLMSG_ALIGN(actual_size));
 		nlhstat->nlmsg_len = actual_size;
 
-		err = iscsi_unicast_skb(skbstat, priv->daemon_pid);
+		err = iscsi_multicast_skb(skbstat, ISCSI_NL_GRP_ISCSID,
+					  GFP_ATOMIC);
 	} while (err < 0 && err != -ECONNREFUSED);
 
 	return err;
@@ -1143,7 +1164,7 @@
 		return -ENOMEM;
 	}
 
-	nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
+	nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
 	ev = NLMSG_DATA(nlh);
 	ev->transport_handle = iscsi_handle(session->transport);
 
@@ -1172,7 +1193,7 @@
 	 * this will occur if the daemon is not up, so we just warn
 	 * the user and when the daemon is restarted it will handle it
 	 */
-	rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
+	rc = iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_KERNEL);
 	if (rc == -ESRCH)
 		iscsi_cls_session_printk(KERN_ERR, session,
 					 "Cannot notify userspace of session "
@@ -1268,26 +1289,54 @@
 	return err;
 }
 
+static int iscsi_if_ep_connect(struct iscsi_transport *transport,
+			       struct iscsi_uevent *ev, int msg_type)
+{
+	struct iscsi_endpoint *ep;
+	struct sockaddr *dst_addr;
+	struct Scsi_Host *shost = NULL;
+	int non_blocking, err = 0;
+
+	if (!transport->ep_connect)
+		return -EINVAL;
+
+	if (msg_type == ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST) {
+		shost = scsi_host_lookup(ev->u.ep_connect_through_host.host_no);
+		if (!shost) {
+			printk(KERN_ERR "ep connect failed. Could not find "
+			       "host no %u\n",
+			       ev->u.ep_connect_through_host.host_no);
+			return -ENODEV;
+		}
+		non_blocking = ev->u.ep_connect_through_host.non_blocking;
+	} else
+		non_blocking = ev->u.ep_connect.non_blocking;
+
+	dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
+	ep = transport->ep_connect(shost, dst_addr, non_blocking);
+	if (IS_ERR(ep)) {
+		err = PTR_ERR(ep);
+		goto release_host;
+	}
+
+	ev->r.ep_connect_ret.handle = ep->id;
+release_host:
+	if (shost)
+		scsi_host_put(shost);
+	return err;
+}
+
 static int
 iscsi_if_transport_ep(struct iscsi_transport *transport,
 		      struct iscsi_uevent *ev, int msg_type)
 {
 	struct iscsi_endpoint *ep;
-	struct sockaddr *dst_addr;
 	int rc = 0;
 
 	switch (msg_type) {
+	case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
 	case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
-		if (!transport->ep_connect)
-			return -EINVAL;
-
-		dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
-		ep = transport->ep_connect(dst_addr,
-					   ev->u.ep_connect.non_blocking);
-		if (IS_ERR(ep))
-			return PTR_ERR(ep);
-
-		ev->r.ep_connect_ret.handle = ep->id;
+		rc = iscsi_if_ep_connect(transport, ev, msg_type);
 		break;
 	case ISCSI_UEVENT_TRANSPORT_EP_POLL:
 		if (!transport->ep_poll)
@@ -1365,7 +1414,31 @@
 }
 
 static int
-iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev)
+{
+	struct Scsi_Host *shost;
+	struct iscsi_path *params;
+	int err;
+
+	if (!transport->set_path)
+		return -ENOSYS;
+
+	shost = scsi_host_lookup(ev->u.set_path.host_no);
+	if (!shost) {
+		printk(KERN_ERR "set path could not find host no %u\n",
+		       ev->u.set_path.host_no);
+		return -ENODEV;
+	}
+
+	params = (struct iscsi_path *)((char *)ev + sizeof(*ev));
+	err = transport->set_path(shost, params);
+
+	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;
 	struct iscsi_uevent *ev = NLMSG_DATA(nlh);
@@ -1375,6 +1448,11 @@
 	struct iscsi_cls_conn *conn;
 	struct iscsi_endpoint *ep = NULL;
 
+	if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE)
+		*group = ISCSI_NL_GRP_UIP;
+	else
+		*group = ISCSI_NL_GRP_ISCSID;
+
 	priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
 	if (!priv)
 		return -EINVAL;
@@ -1383,8 +1461,6 @@
 	if (!try_module_get(transport->owner))
 		return -EINVAL;
 
-	priv->daemon_pid = NETLINK_CREDS(skb)->pid;
-
 	switch (nlh->nlmsg_type) {
 	case ISCSI_UEVENT_CREATE_SESSION:
 		err = iscsi_if_create_session(priv, ep, ev,
@@ -1469,6 +1545,7 @@
 	case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
 	case ISCSI_UEVENT_TRANSPORT_EP_POLL:
 	case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
+	case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
 		err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type);
 		break;
 	case ISCSI_UEVENT_TGT_DSCVR:
@@ -1477,6 +1554,9 @@
 	case ISCSI_UEVENT_SET_HOST_PARAM:
 		err = iscsi_set_host_param(transport, ev);
 		break;
+	case ISCSI_UEVENT_PATH_UPDATE:
+		err = iscsi_set_path(transport, ev);
+		break;
 	default:
 		err = -ENOSYS;
 		break;
@@ -1499,6 +1579,7 @@
 		uint32_t rlen;
 		struct nlmsghdr	*nlh;
 		struct iscsi_uevent *ev;
+		uint32_t group;
 
 		nlh = nlmsg_hdr(skb);
 		if (nlh->nlmsg_len < sizeof(*nlh) ||
@@ -1511,7 +1592,7 @@
 		if (rlen > skb->len)
 			rlen = skb->len;
 
-		err = iscsi_if_recv_msg(skb, nlh);
+		err = iscsi_if_recv_msg(skb, nlh, &group);
 		if (err) {
 			ev->type = ISCSI_KEVENT_IF_ERROR;
 			ev->iferror = err;
@@ -1525,8 +1606,7 @@
 			 */
 			if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
 				break;
-			err = iscsi_if_send_reply(
-				NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
+			err = iscsi_if_send_reply(group, nlh->nlmsg_seq,
 				nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
 		} while (err < 0 && err != -ECONNREFUSED);
 		skb_pull(skb, rlen);
@@ -1774,7 +1854,6 @@
 	if (!priv)
 		return NULL;
 	INIT_LIST_HEAD(&priv->list);
-	priv->daemon_pid = -1;
 	priv->iscsi_transport = tt;
 	priv->t.user_scan = iscsi_user_scan;
 	priv->t.create_work_queue = 1;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index bcf3bd4..878b17a 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1902,24 +1902,6 @@
 	index = sdkp->index;
 	dev = &sdp->sdev_gendev;
 
-	if (!sdp->request_queue->rq_timeout) {
-		if (sdp->type != TYPE_MOD)
-			blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
-		else
-			blk_queue_rq_timeout(sdp->request_queue,
-					     SD_MOD_TIMEOUT);
-	}
-
-	device_initialize(&sdkp->dev);
-	sdkp->dev.parent = &sdp->sdev_gendev;
-	sdkp->dev.class = &sd_disk_class;
-	dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev));
-
-	if (device_add(&sdkp->dev))
-		goto out_free_index;
-
-	get_device(&sdp->sdev_gendev);
-
 	if (index < SD_MAX_DISKS) {
 		gd->major = sd_major((index & 0xf0) >> 4);
 		gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
@@ -1954,11 +1936,6 @@
 
 	sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
 		  sdp->removable ? "removable " : "");
-
-	return;
-
- out_free_index:
-	ida_remove(&sd_index_ida, index);
 }
 
 /**
@@ -2026,6 +2003,24 @@
 	sdkp->openers = 0;
 	sdkp->previous_state = 1;
 
+	if (!sdp->request_queue->rq_timeout) {
+		if (sdp->type != TYPE_MOD)
+			blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
+		else
+			blk_queue_rq_timeout(sdp->request_queue,
+					     SD_MOD_TIMEOUT);
+	}
+
+	device_initialize(&sdkp->dev);
+	sdkp->dev.parent = &sdp->sdev_gendev;
+	sdkp->dev.class = &sd_disk_class;
+	dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev));
+
+	if (device_add(&sdkp->dev))
+		goto out_free_index;
+
+	get_device(&sdp->sdev_gendev);
+
 	async_schedule(sd_probe_async, sdkp);
 
 	return 0;
@@ -2055,8 +2050,10 @@
  **/
 static int sd_remove(struct device *dev)
 {
-	struct scsi_disk *sdkp = dev_get_drvdata(dev);
+	struct scsi_disk *sdkp;
 
+	async_synchronize_full();
+	sdkp = dev_get_drvdata(dev);
 	device_del(&sdkp->dev);
 	del_gendisk(sdkp->disk);
 	sd_shutdown(dev);
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 89bd438..b33d042 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -2964,7 +2964,7 @@
 			    !(STp->use_pf & PF_TESTED)) {
 				/* Try the other possible state of Page Format if not
 				   already tried */
-				STp->use_pf = !STp->use_pf | PF_TESTED;
+				STp->use_pf = (STp->use_pf ^ USE_PF) | PF_TESTED;
 				st_release_request(SRpnt);
 				SRpnt = NULL;
 				return st_int_ioctl(STp, cmd_in, arg);
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 583966e..45374d6 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -737,11 +737,14 @@
 	struct sym_hcb *np = sym_get_hcb(sdev->host);
 	struct sym_tcb *tp = &np->target[sdev->id];
 	struct sym_lcb *lp;
+	unsigned long flags;
+	int error;
 
 	if (sdev->id >= SYM_CONF_MAX_TARGET || sdev->lun >= SYM_CONF_MAX_LUN)
 		return -ENXIO;
 
-	tp->starget = sdev->sdev_target;
+	spin_lock_irqsave(np->s.host->host_lock, flags);
+
 	/*
 	 * Fail the device init if the device is flagged NOSCAN at BOOT in
 	 * the NVRAM.  This may speed up boot and maintain coherency with
@@ -753,26 +756,37 @@
 
 	if (tp->usrflags & SYM_SCAN_BOOT_DISABLED) {
 		tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED;
-		starget_printk(KERN_INFO, tp->starget,
+		starget_printk(KERN_INFO, sdev->sdev_target,
 				"Scan at boot disabled in NVRAM\n");
-		return -ENXIO;
+		error = -ENXIO;
+		goto out;
 	}
 
 	if (tp->usrflags & SYM_SCAN_LUNS_DISABLED) {
-		if (sdev->lun != 0)
-			return -ENXIO;
-		starget_printk(KERN_INFO, tp->starget,
+		if (sdev->lun != 0) {
+			error = -ENXIO;
+			goto out;
+		}
+		starget_printk(KERN_INFO, sdev->sdev_target,
 				"Multiple LUNs disabled in NVRAM\n");
 	}
 
 	lp = sym_alloc_lcb(np, sdev->id, sdev->lun);
-	if (!lp)
-		return -ENOMEM;
+	if (!lp) {
+		error = -ENOMEM;
+		goto out;
+	}
+	if (tp->nlcb == 1)
+		tp->starget = sdev->sdev_target;
 
 	spi_min_period(tp->starget) = tp->usr_period;
 	spi_max_width(tp->starget) = tp->usr_width;
 
-	return 0;
+	error = 0;
+out:
+	spin_unlock_irqrestore(np->s.host->host_lock, flags);
+
+	return error;
 }
 
 /*
@@ -819,12 +833,34 @@
 static void sym53c8xx_slave_destroy(struct scsi_device *sdev)
 {
 	struct sym_hcb *np = sym_get_hcb(sdev->host);
-	struct sym_lcb *lp = sym_lp(&np->target[sdev->id], sdev->lun);
+	struct sym_tcb *tp = &np->target[sdev->id];
+	struct sym_lcb *lp = sym_lp(tp, sdev->lun);
+	unsigned long flags;
 
-	if (lp->itlq_tbl)
-		sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK * 4, "ITLQ_TBL");
-	kfree(lp->cb_tags);
-	sym_mfree_dma(lp, sizeof(*lp), "LCB");
+	spin_lock_irqsave(np->s.host->host_lock, flags);
+
+	if (lp->busy_itlq || lp->busy_itl) {
+		/*
+		 * This really shouldn't happen, but we can't return an error
+		 * so let's try to stop all on-going I/O.
+		 */
+		starget_printk(KERN_WARNING, tp->starget,
+			       "Removing busy LCB (%d)\n", sdev->lun);
+		sym_reset_scsi_bus(np, 1);
+	}
+
+	if (sym_free_lcb(np, sdev->id, sdev->lun) == 0) {
+		/*
+		 * It was the last unit for this target.
+		 */
+		tp->head.sval        = 0;
+		tp->head.wval        = np->rv_scntl3;
+		tp->head.uval        = 0;
+		tp->tgoal.check_nego = 1;
+		tp->starget	     = NULL;
+	}
+
+	spin_unlock_irqrestore(np->s.host->host_lock, flags);
 }
 
 /*
@@ -890,6 +926,8 @@
 			if (!((uc->target >> t) & 1))
 				continue;
 			tp = &np->target[t];
+			if (!tp->nlcb)
+				continue;
 
 			switch (uc->cmd) {
 
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
index ffa70d1..69ad494 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c
@@ -1896,6 +1896,15 @@
 		tp->head.sval = 0;
 		tp->head.wval = np->rv_scntl3;
 		tp->head.uval = 0;
+		if (tp->lun0p)
+			tp->lun0p->to_clear = 0;
+		if (tp->lunmp) {
+			int ln;
+
+			for (ln = 1; ln < SYM_CONF_MAX_LUN; ln++)
+				if (tp->lunmp[ln])
+					tp->lunmp[ln]->to_clear = 0;
+		}
 	}
 
 	/*
@@ -4988,7 +4997,7 @@
 	 */
 	if (ln && !tp->lunmp) {
 		tp->lunmp = kcalloc(SYM_CONF_MAX_LUN, sizeof(struct sym_lcb *),
-				GFP_KERNEL);
+				GFP_ATOMIC);
 		if (!tp->lunmp)
 			goto fail;
 	}
@@ -5008,6 +5017,7 @@
 		tp->lun0p = lp;
 		tp->head.lun0_sa = cpu_to_scr(vtobus(lp));
 	}
+	tp->nlcb++;
 
 	/*
 	 *  Let the itl task point to error handling.
@@ -5085,6 +5095,43 @@
 }
 
 /*
+ *  Lun control block deallocation. Returns the number of valid remaing LCBs
+ *  for the target.
+ */
+int sym_free_lcb(struct sym_hcb *np, u_char tn, u_char ln)
+{
+	struct sym_tcb *tp = &np->target[tn];
+	struct sym_lcb *lp = sym_lp(tp, ln);
+
+	tp->nlcb--;
+
+	if (ln) {
+		if (!tp->nlcb) {
+			kfree(tp->lunmp);
+			sym_mfree_dma(tp->luntbl, 256, "LUNTBL");
+			tp->lunmp = NULL;
+			tp->luntbl = NULL;
+			tp->head.luntbl_sa = cpu_to_scr(vtobus(np->badluntbl));
+		} else {
+			tp->luntbl[ln] = cpu_to_scr(vtobus(&np->badlun_sa));
+			tp->lunmp[ln] = NULL;
+		}
+	} else {
+		tp->lun0p = NULL;
+		tp->head.lun0_sa = cpu_to_scr(vtobus(&np->badlun_sa));
+	}
+
+	if (lp->itlq_tbl) {
+		sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL");
+		kfree(lp->cb_tags);
+	}
+
+	sym_mfree_dma(lp, sizeof(*lp), "LCB");
+
+	return tp->nlcb;
+}
+
+/*
  *  Queue a SCSI IO to the controller.
  */
 int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp)
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h
index 9ebc870..053e63c 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.h
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h
@@ -401,6 +401,7 @@
 	 *  An array of bus addresses is used on reselection.
 	 */
 	u32	*luntbl;	/* LCBs bus address table	*/
+	int	nlcb;		/* Number of valid LCBs (including LUN #0) */
 
 	/*
 	 *  LUN table used by the C code.
@@ -1065,6 +1066,7 @@
 struct sym_ccb *sym_get_ccb(struct sym_hcb *np, struct scsi_cmnd *cmd, u_char tag_order);
 void sym_free_ccb(struct sym_hcb *np, struct sym_ccb *cp);
 struct sym_lcb *sym_alloc_lcb(struct sym_hcb *np, u_char tn, u_char ln);
+int sym_free_lcb(struct sym_hcb *np, u_char tn, u_char ln);
 int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *csio, struct sym_ccb *cp);
 int sym_abort_scsiio(struct sym_hcb *np, struct scsi_cmnd *ccb, int timed_out);
 int sym_reset_scsi_target(struct sym_hcb *np, int target);
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index cdc049d..58a4879 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -686,7 +686,7 @@
 		goto out;
 	}
 
-	base = ioremap(dev->res.start, PAGE_SIZE);
+	base = ioremap(dev->res.start, resource_size(&dev->res));
 	if (!base) {
 		ret = -ENOMEM;
 		goto free;
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 88fdac5..bf82e28 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -70,6 +70,23 @@
 	struct clk		*clk;
 	unsigned int		im;	/* interrupt mask */
 	unsigned int		old_status;
+	unsigned int		ifls;	/* vendor-specific */
+};
+
+/* There is by now at least one vendor with differing details, so handle it */
+struct vendor_data {
+	unsigned int		ifls;
+	unsigned int		fifosize;
+};
+
+static struct vendor_data vendor_arm = {
+	.ifls			= UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
+	.fifosize		= 16,
+};
+
+static struct vendor_data vendor_st = {
+	.ifls			= UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
+	.fifosize		= 64,
 };
 
 static void pl011_stop_tx(struct uart_port *port)
@@ -360,8 +377,7 @@
 	if (retval)
 		goto clk_dis;
 
-	writew(UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
-	       uap->port.membase + UART011_IFLS);
+	writew(uap->ifls, uap->port.membase + UART011_IFLS);
 
 	/*
 	 * Provoke TX FIFO interrupt into asserting.
@@ -732,6 +748,7 @@
 static int pl011_probe(struct amba_device *dev, struct amba_id *id)
 {
 	struct uart_amba_port *uap;
+	struct vendor_data *vendor = id->data;
 	void __iomem *base;
 	int i, ret;
 
@@ -750,7 +767,7 @@
 		goto out;
 	}
 
-	base = ioremap(dev->res.start, PAGE_SIZE);
+	base = ioremap(dev->res.start, resource_size(&dev->res));
 	if (!base) {
 		ret = -ENOMEM;
 		goto free;
@@ -762,12 +779,13 @@
 		goto unmap;
 	}
 
+	uap->ifls = vendor->ifls;
 	uap->port.dev = &dev->dev;
 	uap->port.mapbase = dev->res.start;
 	uap->port.membase = base;
 	uap->port.iotype = UPIO_MEM;
 	uap->port.irq = dev->irq[0];
-	uap->port.fifosize = 16;
+	uap->port.fifosize = vendor->fifosize;
 	uap->port.ops = &amba_pl011_pops;
 	uap->port.flags = UPF_BOOT_AUTOCONF;
 	uap->port.line = i;
@@ -812,6 +830,12 @@
 	{
 		.id	= 0x00041011,
 		.mask	= 0x000fffff,
+		.data	= &vendor_arm,
+	},
+	{
+		.id	= 0x00380802,
+		.mask	= 0x00ffffff,
+		.data	= &vendor_st,
 	},
 	{ 0, 0 },
 };
@@ -845,7 +869,11 @@
 	uart_unregister_driver(&amba_reg);
 }
 
-module_init(pl011_init);
+/*
+ * While this can be a module, if builtin it's most likely the console
+ * So let's leave module_exit but move module_init to an earlier place
+ */
+arch_initcall(pl011_init);
 module_exit(pl011_exit);
 
 MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 7b5d1de..285b414 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -71,7 +71,7 @@
 #define ONEMS 0xb0 /* One Millisecond register */
 #define UTS   0xb4 /* UART Test Register */
 #endif
-#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1)
+#ifdef CONFIG_ARCH_MX1
 #define BIPR1 0xb0 /* Incremental Preset Register 1 */
 #define BIPR2 0xb4 /* Incremental Preset Register 2 */
 #define BIPR3 0xb8 /* Incremental Preset Register 3 */
@@ -101,7 +101,7 @@
 #define  UCR1_RTSDEN     (1<<5)	 /* RTS delta interrupt enable */
 #define  UCR1_SNDBRK     (1<<4)	 /* Send break */
 #define  UCR1_TDMAEN     (1<<3)	 /* Transmitter ready DMA enable */
-#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1)
+#ifdef CONFIG_ARCH_MX1
 #define  UCR1_UARTCLKEN  (1<<2)	 /* UART clock enabled */
 #endif
 #if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2
@@ -132,7 +132,7 @@
 #define  UCR3_RXDSEN	 (1<<6)  /* Receive status interrupt enable */
 #define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
 #define  UCR3_AWAKEN	 (1<<4)  /* Async wake interrupt enable */
-#ifdef CONFIG_ARCH_IMX
+#ifdef CONFIG_ARCH_MX1
 #define  UCR3_REF25 	 (1<<3)  /* Ref freq 25 MHz, only on mx1 */
 #define  UCR3_REF30 	 (1<<2)  /* Ref Freq 30 MHz, only on mx1 */
 #endif
@@ -186,13 +186,6 @@
 #define  UTS_SOFTRST	 (1<<0)	 /* Software reset */
 
 /* We've been assigned a range on the "Low-density serial ports" major */
-#ifdef CONFIG_ARCH_IMX
-#define SERIAL_IMX_MAJOR	204
-#define MINOR_START		41
-#define DEV_NAME		"ttySMX"
-#define MAX_INTERNAL_IRQ	IMX_IRQS
-#endif
-
 #ifdef CONFIG_ARCH_MXC
 #define SERIAL_IMX_MAJOR        207
 #define MINOR_START	        16
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 83a185d..e8aae22 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -118,7 +118,7 @@
 
 config SPI_IMX
 	tristate "Freescale iMX SPI controller"
-	depends on ARCH_IMX && EXPERIMENTAL
+	depends on ARCH_MX1 && EXPERIMENTAL
 	help
 	  This enables using the Freescale iMX SPI controller in master
 	  mode.
@@ -171,6 +171,15 @@
 	help
 	  This enables using the SPI master controller on the Orion chips.
 
+config SPI_PL022
+	tristate "ARM AMBA PL022 SSP controller (EXPERIMENTAL)"
+	depends on ARM_AMBA && EXPERIMENTAL
+	default y if MACH_U300
+	help
+	  This selects the ARM(R) AMBA(R) PrimeCell PL022 SSP
+	  controller. If you have an embedded system with an AMBA(R)
+	  bus and a PL022 controller, say Y or M here.
+
 config SPI_PXA2XX
 	tristate "PXA2xx SSP SPI master"
 	depends on ARCH_PXA && EXPERIMENTAL
@@ -212,7 +221,7 @@
 
 config SPI_XILINX
 	tristate "Xilinx SPI controller"
-	depends on XILINX_VIRTEX && EXPERIMENTAL
+	depends on (XILINX_VIRTEX || MICROBLAZE) && EXPERIMENTAL
 	select SPI_BITBANG
 	help
 	  This exposes the SPI controller IP from the Xilinx EDK.
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 5d04519..ecfadb1 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -23,6 +23,7 @@
 obj-$(CONFIG_SPI_OMAP_UWIRE)		+= omap_uwire.o
 obj-$(CONFIG_SPI_OMAP24XX)		+= omap2_mcspi.o
 obj-$(CONFIG_SPI_ORION)			+= orion_spi.o
+obj-$(CONFIG_SPI_PL022)			+= amba-pl022.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
 obj-$(CONFIG_SPI_MPC83xx)		+= spi_mpc83xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c
new file mode 100644
index 0000000..da76797
--- /dev/null
+++ b/drivers/spi/amba-pl022.c
@@ -0,0 +1,1866 @@
+/*
+ * drivers/spi/amba-pl022.c
+ *
+ * A driver for the ARM PL022 PrimeCell SSP/SPI bus master.
+ *
+ * Copyright (C) 2008-2009 ST-Ericsson AB
+ * Copyright (C) 2006 STMicroelectronics Pvt. Ltd.
+ *
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ *
+ * Initial version inspired by:
+ *	linux-2.6.17-rc3-mm1/drivers/spi/pxa2xx_spi.c
+ * Initial adoption to PL022 by:
+ *      Sachin Verma <sachin.verma@st.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.
+ */
+
+/*
+ * TODO:
+ * - add timeout on polled transfers
+ * - add generic DMA framework support
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/pl022.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+/*
+ * This macro is used to define some register default values.
+ * reg is masked with mask, the OR:ed with an (again masked)
+ * val shifted sb steps to the left.
+ */
+#define SSP_WRITE_BITS(reg, val, mask, sb) \
+ ((reg) = (((reg) & ~(mask)) | (((val)<<(sb)) & (mask))))
+
+/*
+ * This macro is also used to define some default values.
+ * It will just shift val by sb steps to the left and mask
+ * the result with mask.
+ */
+#define GEN_MASK_BITS(val, mask, sb) \
+ (((val)<<(sb)) & (mask))
+
+#define DRIVE_TX		0
+#define DO_NOT_DRIVE_TX		1
+
+#define DO_NOT_QUEUE_DMA	0
+#define QUEUE_DMA		1
+
+#define RX_TRANSFER		1
+#define TX_TRANSFER		2
+
+/*
+ * Macros to access SSP Registers with their offsets
+ */
+#define SSP_CR0(r)	(r + 0x000)
+#define SSP_CR1(r)	(r + 0x004)
+#define SSP_DR(r)	(r + 0x008)
+#define SSP_SR(r)	(r + 0x00C)
+#define SSP_CPSR(r)	(r + 0x010)
+#define SSP_IMSC(r)	(r + 0x014)
+#define SSP_RIS(r)	(r + 0x018)
+#define SSP_MIS(r)	(r + 0x01C)
+#define SSP_ICR(r)	(r + 0x020)
+#define SSP_DMACR(r)	(r + 0x024)
+#define SSP_ITCR(r)	(r + 0x080)
+#define SSP_ITIP(r)	(r + 0x084)
+#define SSP_ITOP(r)	(r + 0x088)
+#define SSP_TDR(r)	(r + 0x08C)
+
+#define SSP_PID0(r)	(r + 0xFE0)
+#define SSP_PID1(r)	(r + 0xFE4)
+#define SSP_PID2(r)	(r + 0xFE8)
+#define SSP_PID3(r)	(r + 0xFEC)
+
+#define SSP_CID0(r)	(r + 0xFF0)
+#define SSP_CID1(r)	(r + 0xFF4)
+#define SSP_CID2(r)	(r + 0xFF8)
+#define SSP_CID3(r)	(r + 0xFFC)
+
+/*
+ * SSP Control Register 0  - SSP_CR0
+ */
+#define SSP_CR0_MASK_DSS	(0x1FUL << 0)
+#define SSP_CR0_MASK_HALFDUP	(0x1UL << 5)
+#define SSP_CR0_MASK_SPO	(0x1UL << 6)
+#define SSP_CR0_MASK_SPH	(0x1UL << 7)
+#define SSP_CR0_MASK_SCR	(0xFFUL << 8)
+#define SSP_CR0_MASK_CSS	(0x1FUL << 16)
+#define SSP_CR0_MASK_FRF	(0x3UL << 21)
+
+/*
+ * SSP Control Register 0  - SSP_CR1
+ */
+#define SSP_CR1_MASK_LBM	(0x1UL << 0)
+#define SSP_CR1_MASK_SSE	(0x1UL << 1)
+#define SSP_CR1_MASK_MS		(0x1UL << 2)
+#define SSP_CR1_MASK_SOD	(0x1UL << 3)
+#define SSP_CR1_MASK_RENDN	(0x1UL << 4)
+#define SSP_CR1_MASK_TENDN	(0x1UL << 5)
+#define SSP_CR1_MASK_MWAIT	(0x1UL << 6)
+#define SSP_CR1_MASK_RXIFLSEL	(0x7UL << 7)
+#define SSP_CR1_MASK_TXIFLSEL	(0x7UL << 10)
+
+/*
+ * SSP Data Register - SSP_DR
+ */
+#define SSP_DR_MASK_DATA	0xFFFFFFFF
+
+/*
+ * SSP Status Register - SSP_SR
+ */
+#define SSP_SR_MASK_TFE		(0x1UL << 0) /* Transmit FIFO empty */
+#define SSP_SR_MASK_TNF		(0x1UL << 1) /* Transmit FIFO not full */
+#define SSP_SR_MASK_RNE		(0x1UL << 2) /* Receive FIFO not empty */
+#define SSP_SR_MASK_RFF 	(0x1UL << 3) /* Receive FIFO full */
+#define SSP_SR_MASK_BSY		(0x1UL << 4) /* Busy Flag */
+
+/*
+ * SSP Clock Prescale Register  - SSP_CPSR
+ */
+#define SSP_CPSR_MASK_CPSDVSR	(0xFFUL << 0)
+
+/*
+ * SSP Interrupt Mask Set/Clear Register - SSP_IMSC
+ */
+#define SSP_IMSC_MASK_RORIM (0x1UL << 0) /* Receive Overrun Interrupt mask */
+#define SSP_IMSC_MASK_RTIM  (0x1UL << 1) /* Receive timeout Interrupt mask */
+#define SSP_IMSC_MASK_RXIM  (0x1UL << 2) /* Receive FIFO Interrupt mask */
+#define SSP_IMSC_MASK_TXIM  (0x1UL << 3) /* Transmit FIFO Interrupt mask */
+
+/*
+ * SSP Raw Interrupt Status Register - SSP_RIS
+ */
+/* Receive Overrun Raw Interrupt status */
+#define SSP_RIS_MASK_RORRIS		(0x1UL << 0)
+/* Receive Timeout Raw Interrupt status */
+#define SSP_RIS_MASK_RTRIS		(0x1UL << 1)
+/* Receive FIFO Raw Interrupt status */
+#define SSP_RIS_MASK_RXRIS		(0x1UL << 2)
+/* Transmit FIFO Raw Interrupt status */
+#define SSP_RIS_MASK_TXRIS		(0x1UL << 3)
+
+/*
+ * SSP Masked Interrupt Status Register - SSP_MIS
+ */
+/* Receive Overrun Masked Interrupt status */
+#define SSP_MIS_MASK_RORMIS		(0x1UL << 0)
+/* Receive Timeout Masked Interrupt status */
+#define SSP_MIS_MASK_RTMIS		(0x1UL << 1)
+/* Receive FIFO Masked Interrupt status */
+#define SSP_MIS_MASK_RXMIS		(0x1UL << 2)
+/* Transmit FIFO Masked Interrupt status */
+#define SSP_MIS_MASK_TXMIS		(0x1UL << 3)
+
+/*
+ * SSP Interrupt Clear Register - SSP_ICR
+ */
+/* Receive Overrun Raw Clear Interrupt bit */
+#define SSP_ICR_MASK_RORIC		(0x1UL << 0)
+/* Receive Timeout Clear Interrupt bit */
+#define SSP_ICR_MASK_RTIC		(0x1UL << 1)
+
+/*
+ * SSP DMA Control Register - SSP_DMACR
+ */
+/* Receive DMA Enable bit */
+#define SSP_DMACR_MASK_RXDMAE		(0x1UL << 0)
+/* Transmit DMA Enable bit */
+#define SSP_DMACR_MASK_TXDMAE		(0x1UL << 1)
+
+/*
+ * SSP Integration Test control Register - SSP_ITCR
+ */
+#define SSP_ITCR_MASK_ITEN		(0x1UL << 0)
+#define SSP_ITCR_MASK_TESTFIFO		(0x1UL << 1)
+
+/*
+ * SSP Integration Test Input Register - SSP_ITIP
+ */
+#define ITIP_MASK_SSPRXD		 (0x1UL << 0)
+#define ITIP_MASK_SSPFSSIN		 (0x1UL << 1)
+#define ITIP_MASK_SSPCLKIN		 (0x1UL << 2)
+#define ITIP_MASK_RXDMAC		 (0x1UL << 3)
+#define ITIP_MASK_TXDMAC		 (0x1UL << 4)
+#define ITIP_MASK_SSPTXDIN		 (0x1UL << 5)
+
+/*
+ * SSP Integration Test output Register - SSP_ITOP
+ */
+#define ITOP_MASK_SSPTXD		 (0x1UL << 0)
+#define ITOP_MASK_SSPFSSOUT		 (0x1UL << 1)
+#define ITOP_MASK_SSPCLKOUT		 (0x1UL << 2)
+#define ITOP_MASK_SSPOEn		 (0x1UL << 3)
+#define ITOP_MASK_SSPCTLOEn		 (0x1UL << 4)
+#define ITOP_MASK_RORINTR		 (0x1UL << 5)
+#define ITOP_MASK_RTINTR		 (0x1UL << 6)
+#define ITOP_MASK_RXINTR		 (0x1UL << 7)
+#define ITOP_MASK_TXINTR		 (0x1UL << 8)
+#define ITOP_MASK_INTR			 (0x1UL << 9)
+#define ITOP_MASK_RXDMABREQ		 (0x1UL << 10)
+#define ITOP_MASK_RXDMASREQ		 (0x1UL << 11)
+#define ITOP_MASK_TXDMABREQ		 (0x1UL << 12)
+#define ITOP_MASK_TXDMASREQ		 (0x1UL << 13)
+
+/*
+ * SSP Test Data Register - SSP_TDR
+ */
+#define TDR_MASK_TESTDATA 		(0xFFFFFFFF)
+
+/*
+ * Message State
+ * we use the spi_message.state (void *) pointer to
+ * hold a single state value, that's why all this
+ * (void *) casting is done here.
+ */
+#define STATE_START                     ((void *) 0)
+#define STATE_RUNNING                   ((void *) 1)
+#define STATE_DONE                      ((void *) 2)
+#define STATE_ERROR                     ((void *) -1)
+
+/*
+ * Queue State
+ */
+#define QUEUE_RUNNING                   (0)
+#define QUEUE_STOPPED                   (1)
+/*
+ * SSP State - Whether Enabled or Disabled
+ */
+#define SSP_DISABLED 			(0)
+#define SSP_ENABLED 			(1)
+
+/*
+ * SSP DMA State - Whether DMA Enabled or Disabled
+ */
+#define SSP_DMA_DISABLED 		(0)
+#define SSP_DMA_ENABLED 		(1)
+
+/*
+ * SSP Clock Defaults
+ */
+#define NMDK_SSP_DEFAULT_CLKRATE 0x2
+#define NMDK_SSP_DEFAULT_PRESCALE 0x40
+
+/*
+ * SSP Clock Parameter ranges
+ */
+#define CPSDVR_MIN 0x02
+#define CPSDVR_MAX 0xFE
+#define SCR_MIN 0x00
+#define SCR_MAX 0xFF
+
+/*
+ * SSP Interrupt related Macros
+ */
+#define DEFAULT_SSP_REG_IMSC  0x0UL
+#define DISABLE_ALL_INTERRUPTS DEFAULT_SSP_REG_IMSC
+#define ENABLE_ALL_INTERRUPTS (~DEFAULT_SSP_REG_IMSC)
+
+#define CLEAR_ALL_INTERRUPTS  0x3
+
+
+/*
+ * The type of reading going on on this chip
+ */
+enum ssp_reading {
+	READING_NULL,
+	READING_U8,
+	READING_U16,
+	READING_U32
+};
+
+/**
+ * The type of writing going on on this chip
+ */
+enum ssp_writing {
+	WRITING_NULL,
+	WRITING_U8,
+	WRITING_U16,
+	WRITING_U32
+};
+
+/**
+ * struct vendor_data - vendor-specific config parameters
+ * for PL022 derivates
+ * @fifodepth: depth of FIFOs (both)
+ * @max_bpw: maximum number of bits per word
+ * @unidir: supports unidirection transfers
+ */
+struct vendor_data {
+	int fifodepth;
+	int max_bpw;
+	bool unidir;
+};
+
+/**
+ * struct pl022 - This is the private SSP driver data structure
+ * @adev: AMBA device model hookup
+ * @phybase: The physical memory where the SSP device resides
+ * @virtbase: The virtual memory where the SSP is mapped
+ * @master: SPI framework hookup
+ * @master_info: controller-specific data from machine setup
+ * @regs: SSP controller register's virtual address
+ * @pump_messages: Work struct for scheduling work to the workqueue
+ * @lock: spinlock to syncronise access to driver data
+ * @workqueue: a workqueue on which any spi_message request is queued
+ * @busy: workqueue is busy
+ * @run: workqueue is running
+ * @pump_transfers: Tasklet used in Interrupt Transfer mode
+ * @cur_msg: Pointer to current spi_message being processed
+ * @cur_transfer: Pointer to current spi_transfer
+ * @cur_chip: pointer to current clients chip(assigned from controller_state)
+ * @tx: current position in TX buffer to be read
+ * @tx_end: end position in TX buffer to be read
+ * @rx: current position in RX buffer to be written
+ * @rx_end: end position in RX buffer to be written
+ * @readingtype: the type of read currently going on
+ * @writingtype: the type or write currently going on
+ */
+struct pl022 {
+	struct amba_device		*adev;
+	struct vendor_data		*vendor;
+	resource_size_t			phybase;
+	void __iomem			*virtbase;
+	struct clk			*clk;
+	struct spi_master		*master;
+	struct pl022_ssp_controller	*master_info;
+	/* Driver message queue */
+	struct workqueue_struct		*workqueue;
+	struct work_struct		pump_messages;
+	spinlock_t			queue_lock;
+	struct list_head		queue;
+	int				busy;
+	int				run;
+	/* Message transfer pump */
+	struct tasklet_struct		pump_transfers;
+	struct spi_message		*cur_msg;
+	struct spi_transfer		*cur_transfer;
+	struct chip_data		*cur_chip;
+	void				*tx;
+	void				*tx_end;
+	void				*rx;
+	void				*rx_end;
+	enum ssp_reading		read;
+	enum ssp_writing		write;
+};
+
+/**
+ * struct chip_data - To maintain runtime state of SSP for each client chip
+ * @cr0: Value of control register CR0 of SSP
+ * @cr1: Value of control register CR1 of SSP
+ * @dmacr: Value of DMA control Register of SSP
+ * @cpsr: Value of Clock prescale register
+ * @n_bytes: how many bytes(power of 2) reqd for a given data width of client
+ * @enable_dma: Whether to enable DMA or not
+ * @write: function ptr to be used to write when doing xfer for this chip
+ * @read: function ptr to be used to read when doing xfer for this chip
+ * @cs_control: chip select callback provided by chip
+ * @xfer_type: polling/interrupt/DMA
+ *
+ * Runtime state of the SSP controller, maintained per chip,
+ * This would be set according to the current message that would be served
+ */
+struct chip_data {
+	u16 cr0;
+	u16 cr1;
+	u16 dmacr;
+	u16 cpsr;
+	u8 n_bytes;
+	u8 enable_dma:1;
+	enum ssp_reading read;
+	enum ssp_writing write;
+	void (*cs_control) (u32 command);
+	int xfer_type;
+};
+
+/**
+ * null_cs_control - Dummy chip select function
+ * @command: select/delect the chip
+ *
+ * If no chip select function is provided by client this is used as dummy
+ * chip select
+ */
+static void null_cs_control(u32 command)
+{
+	pr_debug("pl022: dummy chip select control, CS=0x%x\n", command);
+}
+
+/**
+ * giveback - current spi_message is over, schedule next message and call
+ * callback of this message. Assumes that caller already
+ * set message->status; dma and pio irqs are blocked
+ * @pl022: SSP driver private data structure
+ */
+static void giveback(struct pl022 *pl022)
+{
+	struct spi_transfer *last_transfer;
+	unsigned long flags;
+	struct spi_message *msg;
+	void (*curr_cs_control) (u32 command);
+
+	/*
+	 * This local reference to the chip select function
+	 * is needed because we set curr_chip to NULL
+	 * as a step toward termininating the message.
+	 */
+	curr_cs_control = pl022->cur_chip->cs_control;
+	spin_lock_irqsave(&pl022->queue_lock, flags);
+	msg = pl022->cur_msg;
+	pl022->cur_msg = NULL;
+	pl022->cur_transfer = NULL;
+	pl022->cur_chip = NULL;
+	queue_work(pl022->workqueue, &pl022->pump_messages);
+	spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+	last_transfer = list_entry(msg->transfers.prev,
+					struct spi_transfer,
+					transfer_list);
+
+	/* Delay if requested before any change in chip select */
+	if (last_transfer->delay_usecs)
+		/*
+		 * FIXME: This runs in interrupt context.
+		 * Is this really smart?
+		 */
+		udelay(last_transfer->delay_usecs);
+
+	/*
+	 * Drop chip select UNLESS cs_change is true or we are returning
+	 * a message with an error, or next message is for another chip
+	 */
+	if (!last_transfer->cs_change)
+		curr_cs_control(SSP_CHIP_DESELECT);
+	else {
+		struct spi_message *next_msg;
+
+		/* Holding of cs was hinted, but we need to make sure
+		 * the next message is for the same chip.  Don't waste
+		 * time with the following tests unless this was hinted.
+		 *
+		 * We cannot postpone this until pump_messages, because
+		 * after calling msg->complete (below) the driver that
+		 * sent the current message could be unloaded, which
+		 * could invalidate the cs_control() callback...
+		 */
+
+		/* get a pointer to the next message, if any */
+		spin_lock_irqsave(&pl022->queue_lock, flags);
+		if (list_empty(&pl022->queue))
+			next_msg = NULL;
+		else
+			next_msg = list_entry(pl022->queue.next,
+					struct spi_message, queue);
+		spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+		/* see if the next and current messages point
+		 * to the same chip
+		 */
+		if (next_msg && next_msg->spi != msg->spi)
+			next_msg = NULL;
+		if (!next_msg || msg->state == STATE_ERROR)
+			curr_cs_control(SSP_CHIP_DESELECT);
+	}
+	msg->state = NULL;
+	if (msg->complete)
+		msg->complete(msg->context);
+	/* This message is completed, so let's turn off the clock! */
+	clk_disable(pl022->clk);
+}
+
+/**
+ * flush - flush the FIFO to reach a clean state
+ * @pl022: SSP driver private data structure
+ */
+static int flush(struct pl022 *pl022)
+{
+	unsigned long limit = loops_per_jiffy << 1;
+
+	dev_dbg(&pl022->adev->dev, "flush\n");
+	do {
+		while (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
+			readw(SSP_DR(pl022->virtbase));
+	} while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_BSY) && limit--);
+	return limit;
+}
+
+/**
+ * restore_state - Load configuration of current chip
+ * @pl022: SSP driver private data structure
+ */
+static void restore_state(struct pl022 *pl022)
+{
+	struct chip_data *chip = pl022->cur_chip;
+
+	writew(chip->cr0, SSP_CR0(pl022->virtbase));
+	writew(chip->cr1, SSP_CR1(pl022->virtbase));
+	writew(chip->dmacr, SSP_DMACR(pl022->virtbase));
+	writew(chip->cpsr, SSP_CPSR(pl022->virtbase));
+	writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
+	writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
+}
+
+/**
+ * load_ssp_default_config - Load default configuration for SSP
+ * @pl022: SSP driver private data structure
+ */
+
+/*
+ * Default SSP Register Values
+ */
+#define DEFAULT_SSP_REG_CR0 ( \
+	GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS, 0)	| \
+	GEN_MASK_BITS(SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, SSP_CR0_MASK_HALFDUP, 5) | \
+	GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \
+	GEN_MASK_BITS(SSP_CLK_FALLING_EDGE, SSP_CR0_MASK_SPH, 7) | \
+	GEN_MASK_BITS(NMDK_SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) | \
+	GEN_MASK_BITS(SSP_BITS_8, SSP_CR0_MASK_CSS, 16)	| \
+	GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF, 21) \
+)
+
+#define DEFAULT_SSP_REG_CR1 ( \
+	GEN_MASK_BITS(LOOPBACK_DISABLED, SSP_CR1_MASK_LBM, 0) | \
+	GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \
+	GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \
+	GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) | \
+	GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN, 4) | \
+	GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN, 5) | \
+	GEN_MASK_BITS(SSP_MWIRE_WAIT_ZERO, SSP_CR1_MASK_MWAIT, 6) |\
+	GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL, 7) | \
+	GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL, 10) \
+)
+
+#define DEFAULT_SSP_REG_CPSR ( \
+	GEN_MASK_BITS(NMDK_SSP_DEFAULT_PRESCALE, SSP_CPSR_MASK_CPSDVSR, 0) \
+)
+
+#define DEFAULT_SSP_REG_DMACR (\
+	GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_RXDMAE, 0) | \
+	GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_TXDMAE, 1) \
+)
+
+
+static void load_ssp_default_config(struct pl022 *pl022)
+{
+	writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase));
+	writew(DEFAULT_SSP_REG_CR1, SSP_CR1(pl022->virtbase));
+	writew(DEFAULT_SSP_REG_DMACR, SSP_DMACR(pl022->virtbase));
+	writew(DEFAULT_SSP_REG_CPSR, SSP_CPSR(pl022->virtbase));
+	writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
+	writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
+}
+
+/**
+ * This will write to TX and read from RX according to the parameters
+ * set in pl022.
+ */
+static void readwriter(struct pl022 *pl022)
+{
+
+	/*
+	 * The FIFO depth is different inbetween primecell variants.
+	 * I believe filling in too much in the FIFO might cause
+	 * errons in 8bit wide transfers on ARM variants (just 8 words
+	 * FIFO, means only 8x8 = 64 bits in FIFO) at least.
+	 *
+	 * FIXME: currently we have no logic to account for this.
+	 * perhaps there is even something broken in HW regarding
+	 * 8bit transfers (it doesn't fail on 16bit) so this needs
+	 * more investigation...
+	 */
+	dev_dbg(&pl022->adev->dev,
+		"%s, rx: %p, rxend: %p, tx: %p, txend: %p\n",
+		__func__, pl022->rx, pl022->rx_end, pl022->tx, pl022->tx_end);
+
+	/* Read as much as you can */
+	while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
+	       && (pl022->rx < pl022->rx_end)) {
+		switch (pl022->read) {
+		case READING_NULL:
+			readw(SSP_DR(pl022->virtbase));
+			break;
+		case READING_U8:
+			*(u8 *) (pl022->rx) =
+				readw(SSP_DR(pl022->virtbase)) & 0xFFU;
+			break;
+		case READING_U16:
+			*(u16 *) (pl022->rx) =
+				(u16) readw(SSP_DR(pl022->virtbase));
+			break;
+		case READING_U32:
+			*(u32 *) (pl022->rx) =
+				readl(SSP_DR(pl022->virtbase));
+			break;
+		}
+		pl022->rx += (pl022->cur_chip->n_bytes);
+	}
+	/*
+	 * Write as much as you can, while keeping an eye on the RX FIFO!
+	 */
+	while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF)
+	       && (pl022->tx < pl022->tx_end)) {
+		switch (pl022->write) {
+		case WRITING_NULL:
+			writew(0x0, SSP_DR(pl022->virtbase));
+			break;
+		case WRITING_U8:
+			writew(*(u8 *) (pl022->tx), SSP_DR(pl022->virtbase));
+			break;
+		case WRITING_U16:
+			writew((*(u16 *) (pl022->tx)), SSP_DR(pl022->virtbase));
+			break;
+		case WRITING_U32:
+			writel(*(u32 *) (pl022->tx), SSP_DR(pl022->virtbase));
+			break;
+		}
+		pl022->tx += (pl022->cur_chip->n_bytes);
+		/*
+		 * This inner reader takes care of things appearing in the RX
+		 * FIFO as we're transmitting. This will happen a lot since the
+		 * clock starts running when you put things into the TX FIFO,
+		 * and then things are continously clocked into the RX FIFO.
+		 */
+		while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
+		       && (pl022->rx < pl022->rx_end)) {
+			switch (pl022->read) {
+			case READING_NULL:
+				readw(SSP_DR(pl022->virtbase));
+				break;
+			case READING_U8:
+				*(u8 *) (pl022->rx) =
+					readw(SSP_DR(pl022->virtbase)) & 0xFFU;
+				break;
+			case READING_U16:
+				*(u16 *) (pl022->rx) =
+					(u16) readw(SSP_DR(pl022->virtbase));
+				break;
+			case READING_U32:
+				*(u32 *) (pl022->rx) =
+					readl(SSP_DR(pl022->virtbase));
+				break;
+			}
+			pl022->rx += (pl022->cur_chip->n_bytes);
+		}
+	}
+	/*
+	 * When we exit here the TX FIFO should be full and the RX FIFO
+	 * should be empty
+	 */
+}
+
+
+/**
+ * next_transfer - Move to the Next transfer in the current spi message
+ * @pl022: SSP driver private data structure
+ *
+ * This function moves though the linked list of spi transfers in the
+ * current spi message and returns with the state of current spi
+ * message i.e whether its last transfer is done(STATE_DONE) or
+ * Next transfer is ready(STATE_RUNNING)
+ */
+static void *next_transfer(struct pl022 *pl022)
+{
+	struct spi_message *msg = pl022->cur_msg;
+	struct spi_transfer *trans = pl022->cur_transfer;
+
+	/* Move to next transfer */
+	if (trans->transfer_list.next != &msg->transfers) {
+		pl022->cur_transfer =
+		    list_entry(trans->transfer_list.next,
+			       struct spi_transfer, transfer_list);
+		return STATE_RUNNING;
+	}
+	return STATE_DONE;
+}
+/**
+ * pl022_interrupt_handler - Interrupt handler for SSP controller
+ *
+ * This function handles interrupts generated for an interrupt based transfer.
+ * If a receive overrun (ROR) interrupt is there then we disable SSP, flag the
+ * current message's state as STATE_ERROR and schedule the tasklet
+ * pump_transfers which will do the postprocessing of the current message by
+ * calling giveback(). Otherwise it reads data from RX FIFO till there is no
+ * more data, and writes data in TX FIFO till it is not full. If we complete
+ * the transfer we move to the next transfer and schedule the tasklet.
+ */
+static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
+{
+	struct pl022 *pl022 = dev_id;
+	struct spi_message *msg = pl022->cur_msg;
+	u16 irq_status = 0;
+	u16 flag = 0;
+
+	if (unlikely(!msg)) {
+		dev_err(&pl022->adev->dev,
+			"bad message state in interrupt handler");
+		/* Never fail */
+		return IRQ_HANDLED;
+	}
+
+	/* Read the Interrupt Status Register */
+	irq_status = readw(SSP_MIS(pl022->virtbase));
+
+	if (unlikely(!irq_status))
+		return IRQ_NONE;
+
+	/* This handles the error code interrupts */
+	if (unlikely(irq_status & SSP_MIS_MASK_RORMIS)) {
+		/*
+		 * Overrun interrupt - bail out since our Data has been
+		 * corrupted
+		 */
+		dev_err(&pl022->adev->dev,
+			"FIFO overrun\n");
+		if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF)
+			dev_err(&pl022->adev->dev,
+				"RXFIFO is full\n");
+		if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF)
+			dev_err(&pl022->adev->dev,
+				"TXFIFO is full\n");
+
+		/*
+		 * Disable and clear interrupts, disable SSP,
+		 * mark message with bad status so it can be
+		 * retried.
+		 */
+		writew(DISABLE_ALL_INTERRUPTS,
+		       SSP_IMSC(pl022->virtbase));
+		writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
+		writew((readw(SSP_CR1(pl022->virtbase)) &
+			(~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
+		msg->state = STATE_ERROR;
+
+		/* Schedule message queue handler */
+		tasklet_schedule(&pl022->pump_transfers);
+		return IRQ_HANDLED;
+	}
+
+	readwriter(pl022);
+
+	if ((pl022->tx == pl022->tx_end) && (flag == 0)) {
+		flag = 1;
+		/* Disable Transmit interrupt */
+		writew(readw(SSP_IMSC(pl022->virtbase)) &
+		       (~SSP_IMSC_MASK_TXIM),
+		       SSP_IMSC(pl022->virtbase));
+	}
+
+	/*
+	 * Since all transactions must write as much as shall be read,
+	 * we can conclude the entire transaction once RX is complete.
+	 * At this point, all TX will always be finished.
+	 */
+	if (pl022->rx >= pl022->rx_end) {
+		writew(DISABLE_ALL_INTERRUPTS,
+		       SSP_IMSC(pl022->virtbase));
+		writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
+		if (unlikely(pl022->rx > pl022->rx_end)) {
+			dev_warn(&pl022->adev->dev, "read %u surplus "
+				 "bytes (did you request an odd "
+				 "number of bytes on a 16bit bus?)\n",
+				 (u32) (pl022->rx - pl022->rx_end));
+		}
+		/* Update total bytes transfered */
+		msg->actual_length += pl022->cur_transfer->len;
+		if (pl022->cur_transfer->cs_change)
+			pl022->cur_chip->
+				cs_control(SSP_CHIP_DESELECT);
+		/* Move to next transfer */
+		msg->state = next_transfer(pl022);
+		tasklet_schedule(&pl022->pump_transfers);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * This sets up the pointers to memory for the next message to
+ * send out on the SPI bus.
+ */
+static int set_up_next_transfer(struct pl022 *pl022,
+				struct spi_transfer *transfer)
+{
+	int residue;
+
+	/* Sanity check the message for this bus width */
+	residue = pl022->cur_transfer->len % pl022->cur_chip->n_bytes;
+	if (unlikely(residue != 0)) {
+		dev_err(&pl022->adev->dev,
+			"message of %u bytes to transmit but the current "
+			"chip bus has a data width of %u bytes!\n",
+			pl022->cur_transfer->len,
+			pl022->cur_chip->n_bytes);
+		dev_err(&pl022->adev->dev, "skipping this message\n");
+		return -EIO;
+	}
+	pl022->tx = (void *)transfer->tx_buf;
+	pl022->tx_end = pl022->tx + pl022->cur_transfer->len;
+	pl022->rx = (void *)transfer->rx_buf;
+	pl022->rx_end = pl022->rx + pl022->cur_transfer->len;
+	pl022->write =
+	    pl022->tx ? pl022->cur_chip->write : WRITING_NULL;
+	pl022->read = pl022->rx ? pl022->cur_chip->read : READING_NULL;
+	return 0;
+}
+
+/**
+ * pump_transfers - Tasklet function which schedules next interrupt transfer
+ * when running in interrupt transfer mode.
+ * @data: SSP driver private data structure
+ *
+ */
+static void pump_transfers(unsigned long data)
+{
+	struct pl022 *pl022 = (struct pl022 *) data;
+	struct spi_message *message = NULL;
+	struct spi_transfer *transfer = NULL;
+	struct spi_transfer *previous = NULL;
+
+	/* Get current state information */
+	message = pl022->cur_msg;
+	transfer = pl022->cur_transfer;
+
+	/* Handle for abort */
+	if (message->state == STATE_ERROR) {
+		message->status = -EIO;
+		giveback(pl022);
+		return;
+	}
+
+	/* Handle end of message */
+	if (message->state == STATE_DONE) {
+		message->status = 0;
+		giveback(pl022);
+		return;
+	}
+
+	/* Delay if requested at end of transfer before CS change */
+	if (message->state == STATE_RUNNING) {
+		previous = list_entry(transfer->transfer_list.prev,
+					struct spi_transfer,
+					transfer_list);
+		if (previous->delay_usecs)
+			/*
+			 * FIXME: This runs in interrupt context.
+			 * Is this really smart?
+			 */
+			udelay(previous->delay_usecs);
+
+		/* Drop chip select only if cs_change is requested */
+		if (previous->cs_change)
+			pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+	} else {
+		/* STATE_START */
+		message->state = STATE_RUNNING;
+	}
+
+	if (set_up_next_transfer(pl022, transfer)) {
+		message->state = STATE_ERROR;
+		message->status = -EIO;
+		giveback(pl022);
+		return;
+	}
+	/* Flush the FIFOs and let's go! */
+	flush(pl022);
+	writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
+}
+
+/**
+ * NOT IMPLEMENTED
+ * configure_dma - It configures the DMA pipes for DMA transfers
+ * @data: SSP driver's private data structure
+ *
+ */
+static int configure_dma(void *data)
+{
+	struct pl022 *pl022 = data;
+	dev_dbg(&pl022->adev->dev, "configure DMA\n");
+	return -ENOTSUPP;
+}
+
+/**
+ * do_dma_transfer - It handles transfers of the current message
+ * if it is DMA xfer.
+ * NOT FULLY IMPLEMENTED
+ * @data: SSP driver's private data structure
+ */
+static void do_dma_transfer(void *data)
+{
+	struct pl022 *pl022 = data;
+
+	if (configure_dma(data)) {
+		dev_dbg(&pl022->adev->dev, "configuration of DMA Failed!\n");
+		goto err_config_dma;
+	}
+
+	/* TODO: Implememt DMA setup of pipes here */
+
+	/* Enable target chip, set up transfer */
+	pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+	if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
+		/* Error path */
+		pl022->cur_msg->state = STATE_ERROR;
+		pl022->cur_msg->status = -EIO;
+		giveback(pl022);
+		return;
+	}
+	/* Enable SSP */
+	writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
+	       SSP_CR1(pl022->virtbase));
+
+	/* TODO: Enable the DMA transfer here */
+	return;
+
+ err_config_dma:
+	pl022->cur_msg->state = STATE_ERROR;
+	pl022->cur_msg->status = -EIO;
+	giveback(pl022);
+	return;
+}
+
+static void do_interrupt_transfer(void *data)
+{
+	struct pl022 *pl022 = data;
+
+	/* Enable target chip */
+	pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+	if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
+		/* Error path */
+		pl022->cur_msg->state = STATE_ERROR;
+		pl022->cur_msg->status = -EIO;
+		giveback(pl022);
+		return;
+	}
+	/* Enable SSP, turn on interrupts */
+	writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
+	       SSP_CR1(pl022->virtbase));
+	writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
+}
+
+static void do_polling_transfer(void *data)
+{
+	struct pl022 *pl022 = data;
+	struct spi_message *message = NULL;
+	struct spi_transfer *transfer = NULL;
+	struct spi_transfer *previous = NULL;
+	struct chip_data *chip;
+
+	chip = pl022->cur_chip;
+	message = pl022->cur_msg;
+
+	while (message->state != STATE_DONE) {
+		/* Handle for abort */
+		if (message->state == STATE_ERROR)
+			break;
+		transfer = pl022->cur_transfer;
+
+		/* Delay if requested at end of transfer */
+		if (message->state == STATE_RUNNING) {
+			previous =
+			    list_entry(transfer->transfer_list.prev,
+				       struct spi_transfer, transfer_list);
+			if (previous->delay_usecs)
+				udelay(previous->delay_usecs);
+			if (previous->cs_change)
+				pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+		} else {
+			/* STATE_START */
+			message->state = STATE_RUNNING;
+			pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+		}
+
+		/* Configuration Changing Per Transfer */
+		if (set_up_next_transfer(pl022, transfer)) {
+			/* Error path */
+			message->state = STATE_ERROR;
+			break;
+		}
+		/* Flush FIFOs and enable SSP */
+		flush(pl022);
+		writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
+		       SSP_CR1(pl022->virtbase));
+
+		dev_dbg(&pl022->adev->dev, "POLLING TRANSFER ONGOING ... \n");
+		/* FIXME: insert a timeout so we don't hang here indefinately */
+		while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end)
+			readwriter(pl022);
+
+		/* Update total byte transfered */
+		message->actual_length += pl022->cur_transfer->len;
+		if (pl022->cur_transfer->cs_change)
+			pl022->cur_chip->cs_control(SSP_CHIP_DESELECT);
+		/* Move to next transfer */
+		message->state = next_transfer(pl022);
+	}
+
+	/* Handle end of message */
+	if (message->state == STATE_DONE)
+		message->status = 0;
+	else
+		message->status = -EIO;
+
+	giveback(pl022);
+	return;
+}
+
+/**
+ * pump_messages - Workqueue function which processes spi message queue
+ * @data: pointer to private data of SSP driver
+ *
+ * This function checks if there is any spi message in the queue that
+ * needs processing and delegate control to appropriate function
+ * do_polling_transfer()/do_interrupt_transfer()/do_dma_transfer()
+ * based on the kind of the transfer
+ *
+ */
+static void pump_messages(struct work_struct *work)
+{
+	struct pl022 *pl022 =
+		container_of(work, struct pl022, pump_messages);
+	unsigned long flags;
+
+	/* Lock queue and check for queue work */
+	spin_lock_irqsave(&pl022->queue_lock, flags);
+	if (list_empty(&pl022->queue) || pl022->run == QUEUE_STOPPED) {
+		pl022->busy = 0;
+		spin_unlock_irqrestore(&pl022->queue_lock, flags);
+		return;
+	}
+	/* Make sure we are not already running a message */
+	if (pl022->cur_msg) {
+		spin_unlock_irqrestore(&pl022->queue_lock, flags);
+		return;
+	}
+	/* Extract head of queue */
+	pl022->cur_msg =
+	    list_entry(pl022->queue.next, struct spi_message, queue);
+
+	list_del_init(&pl022->cur_msg->queue);
+	pl022->busy = 1;
+	spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+	/* Initial message state */
+	pl022->cur_msg->state = STATE_START;
+	pl022->cur_transfer = list_entry(pl022->cur_msg->transfers.next,
+					    struct spi_transfer,
+					    transfer_list);
+
+	/* Setup the SPI using the per chip configuration */
+	pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi);
+	/*
+	 * We enable the clock here, then the clock will be disabled when
+	 * giveback() is called in each method (poll/interrupt/DMA)
+	 */
+	clk_enable(pl022->clk);
+	restore_state(pl022);
+	flush(pl022);
+
+	if (pl022->cur_chip->xfer_type == POLLING_TRANSFER)
+		do_polling_transfer(pl022);
+	else if (pl022->cur_chip->xfer_type == INTERRUPT_TRANSFER)
+		do_interrupt_transfer(pl022);
+	else
+		do_dma_transfer(pl022);
+}
+
+
+static int __init init_queue(struct pl022 *pl022)
+{
+	INIT_LIST_HEAD(&pl022->queue);
+	spin_lock_init(&pl022->queue_lock);
+
+	pl022->run = QUEUE_STOPPED;
+	pl022->busy = 0;
+
+	tasklet_init(&pl022->pump_transfers,
+			pump_transfers,	(unsigned long)pl022);
+
+	INIT_WORK(&pl022->pump_messages, pump_messages);
+	pl022->workqueue = create_singlethread_workqueue(
+					dev_name(pl022->master->dev.parent));
+	if (pl022->workqueue == NULL)
+		return -EBUSY;
+
+	return 0;
+}
+
+
+static int start_queue(struct pl022 *pl022)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&pl022->queue_lock, flags);
+
+	if (pl022->run == QUEUE_RUNNING || pl022->busy) {
+		spin_unlock_irqrestore(&pl022->queue_lock, flags);
+		return -EBUSY;
+	}
+
+	pl022->run = QUEUE_RUNNING;
+	pl022->cur_msg = NULL;
+	pl022->cur_transfer = NULL;
+	pl022->cur_chip = NULL;
+	spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+	queue_work(pl022->workqueue, &pl022->pump_messages);
+
+	return 0;
+}
+
+
+static int stop_queue(struct pl022 *pl022)
+{
+	unsigned long flags;
+	unsigned limit = 500;
+	int status = 0;
+
+	spin_lock_irqsave(&pl022->queue_lock, flags);
+
+	/* This is a bit lame, but is optimized for the common execution path.
+	 * A wait_queue on the pl022->busy could be used, but then the common
+	 * execution path (pump_messages) would be required to call wake_up or
+	 * friends on every SPI message. Do this instead */
+	pl022->run = QUEUE_STOPPED;
+	while (!list_empty(&pl022->queue) && pl022->busy && limit--) {
+		spin_unlock_irqrestore(&pl022->queue_lock, flags);
+		msleep(10);
+		spin_lock_irqsave(&pl022->queue_lock, flags);
+	}
+
+	if (!list_empty(&pl022->queue) || pl022->busy)
+		status = -EBUSY;
+
+	spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+	return status;
+}
+
+static int destroy_queue(struct pl022 *pl022)
+{
+	int status;
+
+	status = stop_queue(pl022);
+	/* we are unloading the module or failing to load (only two calls
+	 * to this routine), and neither call can handle a return value.
+	 * However, destroy_workqueue calls flush_workqueue, and that will
+	 * block until all work is done.  If the reason that stop_queue
+	 * timed out is that the work will never finish, then it does no
+	 * good to call destroy_workqueue, so return anyway. */
+	if (status != 0)
+		return status;
+
+	destroy_workqueue(pl022->workqueue);
+
+	return 0;
+}
+
+static int verify_controller_parameters(struct pl022 *pl022,
+					struct pl022_config_chip *chip_info)
+{
+	if ((chip_info->lbm != LOOPBACK_ENABLED)
+	    && (chip_info->lbm != LOOPBACK_DISABLED)) {
+		dev_err(chip_info->dev,
+			"loopback Mode is configured incorrectly\n");
+		return -EINVAL;
+	}
+	if ((chip_info->iface < SSP_INTERFACE_MOTOROLA_SPI)
+	    || (chip_info->iface > SSP_INTERFACE_UNIDIRECTIONAL)) {
+		dev_err(chip_info->dev,
+			"interface is configured incorrectly\n");
+		return -EINVAL;
+	}
+	if ((chip_info->iface == SSP_INTERFACE_UNIDIRECTIONAL) &&
+	    (!pl022->vendor->unidir)) {
+		dev_err(chip_info->dev,
+			"unidirectional mode not supported in this "
+			"hardware version\n");
+		return -EINVAL;
+	}
+	if ((chip_info->hierarchy != SSP_MASTER)
+	    && (chip_info->hierarchy != SSP_SLAVE)) {
+		dev_err(chip_info->dev,
+			"hierarchy is configured incorrectly\n");
+		return -EINVAL;
+	}
+	if (((chip_info->clk_freq).cpsdvsr < CPSDVR_MIN)
+	    || ((chip_info->clk_freq).cpsdvsr > CPSDVR_MAX)) {
+		dev_err(chip_info->dev,
+			"cpsdvsr is configured incorrectly\n");
+		return -EINVAL;
+	}
+	if ((chip_info->endian_rx != SSP_RX_MSB)
+	    && (chip_info->endian_rx != SSP_RX_LSB)) {
+		dev_err(chip_info->dev,
+			"RX FIFO endianess is configured incorrectly\n");
+		return -EINVAL;
+	}
+	if ((chip_info->endian_tx != SSP_TX_MSB)
+	    && (chip_info->endian_tx != SSP_TX_LSB)) {
+		dev_err(chip_info->dev,
+			"TX FIFO endianess is configured incorrectly\n");
+		return -EINVAL;
+	}
+	if ((chip_info->data_size < SSP_DATA_BITS_4)
+	    || (chip_info->data_size > SSP_DATA_BITS_32)) {
+		dev_err(chip_info->dev,
+			"DATA Size is configured incorrectly\n");
+		return -EINVAL;
+	}
+	if ((chip_info->com_mode != INTERRUPT_TRANSFER)
+	    && (chip_info->com_mode != DMA_TRANSFER)
+	    && (chip_info->com_mode != POLLING_TRANSFER)) {
+		dev_err(chip_info->dev,
+			"Communication mode is configured incorrectly\n");
+		return -EINVAL;
+	}
+	if ((chip_info->rx_lev_trig < SSP_RX_1_OR_MORE_ELEM)
+	    || (chip_info->rx_lev_trig > SSP_RX_32_OR_MORE_ELEM)) {
+		dev_err(chip_info->dev,
+			"RX FIFO Trigger Level is configured incorrectly\n");
+		return -EINVAL;
+	}
+	if ((chip_info->tx_lev_trig < SSP_TX_1_OR_MORE_EMPTY_LOC)
+	    || (chip_info->tx_lev_trig > SSP_TX_32_OR_MORE_EMPTY_LOC)) {
+		dev_err(chip_info->dev,
+			"TX FIFO Trigger Level is configured incorrectly\n");
+		return -EINVAL;
+	}
+	if (chip_info->iface == SSP_INTERFACE_MOTOROLA_SPI) {
+		if ((chip_info->clk_phase != SSP_CLK_RISING_EDGE)
+		    && (chip_info->clk_phase != SSP_CLK_FALLING_EDGE)) {
+			dev_err(chip_info->dev,
+				"Clock Phase is configured incorrectly\n");
+			return -EINVAL;
+		}
+		if ((chip_info->clk_pol != SSP_CLK_POL_IDLE_LOW)
+		    && (chip_info->clk_pol != SSP_CLK_POL_IDLE_HIGH)) {
+			dev_err(chip_info->dev,
+				"Clock Polarity is configured incorrectly\n");
+			return -EINVAL;
+		}
+	}
+	if (chip_info->iface == SSP_INTERFACE_NATIONAL_MICROWIRE) {
+		if ((chip_info->ctrl_len < SSP_BITS_4)
+		    || (chip_info->ctrl_len > SSP_BITS_32)) {
+			dev_err(chip_info->dev,
+				"CTRL LEN is configured incorrectly\n");
+			return -EINVAL;
+		}
+		if ((chip_info->wait_state != SSP_MWIRE_WAIT_ZERO)
+		    && (chip_info->wait_state != SSP_MWIRE_WAIT_ONE)) {
+			dev_err(chip_info->dev,
+				"Wait State is configured incorrectly\n");
+			return -EINVAL;
+		}
+		if ((chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
+		    && (chip_info->duplex !=
+			SSP_MICROWIRE_CHANNEL_HALF_DUPLEX)) {
+			dev_err(chip_info->dev,
+				"DUPLEX is configured incorrectly\n");
+			return -EINVAL;
+		}
+	}
+	if (chip_info->cs_control == NULL) {
+		dev_warn(chip_info->dev,
+			"Chip Select Function is NULL for this chip\n");
+		chip_info->cs_control = null_cs_control;
+	}
+	return 0;
+}
+
+/**
+ * pl022_transfer - transfer function registered to SPI master framework
+ * @spi: spi device which is requesting transfer
+ * @msg: spi message which is to handled is queued to driver queue
+ *
+ * This function is registered to the SPI framework for this SPI master
+ * controller. It will queue the spi_message in the queue of driver if
+ * the queue is not stopped and return.
+ */
+static int pl022_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+	struct pl022 *pl022 = spi_master_get_devdata(spi->master);
+	unsigned long flags;
+
+	spin_lock_irqsave(&pl022->queue_lock, flags);
+
+	if (pl022->run == QUEUE_STOPPED) {
+		spin_unlock_irqrestore(&pl022->queue_lock, flags);
+		return -ESHUTDOWN;
+	}
+	msg->actual_length = 0;
+	msg->status = -EINPROGRESS;
+	msg->state = STATE_START;
+
+	list_add_tail(&msg->queue, &pl022->queue);
+	if (pl022->run == QUEUE_RUNNING && !pl022->busy)
+		queue_work(pl022->workqueue, &pl022->pump_messages);
+
+	spin_unlock_irqrestore(&pl022->queue_lock, flags);
+	return 0;
+}
+
+static int calculate_effective_freq(struct pl022 *pl022,
+				    int freq,
+				    struct ssp_clock_params *clk_freq)
+{
+	/* Lets calculate the frequency parameters */
+	u16 cpsdvsr = 2;
+	u16 scr = 0;
+	bool freq_found = false;
+	u32 rate;
+	u32 max_tclk;
+	u32 min_tclk;
+
+	rate = clk_get_rate(pl022->clk);
+	/* cpsdvscr = 2 & scr 0 */
+	max_tclk = (rate / (CPSDVR_MIN * (1 + SCR_MIN)));
+	/* cpsdvsr = 254 & scr = 255 */
+	min_tclk = (rate / (CPSDVR_MAX * (1 + SCR_MAX)));
+
+	if ((freq <= max_tclk) && (freq >= min_tclk)) {
+		while (cpsdvsr <= CPSDVR_MAX && !freq_found) {
+			while (scr <= SCR_MAX && !freq_found) {
+				if ((rate /
+				     (cpsdvsr * (1 + scr))) > freq)
+					scr += 1;
+				else {
+					/*
+					 * This bool is made true when
+					 * effective frequency >=
+					 * target frequency is found
+					 */
+					freq_found = true;
+					if ((rate /
+					     (cpsdvsr * (1 + scr))) != freq) {
+						if (scr == SCR_MIN) {
+							cpsdvsr -= 2;
+							scr = SCR_MAX;
+						} else
+							scr -= 1;
+					}
+				}
+			}
+			if (!freq_found) {
+				cpsdvsr += 2;
+				scr = SCR_MIN;
+			}
+		}
+		if (cpsdvsr != 0) {
+			dev_dbg(&pl022->adev->dev,
+				"SSP Effective Frequency is %u\n",
+				(rate / (cpsdvsr * (1 + scr))));
+			clk_freq->cpsdvsr = (u8) (cpsdvsr & 0xFF);
+			clk_freq->scr = (u8) (scr & 0xFF);
+			dev_dbg(&pl022->adev->dev,
+				"SSP cpsdvsr = %d, scr = %d\n",
+				clk_freq->cpsdvsr, clk_freq->scr);
+		}
+	} else {
+		dev_err(&pl022->adev->dev,
+			"controller data is incorrect: out of range frequency");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ * NOT IMPLEMENTED
+ * process_dma_info - Processes the DMA info provided by client drivers
+ * @chip_info: chip info provided by client device
+ * @chip: Runtime state maintained by the SSP controller for each spi device
+ *
+ * This function processes and stores DMA config provided by client driver
+ * into the runtime state maintained by the SSP controller driver
+ */
+static int process_dma_info(struct pl022_config_chip *chip_info,
+			    struct chip_data *chip)
+{
+	dev_err(chip_info->dev,
+		"cannot process DMA info, DMA not implemented!\n");
+	return -ENOTSUPP;
+}
+
+/**
+ * pl022_setup - setup function registered to SPI master framework
+ * @spi: spi device which is requesting setup
+ *
+ * This function is registered to the SPI framework for this SPI master
+ * controller. If it is the first time when setup is called by this device,
+ * this function will initialize the runtime state for this chip and save
+ * the same in the device structure. Else it will update the runtime info
+ * with the updated chip info. Nothing is really being written to the
+ * controller hardware here, that is not done until the actual transfer
+ * commence.
+ */
+
+/* FIXME: JUST GUESSING the spi->mode bits understood by this driver */
+#define MODEBITS	(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
+			| SPI_LSB_FIRST | SPI_LOOP)
+
+static int pl022_setup(struct spi_device *spi)
+{
+	struct pl022_config_chip *chip_info;
+	struct chip_data *chip;
+	int status = 0;
+	struct pl022 *pl022 = spi_master_get_devdata(spi->master);
+
+	if (spi->mode & ~MODEBITS) {
+		dev_dbg(&spi->dev, "unsupported mode bits %x\n",
+			spi->mode & ~MODEBITS);
+		return -EINVAL;
+	}
+
+	if (!spi->max_speed_hz)
+		return -EINVAL;
+
+	/* Get controller_state if one is supplied */
+	chip = spi_get_ctldata(spi);
+
+	if (chip == NULL) {
+		chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+		if (!chip) {
+			dev_err(&spi->dev,
+				"cannot allocate controller state\n");
+			return -ENOMEM;
+		}
+		dev_dbg(&spi->dev,
+			"allocated memory for controller's runtime state\n");
+	}
+
+	/* Get controller data if one is supplied */
+	chip_info = spi->controller_data;
+
+	if (chip_info == NULL) {
+		/* spi_board_info.controller_data not is supplied */
+		dev_dbg(&spi->dev,
+			"using default controller_data settings\n");
+
+		chip_info =
+			kzalloc(sizeof(struct pl022_config_chip), GFP_KERNEL);
+
+		if (!chip_info) {
+			dev_err(&spi->dev,
+				"cannot allocate controller data\n");
+			status = -ENOMEM;
+			goto err_first_setup;
+		}
+
+		dev_dbg(&spi->dev, "allocated memory for controller data\n");
+
+		/* Pointer back to the SPI device */
+		chip_info->dev = &spi->dev;
+		/*
+		 * Set controller data default values:
+		 * Polling is supported by default
+		 */
+		chip_info->lbm = LOOPBACK_DISABLED;
+		chip_info->com_mode = POLLING_TRANSFER;
+		chip_info->iface = SSP_INTERFACE_MOTOROLA_SPI;
+		chip_info->hierarchy = SSP_SLAVE;
+		chip_info->slave_tx_disable = DO_NOT_DRIVE_TX;
+		chip_info->endian_tx = SSP_TX_LSB;
+		chip_info->endian_rx = SSP_RX_LSB;
+		chip_info->data_size = SSP_DATA_BITS_12;
+		chip_info->rx_lev_trig = SSP_RX_1_OR_MORE_ELEM;
+		chip_info->tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC;
+		chip_info->clk_phase = SSP_CLK_FALLING_EDGE;
+		chip_info->clk_pol = SSP_CLK_POL_IDLE_LOW;
+		chip_info->ctrl_len = SSP_BITS_8;
+		chip_info->wait_state = SSP_MWIRE_WAIT_ZERO;
+		chip_info->duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX;
+		chip_info->cs_control = null_cs_control;
+	} else {
+		dev_dbg(&spi->dev,
+			"using user supplied controller_data settings\n");
+	}
+
+	/*
+	 * We can override with custom divisors, else we use the board
+	 * frequency setting
+	 */
+	if ((0 == chip_info->clk_freq.cpsdvsr)
+	    && (0 == chip_info->clk_freq.scr)) {
+		status = calculate_effective_freq(pl022,
+						  spi->max_speed_hz,
+						  &chip_info->clk_freq);
+		if (status < 0)
+			goto err_config_params;
+	} else {
+		if ((chip_info->clk_freq.cpsdvsr % 2) != 0)
+			chip_info->clk_freq.cpsdvsr =
+				chip_info->clk_freq.cpsdvsr - 1;
+	}
+	status = verify_controller_parameters(pl022, chip_info);
+	if (status) {
+		dev_err(&spi->dev, "controller data is incorrect");
+		goto err_config_params;
+	}
+	/* Now set controller state based on controller data */
+	chip->xfer_type = chip_info->com_mode;
+	chip->cs_control = chip_info->cs_control;
+
+	if (chip_info->data_size <= 8) {
+		dev_dbg(&spi->dev, "1 <= n <=8 bits per word\n");
+		chip->n_bytes = 1;
+		chip->read = READING_U8;
+		chip->write = WRITING_U8;
+	} else if (chip_info->data_size <= 16) {
+		dev_dbg(&spi->dev, "9 <= n <= 16 bits per word\n");
+		chip->n_bytes = 2;
+		chip->read = READING_U16;
+		chip->write = WRITING_U16;
+	} else {
+		if (pl022->vendor->max_bpw >= 32) {
+			dev_dbg(&spi->dev, "17 <= n <= 32 bits per word\n");
+			chip->n_bytes = 4;
+			chip->read = READING_U32;
+			chip->write = WRITING_U32;
+		} else {
+			dev_err(&spi->dev,
+				"illegal data size for this controller!\n");
+			dev_err(&spi->dev,
+				"a standard pl022 can only handle "
+				"1 <= n <= 16 bit words\n");
+			goto err_config_params;
+		}
+	}
+
+	/* Now Initialize all register settings required for this chip */
+	chip->cr0 = 0;
+	chip->cr1 = 0;
+	chip->dmacr = 0;
+	chip->cpsr = 0;
+	if ((chip_info->com_mode == DMA_TRANSFER)
+	    && ((pl022->master_info)->enable_dma)) {
+		chip->enable_dma = 1;
+		dev_dbg(&spi->dev, "DMA mode set in controller state\n");
+		status = process_dma_info(chip_info, chip);
+		if (status < 0)
+			goto err_config_params;
+		SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
+			       SSP_DMACR_MASK_RXDMAE, 0);
+		SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
+			       SSP_DMACR_MASK_TXDMAE, 1);
+	} else {
+		chip->enable_dma = 0;
+		dev_dbg(&spi->dev, "DMA mode NOT set in controller state\n");
+		SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED,
+			       SSP_DMACR_MASK_RXDMAE, 0);
+		SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED,
+			       SSP_DMACR_MASK_TXDMAE, 1);
+	}
+
+	chip->cpsr = chip_info->clk_freq.cpsdvsr;
+
+	SSP_WRITE_BITS(chip->cr0, chip_info->data_size, SSP_CR0_MASK_DSS, 0);
+	SSP_WRITE_BITS(chip->cr0, chip_info->duplex, SSP_CR0_MASK_HALFDUP, 5);
+	SSP_WRITE_BITS(chip->cr0, chip_info->clk_pol, SSP_CR0_MASK_SPO, 6);
+	SSP_WRITE_BITS(chip->cr0, chip_info->clk_phase, SSP_CR0_MASK_SPH, 7);
+	SSP_WRITE_BITS(chip->cr0, chip_info->clk_freq.scr, SSP_CR0_MASK_SCR, 8);
+	SSP_WRITE_BITS(chip->cr0, chip_info->ctrl_len, SSP_CR0_MASK_CSS, 16);
+	SSP_WRITE_BITS(chip->cr0, chip_info->iface, SSP_CR0_MASK_FRF, 21);
+	SSP_WRITE_BITS(chip->cr1, chip_info->lbm, SSP_CR1_MASK_LBM, 0);
+	SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1);
+	SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2);
+	SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 3);
+	SSP_WRITE_BITS(chip->cr1, chip_info->endian_rx, SSP_CR1_MASK_RENDN, 4);
+	SSP_WRITE_BITS(chip->cr1, chip_info->endian_tx, SSP_CR1_MASK_TENDN, 5);
+	SSP_WRITE_BITS(chip->cr1, chip_info->wait_state, SSP_CR1_MASK_MWAIT, 6);
+	SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig, SSP_CR1_MASK_RXIFLSEL, 7);
+	SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig, SSP_CR1_MASK_TXIFLSEL, 10);
+
+	/* Save controller_state */
+	spi_set_ctldata(spi, chip);
+	return status;
+ err_config_params:
+ err_first_setup:
+	kfree(chip);
+	return status;
+}
+
+/**
+ * pl022_cleanup - cleanup function registered to SPI master framework
+ * @spi: spi device which is requesting cleanup
+ *
+ * This function is registered to the SPI framework for this SPI master
+ * controller. It will free the runtime state of chip.
+ */
+static void pl022_cleanup(struct spi_device *spi)
+{
+	struct chip_data *chip = spi_get_ctldata(spi);
+
+	spi_set_ctldata(spi, NULL);
+	kfree(chip);
+}
+
+
+static int __init
+pl022_probe(struct amba_device *adev, struct amba_id *id)
+{
+	struct device *dev = &adev->dev;
+	struct pl022_ssp_controller *platform_info = adev->dev.platform_data;
+	struct spi_master *master;
+	struct pl022 *pl022 = NULL;	/*Data for this driver */
+	int status = 0;
+
+	dev_info(&adev->dev,
+		 "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid);
+	if (platform_info == NULL) {
+		dev_err(&adev->dev, "probe - no platform data supplied\n");
+		status = -ENODEV;
+		goto err_no_pdata;
+	}
+
+	/* Allocate master with space for data */
+	master = spi_alloc_master(dev, sizeof(struct pl022));
+	if (master == NULL) {
+		dev_err(&adev->dev, "probe - cannot alloc SPI master\n");
+		status = -ENOMEM;
+		goto err_no_master;
+	}
+
+	pl022 = spi_master_get_devdata(master);
+	pl022->master = master;
+	pl022->master_info = platform_info;
+	pl022->adev = adev;
+	pl022->vendor = id->data;
+
+	/*
+	 * Bus Number Which has been Assigned to this SSP controller
+	 * on this board
+	 */
+	master->bus_num = platform_info->bus_id;
+	master->num_chipselect = platform_info->num_chipselect;
+	master->cleanup = pl022_cleanup;
+	master->setup = pl022_setup;
+	master->transfer = pl022_transfer;
+
+	dev_dbg(&adev->dev, "BUSNO: %d\n", master->bus_num);
+
+	status = amba_request_regions(adev, NULL);
+	if (status)
+		goto err_no_ioregion;
+
+	pl022->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
+	if (pl022->virtbase == NULL) {
+		status = -ENOMEM;
+		goto err_no_ioremap;
+	}
+	printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n",
+	       adev->res.start, pl022->virtbase);
+
+	pl022->clk = clk_get(&adev->dev, NULL);
+	if (IS_ERR(pl022->clk)) {
+		status = PTR_ERR(pl022->clk);
+		dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n");
+		goto err_no_clk;
+	}
+
+	/* Disable SSP */
+	clk_enable(pl022->clk);
+	writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)),
+	       SSP_CR1(pl022->virtbase));
+	load_ssp_default_config(pl022);
+	clk_disable(pl022->clk);
+
+	status = request_irq(adev->irq[0], pl022_interrupt_handler, 0, "pl022",
+			     pl022);
+	if (status < 0) {
+		dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status);
+		goto err_no_irq;
+	}
+	/* Initialize and start queue */
+	status = init_queue(pl022);
+	if (status != 0) {
+		dev_err(&adev->dev, "probe - problem initializing queue\n");
+		goto err_init_queue;
+	}
+	status = start_queue(pl022);
+	if (status != 0) {
+		dev_err(&adev->dev, "probe - problem starting queue\n");
+		goto err_start_queue;
+	}
+	/* Register with the SPI framework */
+	amba_set_drvdata(adev, pl022);
+	status = spi_register_master(master);
+	if (status != 0) {
+		dev_err(&adev->dev,
+			"probe - problem registering spi master\n");
+		goto err_spi_register;
+	}
+	dev_dbg(dev, "probe succeded\n");
+	return 0;
+
+ err_spi_register:
+ err_start_queue:
+ err_init_queue:
+	destroy_queue(pl022);
+	free_irq(adev->irq[0], pl022);
+ err_no_irq:
+	clk_put(pl022->clk);
+ err_no_clk:
+	iounmap(pl022->virtbase);
+ err_no_ioremap:
+	amba_release_regions(adev);
+ err_no_ioregion:
+	spi_master_put(master);
+ err_no_master:
+ err_no_pdata:
+	return status;
+}
+
+static int __exit
+pl022_remove(struct amba_device *adev)
+{
+	struct pl022 *pl022 = amba_get_drvdata(adev);
+	int status = 0;
+	if (!pl022)
+		return 0;
+
+	/* Remove the queue */
+	status = destroy_queue(pl022);
+	if (status != 0) {
+		dev_err(&adev->dev,
+			"queue remove failed (%d)\n", status);
+		return status;
+	}
+	load_ssp_default_config(pl022);
+	free_irq(adev->irq[0], pl022);
+	clk_disable(pl022->clk);
+	clk_put(pl022->clk);
+	iounmap(pl022->virtbase);
+	amba_release_regions(adev);
+	tasklet_disable(&pl022->pump_transfers);
+	spi_unregister_master(pl022->master);
+	spi_master_put(pl022->master);
+	amba_set_drvdata(adev, NULL);
+	dev_dbg(&adev->dev, "remove succeded\n");
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int pl022_suspend(struct amba_device *adev, pm_message_t state)
+{
+	struct pl022 *pl022 = amba_get_drvdata(adev);
+	int status = 0;
+
+	status = stop_queue(pl022);
+	if (status) {
+		dev_warn(&adev->dev, "suspend cannot stop queue\n");
+		return status;
+	}
+
+	clk_enable(pl022->clk);
+	load_ssp_default_config(pl022);
+	clk_disable(pl022->clk);
+	dev_dbg(&adev->dev, "suspended\n");
+	return 0;
+}
+
+static int pl022_resume(struct amba_device *adev)
+{
+	struct pl022 *pl022 = amba_get_drvdata(adev);
+	int status = 0;
+
+	/* Start the queue running */
+	status = start_queue(pl022);
+	if (status)
+		dev_err(&adev->dev, "problem starting queue (%d)\n", status);
+	else
+		dev_dbg(&adev->dev, "resumed\n");
+
+	return status;
+}
+#else
+#define pl022_suspend NULL
+#define pl022_resume NULL
+#endif	/* CONFIG_PM */
+
+static struct vendor_data vendor_arm = {
+	.fifodepth = 8,
+	.max_bpw = 16,
+	.unidir = false,
+};
+
+
+static struct vendor_data vendor_st = {
+	.fifodepth = 32,
+	.max_bpw = 32,
+	.unidir = false,
+};
+
+static struct amba_id pl022_ids[] = {
+	{
+		/*
+		 * ARM PL022 variant, this has a 16bit wide
+		 * and 8 locations deep TX/RX FIFO
+		 */
+		.id	= 0x00041022,
+		.mask	= 0x000fffff,
+		.data	= &vendor_arm,
+	},
+	{
+		/*
+		 * ST Micro derivative, this has 32bit wide
+		 * and 32 locations deep TX/RX FIFO
+		 */
+		.id	= 0x00108022,
+		.mask	= 0xffffffff,
+		.data	= &vendor_st,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl022_driver = {
+	.drv = {
+		.name	= "ssp-pl022",
+	},
+	.id_table	= pl022_ids,
+	.probe		= pl022_probe,
+	.remove		= __exit_p(pl022_remove),
+	.suspend        = pl022_suspend,
+	.resume         = pl022_resume,
+};
+
+
+static int __init pl022_init(void)
+{
+	return amba_driver_register(&pl022_driver);
+}
+
+module_init(pl022_init);
+
+static void __exit pl022_exit(void)
+{
+	amba_driver_unregister(&pl022_driver);
+}
+
+module_exit(pl022_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
+MODULE_DESCRIPTION("PL022 SSP Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
index f2447a5..bbf9371 100644
--- a/drivers/spi/spi_s3c24xx_gpio.c
+++ b/drivers/spi/spi_s3c24xx_gpio.c
@@ -17,6 +17,7 @@
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index c6c816b..5eee3f8 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -22,6 +22,7 @@
 	default y if PCMCIA && !M32R			# sl811_cs
 	default y if ARM				# SL-811
 	default y if SUPERH				# r8a66597-hcd
+	default y if MICROBLAZE
 	default PCI
 
 # many non-PCI SOC chips embed OHCI
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 7cf74f8..b0dbf41 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -47,7 +47,7 @@
 	struct usb_hcd *hcd;
 
 	if (pdev->resource[1].flags != IORESOURCE_IRQ) {
-		pr_debug("resource[1] is not IORESOURCE_IRQ");
+		dbg("resource[1] is not IORESOURCE_IRQ");
 		return -ENOMEM;
 	}
 
@@ -65,12 +65,18 @@
 
 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 	if (hcd->regs == NULL) {
-		pr_debug("ioremap failed");
+		dbg("ioremap failed");
 		retval = -ENOMEM;
 		goto err2;
 	}
 
-	usb_host_clock = clk_get(&pdev->dev, "usb_host");
+	usb_host_clock = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(usb_host_clock)) {
+		dbg("clk_get failed");
+		retval = PTR_ERR(usb_host_clock);
+		goto err3;
+	}
+
 	ep93xx_start_hc(&pdev->dev);
 
 	ohci_hcd_init(hcd_to_ohci(hcd));
@@ -80,6 +86,7 @@
 		return retval;
 
 	ep93xx_stop_hc(&pdev->dev);
+err3:
 	iounmap(hcd->regs);
 err2:
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 0048f11..2b5a691 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -397,7 +397,7 @@
 
 config FB_IMX
 	tristate "Motorola i.MX LCD support"
-	depends on FB && (ARCH_IMX || ARCH_MX2)
+	depends on FB && (ARCH_MX1 || ARCH_MX2)
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
@@ -1759,6 +1759,16 @@
 	  Say Y here if you want to support the built-in frame buffer of
 	  the Motorola 68328 CPU family.
 
+config FB_PXA168
+	tristate "PXA168/910 LCD framebuffer support"
+	depends on FB && (CPU_PXA168 || CPU_PXA910)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	---help---
+	  Frame buffer driver for the built-in LCD controller in the Marvell
+	  MMP processor.
+
 config FB_PXA
 	tristate "PXA LCD framebuffer support"
 	depends on FB && ARCH_PXA
@@ -1996,7 +2006,7 @@
 
 config FB_XILINX
 	tristate "Xilinx frame buffer support"
-	depends on FB && XILINX_VIRTEX
+	depends on FB && (XILINX_VIRTEX || MICROBLAZE)
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index d8d0be5..01a819f 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -97,6 +97,7 @@
 obj-$(CONFIG_FB_CIRRUS)		  += cirrusfb.o
 obj-$(CONFIG_FB_ASILIANT)	  += asiliantfb.o
 obj-$(CONFIG_FB_PXA)		  += pxafb.o
+obj-$(CONFIG_FB_PXA168)		  += pxa168fb.o
 obj-$(CONFIG_FB_W100)		  += w100fb.o
 obj-$(CONFIG_FB_TMIO)		  += tmiofb.o
 obj-$(CONFIG_FB_AU1100)		  += au1100fb.o
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index d1f80ba..fb8163d 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -351,7 +351,7 @@
 	}
 
 	fb->fb.fix.mmio_start	= fb->dev->res.start;
-	fb->fb.fix.mmio_len	= 4096;
+	fb->fb.fix.mmio_len	= resource_size(&fb->dev->res);
 
 	fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len);
 	if (!fb->regs) {
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 35e8eb0..e4e4d43 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -354,7 +354,7 @@
 static int default_lcd_on __devinitdata = 1;
 
 #ifdef CONFIG_MTRR
-static int mtrr = 1;
+static bool mtrr = true;
 #endif
 
 #ifdef CONFIG_PMAC_BACKLIGHT
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index 83c5cef..da7c01b 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -1736,10 +1736,8 @@
 
 #ifdef CONFIG_ARCH_SHARK
 	err = cyberpro_vl_probe();
-	if (!err) {
+	if (!err)
 		ret = 0;
-		__module_get(THIS_MODULE);
-	}
 #endif
 #ifdef CONFIG_PCI
 	err = pci_register_driver(&cyberpro_driver);
@@ -1749,14 +1747,15 @@
 
 	return ret ? err : 0;
 }
+module_init(cyber2000fb_init);
 
+#ifndef CONFIG_ARCH_SHARK
 static void __exit cyberpro_exit(void)
 {
 	pci_unregister_driver(&cyberpro_driver);
 }
-
-module_init(cyber2000fb_init);
 module_exit(cyberpro_exit);
+#endif
 
 MODULE_AUTHOR("Russell King");
 MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver");
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index 9894de1..b7af525 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -706,7 +706,7 @@
 	dev_dbg(mx3fb->dev, "irq %d callback\n", ichannel->eof_irq);
 
 	/* We only need one interrupt, it will be re-enabled as needed */
-	disable_irq(ichannel->eof_irq);
+	disable_irq_nosync(ichannel->eof_irq);
 
 	complete(&mx3_fbi->flip_cmpl);
 }
@@ -1366,7 +1366,7 @@
 
 	mx3fb_blank(FB_BLANK_UNBLANK, fbi);
 
-	dev_info(dev, "mx3fb: fb registered, using mode %s\n", fb_mode);
+	dev_info(dev, "registered, using mode %s\n", fb_mode);
 
 	ret = register_framebuffer(fbi);
 	if (ret < 0)
diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c
index 8aa6e47..5d4f348 100644
--- a/drivers/video/omap/hwa742.c
+++ b/drivers/video/omap/hwa742.c
@@ -133,8 +133,7 @@
 	struct lcd_ctrl_extif	*extif;
 	struct lcd_ctrl		*int_ctrl;
 
-	void			(*power_up)(struct device *dev);
-	void			(*power_down)(struct device *dev);
+	struct clk		*sys_ck;
 } hwa742;
 
 struct lcd_ctrl hwa742_ctrl;
@@ -915,14 +914,13 @@
 	hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED);
 	/* Enable sleep mode */
 	hwa742_write_reg(HWA742_POWER_SAVE, 1 << 1);
-	if (hwa742.power_down != NULL)
-		hwa742.power_down(hwa742.fbdev->dev);
+	clk_disable(hwa742.sys_ck);
 }
 
 static void hwa742_resume(void)
 {
-	if (hwa742.power_up != NULL)
-		hwa742.power_up(hwa742.fbdev->dev);
+	clk_enable(hwa742.sys_ck);
+
 	/* Disable sleep mode */
 	hwa742_write_reg(HWA742_POWER_SAVE, 0);
 	while (1) {
@@ -955,14 +953,13 @@
 	omapfb_conf = fbdev->dev->platform_data;
 	ctrl_conf = omapfb_conf->ctrl_platform_data;
 
-	if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) {
+	if (ctrl_conf == NULL) {
 		dev_err(fbdev->dev, "HWA742: missing platform data\n");
 		r = -ENOENT;
 		goto err1;
 	}
 
-	hwa742.power_down = ctrl_conf->power_down;
-	hwa742.power_up = ctrl_conf->power_up;
+	hwa742.sys_ck = clk_get(NULL, "hwa_sys_ck");
 
 	spin_lock_init(&hwa742.req_lock);
 
@@ -972,12 +969,11 @@
 	if ((r = hwa742.extif->init(fbdev)) < 0)
 		goto err2;
 
-	ext_clk = ctrl_conf->get_clock_rate(fbdev->dev);
+	ext_clk = clk_get_rate(hwa742.sys_ck);
 	if ((r = calc_extif_timings(ext_clk, &extif_mem_div)) < 0)
 		goto err3;
 	hwa742.extif->set_timings(&hwa742.reg_timings);
-	if (hwa742.power_up != NULL)
-		hwa742.power_up(fbdev->dev);
+	clk_enable(hwa742.sys_ck);
 
 	calc_hwa742_clk_rates(ext_clk, &sys_clk, &pix_clk);
 	if ((r = calc_extif_timings(sys_clk, &extif_mem_div)) < 0)
@@ -1040,8 +1036,7 @@
 
 	return 0;
 err4:
-	if (hwa742.power_down != NULL)
-		hwa742.power_down(fbdev->dev);
+	clk_disable(hwa742.sys_ck);
 err3:
 	hwa742.extif->cleanup();
 err2:
@@ -1055,8 +1050,7 @@
 	hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED);
 	hwa742.extif->cleanup();
 	hwa742.int_ctrl->cleanup();
-	if (hwa742.power_down != NULL)
-		hwa742.power_down(hwa742.fbdev->dev);
+	clk_disable(hwa742.sys_ck);
 }
 
 struct lcd_ctrl hwa742_ctrl = {
diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c
new file mode 100644
index 0000000..84d8327
--- /dev/null
+++ b/drivers/video/pxa168fb.c
@@ -0,0 +1,803 @@
+/*
+ * linux/drivers/video/pxa168fb.c -- Marvell PXA168 LCD Controller
+ *
+ *  Copyright (C) 2008 Marvell International Ltd.
+ *  All rights reserved.
+ *
+ *  2009-02-16  adapted from original version for PXA168/910
+ *              Jun Nie <njun@marvell.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/uaccess.h>
+#include <video/pxa168fb.h>
+
+#include "pxa168fb.h"
+
+#define DEFAULT_REFRESH		60	/* Hz */
+
+static int determine_best_pix_fmt(struct fb_var_screeninfo *var)
+{
+	/*
+	 * Pseudocolor mode?
+	 */
+	if (var->bits_per_pixel == 8)
+		return PIX_FMT_PSEUDOCOLOR;
+
+	/*
+	 * Check for 565/1555.
+	 */
+	if (var->bits_per_pixel == 16 && var->red.length <= 5 &&
+	    var->green.length <= 6 && var->blue.length <= 5) {
+		if (var->transp.length == 0) {
+			if (var->red.offset >= var->blue.offset)
+				return PIX_FMT_RGB565;
+			else
+				return PIX_FMT_BGR565;
+		}
+
+		if (var->transp.length == 1 && var->green.length <= 5) {
+			if (var->red.offset >= var->blue.offset)
+				return PIX_FMT_RGB1555;
+			else
+				return PIX_FMT_BGR1555;
+		}
+
+		/* fall through */
+	}
+
+	/*
+	 * Check for 888/A888.
+	 */
+	if (var->bits_per_pixel <= 32 && var->red.length <= 8 &&
+	    var->green.length <= 8 && var->blue.length <= 8) {
+		if (var->bits_per_pixel == 24 && var->transp.length == 0) {
+			if (var->red.offset >= var->blue.offset)
+				return PIX_FMT_RGB888PACK;
+			else
+				return PIX_FMT_BGR888PACK;
+		}
+
+		if (var->bits_per_pixel == 32 && var->transp.length == 8) {
+			if (var->red.offset >= var->blue.offset)
+				return PIX_FMT_RGBA888;
+			else
+				return PIX_FMT_BGRA888;
+		} else {
+			if (var->red.offset >= var->blue.offset)
+				return PIX_FMT_RGB888UNPACK;
+			else
+				return PIX_FMT_BGR888UNPACK;
+		}
+
+		/* fall through */
+	}
+
+	return -EINVAL;
+}
+
+static void set_pix_fmt(struct fb_var_screeninfo *var, int pix_fmt)
+{
+	switch (pix_fmt) {
+	case PIX_FMT_RGB565:
+		var->bits_per_pixel = 16;
+		var->red.offset = 11;    var->red.length = 5;
+		var->green.offset = 5;   var->green.length = 6;
+		var->blue.offset = 0;    var->blue.length = 5;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIX_FMT_BGR565:
+		var->bits_per_pixel = 16;
+		var->red.offset = 0;     var->red.length = 5;
+		var->green.offset = 5;   var->green.length = 6;
+		var->blue.offset = 11;   var->blue.length = 5;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIX_FMT_RGB1555:
+		var->bits_per_pixel = 16;
+		var->red.offset = 10;    var->red.length = 5;
+		var->green.offset = 5;   var->green.length = 5;
+		var->blue.offset = 0;    var->blue.length = 5;
+		var->transp.offset = 15; var->transp.length = 1;
+		break;
+	case PIX_FMT_BGR1555:
+		var->bits_per_pixel = 16;
+		var->red.offset = 0;     var->red.length = 5;
+		var->green.offset = 5;   var->green.length = 5;
+		var->blue.offset = 10;   var->blue.length = 5;
+		var->transp.offset = 15; var->transp.length = 1;
+		break;
+	case PIX_FMT_RGB888PACK:
+		var->bits_per_pixel = 24;
+		var->red.offset = 16;    var->red.length = 8;
+		var->green.offset = 8;   var->green.length = 8;
+		var->blue.offset = 0;    var->blue.length = 8;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIX_FMT_BGR888PACK:
+		var->bits_per_pixel = 24;
+		var->red.offset = 0;     var->red.length = 8;
+		var->green.offset = 8;   var->green.length = 8;
+		var->blue.offset = 16;   var->blue.length = 8;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIX_FMT_RGBA888:
+		var->bits_per_pixel = 32;
+		var->red.offset = 16;    var->red.length = 8;
+		var->green.offset = 8;   var->green.length = 8;
+		var->blue.offset = 0;    var->blue.length = 8;
+		var->transp.offset = 24; var->transp.length = 8;
+		break;
+	case PIX_FMT_BGRA888:
+		var->bits_per_pixel = 32;
+		var->red.offset = 0;     var->red.length = 8;
+		var->green.offset = 8;   var->green.length = 8;
+		var->blue.offset = 16;   var->blue.length = 8;
+		var->transp.offset = 24; var->transp.length = 8;
+		break;
+	case PIX_FMT_PSEUDOCOLOR:
+		var->bits_per_pixel = 8;
+		var->red.offset = 0;     var->red.length = 8;
+		var->green.offset = 0;   var->green.length = 8;
+		var->blue.offset = 0;    var->blue.length = 8;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	}
+}
+
+static void set_mode(struct pxa168fb_info *fbi, struct fb_var_screeninfo *var,
+		     struct fb_videomode *mode, int pix_fmt, int ystretch)
+{
+	struct fb_info *info = fbi->info;
+
+	set_pix_fmt(var, pix_fmt);
+
+	var->xres = mode->xres;
+	var->yres = mode->yres;
+	var->xres_virtual = max(var->xres, var->xres_virtual);
+	if (ystretch)
+		var->yres_virtual = info->fix.smem_len /
+			(var->xres_virtual * (var->bits_per_pixel >> 3));
+	else
+		var->yres_virtual = max(var->yres, var->yres_virtual);
+	var->grayscale = 0;
+	var->accel_flags = FB_ACCEL_NONE;
+	var->pixclock = mode->pixclock;
+	var->left_margin = mode->left_margin;
+	var->right_margin = mode->right_margin;
+	var->upper_margin = mode->upper_margin;
+	var->lower_margin = mode->lower_margin;
+	var->hsync_len = mode->hsync_len;
+	var->vsync_len = mode->vsync_len;
+	var->sync = mode->sync;
+	var->vmode = FB_VMODE_NONINTERLACED;
+	var->rotate = FB_ROTATE_UR;
+}
+
+static int pxa168fb_check_var(struct fb_var_screeninfo *var,
+			      struct fb_info *info)
+{
+	struct pxa168fb_info *fbi = info->par;
+	int pix_fmt;
+
+	/*
+	 * Determine which pixel format we're going to use.
+	 */
+	pix_fmt = determine_best_pix_fmt(var);
+	if (pix_fmt < 0)
+		return pix_fmt;
+	set_pix_fmt(var, pix_fmt);
+	fbi->pix_fmt = pix_fmt;
+
+	/*
+	 * Basic geometry sanity checks.
+	 */
+	if (var->xoffset + var->xres > var->xres_virtual)
+		return -EINVAL;
+	if (var->yoffset + var->yres > var->yres_virtual)
+		return -EINVAL;
+	if (var->xres + var->right_margin +
+	    var->hsync_len + var->left_margin > 2048)
+		return -EINVAL;
+	if (var->yres + var->lower_margin +
+	    var->vsync_len + var->upper_margin > 2048)
+		return -EINVAL;
+
+	/*
+	 * Check size of framebuffer.
+	 */
+	if (var->xres_virtual * var->yres_virtual *
+	    (var->bits_per_pixel >> 3) > info->fix.smem_len)
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * The hardware clock divider has an integer and a fractional
+ * stage:
+ *
+ *	clk2 = clk_in / integer_divider
+ *	clk_out = clk2 * (1 - (fractional_divider >> 12))
+ *
+ * Calculate integer and fractional divider for given clk_in
+ * and clk_out.
+ */
+static void set_clock_divider(struct pxa168fb_info *fbi,
+			      const struct fb_videomode *m)
+{
+	int divider_int;
+	int needed_pixclk;
+	u64 div_result;
+	u32 x = 0;
+
+	/*
+	 * Notice: The field pixclock is used by linux fb
+	 * is in pixel second. E.g. struct fb_videomode &
+	 * struct fb_var_screeninfo
+	 */
+
+	/*
+	 * Check input values.
+	 */
+	if (!m || !m->pixclock || !m->refresh) {
+		dev_err(fbi->dev, "Input refresh or pixclock is wrong.\n");
+		return;
+	}
+
+	/*
+	 * Using PLL/AXI clock.
+	 */
+	x = 0x80000000;
+
+	/*
+	 * Calc divider according to refresh rate.
+	 */
+	div_result = 1000000000000ll;
+	do_div(div_result, m->pixclock);
+	needed_pixclk = (u32)div_result;
+
+	divider_int = clk_get_rate(fbi->clk) / needed_pixclk;
+
+	/* check whether divisor is too small. */
+	if (divider_int < 2) {
+		dev_warn(fbi->dev, "Warning: clock source is too slow."
+				"Try smaller resolution\n");
+		divider_int = 2;
+	}
+
+	/*
+	 * Set setting to reg.
+	 */
+	x |= divider_int;
+	writel(x, fbi->reg_base + LCD_CFG_SCLK_DIV);
+}
+
+static void set_dma_control0(struct pxa168fb_info *fbi)
+{
+	u32 x;
+
+	/*
+	 * Set bit to enable graphics DMA.
+	 */
+	x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0);
+	x |= fbi->active ? 0x00000100 : 0;
+	fbi->active = 0;
+
+	/*
+	 * If we are in a pseudo-color mode, we need to enable
+	 * palette lookup.
+	 */
+	if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
+		x |= 0x10000000;
+
+	/*
+	 * Configure hardware pixel format.
+	 */
+	x &= ~(0xF << 16);
+	x |= (fbi->pix_fmt >> 1) << 16;
+
+	/*
+	 * Check red and blue pixel swap.
+	 * 1. source data swap
+	 * 2. panel output data swap
+	 */
+	x &= ~(1 << 12);
+	x |= ((fbi->pix_fmt & 1) ^ (fbi->panel_rbswap)) << 12;
+
+	writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL0);
+}
+
+static void set_dma_control1(struct pxa168fb_info *fbi, int sync)
+{
+	u32 x;
+
+	/*
+	 * Configure default bits: vsync triggers DMA, gated clock
+	 * enable, power save enable, configure alpha registers to
+	 * display 100% graphics, and set pixel command.
+	 */
+	x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL1);
+	x |= 0x2032ff81;
+
+	/*
+	 * We trigger DMA on the falling edge of vsync if vsync is
+	 * active low, or on the rising edge if vsync is active high.
+	 */
+	if (!(sync & FB_SYNC_VERT_HIGH_ACT))
+		x |= 0x08000000;
+
+	writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL1);
+}
+
+static void set_graphics_start(struct fb_info *info, int xoffset, int yoffset)
+{
+	struct pxa168fb_info *fbi = info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	int pixel_offset;
+	unsigned long addr;
+
+	pixel_offset = (yoffset * var->xres_virtual) + xoffset;
+
+	addr = fbi->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3));
+	writel(addr, fbi->reg_base + LCD_CFG_GRA_START_ADDR0);
+}
+
+static void set_dumb_panel_control(struct fb_info *info)
+{
+	struct pxa168fb_info *fbi = info->par;
+	struct pxa168fb_mach_info *mi = fbi->dev->platform_data;
+	u32 x;
+
+	/*
+	 * Preserve enable flag.
+	 */
+	x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL) & 0x00000001;
+
+	x |= (fbi->is_blanked ? 0x7 : mi->dumb_mode) << 28;
+	x |= mi->gpio_output_data << 20;
+	x |= mi->gpio_output_mask << 12;
+	x |= mi->panel_rgb_reverse_lanes ? 0x00000080 : 0;
+	x |= mi->invert_composite_blank ? 0x00000040 : 0;
+	x |= (info->var.sync & FB_SYNC_COMP_HIGH_ACT) ? 0x00000020 : 0;
+	x |= mi->invert_pix_val_ena ? 0x00000010 : 0;
+	x |= (info->var.sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x00000008;
+	x |= (info->var.sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x00000004;
+	x |= mi->invert_pixclock ? 0x00000002 : 0;
+
+	writel(x, fbi->reg_base + LCD_SPU_DUMB_CTRL);
+}
+
+static void set_dumb_screen_dimensions(struct fb_info *info)
+{
+	struct pxa168fb_info *fbi = info->par;
+	struct fb_var_screeninfo *v = &info->var;
+	int x;
+	int y;
+
+	x = v->xres + v->right_margin + v->hsync_len + v->left_margin;
+	y = v->yres + v->lower_margin + v->vsync_len + v->upper_margin;
+
+	writel((y << 16) | x, fbi->reg_base + LCD_SPUT_V_H_TOTAL);
+}
+
+static int pxa168fb_set_par(struct fb_info *info)
+{
+	struct pxa168fb_info *fbi = info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	struct fb_videomode mode;
+	u32 x;
+	struct pxa168fb_mach_info *mi;
+
+	mi = fbi->dev->platform_data;
+
+	/*
+	 * Set additional mode info.
+	 */
+	if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	else
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+	info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+	info->fix.ypanstep = var->yres;
+
+	/*
+	 * Disable panel output while we setup the display.
+	 */
+	x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
+	writel(x & ~1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
+
+	/*
+	 * Configure global panel parameters.
+	 */
+	writel((var->yres << 16) | var->xres,
+		fbi->reg_base + LCD_SPU_V_H_ACTIVE);
+
+	/*
+	 * convet var to video mode
+	 */
+	fb_var_to_videomode(&mode, &info->var);
+
+	/* Calculate clock divisor. */
+	set_clock_divider(fbi, &mode);
+
+	/* Configure dma ctrl regs. */
+	set_dma_control0(fbi);
+	set_dma_control1(fbi, info->var.sync);
+
+	/*
+	 * Configure graphics DMA parameters.
+	 */
+	x = readl(fbi->reg_base + LCD_CFG_GRA_PITCH);
+	x = (x & ~0xFFFF) | ((var->xres_virtual * var->bits_per_pixel) >> 3);
+	writel(x, fbi->reg_base + LCD_CFG_GRA_PITCH);
+	writel((var->yres << 16) | var->xres,
+		fbi->reg_base + LCD_SPU_GRA_HPXL_VLN);
+	writel((var->yres << 16) | var->xres,
+		fbi->reg_base + LCD_SPU_GZM_HPXL_VLN);
+
+	/*
+	 * Configure dumb panel ctrl regs & timings.
+	 */
+	set_dumb_panel_control(info);
+	set_dumb_screen_dimensions(info);
+
+	writel((var->left_margin << 16) | var->right_margin,
+			fbi->reg_base + LCD_SPU_H_PORCH);
+	writel((var->upper_margin << 16) | var->lower_margin,
+			fbi->reg_base + LCD_SPU_V_PORCH);
+
+	/*
+	 * Re-enable panel output.
+	 */
+	x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
+	writel(x | 1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
+
+	return 0;
+}
+
+static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
+{
+	return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
+}
+
+static u32 to_rgb(u16 red, u16 green, u16 blue)
+{
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	return (red << 16) | (green << 8) | blue;
+}
+
+static int
+pxa168fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
+		 unsigned int blue, unsigned int trans, struct fb_info *info)
+{
+	struct pxa168fb_info *fbi = info->par;
+	u32 val;
+
+	if (info->var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green +
+					7471 * blue) >> 16;
+
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) {
+		val =  chan_to_field(red,   &info->var.red);
+		val |= chan_to_field(green, &info->var.green);
+		val |= chan_to_field(blue , &info->var.blue);
+		fbi->pseudo_palette[regno] = val;
+	}
+
+	if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
+		val = to_rgb(red, green, blue);
+		writel(val, fbi->reg_base + LCD_SPU_SRAM_WRDAT);
+		writel(0x8300 | regno, fbi->reg_base + LCD_SPU_SRAM_CTRL);
+	}
+
+	return 0;
+}
+
+static int pxa168fb_blank(int blank, struct fb_info *info)
+{
+	struct pxa168fb_info *fbi = info->par;
+
+	fbi->is_blanked = (blank == FB_BLANK_UNBLANK) ? 0 : 1;
+	set_dumb_panel_control(info);
+
+	return 0;
+}
+
+static int pxa168fb_pan_display(struct fb_var_screeninfo *var,
+				struct fb_info *info)
+{
+	set_graphics_start(info, var->xoffset, var->yoffset);
+
+	return 0;
+}
+
+static irqreturn_t pxa168fb_handle_irq(int irq, void *dev_id)
+{
+	struct pxa168fb_info *fbi = dev_id;
+	u32 isr = readl(fbi->reg_base + SPU_IRQ_ISR);
+
+	if ((isr & GRA_FRAME_IRQ0_ENA_MASK)) {
+
+		writel(isr & (~GRA_FRAME_IRQ0_ENA_MASK),
+			fbi->reg_base + SPU_IRQ_ISR);
+
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+
+static struct fb_ops pxa168fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= pxa168fb_check_var,
+	.fb_set_par	= pxa168fb_set_par,
+	.fb_setcolreg	= pxa168fb_setcolreg,
+	.fb_blank	= pxa168fb_blank,
+	.fb_pan_display	= pxa168fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+static int __init pxa168fb_init_mode(struct fb_info *info,
+			      struct pxa168fb_mach_info *mi)
+{
+	struct pxa168fb_info *fbi = info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	int ret = 0;
+	u32 total_w, total_h, refresh;
+	u64 div_result;
+	const struct fb_videomode *m;
+
+	/*
+	 * Set default value
+	 */
+	refresh = DEFAULT_REFRESH;
+
+	/* try to find best video mode. */
+	m = fb_find_best_mode(&info->var, &info->modelist);
+	if (m)
+		fb_videomode_to_var(&info->var, m);
+
+	/* Init settings. */
+	var->xres_virtual = var->xres;
+	var->yres_virtual = info->fix.smem_len /
+		(var->xres_virtual * (var->bits_per_pixel >> 3));
+	dev_dbg(fbi->dev, "pxa168fb: find best mode: res = %dx%d\n",
+				var->xres, var->yres);
+
+	/* correct pixclock. */
+	total_w = var->xres + var->left_margin + var->right_margin +
+		  var->hsync_len;
+	total_h = var->yres + var->upper_margin + var->lower_margin +
+		  var->vsync_len;
+
+	div_result = 1000000000000ll;
+	do_div(div_result, total_w * total_h * refresh);
+	var->pixclock = (u32)div_result;
+
+	return ret;
+}
+
+static int __init pxa168fb_probe(struct platform_device *pdev)
+{
+	struct pxa168fb_mach_info *mi;
+	struct fb_info *info = 0;
+	struct pxa168fb_info *fbi = 0;
+	struct resource *res;
+	struct clk *clk;
+	int irq, ret;
+
+	mi = pdev->dev.platform_data;
+	if (mi == NULL) {
+		dev_err(&pdev->dev, "no platform data defined\n");
+		return -EINVAL;
+	}
+
+	clk = clk_get(&pdev->dev, "LCDCLK");
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "unable to get LCDCLK");
+		return PTR_ERR(clk);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "no IO memory defined\n");
+		return -ENOENT;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "no IRQ defined\n");
+		return -ENOENT;
+	}
+
+	info = framebuffer_alloc(sizeof(struct pxa168fb_info), &pdev->dev);
+	if (info == NULL) {
+		clk_put(clk);
+		return -ENOMEM;
+	}
+
+	/* Initialize private data */
+	fbi = info->par;
+	fbi->info = info;
+	fbi->clk = clk;
+	fbi->dev = info->dev = &pdev->dev;
+	fbi->panel_rbswap = mi->panel_rbswap;
+	fbi->is_blanked = 0;
+	fbi->active = mi->active;
+
+	/*
+	 * Initialise static fb parameters.
+	 */
+	info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK |
+		      FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
+	info->node = -1;
+	strlcpy(info->fix.id, mi->id, 16);
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.type_aux = 0;
+	info->fix.xpanstep = 0;
+	info->fix.ypanstep = 0;
+	info->fix.ywrapstep = 0;
+	info->fix.mmio_start = res->start;
+	info->fix.mmio_len = res->end - res->start + 1;
+	info->fix.accel = FB_ACCEL_NONE;
+	info->fbops = &pxa168fb_ops;
+	info->pseudo_palette = fbi->pseudo_palette;
+
+	/*
+	 * Map LCD controller registers.
+	 */
+	fbi->reg_base = ioremap_nocache(res->start, res->end - res->start);
+	if (fbi->reg_base == NULL) {
+		ret = -ENOMEM;
+		goto failed;
+	}
+
+	/*
+	 * Allocate framebuffer memory.
+	 */
+	info->fix.smem_len = PAGE_ALIGN(DEFAULT_FB_SIZE);
+
+	info->screen_base = dma_alloc_writecombine(fbi->dev, info->fix.smem_len,
+						&fbi->fb_start_dma, GFP_KERNEL);
+	if (info->screen_base == NULL) {
+		ret = -ENOMEM;
+		goto failed;
+	}
+
+	info->fix.smem_start = (unsigned long)fbi->fb_start_dma;
+
+	/*
+	 * Set video mode according to platform data.
+	 */
+	set_mode(fbi, &info->var, mi->modes, mi->pix_fmt, 1);
+
+	fb_videomode_to_modelist(mi->modes, mi->num_modes, &info->modelist);
+
+	/*
+	 * init video mode data.
+	 */
+	pxa168fb_init_mode(info, mi);
+
+	ret = pxa168fb_check_var(&info->var, info);
+	if (ret)
+		goto failed_free_fbmem;
+
+	/*
+	 * Fill in sane defaults.
+	 */
+	ret = pxa168fb_check_var(&info->var, info);
+	if (ret)
+		goto failed;
+
+	/*
+	 * enable controller clock
+	 */
+	clk_enable(fbi->clk);
+
+	pxa168fb_set_par(info);
+
+	/*
+	 * Configure default register values.
+	 */
+	writel(0, fbi->reg_base + LCD_SPU_BLANKCOLOR);
+	writel(mi->io_pin_allocation_mode, fbi->reg_base + SPU_IOPAD_CONTROL);
+	writel(0, fbi->reg_base + LCD_CFG_GRA_START_ADDR1);
+	writel(0, fbi->reg_base + LCD_SPU_GRA_OVSA_HPXL_VLN);
+	writel(0, fbi->reg_base + LCD_SPU_SRAM_PARA0);
+	writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1),
+		fbi->reg_base + LCD_SPU_SRAM_PARA1);
+
+	/*
+	 * Allocate color map.
+	 */
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+		ret = -ENOMEM;
+		goto failed_free_clk;
+	}
+
+	/*
+	 * Register irq handler.
+	 */
+	ret = request_irq(irq, pxa168fb_handle_irq, IRQF_SHARED,
+					info->fix.id, fbi);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "unable to request IRQ\n");
+		ret = -ENXIO;
+		goto failed_free_cmap;
+	}
+
+	/*
+	 * Enable GFX interrupt
+	 */
+	writel(GRA_FRAME_IRQ0_ENA(0x1), fbi->reg_base + SPU_IRQ_ENA);
+
+	/*
+	 * Register framebuffer.
+	 */
+	ret = register_framebuffer(info);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register pxa168-fb: %d\n", ret);
+		ret = -ENXIO;
+		goto failed_free_irq;
+	}
+
+	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:
+	clk_disable(fbi->clk);
+failed_free_fbmem:
+	dma_free_coherent(fbi->dev, info->fix.smem_len,
+			info->screen_base, fbi->fb_start_dma);
+failed:
+	kfree(info);
+	clk_put(clk);
+
+	dev_err(&pdev->dev, "frame buffer device init failed with %d\n", ret);
+	return ret;
+}
+
+static struct platform_driver pxa168fb_driver = {
+	.driver		= {
+		.name	= "pxa168-fb",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= pxa168fb_probe,
+};
+
+static int __devinit pxa168fb_init(void)
+{
+	return platform_driver_register(&pxa168fb_driver);
+}
+module_init(pxa168fb_init);
+
+MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> "
+	      "Green Wan <gwan@marvell.com>");
+MODULE_DESCRIPTION("Framebuffer driver for PXA168/910");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/pxa168fb.h b/drivers/video/pxa168fb.h
new file mode 100644
index 0000000..eee0927
--- /dev/null
+++ b/drivers/video/pxa168fb.h
@@ -0,0 +1,558 @@
+#ifndef __PXA168FB_H__
+#define __PXA168FB_H__
+
+/* ------------< LCD register >------------ */
+/* Video Frame 0&1 start address registers */
+#define	LCD_SPU_DMA_START_ADDR_Y0		0x00C0
+#define	LCD_SPU_DMA_START_ADDR_U0		0x00C4
+#define	LCD_SPU_DMA_START_ADDR_V0		0x00C8
+#define LCD_CFG_DMA_START_ADDR_0		0x00CC /* Cmd address */
+#define	LCD_SPU_DMA_START_ADDR_Y1		0x00D0
+#define	LCD_SPU_DMA_START_ADDR_U1		0x00D4
+#define	LCD_SPU_DMA_START_ADDR_V1		0x00D8
+#define LCD_CFG_DMA_START_ADDR_1		0x00DC /* Cmd address */
+
+/* YC & UV Pitch */
+#define LCD_SPU_DMA_PITCH_YC			0x00E0
+#define     SPU_DMA_PITCH_C(c)			((c) << 16)
+#define     SPU_DMA_PITCH_Y(y)			(y)
+#define LCD_SPU_DMA_PITCH_UV			0x00E4
+#define     SPU_DMA_PITCH_V(v)			((v) << 16)
+#define     SPU_DMA_PITCH_U(u)			(u)
+
+/* Video Starting Point on Screen Register */
+#define LCD_SPUT_DMA_OVSA_HPXL_VLN		0x00E8
+#define     CFG_DMA_OVSA_VLN(y)			((y) << 16) /* 0~0xfff */
+#define     CFG_DMA_OVSA_HPXL(x)		(x)     /* 0~0xfff */
+
+/* Video Size Register */
+#define LCD_SPU_DMA_HPXL_VLN			0x00EC
+#define     CFG_DMA_VLN(y)			((y) << 16)
+#define     CFG_DMA_HPXL(x)			(x)
+
+/* Video Size After zooming Register */
+#define LCD_SPU_DZM_HPXL_VLN			0x00F0
+#define     CFG_DZM_VLN(y)			((y) << 16)
+#define     CFG_DZM_HPXL(x)			(x)
+
+/* Graphic Frame 0&1 Starting Address Register */
+#define LCD_CFG_GRA_START_ADDR0			0x00F4
+#define LCD_CFG_GRA_START_ADDR1			0x00F8
+
+/* Graphic Frame Pitch */
+#define LCD_CFG_GRA_PITCH			0x00FC
+
+/* Graphic Starting Point on Screen Register */
+#define LCD_SPU_GRA_OVSA_HPXL_VLN		0x0100
+#define     CFG_GRA_OVSA_VLN(y)			((y) << 16)
+#define     CFG_GRA_OVSA_HPXL(x)		(x)
+
+/* Graphic Size Register */
+#define LCD_SPU_GRA_HPXL_VLN			0x0104
+#define     CFG_GRA_VLN(y)			((y) << 16)
+#define     CFG_GRA_HPXL(x)			(x)
+
+/* Graphic Size after Zooming Register */
+#define LCD_SPU_GZM_HPXL_VLN			0x0108
+#define     CFG_GZM_VLN(y)			((y) << 16)
+#define     CFG_GZM_HPXL(x)			(x)
+
+/* HW Cursor Starting Point on Screen Register */
+#define LCD_SPU_HWC_OVSA_HPXL_VLN		0x010C
+#define     CFG_HWC_OVSA_VLN(y)			((y) << 16)
+#define     CFG_HWC_OVSA_HPXL(x)		(x)
+
+/* HW Cursor Size */
+#define LCD_SPU_HWC_HPXL_VLN			0x0110
+#define     CFG_HWC_VLN(y)			((y) << 16)
+#define     CFG_HWC_HPXL(x)			(x)
+
+/* Total Screen Size Register */
+#define LCD_SPUT_V_H_TOTAL			0x0114
+#define     CFG_V_TOTAL(y)			((y) << 16)
+#define     CFG_H_TOTAL(x)			(x)
+
+/* Total Screen Active Size Register */
+#define LCD_SPU_V_H_ACTIVE			0x0118
+#define     CFG_V_ACTIVE(y)			((y) << 16)
+#define     CFG_H_ACTIVE(x)			(x)
+
+/* Screen H&V Porch Register */
+#define LCD_SPU_H_PORCH				0x011C
+#define     CFG_H_BACK_PORCH(b)			((b) << 16)
+#define     CFG_H_FRONT_PORCH(f)		(f)
+#define LCD_SPU_V_PORCH				0x0120
+#define     CFG_V_BACK_PORCH(b)			((b) << 16)
+#define     CFG_V_FRONT_PORCH(f)		(f)
+
+/* Screen Blank Color Register */
+#define LCD_SPU_BLANKCOLOR			0x0124
+#define     CFG_BLANKCOLOR_MASK			0x00FFFFFF
+#define     CFG_BLANKCOLOR_R_MASK		0x000000FF
+#define     CFG_BLANKCOLOR_G_MASK		0x0000FF00
+#define     CFG_BLANKCOLOR_B_MASK		0x00FF0000
+
+/* HW Cursor Color 1&2 Register */
+#define LCD_SPU_ALPHA_COLOR1			0x0128
+#define     CFG_HWC_COLOR1			0x00FFFFFF
+#define     CFG_HWC_COLOR1_R(red)		((red) << 16)
+#define     CFG_HWC_COLOR1_G(green)		((green) << 8)
+#define     CFG_HWC_COLOR1_B(blue)		(blue)
+#define     CFG_HWC_COLOR1_R_MASK		0x000000FF
+#define     CFG_HWC_COLOR1_G_MASK		0x0000FF00
+#define     CFG_HWC_COLOR1_B_MASK		0x00FF0000
+#define LCD_SPU_ALPHA_COLOR2			0x012C
+#define     CFG_HWC_COLOR2			0x00FFFFFF
+#define     CFG_HWC_COLOR2_R_MASK		0x000000FF
+#define     CFG_HWC_COLOR2_G_MASK		0x0000FF00
+#define     CFG_HWC_COLOR2_B_MASK		0x00FF0000
+
+/* Video YUV Color Key Control */
+#define LCD_SPU_COLORKEY_Y			0x0130
+#define     CFG_CKEY_Y2(y2)			((y2) << 24)
+#define     CFG_CKEY_Y2_MASK			0xFF000000
+#define     CFG_CKEY_Y1(y1)			((y1) << 16)
+#define     CFG_CKEY_Y1_MASK			0x00FF0000
+#define     CFG_CKEY_Y(y)			((y) << 8)
+#define     CFG_CKEY_Y_MASK			0x0000FF00
+#define     CFG_ALPHA_Y(y)			(y)
+#define     CFG_ALPHA_Y_MASK			0x000000FF
+#define LCD_SPU_COLORKEY_U			0x0134
+#define     CFG_CKEY_U2(u2)			((u2) << 24)
+#define     CFG_CKEY_U2_MASK			0xFF000000
+#define     CFG_CKEY_U1(u1)			((u1) << 16)
+#define     CFG_CKEY_U1_MASK			0x00FF0000
+#define     CFG_CKEY_U(u)			((u) << 8)
+#define     CFG_CKEY_U_MASK			0x0000FF00
+#define     CFG_ALPHA_U(u)			(u)
+#define     CFG_ALPHA_U_MASK			0x000000FF
+#define LCD_SPU_COLORKEY_V			0x0138
+#define     CFG_CKEY_V2(v2)			((v2) << 24)
+#define     CFG_CKEY_V2_MASK			0xFF000000
+#define     CFG_CKEY_V1(v1)			((v1) << 16)
+#define     CFG_CKEY_V1_MASK			0x00FF0000
+#define     CFG_CKEY_V(v)			((v) << 8)
+#define     CFG_CKEY_V_MASK			0x0000FF00
+#define     CFG_ALPHA_V(v)			(v)
+#define     CFG_ALPHA_V_MASK			0x000000FF
+
+/* SPI Read Data Register */
+#define LCD_SPU_SPI_RXDATA			0x0140
+
+/* Smart Panel Read Data Register */
+#define LCD_SPU_ISA_RSDATA			0x0144
+#define     ISA_RXDATA_16BIT_1_DATA_MASK	0x000000FF
+#define     ISA_RXDATA_16BIT_2_DATA_MASK	0x0000FF00
+#define     ISA_RXDATA_16BIT_3_DATA_MASK	0x00FF0000
+#define     ISA_RXDATA_16BIT_4_DATA_MASK	0xFF000000
+#define     ISA_RXDATA_32BIT_1_DATA_MASK	0x00FFFFFF
+
+/* HWC SRAM Read Data Register */
+#define LCD_SPU_HWC_RDDAT			0x0158
+
+/* Gamma Table SRAM Read Data Register */
+#define LCD_SPU_GAMMA_RDDAT			0x015c
+#define     CFG_GAMMA_RDDAT_MASK		0x000000FF
+
+/* Palette Table SRAM Read Data Register */
+#define LCD_SPU_PALETTE_RDDAT			0x0160
+#define     CFG_PALETTE_RDDAT_MASK		0x00FFFFFF
+
+/* I/O Pads Input Read Only Register */
+#define LCD_SPU_IOPAD_IN			0x0178
+#define     CFG_IOPAD_IN_MASK			0x0FFFFFFF
+
+/* Reserved Read Only Registers */
+#define LCD_CFG_RDREG5F				0x017C
+#define     IRE_FRAME_CNT_MASK			0x000000C0
+#define     IPE_FRAME_CNT_MASK			0x00000030
+#define     GRA_FRAME_CNT_MASK			0x0000000C  /* Graphic */
+#define     DMA_FRAME_CNT_MASK			0x00000003  /* Video */
+
+/* SPI Control Register. */
+#define LCD_SPU_SPI_CTRL			0x0180
+#define     CFG_SCLKCNT(div)			((div) << 24)  /* 0xFF~0x2 */
+#define     CFG_SCLKCNT_MASK			0xFF000000
+#define     CFG_RXBITS(rx)			((rx) << 16)   /* 0x1F~0x1 */
+#define     CFG_RXBITS_MASK			0x00FF0000
+#define     CFG_TXBITS(tx)			((tx) << 8)    /* 0x1F~0x1 */
+#define     CFG_TXBITS_MASK			0x0000FF00
+#define     CFG_CLKINV(clk)			((clk) << 7)
+#define     CFG_CLKINV_MASK			0x00000080
+#define     CFG_KEEPXFER(transfer)		((transfer) << 6)
+#define     CFG_KEEPXFER_MASK			0x00000040
+#define     CFG_RXBITSTO0(rx)			((rx) << 5)
+#define     CFG_RXBITSTO0_MASK			0x00000020
+#define     CFG_TXBITSTO0(tx)			((tx) << 4)
+#define     CFG_TXBITSTO0_MASK			0x00000010
+#define     CFG_SPI_ENA(spi)			((spi) << 3)
+#define     CFG_SPI_ENA_MASK			0x00000008
+#define     CFG_SPI_SEL(spi)			((spi) << 2)
+#define     CFG_SPI_SEL_MASK			0x00000004
+#define     CFG_SPI_3W4WB(wire)			((wire) << 1)
+#define     CFG_SPI_3W4WB_MASK			0x00000002
+#define     CFG_SPI_START(start)		(start)
+#define     CFG_SPI_START_MASK			0x00000001
+
+/* SPI Tx Data Register */
+#define LCD_SPU_SPI_TXDATA			0x0184
+
+/*
+   1. Smart Pannel 8-bit Bus Control Register.
+   2. AHB Slave Path Data Port Register
+*/
+#define LCD_SPU_SMPN_CTRL			0x0188
+
+/* DMA Control 0 Register */
+#define LCD_SPU_DMA_CTRL0			0x0190
+#define     CFG_NOBLENDING(nb)			((nb) << 31)
+#define     CFG_NOBLENDING_MASK			0x80000000
+#define     CFG_GAMMA_ENA(gn)			((gn) << 30)
+#define     CFG_GAMMA_ENA_MASK			0x40000000
+#define     CFG_CBSH_ENA(cn)			((cn) << 29)
+#define     CFG_CBSH_ENA_MASK			0x20000000
+#define     CFG_PALETTE_ENA(pn)			((pn) << 28)
+#define     CFG_PALETTE_ENA_MASK		0x10000000
+#define     CFG_ARBFAST_ENA(an)			((an) << 27)
+#define     CFG_ARBFAST_ENA_MASK		0x08000000
+#define     CFG_HWC_1BITMOD(mode)		((mode) << 26)
+#define     CFG_HWC_1BITMOD_MASK		0x04000000
+#define     CFG_HWC_1BITENA(mn)			((mn) << 25)
+#define     CFG_HWC_1BITENA_MASK		0x02000000
+#define     CFG_HWC_ENA(cn)		        ((cn) << 24)
+#define     CFG_HWC_ENA_MASK			0x01000000
+#define     CFG_DMAFORMAT(dmaformat)		((dmaformat) << 20)
+#define     CFG_DMAFORMAT_MASK			0x00F00000
+#define     CFG_GRAFORMAT(graformat)		((graformat) << 16)
+#define     CFG_GRAFORMAT_MASK			0x000F0000
+/* for graphic part */
+#define     CFG_GRA_FTOGGLE(toggle)		((toggle) << 15)
+#define     CFG_GRA_FTOGGLE_MASK		0x00008000
+#define     CFG_GRA_HSMOOTH(smooth)		((smooth) << 14)
+#define     CFG_GRA_HSMOOTH_MASK		0x00004000
+#define     CFG_GRA_TSTMODE(test)		((test) << 13)
+#define     CFG_GRA_TSTMODE_MASK		0x00002000
+#define     CFG_GRA_SWAPRB(swap)		((swap) << 12)
+#define     CFG_GRA_SWAPRB_MASK			0x00001000
+#define     CFG_GRA_SWAPUV(swap)		((swap) << 11)
+#define     CFG_GRA_SWAPUV_MASK			0x00000800
+#define     CFG_GRA_SWAPYU(swap)		((swap) << 10)
+#define     CFG_GRA_SWAPYU_MASK			0x00000400
+#define     CFG_YUV2RGB_GRA(cvrt)		((cvrt) << 9)
+#define     CFG_YUV2RGB_GRA_MASK		0x00000200
+#define     CFG_GRA_ENA(gra)			((gra) << 8)
+#define     CFG_GRA_ENA_MASK			0x00000100
+/* for video part */
+#define     CFG_DMA_FTOGGLE(toggle)		((toggle) << 7)
+#define     CFG_DMA_FTOGGLE_MASK		0x00000080
+#define     CFG_DMA_HSMOOTH(smooth)		((smooth) << 6)
+#define     CFG_DMA_HSMOOTH_MASK		0x00000040
+#define     CFG_DMA_TSTMODE(test)		((test) << 5)
+#define     CFG_DMA_TSTMODE_MASK		0x00000020
+#define     CFG_DMA_SWAPRB(swap)		((swap) << 4)
+#define     CFG_DMA_SWAPRB_MASK			0x00000010
+#define     CFG_DMA_SWAPUV(swap)		((swap) << 3)
+#define     CFG_DMA_SWAPUV_MASK			0x00000008
+#define     CFG_DMA_SWAPYU(swap)		((swap) << 2)
+#define     CFG_DMA_SWAPYU_MASK			0x00000004
+#define     CFG_DMA_SWAP_MASK			0x0000001C
+#define     CFG_YUV2RGB_DMA(cvrt)		((cvrt) << 1)
+#define     CFG_YUV2RGB_DMA_MASK		0x00000002
+#define     CFG_DMA_ENA(video)			(video)
+#define     CFG_DMA_ENA_MASK			0x00000001
+
+/* DMA Control 1 Register */
+#define LCD_SPU_DMA_CTRL1			0x0194
+#define     CFG_FRAME_TRIG(trig)		((trig) << 31)
+#define     CFG_FRAME_TRIG_MASK			0x80000000
+#define     CFG_VSYNC_TRIG(trig)		((trig) << 28)
+#define     CFG_VSYNC_TRIG_MASK			0x70000000
+#define     CFG_VSYNC_INV(inv)			((inv) << 27)
+#define     CFG_VSYNC_INV_MASK			0x08000000
+#define     CFG_COLOR_KEY_MODE(cmode)		((cmode) << 24)
+#define     CFG_COLOR_KEY_MASK			0x07000000
+#define     CFG_CARRY(carry)			((carry) << 23)
+#define     CFG_CARRY_MASK			0x00800000
+#define     CFG_LNBUF_ENA(lnbuf)		((lnbuf) << 22)
+#define     CFG_LNBUF_ENA_MASK			0x00400000
+#define     CFG_GATED_ENA(gated)		((gated) << 21)
+#define     CFG_GATED_ENA_MASK			0x00200000
+#define     CFG_PWRDN_ENA(power)		((power) << 20)
+#define     CFG_PWRDN_ENA_MASK			0x00100000
+#define     CFG_DSCALE(dscale)			((dscale) << 18)
+#define     CFG_DSCALE_MASK			0x000C0000
+#define     CFG_ALPHA_MODE(amode)		((amode) << 16)
+#define     CFG_ALPHA_MODE_MASK			0x00030000
+#define     CFG_ALPHA(alpha)			((alpha) << 8)
+#define     CFG_ALPHA_MASK			0x0000FF00
+#define     CFG_PXLCMD(pxlcmd)			(pxlcmd)
+#define     CFG_PXLCMD_MASK			0x000000FF
+
+/* SRAM Control Register */
+#define LCD_SPU_SRAM_CTRL			0x0198
+#define     CFG_SRAM_INIT_WR_RD(mode)		((mode) << 14)
+#define     CFG_SRAM_INIT_WR_RD_MASK		0x0000C000
+#define     CFG_SRAM_ADDR_LCDID(id)		((id) << 8)
+#define     CFG_SRAM_ADDR_LCDID_MASK		0x00000F00
+#define     CFG_SRAM_ADDR(addr)			(addr)
+#define     CFG_SRAM_ADDR_MASK			0x000000FF
+
+/* SRAM Write Data Register */
+#define LCD_SPU_SRAM_WRDAT			0x019C
+
+/* SRAM RTC/WTC Control Register */
+#define LCD_SPU_SRAM_PARA0			0x01A0
+
+/* SRAM Power Down Control Register */
+#define LCD_SPU_SRAM_PARA1			0x01A4
+#define     CFG_CSB_256x32(hwc)			((hwc) << 15)	/* HWC */
+#define     CFG_CSB_256x32_MASK			0x00008000
+#define     CFG_CSB_256x24(palette)		((palette) << 14)	/* Palette */
+#define     CFG_CSB_256x24_MASK			0x00004000
+#define     CFG_CSB_256x8(gamma)		((gamma) << 13)	/* Gamma */
+#define     CFG_CSB_256x8_MASK			0x00002000
+#define     CFG_PDWN256x32(pdwn)		((pdwn) << 7)	/* HWC */
+#define     CFG_PDWN256x32_MASK			0x00000080
+#define     CFG_PDWN256x24(pdwn)		((pdwn) << 6)	/* Palette */
+#define     CFG_PDWN256x24_MASK			0x00000040
+#define     CFG_PDWN256x8(pdwn)			((pdwn) << 5)	/* Gamma */
+#define     CFG_PDWN256x8_MASK			0x00000020
+#define     CFG_PDWN32x32(pdwn)			((pdwn) << 3)
+#define     CFG_PDWN32x32_MASK			0x00000008
+#define     CFG_PDWN16x66(pdwn)			((pdwn) << 2)
+#define     CFG_PDWN16x66_MASK			0x00000004
+#define     CFG_PDWN32x66(pdwn)			((pdwn) << 1)
+#define     CFG_PDWN32x66_MASK			0x00000002
+#define     CFG_PDWN64x66(pdwn)			(pdwn)
+#define     CFG_PDWN64x66_MASK			0x00000001
+
+/* Smart or Dumb Panel Clock Divider */
+#define LCD_CFG_SCLK_DIV			0x01A8
+#define     SCLK_SOURCE_SELECT(src)		((src) << 31)
+#define     SCLK_SOURCE_SELECT_MASK		0x80000000
+#define     CLK_FRACDIV(frac)			((frac) << 16)
+#define     CLK_FRACDIV_MASK			0x0FFF0000
+#define     CLK_INT_DIV(div)			(div)
+#define     CLK_INT_DIV_MASK			0x0000FFFF
+
+/* Video Contrast Register */
+#define LCD_SPU_CONTRAST			0x01AC
+#define     CFG_BRIGHTNESS(bright)		((bright) << 16)
+#define     CFG_BRIGHTNESS_MASK			0xFFFF0000
+#define     CFG_CONTRAST(contrast)		(contrast)
+#define     CFG_CONTRAST_MASK			0x0000FFFF
+
+/* Video Saturation Register */
+#define LCD_SPU_SATURATION			0x01B0
+#define     CFG_C_MULTS(mult)			((mult) << 16)
+#define     CFG_C_MULTS_MASK			0xFFFF0000
+#define     CFG_SATURATION(sat)			(sat)
+#define     CFG_SATURATION_MASK			0x0000FFFF
+
+/* Video Hue Adjust Register */
+#define LCD_SPU_CBSH_HUE			0x01B4
+#define     CFG_SIN0(sin0)			((sin0) << 16)
+#define     CFG_SIN0_MASK			0xFFFF0000
+#define     CFG_COS0(con0)			(con0)
+#define     CFG_COS0_MASK			0x0000FFFF
+
+/* Dump LCD Panel Control Register */
+#define LCD_SPU_DUMB_CTRL			0x01B8
+#define     CFG_DUMBMODE(mode)			((mode) << 28)
+#define     CFG_DUMBMODE_MASK			0xF0000000
+#define     CFG_LCDGPIO_O(data)			((data) << 20)
+#define     CFG_LCDGPIO_O_MASK			0x0FF00000
+#define     CFG_LCDGPIO_ENA(gpio)		((gpio) << 12)
+#define     CFG_LCDGPIO_ENA_MASK		0x000FF000
+#define     CFG_BIAS_OUT(bias)			((bias) << 8)
+#define     CFG_BIAS_OUT_MASK			0x00000100
+#define     CFG_REVERSE_RGB(rRGB)		((rRGB) << 7)
+#define     CFG_REVERSE_RGB_MASK		0x00000080
+#define     CFG_INV_COMPBLANK(blank)		((blank) << 6)
+#define     CFG_INV_COMPBLANK_MASK		0x00000040
+#define     CFG_INV_COMPSYNC(sync)		((sync) << 5)
+#define     CFG_INV_COMPSYNC_MASK		0x00000020
+#define     CFG_INV_HENA(hena)			((hena) << 4)
+#define     CFG_INV_HENA_MASK			0x00000010
+#define     CFG_INV_VSYNC(vsync)		((vsync) << 3)
+#define     CFG_INV_VSYNC_MASK			0x00000008
+#define     CFG_INV_HSYNC(hsync)		((hsync) << 2)
+#define     CFG_INV_HSYNC_MASK			0x00000004
+#define     CFG_INV_PCLK(pclk)			((pclk) << 1)
+#define     CFG_INV_PCLK_MASK			0x00000002
+#define     CFG_DUMB_ENA(dumb)			(dumb)
+#define     CFG_DUMB_ENA_MASK			0x00000001
+
+/* LCD I/O Pads Control Register */
+#define SPU_IOPAD_CONTROL			0x01BC
+#define     CFG_GRA_VM_ENA(vm)			((vm) << 15)        /* gfx */
+#define     CFG_GRA_VM_ENA_MASK			0x00008000
+#define     CFG_DMA_VM_ENA(vm)			((vm) << 13)	/* video */
+#define     CFG_DMA_VM_ENA_MASK			0x00002000
+#define     CFG_CMD_VM_ENA(vm)			((vm) << 13)
+#define     CFG_CMD_VM_ENA_MASK			0x00000800
+#define     CFG_CSC(csc)			((csc) << 8)	/* csc */
+#define     CFG_CSC_MASK			0x00000300
+#define     CFG_AXICTRL(axi)			((axi) << 4)
+#define     CFG_AXICTRL_MASK			0x000000F0
+#define     CFG_IOPADMODE(iopad)		(iopad)
+#define     CFG_IOPADMODE_MASK			0x0000000F
+
+/* LCD Interrupt Control Register */
+#define SPU_IRQ_ENA				0x01C0
+#define     DMA_FRAME_IRQ0_ENA(irq)		((irq) << 31)
+#define     DMA_FRAME_IRQ0_ENA_MASK		0x80000000
+#define     DMA_FRAME_IRQ1_ENA(irq)		((irq) << 30)
+#define     DMA_FRAME_IRQ1_ENA_MASK		0x40000000
+#define     DMA_FF_UNDERFLOW_ENA(ff)		((ff) << 29)
+#define     DMA_FF_UNDERFLOW_ENA_MASK		0x20000000
+#define     GRA_FRAME_IRQ0_ENA(irq)		((irq) << 27)
+#define     GRA_FRAME_IRQ0_ENA_MASK		0x08000000
+#define     GRA_FRAME_IRQ1_ENA(irq)		((irq) << 26)
+#define     GRA_FRAME_IRQ1_ENA_MASK		0x04000000
+#define     GRA_FF_UNDERFLOW_ENA(ff)		((ff) << 25)
+#define     GRA_FF_UNDERFLOW_ENA_MASK		0x02000000
+#define     VSYNC_IRQ_ENA(vsync_irq)		((vsync_irq) << 23)
+#define     VSYNC_IRQ_ENA_MASK			0x00800000
+#define     DUMB_FRAMEDONE_ENA(fdone)		((fdone) << 22)
+#define     DUMB_FRAMEDONE_ENA_MASK		0x00400000
+#define     TWC_FRAMEDONE_ENA(fdone)		((fdone) << 21)
+#define     TWC_FRAMEDONE_ENA_MASK		0x00200000
+#define     HWC_FRAMEDONE_ENA(fdone)		((fdone) << 20)
+#define     HWC_FRAMEDONE_ENA_MASK		0x00100000
+#define     SLV_IRQ_ENA(irq)			((irq) << 19)
+#define     SLV_IRQ_ENA_MASK			0x00080000
+#define     SPI_IRQ_ENA(irq)			((irq) << 18)
+#define     SPI_IRQ_ENA_MASK			0x00040000
+#define     PWRDN_IRQ_ENA(irq)			((irq) << 17)
+#define     PWRDN_IRQ_ENA_MASK			0x00020000
+#define     ERR_IRQ_ENA(irq)			((irq) << 16)
+#define     ERR_IRQ_ENA_MASK			0x00010000
+#define     CLEAN_SPU_IRQ_ISR(irq)		(irq)
+#define     CLEAN_SPU_IRQ_ISR_MASK		0x0000FFFF
+
+/* LCD Interrupt Status Register */
+#define SPU_IRQ_ISR				0x01C4
+#define     DMA_FRAME_IRQ0(irq)			((irq) << 31)
+#define     DMA_FRAME_IRQ0_MASK			0x80000000
+#define     DMA_FRAME_IRQ1(irq)			((irq) << 30)
+#define     DMA_FRAME_IRQ1_MASK			0x40000000
+#define     DMA_FF_UNDERFLOW(ff)		((ff) << 29)
+#define     DMA_FF_UNDERFLOW_MASK		0x20000000
+#define     GRA_FRAME_IRQ0(irq)			((irq) << 27)
+#define     GRA_FRAME_IRQ0_MASK			0x08000000
+#define     GRA_FRAME_IRQ1(irq)			((irq) << 26)
+#define     GRA_FRAME_IRQ1_MASK			0x04000000
+#define     GRA_FF_UNDERFLOW(ff)		((ff) << 25)
+#define     GRA_FF_UNDERFLOW_MASK		0x02000000
+#define     VSYNC_IRQ(vsync_irq)		((vsync_irq) << 23)
+#define     VSYNC_IRQ_MASK			0x00800000
+#define     DUMB_FRAMEDONE(fdone)		((fdone) << 22)
+#define     DUMB_FRAMEDONE_MASK			0x00400000
+#define     TWC_FRAMEDONE(fdone)		((fdone) << 21)
+#define     TWC_FRAMEDONE_MASK			0x00200000
+#define     HWC_FRAMEDONE(fdone)		((fdone) << 20)
+#define     HWC_FRAMEDONE_MASK			0x00100000
+#define     SLV_IRQ(irq)			((irq) << 19)
+#define     SLV_IRQ_MASK			0x00080000
+#define     SPI_IRQ(irq)			((irq) << 18)
+#define     SPI_IRQ_MASK			0x00040000
+#define     PWRDN_IRQ(irq)			((irq) << 17)
+#define     PWRDN_IRQ_MASK			0x00020000
+#define     ERR_IRQ(irq)			((irq) << 16)
+#define     ERR_IRQ_MASK			0x00010000
+/* read-only */
+#define     DMA_FRAME_IRQ0_LEVEL_MASK		0x00008000
+#define     DMA_FRAME_IRQ1_LEVEL_MASK		0x00004000
+#define     DMA_FRAME_CNT_ISR_MASK		0x00003000
+#define     GRA_FRAME_IRQ0_LEVEL_MASK		0x00000800
+#define     GRA_FRAME_IRQ1_LEVEL_MASK		0x00000400
+#define     GRA_FRAME_CNT_ISR_MASK		0x00000300
+#define     VSYNC_IRQ_LEVEL_MASK		0x00000080
+#define     DUMB_FRAMEDONE_LEVEL_MASK		0x00000040
+#define     TWC_FRAMEDONE_LEVEL_MASK		0x00000020
+#define     HWC_FRAMEDONE_LEVEL_MASK		0x00000010
+#define     SLV_FF_EMPTY_MASK			0x00000008
+#define     DMA_FF_ALLEMPTY_MASK		0x00000004
+#define     GRA_FF_ALLEMPTY_MASK		0x00000002
+#define     PWRDN_IRQ_LEVEL_MASK		0x00000001
+
+
+/*
+ * defined Video Memory Color format for DMA control 0 register
+ * DMA0 bit[23:20]
+ */
+#define VMODE_RGB565		0x0
+#define VMODE_RGB1555		0x1
+#define VMODE_RGB888PACKED	0x2
+#define VMODE_RGB888UNPACKED	0x3
+#define VMODE_RGBA888		0x4
+#define VMODE_YUV422PACKED	0x5
+#define VMODE_YUV422PLANAR	0x6
+#define VMODE_YUV420PLANAR	0x7
+#define VMODE_SMPNCMD		0x8
+#define VMODE_PALETTE4BIT	0x9
+#define VMODE_PALETTE8BIT	0xa
+#define VMODE_RESERVED		0xb
+
+/*
+ * defined Graphic Memory Color format for DMA control 0 register
+ * DMA0 bit[19:16]
+ */
+#define GMODE_RGB565		0x0
+#define GMODE_RGB1555		0x1
+#define GMODE_RGB888PACKED	0x2
+#define GMODE_RGB888UNPACKED	0x3
+#define GMODE_RGBA888		0x4
+#define GMODE_YUV422PACKED	0x5
+#define GMODE_YUV422PLANAR	0x6
+#define GMODE_YUV420PLANAR	0x7
+#define GMODE_SMPNCMD		0x8
+#define GMODE_PALETTE4BIT	0x9
+#define GMODE_PALETTE8BIT	0xa
+#define GMODE_RESERVED		0xb
+
+/*
+ * define for DMA control 1 register
+ */
+#define DMA1_FRAME_TRIG		31 /* bit location */
+#define DMA1_VSYNC_MODE		28
+#define DMA1_VSYNC_INV		27
+#define DMA1_CKEY		24
+#define DMA1_CARRY		23
+#define DMA1_LNBUF_ENA		22
+#define DMA1_GATED_ENA		21
+#define DMA1_PWRDN_ENA		20
+#define DMA1_DSCALE		18
+#define DMA1_ALPHA_MODE		16
+#define DMA1_ALPHA		08
+#define DMA1_PXLCMD		00
+
+/*
+ * defined for Configure Dumb Mode
+ * DUMB LCD Panel bit[31:28]
+ */
+#define DUMB16_RGB565_0		0x0
+#define DUMB16_RGB565_1		0x1
+#define DUMB18_RGB666_0		0x2
+#define DUMB18_RGB666_1		0x3
+#define DUMB12_RGB444_0		0x4
+#define DUMB12_RGB444_1		0x5
+#define DUMB24_RGB888_0		0x6
+#define DUMB_BLANK		0x7
+
+/*
+ * defined for Configure I/O Pin Allocation Mode
+ * LCD LCD I/O Pads control register bit[3:0]
+ */
+#define IOPAD_DUMB24		0x0
+#define IOPAD_DUMB18SPI		0x1
+#define IOPAD_DUMB18GPIO	0x2
+#define IOPAD_DUMB16SPI		0x3
+#define IOPAD_DUMB16GPIO	0x4
+#define IOPAD_DUMB12		0x5
+#define IOPAD_SMART18SPI	0x6
+#define IOPAD_SMART16SPI	0x7
+#define IOPAD_SMART8BOTH	0x8
+
+#endif /* __PXA168FB_H__ */
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index 421770b..ca5b464 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -45,7 +45,7 @@
 static int mtrr		__devinitdata = 3; /* enable mtrr by default */
 static int blank	= 1;		   /* enable blanking by default */
 static int ypan		= 1; 		 /* 0: scroll, 1: ypan, 2: ywrap */
-static int pmi_setpal	__devinitdata = 1; /* use PMI for palette changes */
+static bool pmi_setpal	__devinitdata = true; /* use PMI for palette changes */
 static int nocrtc	__devinitdata; /* ignore CRTC settings */
 static int noedid	__devinitdata; /* don't try DDC transfers */
 static int vram_remap	__devinitdata; /* set amt. of memory to be used */
@@ -2002,11 +2002,7 @@
 
 module_exit(uvesafb_exit);
 
-static int param_get_scroll(char *buffer, struct kernel_param *kp)
-{
-	return 0;
-}
-
+#define param_get_scroll NULL
 static int param_set_scroll(const char *val, struct kernel_param *kp)
 {
 	ypan = 0;
@@ -2017,6 +2013,8 @@
 		ypan = 1;
 	else if (!strcmp(val, "ywrap"))
 		ypan = 2;
+	else
+		return -EINVAL;
 
 	return 0;
 }
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index 018c070..3a43ebf 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -31,21 +31,37 @@
 	return sprintf(buf, "virtio:d%08Xv%08X\n",
 		       dev->id.device, dev->id.vendor);
 }
+static ssize_t features_show(struct device *_d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct virtio_device *dev = container_of(_d, struct virtio_device, dev);
+	unsigned int i;
+	ssize_t len = 0;
+
+	/* We actually represent this as a bitstring, as it could be
+	 * arbitrary length in future. */
+	for (i = 0; i < ARRAY_SIZE(dev->features)*BITS_PER_LONG; i++)
+		len += sprintf(buf+len, "%c",
+			       test_bit(i, dev->features) ? '1' : '0');
+	len += sprintf(buf+len, "\n");
+	return len;
+}
 static struct device_attribute virtio_dev_attrs[] = {
 	__ATTR_RO(device),
 	__ATTR_RO(vendor),
 	__ATTR_RO(status),
 	__ATTR_RO(modalias),
+	__ATTR_RO(features),
 	__ATTR_NULL
 };
 
 static inline int virtio_id_match(const struct virtio_device *dev,
 				  const struct virtio_device_id *id)
 {
-	if (id->device != dev->id.device)
+	if (id->device != dev->id.device && id->device != VIRTIO_DEV_ANY_ID)
 		return 0;
 
-	return id->vendor == VIRTIO_DEV_ANY_ID || id->vendor != dev->id.vendor;
+	return id->vendor == VIRTIO_DEV_ANY_ID || id->vendor == dev->id.vendor;
 }
 
 /* This looks through all the IDs a driver claims to support.  If any of them
@@ -118,13 +134,14 @@
 		if (device_features & (1 << i))
 			set_bit(i, dev->features);
 
+	dev->config->finalize_features(dev);
+
 	err = drv->probe(dev);
 	if (err)
 		add_status(dev, VIRTIO_CONFIG_S_FAILED);
-	else {
-		dev->config->finalize_features(dev);
+	else
 		add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
-	}
+
 	return err;
 }
 
@@ -185,6 +202,8 @@
 	/* Acknowledge that we've seen the device. */
 	add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
 
+	INIT_LIST_HEAD(&dev->vqs);
+
 	/* device_register() causes the bus infrastructure to look for a
 	 * matching driver. */
 	err = device_register(&dev->dev);
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 9c76a06..26b2782 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -204,6 +204,9 @@
 static int virtballoon_probe(struct virtio_device *vdev)
 {
 	struct virtio_balloon *vb;
+	struct virtqueue *vqs[2];
+	vq_callback_t *callbacks[] = { balloon_ack, balloon_ack };
+	const char *names[] = { "inflate", "deflate" };
 	int err;
 
 	vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
@@ -218,22 +221,17 @@
 	vb->vdev = vdev;
 
 	/* We expect two virtqueues. */
-	vb->inflate_vq = vdev->config->find_vq(vdev, 0, balloon_ack);
-	if (IS_ERR(vb->inflate_vq)) {
-		err = PTR_ERR(vb->inflate_vq);
+	err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names);
+	if (err)
 		goto out_free_vb;
-	}
 
-	vb->deflate_vq = vdev->config->find_vq(vdev, 1, balloon_ack);
-	if (IS_ERR(vb->deflate_vq)) {
-		err = PTR_ERR(vb->deflate_vq);
-		goto out_del_inflate_vq;
-	}
+	vb->inflate_vq = vqs[0];
+	vb->deflate_vq = vqs[1];
 
 	vb->thread = kthread_run(balloon, vb, "vballoon");
 	if (IS_ERR(vb->thread)) {
 		err = PTR_ERR(vb->thread);
-		goto out_del_deflate_vq;
+		goto out_del_vqs;
 	}
 
 	vb->tell_host_first
@@ -241,10 +239,8 @@
 
 	return 0;
 
-out_del_deflate_vq:
-	vdev->config->del_vq(vb->deflate_vq);
-out_del_inflate_vq:
-	vdev->config->del_vq(vb->inflate_vq);
+out_del_vqs:
+	vdev->config->del_vqs(vdev);
 out_free_vb:
 	kfree(vb);
 out:
@@ -264,8 +260,7 @@
 	/* Now we reset the device so we can clean up the queues. */
 	vdev->config->reset(vdev);
 
-	vdev->config->del_vq(vb->deflate_vq);
-	vdev->config->del_vq(vb->inflate_vq);
+	vdev->config->del_vqs(vdev);
 	kfree(vb);
 }
 
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
index 330aacb..193c8f0 100644
--- a/drivers/virtio/virtio_pci.c
+++ b/drivers/virtio/virtio_pci.c
@@ -42,6 +42,26 @@
 	/* a list of queues so we can dispatch IRQs */
 	spinlock_t lock;
 	struct list_head virtqueues;
+
+	/* MSI-X support */
+	int msix_enabled;
+	int intx_enabled;
+	struct msix_entry *msix_entries;
+	/* Name strings for interrupts. This size should be enough,
+	 * and I'm too lazy to allocate each name separately. */
+	char (*msix_names)[256];
+	/* Number of available vectors */
+	unsigned msix_vectors;
+	/* Vectors allocated */
+	unsigned msix_used_vectors;
+};
+
+/* Constants for MSI-X */
+/* Use first vector for configuration changes, second and the rest for
+ * virtqueues Thus, we need at least 2 vectors for MSI. */
+enum {
+	VP_MSIX_CONFIG_VECTOR = 0,
+	VP_MSIX_VQ_VECTOR = 1,
 };
 
 struct virtio_pci_vq_info
@@ -60,6 +80,9 @@
 
 	/* the list node for the virtqueues list */
 	struct list_head node;
+
+	/* MSI-X vector (or none) */
+	unsigned vector;
 };
 
 /* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */
@@ -109,7 +132,8 @@
 		   void *buf, unsigned len)
 {
 	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-	void __iomem *ioaddr = vp_dev->ioaddr + VIRTIO_PCI_CONFIG + offset;
+	void __iomem *ioaddr = vp_dev->ioaddr +
+				VIRTIO_PCI_CONFIG(vp_dev) + offset;
 	u8 *ptr = buf;
 	int i;
 
@@ -123,7 +147,8 @@
 		   const void *buf, unsigned len)
 {
 	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-	void __iomem *ioaddr = vp_dev->ioaddr + VIRTIO_PCI_CONFIG + offset;
+	void __iomem *ioaddr = vp_dev->ioaddr +
+				VIRTIO_PCI_CONFIG(vp_dev) + offset;
 	const u8 *ptr = buf;
 	int i;
 
@@ -164,37 +189,26 @@
 	iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
 }
 
-/* A small wrapper to also acknowledge the interrupt when it's handled.
- * I really need an EIO hook for the vring so I can ack the interrupt once we
- * know that we'll be handling the IRQ but before we invoke the callback since
- * the callback may notify the host which results in the host attempting to
- * raise an interrupt that we would then mask once we acknowledged the
- * interrupt. */
-static irqreturn_t vp_interrupt(int irq, void *opaque)
+/* Handle a configuration change: Tell driver if it wants to know. */
+static irqreturn_t vp_config_changed(int irq, void *opaque)
+{
+	struct virtio_pci_device *vp_dev = opaque;
+	struct virtio_driver *drv;
+	drv = container_of(vp_dev->vdev.dev.driver,
+			   struct virtio_driver, driver);
+
+	if (drv && drv->config_changed)
+		drv->config_changed(&vp_dev->vdev);
+	return IRQ_HANDLED;
+}
+
+/* Notify all virtqueues on an interrupt. */
+static irqreturn_t vp_vring_interrupt(int irq, void *opaque)
 {
 	struct virtio_pci_device *vp_dev = opaque;
 	struct virtio_pci_vq_info *info;
 	irqreturn_t ret = IRQ_NONE;
 	unsigned long flags;
-	u8 isr;
-
-	/* reading the ISR has the effect of also clearing it so it's very
-	 * important to save off the value. */
-	isr = ioread8(vp_dev->ioaddr + VIRTIO_PCI_ISR);
-
-	/* It's definitely not us if the ISR was not high */
-	if (!isr)
-		return IRQ_NONE;
-
-	/* Configuration change?  Tell driver if it wants to know. */
-	if (isr & VIRTIO_PCI_ISR_CONFIG) {
-		struct virtio_driver *drv;
-		drv = container_of(vp_dev->vdev.dev.driver,
-				   struct virtio_driver, driver);
-
-		if (drv && drv->config_changed)
-			drv->config_changed(&vp_dev->vdev);
-	}
 
 	spin_lock_irqsave(&vp_dev->lock, flags);
 	list_for_each_entry(info, &vp_dev->virtqueues, node) {
@@ -206,15 +220,157 @@
 	return ret;
 }
 
-/* the config->find_vq() implementation */
+/* A small wrapper to also acknowledge the interrupt when it's handled.
+ * I really need an EIO hook for the vring so I can ack the interrupt once we
+ * know that we'll be handling the IRQ but before we invoke the callback since
+ * the callback may notify the host which results in the host attempting to
+ * raise an interrupt that we would then mask once we acknowledged the
+ * interrupt. */
+static irqreturn_t vp_interrupt(int irq, void *opaque)
+{
+	struct virtio_pci_device *vp_dev = opaque;
+	u8 isr;
+
+	/* reading the ISR has the effect of also clearing it so it's very
+	 * important to save off the value. */
+	isr = ioread8(vp_dev->ioaddr + VIRTIO_PCI_ISR);
+
+	/* It's definitely not us if the ISR was not high */
+	if (!isr)
+		return IRQ_NONE;
+
+	/* Configuration change?  Tell driver if it wants to know. */
+	if (isr & VIRTIO_PCI_ISR_CONFIG)
+		vp_config_changed(irq, opaque);
+
+	return vp_vring_interrupt(irq, opaque);
+}
+
+static void vp_free_vectors(struct virtio_device *vdev)
+{
+	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+	int i;
+
+	if (vp_dev->intx_enabled) {
+		free_irq(vp_dev->pci_dev->irq, vp_dev);
+		vp_dev->intx_enabled = 0;
+	}
+
+	for (i = 0; i < vp_dev->msix_used_vectors; ++i)
+		free_irq(vp_dev->msix_entries[i].vector, vp_dev);
+	vp_dev->msix_used_vectors = 0;
+
+	if (vp_dev->msix_enabled) {
+		/* Disable the vector used for configuration */
+		iowrite16(VIRTIO_MSI_NO_VECTOR,
+			  vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
+		/* Flush the write out to device */
+		ioread16(vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
+
+		vp_dev->msix_enabled = 0;
+		pci_disable_msix(vp_dev->pci_dev);
+	}
+}
+
+static int vp_enable_msix(struct pci_dev *dev, struct msix_entry *entries,
+			  int *options, int noptions)
+{
+	int i;
+	for (i = 0; i < noptions; ++i)
+		if (!pci_enable_msix(dev, entries, options[i]))
+			return options[i];
+	return -EBUSY;
+}
+
+static int vp_request_vectors(struct virtio_device *vdev, unsigned max_vqs)
+{
+	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+	const char *name = dev_name(&vp_dev->vdev.dev);
+	unsigned i, v;
+	int err = -ENOMEM;
+	/* We want at most one vector per queue and one for config changes.
+	 * Fallback to separate vectors for config and a shared for queues.
+	 * Finally fall back to regular interrupts. */
+	int options[] = { max_vqs + 1, 2 };
+	int nvectors = max(options[0], options[1]);
+
+	vp_dev->msix_entries = kmalloc(nvectors * sizeof *vp_dev->msix_entries,
+				       GFP_KERNEL);
+	if (!vp_dev->msix_entries)
+		goto error_entries;
+	vp_dev->msix_names = kmalloc(nvectors * sizeof *vp_dev->msix_names,
+				     GFP_KERNEL);
+	if (!vp_dev->msix_names)
+		goto error_names;
+
+	for (i = 0; i < nvectors; ++i)
+		vp_dev->msix_entries[i].entry = i;
+
+	err = vp_enable_msix(vp_dev->pci_dev, vp_dev->msix_entries,
+			     options, ARRAY_SIZE(options));
+	if (err < 0) {
+		/* Can't allocate enough MSI-X vectors, use regular interrupt */
+		vp_dev->msix_vectors = 0;
+		err = request_irq(vp_dev->pci_dev->irq, vp_interrupt,
+				  IRQF_SHARED, name, vp_dev);
+		if (err)
+			goto error_irq;
+		vp_dev->intx_enabled = 1;
+	} else {
+		vp_dev->msix_vectors = err;
+		vp_dev->msix_enabled = 1;
+
+		/* Set the vector used for configuration */
+		v = vp_dev->msix_used_vectors;
+		snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
+			 "%s-config", name);
+		err = request_irq(vp_dev->msix_entries[v].vector,
+				  vp_config_changed, 0, vp_dev->msix_names[v],
+				  vp_dev);
+		if (err)
+			goto error_irq;
+		++vp_dev->msix_used_vectors;
+
+		iowrite16(v, vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
+		/* Verify we had enough resources to assign the vector */
+		v = ioread16(vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
+		if (v == VIRTIO_MSI_NO_VECTOR) {
+			err = -EBUSY;
+			goto error_irq;
+		}
+	}
+
+	if (vp_dev->msix_vectors && vp_dev->msix_vectors != max_vqs + 1) {
+		/* Shared vector for all VQs */
+		v = vp_dev->msix_used_vectors;
+		snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
+			 "%s-virtqueues", name);
+		err = request_irq(vp_dev->msix_entries[v].vector,
+				  vp_vring_interrupt, 0, vp_dev->msix_names[v],
+				  vp_dev);
+		if (err)
+			goto error_irq;
+		++vp_dev->msix_used_vectors;
+	}
+	return 0;
+error_irq:
+	vp_free_vectors(vdev);
+	kfree(vp_dev->msix_names);
+error_names:
+	kfree(vp_dev->msix_entries);
+error_entries:
+	return err;
+}
+
 static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
-				    void (*callback)(struct virtqueue *vq))
+				    void (*callback)(struct virtqueue *vq),
+				    const char *name)
 {
 	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
 	struct virtio_pci_vq_info *info;
 	struct virtqueue *vq;
 	unsigned long flags, size;
-	u16 num;
+	u16 num, vector;
 	int err;
 
 	/* Select the queue we're interested in */
@@ -233,6 +389,7 @@
 
 	info->queue_index = index;
 	info->num = num;
+	info->vector = VIRTIO_MSI_NO_VECTOR;
 
 	size = PAGE_ALIGN(vring_size(num, VIRTIO_PCI_VRING_ALIGN));
 	info->queue = alloc_pages_exact(size, GFP_KERNEL|__GFP_ZERO);
@@ -247,7 +404,7 @@
 
 	/* create the vring */
 	vq = vring_new_virtqueue(info->num, VIRTIO_PCI_VRING_ALIGN,
-				 vdev, info->queue, vp_notify, callback);
+				 vdev, info->queue, vp_notify, callback, name);
 	if (!vq) {
 		err = -ENOMEM;
 		goto out_activate_queue;
@@ -256,12 +413,43 @@
 	vq->priv = info;
 	info->vq = vq;
 
+	/* allocate per-vq vector if available and necessary */
+	if (callback && vp_dev->msix_used_vectors < vp_dev->msix_vectors) {
+		vector = vp_dev->msix_used_vectors;
+		snprintf(vp_dev->msix_names[vector], sizeof *vp_dev->msix_names,
+			 "%s-%s", dev_name(&vp_dev->vdev.dev), name);
+		err = request_irq(vp_dev->msix_entries[vector].vector,
+				  vring_interrupt, 0,
+				  vp_dev->msix_names[vector], vq);
+		if (err)
+			goto out_request_irq;
+		info->vector = vector;
+		++vp_dev->msix_used_vectors;
+	} else
+		vector = VP_MSIX_VQ_VECTOR;
+
+	 if (callback && vp_dev->msix_enabled) {
+		iowrite16(vector, vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
+		vector = ioread16(vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
+		if (vector == VIRTIO_MSI_NO_VECTOR) {
+			err = -EBUSY;
+			goto out_assign;
+		}
+	}
+
 	spin_lock_irqsave(&vp_dev->lock, flags);
 	list_add(&info->node, &vp_dev->virtqueues);
 	spin_unlock_irqrestore(&vp_dev->lock, flags);
 
 	return vq;
 
+out_assign:
+	if (info->vector != VIRTIO_MSI_NO_VECTOR) {
+		free_irq(vp_dev->msix_entries[info->vector].vector, vq);
+		--vp_dev->msix_used_vectors;
+	}
+out_request_irq:
+	vring_del_virtqueue(vq);
 out_activate_queue:
 	iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
 	free_pages_exact(info->queue, size);
@@ -270,21 +458,27 @@
 	return ERR_PTR(err);
 }
 
-/* the config->del_vq() implementation */
 static void vp_del_vq(struct virtqueue *vq)
 {
 	struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
 	struct virtio_pci_vq_info *info = vq->priv;
-	unsigned long flags, size;
+	unsigned long size;
 
-	spin_lock_irqsave(&vp_dev->lock, flags);
-	list_del(&info->node);
-	spin_unlock_irqrestore(&vp_dev->lock, flags);
+	iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+	if (info->vector != VIRTIO_MSI_NO_VECTOR)
+		free_irq(vp_dev->msix_entries[info->vector].vector, vq);
+
+	if (vp_dev->msix_enabled) {
+		iowrite16(VIRTIO_MSI_NO_VECTOR,
+			  vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
+		/* Flush the write out to device */
+		ioread8(vp_dev->ioaddr + VIRTIO_PCI_ISR);
+	}
 
 	vring_del_virtqueue(vq);
 
 	/* Select and deactivate the queue */
-	iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
 	iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
 
 	size = PAGE_ALIGN(vring_size(info->num, VIRTIO_PCI_VRING_ALIGN));
@@ -292,14 +486,57 @@
 	kfree(info);
 }
 
+/* the config->del_vqs() implementation */
+static void vp_del_vqs(struct virtio_device *vdev)
+{
+	struct virtqueue *vq, *n;
+
+	list_for_each_entry_safe(vq, n, &vdev->vqs, list)
+		vp_del_vq(vq);
+
+	vp_free_vectors(vdev);
+}
+
+/* the config->find_vqs() implementation */
+static int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+		       struct virtqueue *vqs[],
+		       vq_callback_t *callbacks[],
+		       const char *names[])
+{
+	int vectors = 0;
+	int i, err;
+
+	/* How many vectors would we like? */
+	for (i = 0; i < nvqs; ++i)
+		if (callbacks[i])
+			++vectors;
+
+	err = vp_request_vectors(vdev, vectors);
+	if (err)
+		goto error_request;
+
+	for (i = 0; i < nvqs; ++i) {
+		vqs[i] = vp_find_vq(vdev, i, callbacks[i], names[i]);
+		if (IS_ERR(vqs[i]))
+			goto error_find;
+	}
+	return 0;
+
+error_find:
+	vp_del_vqs(vdev);
+
+error_request:
+	return PTR_ERR(vqs[i]);
+}
+
 static struct virtio_config_ops virtio_pci_config_ops = {
 	.get		= vp_get,
 	.set		= vp_set,
 	.get_status	= vp_get_status,
 	.set_status	= vp_set_status,
 	.reset		= vp_reset,
-	.find_vq	= vp_find_vq,
-	.del_vq		= vp_del_vq,
+	.find_vqs	= vp_find_vqs,
+	.del_vqs	= vp_del_vqs,
 	.get_features	= vp_get_features,
 	.finalize_features = vp_finalize_features,
 };
@@ -310,7 +547,7 @@
 	struct virtio_pci_device *vp_dev = to_vp_device(dev);
 	struct pci_dev *pci_dev = vp_dev->pci_dev;
 
-	free_irq(pci_dev->irq, vp_dev);
+	vp_del_vqs(dev);
 	pci_set_drvdata(pci_dev, NULL);
 	pci_iounmap(pci_dev, vp_dev->ioaddr);
 	pci_release_regions(pci_dev);
@@ -369,21 +606,13 @@
 	vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor;
 	vp_dev->vdev.id.device = pci_dev->subsystem_device;
 
-	/* register a handler for the queue with the PCI device's interrupt */
-	err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, IRQF_SHARED,
-			  dev_name(&vp_dev->vdev.dev), vp_dev);
-	if (err)
-		goto out_set_drvdata;
-
 	/* finally register the virtio device */
 	err = register_virtio_device(&vp_dev->vdev);
 	if (err)
-		goto out_req_irq;
+		goto out_set_drvdata;
 
 	return 0;
 
-out_req_irq:
-	free_irq(pci_dev->irq, vp_dev);
 out_set_drvdata:
 	pci_set_drvdata(pci_dev, NULL);
 	pci_iounmap(pci_dev, vp_dev->ioaddr);
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 5c52369..a882f26 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -23,21 +23,30 @@
 
 #ifdef DEBUG
 /* For development, we want to crash whenever the ring is screwed. */
-#define BAD_RING(_vq, fmt...)			\
-	do { dev_err(&(_vq)->vq.vdev->dev, fmt); BUG(); } while(0)
+#define BAD_RING(_vq, fmt, args...)				\
+	do {							\
+		dev_err(&(_vq)->vq.vdev->dev,			\
+			"%s:"fmt, (_vq)->vq.name, ##args);	\
+		BUG();						\
+	} while (0)
 /* Caller is supposed to guarantee no reentry. */
 #define START_USE(_vq)						\
 	do {							\
 		if ((_vq)->in_use)				\
-			panic("in_use = %i\n", (_vq)->in_use);	\
+			panic("%s:in_use = %i\n",		\
+			      (_vq)->vq.name, (_vq)->in_use);	\
 		(_vq)->in_use = __LINE__;			\
 		mb();						\
-	} while(0)
+	} while (0)
 #define END_USE(_vq) \
 	do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; mb(); } while(0)
 #else
-#define BAD_RING(_vq, fmt...)			\
-	do { dev_err(&_vq->vq.vdev->dev, fmt); (_vq)->broken = true; } while(0)
+#define BAD_RING(_vq, fmt, args...)				\
+	do {							\
+		dev_err(&_vq->vq.vdev->dev,			\
+			"%s:"fmt, (_vq)->vq.name, ##args);	\
+		(_vq)->broken = true;				\
+	} while (0)
 #define START_USE(vq)
 #define END_USE(vq)
 #endif
@@ -52,6 +61,9 @@
 	/* Other side has made a mess, don't try any more. */
 	bool broken;
 
+	/* Host supports indirect buffers */
+	bool indirect;
+
 	/* Number of free buffers */
 	unsigned int num_free;
 	/* Head of free buffer list. */
@@ -76,6 +88,55 @@
 
 #define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq)
 
+/* Set up an indirect table of descriptors and add it to the queue. */
+static int vring_add_indirect(struct vring_virtqueue *vq,
+			      struct scatterlist sg[],
+			      unsigned int out,
+			      unsigned int in)
+{
+	struct vring_desc *desc;
+	unsigned head;
+	int i;
+
+	desc = kmalloc((out + in) * sizeof(struct vring_desc), GFP_ATOMIC);
+	if (!desc)
+		return vq->vring.num;
+
+	/* Transfer entries from the sg list into the indirect page */
+	for (i = 0; i < out; i++) {
+		desc[i].flags = VRING_DESC_F_NEXT;
+		desc[i].addr = sg_phys(sg);
+		desc[i].len = sg->length;
+		desc[i].next = i+1;
+		sg++;
+	}
+	for (; i < (out + in); i++) {
+		desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
+		desc[i].addr = sg_phys(sg);
+		desc[i].len = sg->length;
+		desc[i].next = i+1;
+		sg++;
+	}
+
+	/* Last one doesn't continue. */
+	desc[i-1].flags &= ~VRING_DESC_F_NEXT;
+	desc[i-1].next = 0;
+
+	/* We're about to use a buffer */
+	vq->num_free--;
+
+	/* Use a single buffer which doesn't continue */
+	head = vq->free_head;
+	vq->vring.desc[head].flags = VRING_DESC_F_INDIRECT;
+	vq->vring.desc[head].addr = virt_to_phys(desc);
+	vq->vring.desc[head].len = i * sizeof(struct vring_desc);
+
+	/* Update free pointer */
+	vq->free_head = vq->vring.desc[head].next;
+
+	return head;
+}
+
 static int vring_add_buf(struct virtqueue *_vq,
 			 struct scatterlist sg[],
 			 unsigned int out,
@@ -85,12 +146,21 @@
 	struct vring_virtqueue *vq = to_vvq(_vq);
 	unsigned int i, avail, head, uninitialized_var(prev);
 
+	START_USE(vq);
+
 	BUG_ON(data == NULL);
+
+	/* If the host supports indirect descriptor tables, and we have multiple
+	 * buffers, then go indirect. FIXME: tune this threshold */
+	if (vq->indirect && (out + in) > 1 && vq->num_free) {
+		head = vring_add_indirect(vq, sg, out, in);
+		if (head != vq->vring.num)
+			goto add_head;
+	}
+
 	BUG_ON(out + in > vq->vring.num);
 	BUG_ON(out + in == 0);
 
-	START_USE(vq);
-
 	if (vq->num_free < out + in) {
 		pr_debug("Can't add buf len %i - avail = %i\n",
 			 out + in, vq->num_free);
@@ -127,6 +197,7 @@
 	/* Update free pointer */
 	vq->free_head = i;
 
+add_head:
 	/* Set token. */
 	vq->data[head] = data;
 
@@ -170,6 +241,11 @@
 
 	/* Put back on free list: find end */
 	i = head;
+
+	/* Free the indirect table */
+	if (vq->vring.desc[i].flags & VRING_DESC_F_INDIRECT)
+		kfree(phys_to_virt(vq->vring.desc[i].addr));
+
 	while (vq->vring.desc[i].flags & VRING_DESC_F_NEXT) {
 		i = vq->vring.desc[i].next;
 		vq->num_free++;
@@ -284,7 +360,8 @@
 				      struct virtio_device *vdev,
 				      void *pages,
 				      void (*notify)(struct virtqueue *),
-				      void (*callback)(struct virtqueue *))
+				      void (*callback)(struct virtqueue *),
+				      const char *name)
 {
 	struct vring_virtqueue *vq;
 	unsigned int i;
@@ -303,14 +380,18 @@
 	vq->vq.callback = callback;
 	vq->vq.vdev = vdev;
 	vq->vq.vq_ops = &vring_vq_ops;
+	vq->vq.name = name;
 	vq->notify = notify;
 	vq->broken = false;
 	vq->last_used_idx = 0;
 	vq->num_added = 0;
+	list_add_tail(&vq->vq.list, &vdev->vqs);
 #ifdef DEBUG
 	vq->in_use = false;
 #endif
 
+	vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC);
+
 	/* No callback?  Tell other side not to bother us. */
 	if (!callback)
 		vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
@@ -327,6 +408,7 @@
 
 void vring_del_virtqueue(struct virtqueue *vq)
 {
+	list_del(&vq->list);
 	kfree(to_vvq(vq));
 }
 EXPORT_SYMBOL_GPL(vring_del_virtqueue);
@@ -338,6 +420,8 @@
 
 	for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++) {
 		switch (i) {
+		case VIRTIO_RING_F_INDIRECT_DESC:
+			break;
 		default:
 			/* We don't understand this bit. */
 			clear_bit(i, vdev->features);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 452082f..b166f28 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -231,14 +231,14 @@
 	  NOTE: once enabled, this timer cannot be disabled.
 	  Say N if you are unsure.
 
-config ORION5X_WATCHDOG
-	tristate "Orion5x watchdog"
-	depends on ARCH_ORION5X
+config ORION_WATCHDOG
+	tristate "Orion watchdog"
+	depends on ARCH_ORION5X || ARCH_KIRKWOOD
 	help
 	  Say Y here if to include support for the watchdog timer
-	  in the Orion5x ARM SoCs.
+	  in the Marvell Orion5x and Kirkwood ARM SoCs.
 	  To compile this driver as a module, choose M here: the
-	  module will be called orion5x_wdt.
+	  module will be called orion_wdt.
 
 # AVR32 Architecture
 
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 7f8c56b..c3afa14 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -40,7 +40,7 @@
 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
 obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
 obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
-obj-$(CONFIG_ORION5X_WATCHDOG) += orion5x_wdt.o
+obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
diff --git a/drivers/watchdog/orion5x_wdt.c b/drivers/watchdog/orion5x_wdt.c
deleted file mode 100644
index 2cde568..0000000
--- a/drivers/watchdog/orion5x_wdt.c
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * drivers/watchdog/orion5x_wdt.c
- *
- * Watchdog driver for Orion5x processors
- *
- * Author: Sylver Bruneau <sylver.bruneau@googlemail.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/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/init.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <linux/spinlock.h>
-#include <mach/bridge-regs.h>
-#include <plat/orion5x_wdt.h>
-
-/*
- * Watchdog timer block registers.
- */
-#define TIMER_CTRL		(TIMER_VIRT_BASE + 0x0000)
-#define  WDT_EN			0x0010
-#define WDT_VAL			(TIMER_VIRT_BASE + 0x0024)
-
-#define WDT_MAX_CYCLE_COUNT	0xffffffff
-#define WDT_IN_USE		0
-#define WDT_OK_TO_CLOSE		1
-
-static int nowayout = WATCHDOG_NOWAYOUT;
-static int heartbeat = -1;		/* module parameter (seconds) */
-static unsigned int wdt_max_duration;	/* (seconds) */
-static unsigned int wdt_tclk;
-static unsigned long wdt_status;
-static spinlock_t wdt_lock;
-
-static void orion5x_wdt_ping(void)
-{
-	spin_lock(&wdt_lock);
-
-	/* Reload watchdog duration */
-	writel(wdt_tclk * heartbeat, WDT_VAL);
-
-	spin_unlock(&wdt_lock);
-}
-
-static void orion5x_wdt_enable(void)
-{
-	u32 reg;
-
-	spin_lock(&wdt_lock);
-
-	/* Set watchdog duration */
-	writel(wdt_tclk * heartbeat, WDT_VAL);
-
-	/* Clear watchdog timer interrupt */
-	reg = readl(BRIDGE_CAUSE);
-	reg &= ~WDT_INT_REQ;
-	writel(reg, BRIDGE_CAUSE);
-
-	/* Enable watchdog timer */
-	reg = readl(TIMER_CTRL);
-	reg |= WDT_EN;
-	writel(reg, TIMER_CTRL);
-
-	/* Enable reset on watchdog */
-	reg = readl(CPU_RESET_MASK);
-	reg |= WDT_RESET;
-	writel(reg, CPU_RESET_MASK);
-
-	spin_unlock(&wdt_lock);
-}
-
-static void orion5x_wdt_disable(void)
-{
-	u32 reg;
-
-	spin_lock(&wdt_lock);
-
-	/* Disable reset on watchdog */
-	reg = readl(CPU_RESET_MASK);
-	reg &= ~WDT_RESET;
-	writel(reg, CPU_RESET_MASK);
-
-	/* Disable watchdog timer */
-	reg = readl(TIMER_CTRL);
-	reg &= ~WDT_EN;
-	writel(reg, TIMER_CTRL);
-
-	spin_unlock(&wdt_lock);
-}
-
-static int orion5x_wdt_get_timeleft(int *time_left)
-{
-	spin_lock(&wdt_lock);
-	*time_left = readl(WDT_VAL) / wdt_tclk;
-	spin_unlock(&wdt_lock);
-	return 0;
-}
-
-static int orion5x_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);
-	orion5x_wdt_enable();
-	return nonseekable_open(inode, file);
-}
-
-static ssize_t orion5x_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);
-			}
-		}
-		orion5x_wdt_ping();
-	}
-	return len;
-}
-
-static int orion5x_wdt_settimeout(int new_time)
-{
-	if ((new_time <= 0) || (new_time > wdt_max_duration))
-		return -EINVAL;
-
-	/* Set new watchdog time to be used when
-	 * orion5x_wdt_enable() or orion5x_wdt_ping() is called. */
-	heartbeat = new_time;
-	return 0;
-}
-
-static const struct watchdog_info ident = {
-	.options	= WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
-			  WDIOF_KEEPALIVEPING,
-	.identity	= "Orion5x Watchdog",
-};
-
-static long orion5x_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:
-	case WDIOC_GETBOOTSTATUS:
-		ret = put_user(0, (int *)arg);
-		break;
-
-	case WDIOC_KEEPALIVE:
-		orion5x_wdt_ping();
-		ret = 0;
-		break;
-
-	case WDIOC_SETTIMEOUT:
-		ret = get_user(time, (int *)arg);
-		if (ret)
-			break;
-
-		if (orion5x_wdt_settimeout(time)) {
-			ret = -EINVAL;
-			break;
-		}
-		orion5x_wdt_ping();
-		/* Fall through */
-
-	case WDIOC_GETTIMEOUT:
-		ret = put_user(heartbeat, (int *)arg);
-		break;
-
-	case WDIOC_GETTIMELEFT:
-		if (orion5x_wdt_get_timeleft(&time)) {
-			ret = -EINVAL;
-			break;
-		}
-		ret = put_user(time, (int *)arg);
-		break;
-	}
-	return ret;
-}
-
-static int orion5x_wdt_release(struct inode *inode, struct file *file)
-{
-	if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
-		orion5x_wdt_disable();
-	else
-		printk(KERN_CRIT "WATCHDOG: 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 orion5x_wdt_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.write		= orion5x_wdt_write,
-	.unlocked_ioctl	= orion5x_wdt_ioctl,
-	.open		= orion5x_wdt_open,
-	.release	= orion5x_wdt_release,
-};
-
-static struct miscdevice orion5x_wdt_miscdev = {
-	.minor		= WATCHDOG_MINOR,
-	.name		= "watchdog",
-	.fops		= &orion5x_wdt_fops,
-};
-
-static int __devinit orion5x_wdt_probe(struct platform_device *pdev)
-{
-	struct orion5x_wdt_platform_data *pdata = pdev->dev.platform_data;
-	int ret;
-
-	if (pdata) {
-		wdt_tclk = pdata->tclk;
-	} else {
-		printk(KERN_ERR "Orion5x Watchdog misses platform data\n");
-		return -ENODEV;
-	}
-
-	if (orion5x_wdt_miscdev.parent)
-		return -EBUSY;
-	orion5x_wdt_miscdev.parent = &pdev->dev;
-
-	wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
-	if (orion5x_wdt_settimeout(heartbeat))
-		heartbeat = wdt_max_duration;
-
-	ret = misc_register(&orion5x_wdt_miscdev);
-	if (ret)
-		return ret;
-
-	printk(KERN_INFO "Orion5x Watchdog Timer: Initial timeout %d sec%s\n",
-				heartbeat, nowayout ? ", nowayout" : "");
-	return 0;
-}
-
-static int __devexit orion5x_wdt_remove(struct platform_device *pdev)
-{
-	int ret;
-
-	if (test_bit(WDT_IN_USE, &wdt_status)) {
-		orion5x_wdt_disable();
-		clear_bit(WDT_IN_USE, &wdt_status);
-	}
-
-	ret = misc_deregister(&orion5x_wdt_miscdev);
-	if (!ret)
-		orion5x_wdt_miscdev.parent = NULL;
-
-	return ret;
-}
-
-static void orion5x_wdt_shutdown(struct platform_device *pdev)
-{
-	if (test_bit(WDT_IN_USE, &wdt_status))
-		orion5x_wdt_disable();
-}
-
-static struct platform_driver orion5x_wdt_driver = {
-	.probe		= orion5x_wdt_probe,
-	.remove		= __devexit_p(orion5x_wdt_remove),
-	.shutdown	= orion5x_wdt_shutdown,
-	.driver		= {
-		.owner	= THIS_MODULE,
-		.name	= "orion5x_wdt",
-	},
-};
-
-static int __init orion5x_wdt_init(void)
-{
-	spin_lock_init(&wdt_lock);
-	return platform_driver_register(&orion5x_wdt_driver);
-}
-
-static void __exit orion5x_wdt_exit(void)
-{
-	platform_driver_unregister(&orion5x_wdt_driver);
-}
-
-module_init(orion5x_wdt_init);
-module_exit(orion5x_wdt_exit);
-
-MODULE_AUTHOR("Sylver Bruneau <sylver.bruneau@googlemail.com>");
-MODULE_DESCRIPTION("Orion5x Processor Watchdog");
-
-module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds");
-
-module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
-				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
new file mode 100644
index 0000000..2d9fb96
--- /dev/null
+++ b/drivers/watchdog/orion_wdt.c
@@ -0,0 +1,322 @@
+/*
+ * drivers/watchdog/orion_wdt.c
+ *
+ * Watchdog driver for Orion/Kirkwood processors
+ *
+ * Author: Sylver Bruneau <sylver.bruneau@googlemail.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/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/init.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <mach/bridge-regs.h>
+#include <plat/orion_wdt.h>
+
+/*
+ * Watchdog timer block registers.
+ */
+#define TIMER_CTRL		(TIMER_VIRT_BASE + 0x0000)
+#define  WDT_EN			0x0010
+#define WDT_VAL			(TIMER_VIRT_BASE + 0x0024)
+
+#define WDT_MAX_CYCLE_COUNT	0xffffffff
+#define WDT_IN_USE		0
+#define WDT_OK_TO_CLOSE		1
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static int heartbeat = -1;		/* module parameter (seconds) */
+static unsigned int wdt_max_duration;	/* (seconds) */
+static unsigned int wdt_tclk;
+static unsigned long wdt_status;
+static spinlock_t wdt_lock;
+
+static void orion_wdt_ping(void)
+{
+	spin_lock(&wdt_lock);
+
+	/* Reload watchdog duration */
+	writel(wdt_tclk * heartbeat, WDT_VAL);
+
+	spin_unlock(&wdt_lock);
+}
+
+static void orion_wdt_enable(void)
+{
+	u32 reg;
+
+	spin_lock(&wdt_lock);
+
+	/* Set watchdog duration */
+	writel(wdt_tclk * heartbeat, WDT_VAL);
+
+	/* Clear watchdog timer interrupt */
+	reg = readl(BRIDGE_CAUSE);
+	reg &= ~WDT_INT_REQ;
+	writel(reg, BRIDGE_CAUSE);
+
+	/* Enable watchdog timer */
+	reg = readl(TIMER_CTRL);
+	reg |= WDT_EN;
+	writel(reg, TIMER_CTRL);
+
+	/* Enable reset on watchdog */
+	reg = readl(RSTOUTn_MASK);
+	reg |= WDT_RESET_OUT_EN;
+	writel(reg, RSTOUTn_MASK);
+
+	spin_unlock(&wdt_lock);
+}
+
+static void orion_wdt_disable(void)
+{
+	u32 reg;
+
+	spin_lock(&wdt_lock);
+
+	/* Disable reset on watchdog */
+	reg = readl(RSTOUTn_MASK);
+	reg &= ~WDT_RESET_OUT_EN;
+	writel(reg, RSTOUTn_MASK);
+
+	/* Disable watchdog timer */
+	reg = readl(TIMER_CTRL);
+	reg &= ~WDT_EN;
+	writel(reg, TIMER_CTRL);
+
+	spin_unlock(&wdt_lock);
+}
+
+static int orion_wdt_get_timeleft(int *time_left)
+{
+	spin_lock(&wdt_lock);
+	*time_left = readl(WDT_VAL) / wdt_tclk;
+	spin_unlock(&wdt_lock);
+	return 0;
+}
+
+static int orion_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);
+	orion_wdt_enable();
+	return nonseekable_open(inode, file);
+}
+
+static ssize_t orion_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);
+			}
+		}
+		orion_wdt_ping();
+	}
+	return len;
+}
+
+static int orion_wdt_settimeout(int new_time)
+{
+	if ((new_time <= 0) || (new_time > wdt_max_duration))
+		return -EINVAL;
+
+	/* Set new watchdog time to be used when
+	 * orion_wdt_enable() or orion_wdt_ping() is called. */
+	heartbeat = new_time;
+	return 0;
+}
+
+static const struct watchdog_info ident = {
+	.options	= WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
+			  WDIOF_KEEPALIVEPING,
+	.identity	= "Orion Watchdog",
+};
+
+static long orion_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:
+	case WDIOC_GETBOOTSTATUS:
+		ret = put_user(0, (int *)arg);
+		break;
+
+	case WDIOC_KEEPALIVE:
+		orion_wdt_ping();
+		ret = 0;
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		ret = get_user(time, (int *)arg);
+		if (ret)
+			break;
+
+		if (orion_wdt_settimeout(time)) {
+			ret = -EINVAL;
+			break;
+		}
+		orion_wdt_ping();
+		/* Fall through */
+
+	case WDIOC_GETTIMEOUT:
+		ret = put_user(heartbeat, (int *)arg);
+		break;
+
+	case WDIOC_GETTIMELEFT:
+		if (orion_wdt_get_timeleft(&time)) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = put_user(time, (int *)arg);
+		break;
+	}
+	return ret;
+}
+
+static int orion_wdt_release(struct inode *inode, struct file *file)
+{
+	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");
+	clear_bit(WDT_IN_USE, &wdt_status);
+	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+	return 0;
+}
+
+
+static const struct file_operations orion_wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= orion_wdt_write,
+	.unlocked_ioctl	= orion_wdt_ioctl,
+	.open		= orion_wdt_open,
+	.release	= orion_wdt_release,
+};
+
+static struct miscdevice orion_wdt_miscdev = {
+	.minor		= WATCHDOG_MINOR,
+	.name		= "watchdog",
+	.fops		= &orion_wdt_fops,
+};
+
+static int __devinit orion_wdt_probe(struct platform_device *pdev)
+{
+	struct orion_wdt_platform_data *pdata = pdev->dev.platform_data;
+	int ret;
+
+	if (pdata) {
+		wdt_tclk = pdata->tclk;
+	} else {
+		printk(KERN_ERR "Orion Watchdog misses platform data\n");
+		return -ENODEV;
+	}
+
+	if (orion_wdt_miscdev.parent)
+		return -EBUSY;
+	orion_wdt_miscdev.parent = &pdev->dev;
+
+	wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
+	if (orion_wdt_settimeout(heartbeat))
+		heartbeat = wdt_max_duration;
+
+	ret = misc_register(&orion_wdt_miscdev);
+	if (ret)
+		return ret;
+
+	printk(KERN_INFO "Orion Watchdog Timer: Initial timeout %d sec%s\n",
+				heartbeat, nowayout ? ", nowayout" : "");
+	return 0;
+}
+
+static int __devexit orion_wdt_remove(struct platform_device *pdev)
+{
+	int ret;
+
+	if (test_bit(WDT_IN_USE, &wdt_status)) {
+		orion_wdt_disable();
+		clear_bit(WDT_IN_USE, &wdt_status);
+	}
+
+	ret = misc_deregister(&orion_wdt_miscdev);
+	if (!ret)
+		orion_wdt_miscdev.parent = NULL;
+
+	return ret;
+}
+
+static void orion_wdt_shutdown(struct platform_device *pdev)
+{
+	if (test_bit(WDT_IN_USE, &wdt_status))
+		orion_wdt_disable();
+}
+
+static struct platform_driver orion_wdt_driver = {
+	.probe		= orion_wdt_probe,
+	.remove		= __devexit_p(orion_wdt_remove),
+	.shutdown	= orion_wdt_shutdown,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "orion_wdt",
+	},
+};
+
+static int __init orion_wdt_init(void)
+{
+	spin_lock_init(&wdt_lock);
+	return platform_driver_register(&orion_wdt_driver);
+}
+
+static void __exit orion_wdt_exit(void)
+{
+	platform_driver_unregister(&orion_wdt_driver);
+}
+
+module_init(orion_wdt_init);
+module_exit(orion_wdt_exit);
+
+MODULE_AUTHOR("Sylver Bruneau <sylver.bruneau@googlemail.com>");
+MODULE_DESCRIPTION("Orion Processor Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c
index fddc202..10d03d7 100644
--- a/drivers/xen/manage.c
+++ b/drivers/xen/manage.c
@@ -43,7 +43,7 @@
 	if (err) {
 		printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
 			err);
-		device_power_up(PMSG_RESUME);
+		dpm_resume_noirq(PMSG_RESUME);
 		return err;
 	}
 
@@ -69,7 +69,7 @@
 	}
 
 	sysdev_resume();
-	device_power_up(PMSG_RESUME);
+	dpm_resume_noirq(PMSG_RESUME);
 
 	return 0;
 }
@@ -92,18 +92,18 @@
 	}
 #endif
 
-	err = device_suspend(PMSG_SUSPEND);
+	err = dpm_suspend_start(PMSG_SUSPEND);
 	if (err) {
-		printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
+		printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
 		goto out;
 	}
 
 	printk(KERN_DEBUG "suspending xenstore...\n");
 	xs_suspend();
 
-	err = device_power_down(PMSG_SUSPEND);
+	err = dpm_suspend_noirq(PMSG_SUSPEND);
 	if (err) {
-		printk(KERN_ERR "device_power_down failed: %d\n", err);
+		printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
 		goto resume_devices;
 	}
 
@@ -119,10 +119,10 @@
 	} else
 		xs_suspend_cancel();
 
-	device_power_up(PMSG_RESUME);
+	dpm_resume_noirq(PMSG_RESUME);
 
 resume_devices:
-	device_resume(PMSG_RESUME);
+	dpm_resume_end(PMSG_RESUME);
 
 	/* Make sure timer events get retriggered on all CPUs */
 	clock_was_set();
diff --git a/fs/Kconfig b/fs/Kconfig
index 9f7270f..525da2e 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -62,6 +62,16 @@
 source "fs/autofs4/Kconfig"
 source "fs/fuse/Kconfig"
 
+config CUSE
+	tristate "Character device in Userpace support"
+	depends on FUSE_FS
+	help
+	  This FUSE extension allows character devices to be
+	  implemented in userspace.
+
+	  If you want to develop or use userspace character device
+	  based on CUSE, answer Y or M.
+
 config GENERIC_ACL
 	bool
 	select FS_POSIX_ACL
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h
index 762d287..da6061a 100644
--- a/fs/configfs/configfs_internal.h
+++ b/fs/configfs/configfs_internal.h
@@ -39,6 +39,9 @@
 	umode_t			s_mode;
 	struct dentry		* s_dentry;
 	struct iattr		* s_iattr;
+#ifdef CONFIG_LOCKDEP
+	int			s_depth;
+#endif
 };
 
 #define CONFIGFS_ROOT		0x0001
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 05373db..8e48b52 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -78,11 +78,97 @@
 	.d_delete	= configfs_d_delete,
 };
 
+#ifdef CONFIG_LOCKDEP
+
+/*
+ * Helpers to make lockdep happy with our recursive locking of default groups'
+ * inodes (see configfs_attach_group() and configfs_detach_group()).
+ * We put default groups i_mutexes in separate classes according to their depth
+ * from the youngest non-default group ancestor.
+ *
+ * For a non-default group A having default groups A/B, A/C, and A/C/D, default
+ * groups A/B and A/C will have their inode's mutex in class
+ * default_group_class[0], and default group A/C/D will be in
+ * default_group_class[1].
+ *
+ * The lock classes are declared and assigned in inode.c, according to the
+ * s_depth value.
+ * The s_depth value is initialized to -1, adjusted to >= 0 when attaching
+ * default groups, and reset to -1 when all default groups are attached. During
+ * attachment, if configfs_create() sees s_depth > 0, the lock class of the new
+ * inode's mutex is set to default_group_class[s_depth - 1].
+ */
+
+static void configfs_init_dirent_depth(struct configfs_dirent *sd)
+{
+	sd->s_depth = -1;
+}
+
+static void configfs_set_dir_dirent_depth(struct configfs_dirent *parent_sd,
+					  struct configfs_dirent *sd)
+{
+	int parent_depth = parent_sd->s_depth;
+
+	if (parent_depth >= 0)
+		sd->s_depth = parent_depth + 1;
+}
+
+static void
+configfs_adjust_dir_dirent_depth_before_populate(struct configfs_dirent *sd)
+{
+	/*
+	 * item's i_mutex class is already setup, so s_depth is now only
+	 * used to set new sub-directories s_depth, which is always done
+	 * with item's i_mutex locked.
+	 */
+	/*
+	 *  sd->s_depth == -1 iff we are a non default group.
+	 *  else (we are a default group) sd->s_depth > 0 (see
+	 *  create_dir()).
+	 */
+	if (sd->s_depth == -1)
+		/*
+		 * We are a non default group and we are going to create
+		 * default groups.
+		 */
+		sd->s_depth = 0;
+}
+
+static void
+configfs_adjust_dir_dirent_depth_after_populate(struct configfs_dirent *sd)
+{
+	/* We will not create default groups anymore. */
+	sd->s_depth = -1;
+}
+
+#else /* CONFIG_LOCKDEP */
+
+static void configfs_init_dirent_depth(struct configfs_dirent *sd)
+{
+}
+
+static void configfs_set_dir_dirent_depth(struct configfs_dirent *parent_sd,
+					  struct configfs_dirent *sd)
+{
+}
+
+static void
+configfs_adjust_dir_dirent_depth_before_populate(struct configfs_dirent *sd)
+{
+}
+
+static void
+configfs_adjust_dir_dirent_depth_after_populate(struct configfs_dirent *sd)
+{
+}
+
+#endif /* CONFIG_LOCKDEP */
+
 /*
  * Allocates a new configfs_dirent and links it to the parent configfs_dirent
  */
-static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent * parent_sd,
-						void * element)
+static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent *parent_sd,
+						   void *element, int type)
 {
 	struct configfs_dirent * sd;
 
@@ -94,6 +180,8 @@
 	INIT_LIST_HEAD(&sd->s_links);
 	INIT_LIST_HEAD(&sd->s_children);
 	sd->s_element = element;
+	sd->s_type = type;
+	configfs_init_dirent_depth(sd);
 	spin_lock(&configfs_dirent_lock);
 	if (parent_sd->s_type & CONFIGFS_USET_DROPPING) {
 		spin_unlock(&configfs_dirent_lock);
@@ -138,12 +226,11 @@
 {
 	struct configfs_dirent * sd;
 
-	sd = configfs_new_dirent(parent_sd, element);
+	sd = configfs_new_dirent(parent_sd, element, type);
 	if (IS_ERR(sd))
 		return PTR_ERR(sd);
 
 	sd->s_mode = mode;
-	sd->s_type = type;
 	sd->s_dentry = dentry;
 	if (dentry) {
 		dentry->d_fsdata = configfs_get(sd);
@@ -187,6 +274,7 @@
 		error = configfs_make_dirent(p->d_fsdata, d, k, mode,
 					     CONFIGFS_DIR | CONFIGFS_USET_CREATING);
 	if (!error) {
+		configfs_set_dir_dirent_depth(p->d_fsdata, d->d_fsdata);
 		error = configfs_create(d, mode, init_dir);
 		if (!error) {
 			inc_nlink(p->d_inode);
@@ -789,11 +877,13 @@
 		 * error, as rmdir() would.
 		 */
 		mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
+		configfs_adjust_dir_dirent_depth_before_populate(sd);
 		ret = populate_groups(to_config_group(item));
 		if (ret) {
 			configfs_detach_item(item);
 			dentry->d_inode->i_flags |= S_DEAD;
 		}
+		configfs_adjust_dir_dirent_depth_after_populate(sd);
 		mutex_unlock(&dentry->d_inode->i_mutex);
 		if (ret)
 			d_delete(dentry);
@@ -916,11 +1006,11 @@
  * Note, btw, that this can be called at *any* time, even when a configfs
  * subsystem isn't registered, or when configfs is loading or unloading.
  * Just like configfs_register_subsystem().  So we take the same
- * precautions.  We pin the filesystem.  We lock each i_mutex _in_order_
- * on our way down the tree.  If we can find the target item in the
+ * precautions.  We pin the filesystem.  We lock configfs_dirent_lock.
+ * If we can find the target item in the
  * configfs tree, it must be part of the subsystem tree as well, so we
- * do not need the subsystem semaphore.  Holding the i_mutex chain locks
- * out mkdir() and rmdir(), who might be racing us.
+ * do not need the subsystem semaphore.  Holding configfs_dirent_lock helps
+ * locking out mkdir() and rmdir(), who might be racing us.
  */
 
 /*
@@ -933,17 +1023,21 @@
  * do that so we can unlock it if we find nothing.
  *
  * Here we do a depth-first search of the dentry hierarchy looking for
- * our object.  We take i_mutex on each step of the way down.  IT IS
- * ESSENTIAL THAT i_mutex LOCKING IS ORDERED.  If we come back up a branch,
- * we'll drop the i_mutex.
+ * our object.
+ * We deliberately ignore items tagged as dropping since they are virtually
+ * dead, as well as items in the middle of attachment since they virtually
+ * do not exist yet. This completes the locking out of racing mkdir() and
+ * rmdir().
+ * Note: subdirectories in the middle of attachment start with s_type =
+ * CONFIGFS_DIR|CONFIGFS_USET_CREATING set by create_dir().  When
+ * CONFIGFS_USET_CREATING is set, we ignore the item.  The actual set of
+ * s_type is in configfs_new_dirent(), which has configfs_dirent_lock.
  *
- * If the target is not found, -ENOENT is bubbled up and we have released
- * all locks.  If the target was found, the locks will be cleared by
- * configfs_depend_rollback().
+ * If the target is not found, -ENOENT is bubbled up.
  *
  * This adds a requirement that all config_items be unique!
  *
- * This is recursive because the locking traversal is tricky.  There isn't
+ * This is recursive.  There isn't
  * much on the stack, though, so folks that need this function - be careful
  * about your stack!  Patches will be accepted to make it iterative.
  */
@@ -955,13 +1049,13 @@
 
 	BUG_ON(!origin || !sd);
 
-	/* Lock this guy on the way down */
-	mutex_lock(&sd->s_dentry->d_inode->i_mutex);
 	if (sd->s_element == target)  /* Boo-yah */
 		goto out;
 
 	list_for_each_entry(child_sd, &sd->s_children, s_sibling) {
-		if (child_sd->s_type & CONFIGFS_DIR) {
+		if ((child_sd->s_type & CONFIGFS_DIR) &&
+		    !(child_sd->s_type & CONFIGFS_USET_DROPPING) &&
+		    !(child_sd->s_type & CONFIGFS_USET_CREATING)) {
 			ret = configfs_depend_prep(child_sd->s_dentry,
 						   target);
 			if (!ret)
@@ -970,33 +1064,12 @@
 	}
 
 	/* We looped all our children and didn't find target */
-	mutex_unlock(&sd->s_dentry->d_inode->i_mutex);
 	ret = -ENOENT;
 
 out:
 	return ret;
 }
 
-/*
- * This is ONLY called if configfs_depend_prep() did its job.  So we can
- * trust the entire path from item back up to origin.
- *
- * We walk backwards from item, unlocking each i_mutex.  We finish by
- * unlocking origin.
- */
-static void configfs_depend_rollback(struct dentry *origin,
-				     struct config_item *item)
-{
-	struct dentry *dentry = item->ci_dentry;
-
-	while (dentry != origin) {
-		mutex_unlock(&dentry->d_inode->i_mutex);
-		dentry = dentry->d_parent;
-	}
-
-	mutex_unlock(&origin->d_inode->i_mutex);
-}
-
 int configfs_depend_item(struct configfs_subsystem *subsys,
 			 struct config_item *target)
 {
@@ -1037,17 +1110,21 @@
 
 	/* Ok, now we can trust subsys/s_item */
 
-	/* Scan the tree, locking i_mutex recursively, return 0 if found */
+	spin_lock(&configfs_dirent_lock);
+	/* Scan the tree, return 0 if found */
 	ret = configfs_depend_prep(subsys_sd->s_dentry, target);
 	if (ret)
-		goto out_unlock_fs;
+		goto out_unlock_dirent_lock;
 
-	/* We hold all i_mutexes from the subsystem down to the target */
+	/*
+	 * We are sure that the item is not about to be removed by rmdir(), and
+	 * not in the middle of attachment by mkdir().
+	 */
 	p = target->ci_dentry->d_fsdata;
 	p->s_dependent_count += 1;
 
-	configfs_depend_rollback(subsys_sd->s_dentry, target);
-
+out_unlock_dirent_lock:
+	spin_unlock(&configfs_dirent_lock);
 out_unlock_fs:
 	mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex);
 
@@ -1072,10 +1149,10 @@
 	struct configfs_dirent *sd;
 
 	/*
-	 * Since we can trust everything is pinned, we just need i_mutex
-	 * on the item.
+	 * Since we can trust everything is pinned, we just need
+	 * configfs_dirent_lock.
 	 */
-	mutex_lock(&target->ci_dentry->d_inode->i_mutex);
+	spin_lock(&configfs_dirent_lock);
 
 	sd = target->ci_dentry->d_fsdata;
 	BUG_ON(sd->s_dependent_count < 1);
@@ -1086,7 +1163,7 @@
 	 * After this unlock, we cannot trust the item to stay alive!
 	 * DO NOT REFERENCE item after this unlock.
 	 */
-	mutex_unlock(&target->ci_dentry->d_inode->i_mutex);
+	spin_unlock(&configfs_dirent_lock);
 }
 EXPORT_SYMBOL(configfs_undepend_item);
 
@@ -1286,13 +1363,6 @@
 	if (sd->s_type & CONFIGFS_USET_DEFAULT)
 		return -EPERM;
 
-	/*
-	 * Here's where we check for dependents.  We're protected by
-	 * i_mutex.
-	 */
-	if (sd->s_dependent_count)
-		return -EBUSY;
-
 	/* Get a working ref until we have the child */
 	parent_item = configfs_get_config_item(dentry->d_parent);
 	subsys = to_config_group(parent_item)->cg_subsys;
@@ -1316,9 +1386,17 @@
 
 		mutex_lock(&configfs_symlink_mutex);
 		spin_lock(&configfs_dirent_lock);
-		ret = configfs_detach_prep(dentry, &wait_mutex);
-		if (ret)
-			configfs_detach_rollback(dentry);
+		/*
+		 * Here's where we check for dependents.  We're protected by
+		 * configfs_dirent_lock.
+		 * If no dependent, atomically tag the item as dropping.
+		 */
+		ret = sd->s_dependent_count ? -EBUSY : 0;
+		if (!ret) {
+			ret = configfs_detach_prep(dentry, &wait_mutex);
+			if (ret)
+				configfs_detach_rollback(dentry);
+		}
 		spin_unlock(&configfs_dirent_lock);
 		mutex_unlock(&configfs_symlink_mutex);
 
@@ -1429,7 +1507,7 @@
 	 */
 	err = -ENOENT;
 	if (configfs_dirent_is_ready(parent_sd)) {
-		file->private_data = configfs_new_dirent(parent_sd, NULL);
+		file->private_data = configfs_new_dirent(parent_sd, NULL, 0);
 		if (IS_ERR(file->private_data))
 			err = PTR_ERR(file->private_data);
 		else
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
index 5d349d3..4921e74 100644
--- a/fs/configfs/inode.c
+++ b/fs/configfs/inode.c
@@ -33,10 +33,15 @@
 #include <linux/backing-dev.h>
 #include <linux/capability.h>
 #include <linux/sched.h>
+#include <linux/lockdep.h>
 
 #include <linux/configfs.h>
 #include "configfs_internal.h"
 
+#ifdef CONFIG_LOCKDEP
+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 = {
@@ -150,6 +155,38 @@
 	return inode;
 }
 
+#ifdef CONFIG_LOCKDEP
+
+static void configfs_set_inode_lock_class(struct configfs_dirent *sd,
+					  struct inode *inode)
+{
+	int depth = sd->s_depth;
+
+	if (depth > 0) {
+		if (depth <= ARRAY_SIZE(default_group_class)) {
+			lockdep_set_class(&inode->i_mutex,
+					  &default_group_class[depth - 1]);
+		} else {
+			/*
+			 * In practice the maximum level of locking depth is
+			 * already reached. Just inform about possible reasons.
+			 */
+			printk(KERN_INFO "configfs: Too many levels of inodes"
+			       " for the locking correctness validator.\n");
+			printk(KERN_INFO "Spurious warnings may appear.\n");
+		}
+	}
+}
+
+#else /* CONFIG_LOCKDEP */
+
+static void configfs_set_inode_lock_class(struct configfs_dirent *sd,
+					  struct inode *inode)
+{
+}
+
+#endif /* CONFIG_LOCKDEP */
+
 int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *))
 {
 	int error = 0;
@@ -162,6 +199,7 @@
 					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
diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c
index 858fba1..c4dfa1d 100644
--- a/fs/dlm/dir.c
+++ b/fs/dlm/dir.c
@@ -49,7 +49,8 @@
 	spin_unlock(&ls->ls_recover_list_lock);
 
 	if (!found)
-		de = kzalloc(sizeof(struct dlm_direntry) + len, GFP_KERNEL);
+		de = kzalloc(sizeof(struct dlm_direntry) + len,
+			     ls->ls_allocation);
 	return de;
 }
 
@@ -211,7 +212,7 @@
 
 	dlm_dir_clear(ls);
 
-	last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_KERNEL);
+	last_name = kmalloc(DLM_RESNAME_MAXLEN, ls->ls_allocation);
 	if (!last_name)
 		goto out;
 
@@ -322,7 +323,7 @@
 	if (namelen > DLM_RESNAME_MAXLEN)
 		return -EINVAL;
 
-	de = kzalloc(sizeof(struct dlm_direntry) + namelen, GFP_KERNEL);
+	de = kzalloc(sizeof(struct dlm_direntry) + namelen, ls->ls_allocation);
 	if (!de)
 		return -ENOMEM;
 
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index cd8e2df..d489fcc 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -384,7 +384,7 @@
 	dlm_astd_stop();
 }
 
-static int new_lockspace(char *name, int namelen, void **lockspace,
+static int new_lockspace(const char *name, int namelen, void **lockspace,
 			 uint32_t flags, int lvblen)
 {
 	struct dlm_ls *ls;
@@ -419,16 +419,14 @@
 			break;
 		}
 		ls->ls_create_count++;
-		module_put(THIS_MODULE);
-		error = 1; /* not an error, return 0 */
+		*lockspace = ls;
+		error = 1;
 		break;
 	}
 	spin_unlock(&lslist_lock);
 
-	if (error < 0)
-		goto out;
 	if (error)
-		goto ret_zero;
+		goto out;
 
 	error = -ENOMEM;
 
@@ -583,7 +581,6 @@
 	dlm_create_debug_file(ls);
 
 	log_debug(ls, "join complete");
- ret_zero:
 	*lockspace = ls;
 	return 0;
 
@@ -614,7 +611,7 @@
 	return error;
 }
 
-int dlm_new_lockspace(char *name, int namelen, void **lockspace,
+int dlm_new_lockspace(const char *name, int namelen, void **lockspace,
 		      uint32_t flags, int lvblen)
 {
 	int error = 0;
@@ -628,7 +625,9 @@
 	error = new_lockspace(name, namelen, lockspace, flags, lvblen);
 	if (!error)
 		ls_count++;
-	else if (!ls_count)
+	if (error > 0)
+		error = 0;
+	if (!ls_count)
 		threads_stop();
  out:
 	mutex_unlock(&ls_lock);
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 609108a..cdb580a 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -309,6 +309,20 @@
 		lowcomms_write_space(sk);
 }
 
+int dlm_lowcomms_connect_node(int nodeid)
+{
+	struct connection *con;
+
+	if (nodeid == dlm_our_nodeid())
+		return 0;
+
+	con = nodeid2con(nodeid, GFP_NOFS);
+	if (!con)
+		return -ENOMEM;
+	lowcomms_connect_sock(con);
+	return 0;
+}
+
 /* Make a socket active */
 static int add_sock(struct socket *sock, struct connection *con)
 {
@@ -486,7 +500,7 @@
 				return;
 			}
 
-			new_con = nodeid2con(nodeid, GFP_KERNEL);
+			new_con = nodeid2con(nodeid, GFP_NOFS);
 			if (!new_con)
 				return;
 
@@ -722,7 +736,7 @@
 	 *  the same time and the connections cross on the wire.
 	 *  In this case we store the incoming one in "othercon"
 	 */
-	newcon = nodeid2con(nodeid, GFP_KERNEL);
+	newcon = nodeid2con(nodeid, GFP_NOFS);
 	if (!newcon) {
 		result = -ENOMEM;
 		goto accept_err;
@@ -732,7 +746,7 @@
 		struct connection *othercon = newcon->othercon;
 
 		if (!othercon) {
-			othercon = kmem_cache_zalloc(con_cache, GFP_KERNEL);
+			othercon = kmem_cache_zalloc(con_cache, GFP_NOFS);
 			if (!othercon) {
 				log_print("failed to allocate incoming socket");
 				mutex_unlock(&newcon->sock_mutex);
@@ -1421,7 +1435,7 @@
 static void stop_conn(struct connection *con)
 {
 	con->flags |= 0x0F;
-	if (con->sock)
+	if (con->sock && con->sock->sk)
 		con->sock->sk->sk_user_data = NULL;
 }
 
diff --git a/fs/dlm/lowcomms.h b/fs/dlm/lowcomms.h
index a9a9618..1311e64 100644
--- a/fs/dlm/lowcomms.h
+++ b/fs/dlm/lowcomms.h
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2009 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -19,6 +19,7 @@
 int dlm_lowcomms_close(int nodeid);
 void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc);
 void dlm_lowcomms_commit_buffer(void *mh);
+int dlm_lowcomms_connect_node(int nodeid);
 
 #endif				/* __LOWCOMMS_DOT_H__ */
 
diff --git a/fs/dlm/member.c b/fs/dlm/member.c
index 26133f0..b128775 100644
--- a/fs/dlm/member.c
+++ b/fs/dlm/member.c
@@ -1,7 +1,7 @@
 /******************************************************************************
 *******************************************************************************
 **
-**  Copyright (C) 2005-2008 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2009 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -17,6 +17,7 @@
 #include "recover.h"
 #include "rcom.h"
 #include "config.h"
+#include "lowcomms.h"
 
 static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)
 {
@@ -45,9 +46,9 @@
 static int dlm_add_member(struct dlm_ls *ls, int nodeid)
 {
 	struct dlm_member *memb;
-	int w;
+	int w, error;
 
-	memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL);
+	memb = kzalloc(sizeof(struct dlm_member), ls->ls_allocation);
 	if (!memb)
 		return -ENOMEM;
 
@@ -57,6 +58,12 @@
 		return w;
 	}
 
+	error = dlm_lowcomms_connect_node(nodeid);
+	if (error < 0) {
+		kfree(memb);
+		return error;
+	}
+
 	memb->nodeid = nodeid;
 	memb->weight = w;
 	add_ordered_member(ls, memb);
@@ -136,7 +143,7 @@
 
 	ls->ls_total_weight = total;
 
-	array = kmalloc(sizeof(int) * total, GFP_KERNEL);
+	array = kmalloc(sizeof(int) * total, ls->ls_allocation);
 	if (!array)
 		return;
 
@@ -219,7 +226,7 @@
 			continue;
 		log_debug(ls, "new nodeid %d is a re-added member", rv->new[i]);
 
-		memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL);
+		memb = kzalloc(sizeof(struct dlm_member), ls->ls_allocation);
 		if (!memb)
 			return -ENOMEM;
 		memb->nodeid = rv->new[i];
@@ -334,7 +341,7 @@
 	int *ids = NULL, *new = NULL;
 	int error, ids_count = 0, new_count = 0;
 
-	rv = kzalloc(sizeof(struct dlm_recover), GFP_KERNEL);
+	rv = kzalloc(sizeof(struct dlm_recover), ls->ls_allocation);
 	if (!rv)
 		return -ENOMEM;
 
diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c
index daa4183..7a2307c 100644
--- a/fs/dlm/requestqueue.c
+++ b/fs/dlm/requestqueue.c
@@ -35,7 +35,7 @@
 	struct rq_entry *e;
 	int length = ms->m_header.h_length - sizeof(struct dlm_message);
 
-	e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL);
+	e = kmalloc(sizeof(struct rq_entry) + length, ls->ls_allocation);
 	if (!e) {
 		log_print("dlm_add_requestqueue: out of memory len %d", length);
 		return;
diff --git a/fs/eventfd.c b/fs/eventfd.c
index 2a701d5..3f0e197 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -16,6 +16,7 @@
 #include <linux/anon_inodes.h>
 #include <linux/eventfd.h>
 #include <linux/syscalls.h>
+#include <linux/module.h>
 
 struct eventfd_ctx {
 	wait_queue_head_t wqh;
@@ -56,6 +57,7 @@
 
 	return n;
 }
+EXPORT_SYMBOL_GPL(eventfd_signal);
 
 static int eventfd_release(struct inode *inode, struct file *file)
 {
@@ -197,6 +199,7 @@
 
 	return file;
 }
+EXPORT_SYMBOL_GPL(eventfd_fget);
 
 SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
 {
diff --git a/fs/exofs/common.h b/fs/exofs/common.h
index b1512c4..24667ee 100644
--- a/fs/exofs/common.h
+++ b/fs/exofs/common.h
@@ -175,10 +175,4 @@
 
 int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr);
 
-int osd_req_read_kern(struct osd_request *or,
-	const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
-
-int osd_req_write_kern(struct osd_request *or,
-	const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
-
 #endif /*ifndef __EXOFS_COM_H__*/
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
index ba8d9fa..77d0a29 100644
--- a/fs/exofs/inode.c
+++ b/fs/exofs/inode.c
@@ -59,10 +59,9 @@
 		struct inode *inode)
 {
 	struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
-	struct request_queue *req_q = sbi->s_dev->scsi_device->request_queue;
 
 	pcol->sbi = sbi;
-	pcol->req_q = req_q;
+	pcol->req_q = osd_request_queue(sbi->s_dev);
 	pcol->inode = inode;
 	pcol->expected_pages = expected_pages;
 
@@ -266,7 +265,7 @@
 		goto err;
 	}
 
-	osd_req_read(or, &obj, pcol->bio, i_start);
+	osd_req_read(or, &obj, i_start, pcol->bio, pcol->length);
 
 	if (is_sync) {
 		exofs_sync_op(or, pcol->sbi->s_timeout, oi->i_cred);
@@ -522,7 +521,8 @@
 
 	*pcol_copy = *pcol;
 
-	osd_req_write(or, &obj, pcol_copy->bio, i_start);
+	pcol_copy->bio->bi_rw |= (1 << BIO_RW); /* FIXME: bio_set_dir() */
+	osd_req_write(or, &obj, i_start, pcol_copy->bio, pcol_copy->length);
 	ret = exofs_async_op(or, writepages_done, pcol_copy, oi->i_cred);
 	if (unlikely(ret)) {
 		EXOFS_ERR("write_exec: exofs_async_op() Faild\n");
diff --git a/fs/exofs/osd.c b/fs/exofs/osd.c
index 06ca926..b3d2ccb 100644
--- a/fs/exofs/osd.c
+++ b/fs/exofs/osd.c
@@ -125,29 +125,3 @@
 
 	return -EIO;
 }
-
-int osd_req_read_kern(struct osd_request *or,
-	const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
-{
-	struct request_queue *req_q = or->osd_dev->scsi_device->request_queue;
-	struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
-
-	if (!bio)
-		return -ENOMEM;
-
-	osd_req_read(or, obj, bio, offset);
-	return 0;
-}
-
-int osd_req_write_kern(struct osd_request *or,
-	const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
-{
-	struct request_queue *req_q = or->osd_dev->scsi_device->request_queue;
-	struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
-
-	if (!bio)
-		return -ENOMEM;
-
-	osd_req_write(or, obj, bio, offset);
-	return 0;
-}
diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile
index 7243706..e95eeb4 100644
--- a/fs/fuse/Makefile
+++ b/fs/fuse/Makefile
@@ -3,5 +3,6 @@
 #
 
 obj-$(CONFIG_FUSE_FS) += fuse.o
+obj-$(CONFIG_CUSE) += cuse.o
 
 fuse-objs := dev.o dir.o file.o inode.o control.o
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
new file mode 100644
index 0000000..de792dc
--- /dev/null
+++ b/fs/fuse/cuse.c
@@ -0,0 +1,610 @@
+/*
+ * CUSE: Character device in Userspace
+ *
+ * Copyright (C) 2008-2009  SUSE Linux Products GmbH
+ * Copyright (C) 2008-2009  Tejun Heo <tj@kernel.org>
+ *
+ * This file is released under the GPLv2.
+ *
+ * CUSE enables character devices to be implemented from userland much
+ * like FUSE allows filesystems.  On initialization /dev/cuse is
+ * created.  By opening the file and replying to the CUSE_INIT request
+ * userland CUSE server can create a character device.  After that the
+ * operation is very similar to FUSE.
+ *
+ * A CUSE instance involves the following objects.
+ *
+ * cuse_conn	: contains fuse_conn and serves as bonding structure
+ * channel	: file handle connected to the userland CUSE server
+ * cdev		: the implemented character device
+ * dev		: generic device for cdev
+ *
+ * Note that 'channel' is what 'dev' is in FUSE.  As CUSE deals with
+ * devices, it's called 'channel' to reduce confusion.
+ *
+ * channel determines when the character device dies.  When channel is
+ * closed, everything begins to destruct.  The cuse_conn is taken off
+ * the lookup table preventing further access from cdev, cdev and
+ * generic device are removed and the base reference of cuse_conn is
+ * put.
+ *
+ * On each open, the matching cuse_conn is looked up and if found an
+ * additional reference is taken which is released when the file is
+ * closed.
+ */
+
+#include <linux/fuse.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/kdev_t.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/magic.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+
+#include "fuse_i.h"
+
+#define CUSE_CONNTBL_LEN	64
+
+struct cuse_conn {
+	struct list_head	list;	/* linked on cuse_conntbl */
+	struct fuse_conn	fc;	/* fuse connection */
+	struct cdev		*cdev;	/* associated character device */
+	struct device		*dev;	/* device representing @cdev */
+
+	/* init parameters, set once during initialization */
+	bool			unrestricted_ioctl;
+};
+
+static DEFINE_SPINLOCK(cuse_lock);		/* protects cuse_conntbl */
+static struct list_head cuse_conntbl[CUSE_CONNTBL_LEN];
+static struct class *cuse_class;
+
+static struct cuse_conn *fc_to_cc(struct fuse_conn *fc)
+{
+	return container_of(fc, struct cuse_conn, fc);
+}
+
+static struct list_head *cuse_conntbl_head(dev_t devt)
+{
+	return &cuse_conntbl[(MAJOR(devt) + MINOR(devt)) % CUSE_CONNTBL_LEN];
+}
+
+
+/**************************************************************************
+ * CUSE frontend operations
+ *
+ * These are file operations for the character device.
+ *
+ * On open, CUSE opens a file from the FUSE mnt and stores it to
+ * private_data of the open file.  All other ops call FUSE ops on the
+ * FUSE file.
+ */
+
+static ssize_t cuse_read(struct file *file, char __user *buf, size_t count,
+			 loff_t *ppos)
+{
+	loff_t pos = 0;
+
+	return fuse_direct_io(file, buf, count, &pos, 0);
+}
+
+static ssize_t cuse_write(struct file *file, const char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	loff_t pos = 0;
+	/*
+	 * No locking or generic_write_checks(), the server is
+	 * responsible for locking and sanity checks.
+	 */
+	return fuse_direct_io(file, buf, count, &pos, 1);
+}
+
+static int cuse_open(struct inode *inode, struct file *file)
+{
+	dev_t devt = inode->i_cdev->dev;
+	struct cuse_conn *cc = NULL, *pos;
+	int rc;
+
+	/* look up and get the connection */
+	spin_lock(&cuse_lock);
+	list_for_each_entry(pos, cuse_conntbl_head(devt), list)
+		if (pos->dev->devt == devt) {
+			fuse_conn_get(&pos->fc);
+			cc = pos;
+			break;
+		}
+	spin_unlock(&cuse_lock);
+
+	/* dead? */
+	if (!cc)
+		return -ENODEV;
+
+	/*
+	 * Generic permission check is already done against the chrdev
+	 * file, proceed to open.
+	 */
+	rc = fuse_do_open(&cc->fc, 0, file, 0);
+	if (rc)
+		fuse_conn_put(&cc->fc);
+	return rc;
+}
+
+static int cuse_release(struct inode *inode, struct file *file)
+{
+	struct fuse_file *ff = file->private_data;
+	struct fuse_conn *fc = ff->fc;
+
+	fuse_sync_release(ff, file->f_flags);
+	fuse_conn_put(fc);
+
+	return 0;
+}
+
+static long cuse_file_ioctl(struct file *file, unsigned int cmd,
+			    unsigned long arg)
+{
+	struct fuse_file *ff = file->private_data;
+	struct cuse_conn *cc = fc_to_cc(ff->fc);
+	unsigned int flags = 0;
+
+	if (cc->unrestricted_ioctl)
+		flags |= FUSE_IOCTL_UNRESTRICTED;
+
+	return fuse_do_ioctl(file, cmd, arg, flags);
+}
+
+static long cuse_file_compat_ioctl(struct file *file, unsigned int cmd,
+				   unsigned long arg)
+{
+	struct fuse_file *ff = file->private_data;
+	struct cuse_conn *cc = fc_to_cc(ff->fc);
+	unsigned int flags = FUSE_IOCTL_COMPAT;
+
+	if (cc->unrestricted_ioctl)
+		flags |= FUSE_IOCTL_UNRESTRICTED;
+
+	return fuse_do_ioctl(file, cmd, arg, flags);
+}
+
+static const struct file_operations cuse_frontend_fops = {
+	.owner			= THIS_MODULE,
+	.read			= cuse_read,
+	.write			= cuse_write,
+	.open			= cuse_open,
+	.release		= cuse_release,
+	.unlocked_ioctl		= cuse_file_ioctl,
+	.compat_ioctl		= cuse_file_compat_ioctl,
+	.poll			= fuse_file_poll,
+};
+
+
+/**************************************************************************
+ * CUSE channel initialization and destruction
+ */
+
+struct cuse_devinfo {
+	const char		*name;
+};
+
+/**
+ * cuse_parse_one - parse one key=value pair
+ * @pp: i/o parameter for the current position
+ * @end: points to one past the end of the packed string
+ * @keyp: out parameter for key
+ * @valp: out parameter for value
+ *
+ * *@pp points to packed strings - "key0=val0\0key1=val1\0" which ends
+ * at @end - 1.  This function parses one pair and set *@keyp to the
+ * start of the key and *@valp to the start of the value.  Note that
+ * the original string is modified such that the key string is
+ * terminated with '\0'.  *@pp is updated to point to the next string.
+ *
+ * RETURNS:
+ * 1 on successful parse, 0 on EOF, -errno on failure.
+ */
+static int cuse_parse_one(char **pp, char *end, char **keyp, char **valp)
+{
+	char *p = *pp;
+	char *key, *val;
+
+	while (p < end && *p == '\0')
+		p++;
+	if (p == end)
+		return 0;
+
+	if (end[-1] != '\0') {
+		printk(KERN_ERR "CUSE: info not properly terminated\n");
+		return -EINVAL;
+	}
+
+	key = val = p;
+	p += strlen(p);
+
+	if (valp) {
+		strsep(&val, "=");
+		if (!val)
+			val = key + strlen(key);
+		key = strstrip(key);
+		val = strstrip(val);
+	} else
+		key = strstrip(key);
+
+	if (!strlen(key)) {
+		printk(KERN_ERR "CUSE: zero length info key specified\n");
+		return -EINVAL;
+	}
+
+	*pp = p;
+	*keyp = key;
+	if (valp)
+		*valp = val;
+
+	return 1;
+}
+
+/**
+ * cuse_parse_dev_info - parse device info
+ * @p: device info string
+ * @len: length of device info string
+ * @devinfo: out parameter for parsed device info
+ *
+ * Parse @p to extract device info and store it into @devinfo.  String
+ * pointed to by @p is modified by parsing and @devinfo points into
+ * them, so @p shouldn't be freed while @devinfo is in use.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int cuse_parse_devinfo(char *p, size_t len, struct cuse_devinfo *devinfo)
+{
+	char *end = p + len;
+	char *key, *val;
+	int rc;
+
+	while (true) {
+		rc = cuse_parse_one(&p, end, &key, &val);
+		if (rc < 0)
+			return rc;
+		if (!rc)
+			break;
+		if (strcmp(key, "DEVNAME") == 0)
+			devinfo->name = val;
+		else
+			printk(KERN_WARNING "CUSE: unknown device info \"%s\"\n",
+			       key);
+	}
+
+	if (!devinfo->name || !strlen(devinfo->name)) {
+		printk(KERN_ERR "CUSE: DEVNAME unspecified\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void cuse_gendev_release(struct device *dev)
+{
+	kfree(dev);
+}
+
+/**
+ * cuse_process_init_reply - finish initializing CUSE channel
+ *
+ * This function creates the character device and sets up all the
+ * required data structures for it.  Please read the comment at the
+ * top of this file for high level overview.
+ */
+static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
+{
+	struct cuse_conn *cc = fc_to_cc(fc);
+	struct cuse_init_out *arg = &req->misc.cuse_init_out;
+	struct page *page = req->pages[0];
+	struct cuse_devinfo devinfo = { };
+	struct device *dev;
+	struct cdev *cdev;
+	dev_t devt;
+	int rc;
+
+	if (req->out.h.error ||
+	    arg->major != FUSE_KERNEL_VERSION || arg->minor < 11) {
+		goto err;
+	}
+
+	fc->minor = arg->minor;
+	fc->max_read = max_t(unsigned, arg->max_read, 4096);
+	fc->max_write = max_t(unsigned, arg->max_write, 4096);
+
+	/* parse init reply */
+	cc->unrestricted_ioctl = arg->flags & CUSE_UNRESTRICTED_IOCTL;
+
+	rc = cuse_parse_devinfo(page_address(page), req->out.args[1].size,
+				&devinfo);
+	if (rc)
+		goto err;
+
+	/* determine and reserve devt */
+	devt = MKDEV(arg->dev_major, arg->dev_minor);
+	if (!MAJOR(devt))
+		rc = alloc_chrdev_region(&devt, MINOR(devt), 1, devinfo.name);
+	else
+		rc = register_chrdev_region(devt, 1, devinfo.name);
+	if (rc) {
+		printk(KERN_ERR "CUSE: failed to register chrdev region\n");
+		goto err;
+	}
+
+	/* devt determined, create device */
+	rc = -ENOMEM;
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		goto err_region;
+
+	device_initialize(dev);
+	dev_set_uevent_suppress(dev, 1);
+	dev->class = cuse_class;
+	dev->devt = devt;
+	dev->release = cuse_gendev_release;
+	dev_set_drvdata(dev, cc);
+	dev_set_name(dev, "%s", devinfo.name);
+
+	rc = device_add(dev);
+	if (rc)
+		goto err_device;
+
+	/* register cdev */
+	rc = -ENOMEM;
+	cdev = cdev_alloc();
+	if (!cdev)
+		goto err_device;
+
+	cdev->owner = THIS_MODULE;
+	cdev->ops = &cuse_frontend_fops;
+
+	rc = cdev_add(cdev, devt, 1);
+	if (rc)
+		goto err_cdev;
+
+	cc->dev = dev;
+	cc->cdev = cdev;
+
+	/* make the device available */
+	spin_lock(&cuse_lock);
+	list_add(&cc->list, cuse_conntbl_head(devt));
+	spin_unlock(&cuse_lock);
+
+	/* announce device availability */
+	dev_set_uevent_suppress(dev, 0);
+	kobject_uevent(&dev->kobj, KOBJ_ADD);
+out:
+	__free_page(page);
+	return;
+
+err_cdev:
+	cdev_del(cdev);
+err_device:
+	put_device(dev);
+err_region:
+	unregister_chrdev_region(devt, 1);
+err:
+	fc->conn_error = 1;
+	goto out;
+}
+
+static int cuse_send_init(struct cuse_conn *cc)
+{
+	int rc;
+	struct fuse_req *req;
+	struct page *page;
+	struct fuse_conn *fc = &cc->fc;
+	struct cuse_init_in *arg;
+
+	BUILD_BUG_ON(CUSE_INIT_INFO_MAX > PAGE_SIZE);
+
+	req = fuse_get_req(fc);
+	if (IS_ERR(req)) {
+		rc = PTR_ERR(req);
+		goto err;
+	}
+
+	rc = -ENOMEM;
+	page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+	if (!page)
+		goto err_put_req;
+
+	arg = &req->misc.cuse_init_in;
+	arg->major = FUSE_KERNEL_VERSION;
+	arg->minor = FUSE_KERNEL_MINOR_VERSION;
+	arg->flags |= CUSE_UNRESTRICTED_IOCTL;
+	req->in.h.opcode = CUSE_INIT;
+	req->in.numargs = 1;
+	req->in.args[0].size = sizeof(struct cuse_init_in);
+	req->in.args[0].value = arg;
+	req->out.numargs = 2;
+	req->out.args[0].size = sizeof(struct cuse_init_out);
+	req->out.args[0].value = &req->misc.cuse_init_out;
+	req->out.args[1].size = CUSE_INIT_INFO_MAX;
+	req->out.argvar = 1;
+	req->out.argpages = 1;
+	req->pages[0] = page;
+	req->num_pages = 1;
+	req->end = cuse_process_init_reply;
+	fuse_request_send_background(fc, req);
+
+	return 0;
+
+err_put_req:
+	fuse_put_request(fc, req);
+err:
+	return rc;
+}
+
+static void cuse_fc_release(struct fuse_conn *fc)
+{
+	struct cuse_conn *cc = fc_to_cc(fc);
+	kfree(cc);
+}
+
+/**
+ * cuse_channel_open - open method for /dev/cuse
+ * @inode: inode for /dev/cuse
+ * @file: file struct being opened
+ *
+ * Userland CUSE server can create a CUSE device by opening /dev/cuse
+ * and replying to the initilaization request kernel sends.  This
+ * function is responsible for handling CUSE device initialization.
+ * Because the fd opened by this function is used during
+ * initialization, this function only creates cuse_conn and sends
+ * init.  The rest is delegated to a kthread.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int cuse_channel_open(struct inode *inode, struct file *file)
+{
+	struct cuse_conn *cc;
+	int rc;
+
+	/* set up cuse_conn */
+	cc = kzalloc(sizeof(*cc), GFP_KERNEL);
+	if (!cc)
+		return -ENOMEM;
+
+	fuse_conn_init(&cc->fc);
+
+	INIT_LIST_HEAD(&cc->list);
+	cc->fc.release = cuse_fc_release;
+
+	cc->fc.connected = 1;
+	cc->fc.blocked = 0;
+	rc = cuse_send_init(cc);
+	if (rc) {
+		fuse_conn_put(&cc->fc);
+		return rc;
+	}
+	file->private_data = &cc->fc;	/* channel owns base reference to cc */
+
+	return 0;
+}
+
+/**
+ * cuse_channel_release - release method for /dev/cuse
+ * @inode: inode for /dev/cuse
+ * @file: file struct being closed
+ *
+ * Disconnect the channel, deregister CUSE device and initiate
+ * destruction by putting the default reference.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int cuse_channel_release(struct inode *inode, struct file *file)
+{
+	struct cuse_conn *cc = fc_to_cc(file->private_data);
+	int rc;
+
+	/* remove from the conntbl, no more access from this point on */
+	spin_lock(&cuse_lock);
+	list_del_init(&cc->list);
+	spin_unlock(&cuse_lock);
+
+	/* remove device */
+	if (cc->dev)
+		device_unregister(cc->dev);
+	if (cc->cdev) {
+		unregister_chrdev_region(cc->cdev->dev, 1);
+		cdev_del(cc->cdev);
+	}
+
+	/* kill connection and shutdown channel */
+	fuse_conn_kill(&cc->fc);
+	rc = fuse_dev_release(inode, file);	/* puts the base reference */
+
+	return rc;
+}
+
+static struct file_operations cuse_channel_fops; /* initialized during init */
+
+
+/**************************************************************************
+ * Misc stuff and module initializatiion
+ *
+ * CUSE exports the same set of attributes to sysfs as fusectl.
+ */
+
+static ssize_t cuse_class_waiting_show(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	struct cuse_conn *cc = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", atomic_read(&cc->fc.num_waiting));
+}
+
+static ssize_t cuse_class_abort_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t count)
+{
+	struct cuse_conn *cc = dev_get_drvdata(dev);
+
+	fuse_abort_conn(&cc->fc);
+	return count;
+}
+
+static struct device_attribute cuse_class_dev_attrs[] = {
+	__ATTR(waiting, S_IFREG | 0400, cuse_class_waiting_show, NULL),
+	__ATTR(abort, S_IFREG | 0200, NULL, cuse_class_abort_store),
+	{ }
+};
+
+static struct miscdevice cuse_miscdev = {
+	.minor		= MISC_DYNAMIC_MINOR,
+	.name		= "cuse",
+	.fops		= &cuse_channel_fops,
+};
+
+static int __init cuse_init(void)
+{
+	int i, rc;
+
+	/* init conntbl */
+	for (i = 0; i < CUSE_CONNTBL_LEN; i++)
+		INIT_LIST_HEAD(&cuse_conntbl[i]);
+
+	/* inherit and extend fuse_dev_operations */
+	cuse_channel_fops		= fuse_dev_operations;
+	cuse_channel_fops.owner		= THIS_MODULE;
+	cuse_channel_fops.open		= cuse_channel_open;
+	cuse_channel_fops.release	= cuse_channel_release;
+
+	cuse_class = class_create(THIS_MODULE, "cuse");
+	if (IS_ERR(cuse_class))
+		return PTR_ERR(cuse_class);
+
+	cuse_class->dev_attrs = cuse_class_dev_attrs;
+
+	rc = misc_register(&cuse_miscdev);
+	if (rc) {
+		class_destroy(cuse_class);
+		return rc;
+	}
+
+	return 0;
+}
+
+static void __exit cuse_exit(void)
+{
+	misc_deregister(&cuse_miscdev);
+	class_destroy(cuse_class);
+}
+
+module_init(cuse_init);
+module_exit(cuse_exit);
+
+MODULE_AUTHOR("Tejun Heo <tj@kernel.org>");
+MODULE_DESCRIPTION("Character device in Userspace");
+MODULE_LICENSE("GPL");
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index ba76b68..8fed2ed 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -46,6 +46,7 @@
 		fuse_request_init(req);
 	return req;
 }
+EXPORT_SYMBOL_GPL(fuse_request_alloc);
 
 struct fuse_req *fuse_request_alloc_nofs(void)
 {
@@ -124,6 +125,7 @@
 	atomic_dec(&fc->num_waiting);
 	return ERR_PTR(err);
 }
+EXPORT_SYMBOL_GPL(fuse_get_req);
 
 /*
  * Return request in fuse_file->reserved_req.  However that may
@@ -208,6 +210,7 @@
 			fuse_request_free(req);
 	}
 }
+EXPORT_SYMBOL_GPL(fuse_put_request);
 
 static unsigned len_args(unsigned numargs, struct fuse_arg *args)
 {
@@ -282,7 +285,7 @@
 			wake_up_all(&fc->blocked_waitq);
 		}
 		if (fc->num_background == FUSE_CONGESTION_THRESHOLD &&
-		    fc->connected) {
+		    fc->connected && fc->bdi_initialized) {
 			clear_bdi_congested(&fc->bdi, READ);
 			clear_bdi_congested(&fc->bdi, WRITE);
 		}
@@ -400,6 +403,7 @@
 	}
 	spin_unlock(&fc->lock);
 }
+EXPORT_SYMBOL_GPL(fuse_request_send);
 
 static void fuse_request_send_nowait_locked(struct fuse_conn *fc,
 					    struct fuse_req *req)
@@ -408,7 +412,8 @@
 	fc->num_background++;
 	if (fc->num_background == FUSE_MAX_BACKGROUND)
 		fc->blocked = 1;
-	if (fc->num_background == FUSE_CONGESTION_THRESHOLD) {
+	if (fc->num_background == FUSE_CONGESTION_THRESHOLD &&
+	    fc->bdi_initialized) {
 		set_bdi_congested(&fc->bdi, READ);
 		set_bdi_congested(&fc->bdi, WRITE);
 	}
@@ -439,6 +444,7 @@
 	req->isreply = 1;
 	fuse_request_send_nowait(fc, req);
 }
+EXPORT_SYMBOL_GPL(fuse_request_send_background);
 
 /*
  * Called under fc->lock
@@ -1105,8 +1111,9 @@
 	}
 	spin_unlock(&fc->lock);
 }
+EXPORT_SYMBOL_GPL(fuse_abort_conn);
 
-static int fuse_dev_release(struct inode *inode, struct file *file)
+int fuse_dev_release(struct inode *inode, struct file *file)
 {
 	struct fuse_conn *fc = fuse_get_conn(file);
 	if (fc) {
@@ -1120,6 +1127,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(fuse_dev_release);
 
 static int fuse_dev_fasync(int fd, struct file *file, int on)
 {
@@ -1142,6 +1150,7 @@
 	.release	= fuse_dev_release,
 	.fasync		= fuse_dev_fasync,
 };
+EXPORT_SYMBOL_GPL(fuse_dev_operations);
 
 static struct miscdevice fuse_miscdevice = {
 	.minor = FUSE_MINOR,
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 8b8eebc..b3089a0 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -362,19 +362,6 @@
 }
 
 /*
- * Synchronous release for the case when something goes wrong in CREATE_OPEN
- */
-static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff,
-			      u64 nodeid, int flags)
-{
-	fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE);
-	ff->reserved_req->force = 1;
-	fuse_request_send(fc, ff->reserved_req);
-	fuse_put_request(fc, ff->reserved_req);
-	kfree(ff);
-}
-
-/*
  * Atomic create+open operation
  *
  * If the filesystem doesn't support this, then fall back to separate
@@ -445,12 +432,14 @@
 		goto out_free_ff;
 
 	fuse_put_request(fc, req);
+	ff->fh = outopen.fh;
+	ff->nodeid = outentry.nodeid;
+	ff->open_flags = outopen.open_flags;
 	inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
 			  &outentry.attr, entry_attr_timeout(&outentry), 0);
 	if (!inode) {
 		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
-		ff->fh = outopen.fh;
-		fuse_sync_release(fc, ff, outentry.nodeid, flags);
+		fuse_sync_release(ff, flags);
 		fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
 		return -ENOMEM;
 	}
@@ -460,11 +449,11 @@
 	fuse_invalidate_attr(dir);
 	file = lookup_instantiate_filp(nd, entry, generic_file_open);
 	if (IS_ERR(file)) {
-		ff->fh = outopen.fh;
-		fuse_sync_release(fc, ff, outentry.nodeid, flags);
+		fuse_sync_release(ff, flags);
 		return PTR_ERR(file);
 	}
-	fuse_finish_open(inode, file, ff, &outopen);
+	file->private_data = fuse_file_get(ff);
+	fuse_finish_open(inode, file);
 	return 0;
 
  out_free_ff:
@@ -1035,7 +1024,7 @@
 	req->out.argpages = 1;
 	req->num_pages = 1;
 	req->pages[0] = page;
-	fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR);
+	fuse_read_fill(req, file, file->f_pos, PAGE_SIZE, FUSE_READDIR);
 	fuse_request_send(fc, req);
 	nbytes = req->out.args[0].size;
 	err = req->out.h.error;
@@ -1101,12 +1090,14 @@
 
 static int fuse_dir_open(struct inode *inode, struct file *file)
 {
-	return fuse_open_common(inode, file, 1);
+	return fuse_open_common(inode, file, true);
 }
 
 static int fuse_dir_release(struct inode *inode, struct file *file)
 {
-	return fuse_release_common(inode, file, 1);
+	fuse_release_common(file, FUSE_RELEASEDIR);
+
+	return 0;
 }
 
 static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 06f30e9..fce6ce6 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -12,13 +12,13 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/module.h>
 
 static const struct file_operations fuse_direct_io_file_operations;
 
-static int fuse_send_open(struct inode *inode, struct file *file, int isdir,
-			  struct fuse_open_out *outargp)
+static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
+			  int opcode, struct fuse_open_out *outargp)
 {
-	struct fuse_conn *fc = get_fuse_conn(inode);
 	struct fuse_open_in inarg;
 	struct fuse_req *req;
 	int err;
@@ -31,8 +31,8 @@
 	inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY);
 	if (!fc->atomic_o_trunc)
 		inarg.flags &= ~O_TRUNC;
-	req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
-	req->in.h.nodeid = get_node_id(inode);
+	req->in.h.opcode = opcode;
+	req->in.h.nodeid = nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -49,22 +49,27 @@
 struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
 {
 	struct fuse_file *ff;
+
 	ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
-	if (ff) {
-		ff->reserved_req = fuse_request_alloc();
-		if (!ff->reserved_req) {
-			kfree(ff);
-			return NULL;
-		} else {
-			INIT_LIST_HEAD(&ff->write_entry);
-			atomic_set(&ff->count, 0);
-			spin_lock(&fc->lock);
-			ff->kh = ++fc->khctr;
-			spin_unlock(&fc->lock);
-		}
-		RB_CLEAR_NODE(&ff->polled_node);
-		init_waitqueue_head(&ff->poll_wait);
+	if (unlikely(!ff))
+		return NULL;
+
+	ff->fc = fc;
+	ff->reserved_req = fuse_request_alloc();
+	if (unlikely(!ff->reserved_req)) {
+		kfree(ff);
+		return NULL;
 	}
+
+	INIT_LIST_HEAD(&ff->write_entry);
+	atomic_set(&ff->count, 0);
+	RB_CLEAR_NODE(&ff->polled_node);
+	init_waitqueue_head(&ff->poll_wait);
+
+	spin_lock(&fc->lock);
+	ff->kh = ++fc->khctr;
+	spin_unlock(&fc->lock);
+
 	return ff;
 }
 
@@ -74,7 +79,7 @@
 	kfree(ff);
 }
 
-static struct fuse_file *fuse_file_get(struct fuse_file *ff)
+struct fuse_file *fuse_file_get(struct fuse_file *ff)
 {
 	atomic_inc(&ff->count);
 	return ff;
@@ -82,41 +87,66 @@
 
 static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
 {
-	dput(req->misc.release.dentry);
-	mntput(req->misc.release.vfsmount);
+	path_put(&req->misc.release.path);
 }
 
 static void fuse_file_put(struct fuse_file *ff)
 {
 	if (atomic_dec_and_test(&ff->count)) {
 		struct fuse_req *req = ff->reserved_req;
-		struct inode *inode = req->misc.release.dentry->d_inode;
-		struct fuse_conn *fc = get_fuse_conn(inode);
+
 		req->end = fuse_release_end;
-		fuse_request_send_background(fc, req);
+		fuse_request_send_background(ff->fc, req);
 		kfree(ff);
 	}
 }
 
-void fuse_finish_open(struct inode *inode, struct file *file,
-		      struct fuse_file *ff, struct fuse_open_out *outarg)
+int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
+		 bool isdir)
 {
-	if (outarg->open_flags & FOPEN_DIRECT_IO)
-		file->f_op = &fuse_direct_io_file_operations;
-	if (!(outarg->open_flags & FOPEN_KEEP_CACHE))
-		invalidate_inode_pages2(inode->i_mapping);
-	if (outarg->open_flags & FOPEN_NONSEEKABLE)
-		nonseekable_open(inode, file);
-	ff->fh = outarg->fh;
-	file->private_data = fuse_file_get(ff);
-}
-
-int fuse_open_common(struct inode *inode, struct file *file, int isdir)
-{
-	struct fuse_conn *fc = get_fuse_conn(inode);
 	struct fuse_open_out outarg;
 	struct fuse_file *ff;
 	int err;
+	int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
+
+	ff = fuse_file_alloc(fc);
+	if (!ff)
+		return -ENOMEM;
+
+	err = fuse_send_open(fc, nodeid, file, opcode, &outarg);
+	if (err) {
+		fuse_file_free(ff);
+		return err;
+	}
+
+	if (isdir)
+		outarg.open_flags &= ~FOPEN_DIRECT_IO;
+
+	ff->fh = outarg.fh;
+	ff->nodeid = nodeid;
+	ff->open_flags = outarg.open_flags;
+	file->private_data = fuse_file_get(ff);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(fuse_do_open);
+
+void fuse_finish_open(struct inode *inode, struct file *file)
+{
+	struct fuse_file *ff = file->private_data;
+
+	if (ff->open_flags & FOPEN_DIRECT_IO)
+		file->f_op = &fuse_direct_io_file_operations;
+	if (!(ff->open_flags & FOPEN_KEEP_CACHE))
+		invalidate_inode_pages2(inode->i_mapping);
+	if (ff->open_flags & FOPEN_NONSEEKABLE)
+		nonseekable_open(inode, file);
+}
+
+int fuse_open_common(struct inode *inode, struct file *file, bool isdir)
+{
+	struct fuse_conn *fc = get_fuse_conn(inode);
+	int err;
 
 	/* VFS checks this, but only _after_ ->open() */
 	if (file->f_flags & O_DIRECT)
@@ -126,79 +156,86 @@
 	if (err)
 		return err;
 
-	ff = fuse_file_alloc(fc);
-	if (!ff)
-		return -ENOMEM;
-
-	err = fuse_send_open(inode, file, isdir, &outarg);
+	err = fuse_do_open(fc, get_node_id(inode), file, isdir);
 	if (err)
-		fuse_file_free(ff);
-	else {
-		if (isdir)
-			outarg.open_flags &= ~FOPEN_DIRECT_IO;
-		fuse_finish_open(inode, file, ff, &outarg);
-	}
+		return err;
 
-	return err;
+	fuse_finish_open(inode, file);
+
+	return 0;
 }
 
-void fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, int opcode)
+static void fuse_prepare_release(struct fuse_file *ff, int flags, int opcode)
 {
+	struct fuse_conn *fc = ff->fc;
 	struct fuse_req *req = ff->reserved_req;
 	struct fuse_release_in *inarg = &req->misc.release.in;
 
+	spin_lock(&fc->lock);
+	list_del(&ff->write_entry);
+	if (!RB_EMPTY_NODE(&ff->polled_node))
+		rb_erase(&ff->polled_node, &fc->polled_files);
+	spin_unlock(&fc->lock);
+
+	wake_up_interruptible_sync(&ff->poll_wait);
+
 	inarg->fh = ff->fh;
 	inarg->flags = flags;
 	req->in.h.opcode = opcode;
-	req->in.h.nodeid = nodeid;
+	req->in.h.nodeid = ff->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(struct fuse_release_in);
 	req->in.args[0].value = inarg;
 }
 
-int fuse_release_common(struct inode *inode, struct file *file, int isdir)
+void fuse_release_common(struct file *file, int opcode)
 {
-	struct fuse_file *ff = file->private_data;
-	if (ff) {
-		struct fuse_conn *fc = get_fuse_conn(inode);
-		struct fuse_req *req = ff->reserved_req;
+	struct fuse_file *ff;
+	struct fuse_req *req;
 
-		fuse_release_fill(ff, get_node_id(inode), file->f_flags,
-				  isdir ? FUSE_RELEASEDIR : FUSE_RELEASE);
+	ff = file->private_data;
+	if (unlikely(!ff))
+		return;
 
-		/* Hold vfsmount and dentry until release is finished */
-		req->misc.release.vfsmount = mntget(file->f_path.mnt);
-		req->misc.release.dentry = dget(file->f_path.dentry);
+	req = ff->reserved_req;
+	fuse_prepare_release(ff, file->f_flags, opcode);
 
-		spin_lock(&fc->lock);
-		list_del(&ff->write_entry);
-		if (!RB_EMPTY_NODE(&ff->polled_node))
-			rb_erase(&ff->polled_node, &fc->polled_files);
-		spin_unlock(&fc->lock);
+	/* Hold vfsmount and dentry until release is finished */
+	path_get(&file->f_path);
+	req->misc.release.path = file->f_path;
 
-		wake_up_interruptible_sync(&ff->poll_wait);
-		/*
-		 * Normally this will send the RELEASE request,
-		 * however if some asynchronous READ or WRITE requests
-		 * are outstanding, the sending will be delayed
-		 */
-		fuse_file_put(ff);
-	}
-
-	/* Return value is ignored by VFS */
-	return 0;
+	/*
+	 * Normally this will send the RELEASE request, however if
+	 * some asynchronous READ or WRITE requests are outstanding,
+	 * the sending will be delayed.
+	 */
+	fuse_file_put(ff);
 }
 
 static int fuse_open(struct inode *inode, struct file *file)
 {
-	return fuse_open_common(inode, file, 0);
+	return fuse_open_common(inode, file, false);
 }
 
 static int fuse_release(struct inode *inode, struct file *file)
 {
-	return fuse_release_common(inode, file, 0);
+	fuse_release_common(file, FUSE_RELEASE);
+
+	/* return value is ignored by VFS */
+	return 0;
 }
 
+void fuse_sync_release(struct fuse_file *ff, int flags)
+{
+	WARN_ON(atomic_read(&ff->count) > 1);
+	fuse_prepare_release(ff, flags, FUSE_RELEASE);
+	ff->reserved_req->force = 1;
+	fuse_request_send(ff->fc, ff->reserved_req);
+	fuse_put_request(ff->fc, ff->reserved_req);
+	kfree(ff);
+}
+EXPORT_SYMBOL_GPL(fuse_sync_release);
+
 /*
  * Scramble the ID space with XTEA, so that the value of the files_struct
  * pointer is not exposed to userspace.
@@ -371,8 +408,8 @@
 	return fuse_fsync_common(file, de, datasync, 0);
 }
 
-void fuse_read_fill(struct fuse_req *req, struct file *file,
-		    struct inode *inode, loff_t pos, size_t count, int opcode)
+void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos,
+		    size_t count, int opcode)
 {
 	struct fuse_read_in *inarg = &req->misc.read.in;
 	struct fuse_file *ff = file->private_data;
@@ -382,7 +419,7 @@
 	inarg->size = count;
 	inarg->flags = file->f_flags;
 	req->in.h.opcode = opcode;
-	req->in.h.nodeid = get_node_id(inode);
+	req->in.h.nodeid = ff->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(struct fuse_read_in);
 	req->in.args[0].value = inarg;
@@ -392,12 +429,12 @@
 }
 
 static size_t fuse_send_read(struct fuse_req *req, struct file *file,
-			     struct inode *inode, loff_t pos, size_t count,
-			     fl_owner_t owner)
+			     loff_t pos, size_t count, fl_owner_t owner)
 {
-	struct fuse_conn *fc = get_fuse_conn(inode);
+	struct fuse_file *ff = file->private_data;
+	struct fuse_conn *fc = ff->fc;
 
-	fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
+	fuse_read_fill(req, file, pos, count, FUSE_READ);
 	if (owner != NULL) {
 		struct fuse_read_in *inarg = &req->misc.read.in;
 
@@ -455,7 +492,7 @@
 	req->out.argpages = 1;
 	req->num_pages = 1;
 	req->pages[0] = page;
-	num_read = fuse_send_read(req, file, inode, pos, count, NULL);
+	num_read = fuse_send_read(req, file, pos, count, NULL);
 	err = req->out.h.error;
 	fuse_put_request(fc, req);
 
@@ -504,19 +541,18 @@
 		fuse_file_put(req->ff);
 }
 
-static void fuse_send_readpages(struct fuse_req *req, struct file *file,
-				struct inode *inode)
+static void fuse_send_readpages(struct fuse_req *req, struct file *file)
 {
-	struct fuse_conn *fc = get_fuse_conn(inode);
+	struct fuse_file *ff = file->private_data;
+	struct fuse_conn *fc = ff->fc;
 	loff_t pos = page_offset(req->pages[0]);
 	size_t count = req->num_pages << PAGE_CACHE_SHIFT;
 
 	req->out.argpages = 1;
 	req->out.page_zeroing = 1;
-	fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
+	fuse_read_fill(req, file, pos, count, FUSE_READ);
 	req->misc.read.attr_ver = fuse_get_attr_version(fc);
 	if (fc->async_read) {
-		struct fuse_file *ff = file->private_data;
 		req->ff = fuse_file_get(ff);
 		req->end = fuse_readpages_end;
 		fuse_request_send_background(fc, req);
@@ -546,7 +582,7 @@
 	    (req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
 	     (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read ||
 	     req->pages[req->num_pages - 1]->index + 1 != page->index)) {
-		fuse_send_readpages(req, data->file, inode);
+		fuse_send_readpages(req, data->file);
 		data->req = req = fuse_get_req(fc);
 		if (IS_ERR(req)) {
 			unlock_page(page);
@@ -580,7 +616,7 @@
 	err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data);
 	if (!err) {
 		if (data.req->num_pages)
-			fuse_send_readpages(data.req, file, inode);
+			fuse_send_readpages(data.req, file);
 		else
 			fuse_put_request(fc, data.req);
 	}
@@ -607,24 +643,19 @@
 	return generic_file_aio_read(iocb, iov, nr_segs, pos);
 }
 
-static void fuse_write_fill(struct fuse_req *req, struct file *file,
-			    struct fuse_file *ff, struct inode *inode,
-			    loff_t pos, size_t count, int writepage)
+static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff,
+			    loff_t pos, size_t count)
 {
-	struct fuse_conn *fc = get_fuse_conn(inode);
 	struct fuse_write_in *inarg = &req->misc.write.in;
 	struct fuse_write_out *outarg = &req->misc.write.out;
 
-	memset(inarg, 0, sizeof(struct fuse_write_in));
 	inarg->fh = ff->fh;
 	inarg->offset = pos;
 	inarg->size = count;
-	inarg->write_flags = writepage ? FUSE_WRITE_CACHE : 0;
-	inarg->flags = file ? file->f_flags : 0;
 	req->in.h.opcode = FUSE_WRITE;
-	req->in.h.nodeid = get_node_id(inode);
+	req->in.h.nodeid = ff->nodeid;
 	req->in.numargs = 2;
-	if (fc->minor < 9)
+	if (ff->fc->minor < 9)
 		req->in.args[0].size = FUSE_COMPAT_WRITE_IN_SIZE;
 	else
 		req->in.args[0].size = sizeof(struct fuse_write_in);
@@ -636,13 +667,15 @@
 }
 
 static size_t fuse_send_write(struct fuse_req *req, struct file *file,
-			      struct inode *inode, loff_t pos, size_t count,
-			      fl_owner_t owner)
+			      loff_t pos, size_t count, fl_owner_t owner)
 {
-	struct fuse_conn *fc = get_fuse_conn(inode);
-	fuse_write_fill(req, file, file->private_data, inode, pos, count, 0);
+	struct fuse_file *ff = file->private_data;
+	struct fuse_conn *fc = ff->fc;
+	struct fuse_write_in *inarg = &req->misc.write.in;
+
+	fuse_write_fill(req, ff, pos, count);
+	inarg->flags = file->f_flags;
 	if (owner != NULL) {
-		struct fuse_write_in *inarg = &req->misc.write.in;
 		inarg->write_flags |= FUSE_WRITE_LOCKOWNER;
 		inarg->lock_owner = fuse_lock_owner_id(fc, owner);
 	}
@@ -700,7 +733,7 @@
 	req->num_pages = 1;
 	req->pages[0] = page;
 	req->page_offset = offset;
-	nres = fuse_send_write(req, file, inode, pos, count, NULL);
+	nres = fuse_send_write(req, file, pos, count, NULL);
 	err = req->out.h.error;
 	fuse_put_request(fc, req);
 	if (!err && !nres)
@@ -741,7 +774,7 @@
 	for (i = 0; i < req->num_pages; i++)
 		fuse_wait_on_page_writeback(inode, req->pages[i]->index);
 
-	res = fuse_send_write(req, file, inode, pos, count, NULL);
+	res = fuse_send_write(req, file, pos, count, NULL);
 
 	offset = req->page_offset;
 	count = res;
@@ -979,25 +1012,23 @@
 	return 0;
 }
 
-static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
-			      size_t count, loff_t *ppos, int write)
+ssize_t fuse_direct_io(struct file *file, const char __user *buf,
+		       size_t count, loff_t *ppos, int write)
 {
-	struct inode *inode = file->f_path.dentry->d_inode;
-	struct fuse_conn *fc = get_fuse_conn(inode);
+	struct fuse_file *ff = file->private_data;
+	struct fuse_conn *fc = ff->fc;
 	size_t nmax = write ? fc->max_write : fc->max_read;
 	loff_t pos = *ppos;
 	ssize_t res = 0;
 	struct fuse_req *req;
 
-	if (is_bad_inode(inode))
-		return -EIO;
-
 	req = fuse_get_req(fc);
 	if (IS_ERR(req))
 		return PTR_ERR(req);
 
 	while (count) {
 		size_t nres;
+		fl_owner_t owner = current->files;
 		size_t nbytes = min(count, nmax);
 		int err = fuse_get_user_pages(req, buf, &nbytes, write);
 		if (err) {
@@ -1006,11 +1037,10 @@
 		}
 
 		if (write)
-			nres = fuse_send_write(req, file, inode, pos, nbytes,
-					       current->files);
+			nres = fuse_send_write(req, file, pos, nbytes, owner);
 		else
-			nres = fuse_send_read(req, file, inode, pos, nbytes,
-					      current->files);
+			nres = fuse_send_read(req, file, pos, nbytes, owner);
+
 		fuse_release_user_pages(req, !write);
 		if (req->out.h.error) {
 			if (!res)
@@ -1034,20 +1064,27 @@
 		}
 	}
 	fuse_put_request(fc, req);
-	if (res > 0) {
-		if (write)
-			fuse_write_update_size(inode, pos);
+	if (res > 0)
 		*ppos = pos;
-	}
-	fuse_invalidate_attr(inode);
 
 	return res;
 }
+EXPORT_SYMBOL_GPL(fuse_direct_io);
 
 static ssize_t fuse_direct_read(struct file *file, char __user *buf,
 				     size_t count, loff_t *ppos)
 {
-	return fuse_direct_io(file, buf, count, ppos, 0);
+	ssize_t res;
+	struct inode *inode = file->f_path.dentry->d_inode;
+
+	if (is_bad_inode(inode))
+		return -EIO;
+
+	res = fuse_direct_io(file, buf, count, ppos, 0);
+
+	fuse_invalidate_attr(inode);
+
+	return res;
 }
 
 static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
@@ -1055,12 +1092,22 @@
 {
 	struct inode *inode = file->f_path.dentry->d_inode;
 	ssize_t res;
+
+	if (is_bad_inode(inode))
+		return -EIO;
+
 	/* Don't allow parallel writes to the same file */
 	mutex_lock(&inode->i_mutex);
 	res = generic_write_checks(file, ppos, &count, 0);
-	if (!res)
+	if (!res) {
 		res = fuse_direct_io(file, buf, count, ppos, 1);
+		if (res > 0)
+			fuse_write_update_size(inode, *ppos);
+	}
 	mutex_unlock(&inode->i_mutex);
+
+	fuse_invalidate_attr(inode);
+
 	return res;
 }
 
@@ -1177,9 +1224,10 @@
 	req->ff = fuse_file_get(ff);
 	spin_unlock(&fc->lock);
 
-	fuse_write_fill(req, NULL, ff, inode, page_offset(page), 0, 1);
+	fuse_write_fill(req, ff, page_offset(page), 0);
 
 	copy_highpage(tmp_page, page);
+	req->misc.write.in.write_flags |= FUSE_WRITE_CACHE;
 	req->in.argpages = 1;
 	req->num_pages = 1;
 	req->pages[0] = tmp_page;
@@ -1603,12 +1651,11 @@
  * limits ioctl data transfers to well-formed ioctls and is the forced
  * behavior for all FUSE servers.
  */
-static long fuse_file_do_ioctl(struct file *file, unsigned int cmd,
-			       unsigned long arg, unsigned int flags)
+long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
+		   unsigned int flags)
 {
-	struct inode *inode = file->f_dentry->d_inode;
 	struct fuse_file *ff = file->private_data;
-	struct fuse_conn *fc = get_fuse_conn(inode);
+	struct fuse_conn *fc = ff->fc;
 	struct fuse_ioctl_in inarg = {
 		.fh = ff->fh,
 		.cmd = cmd,
@@ -1627,13 +1674,6 @@
 	/* assume all the iovs returned by client always fits in a page */
 	BUILD_BUG_ON(sizeof(struct iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE);
 
-	if (!fuse_allow_task(fc, current))
-		return -EACCES;
-
-	err = -EIO;
-	if (is_bad_inode(inode))
-		goto out;
-
 	err = -ENOMEM;
 	pages = kzalloc(sizeof(pages[0]) * FUSE_MAX_PAGES_PER_REQ, GFP_KERNEL);
 	iov_page = alloc_page(GFP_KERNEL);
@@ -1694,7 +1734,7 @@
 
 	/* okay, let's send it to the client */
 	req->in.h.opcode = FUSE_IOCTL;
-	req->in.h.nodeid = get_node_id(inode);
+	req->in.h.nodeid = ff->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -1777,17 +1817,33 @@
 
 	return err ? err : outarg.result;
 }
+EXPORT_SYMBOL_GPL(fuse_do_ioctl);
+
+static long fuse_file_ioctl_common(struct file *file, unsigned int cmd,
+				   unsigned long arg, unsigned int flags)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	struct fuse_conn *fc = get_fuse_conn(inode);
+
+	if (!fuse_allow_task(fc, current))
+		return -EACCES;
+
+	if (is_bad_inode(inode))
+		return -EIO;
+
+	return fuse_do_ioctl(file, cmd, arg, flags);
+}
 
 static long fuse_file_ioctl(struct file *file, unsigned int cmd,
 			    unsigned long arg)
 {
-	return fuse_file_do_ioctl(file, cmd, arg, 0);
+	return fuse_file_ioctl_common(file, cmd, arg, 0);
 }
 
 static long fuse_file_compat_ioctl(struct file *file, unsigned int cmd,
 				   unsigned long arg)
 {
-	return fuse_file_do_ioctl(file, cmd, arg, FUSE_IOCTL_COMPAT);
+	return fuse_file_ioctl_common(file, cmd, arg, FUSE_IOCTL_COMPAT);
 }
 
 /*
@@ -1841,11 +1897,10 @@
 	spin_unlock(&fc->lock);
 }
 
-static unsigned fuse_file_poll(struct file *file, poll_table *wait)
+unsigned fuse_file_poll(struct file *file, poll_table *wait)
 {
-	struct inode *inode = file->f_dentry->d_inode;
 	struct fuse_file *ff = file->private_data;
-	struct fuse_conn *fc = get_fuse_conn(inode);
+	struct fuse_conn *fc = ff->fc;
 	struct fuse_poll_in inarg = { .fh = ff->fh, .kh = ff->kh };
 	struct fuse_poll_out outarg;
 	struct fuse_req *req;
@@ -1870,7 +1925,7 @@
 		return PTR_ERR(req);
 
 	req->in.h.opcode = FUSE_POLL;
-	req->in.h.nodeid = get_node_id(inode);
+	req->in.h.nodeid = ff->nodeid;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -1889,6 +1944,7 @@
 	}
 	return POLLERR;
 }
+EXPORT_SYMBOL_GPL(fuse_file_poll);
 
 /*
  * This is called from fuse_handle_notify() on FUSE_NOTIFY_POLL and
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 6fc5aed..aaf2f9f 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -97,8 +97,13 @@
 	struct list_head writepages;
 };
 
+struct fuse_conn;
+
 /** FUSE specific file data */
 struct fuse_file {
+	/** Fuse connection for this file */
+	struct fuse_conn *fc;
+
 	/** Request reserved for flush and release */
 	struct fuse_req *reserved_req;
 
@@ -108,9 +113,15 @@
 	/** File handle used by userspace */
 	u64 fh;
 
+	/** Node id of this file */
+	u64 nodeid;
+
 	/** Refcount */
 	atomic_t count;
 
+	/** FOPEN_* flags returned by open */
+	u32 open_flags;
+
 	/** Entry on inode's write_files list */
 	struct list_head write_entry;
 
@@ -185,8 +196,6 @@
 	FUSE_REQ_FINISHED
 };
 
-struct fuse_conn;
-
 /**
  * A request to the client
  */
@@ -248,11 +257,12 @@
 		struct fuse_forget_in forget_in;
 		struct {
 			struct fuse_release_in in;
-			struct vfsmount *vfsmount;
-			struct dentry *dentry;
+			struct path path;
 		} release;
 		struct fuse_init_in init_in;
 		struct fuse_init_out init_out;
+		struct cuse_init_in cuse_init_in;
+		struct cuse_init_out cuse_init_out;
 		struct {
 			struct fuse_read_in in;
 			u64 attr_ver;
@@ -386,6 +396,9 @@
 	/** Filesystem supports NFS exporting.  Only set in INIT */
 	unsigned export_support:1;
 
+	/** Set if bdi is valid */
+	unsigned bdi_initialized:1;
+
 	/*
 	 * The following bitfields are only for optimization purposes
 	 * and hence races in setting them will not cause malfunction
@@ -515,25 +528,24 @@
  * Initialize READ or READDIR request
  */
 void fuse_read_fill(struct fuse_req *req, struct file *file,
-		    struct inode *inode, loff_t pos, size_t count, int opcode);
+		    loff_t pos, size_t count, int opcode);
 
 /**
  * Send OPEN or OPENDIR request
  */
-int fuse_open_common(struct inode *inode, struct file *file, int isdir);
+int fuse_open_common(struct inode *inode, struct file *file, bool isdir);
 
 struct fuse_file *fuse_file_alloc(struct fuse_conn *fc);
+struct fuse_file *fuse_file_get(struct fuse_file *ff);
 void fuse_file_free(struct fuse_file *ff);
-void fuse_finish_open(struct inode *inode, struct file *file,
-		      struct fuse_file *ff, struct fuse_open_out *outarg);
+void fuse_finish_open(struct inode *inode, struct file *file);
 
-/** Fill in ff->reserved_req with a RELEASE request */
-void fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, int opcode);
+void fuse_sync_release(struct fuse_file *ff, int flags);
 
 /**
  * Send RELEASE or RELEASEDIR request
  */
-int fuse_release_common(struct inode *inode, struct file *file, int isdir);
+void fuse_release_common(struct file *file, int opcode);
 
 /**
  * Send FSYNC or FSYNCDIR request
@@ -652,10 +664,12 @@
  */
 struct fuse_conn *fuse_conn_get(struct fuse_conn *fc);
 
+void fuse_conn_kill(struct fuse_conn *fc);
+
 /**
  * Initialize fuse_conn
  */
-int fuse_conn_init(struct fuse_conn *fc, struct super_block *sb);
+void fuse_conn_init(struct fuse_conn *fc);
 
 /**
  * Release reference to fuse_conn
@@ -694,4 +708,13 @@
 
 u64 fuse_get_attr_version(struct fuse_conn *fc);
 
+int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
+		 bool isdir);
+ssize_t fuse_direct_io(struct file *file, const char __user *buf,
+		       size_t count, loff_t *ppos, int write);
+long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
+		   unsigned int flags);
+unsigned fuse_file_poll(struct file *file, poll_table *wait);
+int fuse_dev_release(struct inode *inode, struct file *file);
+
 #endif /* _FS_FUSE_I_H */
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 91f7c85f..f0df55a 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -277,11 +277,14 @@
 	}
 }
 
-static void fuse_put_super(struct super_block *sb)
+static void fuse_bdi_destroy(struct fuse_conn *fc)
 {
-	struct fuse_conn *fc = get_fuse_conn_super(sb);
+	if (fc->bdi_initialized)
+		bdi_destroy(&fc->bdi);
+}
 
-	fuse_send_destroy(fc);
+void fuse_conn_kill(struct fuse_conn *fc)
+{
 	spin_lock(&fc->lock);
 	fc->connected = 0;
 	fc->blocked = 0;
@@ -295,7 +298,16 @@
 	list_del(&fc->entry);
 	fuse_ctl_remove_conn(fc);
 	mutex_unlock(&fuse_mutex);
-	bdi_destroy(&fc->bdi);
+	fuse_bdi_destroy(fc);
+}
+EXPORT_SYMBOL_GPL(fuse_conn_kill);
+
+static void fuse_put_super(struct super_block *sb)
+{
+	struct fuse_conn *fc = get_fuse_conn_super(sb);
+
+	fuse_send_destroy(fc);
+	fuse_conn_kill(fc);
 	fuse_conn_put(fc);
 }
 
@@ -466,10 +478,8 @@
 	return 0;
 }
 
-int fuse_conn_init(struct fuse_conn *fc, struct super_block *sb)
+void fuse_conn_init(struct fuse_conn *fc)
 {
-	int err;
-
 	memset(fc, 0, sizeof(*fc));
 	spin_lock_init(&fc->lock);
 	mutex_init(&fc->inst_mutex);
@@ -484,49 +494,12 @@
 	INIT_LIST_HEAD(&fc->bg_queue);
 	INIT_LIST_HEAD(&fc->entry);
 	atomic_set(&fc->num_waiting, 0);
-	fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
-	fc->bdi.unplug_io_fn = default_unplug_io_fn;
-	/* fuse does it's own writeback accounting */
-	fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB;
 	fc->khctr = 0;
 	fc->polled_files = RB_ROOT;
-	fc->dev = sb->s_dev;
-	err = bdi_init(&fc->bdi);
-	if (err)
-		goto error_mutex_destroy;
-	if (sb->s_bdev) {
-		err = bdi_register(&fc->bdi, NULL, "%u:%u-fuseblk",
-				   MAJOR(fc->dev), MINOR(fc->dev));
-	} else {
-		err = bdi_register_dev(&fc->bdi, fc->dev);
-	}
-	if (err)
-		goto error_bdi_destroy;
-	/*
-	 * For a single fuse filesystem use max 1% of dirty +
-	 * writeback threshold.
-	 *
-	 * This gives about 1M of write buffer for memory maps on a
-	 * machine with 1G and 10% dirty_ratio, which should be more
-	 * than enough.
-	 *
-	 * Privileged users can raise it by writing to
-	 *
-	 *    /sys/class/bdi/<bdi>/max_ratio
-	 */
-	bdi_set_max_ratio(&fc->bdi, 1);
 	fc->reqctr = 0;
 	fc->blocked = 1;
 	fc->attr_version = 1;
 	get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
-
-	return 0;
-
- error_bdi_destroy:
-	bdi_destroy(&fc->bdi);
- error_mutex_destroy:
-	mutex_destroy(&fc->inst_mutex);
-	return err;
 }
 EXPORT_SYMBOL_GPL(fuse_conn_init);
 
@@ -539,12 +512,14 @@
 		fc->release(fc);
 	}
 }
+EXPORT_SYMBOL_GPL(fuse_conn_put);
 
 struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
 {
 	atomic_inc(&fc->count);
 	return fc;
 }
+EXPORT_SYMBOL_GPL(fuse_conn_get);
 
 static struct inode *fuse_get_root_inode(struct super_block *sb, unsigned mode)
 {
@@ -797,6 +772,48 @@
 	kfree(fc);
 }
 
+static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb)
+{
+	int err;
+
+	fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
+	fc->bdi.unplug_io_fn = default_unplug_io_fn;
+	/* fuse does it's own writeback accounting */
+	fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB;
+
+	err = bdi_init(&fc->bdi);
+	if (err)
+		return err;
+
+	fc->bdi_initialized = 1;
+
+	if (sb->s_bdev) {
+		err =  bdi_register(&fc->bdi, NULL, "%u:%u-fuseblk",
+				    MAJOR(fc->dev), MINOR(fc->dev));
+	} else {
+		err = bdi_register_dev(&fc->bdi, fc->dev);
+	}
+
+	if (err)
+		return err;
+
+	/*
+	 * For a single fuse filesystem use max 1% of dirty +
+	 * writeback threshold.
+	 *
+	 * This gives about 1M of write buffer for memory maps on a
+	 * machine with 1G and 10% dirty_ratio, which should be more
+	 * than enough.
+	 *
+	 * Privileged users can raise it by writing to
+	 *
+	 *    /sys/class/bdi/<bdi>/max_ratio
+	 */
+	bdi_set_max_ratio(&fc->bdi, 1);
+
+	return 0;
+}
+
 static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct fuse_conn *fc;
@@ -843,11 +860,12 @@
 	if (!fc)
 		goto err_fput;
 
-	err = fuse_conn_init(fc, sb);
-	if (err) {
-		kfree(fc);
-		goto err_fput;
-	}
+	fuse_conn_init(fc);
+
+	fc->dev = sb->s_dev;
+	err = fuse_bdi_init(fc, sb);
+	if (err)
+		goto err_put_conn;
 
 	fc->release = fuse_free_conn;
 	fc->flags = d.flags;
@@ -911,7 +929,7 @@
  err_put_root:
 	dput(root_dentry);
  err_put_conn:
-	bdi_destroy(&fc->bdi);
+	fuse_bdi_destroy(fc);
 	fuse_conn_put(fc);
  err_fput:
 	fput(file);
diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile
index d53a9be..3da2f1f 100644
--- a/fs/gfs2/Makefile
+++ b/fs/gfs2/Makefile
@@ -1,3 +1,4 @@
+EXTRA_CFLAGS := -I$(src)
 obj-$(CONFIG_GFS2_FS) += gfs2.o
 gfs2-y := acl.o bmap.o dir.o eaops.o eattr.o glock.o \
 	glops.o inode.o log.o lops.o main.o meta_io.o \
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 3297635..6d47379 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -25,6 +25,7 @@
 #include "trans.h"
 #include "dir.h"
 #include "util.h"
+#include "trace_gfs2.h"
 
 /* This doesn't need to be that large as max 64 bit pointers in a 4k
  * block is 512, so __u16 is fine for that. It saves stack space to
@@ -589,6 +590,7 @@
 	clear_buffer_mapped(bh_map);
 	clear_buffer_new(bh_map);
 	clear_buffer_boundary(bh_map);
+	trace_gfs2_bmap(ip, bh_map, lblock, create, 1);
 	if (gfs2_is_dir(ip)) {
 		bsize = sdp->sd_jbsize;
 		arr = sdp->sd_jheightsize;
@@ -623,6 +625,7 @@
 	ret = 0;
 out:
 	release_metapath(&mp);
+	trace_gfs2_bmap(ip, bh_map, lblock, create, ret);
 	bmap_unlock(ip, create);
 	return ret;
 
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 2bf62bc..297421c 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -39,6 +39,8 @@
 #include "super.h"
 #include "util.h"
 #include "bmap.h"
+#define CREATE_TRACE_POINTS
+#include "trace_gfs2.h"
 
 struct gfs2_gl_hash_bucket {
         struct hlist_head hb_list;
@@ -155,7 +157,7 @@
 
 	if (aspace)
 		gfs2_aspace_put(aspace);
-
+	trace_gfs2_glock_put(gl);
 	sdp->sd_lockstruct.ls_ops->lm_put_lock(gfs2_glock_cachep, gl);
 }
 
@@ -317,14 +319,17 @@
 						return 2;
 					gh->gh_error = ret;
 					list_del_init(&gh->gh_list);
+					trace_gfs2_glock_queue(gh, 0);
 					gfs2_holder_wake(gh);
 					goto restart;
 				}
 				set_bit(HIF_HOLDER, &gh->gh_iflags);
+				trace_gfs2_promote(gh, 1);
 				gfs2_holder_wake(gh);
 				goto restart;
 			}
 			set_bit(HIF_HOLDER, &gh->gh_iflags);
+			trace_gfs2_promote(gh, 0);
 			gfs2_holder_wake(gh);
 			continue;
 		}
@@ -354,6 +359,7 @@
 		else
 			continue;
 		list_del_init(&gh->gh_list);
+		trace_gfs2_glock_queue(gh, 0);
 		gfs2_holder_wake(gh);
 	}
 }
@@ -422,6 +428,7 @@
 	int rv;
 
 	spin_lock(&gl->gl_spin);
+	trace_gfs2_glock_state_change(gl, state);
 	state_change(gl, state);
 	gh = find_first_waiter(gl);
 
@@ -851,6 +858,7 @@
 			gl->gl_demote_state != state) {
 		gl->gl_demote_state = LM_ST_UNLOCKED;
 	}
+	trace_gfs2_demote_rq(gl);
 }
 
 /**
@@ -936,6 +944,7 @@
 			goto do_cancel;
 		return;
 	}
+	trace_gfs2_glock_queue(gh, 1);
 	list_add_tail(&gh->gh_list, insert_pt);
 do_cancel:
 	gh = list_entry(gl->gl_holders.next, struct gfs2_holder, gh_list);
@@ -1032,6 +1041,7 @@
 		    !test_bit(GLF_DEMOTE, &gl->gl_flags))
 			fast_path = 1;
 	}
+	trace_gfs2_glock_queue(gh, 0);
 	spin_unlock(&gl->gl_spin);
 	if (likely(fast_path))
 		return;
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index f2e449c..13c6237 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -28,6 +28,7 @@
 #include "meta_io.h"
 #include "util.h"
 #include "dir.h"
+#include "trace_gfs2.h"
 
 #define PULL 1
 
@@ -313,6 +314,7 @@
 		gfs2_log_lock(sdp);
 	}
 	atomic_sub(blks, &sdp->sd_log_blks_free);
+	trace_gfs2_log_blocks(sdp, -blks);
 	gfs2_log_unlock(sdp);
 	mutex_unlock(&sdp->sd_log_reserve_mutex);
 
@@ -333,6 +335,7 @@
 
 	gfs2_log_lock(sdp);
 	atomic_add(blks, &sdp->sd_log_blks_free);
+	trace_gfs2_log_blocks(sdp, blks);
 	gfs2_assert_withdraw(sdp,
 			     atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks);
 	gfs2_log_unlock(sdp);
@@ -558,6 +561,7 @@
 
 	gfs2_log_lock(sdp);
 	atomic_add(dist, &sdp->sd_log_blks_free);
+	trace_gfs2_log_blocks(sdp, dist);
 	gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks);
 	gfs2_log_unlock(sdp);
 
@@ -715,6 +719,7 @@
 		up_write(&sdp->sd_log_flush_lock);
 		return;
 	}
+	trace_gfs2_log_flush(sdp, 1);
 
 	ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL);
 	INIT_LIST_HEAD(&ai->ai_ail1_list);
@@ -746,6 +751,7 @@
 	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);
 		gfs2_log_unlock(sdp);
 		log_write_header(sdp, 0, PULL);
 	}
@@ -763,7 +769,7 @@
 		ai = NULL;
 	}
 	gfs2_log_unlock(sdp);
-
+	trace_gfs2_log_flush(sdp, 0);
 	up_write(&sdp->sd_log_flush_lock);
 
 	kfree(ai);
@@ -787,6 +793,7 @@
 	gfs2_assert_withdraw(sdp, sdp->sd_log_blks_reserved + tr->tr_reserved >= reserved);
 	unused = sdp->sd_log_blks_reserved - reserved + tr->tr_reserved;
 	atomic_add(unused, &sdp->sd_log_blks_free);
+	trace_gfs2_log_blocks(sdp, unused);
 	gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <=
 			     sdp->sd_jdesc->jd_blocks);
 	sdp->sd_log_blks_reserved = reserved;
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 00315f5..9969ff0 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -27,6 +27,7 @@
 #include "rgrp.h"
 #include "trans.h"
 #include "util.h"
+#include "trace_gfs2.h"
 
 /**
  * gfs2_pin - Pin a buffer in memory
@@ -53,6 +54,7 @@
 	if (bd->bd_ail)
 		list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list);
 	get_bh(bh);
+	trace_gfs2_pin(bd, 1);
 }
 
 /**
@@ -89,6 +91,7 @@
 	bd->bd_ail = ai;
 	list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
 	clear_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
+	trace_gfs2_pin(bd, 0);
 	gfs2_log_unlock(sdp);
 	unlock_buffer(bh);
 }
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index cc34f27..7bc3c45 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -33,6 +33,7 @@
 #include "log.h"
 #include "quota.h"
 #include "dir.h"
+#include "trace_gfs2.h"
 
 #define DO 0
 #define UNDO 1
@@ -775,6 +776,7 @@
 		/* Map the extents for this journal's blocks */
 		map_journal_extents(sdp);
 	}
+	trace_gfs2_log_blocks(sdp, atomic_read(&sdp->sd_log_blks_free));
 
 	if (sdp->sd_lockstruct.ls_first) {
 		unsigned int x;
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index de32397..daa4ae3 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -29,6 +29,7 @@
 #include "util.h"
 #include "log.h"
 #include "inode.h"
+#include "trace_gfs2.h"
 
 #define BFITNOENT ((u32)~0)
 #define NO_BLOCK ((u64)~0)
@@ -1519,7 +1520,7 @@
 	spin_lock(&sdp->sd_rindex_spin);
 	rgd->rd_free_clone -= *n;
 	spin_unlock(&sdp->sd_rindex_spin);
-
+	trace_gfs2_block_alloc(ip, block, *n, GFS2_BLKST_USED);
 	*bn = block;
 	return 0;
 
@@ -1571,7 +1572,7 @@
 	spin_lock(&sdp->sd_rindex_spin);
 	rgd->rd_free_clone--;
 	spin_unlock(&sdp->sd_rindex_spin);
-
+	trace_gfs2_block_alloc(dip, block, 1, GFS2_BLKST_DINODE);
 	return block;
 }
 
@@ -1591,7 +1592,7 @@
 	rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE);
 	if (!rgd)
 		return;
-
+	trace_gfs2_block_alloc(ip, bstart, blen, GFS2_BLKST_FREE);
 	rgd->rd_free += blen;
 
 	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
@@ -1619,7 +1620,7 @@
 	rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE);
 	if (!rgd)
 		return;
-
+	trace_gfs2_block_alloc(ip, bstart, blen, GFS2_BLKST_FREE);
 	rgd->rd_free += blen;
 
 	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
@@ -1642,6 +1643,7 @@
 	rgd = rgblk_free(sdp, blkno, 1, GFS2_BLKST_UNLINKED);
 	if (!rgd)
 		return;
+	trace_gfs2_block_alloc(ip, blkno, 1, GFS2_BLKST_UNLINKED);
 	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);
 	gfs2_trans_add_rg(rgd);
@@ -1673,6 +1675,7 @@
 void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
 {
 	gfs2_free_uninit_di(rgd, ip->i_no_addr);
+	trace_gfs2_block_alloc(ip, ip->i_no_addr, 1, GFS2_BLKST_FREE);
 	gfs2_quota_change(ip, -1, ip->i_inode.i_uid, ip->i_inode.i_gid);
 	gfs2_meta_wipe(ip, ip->i_no_addr, 1);
 }
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index c8930b3..0a68013 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -719,8 +719,6 @@
 	int error;
 	struct gfs2_jdesc *jd;
 
-	lock_kernel();
-
 	/*  Unfreeze the filesystem, if we need to  */
 
 	mutex_lock(&sdp->sd_freeze_lock);
@@ -787,8 +785,6 @@
 
 	/*  At this point, we're through participating in the lockspace  */
 	gfs2_sys_fs_del(sdp);
-
-	unlock_kernel();
 }
 
 /**
diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h
new file mode 100644
index 0000000..98d6ef1
--- /dev/null
+++ b/fs/gfs2/trace_gfs2.h
@@ -0,0 +1,407 @@
+#if !defined(_TRACE_GFS2_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_GFS2_H
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM gfs2
+#define TRACE_INCLUDE_FILE trace_gfs2
+
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/dlmconstants.h>
+#include <linux/gfs2_ondisk.h>
+#include "incore.h"
+#include "glock.h"
+
+#define dlm_state_name(nn) { DLM_LOCK_##nn, #nn }
+#define glock_trace_name(x) __print_symbolic(x,		\
+			    dlm_state_name(IV),		\
+			    dlm_state_name(NL),		\
+			    dlm_state_name(CR),		\
+			    dlm_state_name(CW),		\
+			    dlm_state_name(PR),		\
+			    dlm_state_name(PW),		\
+			    dlm_state_name(EX))
+
+#define block_state_name(x) __print_symbolic(x,			\
+			    { GFS2_BLKST_FREE, "free" },	\
+			    { GFS2_BLKST_USED, "used" },	\
+			    { GFS2_BLKST_DINODE, "dinode" },	\
+			    { GFS2_BLKST_UNLINKED, "unlinked" })
+
+#define show_glock_flags(flags) __print_flags(flags, "",	\
+	{(1UL << GLF_LOCK),			"l" },		\
+	{(1UL << GLF_DEMOTE),			"D" },		\
+	{(1UL << GLF_PENDING_DEMOTE),		"d" },		\
+	{(1UL << GLF_DEMOTE_IN_PROGRESS),	"p" },		\
+	{(1UL << GLF_DIRTY),			"y" },		\
+	{(1UL << GLF_LFLUSH),			"f" },		\
+	{(1UL << GLF_INVALIDATE_IN_PROGRESS),	"i" },		\
+	{(1UL << GLF_REPLY_PENDING),		"r" },		\
+	{(1UL << GLF_INITIAL),			"I" },		\
+	{(1UL << GLF_FROZEN),			"F" })
+
+#ifndef NUMPTY
+#define NUMPTY
+static inline u8 glock_trace_state(unsigned int state)
+{
+	switch(state) {
+	case LM_ST_SHARED:
+		return DLM_LOCK_PR;
+	case LM_ST_DEFERRED:
+		return DLM_LOCK_CW;
+	case LM_ST_EXCLUSIVE:
+		return DLM_LOCK_EX;
+	}
+	return DLM_LOCK_NL;
+}
+#endif
+
+/* Section 1 - Locking
+ *
+ * Objectives:
+ * Latency: Remote demote request to state change
+ * Latency: Local lock request to state change
+ * Latency: State change to lock grant
+ * Correctness: Ordering of local lock state vs. I/O requests
+ * Correctness: Responses to remote demote requests
+ */
+
+/* General glock state change (DLM lock request completes) */
+TRACE_EVENT(gfs2_glock_state_change,
+
+	TP_PROTO(const struct gfs2_glock *gl, unsigned int new_state),
+
+	TP_ARGS(gl, new_state),
+
+	TP_STRUCT__entry(
+		__field(	dev_t,	dev			)
+		__field(	u64,	glnum			)
+		__field(	u32,	gltype			)
+		__field(	u8,	cur_state		)
+		__field(	u8,	new_state		)
+		__field(	u8,	dmt_state		)
+		__field(	u8,	tgt_state		)
+		__field(	unsigned long,	flags		)
+	),
+
+	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->cur_state	= glock_trace_state(gl->gl_state);
+		__entry->new_state	= glock_trace_state(new_state);
+		__entry->tgt_state	= glock_trace_state(gl->gl_target);
+		__entry->dmt_state	= glock_trace_state(gl->gl_demote_state);
+		__entry->flags		= gl->gl_flags;
+	),
+
+	TP_printk("%u,%u glock %d:%lld state %s to %s tgt:%s dmt:%s flags:%s",
+		  MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype,
+		 (unsigned long long)__entry->glnum,
+		  glock_trace_name(__entry->cur_state),
+		  glock_trace_name(__entry->new_state),
+		  glock_trace_name(__entry->tgt_state),
+		  glock_trace_name(__entry->dmt_state),
+		  show_glock_flags(__entry->flags))
+);
+
+/* State change -> unlocked, glock is being deallocated */
+TRACE_EVENT(gfs2_glock_put,
+
+	TP_PROTO(const struct gfs2_glock *gl),
+
+	TP_ARGS(gl),
+
+	TP_STRUCT__entry(
+		__field(        dev_t,  dev                     )
+		__field(	u64,	glnum			)
+		__field(	u32,	gltype			)
+		__field(	u8,	cur_state		)
+		__field(	unsigned long,	flags		)
+	),
+
+	TP_fast_assign(
+		__entry->dev		= gl->gl_sbd->sd_vfs->s_dev;
+		__entry->gltype		= gl->gl_name.ln_type;
+		__entry->glnum		= gl->gl_name.ln_number;
+		__entry->cur_state	= glock_trace_state(gl->gl_state);
+		__entry->flags		= gl->gl_flags;
+	),
+
+	TP_printk("%u,%u glock %d:%lld state %s => %s flags:%s",
+		  MAJOR(__entry->dev), MINOR(__entry->dev),
+                  __entry->gltype, (unsigned long long)__entry->glnum,
+                  glock_trace_name(__entry->cur_state),
+		  glock_trace_name(DLM_LOCK_IV),
+		  show_glock_flags(__entry->flags))
+
+);
+
+/* Callback (local or remote) requesting lock demotion */
+TRACE_EVENT(gfs2_demote_rq,
+
+	TP_PROTO(const struct gfs2_glock *gl),
+
+	TP_ARGS(gl),
+
+	TP_STRUCT__entry(
+		__field(        dev_t,  dev                     )
+		__field(	u64,	glnum			)
+		__field(	u32,	gltype			)
+		__field(	u8,	cur_state		)
+		__field(	u8,	dmt_state		)
+		__field(	unsigned long,	flags		)
+	),
+
+	TP_fast_assign(
+		__entry->dev		= gl->gl_sbd->sd_vfs->s_dev;
+		__entry->gltype		= gl->gl_name.ln_type;
+		__entry->glnum		= gl->gl_name.ln_number;
+		__entry->cur_state	= glock_trace_state(gl->gl_state);
+		__entry->dmt_state	= glock_trace_state(gl->gl_demote_state);
+		__entry->flags		= gl->gl_flags;
+	),
+
+	TP_printk("%u,%u glock %d:%lld demote %s to %s flags:%s",
+		  MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype,
+		  (unsigned long long)__entry->glnum,
+                  glock_trace_name(__entry->cur_state),
+                  glock_trace_name(__entry->dmt_state),
+		  show_glock_flags(__entry->flags))
+
+);
+
+/* Promotion/grant of a glock */
+TRACE_EVENT(gfs2_promote,
+
+	TP_PROTO(const struct gfs2_holder *gh, int first),
+
+	TP_ARGS(gh, first),
+
+	TP_STRUCT__entry(
+		__field(        dev_t,  dev                     )
+		__field(	u64,	glnum			)
+		__field(	u32,	gltype			)
+		__field(	int,	first			)
+		__field(	u8,	state			)
+	),
+
+	TP_fast_assign(
+		__entry->dev	= gh->gh_gl->gl_sbd->sd_vfs->s_dev;
+		__entry->glnum	= gh->gh_gl->gl_name.ln_number;
+		__entry->gltype	= gh->gh_gl->gl_name.ln_type;
+		__entry->first	= first;
+		__entry->state	= glock_trace_state(gh->gh_state);
+	),
+
+	TP_printk("%u,%u glock %u:%llu promote %s %s",
+		  MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype,
+		  (unsigned long long)__entry->glnum,
+		  __entry->first ? "first": "other",
+		  glock_trace_name(__entry->state))
+);
+
+/* Queue/dequeue a lock request */
+TRACE_EVENT(gfs2_glock_queue,
+
+	TP_PROTO(const struct gfs2_holder *gh, int queue),
+
+	TP_ARGS(gh, queue),
+
+	TP_STRUCT__entry(
+		__field(        dev_t,  dev                     )
+		__field(	u64,	glnum			)
+		__field(	u32,	gltype			)
+		__field(	int,	queue			)
+		__field(	u8,	state			)
+	),
+
+	TP_fast_assign(
+		__entry->dev	= gh->gh_gl->gl_sbd->sd_vfs->s_dev;
+		__entry->glnum	= gh->gh_gl->gl_name.ln_number;
+		__entry->gltype	= gh->gh_gl->gl_name.ln_type;
+		__entry->queue	= queue;
+		__entry->state	= glock_trace_state(gh->gh_state);
+	),
+
+	TP_printk("%u,%u glock %u:%llu %squeue %s",
+		  MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype,
+		  (unsigned long long)__entry->glnum,
+		  __entry->queue ? "" : "de",
+		  glock_trace_name(__entry->state))
+);
+
+/* Section 2 - Log/journal
+ *
+ * Objectives:
+ * Latency: Log flush time
+ * Correctness: pin/unpin vs. disk I/O ordering
+ * Performance: Log usage stats
+ */
+
+/* Pin/unpin a block in the log */
+TRACE_EVENT(gfs2_pin,
+
+	TP_PROTO(const struct gfs2_bufdata *bd, int pin),
+
+	TP_ARGS(bd, pin),
+
+	TP_STRUCT__entry(
+		__field(        dev_t,  dev                     )
+		__field(	int,	pin			)
+		__field(	u32,	len			)
+		__field(	sector_t,	block		)
+		__field(	u64,	ino			)
+	),
+
+	TP_fast_assign(
+		__entry->dev		= bd->bd_gl->gl_sbd->sd_vfs->s_dev;
+		__entry->pin		= pin;
+		__entry->len		= bd->bd_bh->b_size;
+		__entry->block		= bd->bd_bh->b_blocknr;
+		__entry->ino		= bd->bd_gl->gl_name.ln_number;
+	),
+
+	TP_printk("%u,%u log %s %llu/%lu inode %llu",
+		  MAJOR(__entry->dev), MINOR(__entry->dev),
+		  __entry->pin ? "pin" : "unpin",
+		  (unsigned long long)__entry->block,
+		  (unsigned long)__entry->len,
+		  (unsigned long long)__entry->ino)
+);
+
+/* Flushing the log */
+TRACE_EVENT(gfs2_log_flush,
+
+	TP_PROTO(const struct gfs2_sbd *sdp, int start),
+
+	TP_ARGS(sdp, start),
+
+	TP_STRUCT__entry(
+		__field(        dev_t,  dev                     )
+		__field(	int,	start			)
+		__field(	u64,	log_seq			)
+	),
+
+	TP_fast_assign(
+		__entry->dev            = sdp->sd_vfs->s_dev;
+		__entry->start		= start;
+		__entry->log_seq	= sdp->sd_log_sequence;
+	),
+
+	TP_printk("%u,%u log flush %s %llu",
+		  MAJOR(__entry->dev), MINOR(__entry->dev),
+		  __entry->start ? "start" : "end",
+		  (unsigned long long)__entry->log_seq)
+);
+
+/* Reserving/releasing blocks in the log */
+TRACE_EVENT(gfs2_log_blocks,
+
+	TP_PROTO(const struct gfs2_sbd *sdp, int blocks),
+
+	TP_ARGS(sdp, blocks),
+
+	TP_STRUCT__entry(
+		__field(        dev_t,  dev                     )
+		__field(	int,	blocks			)
+	),
+
+	TP_fast_assign(
+		__entry->dev		= sdp->sd_vfs->s_dev;
+		__entry->blocks		= blocks;
+	),
+
+	TP_printk("%u,%u log reserve %d", MAJOR(__entry->dev),
+		  MINOR(__entry->dev), __entry->blocks)
+);
+
+/* Section 3 - bmap
+ *
+ * Objectives:
+ * Latency: Bmap request time
+ * Performance: Block allocator tracing
+ * Correctness: Test of disard generation vs. blocks allocated
+ */
+
+/* Map an extent of blocks, possibly a new allocation */
+TRACE_EVENT(gfs2_bmap,
+
+	TP_PROTO(const struct gfs2_inode *ip, const struct buffer_head *bh,
+		sector_t lblock, int create, int errno),
+
+	TP_ARGS(ip, bh, lblock, create, errno),
+
+	TP_STRUCT__entry(
+		__field(        dev_t,  dev                     )
+		__field(	sector_t, lblock		)
+		__field(	sector_t, pblock		)
+		__field(	u64,	inum			)
+		__field(	unsigned long, state		)
+		__field(	u32,	len			)
+		__field(	int,	create			)
+		__field(	int,	errno			)
+	),
+
+	TP_fast_assign(
+		__entry->dev            = ip->i_gl->gl_sbd->sd_vfs->s_dev;
+		__entry->lblock		= lblock;
+		__entry->pblock		= buffer_mapped(bh) ?  bh->b_blocknr : 0;
+		__entry->inum		= ip->i_no_addr;
+		__entry->state		= bh->b_state;
+		__entry->len		= bh->b_size;
+		__entry->create		= create;
+		__entry->errno		= errno;
+	),
+
+	TP_printk("%u,%u bmap %llu map %llu/%lu to %llu flags:%08lx %s %d",
+		  MAJOR(__entry->dev), MINOR(__entry->dev),
+		  (unsigned long long)__entry->inum,
+		  (unsigned long long)__entry->lblock,
+		  (unsigned long)__entry->len,
+		  (unsigned long long)__entry->pblock,
+		  __entry->state, __entry->create ? "create " : "nocreate",
+		  __entry->errno)
+);
+
+/* Keep track of blocks as they are allocated/freed */
+TRACE_EVENT(gfs2_block_alloc,
+
+	TP_PROTO(const struct gfs2_inode *ip, u64 block, unsigned len,
+		u8 block_state),
+
+	TP_ARGS(ip, block, len, block_state),
+
+	TP_STRUCT__entry(
+		__field(        dev_t,  dev                     )
+		__field(	u64,	start			)
+		__field(	u64,	inum			)
+		__field(	u32,	len			)
+		__field(	u8,	block_state		)
+	),
+
+	TP_fast_assign(
+		__entry->dev		= ip->i_gl->gl_sbd->sd_vfs->s_dev;
+		__entry->start		= block;
+		__entry->inum		= ip->i_no_addr;
+		__entry->len		= len;
+		__entry->block_state	= block_state;
+	),
+
+	TP_printk("%u,%u bmap %llu alloc %llu/%lu %s",
+		  MAJOR(__entry->dev), MINOR(__entry->dev),
+		  (unsigned long long)__entry->inum,
+		  (unsigned long long)__entry->start,
+		  (unsigned long)__entry->len,
+		  block_state_name(__entry->block_state))
+);
+
+#endif /* _TRACE_GFS2_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#include <trace/define_trace.h>
+
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 0af3608..1a9c787 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -556,27 +556,49 @@
 
 	/* add partitions */
 	for (p = 1; p < state->limit; p++) {
-		sector_t size = state->parts[p].size;
-		sector_t from = state->parts[p].from;
+		sector_t size, from;
+try_scan:
+		size = state->parts[p].size;
 		if (!size)
 			continue;
+
+		from = state->parts[p].from;
 		if (from >= get_capacity(disk)) {
 			printk(KERN_WARNING
 			       "%s: p%d ignored, start %llu is behind the end of the disk\n",
 			       disk->disk_name, p, (unsigned long long) from);
 			continue;
 		}
+
 		if (from + size > get_capacity(disk)) {
-			/*
-			 * we can not ignore partitions of broken tables
-			 * created by for example camera firmware, but we
-			 * limit them to the end of the disk to avoid
-			 * creating invalid block devices
-			 */
+			struct block_device_operations *bdops = disk->fops;
+			unsigned long long capacity;
+
 			printk(KERN_WARNING
-			       "%s: p%d size %llu limited to end of disk\n",
+			       "%s: p%d size %llu exceeds device capacity, ",
 			       disk->disk_name, p, (unsigned long long) size);
-			size = get_capacity(disk) - from;
+
+			if (bdops->set_capacity &&
+			    (disk->flags & GENHD_FL_NATIVE_CAPACITY) == 0) {
+				printk(KERN_CONT "enabling native capacity\n");
+				capacity = bdops->set_capacity(disk, ~0ULL);
+				disk->flags |= GENHD_FL_NATIVE_CAPACITY;
+				if (capacity > get_capacity(disk)) {
+					set_capacity(disk, capacity);
+					check_disk_size_change(disk, bdev);
+					bdev->bd_invalidated = 0;
+				}
+				goto try_scan;
+			} else {
+				/*
+				 * we can not ignore partitions of broken tables
+				 * created by for example camera firmware, but
+				 * we limit them to the end of the disk to avoid
+				 * creating invalid block devices
+				 */
+				printk(KERN_CONT "limited to end of disk\n");
+				size = get_capacity(disk) - from;
+			}
 		}
 		part = add_partition(disk, p, from, size,
 				     state->parts[p].flags);
diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
index 29228f5..480f281 100644
--- a/fs/xfs/Kconfig
+++ b/fs/xfs/Kconfig
@@ -39,6 +39,7 @@
 config XFS_POSIX_ACL
 	bool "XFS POSIX ACL support"
 	depends on XFS_FS
+	select FS_POSIX_ACL
 	help
 	  POSIX Access Control Lists (ACLs) support permissions for users and
 	  groups beyond the owner/group/world scheme.
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 60f107e..7a59dae 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -40,7 +40,7 @@
 endif
 
 xfs-$(CONFIG_XFS_RT)		+= xfs_rtalloc.o
-xfs-$(CONFIG_XFS_POSIX_ACL)	+= xfs_acl.o
+xfs-$(CONFIG_XFS_POSIX_ACL)	+= $(XFS_LINUX)/xfs_acl.o
 xfs-$(CONFIG_PROC_FS)		+= $(XFS_LINUX)/xfs_stats.o
 xfs-$(CONFIG_SYSCTL)		+= $(XFS_LINUX)/xfs_sysctl.o
 xfs-$(CONFIG_COMPAT)		+= $(XFS_LINUX)/xfs_ioctl32.o
@@ -88,8 +88,7 @@
 				   xfs_utils.o \
 				   xfs_vnodeops.o \
 				   xfs_rw.o \
-				   xfs_dmops.o \
-				   xfs_qmops.o
+				   xfs_dmops.o
 
 xfs-$(CONFIG_XFS_TRACE)		+= xfs_btree_trace.o \
 				   xfs_dir2_trace.o
diff --git a/fs/xfs/linux-2.6/xfs_acl.c b/fs/xfs/linux-2.6/xfs_acl.c
new file mode 100644
index 0000000..1e9d124
--- /dev/null
+++ b/fs/xfs/linux-2.6/xfs_acl.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2008, Christoph Hellwig
+ * 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_acl.h"
+#include "xfs_attr.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_inode.h"
+#include "xfs_vnodeops.h"
+#include <linux/xattr.h>
+#include <linux/posix_acl_xattr.h>
+
+
+#define XFS_ACL_NOT_CACHED	((void *)-1)
+
+/*
+ * Locking scheme:
+ *  - all ACL updates are protected by inode->i_mutex, which is taken before
+ *    calling into this file.
+ *  - access and updates to the ip->i_acl and ip->i_default_acl pointers are
+ *    protected by inode->i_lock.
+ */
+
+STATIC struct posix_acl *
+xfs_acl_from_disk(struct xfs_acl *aclp)
+{
+	struct posix_acl_entry *acl_e;
+	struct posix_acl *acl;
+	struct xfs_acl_entry *ace;
+	int count, i;
+
+	count = be32_to_cpu(aclp->acl_cnt);
+
+	acl = posix_acl_alloc(count, GFP_KERNEL);
+	if (!acl)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < count; i++) {
+		acl_e = &acl->a_entries[i];
+		ace = &aclp->acl_entry[i];
+
+		/*
+		 * The tag is 32 bits on disk and 16 bits in core.
+		 *
+		 * Because every access to it goes through the core
+		 * format first this is not a problem.
+		 */
+		acl_e->e_tag = be32_to_cpu(ace->ae_tag);
+		acl_e->e_perm = be16_to_cpu(ace->ae_perm);
+
+		switch (acl_e->e_tag) {
+		case ACL_USER:
+		case ACL_GROUP:
+			acl_e->e_id = be32_to_cpu(ace->ae_id);
+			break;
+		case ACL_USER_OBJ:
+		case ACL_GROUP_OBJ:
+		case ACL_MASK:
+		case ACL_OTHER:
+			acl_e->e_id = ACL_UNDEFINED_ID;
+			break;
+		default:
+			goto fail;
+		}
+	}
+	return acl;
+
+fail:
+	posix_acl_release(acl);
+	return ERR_PTR(-EINVAL);
+}
+
+STATIC void
+xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl)
+{
+	const struct posix_acl_entry *acl_e;
+	struct xfs_acl_entry *ace;
+	int i;
+
+	aclp->acl_cnt = cpu_to_be32(acl->a_count);
+	for (i = 0; i < acl->a_count; i++) {
+		ace = &aclp->acl_entry[i];
+		acl_e = &acl->a_entries[i];
+
+		ace->ae_tag = cpu_to_be32(acl_e->e_tag);
+		ace->ae_id = cpu_to_be32(acl_e->e_id);
+		ace->ae_perm = cpu_to_be16(acl_e->e_perm);
+	}
+}
+
+/*
+ * Update the cached ACL pointer in the inode.
+ *
+ * Because we don't hold any locks while reading/writing the attribute
+ * from/to disk another thread could have raced and updated the cached
+ * ACL value before us. In that case we release the previous cached value
+ * and update it with our new value.
+ */
+STATIC void
+xfs_update_cached_acl(struct inode *inode, struct posix_acl **p_acl,
+		struct posix_acl *acl)
+{
+	spin_lock(&inode->i_lock);
+	if (*p_acl && *p_acl != XFS_ACL_NOT_CACHED)
+		posix_acl_release(*p_acl);
+	*p_acl = posix_acl_dup(acl);
+	spin_unlock(&inode->i_lock);
+}
+
+struct posix_acl *
+xfs_get_acl(struct inode *inode, int type)
+{
+	struct xfs_inode *ip = XFS_I(inode);
+	struct posix_acl *acl = NULL, **p_acl;
+	struct xfs_acl *xfs_acl;
+	int len = sizeof(struct xfs_acl);
+	char *ea_name;
+	int error;
+
+	switch (type) {
+	case ACL_TYPE_ACCESS:
+		ea_name = SGI_ACL_FILE;
+		p_acl = &ip->i_acl;
+		break;
+	case ACL_TYPE_DEFAULT:
+		ea_name = SGI_ACL_DEFAULT;
+		p_acl = &ip->i_default_acl;
+		break;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+
+	spin_lock(&inode->i_lock);
+	if (*p_acl != XFS_ACL_NOT_CACHED)
+		acl = posix_acl_dup(*p_acl);
+	spin_unlock(&inode->i_lock);
+
+	/*
+	 * If we have a cached ACLs value just return it, not need to
+	 * go out to the disk.
+	 */
+	if (acl)
+		return acl;
+
+	xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
+	if (!xfs_acl)
+		return ERR_PTR(-ENOMEM);
+
+	error = -xfs_attr_get(ip, ea_name, (char *)xfs_acl, &len, ATTR_ROOT);
+	if (error) {
+		/*
+		 * If the attribute doesn't exist make sure we have a negative
+		 * cache entry, for any other error assume it is transient and
+		 * leave the cache entry as XFS_ACL_NOT_CACHED.
+		 */
+		if (error == -ENOATTR) {
+			acl = NULL;
+			goto out_update_cache;
+		}
+		goto out;
+	}
+
+	acl = xfs_acl_from_disk(xfs_acl);
+	if (IS_ERR(acl))
+		goto out;
+
+ out_update_cache:
+	xfs_update_cached_acl(inode, p_acl, acl);
+ out:
+	kfree(xfs_acl);
+	return acl;
+}
+
+STATIC int
+xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+{
+	struct xfs_inode *ip = XFS_I(inode);
+	struct posix_acl **p_acl;
+	char *ea_name;
+	int error;
+
+	if (S_ISLNK(inode->i_mode))
+		return -EOPNOTSUPP;
+
+	switch (type) {
+	case ACL_TYPE_ACCESS:
+		ea_name = SGI_ACL_FILE;
+		p_acl = &ip->i_acl;
+		break;
+	case ACL_TYPE_DEFAULT:
+		if (!S_ISDIR(inode->i_mode))
+			return acl ? -EACCES : 0;
+		ea_name = SGI_ACL_DEFAULT;
+		p_acl = &ip->i_default_acl;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (acl) {
+		struct xfs_acl *xfs_acl;
+		int len;
+
+		xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
+		if (!xfs_acl)
+			return -ENOMEM;
+
+		xfs_acl_to_disk(xfs_acl, acl);
+		len = sizeof(struct xfs_acl) -
+			(sizeof(struct xfs_acl_entry) *
+			 (XFS_ACL_MAX_ENTRIES - acl->a_count));
+
+		error = -xfs_attr_set(ip, ea_name, (char *)xfs_acl,
+				len, ATTR_ROOT);
+
+		kfree(xfs_acl);
+	} else {
+		/*
+		 * A NULL ACL argument means we want to remove the ACL.
+		 */
+		error = -xfs_attr_remove(ip, ea_name, ATTR_ROOT);
+
+		/*
+		 * If the attribute didn't exist to start with that's fine.
+		 */
+		if (error == -ENOATTR)
+			error = 0;
+	}
+
+	if (!error)
+		xfs_update_cached_acl(inode, p_acl, acl);
+	return error;
+}
+
+int
+xfs_check_acl(struct inode *inode, int mask)
+{
+	struct xfs_inode *ip = XFS_I(inode);
+	struct posix_acl *acl;
+	int error = -EAGAIN;
+
+	xfs_itrace_entry(ip);
+
+	/*
+	 * If there is no attribute fork no ACL exists on this inode and
+	 * we can skip the whole exercise.
+	 */
+	if (!XFS_IFORK_Q(ip))
+		return -EAGAIN;
+
+	acl = xfs_get_acl(inode, ACL_TYPE_ACCESS);
+	if (IS_ERR(acl))
+		return PTR_ERR(acl);
+	if (acl) {
+		error = posix_acl_permission(inode, acl, mask);
+		posix_acl_release(acl);
+	}
+
+	return error;
+}
+
+static int
+xfs_set_mode(struct inode *inode, mode_t mode)
+{
+	int error = 0;
+
+	if (mode != inode->i_mode) {
+		struct iattr iattr;
+
+		iattr.ia_valid = ATTR_MODE;
+		iattr.ia_mode = mode;
+
+		error = -xfs_setattr(XFS_I(inode), &iattr, XFS_ATTR_NOACL);
+	}
+
+	return error;
+}
+
+static int
+xfs_acl_exists(struct inode *inode, char *name)
+{
+	int len = sizeof(struct xfs_acl);
+
+	return (xfs_attr_get(XFS_I(inode), name, NULL, &len,
+			    ATTR_ROOT|ATTR_KERNOVAL) == 0);
+}
+
+int
+posix_acl_access_exists(struct inode *inode)
+{
+	return xfs_acl_exists(inode, SGI_ACL_FILE);
+}
+
+int
+posix_acl_default_exists(struct inode *inode)
+{
+	if (!S_ISDIR(inode->i_mode))
+		return 0;
+	return xfs_acl_exists(inode, SGI_ACL_DEFAULT);
+}
+
+/*
+ * No need for i_mutex because the inode is not yet exposed to the VFS.
+ */
+int
+xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl)
+{
+	struct posix_acl *clone;
+	mode_t mode;
+	int error = 0, inherit = 0;
+
+	if (S_ISDIR(inode->i_mode)) {
+		error = xfs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl);
+		if (error)
+			return error;
+	}
+
+	clone = posix_acl_clone(default_acl, GFP_KERNEL);
+	if (!clone)
+		return -ENOMEM;
+
+	mode = inode->i_mode;
+	error = posix_acl_create_masq(clone, &mode);
+	if (error < 0)
+		goto out_release_clone;
+
+	/*
+	 * If posix_acl_create_masq returns a positive value we need to
+	 * inherit a permission that can't be represented using the Unix
+	 * mode bits and we actually need to set an ACL.
+	 */
+	if (error > 0)
+		inherit = 1;
+
+	error = xfs_set_mode(inode, mode);
+	if (error)
+		goto out_release_clone;
+
+	if (inherit)
+		error = xfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
+
+ out_release_clone:
+	posix_acl_release(clone);
+	return error;
+}
+
+int
+xfs_acl_chmod(struct inode *inode)
+{
+	struct posix_acl *acl, *clone;
+	int error;
+
+	if (S_ISLNK(inode->i_mode))
+		return -EOPNOTSUPP;
+
+	acl = xfs_get_acl(inode, ACL_TYPE_ACCESS);
+	if (IS_ERR(acl) || !acl)
+		return PTR_ERR(acl);
+
+	clone = posix_acl_clone(acl, GFP_KERNEL);
+	posix_acl_release(acl);
+	if (!clone)
+		return -ENOMEM;
+
+	error = posix_acl_chmod_masq(clone, inode->i_mode);
+	if (!error)
+		error = xfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
+
+	posix_acl_release(clone);
+	return error;
+}
+
+void
+xfs_inode_init_acls(struct xfs_inode *ip)
+{
+	/*
+	 * No need for locking, inode is not live yet.
+	 */
+	ip->i_acl = XFS_ACL_NOT_CACHED;
+	ip->i_default_acl = XFS_ACL_NOT_CACHED;
+}
+
+void
+xfs_inode_clear_acls(struct xfs_inode *ip)
+{
+	/*
+	 * No need for locking here, the inode is not live anymore
+	 * and just about to be freed.
+	 */
+	if (ip->i_acl != XFS_ACL_NOT_CACHED)
+		posix_acl_release(ip->i_acl);
+	if (ip->i_default_acl != XFS_ACL_NOT_CACHED)
+		posix_acl_release(ip->i_default_acl);
+}
+
+
+/*
+ * System xattr handlers.
+ *
+ * Currently Posix ACLs are the only system namespace extended attribute
+ * handlers supported by XFS, so we just implement the handlers here.
+ * If we ever support other system extended attributes this will need
+ * some refactoring.
+ */
+
+static int
+xfs_decode_acl(const char *name)
+{
+	if (strcmp(name, "posix_acl_access") == 0)
+		return ACL_TYPE_ACCESS;
+	else if (strcmp(name, "posix_acl_default") == 0)
+		return ACL_TYPE_DEFAULT;
+	return -EINVAL;
+}
+
+static int
+xfs_xattr_system_get(struct inode *inode, const char *name,
+		void *value, size_t size)
+{
+	struct posix_acl *acl;
+	int type, error;
+
+	type = xfs_decode_acl(name);
+	if (type < 0)
+		return type;
+
+	acl = xfs_get_acl(inode, type);
+	if (IS_ERR(acl))
+		return PTR_ERR(acl);
+	if (acl == NULL)
+		return -ENODATA;
+
+	error = posix_acl_to_xattr(acl, value, size);
+	posix_acl_release(acl);
+
+	return error;
+}
+
+static int
+xfs_xattr_system_set(struct inode *inode, const char *name,
+		const void *value, size_t size, int flags)
+{
+	struct posix_acl *acl = NULL;
+	int error = 0, type;
+
+	type = xfs_decode_acl(name);
+	if (type < 0)
+		return type;
+	if (flags & XATTR_CREATE)
+		return -EINVAL;
+	if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
+		return value ? -EACCES : 0;
+	if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER))
+		return -EPERM;
+
+	if (!value)
+		goto set_acl;
+
+	acl = posix_acl_from_xattr(value, size);
+	if (!acl) {
+		/*
+		 * acl_set_file(3) may request that we set default ACLs with
+		 * zero length -- defend (gracefully) against that here.
+		 */
+		goto out;
+	}
+	if (IS_ERR(acl)) {
+		error = PTR_ERR(acl);
+		goto out;
+	}
+
+	error = posix_acl_valid(acl);
+	if (error)
+		goto out_release;
+
+	error = -EINVAL;
+	if (acl->a_count > XFS_ACL_MAX_ENTRIES)
+		goto out_release;
+
+	if (type == ACL_TYPE_ACCESS) {
+		mode_t mode = inode->i_mode;
+		error = posix_acl_equiv_mode(acl, &mode);
+
+		if (error <= 0) {
+			posix_acl_release(acl);
+			acl = NULL;
+
+			if (error < 0)
+				return error;
+		}
+
+		error = xfs_set_mode(inode, mode);
+		if (error)
+			goto out_release;
+	}
+
+ set_acl:
+	error = xfs_set_acl(inode, type, acl);
+ out_release:
+	posix_acl_release(acl);
+ out:
+	return error;
+}
+
+struct xattr_handler xfs_xattr_system_handler = {
+	.prefix	= XATTR_SYSTEM_PREFIX,
+	.get	= xfs_xattr_system_get,
+	.set	= xfs_xattr_system_set,
+};
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index 34eaab6..5bb523d 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -41,7 +41,6 @@
 #include "xfs_itable.h"
 #include "xfs_error.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_bmap.h"
 #include "xfs_buf_item.h"
@@ -899,7 +898,8 @@
 	struct xfs_mount	*mp = ip->i_mount;
 	struct xfs_trans	*tp;
 	unsigned int		lock_flags = 0;
-	struct xfs_dquot	*udqp = NULL, *gdqp = NULL;
+	struct xfs_dquot	*udqp = NULL;
+	struct xfs_dquot	*gdqp = NULL;
 	struct xfs_dquot	*olddquot = NULL;
 	int			code;
 
@@ -919,7 +919,7 @@
 	 * because the i_*dquot fields will get updated anyway.
 	 */
 	if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) {
-		code = XFS_QM_DQVOPALLOC(mp, ip, ip->i_d.di_uid,
+		code = xfs_qm_vop_dqalloc(ip, ip->i_d.di_uid,
 					 ip->i_d.di_gid, fa->fsx_projid,
 					 XFS_QMOPT_PQUOTA, &udqp, &gdqp);
 		if (code)
@@ -954,10 +954,11 @@
 	 * Do a quota reservation only if projid is actually going to change.
 	 */
 	if (mask & FSX_PROJID) {
-		if (XFS_IS_PQUOTA_ON(mp) &&
+		if (XFS_IS_QUOTA_RUNNING(mp) &&
+		    XFS_IS_PQUOTA_ON(mp) &&
 		    ip->i_d.di_projid != fa->fsx_projid) {
 			ASSERT(tp);
-			code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,
+			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
 						capable(CAP_FOWNER) ?
 						XFS_QMOPT_FORCE_RES : 0);
 			if (code)	/* out of quota */
@@ -1059,8 +1060,8 @@
 		 * in the transaction.
 		 */
 		if (ip->i_d.di_projid != fa->fsx_projid) {
-			if (XFS_IS_PQUOTA_ON(mp)) {
-				olddquot = XFS_QM_DQVOPCHOWN(mp, tp, ip,
+			if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) {
+				olddquot = xfs_qm_vop_chown(tp, ip,
 							&ip->i_gdquot, gdqp);
 			}
 			ip->i_d.di_projid = fa->fsx_projid;
@@ -1106,9 +1107,9 @@
 	/*
 	 * Release any dquot(s) the inode had kept before chown.
 	 */
-	XFS_QM_DQRELE(mp, olddquot);
-	XFS_QM_DQRELE(mp, udqp);
-	XFS_QM_DQRELE(mp, gdqp);
+	xfs_qm_dqrele(olddquot);
+	xfs_qm_dqrele(udqp);
+	xfs_qm_dqrele(gdqp);
 
 	if (code)
 		return code;
@@ -1122,8 +1123,8 @@
 	return 0;
 
  error_return:
-	XFS_QM_DQRELE(mp, udqp);
-	XFS_QM_DQRELE(mp, gdqp);
+	xfs_qm_dqrele(udqp);
+	xfs_qm_dqrele(gdqp);
 	xfs_trans_cancel(tp, 0);
 	if (lock_flags)
 		xfs_iunlock(ip, lock_flags);
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index 6075382..58973bb 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -17,6 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_acl.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_inum.h"
@@ -51,6 +52,7 @@
 #include <linux/capability.h>
 #include <linux/xattr.h>
 #include <linux/namei.h>
+#include <linux/posix_acl.h>
 #include <linux/security.h>
 #include <linux/falloc.h>
 #include <linux/fiemap.h>
@@ -202,9 +204,8 @@
 {
 	struct inode	*inode;
 	struct xfs_inode *ip = NULL;
-	xfs_acl_t	*default_acl = NULL;
+	struct posix_acl *default_acl = NULL;
 	struct xfs_name	name;
-	int (*test_default_acl)(struct inode *) = _ACL_DEFAULT_EXISTS;
 	int		error;
 
 	/*
@@ -219,18 +220,14 @@
 		rdev = 0;
 	}
 
-	if (test_default_acl && test_default_acl(dir)) {
-		if (!_ACL_ALLOC(default_acl)) {
-			return -ENOMEM;
-		}
-		if (!_ACL_GET_DEFAULT(dir, default_acl)) {
-			_ACL_FREE(default_acl);
-			default_acl = NULL;
-		}
-	}
+	if (IS_POSIXACL(dir)) {
+		default_acl = xfs_get_acl(dir, ACL_TYPE_DEFAULT);
+		if (IS_ERR(default_acl))
+			return -PTR_ERR(default_acl);
 
-	if (IS_POSIXACL(dir) && !default_acl)
-		mode &= ~current_umask();
+		if (!default_acl)
+			mode &= ~current_umask();
+	}
 
 	xfs_dentry_to_name(&name, dentry);
 	error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip, NULL);
@@ -244,10 +241,10 @@
 		goto out_cleanup_inode;
 
 	if (default_acl) {
-		error = _ACL_INHERIT(inode, mode, default_acl);
+		error = -xfs_inherit_acl(inode, default_acl);
 		if (unlikely(error))
 			goto out_cleanup_inode;
-		_ACL_FREE(default_acl);
+		posix_acl_release(default_acl);
 	}
 
 
@@ -257,8 +254,7 @@
  out_cleanup_inode:
 	xfs_cleanup_inode(dir, inode, dentry);
  out_free_acl:
-	if (default_acl)
-		_ACL_FREE(default_acl);
+	posix_acl_release(default_acl);
 	return -error;
 }
 
@@ -488,26 +484,6 @@
 		kfree(s);
 }
 
-#ifdef CONFIG_XFS_POSIX_ACL
-STATIC int
-xfs_check_acl(
-	struct inode		*inode,
-	int			mask)
-{
-	struct xfs_inode	*ip = XFS_I(inode);
-	int			error;
-
-	xfs_itrace_entry(ip);
-
-	if (XFS_IFORK_Q(ip)) {
-		error = xfs_acl_iaccess(ip, mask, NULL);
-		if (error != -1)
-			return -error;
-	}
-
-	return -EAGAIN;
-}
-
 STATIC int
 xfs_vn_permission(
 	struct inode		*inode,
@@ -515,9 +491,6 @@
 {
 	return generic_permission(inode, mask, xfs_check_acl);
 }
-#else
-#define xfs_vn_permission NULL
-#endif
 
 STATIC int
 xfs_vn_getattr(
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index 9142192..7078974 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -42,7 +42,6 @@
 #include "xfs_error.h"
 #include "xfs_itable.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_inode_item.h"
 #include "xfs_buf_item.h"
diff --git a/fs/xfs/linux-2.6/xfs_quotaops.c b/fs/xfs/linux-2.6/xfs_quotaops.c
index 94d9a63..cb6e2cc 100644
--- a/fs/xfs/linux-2.6/xfs_quotaops.c
+++ b/fs/xfs/linux-2.6/xfs_quotaops.c
@@ -50,9 +50,11 @@
 {
 	struct xfs_mount	*mp = XFS_M(sb);
 
+	if (sb->s_flags & MS_RDONLY)
+		return -EROFS;
 	if (!XFS_IS_QUOTA_RUNNING(mp))
 		return -ENOSYS;
-	return -xfs_sync_inodes(mp, SYNC_DELWRI);
+	return -xfs_sync_data(mp, 0);
 }
 
 STATIC int
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 08d6bd9..2e09efb 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -43,7 +43,6 @@
 #include "xfs_itable.h"
 #include "xfs_fsops.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_utils.h"
@@ -405,6 +404,14 @@
 		return EINVAL;
 	}
 
+#ifndef CONFIG_XFS_QUOTA
+	if (XFS_IS_QUOTA_RUNNING(mp)) {
+		cmn_err(CE_WARN,
+			"XFS: quota support not available in this kernel.");
+		return EINVAL;
+	}
+#endif
+
 	if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
 	    (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE))) {
 		cmn_err(CE_WARN,
@@ -1063,7 +1070,18 @@
 	int			unmount_event_flags = 0;
 
 	xfs_syncd_stop(mp);
-	xfs_sync_inodes(mp, SYNC_ATTR|SYNC_DELWRI);
+
+	if (!(sb->s_flags & MS_RDONLY)) {
+		/*
+		 * XXX(hch): this should be SYNC_WAIT.
+		 *
+		 * Or more likely not needed at all because the VFS is already
+		 * calling ->sync_fs after shutting down all filestem
+		 * operations and just before calling ->put_super.
+		 */
+		xfs_sync_data(mp, 0);
+		xfs_sync_attr(mp, 0);
+	}
 
 #ifdef HAVE_DMAPI
 	if (mp->m_flags & XFS_MOUNT_DMAPI) {
@@ -1098,7 +1116,6 @@
 	xfs_freesb(mp);
 	xfs_icsb_destroy_counters(mp);
 	xfs_close_devices(mp);
-	xfs_qmops_put(mp);
 	xfs_dmops_put(mp);
 	xfs_free_fsname(mp);
 	kfree(mp);
@@ -1158,6 +1175,7 @@
 {
 	struct xfs_mount	*mp = XFS_M(dentry->d_sb);
 	xfs_sb_t		*sbp = &mp->m_sb;
+	struct xfs_inode	*ip = XFS_I(dentry->d_inode);
 	__uint64_t		fakeinos, id;
 	xfs_extlen_t		lsize;
 
@@ -1186,7 +1204,10 @@
 	statp->f_ffree = statp->f_files - (sbp->sb_icount - sbp->sb_ifree);
 	spin_unlock(&mp->m_sb_lock);
 
-	XFS_QM_DQSTATVFS(XFS_I(dentry->d_inode), statp);
+	if ((ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) ||
+	    ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))) ==
+			      (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))
+		xfs_qm_statvfs(ip, statp);
 	return 0;
 }
 
@@ -1394,16 +1415,13 @@
 	error = xfs_dmops_get(mp);
 	if (error)
 		goto out_free_fsname;
-	error = xfs_qmops_get(mp);
-	if (error)
-		goto out_put_dmops;
 
 	if (silent)
 		flags |= XFS_MFSI_QUIET;
 
 	error = xfs_open_devices(mp);
 	if (error)
-		goto out_put_qmops;
+		goto out_put_dmops;
 
 	if (xfs_icsb_init_counters(mp))
 		mp->m_flags |= XFS_MOUNT_NO_PERCPU_SB;
@@ -1471,8 +1489,6 @@
  out_destroy_counters:
 	xfs_icsb_destroy_counters(mp);
 	xfs_close_devices(mp);
- out_put_qmops:
-	xfs_qmops_put(mp);
  out_put_dmops:
 	xfs_dmops_put(mp);
  out_free_fsname:
@@ -1706,18 +1722,8 @@
 	if (!xfs_ili_zone)
 		goto out_destroy_inode_zone;
 
-#ifdef CONFIG_XFS_POSIX_ACL
-	xfs_acl_zone = kmem_zone_init(sizeof(xfs_acl_t), "xfs_acl");
-	if (!xfs_acl_zone)
-		goto out_destroy_ili_zone;
-#endif
-
 	return 0;
 
-#ifdef CONFIG_XFS_POSIX_ACL
- out_destroy_ili_zone:
-#endif
-	kmem_zone_destroy(xfs_ili_zone);
  out_destroy_inode_zone:
 	kmem_zone_destroy(xfs_inode_zone);
  out_destroy_efi_zone:
@@ -1751,9 +1757,6 @@
 STATIC void
 xfs_destroy_zones(void)
 {
-#ifdef CONFIG_XFS_POSIX_ACL
-	kmem_zone_destroy(xfs_acl_zone);
-#endif
 	kmem_zone_destroy(xfs_ili_zone);
 	kmem_zone_destroy(xfs_inode_zone);
 	kmem_zone_destroy(xfs_efi_zone);
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index f7ba766..b619d6b 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -43,168 +43,269 @@
 #include "xfs_buf_item.h"
 #include "xfs_inode_item.h"
 #include "xfs_rw.h"
+#include "xfs_quota.h"
 
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 
-/*
- * Sync all the inodes in the given AG according to the
- * direction given by the flags.
- */
-STATIC int
-xfs_sync_inodes_ag(
-	xfs_mount_t	*mp,
-	int		ag,
-	int		flags)
+
+STATIC xfs_inode_t *
+xfs_inode_ag_lookup(
+	struct xfs_mount	*mp,
+	struct xfs_perag	*pag,
+	uint32_t		*first_index,
+	int			tag)
 {
-	xfs_perag_t	*pag = &mp->m_perag[ag];
-	int		nr_found;
-	uint32_t	first_index = 0;
-	int		error = 0;
-	int		last_error = 0;
+	int			nr_found;
+	struct xfs_inode	*ip;
 
-	do {
-		struct inode	*inode;
-		xfs_inode_t	*ip = NULL;
-		int		lock_flags = XFS_ILOCK_SHARED;
-
-		/*
-		 * use a gang lookup to find the next inode in the tree
-		 * as the tree is sparse and a gang lookup walks to find
-		 * the number of objects requested.
-		 */
-		read_lock(&pag->pag_ici_lock);
+	/*
+	 * use a gang lookup to find the next inode in the tree
+	 * as the tree is sparse and a gang lookup walks to find
+	 * the number of objects requested.
+	 */
+	read_lock(&pag->pag_ici_lock);
+	if (tag == XFS_ICI_NO_TAG) {
 		nr_found = radix_tree_gang_lookup(&pag->pag_ici_root,
-				(void**)&ip, first_index, 1);
+				(void **)&ip, *first_index, 1);
+	} else {
+		nr_found = radix_tree_gang_lookup_tag(&pag->pag_ici_root,
+				(void **)&ip, *first_index, 1, tag);
+	}
+	if (!nr_found)
+		goto unlock;
 
-		if (!nr_found) {
-			read_unlock(&pag->pag_ici_lock);
+	/*
+	 * Update the index for the next lookup. Catch overflows
+	 * into the next AG range which can occur if we have inodes
+	 * in the last block of the AG and we are currently
+	 * pointing to the last inode.
+	 */
+	*first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
+	if (*first_index < XFS_INO_TO_AGINO(mp, ip->i_ino))
+		goto unlock;
+
+	return ip;
+
+unlock:
+	read_unlock(&pag->pag_ici_lock);
+	return NULL;
+}
+
+STATIC int
+xfs_inode_ag_walk(
+	struct xfs_mount	*mp,
+	xfs_agnumber_t		ag,
+	int			(*execute)(struct xfs_inode *ip,
+					   struct xfs_perag *pag, int flags),
+	int			flags,
+	int			tag)
+{
+	struct xfs_perag	*pag = &mp->m_perag[ag];
+	uint32_t		first_index;
+	int			last_error = 0;
+	int			skipped;
+
+restart:
+	skipped = 0;
+	first_index = 0;
+	do {
+		int		error = 0;
+		xfs_inode_t	*ip;
+
+		ip = xfs_inode_ag_lookup(mp, pag, &first_index, tag);
+		if (!ip)
 			break;
-		}
 
-		/*
-		 * Update the index for the next lookup. Catch overflows
-		 * into the next AG range which can occur if we have inodes
-		 * in the last block of the AG and we are currently
-		 * pointing to the last inode.
-		 */
-		first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
-		if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) {
-			read_unlock(&pag->pag_ici_lock);
-			break;
-		}
-
-		/* nothing to sync during shutdown */
-		if (XFS_FORCED_SHUTDOWN(mp)) {
-			read_unlock(&pag->pag_ici_lock);
-			return 0;
-		}
-
-		/*
-		 * If we can't get a reference on the inode, it must be
-		 * in reclaim. Leave it for the reclaim code to flush.
-		 */
-		inode = VFS_I(ip);
-		if (!igrab(inode)) {
-			read_unlock(&pag->pag_ici_lock);
+		error = execute(ip, pag, flags);
+		if (error == EAGAIN) {
+			skipped++;
 			continue;
 		}
-		read_unlock(&pag->pag_ici_lock);
-
-		/* avoid new or bad inodes */
-		if (is_bad_inode(inode) ||
-		    xfs_iflags_test(ip, XFS_INEW)) {
-			IRELE(ip);
-			continue;
-		}
-
-		/*
-		 * If we have to flush data or wait for I/O completion
-		 * we need to hold the iolock.
-		 */
-		if (flags & SYNC_DELWRI) {
-			if (VN_DIRTY(inode)) {
-				if (flags & SYNC_TRYLOCK) {
-					if (xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED))
-						lock_flags |= XFS_IOLOCK_SHARED;
-				} else {
-					xfs_ilock(ip, XFS_IOLOCK_SHARED);
-					lock_flags |= XFS_IOLOCK_SHARED;
-				}
-				if (lock_flags & XFS_IOLOCK_SHARED) {
-					error = xfs_flush_pages(ip, 0, -1,
-							(flags & SYNC_WAIT) ? 0
-								: XFS_B_ASYNC,
-							FI_NONE);
-				}
-			}
-			if (VN_CACHED(inode) && (flags & SYNC_IOWAIT))
-				xfs_ioend_wait(ip);
-		}
-		xfs_ilock(ip, XFS_ILOCK_SHARED);
-
-		if ((flags & SYNC_ATTR) && !xfs_inode_clean(ip)) {
-			if (flags & SYNC_WAIT) {
-				xfs_iflock(ip);
-				if (!xfs_inode_clean(ip))
-					error = xfs_iflush(ip, XFS_IFLUSH_SYNC);
-				else
-					xfs_ifunlock(ip);
-			} else if (xfs_iflock_nowait(ip)) {
-				if (!xfs_inode_clean(ip))
-					error = xfs_iflush(ip, XFS_IFLUSH_DELWRI);
-				else
-					xfs_ifunlock(ip);
-			}
-		}
-		xfs_iput(ip, lock_flags);
-
 		if (error)
 			last_error = error;
 		/*
 		 * bail out if the filesystem is corrupted.
 		 */
 		if (error == EFSCORRUPTED)
-			return XFS_ERROR(error);
+			break;
 
-	} while (nr_found);
+	} while (1);
 
+	if (skipped) {
+		delay(1);
+		goto restart;
+	}
+
+	xfs_put_perag(mp, pag);
 	return last_error;
 }
 
 int
-xfs_sync_inodes(
-	xfs_mount_t	*mp,
-	int		flags)
+xfs_inode_ag_iterator(
+	struct xfs_mount	*mp,
+	int			(*execute)(struct xfs_inode *ip,
+					   struct xfs_perag *pag, int flags),
+	int			flags,
+	int			tag)
 {
-	int		error;
-	int		last_error;
-	int		i;
-	int		lflags = XFS_LOG_FORCE;
+	int			error = 0;
+	int			last_error = 0;
+	xfs_agnumber_t		ag;
 
-	if (mp->m_flags & XFS_MOUNT_RDONLY)
-		return 0;
-	error = 0;
-	last_error = 0;
-
-	if (flags & SYNC_WAIT)
-		lflags |= XFS_LOG_SYNC;
-
-	for (i = 0; i < mp->m_sb.sb_agcount; i++) {
-		if (!mp->m_perag[i].pag_ici_init)
+	for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
+		if (!mp->m_perag[ag].pag_ici_init)
 			continue;
-		error = xfs_sync_inodes_ag(mp, i, flags);
-		if (error)
+		error = xfs_inode_ag_walk(mp, ag, execute, flags, tag);
+		if (error) {
 			last_error = error;
-		if (error == EFSCORRUPTED)
-			break;
+			if (error == EFSCORRUPTED)
+				break;
+		}
 	}
-	if (flags & SYNC_DELWRI)
-		xfs_log_force(mp, 0, lflags);
-
 	return XFS_ERROR(last_error);
 }
 
+/* must be called with pag_ici_lock held and releases it */
+int
+xfs_sync_inode_valid(
+	struct xfs_inode	*ip,
+	struct xfs_perag	*pag)
+{
+	struct inode		*inode = VFS_I(ip);
+
+	/* nothing to sync during shutdown */
+	if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
+		read_unlock(&pag->pag_ici_lock);
+		return EFSCORRUPTED;
+	}
+
+	/*
+	 * If we can't get a reference on the inode, it must be in reclaim.
+	 * Leave it for the reclaim code to flush. Also avoid inodes that
+	 * haven't been fully initialised.
+	 */
+	if (!igrab(inode)) {
+		read_unlock(&pag->pag_ici_lock);
+		return ENOENT;
+	}
+	read_unlock(&pag->pag_ici_lock);
+
+	if (is_bad_inode(inode) || xfs_iflags_test(ip, XFS_INEW)) {
+		IRELE(ip);
+		return ENOENT;
+	}
+
+	return 0;
+}
+
+STATIC int
+xfs_sync_inode_data(
+	struct xfs_inode	*ip,
+	struct xfs_perag	*pag,
+	int			flags)
+{
+	struct inode		*inode = VFS_I(ip);
+	struct address_space *mapping = inode->i_mapping;
+	int			error = 0;
+
+	error = xfs_sync_inode_valid(ip, pag);
+	if (error)
+		return error;
+
+	if (!mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
+		goto out_wait;
+
+	if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)) {
+		if (flags & SYNC_TRYLOCK)
+			goto out_wait;
+		xfs_ilock(ip, XFS_IOLOCK_SHARED);
+	}
+
+	error = xfs_flush_pages(ip, 0, -1, (flags & SYNC_WAIT) ?
+				0 : XFS_B_ASYNC, FI_NONE);
+	xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+
+ out_wait:
+	if (flags & SYNC_WAIT)
+		xfs_ioend_wait(ip);
+	IRELE(ip);
+	return error;
+}
+
+STATIC int
+xfs_sync_inode_attr(
+	struct xfs_inode	*ip,
+	struct xfs_perag	*pag,
+	int			flags)
+{
+	int			error = 0;
+
+	error = xfs_sync_inode_valid(ip, pag);
+	if (error)
+		return error;
+
+	xfs_ilock(ip, XFS_ILOCK_SHARED);
+	if (xfs_inode_clean(ip))
+		goto out_unlock;
+	if (!xfs_iflock_nowait(ip)) {
+		if (!(flags & SYNC_WAIT))
+			goto out_unlock;
+		xfs_iflock(ip);
+	}
+
+	if (xfs_inode_clean(ip)) {
+		xfs_ifunlock(ip);
+		goto out_unlock;
+	}
+
+	error = xfs_iflush(ip, (flags & SYNC_WAIT) ?
+			   XFS_IFLUSH_SYNC : XFS_IFLUSH_DELWRI);
+
+ out_unlock:
+	xfs_iunlock(ip, XFS_ILOCK_SHARED);
+	IRELE(ip);
+	return error;
+}
+
+/*
+ * Write out pagecache data for the whole filesystem.
+ */
+int
+xfs_sync_data(
+	struct xfs_mount	*mp,
+	int			flags)
+{
+	int			error;
+
+	ASSERT((flags & ~(SYNC_TRYLOCK|SYNC_WAIT)) == 0);
+
+	error = xfs_inode_ag_iterator(mp, xfs_sync_inode_data, flags,
+				      XFS_ICI_NO_TAG);
+	if (error)
+		return XFS_ERROR(error);
+
+	xfs_log_force(mp, 0,
+		      (flags & SYNC_WAIT) ?
+		       XFS_LOG_FORCE | XFS_LOG_SYNC :
+		       XFS_LOG_FORCE);
+	return 0;
+}
+
+/*
+ * Write out inode metadata (attributes) for the whole filesystem.
+ */
+int
+xfs_sync_attr(
+	struct xfs_mount	*mp,
+	int			flags)
+{
+	ASSERT((flags & ~SYNC_WAIT) == 0);
+
+	return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags,
+				     XFS_ICI_NO_TAG);
+}
+
 STATIC int
 xfs_commit_dummy_trans(
 	struct xfs_mount	*mp,
@@ -252,7 +353,7 @@
 	 * If this is xfssyncd() then only sync the superblock if we can
 	 * lock it without sleeping and it is not pinned.
 	 */
-	if (flags & SYNC_BDFLUSH) {
+	if (flags & SYNC_TRYLOCK) {
 		ASSERT(!(flags & SYNC_WAIT));
 
 		bp = xfs_getsb(mp, XFS_BUF_TRYLOCK);
@@ -316,13 +417,13 @@
 	int error;
 
 	/* push non-blocking */
-	xfs_sync_inodes(mp, SYNC_DELWRI|SYNC_BDFLUSH);
-	XFS_QM_DQSYNC(mp, SYNC_BDFLUSH);
+	xfs_sync_data(mp, 0);
+	xfs_qm_sync(mp, SYNC_TRYLOCK);
 	xfs_filestream_flush(mp);
 
 	/* push and block */
-	xfs_sync_inodes(mp, SYNC_DELWRI|SYNC_WAIT|SYNC_IOWAIT);
-	XFS_QM_DQSYNC(mp, SYNC_WAIT);
+	xfs_sync_data(mp, SYNC_WAIT);
+	xfs_qm_sync(mp, SYNC_WAIT);
 
 	/* write superblock and hoover up shutdown errors */
 	error = xfs_sync_fsdata(mp, 0);
@@ -341,7 +442,7 @@
 	int	count = 0, pincount;
 
 	xfs_flush_buftarg(mp->m_ddev_targp, 0);
-	xfs_reclaim_inodes(mp, 0, XFS_IFLUSH_DELWRI_ELSE_ASYNC);
+	xfs_reclaim_inodes(mp, XFS_IFLUSH_DELWRI_ELSE_ASYNC);
 
 	/*
 	 * This loop must run at least twice.  The first instance of the loop
@@ -350,7 +451,7 @@
 	 * logged before we can write the unmount record.
 	 */
 	do {
-		xfs_sync_inodes(mp, SYNC_ATTR|SYNC_WAIT);
+		xfs_sync_attr(mp, SYNC_WAIT);
 		pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);
 		if (!pincount) {
 			delay(50);
@@ -433,8 +534,8 @@
 	void		*arg)
 {
 	struct inode	*inode = arg;
-	xfs_sync_inodes(mp, SYNC_DELWRI | SYNC_TRYLOCK);
-	xfs_sync_inodes(mp, SYNC_DELWRI | SYNC_TRYLOCK | SYNC_IOWAIT);
+	xfs_sync_data(mp, SYNC_TRYLOCK);
+	xfs_sync_data(mp, SYNC_TRYLOCK | SYNC_WAIT);
 	iput(inode);
 }
 
@@ -465,10 +566,10 @@
 
 	if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
 		xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE);
-		xfs_reclaim_inodes(mp, 0, XFS_IFLUSH_DELWRI_ELSE_ASYNC);
+		xfs_reclaim_inodes(mp, XFS_IFLUSH_DELWRI_ELSE_ASYNC);
 		/* dgc: errors ignored here */
-		error = XFS_QM_DQSYNC(mp, SYNC_BDFLUSH);
-		error = xfs_sync_fsdata(mp, SYNC_BDFLUSH);
+		error = xfs_qm_sync(mp, SYNC_TRYLOCK);
+		error = xfs_sync_fsdata(mp, SYNC_TRYLOCK);
 		if (xfs_log_need_covered(mp))
 			error = xfs_commit_dummy_trans(mp, XFS_LOG_FORCE);
 	}
@@ -569,7 +670,7 @@
 			xfs_ifunlock(ip);
 			xfs_iunlock(ip, XFS_ILOCK_EXCL);
 		}
-		return 1;
+		return -EAGAIN;
 	}
 	__xfs_iflags_set(ip, XFS_IRECLAIM);
 	spin_unlock(&ip->i_flags_lock);
@@ -654,101 +755,27 @@
 	xfs_put_perag(mp, pag);
 }
 
-
-STATIC void
-xfs_reclaim_inodes_ag(
-	xfs_mount_t	*mp,
-	int		ag,
-	int		noblock,
-	int		mode)
+STATIC int
+xfs_reclaim_inode_now(
+	struct xfs_inode	*ip,
+	struct xfs_perag	*pag,
+	int			flags)
 {
-	xfs_inode_t	*ip = NULL;
-	xfs_perag_t	*pag = &mp->m_perag[ag];
-	int		nr_found;
-	uint32_t	first_index;
-	int		skipped;
-
-restart:
-	first_index = 0;
-	skipped = 0;
-	do {
-		/*
-		 * use a gang lookup to find the next inode in the tree
-		 * as the tree is sparse and a gang lookup walks to find
-		 * the number of objects requested.
-		 */
-		read_lock(&pag->pag_ici_lock);
-		nr_found = radix_tree_gang_lookup_tag(&pag->pag_ici_root,
-					(void**)&ip, first_index, 1,
-					XFS_ICI_RECLAIM_TAG);
-
-		if (!nr_found) {
-			read_unlock(&pag->pag_ici_lock);
-			break;
-		}
-
-		/*
-		 * Update the index for the next lookup. Catch overflows
-		 * into the next AG range which can occur if we have inodes
-		 * in the last block of the AG and we are currently
-		 * pointing to the last inode.
-		 */
-		first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
-		if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) {
-			read_unlock(&pag->pag_ici_lock);
-			break;
-		}
-
-		/* ignore if already under reclaim */
-		if (xfs_iflags_test(ip, XFS_IRECLAIM)) {
-			read_unlock(&pag->pag_ici_lock);
-			continue;
-		}
-
-		if (noblock) {
-			if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
-				read_unlock(&pag->pag_ici_lock);
-				continue;
-			}
-			if (xfs_ipincount(ip) ||
-			    !xfs_iflock_nowait(ip)) {
-				xfs_iunlock(ip, XFS_ILOCK_EXCL);
-				read_unlock(&pag->pag_ici_lock);
-				continue;
-			}
-		}
+	/* ignore if already under reclaim */
+	if (xfs_iflags_test(ip, XFS_IRECLAIM)) {
 		read_unlock(&pag->pag_ici_lock);
-
-		/*
-		 * hmmm - this is an inode already in reclaim. Do
-		 * we even bother catching it here?
-		 */
-		if (xfs_reclaim_inode(ip, noblock, mode))
-			skipped++;
-	} while (nr_found);
-
-	if (skipped) {
-		delay(1);
-		goto restart;
+		return 0;
 	}
-	return;
+	read_unlock(&pag->pag_ici_lock);
 
+	return xfs_reclaim_inode(ip, 0, flags);
 }
 
 int
 xfs_reclaim_inodes(
 	xfs_mount_t	*mp,
-	int		 noblock,
 	int		mode)
 {
-	int		i;
-
-	for (i = 0; i < mp->m_sb.sb_agcount; i++) {
-		if (!mp->m_perag[i].pag_ici_init)
-			continue;
-		xfs_reclaim_inodes_ag(mp, i, noblock, mode);
-	}
-	return 0;
+	return xfs_inode_ag_iterator(mp, xfs_reclaim_inode_now, mode,
+					XFS_ICI_RECLAIM_TAG);
 }
-
-
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h
index 308d5bf..2a10301 100644
--- a/fs/xfs/linux-2.6/xfs_sync.h
+++ b/fs/xfs/linux-2.6/xfs_sync.h
@@ -29,17 +29,14 @@
 	struct completion	*w_completion;
 } xfs_sync_work_t;
 
-#define SYNC_ATTR		0x0001	/* sync attributes */
-#define SYNC_DELWRI		0x0002	/* look at delayed writes */
-#define SYNC_WAIT		0x0004	/* wait for i/o to complete */
-#define SYNC_BDFLUSH		0x0008	/* BDFLUSH is calling -- don't block */
-#define SYNC_IOWAIT		0x0010  /* wait for all I/O to complete */
-#define SYNC_TRYLOCK		0x0020  /* only try to lock inodes */
+#define SYNC_WAIT		0x0001	/* wait for i/o to complete */
+#define SYNC_TRYLOCK		0x0002  /* only try to lock inodes */
 
 int xfs_syncd_init(struct xfs_mount *mp);
 void xfs_syncd_stop(struct xfs_mount *mp);
 
-int xfs_sync_inodes(struct xfs_mount *mp, int flags);
+int xfs_sync_attr(struct xfs_mount *mp, int flags);
+int xfs_sync_data(struct xfs_mount *mp, int flags);
 int xfs_sync_fsdata(struct xfs_mount *mp, int flags);
 
 int xfs_quiesce_data(struct xfs_mount *mp);
@@ -48,10 +45,16 @@
 void xfs_flush_inodes(struct xfs_inode *ip);
 
 int xfs_reclaim_inode(struct xfs_inode *ip, int locked, int sync_mode);
-int xfs_reclaim_inodes(struct xfs_mount *mp, int noblock, int mode);
+int xfs_reclaim_inodes(struct xfs_mount *mp, int mode);
 
 void xfs_inode_set_reclaim_tag(struct xfs_inode *ip);
 void xfs_inode_clear_reclaim_tag(struct xfs_inode *ip);
 void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag,
 				struct xfs_inode *ip);
+
+int xfs_sync_inode_valid(struct xfs_inode *ip, struct xfs_perag *pag);
+int xfs_inode_ag_iterator(struct xfs_mount *mp,
+	int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags),
+	int flags, int tag);
+
 #endif
diff --git a/fs/xfs/linux-2.6/xfs_xattr.c b/fs/xfs/linux-2.6/xfs_xattr.c
index 964621f..497c7fb 100644
--- a/fs/xfs/linux-2.6/xfs_xattr.c
+++ b/fs/xfs/linux-2.6/xfs_xattr.c
@@ -29,67 +29,6 @@
 #include <linux/xattr.h>
 
 
-/*
- * ACL handling.  Should eventually be moved into xfs_acl.c
- */
-
-static int
-xfs_decode_acl(const char *name)
-{
-	if (strcmp(name, "posix_acl_access") == 0)
-		return _ACL_TYPE_ACCESS;
-	else if (strcmp(name, "posix_acl_default") == 0)
-		return _ACL_TYPE_DEFAULT;
-	return -EINVAL;
-}
-
-/*
- * Get system extended attributes which at the moment only
- * includes Posix ACLs.
- */
-static int
-xfs_xattr_system_get(struct inode *inode, const char *name,
-		void *buffer, size_t size)
-{
-	int acl;
-
-	acl = xfs_decode_acl(name);
-	if (acl < 0)
-		return acl;
-
-	return xfs_acl_vget(inode, buffer, size, acl);
-}
-
-static int
-xfs_xattr_system_set(struct inode *inode, const char *name,
-		const void *value, size_t size, int flags)
-{
-	int acl;
-
-	acl = xfs_decode_acl(name);
-	if (acl < 0)
-		return acl;
-	if (flags & XATTR_CREATE)
-		return -EINVAL;
-
-	if (!value)
-		return xfs_acl_vremove(inode, acl);
-
-	return xfs_acl_vset(inode, (void *)value, size, acl);
-}
-
-static struct xattr_handler xfs_xattr_system_handler = {
-	.prefix	= XATTR_SYSTEM_PREFIX,
-	.get	= xfs_xattr_system_get,
-	.set	= xfs_xattr_system_set,
-};
-
-
-/*
- * Real xattr handling.  The only difference between the namespaces is
- * a flag passed to the low-level attr code.
- */
-
 static int
 __xfs_xattr_get(struct inode *inode, const char *name,
 		void *value, size_t size, int xflags)
@@ -199,7 +138,9 @@
 	&xfs_xattr_user_handler,
 	&xfs_xattr_trusted_handler,
 	&xfs_xattr_security_handler,
+#ifdef CONFIG_XFS_POSIX_ACL
 	&xfs_xattr_system_handler,
+#endif
 	NULL
 };
 
@@ -310,7 +251,7 @@
 	/*
 	 * Then add the two synthetic ACL attributes.
 	 */
-	if (xfs_acl_vhasacl_access(inode)) {
+	if (posix_acl_access_exists(inode)) {
 		error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
 				strlen(POSIX_ACL_XATTR_ACCESS) + 1,
 				data, size, &context.count);
@@ -318,7 +259,7 @@
 			return error;
 	}
 
-	if (xfs_acl_vhasacl_default(inode)) {
+	if (posix_acl_default_exists(inode)) {
 		error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
 				strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
 				data, size, &context.count);
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c
index e4babcc..2f3f2229 100644
--- a/fs/xfs/quota/xfs_dquot.c
+++ b/fs/xfs/quota/xfs_dquot.c
@@ -42,7 +42,6 @@
 #include "xfs_error.h"
 #include "xfs_itable.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_space.h"
@@ -1194,7 +1193,9 @@
 xfs_qm_dqrele(
 	xfs_dquot_t	*dqp)
 {
-	ASSERT(dqp);
+	if (!dqp)
+		return;
+
 	xfs_dqtrace_entry(dqp, "DQRELE");
 
 	xfs_dqlock(dqp);
diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/quota/xfs_dquot.h
index de0f402..6533ead 100644
--- a/fs/xfs/quota/xfs_dquot.h
+++ b/fs/xfs/quota/xfs_dquot.h
@@ -181,7 +181,6 @@
 extern int		xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *,
 					xfs_dqid_t, uint, uint, xfs_dquot_t **);
 extern void		xfs_qm_dqput(xfs_dquot_t *);
-extern void		xfs_qm_dqrele(xfs_dquot_t *);
 extern void		xfs_dqlock(xfs_dquot_t *);
 extern void		xfs_dqlock2(xfs_dquot_t *, xfs_dquot_t *);
 extern void		xfs_dqunlock(xfs_dquot_t *);
diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c
index 1728f6a..d0d4a9a 100644
--- a/fs/xfs/quota/xfs_dquot_item.c
+++ b/fs/xfs/quota/xfs_dquot_item.c
@@ -42,7 +42,6 @@
 #include "xfs_error.h"
 #include "xfs_itable.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_priv.h"
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 5b66950..45b1bfe 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -42,7 +42,6 @@
 #include "xfs_error.h"
 #include "xfs_bmap.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_space.h"
@@ -287,11 +286,13 @@
  * Just destroy the quotainfo structure.
  */
 void
-xfs_qm_unmount_quotadestroy(
-	xfs_mount_t	*mp)
+xfs_qm_unmount(
+	struct xfs_mount	*mp)
 {
-	if (mp->m_quotainfo)
+	if (mp->m_quotainfo) {
+		xfs_qm_dqpurge_all(mp, XFS_QMOPT_QUOTALL | XFS_QMOPT_UMOUNTING);
 		xfs_qm_destroy_quotainfo(mp);
+	}
 }
 
 
@@ -385,8 +386,13 @@
 	if (error) {
 		xfs_fs_cmn_err(CE_WARN, mp,
 			"Failed to initialize disk quotas.");
+		return;
 	}
-	return;
+
+#ifdef QUOTADEBUG
+	if (XFS_IS_QUOTA_ON(mp))
+		xfs_qm_internalqcheck(mp);
+#endif
 }
 
 /*
@@ -774,12 +780,11 @@
  * Given a locked inode, attach dquot(s) to it, taking U/G/P-QUOTAON
  * into account.
  * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed.
- * If XFS_QMOPT_ILOCKED, then inode sent is already locked EXCL.
  * Inode may get unlocked and relocked in here, and the caller must deal with
  * the consequences.
  */
 int
-xfs_qm_dqattach(
+xfs_qm_dqattach_locked(
 	xfs_inode_t	*ip,
 	uint		flags)
 {
@@ -787,17 +792,14 @@
 	uint		nquotas = 0;
 	int		error = 0;
 
-	if ((! XFS_IS_QUOTA_ON(mp)) ||
-	    (! XFS_NOT_DQATTACHED(mp, ip)) ||
-	    (ip->i_ino == mp->m_sb.sb_uquotino) ||
-	    (ip->i_ino == mp->m_sb.sb_gquotino))
+	if (!XFS_IS_QUOTA_RUNNING(mp) ||
+	    !XFS_IS_QUOTA_ON(mp) ||
+	    !XFS_NOT_DQATTACHED(mp, ip) ||
+	    ip->i_ino == mp->m_sb.sb_uquotino ||
+	    ip->i_ino == mp->m_sb.sb_gquotino)
 		return 0;
 
-	ASSERT((flags & XFS_QMOPT_ILOCKED) == 0 ||
-	       xfs_isilocked(ip, XFS_ILOCK_EXCL));
-
-	if (! (flags & XFS_QMOPT_ILOCKED))
-		xfs_ilock(ip, XFS_ILOCK_EXCL);
+	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 
 	if (XFS_IS_UQUOTA_ON(mp)) {
 		error = xfs_qm_dqattach_one(ip, ip->i_d.di_uid, XFS_DQ_USER,
@@ -849,8 +851,7 @@
 		xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot);
 	}
 
-      done:
-
+ done:
 #ifdef QUOTADEBUG
 	if (! error) {
 		if (XFS_IS_UQUOTA_ON(mp))
@@ -858,15 +859,22 @@
 		if (XFS_IS_OQUOTA_ON(mp))
 			ASSERT(ip->i_gdquot);
 	}
+	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 #endif
+	return error;
+}
 
-	if (! (flags & XFS_QMOPT_ILOCKED))
-		xfs_iunlock(ip, XFS_ILOCK_EXCL);
+int
+xfs_qm_dqattach(
+	struct xfs_inode	*ip,
+	uint			flags)
+{
+	int			error;
 
-#ifdef QUOTADEBUG
-	else
-		ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-#endif
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
+	error = xfs_qm_dqattach_locked(ip, flags);
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
+
 	return error;
 }
 
@@ -896,11 +904,6 @@
 	}
 }
 
-/*
- * This is called to sync quotas. We can be told to use non-blocking
- * semantics by either the SYNC_BDFLUSH flag or the absence of the
- * SYNC_WAIT flag.
- */
 int
 xfs_qm_sync(
 	xfs_mount_t	*mp,
@@ -909,17 +912,13 @@
 	int		recl, restarts;
 	xfs_dquot_t	*dqp;
 	uint		flush_flags;
-	boolean_t	nowait;
 	int		error;
 
-	if (! XFS_IS_QUOTA_ON(mp))
+	if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
 		return 0;
 
+	flush_flags = (flags & SYNC_WAIT) ? XFS_QMOPT_SYNC : XFS_QMOPT_DELWRI;
 	restarts = 0;
-	/*
-	 * We won't block unless we are asked to.
-	 */
-	nowait = (boolean_t)(flags & SYNC_BDFLUSH || (flags & SYNC_WAIT) == 0);
 
   again:
 	xfs_qm_mplist_lock(mp);
@@ -939,18 +938,10 @@
 		 * don't 'seem' to be dirty. ie. don't acquire dqlock.
 		 * This is very similar to what xfs_sync does with inodes.
 		 */
-		if (flags & SYNC_BDFLUSH) {
-			if (! XFS_DQ_IS_DIRTY(dqp))
+		if (flags & SYNC_TRYLOCK) {
+			if (!XFS_DQ_IS_DIRTY(dqp))
 				continue;
-		}
-
-		if (nowait) {
-			/*
-			 * Try to acquire the dquot lock. We are NOT out of
-			 * lock order, but we just don't want to wait for this
-			 * lock, unless somebody wanted us to.
-			 */
-			if (! xfs_qm_dqlock_nowait(dqp))
+			if (!xfs_qm_dqlock_nowait(dqp))
 				continue;
 		} else {
 			xfs_dqlock(dqp);
@@ -967,7 +958,7 @@
 		/* XXX a sentinel would be better */
 		recl = XFS_QI_MPLRECLAIMS(mp);
 		if (!xfs_dqflock_nowait(dqp)) {
-			if (nowait) {
+			if (flags & SYNC_TRYLOCK) {
 				xfs_dqunlock(dqp);
 				continue;
 			}
@@ -985,7 +976,6 @@
 		 * Let go of the mplist lock. We don't want to hold it
 		 * across a disk write
 		 */
-		flush_flags = (nowait) ? XFS_QMOPT_DELWRI : XFS_QMOPT_SYNC;
 		xfs_qm_mplist_unlock(mp);
 		xfs_dqtrace_entry(dqp, "XQM_SYNC: DQFLUSH");
 		error = xfs_qm_dqflush(dqp, flush_flags);
@@ -2319,20 +2309,20 @@
  */
 int
 xfs_qm_vop_dqalloc(
-	xfs_mount_t	*mp,
-	xfs_inode_t	*ip,
-	uid_t		uid,
-	gid_t		gid,
-	prid_t		prid,
-	uint		flags,
-	xfs_dquot_t	**O_udqpp,
-	xfs_dquot_t	**O_gdqpp)
+	struct xfs_inode	*ip,
+	uid_t			uid,
+	gid_t			gid,
+	prid_t			prid,
+	uint			flags,
+	struct xfs_dquot	**O_udqpp,
+	struct xfs_dquot	**O_gdqpp)
 {
-	int		error;
-	xfs_dquot_t	*uq, *gq;
-	uint		lockflags;
+	struct xfs_mount	*mp = ip->i_mount;
+	struct xfs_dquot	*uq, *gq;
+	int			error;
+	uint			lockflags;
 
-	if (!XFS_IS_QUOTA_ON(mp))
+	if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
 		return 0;
 
 	lockflags = XFS_ILOCK_EXCL;
@@ -2346,8 +2336,8 @@
 	 * if necessary. The dquot(s) will not be locked.
 	 */
 	if (XFS_NOT_DQATTACHED(mp, ip)) {
-		if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_DQALLOC |
-					    XFS_QMOPT_ILOCKED))) {
+		error = xfs_qm_dqattach_locked(ip, XFS_QMOPT_DQALLOC);
+		if (error) {
 			xfs_iunlock(ip, lockflags);
 			return error;
 		}
@@ -2469,6 +2459,7 @@
 	uint		bfield = XFS_IS_REALTIME_INODE(ip) ?
 				 XFS_TRANS_DQ_RTBCOUNT : XFS_TRANS_DQ_BCOUNT;
 
+
 	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 	ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
 
@@ -2508,13 +2499,13 @@
 	xfs_dquot_t	*gdqp,
 	uint		flags)
 {
-	int		error;
-	xfs_mount_t	*mp;
+	xfs_mount_t	*mp = ip->i_mount;
 	uint		delblks, blkflags, prjflags = 0;
 	xfs_dquot_t	*unresudq, *unresgdq, *delblksudq, *delblksgdq;
+	int		error;
+
 
 	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
-	mp = ip->i_mount;
 	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 
 	delblks = ip->i_delayed_blks;
@@ -2582,28 +2573,23 @@
 
 int
 xfs_qm_vop_rename_dqattach(
-	xfs_inode_t	**i_tab)
+	struct xfs_inode	**i_tab)
 {
-	xfs_inode_t	*ip;
-	int		i;
-	int		error;
+	struct xfs_mount	*mp = i_tab[0]->i_mount;
+	int			i;
 
-	ip = i_tab[0];
-
-	if (! XFS_IS_QUOTA_ON(ip->i_mount))
+	if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
 		return 0;
 
-	if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
-		error = xfs_qm_dqattach(ip, 0);
-		if (error)
-			return error;
-	}
-	for (i = 1; (i < 4 && i_tab[i]); i++) {
+	for (i = 0; (i < 4 && i_tab[i]); i++) {
+		struct xfs_inode	*ip = i_tab[i];
+		int			error;
+
 		/*
 		 * Watch out for duplicate entries in the table.
 		 */
-		if ((ip = i_tab[i]) != i_tab[i-1]) {
-			if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
+		if (i == 0 || ip != i_tab[i-1]) {
+			if (XFS_NOT_DQATTACHED(mp, ip)) {
 				error = xfs_qm_dqattach(ip, 0);
 				if (error)
 					return error;
@@ -2614,17 +2600,19 @@
 }
 
 void
-xfs_qm_vop_dqattach_and_dqmod_newinode(
-	xfs_trans_t	*tp,
-	xfs_inode_t	*ip,
-	xfs_dquot_t	*udqp,
-	xfs_dquot_t	*gdqp)
+xfs_qm_vop_create_dqattach(
+	struct xfs_trans	*tp,
+	struct xfs_inode	*ip,
+	struct xfs_dquot	*udqp,
+	struct xfs_dquot	*gdqp)
 {
-	if (!XFS_IS_QUOTA_ON(tp->t_mountp))
+	struct xfs_mount	*mp = tp->t_mountp;
+
+	if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
 		return;
 
 	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-	ASSERT(XFS_IS_QUOTA_RUNNING(tp->t_mountp));
+	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 
 	if (udqp) {
 		xfs_dqlock(udqp);
@@ -2632,7 +2620,7 @@
 		xfs_dqunlock(udqp);
 		ASSERT(ip->i_udquot == NULL);
 		ip->i_udquot = udqp;
-		ASSERT(XFS_IS_UQUOTA_ON(tp->t_mountp));
+		ASSERT(XFS_IS_UQUOTA_ON(mp));
 		ASSERT(ip->i_d.di_uid == be32_to_cpu(udqp->q_core.d_id));
 		xfs_trans_mod_dquot(tp, udqp, XFS_TRANS_DQ_ICOUNT, 1);
 	}
@@ -2642,8 +2630,8 @@
 		xfs_dqunlock(gdqp);
 		ASSERT(ip->i_gdquot == NULL);
 		ip->i_gdquot = gdqp;
-		ASSERT(XFS_IS_OQUOTA_ON(tp->t_mountp));
-		ASSERT((XFS_IS_GQUOTA_ON(tp->t_mountp) ?
+		ASSERT(XFS_IS_OQUOTA_ON(mp));
+		ASSERT((XFS_IS_GQUOTA_ON(mp) ?
 			ip->i_d.di_gid : ip->i_d.di_projid) ==
 				be32_to_cpu(gdqp->q_core.d_id));
 		xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h
index a371954..495564b 100644
--- a/fs/xfs/quota/xfs_qm.h
+++ b/fs/xfs/quota/xfs_qm.h
@@ -127,8 +127,6 @@
 } xfs_quotainfo_t;
 
 
-extern xfs_dqtrxops_t	xfs_trans_dquot_ops;
-
 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 *,
 			xfs_dquot_t *, xfs_dquot_t *, long, long, uint);
@@ -159,17 +157,11 @@
 #define XFS_QM_RTBWARNLIMIT	5
 
 extern void		xfs_qm_destroy_quotainfo(xfs_mount_t *);
-extern void		xfs_qm_mount_quotas(xfs_mount_t *);
 extern int		xfs_qm_quotacheck(xfs_mount_t *);
-extern void		xfs_qm_unmount_quotadestroy(xfs_mount_t *);
-extern void		xfs_qm_unmount_quotas(xfs_mount_t *);
 extern int		xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
-extern int		xfs_qm_sync(xfs_mount_t *, int);
 
 /* dquot stuff */
 extern boolean_t	xfs_qm_dqalloc_incore(xfs_dquot_t **);
-extern int		xfs_qm_dqattach(xfs_inode_t *, uint);
-extern void		xfs_qm_dqdetach(xfs_inode_t *);
 extern int		xfs_qm_dqpurge_all(xfs_mount_t *, uint);
 extern void		xfs_qm_dqrele_all_inodes(xfs_mount_t *, uint);
 
@@ -183,19 +175,6 @@
 extern int		xfs_qm_scall_quotaon(xfs_mount_t *, uint);
 extern int		xfs_qm_scall_quotaoff(xfs_mount_t *, uint);
 
-/* vop stuff */
-extern int		xfs_qm_vop_dqalloc(xfs_mount_t *, xfs_inode_t *,
-					uid_t, gid_t, prid_t, uint,
-					xfs_dquot_t **, xfs_dquot_t **);
-extern void		xfs_qm_vop_dqattach_and_dqmod_newinode(
-					xfs_trans_t *, xfs_inode_t *,
-					xfs_dquot_t *, xfs_dquot_t *);
-extern int		xfs_qm_vop_rename_dqattach(xfs_inode_t **);
-extern xfs_dquot_t *	xfs_qm_vop_chown(xfs_trans_t *, xfs_inode_t *,
-					xfs_dquot_t **, xfs_dquot_t *);
-extern int		xfs_qm_vop_chown_reserve(xfs_trans_t *, xfs_inode_t *,
-					xfs_dquot_t *, xfs_dquot_t *, uint);
-
 /* list stuff */
 extern void		xfs_qm_freelist_append(xfs_frlist_t *, xfs_dquot_t *);
 extern void		xfs_qm_freelist_unlink(xfs_dquot_t *);
diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c
index 63037c6..a534663 100644
--- a/fs/xfs/quota/xfs_qm_bhv.c
+++ b/fs/xfs/quota/xfs_qm_bhv.c
@@ -42,7 +42,6 @@
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_qm.h"
@@ -84,7 +83,7 @@
  * return a statvfs of the project, not the entire filesystem.
  * This makes such trees appear as if they are filesystems in themselves.
  */
-STATIC void
+void
 xfs_qm_statvfs(
 	xfs_inode_t		*ip,
 	struct kstatfs		*statp)
@@ -92,20 +91,13 @@
 	xfs_mount_t		*mp = ip->i_mount;
 	xfs_dquot_t		*dqp;
 
-	if (!(ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) ||
-	    !((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))) ==
-	    		      (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))
-		return;
-
 	if (!xfs_qm_dqget(mp, NULL, ip->i_d.di_projid, XFS_DQ_PROJ, 0, &dqp)) {
-		xfs_disk_dquot_t	*dp = &dqp->q_core;
-
-		xfs_fill_statvfs_from_dquot(statp, dp);
+		xfs_fill_statvfs_from_dquot(statp, &dqp->q_core);
 		xfs_qm_dqput(dqp);
 	}
 }
 
-STATIC int
+int
 xfs_qm_newmount(
 	xfs_mount_t	*mp,
 	uint		*needquotamount,
@@ -114,9 +106,6 @@
 	uint		quotaondisk;
 	uint		uquotaondisk = 0, gquotaondisk = 0, pquotaondisk = 0;
 
-	*quotaflags = 0;
-	*needquotamount = B_FALSE;
-
 	quotaondisk = xfs_sb_version_hasquota(&mp->m_sb) &&
 				(mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT);
 
@@ -179,66 +168,6 @@
 	return 0;
 }
 
-STATIC int
-xfs_qm_endmount(
-	xfs_mount_t	*mp,
-	uint		needquotamount,
-	uint		quotaflags)
-{
-	if (needquotamount) {
-		ASSERT(mp->m_qflags == 0);
-		mp->m_qflags = quotaflags;
-		xfs_qm_mount_quotas(mp);
-	}
-
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
-	if (! (XFS_IS_QUOTA_ON(mp)))
-		xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas not turned on");
-	else
-		xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas turned on");
-#endif
-
-#ifdef QUOTADEBUG
-	if (XFS_IS_QUOTA_ON(mp) && xfs_qm_internalqcheck(mp))
-		cmn_err(CE_WARN, "XFS: mount internalqcheck failed");
-#endif
-
-	return 0;
-}
-
-STATIC void
-xfs_qm_dqrele_null(
-	xfs_dquot_t	*dq)
-{
-	/*
-	 * Called from XFS, where we always check first for a NULL dquot.
-	 */
-	if (!dq)
-		return;
-	xfs_qm_dqrele(dq);
-}
-
-
-struct xfs_qmops xfs_qmcore_xfs = {
-	.xfs_qminit		= xfs_qm_newmount,
-	.xfs_qmdone		= xfs_qm_unmount_quotadestroy,
-	.xfs_qmmount		= xfs_qm_endmount,
-	.xfs_qmunmount		= xfs_qm_unmount_quotas,
-	.xfs_dqrele		= xfs_qm_dqrele_null,
-	.xfs_dqattach		= xfs_qm_dqattach,
-	.xfs_dqdetach		= xfs_qm_dqdetach,
-	.xfs_dqpurgeall		= xfs_qm_dqpurge_all,
-	.xfs_dqvopalloc		= xfs_qm_vop_dqalloc,
-	.xfs_dqvopcreate	= xfs_qm_vop_dqattach_and_dqmod_newinode,
-	.xfs_dqvoprename	= xfs_qm_vop_rename_dqattach,
-	.xfs_dqvopchown		= xfs_qm_vop_chown,
-	.xfs_dqvopchownresv	= xfs_qm_vop_chown_reserve,
-	.xfs_dqstatvfs		= xfs_qm_statvfs,
-	.xfs_dqsync		= xfs_qm_sync,
-	.xfs_dqtrxops		= &xfs_trans_dquot_ops,
-};
-EXPORT_SYMBOL(xfs_qmcore_xfs);
-
 void __init
 xfs_qm_init(void)
 {
diff --git a/fs/xfs/quota/xfs_qm_stats.c b/fs/xfs/quota/xfs_qm_stats.c
index 709f5f5..21b08c0 100644
--- a/fs/xfs/quota/xfs_qm_stats.c
+++ b/fs/xfs/quota/xfs_qm_stats.c
@@ -42,7 +42,6 @@
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_qm.h"
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
index c7b66f6..4e4276b 100644
--- a/fs/xfs/quota/xfs_qm_syscalls.c
+++ b/fs/xfs/quota/xfs_qm_syscalls.c
@@ -45,7 +45,6 @@
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_utils.h"
@@ -847,105 +846,55 @@
 }
 
 
-/*
- * Release all the dquots on the inodes in an AG.
- */
-STATIC void
-xfs_qm_dqrele_inodes_ag(
-	xfs_mount_t	*mp,
-	int		ag,
-	uint		flags)
+STATIC int
+xfs_dqrele_inode(
+	struct xfs_inode	*ip,
+	struct xfs_perag	*pag,
+	int			flags)
 {
-	xfs_inode_t	*ip = NULL;
-	xfs_perag_t	*pag = &mp->m_perag[ag];
-	int		first_index = 0;
-	int		nr_found;
+	int			error;
 
-	do {
-		/*
-		 * use a gang lookup to find the next inode in the tree
-		 * as the tree is sparse and a gang lookup walks to find
-		 * the number of objects requested.
-		 */
-		read_lock(&pag->pag_ici_lock);
-		nr_found = radix_tree_gang_lookup(&pag->pag_ici_root,
-				(void**)&ip, first_index, 1);
-
-		if (!nr_found) {
-			read_unlock(&pag->pag_ici_lock);
-			break;
-		}
-
-		/*
-		 * Update the index for the next lookup. Catch overflows
-		 * into the next AG range which can occur if we have inodes
-		 * in the last block of the AG and we are currently
-		 * pointing to the last inode.
-		 */
-		first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
-		if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) {
-			read_unlock(&pag->pag_ici_lock);
-			break;
-		}
-
-		/* skip quota inodes */
-		if (ip == XFS_QI_UQIP(mp) || ip == XFS_QI_GQIP(mp)) {
-			ASSERT(ip->i_udquot == NULL);
-			ASSERT(ip->i_gdquot == NULL);
-			read_unlock(&pag->pag_ici_lock);
-			continue;
-		}
-
-		/*
-		 * If we can't get a reference on the inode, it must be
-		 * in reclaim. Leave it for the reclaim code to flush.
-		 */
-		if (!igrab(VFS_I(ip))) {
-			read_unlock(&pag->pag_ici_lock);
-			continue;
-		}
+	/* skip quota inodes */
+	if (ip == XFS_QI_UQIP(ip->i_mount) || ip == XFS_QI_GQIP(ip->i_mount)) {
+		ASSERT(ip->i_udquot == NULL);
+		ASSERT(ip->i_gdquot == NULL);
 		read_unlock(&pag->pag_ici_lock);
+		return 0;
+	}
 
-		/* avoid new inodes though we shouldn't find any here */
-		if (xfs_iflags_test(ip, XFS_INEW)) {
-			IRELE(ip);
-			continue;
-		}
+	error = xfs_sync_inode_valid(ip, pag);
+	if (error)
+		return error;
 
-		xfs_ilock(ip, XFS_ILOCK_EXCL);
-		if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) {
-			xfs_qm_dqrele(ip->i_udquot);
-			ip->i_udquot = NULL;
-		}
-		if (flags & (XFS_PQUOTA_ACCT|XFS_GQUOTA_ACCT) &&
-		    ip->i_gdquot) {
-			xfs_qm_dqrele(ip->i_gdquot);
-			ip->i_gdquot = NULL;
-		}
-		xfs_iput(ip, XFS_ILOCK_EXCL);
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
+	if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) {
+		xfs_qm_dqrele(ip->i_udquot);
+		ip->i_udquot = NULL;
+	}
+	if (flags & (XFS_PQUOTA_ACCT|XFS_GQUOTA_ACCT) && ip->i_gdquot) {
+		xfs_qm_dqrele(ip->i_gdquot);
+		ip->i_gdquot = NULL;
+	}
+	xfs_iput(ip, XFS_ILOCK_EXCL);
+	IRELE(ip);
 
-	} while (nr_found);
+	return 0;
 }
 
+
 /*
  * Go thru all the inodes in the file system, releasing their dquots.
+ *
  * Note that the mount structure gets modified to indicate that quotas are off
- * AFTER this, in the case of quotaoff. This also gets called from
- * xfs_rootumount.
+ * AFTER this, in the case of quotaoff.
  */
 void
 xfs_qm_dqrele_all_inodes(
 	struct xfs_mount *mp,
 	uint		 flags)
 {
-	int		i;
-
 	ASSERT(mp->m_quotainfo);
-	for (i = 0; i < mp->m_sb.sb_agcount; i++) {
-		if (!mp->m_perag[i].pag_ici_init)
-			continue;
-		xfs_qm_dqrele_inodes_ag(mp, i, flags);
-	}
+	xfs_inode_ag_iterator(mp, xfs_dqrele_inode, flags, XFS_ICI_NO_TAG);
 }
 
 /*------------------------------------------------------------------------*/
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c
index 447173b..97ac964 100644
--- a/fs/xfs/quota/xfs_trans_dquot.c
+++ b/fs/xfs/quota/xfs_trans_dquot.c
@@ -42,7 +42,6 @@
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_priv.h"
@@ -111,7 +110,7 @@
  * Carry forward whatever is left of the quota blk reservation to
  * the spanky new transaction
  */
-STATIC void
+void
 xfs_trans_dup_dqinfo(
 	xfs_trans_t	*otp,
 	xfs_trans_t	*ntp)
@@ -167,19 +166,17 @@
 /*
  * Wrap around mod_dquot to account for both user and group quotas.
  */
-STATIC void
+void
 xfs_trans_mod_dquot_byino(
 	xfs_trans_t	*tp,
 	xfs_inode_t	*ip,
 	uint		field,
 	long		delta)
 {
-	xfs_mount_t	*mp;
+	xfs_mount_t	*mp = tp->t_mountp;
 
-	ASSERT(tp);
-	mp = tp->t_mountp;
-
-	if (!XFS_IS_QUOTA_ON(mp) ||
+	if (!XFS_IS_QUOTA_RUNNING(mp) ||
+	    !XFS_IS_QUOTA_ON(mp) ||
 	    ip->i_ino == mp->m_sb.sb_uquotino ||
 	    ip->i_ino == mp->m_sb.sb_gquotino)
 		return;
@@ -229,6 +226,7 @@
 	xfs_dqtrx_t	*qtrx;
 
 	ASSERT(tp);
+	ASSERT(XFS_IS_QUOTA_RUNNING(tp->t_mountp));
 	qtrx = NULL;
 
 	if (tp->t_dqinfo == NULL)
@@ -346,7 +344,7 @@
  * Unreserve just the reservations done by this transaction.
  * dquot is still left locked at exit.
  */
-STATIC void
+void
 xfs_trans_apply_dquot_deltas(
 	xfs_trans_t		*tp)
 {
@@ -357,7 +355,7 @@
 	long			totalbdelta;
 	long			totalrtbdelta;
 
-	if (! (tp->t_flags & XFS_TRANS_DQ_DIRTY))
+	if (!(tp->t_flags & XFS_TRANS_DQ_DIRTY))
 		return;
 
 	ASSERT(tp->t_dqinfo);
@@ -531,7 +529,7 @@
  * we simply throw those away, since that's the expected behavior
  * when a transaction is curtailed without a commit.
  */
-STATIC void
+void
 xfs_trans_unreserve_and_mod_dquots(
 	xfs_trans_t		*tp)
 {
@@ -768,7 +766,7 @@
 {
 	int		resvd = 0, error;
 
-	if (!XFS_IS_QUOTA_ON(mp))
+	if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
 		return 0;
 
 	if (tp && tp->t_dqinfo == NULL)
@@ -811,18 +809,17 @@
  * This doesn't change the actual usage, just the reservation.
  * The inode sent in is locked.
  */
-STATIC int
+int
 xfs_trans_reserve_quota_nblks(
-	xfs_trans_t	*tp,
-	xfs_mount_t	*mp,
-	xfs_inode_t	*ip,
-	long		nblks,
-	long		ninos,
-	uint		flags)
+	struct xfs_trans	*tp,
+	struct xfs_inode	*ip,
+	long			nblks,
+	long			ninos,
+	uint			flags)
 {
-	int		error;
+	struct xfs_mount	*mp = ip->i_mount;
 
-	if (!XFS_IS_QUOTA_ON(mp))
+	if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
 		return 0;
 	if (XFS_IS_PQUOTA_ON(mp))
 		flags |= XFS_QMOPT_ENOSPC;
@@ -831,7 +828,6 @@
 	ASSERT(ip->i_ino != mp->m_sb.sb_gquotino);
 
 	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-	ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
 	ASSERT((flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
 				XFS_TRANS_DQ_RES_RTBLKS ||
 	       (flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
@@ -840,11 +836,9 @@
 	/*
 	 * Reserve nblks against these dquots, with trans as the mediator.
 	 */
-	error = xfs_trans_reserve_quota_bydquots(tp, mp,
-						 ip->i_udquot, ip->i_gdquot,
-						 nblks, ninos,
-						 flags);
-	return error;
+	return xfs_trans_reserve_quota_bydquots(tp, mp,
+						ip->i_udquot, ip->i_gdquot,
+						nblks, ninos, flags);
 }
 
 /*
@@ -895,25 +889,15 @@
 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_Gqm->qm_dqtrxzone, KM_SLEEP);
 }
 
-STATIC void
+void
 xfs_trans_free_dqinfo(
 	xfs_trans_t	*tp)
 {
 	if (!tp->t_dqinfo)
 		return;
-	kmem_zone_free(xfs_Gqm->qm_dqtrxzone, (tp)->t_dqinfo);
-	(tp)->t_dqinfo = NULL;
+	kmem_zone_free(xfs_Gqm->qm_dqtrxzone, tp->t_dqinfo);
+	tp->t_dqinfo = NULL;
 }
-
-xfs_dqtrxops_t	xfs_trans_dquot_ops = {
-	.qo_dup_dqinfo			= xfs_trans_dup_dqinfo,
-	.qo_free_dqinfo			= xfs_trans_free_dqinfo,
-	.qo_mod_dquot_byino		= xfs_trans_mod_dquot_byino,
-	.qo_apply_dquot_deltas		= xfs_trans_apply_dquot_deltas,
-	.qo_reserve_quota_nblks		= xfs_trans_reserve_quota_nblks,
-	.qo_reserve_quota_bydquots	= xfs_trans_reserve_quota_bydquots,
-	.qo_unreserve_and_mod_dquots	= xfs_trans_unreserve_and_mod_dquots,
-};
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
deleted file mode 100644
index a8cdd73..0000000
--- a/fs/xfs/xfs_acl.c
+++ /dev/null
@@ -1,874 +0,0 @@
-/*
- * Copyright (c) 2001-2002,2005 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_types.h"
-#include "xfs_bit.h"
-#include "xfs_inum.h"
-#include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
-#include "xfs_inode.h"
-#include "xfs_btree.h"
-#include "xfs_acl.h"
-#include "xfs_attr.h"
-#include "xfs_vnodeops.h"
-
-#include <linux/capability.h>
-#include <linux/posix_acl_xattr.h>
-
-STATIC int	xfs_acl_setmode(struct inode *, xfs_acl_t *, int *);
-STATIC void     xfs_acl_filter_mode(mode_t, xfs_acl_t *);
-STATIC void	xfs_acl_get_endian(xfs_acl_t *);
-STATIC int	xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *);
-STATIC int	xfs_acl_invalid(xfs_acl_t *);
-STATIC void	xfs_acl_sync_mode(mode_t, xfs_acl_t *);
-STATIC void	xfs_acl_get_attr(struct inode *, xfs_acl_t *, int, int, int *);
-STATIC void	xfs_acl_set_attr(struct inode *, xfs_acl_t *, int, int *);
-STATIC int	xfs_acl_allow_set(struct inode *, int);
-
-kmem_zone_t *xfs_acl_zone;
-
-
-/*
- * Test for existence of access ACL attribute as efficiently as possible.
- */
-int
-xfs_acl_vhasacl_access(
-	struct inode	*vp)
-{
-	int		error;
-
-	xfs_acl_get_attr(vp, NULL, _ACL_TYPE_ACCESS, ATTR_KERNOVAL, &error);
-	return (error == 0);
-}
-
-/*
- * Test for existence of default ACL attribute as efficiently as possible.
- */
-int
-xfs_acl_vhasacl_default(
-	struct inode	*vp)
-{
-	int		error;
-
-	if (!S_ISDIR(vp->i_mode))
-		return 0;
-	xfs_acl_get_attr(vp, NULL, _ACL_TYPE_DEFAULT, ATTR_KERNOVAL, &error);
-	return (error == 0);
-}
-
-/*
- * Convert from extended attribute representation to in-memory for XFS.
- */
-STATIC int
-posix_acl_xattr_to_xfs(
-	posix_acl_xattr_header	*src,
-	size_t			size,
-	xfs_acl_t		*dest)
-{
-	posix_acl_xattr_entry	*src_entry;
-	xfs_acl_entry_t		*dest_entry;
-	int			n;
-
-	if (!src || !dest)
-		return EINVAL;
-
-	if (size < sizeof(posix_acl_xattr_header))
-		return EINVAL;
-
-	if (src->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
-		return EOPNOTSUPP;
-
-	memset(dest, 0, sizeof(xfs_acl_t));
-	dest->acl_cnt = posix_acl_xattr_count(size);
-	if (dest->acl_cnt < 0 || dest->acl_cnt > XFS_ACL_MAX_ENTRIES)
-		return EINVAL;
-
-	/*
-	 * acl_set_file(3) may request that we set default ACLs with
-	 * zero length -- defend (gracefully) against that here.
-	 */
-	if (!dest->acl_cnt)
-		return 0;
-
-	src_entry = (posix_acl_xattr_entry *)((char *)src + sizeof(*src));
-	dest_entry = &dest->acl_entry[0];
-
-	for (n = 0; n < dest->acl_cnt; n++, src_entry++, dest_entry++) {
-		dest_entry->ae_perm = le16_to_cpu(src_entry->e_perm);
-		if (_ACL_PERM_INVALID(dest_entry->ae_perm))
-			return EINVAL;
-		dest_entry->ae_tag  = le16_to_cpu(src_entry->e_tag);
-		switch(dest_entry->ae_tag) {
-		case ACL_USER:
-		case ACL_GROUP:
-			dest_entry->ae_id = le32_to_cpu(src_entry->e_id);
-			break;
-		case ACL_USER_OBJ:
-		case ACL_GROUP_OBJ:
-		case ACL_MASK:
-		case ACL_OTHER:
-			dest_entry->ae_id = ACL_UNDEFINED_ID;
-			break;
-		default:
-			return EINVAL;
-		}
-	}
-	if (xfs_acl_invalid(dest))
-		return EINVAL;
-
-	return 0;
-}
-
-/*
- * Comparison function called from xfs_sort().
- * Primary key is ae_tag, secondary key is ae_id.
- */
-STATIC int
-xfs_acl_entry_compare(
-	const void	*va,
-	const void	*vb)
-{
-	xfs_acl_entry_t	*a = (xfs_acl_entry_t *)va,
-			*b = (xfs_acl_entry_t *)vb;
-
-	if (a->ae_tag == b->ae_tag)
-		return (a->ae_id - b->ae_id);
-	return (a->ae_tag - b->ae_tag);
-}
-
-/*
- * Convert from in-memory XFS to extended attribute representation.
- */
-STATIC int
-posix_acl_xfs_to_xattr(
-	xfs_acl_t		*src,
-	posix_acl_xattr_header	*dest,
-	size_t			size)
-{
-	int			n;
-	size_t			new_size = posix_acl_xattr_size(src->acl_cnt);
-	posix_acl_xattr_entry	*dest_entry;
-	xfs_acl_entry_t		*src_entry;
-
-	if (size < new_size)
-		return -ERANGE;
-
-	/* Need to sort src XFS ACL by <ae_tag,ae_id> */
-	xfs_sort(src->acl_entry, src->acl_cnt, sizeof(src->acl_entry[0]),
-		 xfs_acl_entry_compare);
-
-	dest->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
-	dest_entry = &dest->a_entries[0];
-	src_entry = &src->acl_entry[0];
-	for (n = 0; n < src->acl_cnt; n++, dest_entry++, src_entry++) {
-		dest_entry->e_perm = cpu_to_le16(src_entry->ae_perm);
-		if (_ACL_PERM_INVALID(src_entry->ae_perm))
-			return -EINVAL;
-		dest_entry->e_tag  = cpu_to_le16(src_entry->ae_tag);
-		switch (src_entry->ae_tag) {
-		case ACL_USER:
-		case ACL_GROUP:
-			dest_entry->e_id = cpu_to_le32(src_entry->ae_id);
-				break;
-		case ACL_USER_OBJ:
-		case ACL_GROUP_OBJ:
-		case ACL_MASK:
-		case ACL_OTHER:
-			dest_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-	return new_size;
-}
-
-int
-xfs_acl_vget(
-	struct inode	*vp,
-	void		*acl,
-	size_t		size,
-	int		kind)
-{
-	int			error;
-	xfs_acl_t		*xfs_acl = NULL;
-	posix_acl_xattr_header	*ext_acl = acl;
-	int			flags = 0;
-
-	if(size) {
-		if (!(_ACL_ALLOC(xfs_acl))) {
-			error = ENOMEM;
-			goto out;
-		}
-		memset(xfs_acl, 0, sizeof(xfs_acl_t));
-	} else
-		flags = ATTR_KERNOVAL;
-
-	xfs_acl_get_attr(vp, xfs_acl, kind, flags, &error);
-	if (error)
-		goto out;
-
-	if (!size) {
-		error = -posix_acl_xattr_size(XFS_ACL_MAX_ENTRIES);
-	} else {
-		if (xfs_acl_invalid(xfs_acl)) {
-			error = EINVAL;
-			goto out;
-		}
-		if (kind == _ACL_TYPE_ACCESS)
-			xfs_acl_sync_mode(XFS_I(vp)->i_d.di_mode, xfs_acl);
-		error = -posix_acl_xfs_to_xattr(xfs_acl, ext_acl, size);
-	}
-out:
-	if(xfs_acl)
-		_ACL_FREE(xfs_acl);
-	return -error;
-}
-
-int
-xfs_acl_vremove(
-	struct inode	*vp,
-	int		kind)
-{
-	int		error;
-
-	error = xfs_acl_allow_set(vp, kind);
-	if (!error) {
-		error = xfs_attr_remove(XFS_I(vp),
-						kind == _ACL_TYPE_DEFAULT?
-						SGI_ACL_DEFAULT: SGI_ACL_FILE,
-						ATTR_ROOT);
-		if (error == ENOATTR)
-			error = 0;	/* 'scool */
-	}
-	return -error;
-}
-
-int
-xfs_acl_vset(
-	struct inode		*vp,
-	void			*acl,
-	size_t			size,
-	int			kind)
-{
-	posix_acl_xattr_header	*ext_acl = acl;
-	xfs_acl_t		*xfs_acl;
-	int			error;
-	int			basicperms = 0; /* more than std unix perms? */
-
-	if (!acl)
-		return -EINVAL;
-
-	if (!(_ACL_ALLOC(xfs_acl)))
-		return -ENOMEM;
-
-	error = posix_acl_xattr_to_xfs(ext_acl, size, xfs_acl);
-	if (error) {
-		_ACL_FREE(xfs_acl);
-		return -error;
-	}
-	if (!xfs_acl->acl_cnt) {
-		_ACL_FREE(xfs_acl);
-		return 0;
-	}
-
-	error = xfs_acl_allow_set(vp, kind);
-
-	/* Incoming ACL exists, set file mode based on its value */
-	if (!error && kind == _ACL_TYPE_ACCESS)
-		error = xfs_acl_setmode(vp, xfs_acl, &basicperms);
-
-	if (error)
-		goto out;
-
-	/*
-	 * If we have more than std unix permissions, set up the actual attr.
-	 * Otherwise, delete any existing attr.  This prevents us from
-	 * having actual attrs for permissions that can be stored in the
-	 * standard permission bits.
-	 */
-	if (!basicperms) {
-		xfs_acl_set_attr(vp, xfs_acl, kind, &error);
-	} else {
-		error = -xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
-	}
-
-out:
-	_ACL_FREE(xfs_acl);
-	return -error;
-}
-
-int
-xfs_acl_iaccess(
-	xfs_inode_t	*ip,
-	mode_t		mode,
-	cred_t		*cr)
-{
-	xfs_acl_t	*acl;
-	int		rval;
-	struct xfs_name	acl_name = {SGI_ACL_FILE, SGI_ACL_FILE_SIZE};
-
-	if (!(_ACL_ALLOC(acl)))
-		return -1;
-
-	/* If the file has no ACL return -1. */
-	rval = sizeof(xfs_acl_t);
-	if (xfs_attr_fetch(ip, &acl_name, (char *)acl, &rval, ATTR_ROOT)) {
-		_ACL_FREE(acl);
-		return -1;
-	}
-	xfs_acl_get_endian(acl);
-
-	/* If the file has an empty ACL return -1. */
-	if (acl->acl_cnt == XFS_ACL_NOT_PRESENT) {
-		_ACL_FREE(acl);
-		return -1;
-	}
-
-	/* Synchronize ACL with mode bits */
-	xfs_acl_sync_mode(ip->i_d.di_mode, acl);
-
-	rval = xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, acl, mode, cr);
-	_ACL_FREE(acl);
-	return rval;
-}
-
-STATIC int
-xfs_acl_allow_set(
-	struct inode	*vp,
-	int		kind)
-{
-	if (vp->i_flags & (S_IMMUTABLE|S_APPEND))
-		return EPERM;
-	if (kind == _ACL_TYPE_DEFAULT && !S_ISDIR(vp->i_mode))
-		return ENOTDIR;
-	if (vp->i_sb->s_flags & MS_RDONLY)
-		return EROFS;
-	if (XFS_I(vp)->i_d.di_uid != current_fsuid() && !capable(CAP_FOWNER))
-		return EPERM;
-	return 0;
-}
-
-/*
- * Note: cr is only used here for the capability check if the ACL test fails.
- *       It is not used to find out the credentials uid or groups etc, as was
- *       done in IRIX. It is assumed that the uid and groups for the current
- *       thread are taken from "current" instead of the cr parameter.
- */
-STATIC int
-xfs_acl_access(
-	uid_t		fuid,
-	gid_t		fgid,
-	xfs_acl_t	*fap,
-	mode_t		md,
-	cred_t		*cr)
-{
-	xfs_acl_entry_t	matched;
-	int		i, allows;
-	int		maskallows = -1;	/* true, but not 1, either */
-	int		seen_userobj = 0;
-
-	matched.ae_tag = 0;	/* Invalid type */
-	matched.ae_perm = 0;
-
-	for (i = 0; i < fap->acl_cnt; i++) {
-		/*
-		 * Break out if we've got a user_obj entry or
-		 * a user entry and the mask (and have processed USER_OBJ)
-		 */
-		if (matched.ae_tag == ACL_USER_OBJ)
-			break;
-		if (matched.ae_tag == ACL_USER) {
-			if (maskallows != -1 && seen_userobj)
-				break;
-			if (fap->acl_entry[i].ae_tag != ACL_MASK &&
-			    fap->acl_entry[i].ae_tag != ACL_USER_OBJ)
-				continue;
-		}
-		/* True if this entry allows the requested access */
-		allows = ((fap->acl_entry[i].ae_perm & md) == md);
-
-		switch (fap->acl_entry[i].ae_tag) {
-		case ACL_USER_OBJ:
-			seen_userobj = 1;
-			if (fuid != current_fsuid())
-				continue;
-			matched.ae_tag = ACL_USER_OBJ;
-			matched.ae_perm = allows;
-			break;
-		case ACL_USER:
-			if (fap->acl_entry[i].ae_id != current_fsuid())
-				continue;
-			matched.ae_tag = ACL_USER;
-			matched.ae_perm = allows;
-			break;
-		case ACL_GROUP_OBJ:
-			if ((matched.ae_tag == ACL_GROUP_OBJ ||
-			    matched.ae_tag == ACL_GROUP) && !allows)
-				continue;
-			if (!in_group_p(fgid))
-				continue;
-			matched.ae_tag = ACL_GROUP_OBJ;
-			matched.ae_perm = allows;
-			break;
-		case ACL_GROUP:
-			if ((matched.ae_tag == ACL_GROUP_OBJ ||
-			    matched.ae_tag == ACL_GROUP) && !allows)
-				continue;
-			if (!in_group_p(fap->acl_entry[i].ae_id))
-				continue;
-			matched.ae_tag = ACL_GROUP;
-			matched.ae_perm = allows;
-			break;
-		case ACL_MASK:
-			maskallows = allows;
-			break;
-		case ACL_OTHER:
-			if (matched.ae_tag != 0)
-				continue;
-			matched.ae_tag = ACL_OTHER;
-			matched.ae_perm = allows;
-			break;
-		}
-	}
-	/*
-	 * First possibility is that no matched entry allows access.
-	 * The capability to override DAC may exist, so check for it.
-	 */
-	switch (matched.ae_tag) {
-	case ACL_OTHER:
-	case ACL_USER_OBJ:
-		if (matched.ae_perm)
-			return 0;
-		break;
-	case ACL_USER:
-	case ACL_GROUP_OBJ:
-	case ACL_GROUP:
-		if (maskallows && matched.ae_perm)
-			return 0;
-		break;
-	case 0:
-		break;
-	}
-
-	/* EACCES tells generic_permission to check for capability overrides */
-	return EACCES;
-}
-
-/*
- * ACL validity checker.
- *   This acl validation routine checks each ACL entry read in makes sense.
- */
-STATIC int
-xfs_acl_invalid(
-	xfs_acl_t	*aclp)
-{
-	xfs_acl_entry_t	*entry, *e;
-	int		user = 0, group = 0, other = 0, mask = 0;
-	int		mask_required = 0;
-	int		i, j;
-
-	if (!aclp)
-		goto acl_invalid;
-
-	if (aclp->acl_cnt > XFS_ACL_MAX_ENTRIES)
-		goto acl_invalid;
-
-	for (i = 0; i < aclp->acl_cnt; i++) {
-		entry = &aclp->acl_entry[i];
-		switch (entry->ae_tag) {
-		case ACL_USER_OBJ:
-			if (user++)
-				goto acl_invalid;
-			break;
-		case ACL_GROUP_OBJ:
-			if (group++)
-				goto acl_invalid;
-			break;
-		case ACL_OTHER:
-			if (other++)
-				goto acl_invalid;
-			break;
-		case ACL_USER:
-		case ACL_GROUP:
-			for (j = i + 1; j < aclp->acl_cnt; j++) {
-				e = &aclp->acl_entry[j];
-				if (e->ae_id == entry->ae_id &&
-				    e->ae_tag == entry->ae_tag)
-					goto acl_invalid;
-			}
-			mask_required++;
-			break;
-		case ACL_MASK:
-			if (mask++)
-				goto acl_invalid;
-			break;
-		default:
-			goto acl_invalid;
-		}
-	}
-	if (!user || !group || !other || (mask_required && !mask))
-		goto acl_invalid;
-	else
-		return 0;
-acl_invalid:
-	return EINVAL;
-}
-
-/*
- * Do ACL endian conversion.
- */
-STATIC void
-xfs_acl_get_endian(
-	xfs_acl_t	*aclp)
-{
-	xfs_acl_entry_t	*ace, *end;
-
-	INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
-	end = &aclp->acl_entry[0]+aclp->acl_cnt;
-	for (ace = &aclp->acl_entry[0]; ace < end; ace++) {
-		INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag);
-		INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id);
-		INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm);
-	}
-}
-
-/*
- * Get the ACL from the EA and do endian conversion.
- */
-STATIC void
-xfs_acl_get_attr(
-	struct inode	*vp,
-	xfs_acl_t	*aclp,
-	int		kind,
-	int		flags,
-	int		*error)
-{
-	int		len = sizeof(xfs_acl_t);
-
-	ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1);
-	flags |= ATTR_ROOT;
-	*error = xfs_attr_get(XFS_I(vp),
-					kind == _ACL_TYPE_ACCESS ?
-					SGI_ACL_FILE : SGI_ACL_DEFAULT,
-					(char *)aclp, &len, flags);
-	if (*error || (flags & ATTR_KERNOVAL))
-		return;
-	xfs_acl_get_endian(aclp);
-}
-
-/*
- * Set the EA with the ACL and do endian conversion.
- */
-STATIC void
-xfs_acl_set_attr(
-	struct inode	*vp,
-	xfs_acl_t	*aclp,
-	int		kind,
-	int		*error)
-{
-	xfs_acl_entry_t	*ace, *newace, *end;
-	xfs_acl_t	*newacl;
-	int		len;
-
-	if (!(_ACL_ALLOC(newacl))) {
-		*error = ENOMEM;
-		return;
-	}
-
-	len = sizeof(xfs_acl_t) -
-	      (sizeof(xfs_acl_entry_t) * (XFS_ACL_MAX_ENTRIES - aclp->acl_cnt));
-	end = &aclp->acl_entry[0]+aclp->acl_cnt;
-	for (ace = &aclp->acl_entry[0], newace = &newacl->acl_entry[0];
-	     ace < end;
-	     ace++, newace++) {
-		INT_SET(newace->ae_tag, ARCH_CONVERT, ace->ae_tag);
-		INT_SET(newace->ae_id, ARCH_CONVERT, ace->ae_id);
-		INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm);
-	}
-	INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
-	*error = xfs_attr_set(XFS_I(vp),
-				kind == _ACL_TYPE_ACCESS ?
-				SGI_ACL_FILE: SGI_ACL_DEFAULT,
-				(char *)newacl, len, ATTR_ROOT);
-	_ACL_FREE(newacl);
-}
-
-int
-xfs_acl_vtoacl(
-	struct inode	*vp,
-	xfs_acl_t	*access_acl,
-	xfs_acl_t	*default_acl)
-{
-	int		error = 0;
-
-	if (access_acl) {
-		/*
-		 * Get the Access ACL and the mode.  If either cannot
-		 * be obtained for some reason, invalidate the access ACL.
-		 */
-		xfs_acl_get_attr(vp, access_acl, _ACL_TYPE_ACCESS, 0, &error);
-		if (error)
-			access_acl->acl_cnt = XFS_ACL_NOT_PRESENT;
-		else /* We have a good ACL and the file mode, synchronize. */
-			xfs_acl_sync_mode(XFS_I(vp)->i_d.di_mode, access_acl);
-	}
-
-	if (default_acl) {
-		xfs_acl_get_attr(vp, default_acl, _ACL_TYPE_DEFAULT, 0, &error);
-		if (error)
-			default_acl->acl_cnt = XFS_ACL_NOT_PRESENT;
-	}
-	return error;
-}
-
-/*
- * This function retrieves the parent directory's acl, processes it
- * and lets the child inherit the acl(s) that it should.
- */
-int
-xfs_acl_inherit(
-	struct inode	*vp,
-	mode_t		mode,
-	xfs_acl_t	*pdaclp)
-{
-	xfs_acl_t	*cacl;
-	int		error = 0;
-	int		basicperms = 0;
-
-	/*
-	 * If the parent does not have a default ACL, or it's an
-	 * invalid ACL, we're done.
-	 */
-	if (!vp)
-		return 0;
-	if (!pdaclp || xfs_acl_invalid(pdaclp))
-		return 0;
-
-	/*
-	 * Copy the default ACL of the containing directory to
-	 * the access ACL of the new file and use the mode that
-	 * was passed in to set up the correct initial values for
-	 * the u::,g::[m::], and o:: entries.  This is what makes
-	 * umask() "work" with ACL's.
-	 */
-
-	if (!(_ACL_ALLOC(cacl)))
-		return ENOMEM;
-
-	memcpy(cacl, pdaclp, sizeof(xfs_acl_t));
-	xfs_acl_filter_mode(mode, cacl);
-	error = xfs_acl_setmode(vp, cacl, &basicperms);
-	if (error)
-		goto out_error;
-
-	/*
-	 * Set the Default and Access ACL on the file.  The mode is already
-	 * set on the file, so we don't need to worry about that.
-	 *
-	 * If the new file is a directory, its default ACL is a copy of
-	 * the containing directory's default ACL.
-	 */
-	if (S_ISDIR(vp->i_mode))
-		xfs_acl_set_attr(vp, pdaclp, _ACL_TYPE_DEFAULT, &error);
-	if (!error && !basicperms)
-		xfs_acl_set_attr(vp, cacl, _ACL_TYPE_ACCESS, &error);
-out_error:
-	_ACL_FREE(cacl);
-	return error;
-}
-
-/*
- * Set up the correct mode on the file based on the supplied ACL.  This
- * makes sure that the mode on the file reflects the state of the
- * u::,g::[m::], and o:: entries in the ACL.  Since the mode is where
- * the ACL is going to get the permissions for these entries, we must
- * synchronize the mode whenever we set the ACL on a file.
- */
-STATIC int
-xfs_acl_setmode(
-	struct inode	*vp,
-	xfs_acl_t	*acl,
-	int		*basicperms)
-{
-	struct iattr	iattr;
-	xfs_acl_entry_t	*ap;
-	xfs_acl_entry_t	*gap = NULL;
-	int		i, nomask = 1;
-
-	*basicperms = 1;
-
-	if (acl->acl_cnt == XFS_ACL_NOT_PRESENT)
-		return 0;
-
-	/*
-	 * Copy the u::, g::, o::, and m:: bits from the ACL into the
-	 * mode.  The m:: bits take precedence over the g:: bits.
-	 */
-	iattr.ia_valid = ATTR_MODE;
-	iattr.ia_mode = XFS_I(vp)->i_d.di_mode;
-	iattr.ia_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO);
-	ap = acl->acl_entry;
-	for (i = 0; i < acl->acl_cnt; ++i) {
-		switch (ap->ae_tag) {
-		case ACL_USER_OBJ:
-			iattr.ia_mode |= ap->ae_perm << 6;
-			break;
-		case ACL_GROUP_OBJ:
-			gap = ap;
-			break;
-		case ACL_MASK:	/* more than just standard modes */
-			nomask = 0;
-			iattr.ia_mode |= ap->ae_perm << 3;
-			*basicperms = 0;
-			break;
-		case ACL_OTHER:
-			iattr.ia_mode |= ap->ae_perm;
-			break;
-		default:	/* more than just standard modes */
-			*basicperms = 0;
-			break;
-		}
-		ap++;
-	}
-
-	/* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */
-	if (gap && nomask)
-		iattr.ia_mode |= gap->ae_perm << 3;
-
-	return xfs_setattr(XFS_I(vp), &iattr, 0);
-}
-
-/*
- * The permissions for the special ACL entries (u::, g::[m::], o::) are
- * actually stored in the file mode (if there is both a group and a mask,
- * the group is stored in the ACL entry and the mask is stored on the file).
- * This allows the mode to remain automatically in sync with the ACL without
- * the need for a call-back to the ACL system at every point where the mode
- * could change.  This function takes the permissions from the specified mode
- * and places it in the supplied ACL.
- *
- * This implementation draws its validity from the fact that, when the ACL
- * was assigned, the mode was copied from the ACL.
- * If the mode did not change, therefore, the mode remains exactly what was
- * taken from the special ACL entries at assignment.
- * If a subsequent chmod() was done, the POSIX spec says that the change in
- * mode must cause an update to the ACL seen at user level and used for
- * access checks.  Before and after a mode change, therefore, the file mode
- * most accurately reflects what the special ACL entries should permit/deny.
- *
- * CAVEAT: If someone sets the SGI_ACL_FILE attribute directly,
- *         the existing mode bits will override whatever is in the
- *         ACL. Similarly, if there is a pre-existing ACL that was
- *         never in sync with its mode (owing to a bug in 6.5 and
- *         before), it will now magically (or mystically) be
- *         synchronized.  This could cause slight astonishment, but
- *         it is better than inconsistent permissions.
- *
- * The supplied ACL is a template that may contain any combination
- * of special entries.  These are treated as place holders when we fill
- * out the ACL.  This routine does not add or remove special entries, it
- * simply unites each special entry with its associated set of permissions.
- */
-STATIC void
-xfs_acl_sync_mode(
-	mode_t		mode,
-	xfs_acl_t	*acl)
-{
-	int		i, nomask = 1;
-	xfs_acl_entry_t	*ap;
-	xfs_acl_entry_t	*gap = NULL;
-
-	/*
-	 * Set ACL entries. POSIX1003.1eD16 requires that the MASK
-	 * be set instead of the GROUP entry, if there is a MASK.
-	 */
-	for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) {
-		switch (ap->ae_tag) {
-		case ACL_USER_OBJ:
-			ap->ae_perm = (mode >> 6) & 0x7;
-			break;
-		case ACL_GROUP_OBJ:
-			gap = ap;
-			break;
-		case ACL_MASK:
-			nomask = 0;
-			ap->ae_perm = (mode >> 3) & 0x7;
-			break;
-		case ACL_OTHER:
-			ap->ae_perm = mode & 0x7;
-			break;
-		default:
-			break;
-		}
-	}
-	/* Set the ACL_GROUP_OBJ if there's no ACL_MASK */
-	if (gap && nomask)
-		gap->ae_perm = (mode >> 3) & 0x7;
-}
-
-/*
- * When inheriting an Access ACL from a directory Default ACL,
- * the ACL bits are set to the intersection of the ACL default
- * permission bits and the file permission bits in mode. If there
- * are no permission bits on the file then we must not give them
- * the ACL. This is what what makes umask() work with ACLs.
- */
-STATIC void
-xfs_acl_filter_mode(
-	mode_t		mode,
-	xfs_acl_t	*acl)
-{
-	int		i, nomask = 1;
-	xfs_acl_entry_t	*ap;
-	xfs_acl_entry_t	*gap = NULL;
-
-	/*
-	 * Set ACL entries. POSIX1003.1eD16 requires that the MASK
-	 * be merged with GROUP entry, if there is a MASK.
-	 */
-	for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) {
-		switch (ap->ae_tag) {
-		case ACL_USER_OBJ:
-			ap->ae_perm &= (mode >> 6) & 0x7;
-			break;
-		case ACL_GROUP_OBJ:
-			gap = ap;
-			break;
-		case ACL_MASK:
-			nomask = 0;
-			ap->ae_perm &= (mode >> 3) & 0x7;
-			break;
-		case ACL_OTHER:
-			ap->ae_perm &= mode & 0x7;
-			break;
-		default:
-			break;
-		}
-	}
-	/* Set the ACL_GROUP_OBJ if there's no ACL_MASK */
-	if (gap && nomask)
-		gap->ae_perm &= (mode >> 3) & 0x7;
-}
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h
index 642f1db..63dc1f2 100644
--- a/fs/xfs/xfs_acl.h
+++ b/fs/xfs/xfs_acl.h
@@ -18,81 +18,48 @@
 #ifndef __XFS_ACL_H__
 #define __XFS_ACL_H__
 
-/*
- * Access Control Lists
- */
-typedef __uint16_t	xfs_acl_perm_t;
-typedef __int32_t	xfs_acl_tag_t;
-typedef __int32_t	xfs_acl_id_t;
+struct inode;
+struct posix_acl;
+struct xfs_inode;
 
 #define XFS_ACL_MAX_ENTRIES 25
 #define XFS_ACL_NOT_PRESENT (-1)
 
-typedef struct xfs_acl_entry {
-	xfs_acl_tag_t	ae_tag;
-	xfs_acl_id_t	ae_id;
-	xfs_acl_perm_t	ae_perm;
-} xfs_acl_entry_t;
-
-typedef struct xfs_acl {
-	__int32_t	acl_cnt;
-	xfs_acl_entry_t	acl_entry[XFS_ACL_MAX_ENTRIES];
-} xfs_acl_t;
+/* On-disk XFS access control list structure */
+struct xfs_acl {
+	__be32		acl_cnt;
+	struct xfs_acl_entry {
+		__be32	ae_tag;
+		__be32	ae_id;
+		__be16	ae_perm;
+	} acl_entry[XFS_ACL_MAX_ENTRIES];
+};
 
 /* On-disk XFS extended attribute names */
-#define SGI_ACL_FILE	"SGI_ACL_FILE"
-#define SGI_ACL_DEFAULT	"SGI_ACL_DEFAULT"
+#define SGI_ACL_FILE		"SGI_ACL_FILE"
+#define SGI_ACL_DEFAULT		"SGI_ACL_DEFAULT"
 #define SGI_ACL_FILE_SIZE	(sizeof(SGI_ACL_FILE)-1)
 #define SGI_ACL_DEFAULT_SIZE	(sizeof(SGI_ACL_DEFAULT)-1)
 
-#define _ACL_TYPE_ACCESS	1
-#define _ACL_TYPE_DEFAULT	2
-
 #ifdef CONFIG_XFS_POSIX_ACL
+extern int xfs_check_acl(struct inode *inode, int mask);
+extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
+extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl);
+extern int xfs_acl_chmod(struct inode *inode);
+extern void xfs_inode_init_acls(struct xfs_inode *ip);
+extern void xfs_inode_clear_acls(struct xfs_inode *ip);
+extern int posix_acl_access_exists(struct inode *inode);
+extern int posix_acl_default_exists(struct inode *inode);
 
-struct vattr;
-struct xfs_inode;
-
-extern struct kmem_zone *xfs_acl_zone;
-#define xfs_acl_zone_init(zone, name)	\
-		(zone) = kmem_zone_init(sizeof(xfs_acl_t), (name))
-#define xfs_acl_zone_destroy(zone)	kmem_zone_destroy(zone)
-
-extern int xfs_acl_inherit(struct inode *, mode_t mode, xfs_acl_t *);
-extern int xfs_acl_iaccess(struct xfs_inode *, mode_t, cred_t *);
-extern int xfs_acl_vtoacl(struct inode *, xfs_acl_t *, xfs_acl_t *);
-extern int xfs_acl_vhasacl_access(struct inode *);
-extern int xfs_acl_vhasacl_default(struct inode *);
-extern int xfs_acl_vset(struct inode *, void *, size_t, int);
-extern int xfs_acl_vget(struct inode *, void *, size_t, int);
-extern int xfs_acl_vremove(struct inode *, int);
-
-#define _ACL_PERM_INVALID(perm)	((perm) & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE))
-
-#define _ACL_INHERIT(c,m,d)	(xfs_acl_inherit(c,m,d))
-#define _ACL_GET_ACCESS(pv,pa)	(xfs_acl_vtoacl(pv,pa,NULL) == 0)
-#define _ACL_GET_DEFAULT(pv,pd)	(xfs_acl_vtoacl(pv,NULL,pd) == 0)
-#define _ACL_ACCESS_EXISTS	xfs_acl_vhasacl_access
-#define _ACL_DEFAULT_EXISTS	xfs_acl_vhasacl_default
-
-#define _ACL_ALLOC(a)		((a) = kmem_zone_alloc(xfs_acl_zone, KM_SLEEP))
-#define _ACL_FREE(a)		((a)? kmem_zone_free(xfs_acl_zone, (a)):(void)0)
-
+extern struct xattr_handler xfs_xattr_system_handler;
 #else
-#define xfs_acl_zone_init(zone,name)
-#define xfs_acl_zone_destroy(zone)
-#define xfs_acl_vset(v,p,sz,t)	(-EOPNOTSUPP)
-#define xfs_acl_vget(v,p,sz,t)	(-EOPNOTSUPP)
-#define xfs_acl_vremove(v,t)	(-EOPNOTSUPP)
-#define xfs_acl_vhasacl_access(v)	(0)
-#define xfs_acl_vhasacl_default(v)	(0)
-#define _ACL_ALLOC(a)		(1)	/* successfully allocate nothing */
-#define _ACL_FREE(a)		((void)0)
-#define _ACL_INHERIT(c,m,d)	(0)
-#define _ACL_GET_ACCESS(pv,pa)	(0)
-#define _ACL_GET_DEFAULT(pv,pd)	(0)
-#define _ACL_ACCESS_EXISTS	(NULL)
-#define _ACL_DEFAULT_EXISTS	(NULL)
-#endif
-
+# define xfs_check_acl					NULL
+# define xfs_get_acl(inode, type)			NULL
+# define xfs_inherit_acl(inode, default_acl)		0
+# define xfs_acl_chmod(inode)				0
+# define xfs_inode_init_acls(ip)
+# define xfs_inode_clear_acls(ip)
+# define posix_acl_access_exists(inode)			0
+# define posix_acl_default_exists(inode)		0
+#endif /* CONFIG_XFS_POSIX_ACL */
 #endif	/* __XFS_ACL_H__ */
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h
index c8641f7..f24b50b 100644
--- a/fs/xfs/xfs_ag.h
+++ b/fs/xfs/xfs_ag.h
@@ -212,6 +212,8 @@
 /*
  * tags for inode radix tree
  */
+#define XFS_ICI_NO_TAG		(-1)	/* special flag for an untagged lookup
+					   in xfs_inode_ag_iterator */
 #define XFS_ICI_RECLAIM_TAG	0	/* inode is to be reclaimed */
 
 #define	XFS_AG_MAXLEVELS(mp)		((mp)->m_ag_maxlevels)
diff --git a/fs/xfs/xfs_arch.h b/fs/xfs/xfs_arch.h
index 53d5e70..0902249 100644
--- a/fs/xfs/xfs_arch.h
+++ b/fs/xfs/xfs_arch.h
@@ -73,28 +73,6 @@
 
 #endif	/* __KERNEL__ */
 
-/* do we need conversion? */
-#define ARCH_NOCONVERT 1
-#ifdef XFS_NATIVE_HOST
-# define ARCH_CONVERT	ARCH_NOCONVERT
-#else
-# define ARCH_CONVERT	0
-#endif
-
-/* generic swapping macros */
-
-#ifndef HAVE_SWABMACROS
-#define INT_SWAP16(type,var) ((typeof(type))(__swab16((__u16)(var))))
-#define INT_SWAP32(type,var) ((typeof(type))(__swab32((__u32)(var))))
-#define INT_SWAP64(type,var) ((typeof(type))(__swab64((__u64)(var))))
-#endif
-
-#define INT_SWAP(type, var) \
-    ((sizeof(type) == 8) ? INT_SWAP64(type,var) : \
-    ((sizeof(type) == 4) ? INT_SWAP32(type,var) : \
-    ((sizeof(type) == 2) ? INT_SWAP16(type,var) : \
-    (var))))
-
 /*
  * get and set integers from potentially unaligned locations
  */
@@ -107,16 +85,6 @@
 	((__u8*)(pointer))[1] = (((value)     ) & 0xff); \
     }
 
-/* does not return a value */
-#define INT_SET(reference,arch,valueref) \
-    (__builtin_constant_p(valueref) ? \
-	(void)( (reference) = ( ((arch) != ARCH_NOCONVERT) ? (INT_SWAP((reference),(valueref))) : (valueref)) ) : \
-	(void)( \
-	    ((reference) = (valueref)), \
-	    ( ((arch) != ARCH_NOCONVERT) ? (reference) = INT_SWAP((reference),(reference)) : 0 ) \
-	) \
-    )
-
 /*
  * In directories inode numbers are stored as unaligned arrays of unsigned
  * 8bit integers on disk.
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
index 5fde165..db15feb 100644
--- a/fs/xfs/xfs_attr.c
+++ b/fs/xfs/xfs_attr.c
@@ -45,7 +45,6 @@
 #include "xfs_error.h"
 #include "xfs_quota.h"
 #include "xfs_trans_space.h"
-#include "xfs_acl.h"
 #include "xfs_rw.h"
 #include "xfs_vnodeops.h"
 
@@ -249,8 +248,9 @@
 	/*
 	 * Attach the dquots to the inode.
 	 */
-	if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
-		return (error);
+	error = xfs_qm_dqattach(dp, 0);
+	if (error)
+		return error;
 
 	/*
 	 * If the inode doesn't have an attribute fork, add one.
@@ -311,7 +311,7 @@
 	}
 	xfs_ilock(dp, XFS_ILOCK_EXCL);
 
-	error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, args.total, 0,
+	error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0,
 				rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
 				       XFS_QMOPT_RES_REGBLKS);
 	if (error) {
@@ -501,8 +501,9 @@
 	/*
 	 * Attach the dquots to the inode.
 	 */
-	if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
-		return (error);
+	error = xfs_qm_dqattach(dp, 0);
+	if (error)
+		return error;
 
 	/*
 	 * Start our first transaction of the day.
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index ca7c600..7928b99 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -2691,7 +2691,7 @@
 		 * Adjust the disk quota also. This was reserved
 		 * earlier.
 		 */
-		XFS_TRANS_MOD_DQUOT_BYINO(mp, ap->tp, ap->ip,
+		xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
 			ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT :
 					XFS_TRANS_DQ_RTBCOUNT, (long) ralen);
 	} else {
@@ -2995,7 +2995,7 @@
 		 * Adjust the disk quota also. This was reserved
 		 * earlier.
 		 */
-		XFS_TRANS_MOD_DQUOT_BYINO(mp, ap->tp, ap->ip,
+		xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
 			ap->wasdel ? XFS_TRANS_DQ_DELBCOUNT :
 					XFS_TRANS_DQ_BCOUNT,
 			(long) args.len);
@@ -3066,7 +3066,7 @@
 		return error;
 	xfs_bmap_add_free(cbno, 1, cur->bc_private.b.flist, mp);
 	ip->i_d.di_nblocks--;
-	XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
+	xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
 	xfs_trans_binval(tp, cbp);
 	if (cur->bc_bufs[0] == cbp)
 		cur->bc_bufs[0] = NULL;
@@ -3386,7 +3386,7 @@
 	 * Adjust quota data.
 	 */
 	if (qfield)
-		XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, qfield, (long)-nblks);
+		xfs_trans_mod_dquot_byino(tp, ip, qfield, (long)-nblks);
 
 	/*
 	 * Account for change in delayed indirect blocks.
@@ -3523,7 +3523,7 @@
 	*firstblock = cur->bc_private.b.firstblock = args.fsbno;
 	cur->bc_private.b.allocated++;
 	ip->i_d.di_nblocks++;
-	XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
+	xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
 	abp = xfs_btree_get_bufl(mp, tp, args.fsbno, 0);
 	/*
 	 * Fill in the child block.
@@ -3690,7 +3690,7 @@
 		XFS_BMAP_TRACE_POST_UPDATE("new", ip, 0, whichfork);
 		XFS_IFORK_NEXT_SET(ip, whichfork, 1);
 		ip->i_d.di_nblocks = 1;
-		XFS_TRANS_MOD_DQUOT_BYINO(args.mp, tp, ip,
+		xfs_trans_mod_dquot_byino(tp, ip,
 			XFS_TRANS_DQ_BCOUNT, 1L);
 		flags |= xfs_ilog_fext(whichfork);
 	} else {
@@ -4048,7 +4048,7 @@
 			XFS_TRANS_PERM_LOG_RES, XFS_ADDAFORK_LOG_COUNT)))
 		goto error0;
 	xfs_ilock(ip, XFS_ILOCK_EXCL);
-	error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, blks, 0, rsvd ?
+	error = xfs_trans_reserve_quota_nblks(tp, ip, blks, 0, rsvd ?
 			XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
 			XFS_QMOPT_RES_REGBLKS);
 	if (error) {
@@ -4983,10 +4983,11 @@
 				 * adjusted later.  We return if we haven't
 				 * allocated blocks already inside this loop.
 				 */
-				if ((error = XFS_TRANS_RESERVE_QUOTA_NBLKS(
-						mp, NULL, ip, (long)alen, 0,
+				error = xfs_trans_reserve_quota_nblks(
+						NULL, ip, (long)alen, 0,
 						rt ? XFS_QMOPT_RES_RTBLKS :
-						     XFS_QMOPT_RES_REGBLKS))) {
+						     XFS_QMOPT_RES_REGBLKS);
+				if (error) {
 					if (n == 0) {
 						*nmap = 0;
 						ASSERT(cur == NULL);
@@ -5035,8 +5036,8 @@
 					if (XFS_IS_QUOTA_ON(mp))
 						/* unreserve the blocks now */
 						(void)
-						XFS_TRANS_UNRESERVE_QUOTA_NBLKS(
-							mp, NULL, ip,
+						xfs_trans_unreserve_quota_nblks(
+							NULL, ip,
 							(long)alen, 0, rt ?
 							XFS_QMOPT_RES_RTBLKS :
 							XFS_QMOPT_RES_REGBLKS);
@@ -5691,14 +5692,14 @@
 				do_div(rtexts, mp->m_sb.sb_rextsize);
 				xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS,
 						(int64_t)rtexts, rsvd);
-				(void)XFS_TRANS_RESERVE_QUOTA_NBLKS(mp,
-					NULL, ip, -((long)del.br_blockcount), 0,
+				(void)xfs_trans_reserve_quota_nblks(NULL,
+					ip, -((long)del.br_blockcount), 0,
 					XFS_QMOPT_RES_RTBLKS);
 			} else {
 				xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS,
 						(int64_t)del.br_blockcount, rsvd);
-				(void)XFS_TRANS_RESERVE_QUOTA_NBLKS(mp,
-					NULL, ip, -((long)del.br_blockcount), 0,
+				(void)xfs_trans_reserve_quota_nblks(NULL,
+					ip, -((long)del.br_blockcount), 0,
 					XFS_QMOPT_RES_REGBLKS);
 			}
 			ip->i_delayed_blks -= del.br_blockcount;
@@ -6085,6 +6086,7 @@
 			break;
 	}
 
+	kmem_free(out);
 	return error;
 }
 
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c
index 0760d35..5c1ade0 100644
--- a/fs/xfs/xfs_bmap_btree.c
+++ b/fs/xfs/xfs_bmap_btree.c
@@ -590,7 +590,7 @@
 	cur->bc_private.b.allocated++;
 	cur->bc_private.b.ip->i_d.di_nblocks++;
 	xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE);
-	XFS_TRANS_MOD_DQUOT_BYINO(args.mp, args.tp, cur->bc_private.b.ip,
+	xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip,
 			XFS_TRANS_DQ_BCOUNT, 1L);
 
 	new->l = cpu_to_be64(args.fsbno);
@@ -618,7 +618,7 @@
 	ip->i_d.di_nblocks--;
 
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-	XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
+	xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
 	xfs_trans_binval(tp, bp);
 	return 0;
 }
diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c
index 6c87c8f..edf8bdf 100644
--- a/fs/xfs/xfs_filestream.c
+++ b/fs/xfs/xfs_filestream.c
@@ -542,10 +542,8 @@
 	 * waiting for the lock because someone else is waiting on the lock we
 	 * hold and we cannot drop that as we are in a transaction here.
 	 *
-	 * Lucky for us, this inversion is rarely a problem because it's a
-	 * directory inode that we are trying to lock here and that means the
-	 * only place that matters is xfs_sync_inodes() and SYNC_DELWRI is
-	 * used. i.e. freeze, remount-ro, quotasync or unmount.
+	 * Lucky for us, this inversion is not a problem because it's a
+	 * directory inode that we are trying to lock here.
 	 *
 	 * So, if we can't get the iolock without sleeping then just give up
 	 */
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
index f7c06fa..c4ea51b 100644
--- a/fs/xfs/xfs_fs.h
+++ b/fs/xfs/xfs_fs.h
@@ -239,10 +239,13 @@
  * Minimum and maximum sizes need for growth checks
  */
 #define XFS_MIN_AG_BLOCKS	64
-#define XFS_MIN_LOG_BLOCKS	512
-#define XFS_MAX_LOG_BLOCKS	(64 * 1024)
-#define XFS_MIN_LOG_BYTES	(256 * 1024)
-#define XFS_MAX_LOG_BYTES	(128 * 1024 * 1024)
+#define XFS_MIN_LOG_BLOCKS	512ULL
+#define XFS_MAX_LOG_BLOCKS	(1024 * 1024ULL)
+#define XFS_MIN_LOG_BYTES	(10 * 1024 * 1024ULL)
+
+/* keep the maximum size under 2^31 by a small amount */
+#define XFS_MAX_LOG_BYTES \
+	((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES)
 
 /*
  * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index 89b81ee..76c540f 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -18,6 +18,7 @@
 #include "xfs.h"
 #include "xfs_fs.h"
 #include "xfs_types.h"
+#include "xfs_acl.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_inum.h"
@@ -82,6 +83,7 @@
 	memset(&ip->i_d, 0, sizeof(xfs_icdinode_t));
 	ip->i_size = 0;
 	ip->i_new_size = 0;
+	xfs_inode_init_acls(ip);
 
 	/*
 	 * Initialize inode's trace buffers.
@@ -500,10 +502,7 @@
 	 * ilock one but will still hold the iolock.
 	 */
 	xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-	/*
-	 * Release dquots (and their references) if any.
-	 */
-	XFS_QM_DQDETACH(ip->i_mount, ip);
+	xfs_qm_dqdetach(ip);
 	xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
 
 	switch (ip->i_d.di_mode & S_IFMT) {
@@ -561,6 +560,7 @@
 	ASSERT(atomic_read(&ip->i_pincount) == 0);
 	ASSERT(!spin_is_locked(&ip->i_flags_lock));
 	ASSERT(completion_done(&ip->i_flush));
+	xfs_inode_clear_acls(ip);
 	kmem_zone_free(xfs_inode_zone, ip);
 }
 
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 123b20c..1f22d65 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -49,7 +49,6 @@
 #include "xfs_utils.h"
 #include "xfs_dir2_trace.h"
 #include "xfs_quota.h"
-#include "xfs_acl.h"
 #include "xfs_filestream.h"
 #include "xfs_vnodeops.h"
 
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index f879c1b..7701670 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -18,6 +18,7 @@
 #ifndef	__XFS_INODE_H__
 #define	__XFS_INODE_H__
 
+struct posix_acl;
 struct xfs_dinode;
 struct xfs_inode;
 
@@ -272,6 +273,11 @@
 	/* VFS inode */
 	struct inode		i_vnode;	/* embedded VFS inode */
 
+#ifdef CONFIG_XFS_POSIX_ACL
+	struct posix_acl	*i_acl;
+	struct posix_acl	*i_default_acl;
+#endif
+
 	/* Trace buffers per inode. */
 #ifdef XFS_INODE_TRACE
 	struct ktrace		*i_trace;	/* general inode trace */
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 5aaa2d7..67ae5555 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -42,7 +42,6 @@
 #include "xfs_error.h"
 #include "xfs_itable.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_space.h"
@@ -385,7 +384,7 @@
 	 * Make sure that the dquots are there. This doesn't hold
 	 * the ilock across a disk read.
 	 */
-	error = XFS_QM_DQATTACH(ip->i_mount, ip, XFS_QMOPT_ILOCKED);
+	error = xfs_qm_dqattach_locked(ip, 0);
 	if (error)
 		return XFS_ERROR(error);
 
@@ -444,8 +443,7 @@
 	if (error)
 		goto error_out;
 
-	error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip,
-					      qblocks, 0, quota_flag);
+	error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
 	if (error)
 		goto error1;
 
@@ -495,7 +493,7 @@
 
 error0:	/* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
 	xfs_bmap_cancel(&free_list);
-	XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag);
+	xfs_trans_unreserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
 
 error1:	/* Just cancel transaction */
 	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
@@ -582,7 +580,7 @@
 	 * Make sure that the dquots are there. This doesn't hold
 	 * the ilock across a disk read.
 	 */
-	error = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED);
+	error = xfs_qm_dqattach_locked(ip, 0);
 	if (error)
 		return XFS_ERROR(error);
 
@@ -684,7 +682,8 @@
 	/*
 	 * Make sure that the dquots are there.
 	 */
-	if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+	error = xfs_qm_dqattach(ip, 0);
+	if (error)
 		return XFS_ERROR(error);
 
 	offset_fsb = XFS_B_TO_FSBT(mp, offset);
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 7ba4501..47da2fb 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -1975,16 +1975,30 @@
 		error = 0;
 		if (buf_f->blf_flags &
 		   (XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) {
+			if (item->ri_buf[i].i_addr == NULL) {
+				cmn_err(CE_ALERT,
+					"XFS: NULL dquot in %s.", __func__);
+				goto next;
+			}
+			if (item->ri_buf[i].i_len < sizeof(xfs_dqblk_t)) {
+				cmn_err(CE_ALERT,
+					"XFS: dquot too small (%d) in %s.",
+					item->ri_buf[i].i_len, __func__);
+				goto next;
+			}
 			error = xfs_qm_dqcheck((xfs_disk_dquot_t *)
 					       item->ri_buf[i].i_addr,
 					       -1, 0, XFS_QMOPT_DOWARN,
 					       "dquot_buf_recover");
+			if (error)
+				goto next;
 		}
-		if (!error)
-			memcpy(xfs_buf_offset(bp,
-				(uint)bit << XFS_BLI_SHIFT),	/* dest */
-				item->ri_buf[i].i_addr,		/* source */
-				nbits<<XFS_BLI_SHIFT);		/* length */
+
+		memcpy(xfs_buf_offset(bp,
+			(uint)bit << XFS_BLI_SHIFT),	/* dest */
+			item->ri_buf[i].i_addr,		/* source */
+			nbits<<XFS_BLI_SHIFT);		/* length */
+ next:
 		i++;
 		bit += nbits;
 	}
@@ -2615,7 +2629,19 @@
 		return (0);
 
 	recddq = (xfs_disk_dquot_t *)item->ri_buf[1].i_addr;
-	ASSERT(recddq);
+
+	if (item->ri_buf[1].i_addr == NULL) {
+		cmn_err(CE_ALERT,
+			"XFS: NULL dquot in %s.", __func__);
+		return XFS_ERROR(EIO);
+	}
+	if (item->ri_buf[1].i_len < sizeof(xfs_dqblk_t)) {
+		cmn_err(CE_ALERT,
+			"XFS: dquot too small (%d) in %s.",
+			item->ri_buf[1].i_len, __func__);
+		return XFS_ERROR(EIO);
+	}
+
 	/*
 	 * This type of quotas was turned off, so ignore this record.
 	 */
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 65a9972..5c6f092 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -960,6 +960,53 @@
 }
 
 /*
+ * Clear the quotaflags in memory and in the superblock.
+ */
+int
+xfs_mount_reset_sbqflags(
+	struct xfs_mount	*mp)
+{
+	int			error;
+	struct xfs_trans	*tp;
+
+	mp->m_qflags = 0;
+
+	/*
+	 * It is OK to look at sb_qflags here in mount path,
+	 * without m_sb_lock.
+	 */
+	if (mp->m_sb.sb_qflags == 0)
+		return 0;
+	spin_lock(&mp->m_sb_lock);
+	mp->m_sb.sb_qflags = 0;
+	spin_unlock(&mp->m_sb_lock);
+
+	/*
+	 * If the fs is readonly, let the incore superblock run
+	 * with quotas off but don't flush the update out to disk
+	 */
+	if (mp->m_flags & XFS_MOUNT_RDONLY)
+		return 0;
+
+#ifdef QUOTADEBUG
+	xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
+#endif
+
+	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
+	error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
+				      XFS_DEFAULT_LOG_COUNT);
+	if (error) {
+		xfs_trans_cancel(tp, 0);
+		xfs_fs_cmn_err(CE_ALERT, mp,
+			"xfs_mount_reset_sbqflags: Superblock update failed!");
+		return error;
+	}
+
+	xfs_mod_sb(tp, XFS_SB_QFLAGS);
+	return xfs_trans_commit(tp, 0);
+}
+
+/*
  * This function does the following on an initial mount of a file system:
  *	- reads the superblock from disk and init the mount struct
  *	- if we're a 32-bit kernel, do a size check on the superblock
@@ -976,7 +1023,8 @@
 	xfs_sb_t	*sbp = &(mp->m_sb);
 	xfs_inode_t	*rip;
 	__uint64_t	resblks;
-	uint		quotamount, quotaflags;
+	uint		quotamount = 0;
+	uint		quotaflags = 0;
 	int		error = 0;
 
 	xfs_mount_common(mp, sbp);
@@ -1210,9 +1258,28 @@
 	/*
 	 * Initialise the XFS quota management subsystem for this mount
 	 */
-	error = XFS_QM_INIT(mp, &quotamount, &quotaflags);
-	if (error)
-		goto out_rtunmount;
+	if (XFS_IS_QUOTA_RUNNING(mp)) {
+		error = xfs_qm_newmount(mp, &quotamount, &quotaflags);
+		if (error)
+			goto out_rtunmount;
+	} else {
+		ASSERT(!XFS_IS_QUOTA_ON(mp));
+
+		/*
+		 * If a file system had quotas running earlier, but decided to
+		 * mount without -o uquota/pquota/gquota options, revoke the
+		 * quotachecked license.
+		 */
+		if (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT) {
+			cmn_err(CE_NOTE,
+				"XFS: resetting qflags for filesystem %s",
+				mp->m_fsname);
+
+			error = xfs_mount_reset_sbqflags(mp);
+			if (error)
+				return error;
+		}
+	}
 
 	/*
 	 * Finish recovering the file system.  This part needed to be
@@ -1228,9 +1295,19 @@
 	/*
 	 * Complete the quota initialisation, post-log-replay component.
 	 */
-	error = XFS_QM_MOUNT(mp, quotamount, quotaflags);
-	if (error)
-		goto out_rtunmount;
+	if (quotamount) {
+		ASSERT(mp->m_qflags == 0);
+		mp->m_qflags = quotaflags;
+
+		xfs_qm_mount_quotas(mp);
+	}
+
+#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
+	if (XFS_IS_QUOTA_ON(mp))
+		xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas turned on");
+	else
+		xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas not turned on");
+#endif
 
 	/*
 	 * Now we are mounted, reserve a small amount of unused space for
@@ -1279,12 +1356,7 @@
 	__uint64_t		resblks;
 	int			error;
 
-	/*
-	 * Release dquot that rootinode, rbmino and rsumino might be holding,
-	 * and release the quota inodes.
-	 */
-	XFS_QM_UNMOUNT(mp);
-
+	xfs_qm_unmount_quotas(mp);
 	xfs_rtunmount_inodes(mp);
 	IRELE(mp->m_rootip);
 
@@ -1299,12 +1371,9 @@
 	 * need to force the log first.
 	 */
 	xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
-	xfs_reclaim_inodes(mp, 0, XFS_IFLUSH_ASYNC);
+	xfs_reclaim_inodes(mp, XFS_IFLUSH_ASYNC);
 
-	XFS_QM_DQPURGEALL(mp, XFS_QMOPT_QUOTALL | XFS_QMOPT_UMOUNTING);
-
-	if (mp->m_quotainfo)
-		XFS_QM_DONE(mp);
+	xfs_qm_unmount(mp);
 
 	/*
 	 * Flush out the log synchronously so that we know for sure
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index d6a6439..a512238 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -64,6 +64,8 @@
 struct xfs_mru_cache;
 struct xfs_nameops;
 struct xfs_ail;
+struct xfs_quotainfo;
+
 
 /*
  * Prototypes and functions for the Data Migration subsystem.
@@ -107,86 +109,6 @@
 	(*(mp)->m_dm_ops->xfs_send_unmount)(mp,ip,right,mode,rval,fl)
 
 
-/*
- * Prototypes and functions for the Quota Management subsystem.
- */
-
-struct xfs_dquot;
-struct xfs_dqtrxops;
-struct xfs_quotainfo;
-
-typedef int	(*xfs_qminit_t)(struct xfs_mount *, uint *, uint *);
-typedef int	(*xfs_qmmount_t)(struct xfs_mount *, uint, uint);
-typedef void	(*xfs_qmunmount_t)(struct xfs_mount *);
-typedef void	(*xfs_qmdone_t)(struct xfs_mount *);
-typedef void	(*xfs_dqrele_t)(struct xfs_dquot *);
-typedef int	(*xfs_dqattach_t)(struct xfs_inode *, uint);
-typedef void	(*xfs_dqdetach_t)(struct xfs_inode *);
-typedef int	(*xfs_dqpurgeall_t)(struct xfs_mount *, uint);
-typedef int	(*xfs_dqvopalloc_t)(struct xfs_mount *,
-			struct xfs_inode *, uid_t, gid_t, prid_t, uint,
-			struct xfs_dquot **, struct xfs_dquot **);
-typedef void	(*xfs_dqvopcreate_t)(struct xfs_trans *, struct xfs_inode *,
-			struct xfs_dquot *, struct xfs_dquot *);
-typedef int	(*xfs_dqvoprename_t)(struct xfs_inode **);
-typedef struct xfs_dquot * (*xfs_dqvopchown_t)(
-			struct xfs_trans *, struct xfs_inode *,
-			struct xfs_dquot **, struct xfs_dquot *);
-typedef int	(*xfs_dqvopchownresv_t)(struct xfs_trans *, struct xfs_inode *,
-			struct xfs_dquot *, struct xfs_dquot *, uint);
-typedef void	(*xfs_dqstatvfs_t)(struct xfs_inode *, struct kstatfs *);
-typedef int	(*xfs_dqsync_t)(struct xfs_mount *, int flags);
-
-typedef struct xfs_qmops {
-	xfs_qminit_t		xfs_qminit;
-	xfs_qmdone_t		xfs_qmdone;
-	xfs_qmmount_t		xfs_qmmount;
-	xfs_qmunmount_t		xfs_qmunmount;
-	xfs_dqrele_t		xfs_dqrele;
-	xfs_dqattach_t		xfs_dqattach;
-	xfs_dqdetach_t		xfs_dqdetach;
-	xfs_dqpurgeall_t	xfs_dqpurgeall;
-	xfs_dqvopalloc_t	xfs_dqvopalloc;
-	xfs_dqvopcreate_t	xfs_dqvopcreate;
-	xfs_dqvoprename_t	xfs_dqvoprename;
-	xfs_dqvopchown_t	xfs_dqvopchown;
-	xfs_dqvopchownresv_t	xfs_dqvopchownresv;
-	xfs_dqstatvfs_t		xfs_dqstatvfs;
-	xfs_dqsync_t		xfs_dqsync;
-	struct xfs_dqtrxops	*xfs_dqtrxops;
-} xfs_qmops_t;
-
-#define XFS_QM_INIT(mp, mnt, fl) \
-	(*(mp)->m_qm_ops->xfs_qminit)(mp, mnt, fl)
-#define XFS_QM_MOUNT(mp, mnt, fl) \
-	(*(mp)->m_qm_ops->xfs_qmmount)(mp, mnt, fl)
-#define XFS_QM_UNMOUNT(mp) \
-	(*(mp)->m_qm_ops->xfs_qmunmount)(mp)
-#define XFS_QM_DONE(mp) \
-	(*(mp)->m_qm_ops->xfs_qmdone)(mp)
-#define XFS_QM_DQRELE(mp, dq) \
-	(*(mp)->m_qm_ops->xfs_dqrele)(dq)
-#define XFS_QM_DQATTACH(mp, ip, fl) \
-	(*(mp)->m_qm_ops->xfs_dqattach)(ip, fl)
-#define XFS_QM_DQDETACH(mp, ip) \
-	(*(mp)->m_qm_ops->xfs_dqdetach)(ip)
-#define XFS_QM_DQPURGEALL(mp, fl) \
-	(*(mp)->m_qm_ops->xfs_dqpurgeall)(mp, fl)
-#define XFS_QM_DQVOPALLOC(mp, ip, uid, gid, prid, fl, dq1, dq2) \
-	(*(mp)->m_qm_ops->xfs_dqvopalloc)(mp, ip, uid, gid, prid, fl, dq1, dq2)
-#define XFS_QM_DQVOPCREATE(mp, tp, ip, dq1, dq2) \
-	(*(mp)->m_qm_ops->xfs_dqvopcreate)(tp, ip, dq1, dq2)
-#define XFS_QM_DQVOPRENAME(mp, ip) \
-	(*(mp)->m_qm_ops->xfs_dqvoprename)(ip)
-#define XFS_QM_DQVOPCHOWN(mp, tp, ip, dqp, dq) \
-	(*(mp)->m_qm_ops->xfs_dqvopchown)(tp, ip, dqp, dq)
-#define XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, dq1, dq2, fl) \
-	(*(mp)->m_qm_ops->xfs_dqvopchownresv)(tp, ip, dq1, dq2, fl)
-#define XFS_QM_DQSTATVFS(ip, statp) \
-	(*(ip)->i_mount->m_qm_ops->xfs_dqstatvfs)(ip, statp)
-#define XFS_QM_DQSYNC(mp, flags) \
-	(*(mp)->m_qm_ops->xfs_dqsync)(mp, flags)
-
 #ifdef HAVE_PERCPU_SB
 
 /*
@@ -510,8 +432,6 @@
 
 extern int	xfs_dmops_get(struct xfs_mount *);
 extern void	xfs_dmops_put(struct xfs_mount *);
-extern int	xfs_qmops_get(struct xfs_mount *);
-extern void	xfs_qmops_put(struct xfs_mount *);
 
 extern struct xfs_dmops xfs_dmcore_xfs;
 
diff --git a/fs/xfs/xfs_qmops.c b/fs/xfs/xfs_qmops.c
deleted file mode 100644
index e101790..0000000
--- a/fs/xfs/xfs_qmops.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 2000-2005 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_types.h"
-#include "xfs_log.h"
-#include "xfs_inum.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
-#include "xfs_mount.h"
-#include "xfs_quota.h"
-#include "xfs_error.h"
-
-
-STATIC struct xfs_dquot *
-xfs_dqvopchown_default(
-	struct xfs_trans	*tp,
-	struct xfs_inode	*ip,
-	struct xfs_dquot	**dqp,
-	struct xfs_dquot	*dq)
-{
-	return NULL;
-}
-
-/*
- * Clear the quotaflags in memory and in the superblock.
- */
-int
-xfs_mount_reset_sbqflags(xfs_mount_t *mp)
-{
-	int			error;
-	xfs_trans_t		*tp;
-
-	mp->m_qflags = 0;
-	/*
-	 * It is OK to look at sb_qflags here in mount path,
-	 * without m_sb_lock.
-	 */
-	if (mp->m_sb.sb_qflags == 0)
-		return 0;
-	spin_lock(&mp->m_sb_lock);
-	mp->m_sb.sb_qflags = 0;
-	spin_unlock(&mp->m_sb_lock);
-
-	/*
-	 * if the fs is readonly, let the incore superblock run
-	 * with quotas off but don't flush the update out to disk
-	 */
-	if (mp->m_flags & XFS_MOUNT_RDONLY)
-		return 0;
-#ifdef QUOTADEBUG
-	xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
-#endif
-	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
-	if ((error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
-				      XFS_DEFAULT_LOG_COUNT))) {
-		xfs_trans_cancel(tp, 0);
-		xfs_fs_cmn_err(CE_ALERT, mp,
-			"xfs_mount_reset_sbqflags: Superblock update failed!");
-		return error;
-	}
-	xfs_mod_sb(tp, XFS_SB_QFLAGS);
-	error = xfs_trans_commit(tp, 0);
-	return error;
-}
-
-STATIC int
-xfs_noquota_init(
-	xfs_mount_t	*mp,
-	uint		*needquotamount,
-	uint		*quotaflags)
-{
-	int		error = 0;
-
-	*quotaflags = 0;
-	*needquotamount = B_FALSE;
-
-	ASSERT(!XFS_IS_QUOTA_ON(mp));
-
-	/*
-	 * If a file system had quotas running earlier, but decided to
-	 * mount without -o uquota/pquota/gquota options, revoke the
-	 * quotachecked license.
-	 */
-	if (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT) {
-		cmn_err(CE_NOTE,
-                        "XFS resetting qflags for filesystem %s",
-                        mp->m_fsname);
-
-		error = xfs_mount_reset_sbqflags(mp);
-	}
-	return error;
-}
-
-static struct xfs_qmops xfs_qmcore_stub = {
-	.xfs_qminit		= (xfs_qminit_t) xfs_noquota_init,
-	.xfs_qmdone		= (xfs_qmdone_t) fs_noerr,
-	.xfs_qmmount		= (xfs_qmmount_t) fs_noerr,
-	.xfs_qmunmount		= (xfs_qmunmount_t) fs_noerr,
-	.xfs_dqrele		= (xfs_dqrele_t) fs_noerr,
-	.xfs_dqattach		= (xfs_dqattach_t) fs_noerr,
-	.xfs_dqdetach		= (xfs_dqdetach_t) fs_noerr,
-	.xfs_dqpurgeall		= (xfs_dqpurgeall_t) fs_noerr,
-	.xfs_dqvopalloc		= (xfs_dqvopalloc_t) fs_noerr,
-	.xfs_dqvopcreate	= (xfs_dqvopcreate_t) fs_noerr,
-	.xfs_dqvoprename	= (xfs_dqvoprename_t) fs_noerr,
-	.xfs_dqvopchown		= xfs_dqvopchown_default,
-	.xfs_dqvopchownresv	= (xfs_dqvopchownresv_t) fs_noerr,
-	.xfs_dqstatvfs		= (xfs_dqstatvfs_t) fs_noval,
-	.xfs_dqsync		= (xfs_dqsync_t) fs_noerr,
-};
-
-int
-xfs_qmops_get(struct xfs_mount *mp)
-{
-	if (XFS_IS_QUOTA_RUNNING(mp)) {
-#ifdef CONFIG_XFS_QUOTA
-		mp->m_qm_ops = &xfs_qmcore_xfs;
-#else
-		cmn_err(CE_WARN,
-			"XFS: qouta support not available in this kernel.");
-		return EINVAL;
-#endif
-	} else {
-		mp->m_qm_ops = &xfs_qmcore_stub;
-	}
-
-	return 0;
-}
-
-void
-xfs_qmops_put(struct xfs_mount *mp)
-{
-}
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index f5d1202..3ec91ac 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -197,7 +197,6 @@
 #define XFS_QMOPT_UMOUNTING	0x0000100 /* filesys is being unmounted */
 #define XFS_QMOPT_DOLOG		0x0000200 /* log buf changes (in quotacheck) */
 #define XFS_QMOPT_DOWARN        0x0000400 /* increase warning cnt if needed */
-#define XFS_QMOPT_ILOCKED	0x0000800 /* inode is already locked (excl) */
 #define XFS_QMOPT_DQREPAIR	0x0001000 /* repair dquot if damaged */
 #define XFS_QMOPT_GQUOTA	0x0002000 /* group dquot requested */
 #define XFS_QMOPT_ENOSPC	0x0004000 /* enospc instead of edquot (prj) */
@@ -302,69 +301,79 @@
 	long		qt_delrtb_delta;  /* delayed RT blk count changes */
 } xfs_dqtrx_t;
 
-/*
- * Dquot transaction functions, used if quota is enabled.
- */
-typedef void	(*qo_dup_dqinfo_t)(struct xfs_trans *, struct xfs_trans *);
-typedef void	(*qo_mod_dquot_byino_t)(struct xfs_trans *,
-				struct xfs_inode *, uint, long);
-typedef void	(*qo_free_dqinfo_t)(struct xfs_trans *);
-typedef void	(*qo_apply_dquot_deltas_t)(struct xfs_trans *);
-typedef void	(*qo_unreserve_and_mod_dquots_t)(struct xfs_trans *);
-typedef int	(*qo_reserve_quota_nblks_t)(
-				struct xfs_trans *, struct xfs_mount *,
-				struct xfs_inode *, long, long, uint);
-typedef int	(*qo_reserve_quota_bydquots_t)(
-				struct xfs_trans *, struct xfs_mount *,
-				struct xfs_dquot *, struct xfs_dquot *,
-				long, long, uint);
-typedef struct xfs_dqtrxops {
-	qo_dup_dqinfo_t			qo_dup_dqinfo;
-	qo_free_dqinfo_t		qo_free_dqinfo;
-	qo_mod_dquot_byino_t		qo_mod_dquot_byino;
-	qo_apply_dquot_deltas_t		qo_apply_dquot_deltas;
-	qo_reserve_quota_nblks_t	qo_reserve_quota_nblks;
-	qo_reserve_quota_bydquots_t	qo_reserve_quota_bydquots;
-	qo_unreserve_and_mod_dquots_t	qo_unreserve_and_mod_dquots;
-} xfs_dqtrxops_t;
+#ifdef CONFIG_XFS_QUOTA
+extern void xfs_trans_dup_dqinfo(struct xfs_trans *, struct xfs_trans *);
+extern void xfs_trans_free_dqinfo(struct xfs_trans *);
+extern void xfs_trans_mod_dquot_byino(struct xfs_trans *, struct xfs_inode *,
+		uint, long);
+extern void xfs_trans_apply_dquot_deltas(struct xfs_trans *);
+extern void xfs_trans_unreserve_and_mod_dquots(struct xfs_trans *);
+extern int xfs_trans_reserve_quota_nblks(struct xfs_trans *,
+		struct xfs_inode *, long, long, uint);
+extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *,
+		struct xfs_mount *, struct xfs_dquot *,
+		struct xfs_dquot *, long, long, uint);
 
-#define XFS_DQTRXOP(mp, tp, op, args...) \
-		((mp)->m_qm_ops->xfs_dqtrxops ? \
-		((mp)->m_qm_ops->xfs_dqtrxops->op)(tp, ## args) : 0)
+extern int xfs_qm_vop_dqalloc(struct xfs_inode *, uid_t, gid_t, prid_t, uint,
+		struct xfs_dquot **, struct xfs_dquot **);
+extern void xfs_qm_vop_create_dqattach(struct xfs_trans *, struct xfs_inode *,
+		struct xfs_dquot *, struct xfs_dquot *);
+extern int xfs_qm_vop_rename_dqattach(struct xfs_inode **);
+extern struct xfs_dquot *xfs_qm_vop_chown(struct xfs_trans *,
+		struct xfs_inode *, struct xfs_dquot **, struct xfs_dquot *);
+extern int xfs_qm_vop_chown_reserve(struct xfs_trans *, struct xfs_inode *,
+		struct xfs_dquot *, struct xfs_dquot *, uint);
+extern int xfs_qm_dqattach(struct xfs_inode *, uint);
+extern int xfs_qm_dqattach_locked(struct xfs_inode *, uint);
+extern void xfs_qm_dqdetach(struct xfs_inode *);
+extern void xfs_qm_dqrele(struct xfs_dquot *);
+extern void xfs_qm_statvfs(struct xfs_inode *, struct kstatfs *);
+extern int xfs_qm_sync(struct xfs_mount *, int);
+extern int xfs_qm_newmount(struct xfs_mount *, uint *, uint *);
+extern void xfs_qm_mount_quotas(struct xfs_mount *);
+extern void xfs_qm_unmount(struct xfs_mount *);
+extern void xfs_qm_unmount_quotas(struct xfs_mount *);
 
-#define XFS_DQTRXOP_VOID(mp, tp, op, args...) \
-		((mp)->m_qm_ops->xfs_dqtrxops ? \
-		((mp)->m_qm_ops->xfs_dqtrxops->op)(tp, ## args) : (void)0)
+#else
+static inline int
+xfs_qm_vop_dqalloc(struct xfs_inode *ip, uid_t uid, gid_t gid, prid_t prid,
+		uint flags, struct xfs_dquot **udqp, struct xfs_dquot **gdqp)
+{
+	*udqp = NULL;
+	*gdqp = NULL;
+	return 0;
+}
+#define xfs_trans_dup_dqinfo(tp, tp2)
+#define xfs_trans_free_dqinfo(tp)
+#define xfs_trans_mod_dquot_byino(tp, ip, fields, delta)
+#define xfs_trans_apply_dquot_deltas(tp)
+#define xfs_trans_unreserve_and_mod_dquots(tp)
+#define xfs_trans_reserve_quota_nblks(tp, ip, nblks, ninos, flags)	(0)
+#define xfs_trans_reserve_quota_bydquots(tp, mp, u, g, nb, ni, fl)	(0)
+#define xfs_qm_vop_create_dqattach(tp, ip, u, g)
+#define xfs_qm_vop_rename_dqattach(it)					(0)
+#define xfs_qm_vop_chown(tp, ip, old, new)				(NULL)
+#define xfs_qm_vop_chown_reserve(tp, ip, u, g, fl)			(0)
+#define xfs_qm_dqattach(ip, fl)						(0)
+#define xfs_qm_dqattach_locked(ip, fl)					(0)
+#define xfs_qm_dqdetach(ip)
+#define xfs_qm_dqrele(d)
+#define xfs_qm_statvfs(ip, s)
+#define xfs_qm_sync(mp, fl)						(0)
+#define xfs_qm_newmount(mp, a, b)					(0)
+#define xfs_qm_mount_quotas(mp)
+#define xfs_qm_unmount(mp)
+#define xfs_qm_unmount_quotas(mp)					(0)
+#endif /* CONFIG_XFS_QUOTA */
 
-#define XFS_TRANS_DUP_DQINFO(mp, otp, ntp) \
-	XFS_DQTRXOP_VOID(mp, otp, qo_dup_dqinfo, ntp)
-#define XFS_TRANS_FREE_DQINFO(mp, tp) \
-	XFS_DQTRXOP_VOID(mp, tp, qo_free_dqinfo)
-#define XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, field, delta) \
-	XFS_DQTRXOP_VOID(mp, tp, qo_mod_dquot_byino, ip, field, delta)
-#define XFS_TRANS_APPLY_DQUOT_DELTAS(mp, tp) \
-	XFS_DQTRXOP_VOID(mp, tp, qo_apply_dquot_deltas)
-#define XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, ninos, fl) \
-	XFS_DQTRXOP(mp, tp, qo_reserve_quota_nblks, mp, ip, nblks, ninos, fl)
-#define XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, nb, ni, fl) \
-	XFS_DQTRXOP(mp, tp, qo_reserve_quota_bydquots, mp, ud, gd, nb, ni, fl)
-#define XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp) \
-	XFS_DQTRXOP_VOID(mp, tp, qo_unreserve_and_mod_dquots)
-
-#define XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, ninos, flags) \
-	XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, -(nblks), -(ninos), flags)
-#define XFS_TRANS_RESERVE_QUOTA(mp, tp, ud, gd, nb, ni, f) \
-	XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, nb, ni, \
-				f | XFS_QMOPT_RES_REGBLKS)
-#define XFS_TRANS_UNRESERVE_QUOTA(mp, tp, ud, gd, nb, ni, f) \
-	XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, -(nb), -(ni), \
+#define xfs_trans_unreserve_quota_nblks(tp, ip, nblks, ninos, flags) \
+	xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), -(ninos), flags)
+#define xfs_trans_reserve_quota(tp, mp, ud, gd, nb, ni, f) \
+	xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, nb, ni, \
 				f | XFS_QMOPT_RES_REGBLKS)
 
 extern int xfs_qm_dqcheck(xfs_disk_dquot_t *, xfs_dqid_t, uint, uint, char *);
 extern int xfs_mount_reset_sbqflags(struct xfs_mount *);
 
-extern struct xfs_qmops xfs_qmcore_xfs;
-
 #endif	/* __KERNEL__ */
-
 #endif	/* __XFS_QUOTA_H__ */
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c
index 58f85e9..b81deea 100644
--- a/fs/xfs/xfs_rename.c
+++ b/fs/xfs/xfs_rename.c
@@ -166,7 +166,8 @@
 	/*
 	 * Attach the dquots to the inodes
 	 */
-	if ((error = XFS_QM_DQVOPRENAME(mp, inodes))) {
+	error = xfs_qm_vop_rename_dqattach(inodes);
+	if (error) {
 		xfs_trans_cancel(tp, cancel_flags);
 		goto std_return;
 	}
diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c
index 36f3a21..fea6861 100644
--- a/fs/xfs/xfs_rw.c
+++ b/fs/xfs/xfs_rw.c
@@ -41,7 +41,6 @@
 #include "xfs_ialloc.h"
 #include "xfs_attr.h"
 #include "xfs_bmap.h"
-#include "xfs_acl.h"
 #include "xfs_error.h"
 #include "xfs_buf_item.h"
 #include "xfs_rw.h"
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index bcc39d3..66b8493 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -297,7 +297,7 @@
 	tp->t_rtx_res = tp->t_rtx_res_used;
 	ntp->t_pflags = tp->t_pflags;
 
-	XFS_TRANS_DUP_DQINFO(tp->t_mountp, tp, ntp);
+	xfs_trans_dup_dqinfo(tp, ntp);
 
 	atomic_inc(&tp->t_mountp->m_active_trans);
 	return ntp;
@@ -829,7 +829,7 @@
 		 * means is that we have some (non-persistent) quota
 		 * reservations that need to be unreserved.
 		 */
-		XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp);
+		xfs_trans_unreserve_and_mod_dquots(tp);
 		if (tp->t_ticket) {
 			commit_lsn = xfs_log_done(mp, tp->t_ticket,
 							NULL, log_flags);
@@ -848,10 +848,9 @@
 	/*
 	 * If we need to update the superblock, then do it now.
 	 */
-	if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
+	if (tp->t_flags & XFS_TRANS_SB_DIRTY)
 		xfs_trans_apply_sb_deltas(tp);
-	}
-	XFS_TRANS_APPLY_DQUOT_DELTAS(mp, tp);
+	xfs_trans_apply_dquot_deltas(tp);
 
 	/*
 	 * Ask each log item how many log_vector entries it will
@@ -1056,7 +1055,7 @@
 	}
 
 	xfs_trans_unreserve_and_mod_sb(tp);
-	XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(tp->t_mountp, tp);
+	xfs_trans_unreserve_and_mod_dquots(tp);
 
 	xfs_trans_free_items(tp, flags);
 	xfs_trans_free_busy(tp);
@@ -1181,7 +1180,7 @@
 	}
 #endif
 	xfs_trans_unreserve_and_mod_sb(tp);
-	XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp);
+	xfs_trans_unreserve_and_mod_dquots(tp);
 
 	if (tp->t_ticket) {
 		if (flags & XFS_TRANS_RELEASE_LOG_RES) {
@@ -1211,7 +1210,7 @@
 	xfs_trans_t	*tp)
 {
 	atomic_dec(&tp->t_mountp->m_active_trans);
-	XFS_TRANS_FREE_DQINFO(tp->t_mountp, tp);
+	xfs_trans_free_dqinfo(tp);
 	kmem_zone_free(xfs_trans_zone, tp);
 }
 
diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c
index 79b9e5e..4d88616 100644
--- a/fs/xfs/xfs_utils.c
+++ b/fs/xfs/xfs_utils.c
@@ -166,7 +166,7 @@
 			xfs_buf_relse(ialloc_context);
 			if (dqinfo) {
 				tp->t_dqinfo = dqinfo;
-				XFS_TRANS_FREE_DQINFO(tp->t_mountp, tp);
+				xfs_trans_free_dqinfo(tp);
 			}
 			*tpp = ntp;
 			*ipp = NULL;
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 19cf90a..c4eca5e 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -42,6 +42,7 @@
 #include "xfs_ialloc.h"
 #include "xfs_alloc.h"
 #include "xfs_bmap.h"
+#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_rw.h"
 #include "xfs_error.h"
@@ -118,7 +119,7 @@
 		 */
 		ASSERT(udqp == NULL);
 		ASSERT(gdqp == NULL);
-		code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, ip->i_d.di_projid,
+		code = xfs_qm_vop_dqalloc(ip, uid, gid, ip->i_d.di_projid,
 					 qflags, &udqp, &gdqp);
 		if (code)
 			return code;
@@ -180,10 +181,11 @@
 		 * Do a quota reservation only if uid/gid is actually
 		 * going to change.
 		 */
-		if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
-		    (XFS_IS_GQUOTA_ON(mp) && igid != gid)) {
+		if (XFS_IS_QUOTA_RUNNING(mp) &&
+		    ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
+		     (XFS_IS_GQUOTA_ON(mp) && igid != gid))) {
 			ASSERT(tp);
-			code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,
+			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
 						capable(CAP_FOWNER) ?
 						XFS_QMOPT_FORCE_RES : 0);
 			if (code)	/* out of quota */
@@ -217,7 +219,7 @@
 		/*
 		 * Make sure that the dquots are attached to the inode.
 		 */
-		code = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED);
+		code = xfs_qm_dqattach_locked(ip, 0);
 		if (code)
 			goto error_return;
 
@@ -351,21 +353,21 @@
 		 * in the transaction.
 		 */
 		if (iuid != uid) {
-			if (XFS_IS_UQUOTA_ON(mp)) {
+			if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_UQUOTA_ON(mp)) {
 				ASSERT(mask & ATTR_UID);
 				ASSERT(udqp);
-				olddquot1 = XFS_QM_DQVOPCHOWN(mp, tp, ip,
+				olddquot1 = xfs_qm_vop_chown(tp, ip,
 							&ip->i_udquot, udqp);
 			}
 			ip->i_d.di_uid = uid;
 			inode->i_uid = uid;
 		}
 		if (igid != gid) {
-			if (XFS_IS_GQUOTA_ON(mp)) {
+			if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_GQUOTA_ON(mp)) {
 				ASSERT(!XFS_IS_PQUOTA_ON(mp));
 				ASSERT(mask & ATTR_GID);
 				ASSERT(gdqp);
-				olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip,
+				olddquot2 = xfs_qm_vop_chown(tp, ip,
 							&ip->i_gdquot, gdqp);
 			}
 			ip->i_d.di_gid = gid;
@@ -461,13 +463,25 @@
 	/*
 	 * Release any dquot(s) the inode had kept before chown.
 	 */
-	XFS_QM_DQRELE(mp, olddquot1);
-	XFS_QM_DQRELE(mp, olddquot2);
-	XFS_QM_DQRELE(mp, udqp);
-	XFS_QM_DQRELE(mp, gdqp);
+	xfs_qm_dqrele(olddquot1);
+	xfs_qm_dqrele(olddquot2);
+	xfs_qm_dqrele(udqp);
+	xfs_qm_dqrele(gdqp);
 
-	if (code) {
+	if (code)
 		return code;
+
+	/*
+	 * XXX(hch): Updating the ACL entries is not atomic vs the i_mode
+	 * 	     update.  We could avoid this with linked transactions
+	 * 	     and passing down the transaction pointer all the way
+	 *	     to attr_set.  No previous user of the generic
+	 * 	     Posix ACL code seems to care about this issue either.
+	 */
+	if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) {
+		code = -xfs_acl_chmod(inode);
+		if (code)
+			return XFS_ERROR(code);
 	}
 
 	if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE) &&
@@ -482,8 +496,8 @@
 	commit_flags |= XFS_TRANS_ABORT;
 	/* FALLTHROUGH */
  error_return:
-	XFS_QM_DQRELE(mp, udqp);
-	XFS_QM_DQRELE(mp, gdqp);
+	xfs_qm_dqrele(udqp);
+	xfs_qm_dqrele(gdqp);
 	if (tp) {
 		xfs_trans_cancel(tp, commit_flags);
 	}
@@ -739,7 +753,8 @@
 		/*
 		 * Attach the dquots to the inode up front.
 		 */
-		if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+		error = xfs_qm_dqattach(ip, 0);
+		if (error)
 			return error;
 
 		/*
@@ -1181,7 +1196,8 @@
 
 	ASSERT(ip->i_d.di_nlink == 0);
 
-	if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+	error = xfs_qm_dqattach(ip, 0);
+	if (error)
 		return VN_INACTIVE_CACHE;
 
 	tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
@@ -1307,7 +1323,7 @@
 		/*
 		 * Credit the quota account(s). The inode is gone.
 		 */
-		XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_ICOUNT, -1);
+		xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT, -1);
 
 		/*
 		 * Just ignore errors at this point.  There is nothing we can
@@ -1323,11 +1339,11 @@
 			xfs_fs_cmn_err(CE_NOTE, mp, "xfs_inactive: "
 				"xfs_trans_commit() returned error %d", error);
 	}
+
 	/*
 	 * Release the dquots held by inode, if any.
 	 */
-	XFS_QM_DQDETACH(mp, ip);
-
+	xfs_qm_dqdetach(ip);
 	xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
 
  out:
@@ -1427,8 +1443,7 @@
 	/*
 	 * Make sure that we have allocated dquot(s) on disk.
 	 */
-	error = XFS_QM_DQVOPALLOC(mp, dp,
-			current_fsuid(), current_fsgid(), prid,
+	error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
 			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
 	if (error)
 		goto std_return;
@@ -1489,7 +1504,7 @@
 	/*
 	 * Reserve disk quota and the inode.
 	 */
-	error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
+	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
 	if (error)
 		goto out_trans_cancel;
 
@@ -1561,7 +1576,7 @@
 	 * These ids of the inode couldn't have changed since the new
 	 * inode has been locked ever since it was created.
 	 */
-	XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp);
+	xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
 
 	/*
 	 * xfs_trans_commit normally decrements the vnode ref count
@@ -1580,8 +1595,8 @@
 		goto out_dqrele;
 	}
 
-	XFS_QM_DQRELE(mp, udqp);
-	XFS_QM_DQRELE(mp, gdqp);
+	xfs_qm_dqrele(udqp);
+	xfs_qm_dqrele(gdqp);
 
 	*ipp = ip;
 
@@ -1602,8 +1617,8 @@
  out_trans_cancel:
 	xfs_trans_cancel(tp, cancel_flags);
  out_dqrele:
-	XFS_QM_DQRELE(mp, udqp);
-	XFS_QM_DQRELE(mp, gdqp);
+	xfs_qm_dqrele(udqp);
+	xfs_qm_dqrele(gdqp);
 
 	if (unlock_dp_on_error)
 		xfs_iunlock(dp, XFS_ILOCK_EXCL);
@@ -1837,11 +1852,11 @@
 			return error;
 	}
 
-	error = XFS_QM_DQATTACH(mp, dp, 0);
+	error = xfs_qm_dqattach(dp, 0);
 	if (error)
 		goto std_return;
 
-	error = XFS_QM_DQATTACH(mp, ip, 0);
+	error = xfs_qm_dqattach(ip, 0);
 	if (error)
 		goto std_return;
 
@@ -2028,11 +2043,11 @@
 
 	/* Return through std_return after this point. */
 
-	error = XFS_QM_DQATTACH(mp, sip, 0);
+	error = xfs_qm_dqattach(sip, 0);
 	if (error)
 		goto std_return;
 
-	error = XFS_QM_DQATTACH(mp, tdp, 0);
+	error = xfs_qm_dqattach(tdp, 0);
 	if (error)
 		goto std_return;
 
@@ -2205,8 +2220,7 @@
 	/*
 	 * Make sure that we have allocated dquot(s) on disk.
 	 */
-	error = XFS_QM_DQVOPALLOC(mp, dp,
-			current_fsuid(), current_fsgid(), prid,
+	error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
 			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
 	if (error)
 		goto std_return;
@@ -2248,7 +2262,7 @@
 	/*
 	 * Reserve disk quota : blocks and inode.
 	 */
-	error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
+	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
 	if (error)
 		goto error_return;
 
@@ -2288,7 +2302,7 @@
 	/*
 	 * Also attach the dquot(s) to it, if applicable.
 	 */
-	XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp);
+	xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
 
 	if (resblks)
 		resblks -= XFS_IALLOC_SPACE_RES(mp);
@@ -2376,8 +2390,8 @@
 		goto error2;
 	}
 	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-	XFS_QM_DQRELE(mp, udqp);
-	XFS_QM_DQRELE(mp, gdqp);
+	xfs_qm_dqrele(udqp);
+	xfs_qm_dqrele(gdqp);
 
 	/* Fall through to std_return with error = 0 or errno from
 	 * xfs_trans_commit	*/
@@ -2401,8 +2415,8 @@
 	cancel_flags |= XFS_TRANS_ABORT;
  error_return:
 	xfs_trans_cancel(tp, cancel_flags);
-	XFS_QM_DQRELE(mp, udqp);
-	XFS_QM_DQRELE(mp, gdqp);
+	xfs_qm_dqrele(udqp);
+	xfs_qm_dqrele(gdqp);
 
 	if (unlock_dp_on_error)
 		xfs_iunlock(dp, XFS_ILOCK_EXCL);
@@ -2541,7 +2555,8 @@
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return XFS_ERROR(EIO);
 
-	if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+	error = xfs_qm_dqattach(ip, 0);
+	if (error)
 		return error;
 
 	if (len <= 0)
@@ -2628,8 +2643,8 @@
 			break;
 		}
 		xfs_ilock(ip, XFS_ILOCK_EXCL);
-		error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip,
-						      qblocks, 0, quota_flag);
+		error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks,
+						      0, quota_flag);
 		if (error)
 			goto error1;
 
@@ -2688,7 +2703,7 @@
 
 error0:	/* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
 	xfs_bmap_cancel(&free_list);
-	XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag);
+	xfs_trans_unreserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
 
 error1:	/* Just cancel transaction */
 	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
@@ -2827,7 +2842,8 @@
 
 	xfs_itrace_entry(ip);
 
-	if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+	error = xfs_qm_dqattach(ip, 0);
+	if (error)
 		return error;
 
 	error = 0;
@@ -2953,9 +2969,9 @@
 			break;
 		}
 		xfs_ilock(ip, XFS_ILOCK_EXCL);
-		error = XFS_TRANS_RESERVE_QUOTA(mp, tp,
-				ip->i_udquot, ip->i_gdquot, resblks, 0,
-				XFS_QMOPT_RES_REGBLKS);
+		error = xfs_trans_reserve_quota(tp, mp,
+				ip->i_udquot, ip->i_gdquot,
+				resblks, 0, XFS_QMOPT_RES_REGBLKS);
 		if (error)
 			goto error1;
 
diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h
index 04373c6..a9e102d 100644
--- a/fs/xfs/xfs_vnodeops.h
+++ b/fs/xfs/xfs_vnodeops.h
@@ -18,6 +18,7 @@
 #define	XFS_ATTR_DMI		0x01	/* invocation from a DMI function */
 #define	XFS_ATTR_NONBLOCK	0x02	/* return EAGAIN if operation would block */
 #define XFS_ATTR_NOLOCK		0x04	/* Don't grab any conflicting locks */
+#define XFS_ATTR_NOACL		0x08	/* Don't call xfs_acl_chmod */
 
 int xfs_readlink(struct xfs_inode *ip, char *link);
 int xfs_fsync(struct xfs_inode *ip);
diff --git a/include/asm-generic/Kbuild b/include/asm-generic/Kbuild
index 4c9932a..eb62334 100644
--- a/include/asm-generic/Kbuild
+++ b/include/asm-generic/Kbuild
@@ -1,11 +1,33 @@
+header-y += auxvec.h
+header-y += bitsperlong.h
 header-y += errno-base.h
 header-y += errno.h
 header-y += fcntl.h
 header-y += ioctl.h
+header-y += ioctls.h
+header-y += ipcbuf.h
+header-y += mman-common.h
 header-y += mman.h
+header-y += msgbuf.h
+header-y += param.h
 header-y += poll.h
+header-y += posix_types.h
+header-y += sembuf.h
+header-y += setup.h
+header-y += shmbuf.h
+header-y += shmparam.h
+header-y += signal-defs.h
 header-y += signal.h
+header-y += socket.h
+header-y += sockios.h
+header-y += stat.h
 header-y += statfs.h
+header-y += swab.h
+header-y += termbits.h
+header-y += termios.h
+header-y += types.h
+header-y += ucontext.h
+header-y += unistd.h
 
 unifdef-y += int-l64.h
 unifdef-y += int-ll64.h
diff --git a/include/asm-generic/Kbuild.asm b/include/asm-generic/Kbuild.asm
index 70d1855..290910e 100644
--- a/include/asm-generic/Kbuild.asm
+++ b/include/asm-generic/Kbuild.asm
@@ -9,6 +9,7 @@
 endif
 unifdef-y += auxvec.h
 unifdef-y += byteorder.h
+unifdef-y += bitsperlong.h
 unifdef-y += errno.h
 unifdef-y += fcntl.h
 unifdef-y += ioctl.h
diff --git a/include/asm-generic/atomic-long.h b/include/asm-generic/atomic-long.h
new file mode 100644
index 0000000..b7babf0
--- /dev/null
+++ b/include/asm-generic/atomic-long.h
@@ -0,0 +1,258 @@
+#ifndef _ASM_GENERIC_ATOMIC_LONG_H
+#define _ASM_GENERIC_ATOMIC_LONG_H
+/*
+ * Copyright (C) 2005 Silicon Graphics, Inc.
+ *	Christoph Lameter
+ *
+ * Allows to provide arch independent atomic definitions without the need to
+ * edit all arch specific atomic.h files.
+ */
+
+#include <asm/types.h>
+
+/*
+ * Suppport for atomic_long_t
+ *
+ * Casts for parameters are avoided for existing atomic functions in order to
+ * avoid issues with cast-as-lval under gcc 4.x and other limitations that the
+ * macros of a platform may have.
+ */
+
+#if BITS_PER_LONG == 64
+
+typedef atomic64_t atomic_long_t;
+
+#define ATOMIC_LONG_INIT(i)	ATOMIC64_INIT(i)
+
+static inline long atomic_long_read(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return (long)atomic64_read(v);
+}
+
+static inline void atomic_long_set(atomic_long_t *l, long i)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	atomic64_set(v, i);
+}
+
+static inline void atomic_long_inc(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	atomic64_inc(v);
+}
+
+static inline void atomic_long_dec(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	atomic64_dec(v);
+}
+
+static inline void atomic_long_add(long i, atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	atomic64_add(i, v);
+}
+
+static inline void atomic_long_sub(long i, atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	atomic64_sub(i, v);
+}
+
+static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return atomic64_sub_and_test(i, v);
+}
+
+static inline int atomic_long_dec_and_test(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return atomic64_dec_and_test(v);
+}
+
+static inline int atomic_long_inc_and_test(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return atomic64_inc_and_test(v);
+}
+
+static inline int atomic_long_add_negative(long i, atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return atomic64_add_negative(i, v);
+}
+
+static inline long atomic_long_add_return(long i, atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return (long)atomic64_add_return(i, v);
+}
+
+static inline long atomic_long_sub_return(long i, atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return (long)atomic64_sub_return(i, v);
+}
+
+static inline long atomic_long_inc_return(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return (long)atomic64_inc_return(v);
+}
+
+static inline long atomic_long_dec_return(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return (long)atomic64_dec_return(v);
+}
+
+static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return (long)atomic64_add_unless(v, a, u);
+}
+
+#define atomic_long_inc_not_zero(l) atomic64_inc_not_zero((atomic64_t *)(l))
+
+#define atomic_long_cmpxchg(l, old, new) \
+	(atomic64_cmpxchg((atomic64_t *)(l), (old), (new)))
+#define atomic_long_xchg(v, new) \
+	(atomic64_xchg((atomic64_t *)(v), (new)))
+
+#else  /*  BITS_PER_LONG == 64  */
+
+typedef atomic_t atomic_long_t;
+
+#define ATOMIC_LONG_INIT(i)	ATOMIC_INIT(i)
+static inline long atomic_long_read(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return (long)atomic_read(v);
+}
+
+static inline void atomic_long_set(atomic_long_t *l, long i)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	atomic_set(v, i);
+}
+
+static inline void atomic_long_inc(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	atomic_inc(v);
+}
+
+static inline void atomic_long_dec(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	atomic_dec(v);
+}
+
+static inline void atomic_long_add(long i, atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	atomic_add(i, v);
+}
+
+static inline void atomic_long_sub(long i, atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	atomic_sub(i, v);
+}
+
+static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return atomic_sub_and_test(i, v);
+}
+
+static inline int atomic_long_dec_and_test(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return atomic_dec_and_test(v);
+}
+
+static inline int atomic_long_inc_and_test(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return atomic_inc_and_test(v);
+}
+
+static inline int atomic_long_add_negative(long i, atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return atomic_add_negative(i, v);
+}
+
+static inline long atomic_long_add_return(long i, atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return (long)atomic_add_return(i, v);
+}
+
+static inline long atomic_long_sub_return(long i, atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return (long)atomic_sub_return(i, v);
+}
+
+static inline long atomic_long_inc_return(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return (long)atomic_inc_return(v);
+}
+
+static inline long atomic_long_dec_return(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return (long)atomic_dec_return(v);
+}
+
+static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return (long)atomic_add_unless(v, a, u);
+}
+
+#define atomic_long_inc_not_zero(l) atomic_inc_not_zero((atomic_t *)(l))
+
+#define atomic_long_cmpxchg(l, old, new) \
+	(atomic_cmpxchg((atomic_t *)(l), (old), (new)))
+#define atomic_long_xchg(v, new) \
+	(atomic_xchg((atomic_t *)(v), (new)))
+
+#endif  /*  BITS_PER_LONG == 64  */
+
+#endif  /*  _ASM_GENERIC_ATOMIC_LONG_H  */
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h
index 81d3be4..c99c64d 100644
--- a/include/asm-generic/atomic.h
+++ b/include/asm-generic/atomic.h
@@ -1,258 +1,165 @@
-#ifndef _ASM_GENERIC_ATOMIC_H
-#define _ASM_GENERIC_ATOMIC_H
 /*
- * Copyright (C) 2005 Silicon Graphics, Inc.
- *	Christoph Lameter
+ * Generic C implementation of atomic counter operations
+ * Originally implemented for MN10300.
  *
- * Allows to provide arch independent atomic definitions without the need to
- * edit all arch specific atomic.h files.
+ * 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_ATOMIC_H
+#define __ASM_GENERIC_ATOMIC_H
 
-#include <asm/types.h>
+#ifdef CONFIG_SMP
+#error not SMP safe
+#endif
 
 /*
- * Suppport for atomic_long_t
- *
- * Casts for parameters are avoided for existing atomic functions in order to
- * avoid issues with cast-as-lval under gcc 4.x and other limitations that the
- * macros of a platform may have.
+ * Atomic operations that C can't guarantee us.  Useful for
+ * resource counting etc..
  */
 
-#if BITS_PER_LONG == 64
+#define ATOMIC_INIT(i)	{ (i) }
 
-typedef atomic64_t atomic_long_t;
+#ifdef __KERNEL__
 
-#define ATOMIC_LONG_INIT(i)	ATOMIC64_INIT(i)
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically reads the value of @v.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_read(v)	((v)->counter)
 
-static inline long atomic_long_read(atomic_long_t *l)
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_set(v, i) (((v)->counter) = (i))
+
+#include <asm/system.h>
+
+/**
+ * atomic_add_return - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ *
+ * Atomically adds @i to @v and returns the result
+ * Note that the guaranteed useful range of an atomic_t is only 24 bits.
+ */
+static inline int atomic_add_return(int i, atomic_t *v)
 {
-	atomic64_t *v = (atomic64_t *)l;
+	unsigned long flags;
+	int temp;
 
-	return (long)atomic64_read(v);
+	local_irq_save(flags);
+	temp = v->counter;
+	temp += i;
+	v->counter = temp;
+	local_irq_restore(flags);
+
+	return temp;
 }
 
-static inline void atomic_long_set(atomic_long_t *l, long i)
+/**
+ * atomic_sub_return - subtract integer from atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v and returns the result
+ * Note that the guaranteed useful range of an atomic_t is only 24 bits.
+ */
+static inline int atomic_sub_return(int i, atomic_t *v)
 {
-	atomic64_t *v = (atomic64_t *)l;
+	unsigned long flags;
+	int temp;
 
-	atomic64_set(v, i);
+	local_irq_save(flags);
+	temp = v->counter;
+	temp -= i;
+	v->counter = temp;
+	local_irq_restore(flags);
+
+	return temp;
 }
 
-static inline void atomic_long_inc(atomic_long_t *l)
+static inline int atomic_add_negative(int i, atomic_t *v)
 {
-	atomic64_t *v = (atomic64_t *)l;
-
-	atomic64_inc(v);
+	return atomic_add_return(i, v) < 0;
 }
 
-static inline void atomic_long_dec(atomic_long_t *l)
+static inline void atomic_add(int i, atomic_t *v)
 {
-	atomic64_t *v = (atomic64_t *)l;
-
-	atomic64_dec(v);
+	atomic_add_return(i, v);
 }
 
-static inline void atomic_long_add(long i, atomic_long_t *l)
+static inline void atomic_sub(int i, atomic_t *v)
 {
-	atomic64_t *v = (atomic64_t *)l;
-
-	atomic64_add(i, v);
+	atomic_sub_return(i, v);
 }
 
-static inline void atomic_long_sub(long i, atomic_long_t *l)
+static inline void atomic_inc(atomic_t *v)
 {
-	atomic64_t *v = (atomic64_t *)l;
-
-	atomic64_sub(i, v);
+	atomic_add_return(1, v);
 }
 
-static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
+static inline void atomic_dec(atomic_t *v)
 {
-	atomic64_t *v = (atomic64_t *)l;
-
-	return atomic64_sub_and_test(i, v);
+	atomic_sub_return(1, v);
 }
 
-static inline int atomic_long_dec_and_test(atomic_long_t *l)
-{
-	atomic64_t *v = (atomic64_t *)l;
+#define atomic_dec_return(v)		atomic_sub_return(1, (v))
+#define atomic_inc_return(v)		atomic_add_return(1, (v))
 
-	return atomic64_dec_and_test(v);
+#define atomic_sub_and_test(i, v)	(atomic_sub_return((i), (v)) == 0)
+#define atomic_dec_and_test(v)		(atomic_sub_return(1, (v)) == 0)
+#define atomic_inc_and_test(v)		(atomic_add_return(1, (v)) == 0)
+
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
+{
+	unsigned long flags;
+
+	mask = ~mask;
+	local_irq_save(flags);
+	*addr &= mask;
+	local_irq_restore(flags);
 }
 
-static inline int atomic_long_inc_and_test(atomic_long_t *l)
-{
-	atomic64_t *v = (atomic64_t *)l;
+#define atomic_xchg(ptr, v)		(xchg(&(ptr)->counter, (v)))
+#define atomic_cmpxchg(v, old, new)	(cmpxchg(&((v)->counter), (old), (new)))
 
-	return atomic64_inc_and_test(v);
-}
+#define cmpxchg_local(ptr, o, n)				  	       \
+	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+			(unsigned long)(n), sizeof(*(ptr))))
 
-static inline int atomic_long_add_negative(long i, atomic_long_t *l)
-{
-	atomic64_t *v = (atomic64_t *)l;
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
 
-	return atomic64_add_negative(i, v);
-}
+/* Assume that atomic operations are already serializing */
+#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()
 
-static inline long atomic_long_add_return(long i, atomic_long_t *l)
-{
-	atomic64_t *v = (atomic64_t *)l;
+#include <asm-generic/atomic-long.h>
 
-	return (long)atomic64_add_return(i, v);
-}
-
-static inline long atomic_long_sub_return(long i, atomic_long_t *l)
-{
-	atomic64_t *v = (atomic64_t *)l;
-
-	return (long)atomic64_sub_return(i, v);
-}
-
-static inline long atomic_long_inc_return(atomic_long_t *l)
-{
-	atomic64_t *v = (atomic64_t *)l;
-
-	return (long)atomic64_inc_return(v);
-}
-
-static inline long atomic_long_dec_return(atomic_long_t *l)
-{
-	atomic64_t *v = (atomic64_t *)l;
-
-	return (long)atomic64_dec_return(v);
-}
-
-static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
-{
-	atomic64_t *v = (atomic64_t *)l;
-
-	return (long)atomic64_add_unless(v, a, u);
-}
-
-#define atomic_long_inc_not_zero(l) atomic64_inc_not_zero((atomic64_t *)(l))
-
-#define atomic_long_cmpxchg(l, old, new) \
-	(atomic64_cmpxchg((atomic64_t *)(l), (old), (new)))
-#define atomic_long_xchg(v, new) \
-	(atomic64_xchg((atomic64_t *)(v), (new)))
-
-#else  /*  BITS_PER_LONG == 64  */
-
-typedef atomic_t atomic_long_t;
-
-#define ATOMIC_LONG_INIT(i)	ATOMIC_INIT(i)
-static inline long atomic_long_read(atomic_long_t *l)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	return (long)atomic_read(v);
-}
-
-static inline void atomic_long_set(atomic_long_t *l, long i)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	atomic_set(v, i);
-}
-
-static inline void atomic_long_inc(atomic_long_t *l)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	atomic_inc(v);
-}
-
-static inline void atomic_long_dec(atomic_long_t *l)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	atomic_dec(v);
-}
-
-static inline void atomic_long_add(long i, atomic_long_t *l)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	atomic_add(i, v);
-}
-
-static inline void atomic_long_sub(long i, atomic_long_t *l)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	atomic_sub(i, v);
-}
-
-static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	return atomic_sub_and_test(i, v);
-}
-
-static inline int atomic_long_dec_and_test(atomic_long_t *l)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	return atomic_dec_and_test(v);
-}
-
-static inline int atomic_long_inc_and_test(atomic_long_t *l)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	return atomic_inc_and_test(v);
-}
-
-static inline int atomic_long_add_negative(long i, atomic_long_t *l)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	return atomic_add_negative(i, v);
-}
-
-static inline long atomic_long_add_return(long i, atomic_long_t *l)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	return (long)atomic_add_return(i, v);
-}
-
-static inline long atomic_long_sub_return(long i, atomic_long_t *l)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	return (long)atomic_sub_return(i, v);
-}
-
-static inline long atomic_long_inc_return(atomic_long_t *l)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	return (long)atomic_inc_return(v);
-}
-
-static inline long atomic_long_dec_return(atomic_long_t *l)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	return (long)atomic_dec_return(v);
-}
-
-static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
-{
-	atomic_t *v = (atomic_t *)l;
-
-	return (long)atomic_add_unless(v, a, u);
-}
-
-#define atomic_long_inc_not_zero(l) atomic_inc_not_zero((atomic_t *)(l))
-
-#define atomic_long_cmpxchg(l, old, new) \
-	(atomic_cmpxchg((atomic_t *)(l), (old), (new)))
-#define atomic_long_xchg(v, new) \
-	(atomic_xchg((atomic_t *)(v), (new)))
-
-#endif  /*  BITS_PER_LONG == 64  */
-
-#endif  /*  _ASM_GENERIC_ATOMIC_H  */
+#endif /* __KERNEL__ */
+#endif /* __ASM_GENERIC_ATOMIC_H */
diff --git a/include/asm-generic/auxvec.h b/include/asm-generic/auxvec.h
new file mode 100644
index 0000000..b99573b
--- /dev/null
+++ b/include/asm-generic/auxvec.h
@@ -0,0 +1,8 @@
+#ifndef __ASM_GENERIC_AUXVEC_H
+#define __ASM_GENERIC_AUXVEC_H
+/*
+ * Not all architectures need their own auxvec.h, the most
+ * common definitions are already in linux/auxvec.h.
+ */
+
+#endif /* __ASM_GENERIC_AUXVEC_H */
diff --git a/include/asm-generic/bitops.h b/include/asm-generic/bitops.h
index c9f369c..a54f442 100644
--- a/include/asm-generic/bitops.h
+++ b/include/asm-generic/bitops.h
@@ -1,19 +1,29 @@
-#ifndef _ASM_GENERIC_BITOPS_H_
-#define _ASM_GENERIC_BITOPS_H_
+#ifndef __ASM_GENERIC_BITOPS_H
+#define __ASM_GENERIC_BITOPS_H
 
 /*
  * For the benefit of those who are trying to port Linux to another
  * architecture, here are some C-language equivalents.  You should
  * recode these in the native assembly language, if at all possible.
- * 
+ *
  * C language equivalents written by Theodore Ts'o, 9/26/92
  */
 
-#include <asm-generic/bitops/atomic.h>
-#include <asm-generic/bitops/non-atomic.h>
+#include <linux/irqflags.h>
+#include <linux/compiler.h>
+
+/*
+ * clear_bit may not imply a memory barrier
+ */
+#ifndef smp_mb__before_clear_bit
+#define smp_mb__before_clear_bit()	smp_mb()
+#define smp_mb__after_clear_bit()	smp_mb()
+#endif
+
 #include <asm-generic/bitops/__ffs.h>
 #include <asm-generic/bitops/ffz.h>
 #include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
 #include <asm-generic/bitops/fls64.h>
 #include <asm-generic/bitops/find.h>
 
@@ -26,8 +36,10 @@
 #include <asm-generic/bitops/hweight.h>
 #include <asm-generic/bitops/lock.h>
 
+#include <asm-generic/bitops/atomic.h>
+#include <asm-generic/bitops/non-atomic.h>
 #include <asm-generic/bitops/ext2-non-atomic.h>
 #include <asm-generic/bitops/ext2-atomic.h>
 #include <asm-generic/bitops/minix.h>
 
-#endif /* _ASM_GENERIC_BITOPS_H */
+#endif /* __ASM_GENERIC_BITOPS_H */
diff --git a/include/asm-generic/bitops/atomic.h b/include/asm-generic/bitops/atomic.h
index 4657f3e..c894646 100644
--- a/include/asm-generic/bitops/atomic.h
+++ b/include/asm-generic/bitops/atomic.h
@@ -2,6 +2,7 @@
 #define _ASM_GENERIC_BITOPS_ATOMIC_H_
 
 #include <asm/types.h>
+#include <asm/system.h>
 
 #ifdef CONFIG_SMP
 #include <asm/spinlock.h>
diff --git a/include/asm-generic/bitsperlong.h b/include/asm-generic/bitsperlong.h
new file mode 100644
index 0000000..4ae54e0
--- /dev/null
+++ b/include/asm-generic/bitsperlong.h
@@ -0,0 +1,32 @@
+#ifndef __ASM_GENERIC_BITS_PER_LONG
+#define __ASM_GENERIC_BITS_PER_LONG
+
+/*
+ * There seems to be no way of detecting this automatically from user
+ * space, so 64 bit architectures should override this in their
+ * bitsperlong.h. In particular, an architecture that supports
+ * both 32 and 64 bit user space must not rely on CONFIG_64BIT
+ * to decide it, but rather check a compiler provided macro.
+ */
+#ifndef __BITS_PER_LONG
+#define __BITS_PER_LONG 32
+#endif
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_64BIT
+#define BITS_PER_LONG 64
+#else
+#define BITS_PER_LONG 32
+#endif /* CONFIG_64BIT */
+
+/*
+ * FIXME: The check currently breaks x86-64 build, so it's
+ * temporarily disabled. Please fix x86-64 and reenable
+ */
+#if 0 && BITS_PER_LONG != __BITS_PER_LONG
+#error Inconsistent word size. Check asm/bitsperlong.h
+#endif
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_GENERIC_BITS_PER_LONG */
diff --git a/include/asm-generic/bugs.h b/include/asm-generic/bugs.h
new file mode 100644
index 0000000..6c4f62e
--- /dev/null
+++ b/include/asm-generic/bugs.h
@@ -0,0 +1,10 @@
+#ifndef __ASM_GENERIC_BUGS_H
+#define __ASM_GENERIC_BUGS_H
+/*
+ * This file is included by 'init/main.c' to check for
+ * architecture-dependent bugs.
+ */
+
+static inline void check_bugs(void) { }
+
+#endif	/* __ASM_GENERIC_BUGS_H */
diff --git a/include/asm-generic/cache.h b/include/asm-generic/cache.h
new file mode 100644
index 0000000..1bfcfe5
--- /dev/null
+++ b/include/asm-generic/cache.h
@@ -0,0 +1,12 @@
+#ifndef __ASM_GENERIC_CACHE_H
+#define __ASM_GENERIC_CACHE_H
+/*
+ * 32 bytes appears to be the most common cache line size,
+ * so make that the default here. Architectures with larger
+ * cache lines need to provide their own cache.h.
+ */
+
+#define L1_CACHE_SHIFT		5
+#define L1_CACHE_BYTES		(1 << L1_CACHE_SHIFT)
+
+#endif /* __ASM_GENERIC_CACHE_H */
diff --git a/include/asm-generic/cacheflush.h b/include/asm-generic/cacheflush.h
new file mode 100644
index 0000000..ba4ec39
--- /dev/null
+++ b/include/asm-generic/cacheflush.h
@@ -0,0 +1,30 @@
+#ifndef __ASM_CACHEFLUSH_H
+#define __ASM_CACHEFLUSH_H
+
+/* Keep includes the same across arches.  */
+#include <linux/mm.h>
+
+/*
+ * The cache doesn't need to be flushed when TLB entries change when
+ * the cache is mapped to physical memory, not virtual memory
+ */
+#define flush_cache_all()			do { } while (0)
+#define flush_cache_mm(mm)			do { } while (0)
+#define flush_cache_dup_mm(mm)			do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define flush_dcache_page(page)			do { } while (0)
+#define flush_dcache_mmap_lock(mapping)		do { } while (0)
+#define flush_dcache_mmap_unlock(mapping)	do { } while (0)
+#define flush_icache_range(start, end)		do { } while (0)
+#define flush_icache_page(vma,pg)		do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
+#define flush_cache_vmap(start, end)		do { } while (0)
+#define flush_cache_vunmap(start, end)		do { } while (0)
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+	memcpy(dst, src, len)
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
+	memcpy(dst, src, len)
+
+#endif /* __ASM_CACHEFLUSH_H */
diff --git a/include/asm-generic/checksum.h b/include/asm-generic/checksum.h
new file mode 100644
index 0000000..4647c76
--- /dev/null
+++ b/include/asm-generic/checksum.h
@@ -0,0 +1,79 @@
+#ifndef __ASM_GENERIC_CHECKSUM_H
+#define __ASM_GENERIC_CHECKSUM_H
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+extern __wsum csum_partial(const void *buff, int len, __wsum sum);
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+extern __wsum csum_partial_copy(const void *src, void *dst, int len, __wsum sum);
+
+/*
+ * the same as csum_partial_copy, but copies from user space.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+extern __wsum csum_partial_copy_from_user(const void __user *src, void *dst,
+					int len, __wsum sum, int *csum_err);
+
+#define csum_partial_copy_nocheck(src, dst, len, sum)	\
+	csum_partial_copy((src), (dst), (len), (sum))
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ */
+extern __sum16 ip_fast_csum(const void *iph, unsigned int ihl);
+
+/*
+ * Fold a partial checksum
+ */
+static inline __sum16 csum_fold(__wsum csum)
+{
+	u32 sum = (__force u32)csum;
+	sum = (sum & 0xffff) + (sum >> 16);
+	sum = (sum & 0xffff) + (sum >> 16);
+	return (__force __sum16)~sum;
+}
+
+#ifndef csum_tcpudp_nofold
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+extern __wsum
+csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
+		unsigned short proto, __wsum sum);
+#endif
+
+static inline __sum16
+csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len,
+		  unsigned short proto, __wsum sum)
+{
+	return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+extern __sum16 ip_compute_csum(const void *buff, int len);
+
+#endif /* __ASM_GENERIC_CHECKSUM_H */
diff --git a/include/asm-generic/current.h b/include/asm-generic/current.h
new file mode 100644
index 0000000..5e86f6a
--- /dev/null
+++ b/include/asm-generic/current.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_GENERIC_CURRENT_H
+#define __ASM_GENERIC_CURRENT_H
+
+#include <linux/thread_info.h>
+
+#define get_current() (current_thread_info()->task)
+#define current get_current()
+
+#endif /* __ASM_GENERIC_CURRENT_H */
diff --git a/include/asm-generic/delay.h b/include/asm-generic/delay.h
new file mode 100644
index 0000000..4586fec
--- /dev/null
+++ b/include/asm-generic/delay.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_GENERIC_DELAY_H
+#define __ASM_GENERIC_DELAY_H
+
+extern void __udelay(unsigned long usecs);
+extern void __delay(unsigned long loops);
+
+#define udelay(n) __udelay(n)
+
+#endif /* __ASM_GENERIC_DELAY_H */
diff --git a/include/asm-generic/dma.h b/include/asm-generic/dma.h
new file mode 100644
index 0000000..9dfc3a7
--- /dev/null
+++ b/include/asm-generic/dma.h
@@ -0,0 +1,15 @@
+#ifndef __ASM_GENERIC_DMA_H
+#define __ASM_GENERIC_DMA_H
+/*
+ * This file traditionally describes the i8237 PC style DMA controller.
+ * Most architectures don't have these any more and can get the minimal
+ * implementation from kernel/dma.c by not defining MAX_DMA_CHANNELS.
+ *
+ * Some code relies on seeing MAX_DMA_ADDRESS though.
+ */
+#define MAX_DMA_ADDRESS PAGE_OFFSET
+
+extern int request_dma(unsigned int dmanr, const char *device_id);
+extern void free_dma(unsigned int dmanr);
+
+#endif /* __ASM_GENERIC_DMA_H */
diff --git a/include/asm-generic/fb.h b/include/asm-generic/fb.h
new file mode 100644
index 0000000..fe8ca7f
--- /dev/null
+++ b/include/asm-generic/fb.h
@@ -0,0 +1,12 @@
+#ifndef __ASM_GENERIC_FB_H_
+#define __ASM_GENERIC_FB_H_
+#include <linux/fb.h>
+
+#define fb_pgprotect(...) do {} while (0)
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+	return 0;
+}
+
+#endif /* __ASM_GENERIC_FB_H_ */
diff --git a/include/asm-generic/getorder.h b/include/asm-generic/getorder.h
new file mode 100644
index 0000000..67e7245
--- /dev/null
+++ b/include/asm-generic/getorder.h
@@ -0,0 +1,24 @@
+#ifndef __ASM_GENERIC_GETORDER_H
+#define __ASM_GENERIC_GETORDER_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/compiler.h>
+
+/* Pure 2^n version 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);
+	return order;
+}
+
+#endif	/* __ASSEMBLY__ */
+
+#endif	/* __ASM_GENERIC_GETORDER_H */
diff --git a/include/asm-generic/hardirq.h b/include/asm-generic/hardirq.h
new file mode 100644
index 0000000..3d5d2c9
--- /dev/null
+++ b/include/asm-generic/hardirq.h
@@ -0,0 +1,34 @@
+#ifndef __ASM_GENERIC_HARDIRQ_H
+#define __ASM_GENERIC_HARDIRQ_H
+
+#include <linux/cache.h>
+#include <linux/threads.h>
+#include <linux/irq.h>
+
+typedef struct {
+	unsigned long __softirq_pending;
+} ____cacheline_aligned irq_cpustat_t;
+
+#include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
+
+#ifndef HARDIRQ_BITS
+#define HARDIRQ_BITS	8
+#endif
+
+/*
+ * The hardirq mask has to be large enough to have
+ * space for potentially all IRQ sources in the system
+ * nesting on a single CPU:
+ */
+#if (1 << HARDIRQ_BITS) < NR_IRQS
+# error HARDIRQ_BITS is too low!
+#endif
+
+#ifndef ack_bad_irq
+static inline void ack_bad_irq(unsigned int irq)
+{
+	printk(KERN_CRIT "unexpected IRQ trap at vector %02x\n", irq);
+}
+#endif
+
+#endif /* __ASM_GENERIC_HARDIRQ_H */
diff --git a/include/asm-generic/hw_irq.h b/include/asm-generic/hw_irq.h
new file mode 100644
index 0000000..89036d7
--- /dev/null
+++ b/include/asm-generic/hw_irq.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_GENERIC_HW_IRQ_H
+#define __ASM_GENERIC_HW_IRQ_H
+/*
+ * hw_irq.h has internal declarations for the low-level interrupt
+ * controller, like the original i8259A.
+ * In general, this is not needed for new architectures.
+ */
+
+#endif /* __ASM_GENERIC_HW_IRQ_H */
diff --git a/include/asm-generic/int-l64.h b/include/asm-generic/int-l64.h
index 2af9b75..1ca3efc 100644
--- a/include/asm-generic/int-l64.h
+++ b/include/asm-generic/int-l64.h
@@ -8,6 +8,8 @@
 #ifndef _ASM_GENERIC_INT_L64_H
 #define _ASM_GENERIC_INT_L64_H
 
+#include <asm/bitsperlong.h>
+
 #ifndef __ASSEMBLY__
 /*
  * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
diff --git a/include/asm-generic/int-ll64.h b/include/asm-generic/int-ll64.h
index f9bc9ac..f394147 100644
--- a/include/asm-generic/int-ll64.h
+++ b/include/asm-generic/int-ll64.h
@@ -8,6 +8,8 @@
 #ifndef _ASM_GENERIC_INT_LL64_H
 #define _ASM_GENERIC_INT_LL64_H
 
+#include <asm/bitsperlong.h>
+
 #ifndef __ASSEMBLY__
 /*
  * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
new file mode 100644
index 0000000..bcee636
--- /dev/null
+++ b/include/asm-generic/io.h
@@ -0,0 +1,300 @@
+/* Generic I/O port emulation, based on MN10300 code
+ *
+ * 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_IO_H
+#define __ASM_GENERIC_IO_H
+
+#include <asm/page.h> /* I/O is all done through memory accesses */
+#include <asm/cacheflush.h>
+#include <linux/types.h>
+
+#ifdef CONFIG_GENERIC_IOMAP
+#include <asm-generic/iomap.h>
+#endif
+
+#define mmiowb() do {} while (0)
+
+/*****************************************************************************/
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the simple architectures, we just read/write the
+ * memory location directly.
+ */
+static inline u8 __raw_readb(const volatile void __iomem *addr)
+{
+	return *(const volatile u8 __force *) addr;
+}
+
+static inline u16 __raw_readw(const volatile void __iomem *addr)
+{
+	return *(const volatile u16 __force *) addr;
+}
+
+static inline u32 __raw_readl(const volatile void __iomem *addr)
+{
+	return *(const volatile u32 __force *) addr;
+}
+
+#define readb __raw_readb
+#define readw(addr) __le16_to_cpu(__raw_readw(addr))
+#define readl(addr) __le32_to_cpu(__raw_readl(addr))
+
+static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
+{
+	*(volatile u8 __force *) addr = b;
+}
+
+static inline void __raw_writew(u16 b, volatile void __iomem *addr)
+{
+	*(volatile u16 __force *) addr = b;
+}
+
+static inline void __raw_writel(u32 b, volatile void __iomem *addr)
+{
+	*(volatile u32 __force *) addr = b;
+}
+
+#define writeb __raw_writeb
+#define writew(b,addr) __raw_writew(__cpu_to_le16(b),addr)
+#define writel(b,addr) __raw_writel(__cpu_to_le32(b),addr)
+
+#ifdef CONFIG_64BIT
+static inline u64 __raw_readq(const volatile void __iomem *addr)
+{
+	return *(const volatile u64 __force *) addr;
+}
+#define readq(addr) __le64_to_cpu(__raw_readq(addr))
+
+static inline void __raw_writeq(u64 b, volatile void __iomem *addr)
+{
+	*(volatile u64 __force *) addr = b;
+}
+#define writeq(b,addr) __raw_writeq(__cpu_to_le64(b),addr)
+#endif
+
+/*****************************************************************************/
+/*
+ * traditional input/output functions
+ */
+
+static inline u8 inb(unsigned long addr)
+{
+	return readb((volatile void __iomem *) addr);
+}
+
+static inline u16 inw(unsigned long addr)
+{
+	return readw((volatile void __iomem *) addr);
+}
+
+static inline u32 inl(unsigned long addr)
+{
+	return readl((volatile void __iomem *) addr);
+}
+
+static inline void outb(u8 b, unsigned long addr)
+{
+	writeb(b, (volatile void __iomem *) addr);
+}
+
+static inline void outw(u16 b, unsigned long addr)
+{
+	writew(b, (volatile void __iomem *) addr);
+}
+
+static inline void outl(u32 b, unsigned long addr)
+{
+	writel(b, (volatile void __iomem *) addr);
+}
+
+#define inb_p(addr)	inb(addr)
+#define inw_p(addr)	inw(addr)
+#define inl_p(addr)	inl(addr)
+#define outb_p(x, addr)	outb((x), (addr))
+#define outw_p(x, addr)	outw((x), (addr))
+#define outl_p(x, addr)	outl((x), (addr))
+
+static inline void insb(unsigned long addr, void *buffer, int count)
+{
+	if (count) {
+		u8 *buf = buffer;
+		do {
+			u8 x = inb(addr);
+			*buf++ = x;
+		} while (--count);
+	}
+}
+
+static inline void insw(unsigned long addr, void *buffer, int count)
+{
+	if (count) {
+		u16 *buf = buffer;
+		do {
+			u16 x = inw(addr);
+			*buf++ = x;
+		} while (--count);
+	}
+}
+
+static inline void insl(unsigned long addr, void *buffer, int count)
+{
+	if (count) {
+		u32 *buf = buffer;
+		do {
+			u32 x = inl(addr);
+			*buf++ = x;
+		} while (--count);
+	}
+}
+
+static inline void outsb(unsigned long addr, const void *buffer, int count)
+{
+	if (count) {
+		const u8 *buf = buffer;
+		do {
+			outb(*buf++, addr);
+		} while (--count);
+	}
+}
+
+static inline void outsw(unsigned long addr, const void *buffer, int count)
+{
+	if (count) {
+		const u16 *buf = buffer;
+		do {
+			outw(*buf++, addr);
+		} while (--count);
+	}
+}
+
+static inline void outsl(unsigned long addr, const void *buffer, int count)
+{
+	if (count) {
+		const u32 *buf = buffer;
+		do {
+			outl(*buf++, addr);
+		} while (--count);
+	}
+}
+
+#ifndef CONFIG_GENERIC_IOMAP
+#define ioread8(addr)		readb(addr)
+#define ioread16(addr)		readw(addr)
+#define ioread32(addr)		readl(addr)
+
+#define iowrite8(v, addr)	writeb((v), (addr))
+#define iowrite16(v, addr)	writew((v), (addr))
+#define iowrite32(v, addr)	writel((v), (addr))
+
+#define ioread8_rep(p, dst, count) \
+	insb((unsigned long) (p), (dst), (count))
+#define ioread16_rep(p, dst, count) \
+	insw((unsigned long) (p), (dst), (count))
+#define ioread32_rep(p, dst, count) \
+	insl((unsigned long) (p), (dst), (count))
+
+#define iowrite8_rep(p, src, count) \
+	outsb((unsigned long) (p), (src), (count))
+#define iowrite16_rep(p, src, count) \
+	outsw((unsigned long) (p), (src), (count))
+#define iowrite32_rep(p, src, count) \
+	outsl((unsigned long) (p), (src), (count))
+#endif /* CONFIG_GENERIC_IOMAP */
+
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#ifdef __KERNEL__
+
+#include <linux/vmalloc.h>
+#define __io_virt(x) ((void __force *) (x))
+
+#ifndef CONFIG_GENERIC_IOMAP
+/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
+struct pci_dev;
+extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
+{
+}
+#endif /* CONFIG_GENERIC_IOMAP */
+
+/*
+ * Change virtual addresses to physical addresses and vv.
+ * These are pretty trivial
+ */
+static inline unsigned long virt_to_phys(volatile void *address)
+{
+	return __pa((unsigned long)address);
+}
+
+static inline void *phys_to_virt(unsigned long address)
+{
+	return __va(address);
+}
+
+/*
+ * Change "struct page" to physical address.
+ */
+static inline void __iomem *ioremap(phys_addr_t offset, unsigned long size)
+{
+	return (void __iomem*) (unsigned long)offset;
+}
+
+#define __ioremap(offset, size, flags)	ioremap(offset, size)
+
+#ifndef ioremap_nocache
+#define ioremap_nocache ioremap
+#endif
+
+#ifndef ioremap_wc
+#define ioremap_wc ioremap_nocache
+#endif
+
+static inline void iounmap(void *addr)
+{
+}
+
+#ifndef CONFIG_GENERIC_IOMAP
+static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+	return (void __iomem *) port;
+}
+
+static inline void ioport_unmap(void __iomem *p)
+{
+}
+#else /* CONFIG_GENERIC_IOMAP */
+extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
+extern void ioport_unmap(void __iomem *p);
+#endif /* CONFIG_GENERIC_IOMAP */
+
+#define xlate_dev_kmem_ptr(p)	p
+#define xlate_dev_mem_ptr(p)	((void *) (p))
+
+#ifndef virt_to_bus
+static inline unsigned long virt_to_bus(volatile void *address)
+{
+	return ((unsigned long) address);
+}
+
+static inline void *bus_to_virt(unsigned long address)
+{
+	return (void *) address;
+}
+#endif
+
+#define memset_io(a, b, c)	memset(__io_virt(a), (b), (c))
+#define memcpy_fromio(a, b, c)	memcpy((a), __io_virt(b), (c))
+#define memcpy_toio(a, b, c)	memcpy(__io_virt(a), (b), (c))
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_GENERIC_IO_H */
diff --git a/include/asm-generic/ioctls.h b/include/asm-generic/ioctls.h
new file mode 100644
index 0000000..a799e20
--- /dev/null
+++ b/include/asm-generic/ioctls.h
@@ -0,0 +1,110 @@
+#ifndef __ASM_GENERIC_IOCTLS_H
+#define __ASM_GENERIC_IOCTLS_H
+
+#include <linux/ioctl.h>
+
+/*
+ * These are the most common definitions for tty ioctl numbers.
+ * Most of them do not use the recommended _IOC(), but there is
+ * probably some source code out there hardcoding the number,
+ * so we might as well use them for all new platforms.
+ *
+ * The architectures that use different values here typically
+ * try to be compatible with some Unix variants for the same
+ * architecture.
+ */
+
+/* 0x54 is just a magic number to make these relatively unique ('T') */
+
+#define TCGETS		0x5401
+#define TCSETS		0x5402
+#define TCSETSW		0x5403
+#define TCSETSF		0x5404
+#define TCGETA		0x5405
+#define TCSETA		0x5406
+#define TCSETAW		0x5407
+#define TCSETAF		0x5408
+#define TCSBRK		0x5409
+#define TCXONC		0x540A
+#define TCFLSH		0x540B
+#define TIOCEXCL	0x540C
+#define TIOCNXCL	0x540D
+#define TIOCSCTTY	0x540E
+#define TIOCGPGRP	0x540F
+#define TIOCSPGRP	0x5410
+#define TIOCOUTQ	0x5411
+#define TIOCSTI		0x5412
+#define TIOCGWINSZ	0x5413
+#define TIOCSWINSZ	0x5414
+#define TIOCMGET	0x5415
+#define TIOCMBIS	0x5416
+#define TIOCMBIC	0x5417
+#define TIOCMSET	0x5418
+#define TIOCGSOFTCAR	0x5419
+#define TIOCSSOFTCAR	0x541A
+#define FIONREAD	0x541B
+#define TIOCINQ		FIONREAD
+#define TIOCLINUX	0x541C
+#define TIOCCONS	0x541D
+#define TIOCGSERIAL	0x541E
+#define TIOCSSERIAL	0x541F
+#define TIOCPKT		0x5420
+#define FIONBIO		0x5421
+#define TIOCNOTTY	0x5422
+#define TIOCSETD	0x5423
+#define TIOCGETD	0x5424
+#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TIOCSBRK	0x5427  /* BSD compatibility */
+#define TIOCCBRK	0x5428  /* BSD compatibility */
+#define TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TCGETS2		_IOR('T', 0x2A, struct termios2)
+#define TCSETS2		_IOW('T', 0x2B, struct termios2)
+#define TCSETSW2	_IOW('T', 0x2C, struct termios2)
+#define TCSETSF2	_IOW('T', 0x2D, struct termios2)
+#define TIOCGRS485	0x542E
+#define TIOCSRS485	0x542F
+#define TIOCGPTN	_IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK	_IOW('T', 0x31, int)  /* Lock/unlock Pty */
+#define TCGETX		0x5432 /* SYS5 TCGETX compatibility */
+#define TCSETX		0x5433
+#define TCSETXF		0x5434
+#define TCSETXW		0x5435
+
+#define FIONCLEX	0x5450
+#define FIOCLEX		0x5451
+#define FIOASYNC	0x5452
+#define TIOCSERCONFIG	0x5453
+#define TIOCSERGWILD	0x5454
+#define TIOCSERSWILD	0x5455
+#define TIOCGLCKTRMIOS	0x5456
+#define TIOCSLCKTRMIOS	0x5457
+#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+
+/*
+ * some architectures define FIOQSIZE as 0x545E, which is used for
+ * TIOCGHAYESESP on others
+ */
+#ifndef FIOQSIZE
+# define TIOCGHAYESESP	0x545E  /* Get Hayes ESP configuration */
+# define TIOCSHAYESESP	0x545F  /* Set Hayes ESP configuration */
+# define FIOQSIZE	0x5460
+#endif
+
+/* Used for packet mode */
+#define TIOCPKT_DATA		 0
+#define TIOCPKT_FLUSHREAD	 1
+#define TIOCPKT_FLUSHWRITE	 2
+#define TIOCPKT_STOP		 4
+#define TIOCPKT_START		 8
+#define TIOCPKT_NOSTOP		16
+#define TIOCPKT_DOSTOP		32
+
+#define TIOCSER_TEMT	0x01	/* Transmitter physically empty */
+
+#endif /* __ASM_GENERIC_IOCTLS_H */
diff --git a/include/asm-generic/ipcbuf.h b/include/asm-generic/ipcbuf.h
new file mode 100644
index 0000000..76982b2
--- /dev/null
+++ b/include/asm-generic/ipcbuf.h
@@ -0,0 +1,34 @@
+#ifndef __ASM_GENERIC_IPCBUF_H
+#define __ASM_GENERIC_IPCBUF_H
+
+/*
+ * The generic ipc64_perm structure:
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * ipc64_perm was originally meant to be architecture specific, but
+ * everyone just ended up making identical copies without specific
+ * optimizations, so we may just as well all use the same one.
+ *
+ * Pad space is left for:
+ * - 32-bit mode_t on architectures that only had 16 bit
+ * - 32-bit seq
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct ipc64_perm {
+	__kernel_key_t		key;
+	__kernel_uid32_t	uid;
+	__kernel_gid32_t	gid;
+	__kernel_uid32_t	cuid;
+	__kernel_gid32_t	cgid;
+	__kernel_mode_t		mode;
+				/* pad if mode_t is u16: */
+	unsigned char		__pad1[4 - sizeof(__kernel_mode_t)];
+	unsigned short		seq;
+	unsigned short		__pad2;
+	unsigned long		__unused1;
+	unsigned long		__unused2;
+};
+
+#endif /* __ASM_GENERIC_IPCBUF_H */
diff --git a/include/asm-generic/irq.h b/include/asm-generic/irq.h
new file mode 100644
index 0000000..b90ec0b
--- /dev/null
+++ b/include/asm-generic/irq.h
@@ -0,0 +1,18 @@
+#ifndef __ASM_GENERIC_IRQ_H
+#define __ASM_GENERIC_IRQ_H
+
+/*
+ * NR_IRQS is the upper bound of how many interrupts can be handled
+ * in the platform. It is used to size the static irq_map array,
+ * so don't make it too big.
+ */
+#ifndef NR_IRQS
+#define NR_IRQS 64
+#endif
+
+static inline int irq_canonicalize(int irq)
+{
+	return irq;
+}
+
+#endif /* __ASM_GENERIC_IRQ_H */
diff --git a/include/asm-generic/irqflags.h b/include/asm-generic/irqflags.h
new file mode 100644
index 0000000..9aebf61
--- /dev/null
+++ b/include/asm-generic/irqflags.h
@@ -0,0 +1,72 @@
+#ifndef __ASM_GENERIC_IRQFLAGS_H
+#define __ASM_GENERIC_IRQFLAGS_H
+
+/*
+ * All architectures should implement at least the first two functions,
+ * usually inline assembly will be the best way.
+ */
+#ifndef RAW_IRQ_DISABLED
+#define RAW_IRQ_DISABLED 0
+#define RAW_IRQ_ENABLED 1
+#endif
+
+/* read interrupt enabled status */
+#ifndef __raw_local_save_flags
+unsigned long __raw_local_save_flags(void);
+#endif
+
+/* set interrupt enabled status */
+#ifndef raw_local_irq_restore
+void raw_local_irq_restore(unsigned long flags);
+#endif
+
+/* get status and disable interrupts */
+#ifndef __raw_local_irq_save
+static inline unsigned long __raw_local_irq_save(void)
+{
+	unsigned long flags;
+	flags = __raw_local_save_flags();
+	raw_local_irq_restore(RAW_IRQ_DISABLED);
+	return flags;
+}
+#endif
+
+/* test flags */
+#ifndef raw_irqs_disabled_flags
+static inline int raw_irqs_disabled_flags(unsigned long flags)
+{
+	return flags == RAW_IRQ_DISABLED;
+}
+#endif
+
+/* unconditionally enable interrupts */
+#ifndef raw_local_irq_enable
+static inline void raw_local_irq_enable(void)
+{
+	raw_local_irq_restore(RAW_IRQ_ENABLED);
+}
+#endif
+
+/* unconditionally disable interrupts */
+#ifndef raw_local_irq_disable
+static inline void raw_local_irq_disable(void)
+{
+	raw_local_irq_restore(RAW_IRQ_DISABLED);
+}
+#endif
+
+/* test hardware interrupt enable bit */
+#ifndef raw_irqs_disabled
+static inline int raw_irqs_disabled(void)
+{
+	return raw_irqs_disabled_flags(__raw_local_save_flags());
+}
+#endif
+
+#define raw_local_save_flags(flags) \
+	do { (flags) = __raw_local_save_flags(); } while (0)
+
+#define raw_local_irq_save(flags) \
+	do { (flags) = __raw_local_irq_save(); } while (0)
+
+#endif /* __ASM_GENERIC_IRQFLAGS_H */
diff --git a/include/asm-generic/kmap_types.h b/include/asm-generic/kmap_types.h
new file mode 100644
index 0000000..58c3305
--- /dev/null
+++ b/include/asm-generic/kmap_types.h
@@ -0,0 +1,32 @@
+#ifndef _ASM_GENERIC_KMAP_TYPES_H
+#define _ASM_GENERIC_KMAP_TYPES_H
+
+#ifdef CONFIG_DEBUG_HIGHMEM
+# define D(n) __KM_FENCE_##n ,
+#else
+# define D(n)
+#endif
+
+enum km_type {
+D(0)	KM_BOUNCE_READ,
+D(1)	KM_SKB_SUNRPC_DATA,
+D(2)	KM_SKB_DATA_SOFTIRQ,
+D(3)	KM_USER0,
+D(4)	KM_USER1,
+D(5)	KM_BIO_SRC_IRQ,
+D(6)	KM_BIO_DST_IRQ,
+D(7)	KM_PTE0,
+D(8)	KM_PTE1,
+D(9)	KM_IRQ0,
+D(10)	KM_IRQ1,
+D(11)	KM_SOFTIRQ0,
+D(12)	KM_SOFTIRQ1,
+D(13)	KM_SYNC_ICACHE,
+D(14)	KM_SYNC_DCACHE,
+D(15)	KM_UML_USERCOPY, /* UML specific, for copy_*_user - used in do_op_one_page */
+D(16)	KM_TYPE_NR
+};
+
+#undef D
+
+#endif
diff --git a/include/asm-generic/linkage.h b/include/asm-generic/linkage.h
new file mode 100644
index 0000000..fef7a01
--- /dev/null
+++ b/include/asm-generic/linkage.h
@@ -0,0 +1,8 @@
+#ifndef __ASM_GENERIC_LINKAGE_H
+#define __ASM_GENERIC_LINKAGE_H
+/*
+ * linux/linkage.h provides reasonable defaults.
+ * an architecture can override them by providing its own version.
+ */
+
+#endif /* __ASM_GENERIC_LINKAGE_H */
diff --git a/include/asm-generic/mman-common.h b/include/asm-generic/mman-common.h
new file mode 100644
index 0000000..3b69ad3
--- /dev/null
+++ b/include/asm-generic/mman-common.h
@@ -0,0 +1,41 @@
+#ifndef __ASM_GENERIC_MMAN_COMMON_H
+#define __ASM_GENERIC_MMAN_COMMON_H
+
+/*
+ Author: Michael S. Tsirkin <mst@mellanox.co.il>, Mellanox Technologies Ltd.
+ Based on: asm-xxx/mman.h
+*/
+
+#define PROT_READ	0x1		/* page can be read */
+#define PROT_WRITE	0x2		/* page can be written */
+#define PROT_EXEC	0x4		/* page can be executed */
+#define PROT_SEM	0x8		/* page may be used for atomic ops */
+#define PROT_NONE	0x0		/* page can not be accessed */
+#define PROT_GROWSDOWN	0x01000000	/* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP	0x02000000	/* mprotect flag: extend change to end of growsup vma */
+
+#define MAP_SHARED	0x01		/* Share changes */
+#define MAP_PRIVATE	0x02		/* Changes are private */
+#define MAP_TYPE	0x0f		/* Mask for type of mapping */
+#define MAP_FIXED	0x10		/* Interpret addr exactly */
+#define MAP_ANONYMOUS	0x20		/* don't use a file */
+
+#define MS_ASYNC	1		/* sync memory asynchronously */
+#define MS_INVALIDATE	2		/* invalidate the caches */
+#define MS_SYNC		4		/* synchronous memory sync */
+
+#define MADV_NORMAL	0		/* no further special treatment */
+#define MADV_RANDOM	1		/* expect random page references */
+#define MADV_SEQUENTIAL	2		/* expect sequential page references */
+#define MADV_WILLNEED	3		/* will need these pages */
+#define MADV_DONTNEED	4		/* don't need these pages */
+
+/* common parameters: try to keep these consistent across architectures */
+#define MADV_REMOVE	9		/* remove these pages & resources */
+#define MADV_DONTFORK	10		/* don't inherit across fork */
+#define MADV_DOFORK	11		/* do inherit across fork */
+
+/* compatibility flags */
+#define MAP_FILE	0
+
+#endif /* __ASM_GENERIC_MMAN_COMMON_H */
diff --git a/include/asm-generic/mman.h b/include/asm-generic/mman.h
index 5e3dde2..7cab4de 100644
--- a/include/asm-generic/mman.h
+++ b/include/asm-generic/mman.h
@@ -1,41 +1,18 @@
-#ifndef _ASM_GENERIC_MMAN_H
-#define _ASM_GENERIC_MMAN_H
+#ifndef __ASM_GENERIC_MMAN_H
+#define __ASM_GENERIC_MMAN_H
 
-/*
- Author: Michael S. Tsirkin <mst@mellanox.co.il>, Mellanox Technologies Ltd.
- Based on: asm-xxx/mman.h
-*/
+#include <asm-generic/mman-common.h>
 
-#define PROT_READ	0x1		/* page can be read */
-#define PROT_WRITE	0x2		/* page can be written */
-#define PROT_EXEC	0x4		/* page can be executed */
-#define PROT_SEM	0x8		/* page may be used for atomic ops */
-#define PROT_NONE	0x0		/* page can not be accessed */
-#define PROT_GROWSDOWN	0x01000000	/* mprotect flag: extend change to start of growsdown vma */
-#define PROT_GROWSUP	0x02000000	/* mprotect flag: extend change to end of growsup vma */
+#define MAP_GROWSDOWN	0x0100		/* stack-like segment */
+#define MAP_DENYWRITE	0x0800		/* ETXTBSY */
+#define MAP_EXECUTABLE	0x1000		/* mark it as an executable */
+#define MAP_LOCKED	0x2000		/* pages are locked */
+#define MAP_NORESERVE	0x4000		/* don't check for reservations */
+#define MAP_POPULATE	0x8000		/* populate (prefault) pagetables */
+#define MAP_NONBLOCK	0x10000		/* do not block on IO */
+#define MAP_STACK	0x20000		/* give out an address that is best suited for process/thread stacks */
 
-#define MAP_SHARED	0x01		/* Share changes */
-#define MAP_PRIVATE	0x02		/* Changes are private */
-#define MAP_TYPE	0x0f		/* Mask for type of mapping */
-#define MAP_FIXED	0x10		/* Interpret addr exactly */
-#define MAP_ANONYMOUS	0x20		/* don't use a file */
+#define MCL_CURRENT	1		/* lock all current mappings */
+#define MCL_FUTURE	2		/* lock all future mappings */
 
-#define MS_ASYNC	1		/* sync memory asynchronously */
-#define MS_INVALIDATE	2		/* invalidate the caches */
-#define MS_SYNC		4		/* synchronous memory sync */
-
-#define MADV_NORMAL	0		/* no further special treatment */
-#define MADV_RANDOM	1		/* expect random page references */
-#define MADV_SEQUENTIAL	2		/* expect sequential page references */
-#define MADV_WILLNEED	3		/* will need these pages */
-#define MADV_DONTNEED	4		/* don't need these pages */
-
-/* common parameters: try to keep these consistent across architectures */
-#define MADV_REMOVE	9		/* remove these pages & resources */
-#define MADV_DONTFORK	10		/* don't inherit across fork */
-#define MADV_DOFORK	11		/* do inherit across fork */
-
-/* compatibility flags */
-#define MAP_FILE	0
-
-#endif
+#endif /* __ASM_GENERIC_MMAN_H */
diff --git a/include/asm-generic/mmu.h b/include/asm-generic/mmu.h
new file mode 100644
index 0000000..4f4aa56
--- /dev/null
+++ b/include/asm-generic/mmu.h
@@ -0,0 +1,15 @@
+#ifndef __ASM_GENERIC_MMU_H
+#define __ASM_GENERIC_MMU_H
+
+/*
+ * This is the mmu.h header for nommu implementations.
+ * Architectures with an MMU need something more complex.
+ */
+#ifndef __ASSEMBLY__
+typedef struct {
+	struct vm_list_struct	*vmlist;
+	unsigned long		end_brk;
+} mm_context_t;
+#endif
+
+#endif /* __ASM_GENERIC_MMU_H */
diff --git a/include/asm-generic/mmu_context.h b/include/asm-generic/mmu_context.h
new file mode 100644
index 0000000..a7eec91
--- /dev/null
+++ b/include/asm-generic/mmu_context.h
@@ -0,0 +1,45 @@
+#ifndef __ASM_GENERIC_MMU_CONTEXT_H
+#define __ASM_GENERIC_MMU_CONTEXT_H
+
+/*
+ * Generic hooks for NOMMU architectures, which do not need to do
+ * anything special here.
+ */
+
+#include <asm-generic/mm_hooks.h>
+
+struct task_struct;
+struct mm_struct;
+
+static inline void enter_lazy_tlb(struct mm_struct *mm,
+			struct task_struct *tsk)
+{
+}
+
+static inline int init_new_context(struct task_struct *tsk,
+			struct mm_struct *mm)
+{
+	return 0;
+}
+
+static inline void destroy_context(struct mm_struct *mm)
+{
+}
+
+static inline void deactivate_mm(struct task_struct *task,
+			struct mm_struct *mm)
+{
+}
+
+static inline void switch_mm(struct mm_struct *prev,
+			struct mm_struct *next,
+			struct task_struct *tsk)
+{
+}
+
+static inline void activate_mm(struct mm_struct *prev_mm,
+			       struct mm_struct *next_mm)
+{
+}
+
+#endif /* __ASM_GENERIC_MMU_CONTEXT_H */
diff --git a/include/asm-generic/module.h b/include/asm-generic/module.h
new file mode 100644
index 0000000..ed5b44d
--- /dev/null
+++ b/include/asm-generic/module.h
@@ -0,0 +1,22 @@
+#ifndef __ASM_GENERIC_MODULE_H
+#define __ASM_GENERIC_MODULE_H
+
+/*
+ * Many architectures just need a simple module
+ * loader without arch specific data.
+ */
+struct mod_arch_specific
+{
+};
+
+#ifdef CONFIG_64BIT
+#define Elf_Shdr Elf64_Shdr
+#define Elf_Sym Elf64_Sym
+#define Elf_Ehdr Elf64_Ehdr
+#else
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#define Elf_Ehdr Elf32_Ehdr
+#endif
+
+#endif /* __ASM_GENERIC_MODULE_H */
diff --git a/include/asm-generic/msgbuf.h b/include/asm-generic/msgbuf.h
new file mode 100644
index 0000000..aec850d
--- /dev/null
+++ b/include/asm-generic/msgbuf.h
@@ -0,0 +1,47 @@
+#ifndef __ASM_GENERIC_MSGBUF_H
+#define __ASM_GENERIC_MSGBUF_H
+
+#include <asm/bitsperlong.h>
+/*
+ * generic msqid64_ds structure.
+ *
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * msqid64_ds was originally meant to be architecture specific, but
+ * everyone just ended up making identical copies without specific
+ * optimizations, so we may just as well all use the same one.
+ *
+ * 64 bit architectures typically define a 64 bit __kernel_time_t,
+ * so they do not need the first three padding words.
+ * On big-endian systems, the padding is in the wrong place.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct msqid64_ds {
+	struct ipc64_perm msg_perm;
+	__kernel_time_t msg_stime;	/* last msgsnd time */
+#if __BITS_PER_LONG != 64
+	unsigned long	__unused1;
+#endif
+	__kernel_time_t msg_rtime;	/* last msgrcv time */
+#if __BITS_PER_LONG != 64
+	unsigned long	__unused2;
+#endif
+	__kernel_time_t msg_ctime;	/* last change time */
+#if __BITS_PER_LONG != 64
+	unsigned long	__unused3;
+#endif
+	unsigned long  msg_cbytes;	/* current number of bytes on queue */
+	unsigned long  msg_qnum;	/* number of messages in queue */
+	unsigned long  msg_qbytes;	/* max number of bytes on queue */
+	__kernel_pid_t msg_lspid;	/* pid of last msgsnd */
+	__kernel_pid_t msg_lrpid;	/* last receive pid */
+	unsigned long  __unused4;
+	unsigned long  __unused5;
+};
+
+#endif /* __ASM_GENERIC_MSGBUF_H */
diff --git a/include/asm-generic/mutex.h b/include/asm-generic/mutex.h
new file mode 100644
index 0000000..fe91ab5
--- /dev/null
+++ b/include/asm-generic/mutex.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_GENERIC_MUTEX_H
+#define __ASM_GENERIC_MUTEX_H
+/*
+ * Pull in the generic implementation for the mutex fastpath,
+ * which is a reasonable default on many architectures.
+ */
+
+#include <asm-generic/mutex-dec.h>
+#endif /* __ASM_GENERIC_MUTEX_H */
diff --git a/include/asm-generic/page.h b/include/asm-generic/page.h
index 14db733..75fec18 100644
--- a/include/asm-generic/page.h
+++ b/include/asm-generic/page.h
@@ -1,24 +1,99 @@
-#ifndef _ASM_GENERIC_PAGE_H
-#define _ASM_GENERIC_PAGE_H
+#ifndef __ASM_GENERIC_PAGE_H
+#define __ASM_GENERIC_PAGE_H
+/*
+ * Generic page.h implementation, for NOMMU architectures.
+ * This provides the dummy definitions for the memory management.
+ */
+
+#ifdef CONFIG_MMU
+#error need to prove a real asm/page.h
+#endif
+
+
+/* PAGE_SHIFT determines the page size */
+
+#define PAGE_SHIFT	12
+#ifdef __ASSEMBLY__
+#define PAGE_SIZE	(1 << PAGE_SHIFT)
+#else
+#define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#endif
+#define PAGE_MASK	(~(PAGE_SIZE-1))
+
+#include <asm/setup.h>
 
 #ifndef __ASSEMBLY__
 
-#include <linux/compiler.h>
+#define get_user_page(vaddr)		__get_free_page(GFP_KERNEL)
+#define free_user_page(page, addr)	free_page(addr)
 
-/* Pure 2^n version of get_order */
-static __inline__ __attribute_const__ int get_order(unsigned long size)
-{
-	int order;
+#define clear_page(page)	memset((page), 0, PAGE_SIZE)
+#define copy_page(to,from)	memcpy((to), (from), PAGE_SIZE)
 
-	size = (size - 1) >> (PAGE_SHIFT - 1);
-	order = -1;
-	do {
-		size >>= 1;
-		order++;
-	} while (size);
-	return order;
-}
+#define clear_user_page(page, vaddr, pg)	clear_page(page)
+#define copy_user_page(to, from, vaddr, pg)	copy_page(to, from)
 
-#endif	/* __ASSEMBLY__ */
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct {
+	unsigned long pte;
+} pte_t;
+typedef struct {
+	unsigned long pmd[16];
+} pmd_t;
+typedef struct {
+	unsigned long pgd;
+} pgd_t;
+typedef struct {
+	unsigned long pgprot;
+} pgprot_t;
+typedef struct page *pgtable_t;
 
-#endif	/* _ASM_GENERIC_PAGE_H */
+#define pte_val(x)	((x).pte)
+#define pmd_val(x)	((&x)->pmd[0])
+#define pgd_val(x)	((x).pgd)
+#define pgprot_val(x)	((x).pgprot)
+
+#define __pte(x)	((pte_t) { (x) } )
+#define __pmd(x)	((pmd_t) { (x) } )
+#define __pgd(x)	((pgd_t) { (x) } )
+#define __pgprot(x)	((pgprot_t) { (x) } )
+
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+
+#endif /* !__ASSEMBLY__ */
+
+#ifdef CONFIG_KERNEL_RAM_BASE_ADDRESS
+#define PAGE_OFFSET		(CONFIG_KERNEL_RAM_BASE_ADDRESS)
+#else
+#define PAGE_OFFSET		(0)
+#endif
+
+#ifndef __ASSEMBLY__
+
+#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
+#define __pa(x) ((unsigned long) (x) - PAGE_OFFSET)
+
+#define virt_to_pfn(kaddr)	(__pa(kaddr) >> PAGE_SHIFT)
+#define pfn_to_virt(pfn)	__va((pfn) << PAGE_SHIFT)
+
+#define virt_to_page(addr)	(mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT))
+#define page_to_virt(page)	((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET)
+
+#ifndef page_to_phys
+#define page_to_phys(page)      ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
+#endif
+
+#define pfn_valid(pfn)		((pfn) < max_mapnr)
+
+#define	virt_addr_valid(kaddr)	(((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
+				((void *)(kaddr) < (void *)memory_end))
+
+#endif /* __ASSEMBLY__ */
+
+#include <asm-generic/memory_model.h>
+#include <asm-generic/getorder.h>
+
+#endif /* __ASM_GENERIC_PAGE_H */
diff --git a/include/asm-generic/param.h b/include/asm-generic/param.h
new file mode 100644
index 0000000..cdf8251
--- /dev/null
+++ b/include/asm-generic/param.h
@@ -0,0 +1,24 @@
+#ifndef __ASM_GENERIC_PARAM_H
+#define __ASM_GENERIC_PARAM_H
+
+#ifdef __KERNEL__
+# define HZ		CONFIG_HZ	/* Internal kernel timer frequency */
+# define USER_HZ	100		/* some user interfaces are */
+# define CLOCKS_PER_SEC	(USER_HZ)       /* in "ticks" like times() */
+#endif
+
+#ifndef HZ
+#define HZ 100
+#endif
+
+#ifndef EXEC_PAGESIZE
+#define EXEC_PAGESIZE	4096
+#endif
+
+#ifndef NOGROUP
+#define NOGROUP		(-1)
+#endif
+
+#define MAXHOSTNAMELEN	64	/* max length of hostname */
+
+#endif /* __ASM_GENERIC_PARAM_H */
diff --git a/include/asm-generic/parport.h b/include/asm-generic/parport.h
new file mode 100644
index 0000000..40528cb
--- /dev/null
+++ b/include/asm-generic/parport.h
@@ -0,0 +1,23 @@
+#ifndef __ASM_GENERIC_PARPORT_H
+#define __ASM_GENERIC_PARPORT_H
+
+/*
+ * An ISA bus may have i8255 parallel ports at well-known
+ * locations in the I/O space, which are scanned by
+ * parport_pc_find_isa_ports.
+ *
+ * Without ISA support, the driver will only attach
+ * to devices on the PCI bus.
+ */
+
+static int __devinit parport_pc_find_isa_ports(int autoirq, int autodma);
+static int __devinit parport_pc_find_nonpci_ports(int autoirq, int autodma)
+{
+#ifdef CONFIG_ISA
+	return parport_pc_find_isa_ports(autoirq, autodma);
+#else
+	return 0;
+#endif
+}
+
+#endif /* __ASM_GENERIC_PARPORT_H */
diff --git a/include/asm-generic/pci.h b/include/asm-generic/pci.h
index c36a77d..515c6e2 100644
--- a/include/asm-generic/pci.h
+++ b/include/asm-generic/pci.h
@@ -52,4 +52,12 @@
 }
 #endif /* HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ */
 
+/*
+ * By default, assume that no iommu is in use and that the PCI
+ * space is mapped to address physical 0.
+ */
+#ifndef PCI_DMA_BUS_IS_PHYS
+#define PCI_DMA_BUS_IS_PHYS	(1)
 #endif
+
+#endif /* _ASM_GENERIC_PCI_H */
diff --git a/include/asm-generic/pgalloc.h b/include/asm-generic/pgalloc.h
new file mode 100644
index 0000000..9e429d0
--- /dev/null
+++ b/include/asm-generic/pgalloc.h
@@ -0,0 +1,12 @@
+#ifndef __ASM_GENERIC_PGALLOC_H
+#define __ASM_GENERIC_PGALLOC_H
+/*
+ * an empty file is enough for a nommu architecture
+ */
+#ifdef CONFIG_MMU
+#error need to implement an architecture specific asm/pgalloc.h
+#endif
+
+#define check_pgt_cache()          do { } while (0)
+
+#endif /* __ASM_GENERIC_PGALLOC_H */
diff --git a/include/asm-generic/posix_types.h b/include/asm-generic/posix_types.h
new file mode 100644
index 0000000..3dab008
--- /dev/null
+++ b/include/asm-generic/posix_types.h
@@ -0,0 +1,165 @@
+#ifndef __ASM_GENERIC_POSIX_TYPES_H
+#define __ASM_GENERIC_POSIX_TYPES_H
+
+#include <asm/bitsperlong.h>
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.
+ *
+ * First the types that are often defined in different ways across
+ * architectures, so that you can override them.
+ */
+
+#ifndef __kernel_ino_t
+typedef unsigned long	__kernel_ino_t;
+#endif
+
+#ifndef __kernel_mode_t
+typedef unsigned int	__kernel_mode_t;
+#endif
+
+#ifndef __kernel_nlink_t
+typedef unsigned long	__kernel_nlink_t;
+#endif
+
+#ifndef __kernel_pid_t
+typedef int		__kernel_pid_t;
+#endif
+
+#ifndef __kernel_ipc_pid_t
+typedef int		__kernel_ipc_pid_t;
+#endif
+
+#ifndef __kernel_uid_t
+typedef unsigned int	__kernel_uid_t;
+typedef unsigned int	__kernel_gid_t;
+#endif
+
+#ifndef __kernel_suseconds_t
+typedef long		__kernel_suseconds_t;
+#endif
+
+#ifndef __kernel_daddr_t
+typedef int		__kernel_daddr_t;
+#endif
+
+#ifndef __kernel_uid32_t
+typedef __kernel_uid_t	__kernel_uid32_t;
+typedef __kernel_gid_t	__kernel_gid32_t;
+#endif
+
+#ifndef __kernel_old_uid_t
+typedef __kernel_uid_t	__kernel_old_uid_t;
+typedef __kernel_gid_t	__kernel_old_gid_t;
+#endif
+
+#ifndef __kernel_old_dev_t
+typedef unsigned int	__kernel_old_dev_t;
+#endif
+
+/*
+ * Most 32 bit architectures use "unsigned int" size_t,
+ * and all 64 bit architectures use "unsigned long" size_t.
+ */
+#ifndef __kernel_size_t
+#if __BITS_PER_LONG != 64
+typedef unsigned int	__kernel_size_t;
+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;
+#endif
+#endif
+
+/*
+ * anything below here should be completely generic
+ */
+typedef long		__kernel_off_t;
+typedef long long	__kernel_loff_t;
+typedef long		__kernel_time_t;
+typedef long		__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/rtc.h b/include/asm-generic/rtc.h
index 763e3b0..fa86f24 100644
--- a/include/asm-generic/rtc.h
+++ b/include/asm-generic/rtc.h
@@ -202,7 +202,7 @@
 {
 	struct rtc_time h;
 
-	__get_rtc_time(&h);
+	get_rtc_time(&h);
 	return h.tm_sec;
 }
 
diff --git a/include/asm-generic/scatterlist.h b/include/asm-generic/scatterlist.h
new file mode 100644
index 0000000..8b94544
--- /dev/null
+++ b/include/asm-generic/scatterlist.h
@@ -0,0 +1,43 @@
+#ifndef __ASM_GENERIC_SCATTERLIST_H
+#define __ASM_GENERIC_SCATTERLIST_H
+
+#include <linux/types.h>
+
+struct scatterlist {
+#ifdef CONFIG_DEBUG_SG
+	unsigned long	sg_magic;
+#endif
+	unsigned long	page_link;
+	unsigned int	offset;
+	unsigned int	length;
+	dma_addr_t	dma_address;
+	unsigned int	dma_length;
+};
+
+/*
+ * These macros should be used after a dma_map_sg call has been done
+ * to get bus addresses of each of the SG entries and their lengths.
+ * You should only work with the number of sg entries pci_map_sg
+ * returns, or alternatively stop on the first sg_dma_len(sg) which
+ * is 0.
+ */
+#define sg_dma_address(sg)	((sg)->dma_address)
+#ifndef sg_dma_len
+/*
+ * Normally, you have an iommu on 64 bit machines, but not on 32 bit
+ * machines. Architectures that are differnt should override this.
+ */
+#if __BITS_PER_LONG == 64
+#define sg_dma_len(sg)		((sg)->dma_length)
+#else
+#define sg_dma_len(sg)		((sg)->length)
+#endif /* 64 bit */
+#endif /* sg_dma_len */
+
+#ifndef ISA_DMA_THRESHOLD
+#define ISA_DMA_THRESHOLD	(~0UL)
+#endif
+
+#define ARCH_HAS_SG_CHAIN
+
+#endif /* __ASM_GENERIC_SCATTERLIST_H */
diff --git a/include/asm-generic/segment.h b/include/asm-generic/segment.h
new file mode 100644
index 0000000..5580eac
--- /dev/null
+++ b/include/asm-generic/segment.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_GENERIC_SEGMENT_H
+#define __ASM_GENERIC_SEGMENT_H
+/*
+ * Only here because we have some old header files that expect it...
+ *
+ * New architectures probably don't want to have their own version.
+ */
+
+#endif /* __ASM_GENERIC_SEGMENT_H */
diff --git a/include/asm-generic/sembuf.h b/include/asm-generic/sembuf.h
new file mode 100644
index 0000000..4cb2c13
--- /dev/null
+++ b/include/asm-generic/sembuf.h
@@ -0,0 +1,38 @@
+#ifndef __ASM_GENERIC_SEMBUF_H
+#define __ASM_GENERIC_SEMBUF_H
+
+#include <asm/bitsperlong.h>
+
+/*
+ * The semid64_ds structure for x86 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * semid64_ds was originally meant to be architecture specific, but
+ * everyone just ended up making identical copies without specific
+ * optimizations, so we may just as well all use the same one.
+ *
+ * 64 bit architectures typically define a 64 bit __kernel_time_t,
+ * so they do not need the first two padding words.
+ * On big-endian systems, the padding is in the wrong place.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+struct semid64_ds {
+	struct ipc64_perm sem_perm;	/* permissions .. see ipc.h */
+	__kernel_time_t	sem_otime;	/* last semop time */
+#if __BITS_PER_LONG != 64
+	unsigned long	__unused1;
+#endif
+	__kernel_time_t	sem_ctime;	/* last change time */
+#if __BITS_PER_LONG != 64
+	unsigned long	__unused2;
+#endif
+	unsigned long	sem_nsems;	/* no. of semaphores in array */
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+#endif /* __ASM_GENERIC_SEMBUF_H */
diff --git a/include/asm-generic/serial.h b/include/asm-generic/serial.h
new file mode 100644
index 0000000..5e29109
--- /dev/null
+++ b/include/asm-generic/serial.h
@@ -0,0 +1,13 @@
+#ifndef __ASM_GENERIC_SERIAL_H
+#define __ASM_GENERIC_SERIAL_H
+
+/*
+ * This should not be an architecture specific #define, oh well.
+ *
+ * Traditionally, it just describes i8250 and related serial ports
+ * that have this clock rate.
+ */
+
+#define BASE_BAUD (1843200 / 16)
+
+#endif /* __ASM_GENERIC_SERIAL_H */
diff --git a/include/asm-generic/setup.h b/include/asm-generic/setup.h
new file mode 100644
index 0000000..6fc26a5
--- /dev/null
+++ b/include/asm-generic/setup.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_GENERIC_SETUP_H
+#define __ASM_GENERIC_SETUP_H
+
+#define COMMAND_LINE_SIZE	512
+
+#endif	/* __ASM_GENERIC_SETUP_H */
diff --git a/include/asm-generic/shmbuf.h b/include/asm-generic/shmbuf.h
new file mode 100644
index 0000000..5768fa6
--- /dev/null
+++ b/include/asm-generic/shmbuf.h
@@ -0,0 +1,59 @@
+#ifndef __ASM_GENERIC_SHMBUF_H
+#define __ASM_GENERIC_SHMBUF_H
+
+#include <asm/bitsperlong.h>
+
+/*
+ * The shmid64_ds structure for x86 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * shmid64_ds was originally meant to be architecture specific, but
+ * everyone just ended up making identical copies without specific
+ * optimizations, so we may just as well all use the same one.
+ *
+ * 64 bit architectures typically define a 64 bit __kernel_time_t,
+ * so they do not need the first two padding words.
+ * On big-endian systems, the padding is in the wrong place.
+ *
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+	struct ipc64_perm	shm_perm;	/* operation perms */
+	size_t			shm_segsz;	/* size of segment (bytes) */
+	__kernel_time_t		shm_atime;	/* last attach time */
+#if __BITS_PER_LONG != 64
+	unsigned long		__unused1;
+#endif
+	__kernel_time_t		shm_dtime;	/* last detach time */
+#if __BITS_PER_LONG != 64
+	unsigned long		__unused2;
+#endif
+	__kernel_time_t		shm_ctime;	/* last change time */
+#if __BITS_PER_LONG != 64
+	unsigned long		__unused3;
+#endif
+	__kernel_pid_t		shm_cpid;	/* pid of creator */
+	__kernel_pid_t		shm_lpid;	/* pid of last operator */
+	unsigned long		shm_nattch;	/* no. of current attaches */
+	unsigned long		__unused4;
+	unsigned long		__unused5;
+};
+
+struct shminfo64 {
+	unsigned long	shmmax;
+	unsigned long	shmmin;
+	unsigned long	shmmni;
+	unsigned long	shmseg;
+	unsigned long	shmall;
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+#endif /* __ASM_GENERIC_SHMBUF_H */
diff --git a/include/asm-generic/shmparam.h b/include/asm-generic/shmparam.h
new file mode 100644
index 0000000..51a3852
--- /dev/null
+++ b/include/asm-generic/shmparam.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_GENERIC_SHMPARAM_H
+#define __ASM_GENERIC_SHMPARAM_H
+
+#define SHMLBA PAGE_SIZE	 /* attach addr a multiple of this */
+
+#endif /* _ASM_GENERIC_SHMPARAM_H */
diff --git a/include/asm-generic/signal-defs.h b/include/asm-generic/signal-defs.h
new file mode 100644
index 0000000..00f95df
--- /dev/null
+++ b/include/asm-generic/signal-defs.h
@@ -0,0 +1,28 @@
+#ifndef __ASM_GENERIC_SIGNAL_DEFS_H
+#define __ASM_GENERIC_SIGNAL_DEFS_H
+
+#include <linux/compiler.h>
+
+#ifndef SIG_BLOCK
+#define SIG_BLOCK          0	/* for blocking signals */
+#endif
+#ifndef SIG_UNBLOCK
+#define SIG_UNBLOCK        1	/* for unblocking signals */
+#endif
+#ifndef SIG_SETMASK
+#define SIG_SETMASK        2	/* for setting the signal mask */
+#endif
+
+#ifndef __ASSEMBLY__
+typedef void __signalfn_t(int);
+typedef __signalfn_t __user *__sighandler_t;
+
+typedef void __restorefn_t(void);
+typedef __restorefn_t __user *__sigrestore_t;
+
+#define SIG_DFL	((__force __sighandler_t)0)	/* default signal handling */
+#define SIG_IGN	((__force __sighandler_t)1)	/* ignore signal */
+#define SIG_ERR	((__force __sighandler_t)-1)	/* error return from signal */
+#endif
+
+#endif /* __ASM_GENERIC_SIGNAL_DEFS_H */
diff --git a/include/asm-generic/signal.h b/include/asm-generic/signal.h
index dae1d87..555c0ae 100644
--- a/include/asm-generic/signal.h
+++ b/include/asm-generic/signal.h
@@ -1,28 +1,131 @@
 #ifndef __ASM_GENERIC_SIGNAL_H
 #define __ASM_GENERIC_SIGNAL_H
 
-#include <linux/compiler.h>
+#include <linux/types.h>
 
-#ifndef SIG_BLOCK
-#define SIG_BLOCK          0	/* for blocking signals */
+#define _NSIG		64
+#define _NSIG_BPW	__BITS_PER_LONG
+#define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
+
+#define SIGHUP		 1
+#define SIGINT		 2
+#define SIGQUIT		 3
+#define SIGILL		 4
+#define SIGTRAP		 5
+#define SIGABRT		 6
+#define SIGIOT		 6
+#define SIGBUS		 7
+#define SIGFPE		 8
+#define SIGKILL		 9
+#define SIGUSR1		10
+#define SIGSEGV		11
+#define SIGUSR2		12
+#define SIGPIPE		13
+#define SIGALRM		14
+#define SIGTERM		15
+#define SIGSTKFLT	16
+#define SIGCHLD		17
+#define SIGCONT		18
+#define SIGSTOP		19
+#define SIGTSTP		20
+#define SIGTTIN		21
+#define SIGTTOU		22
+#define SIGURG		23
+#define SIGXCPU		24
+#define SIGXFSZ		25
+#define SIGVTALRM	26
+#define SIGPROF		27
+#define SIGWINCH	28
+#define SIGIO		29
+#define SIGPOLL		SIGIO
+/*
+#define SIGLOST		29
+*/
+#define SIGPWR		30
+#define SIGSYS		31
+#define	SIGUNUSED	31
+
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN	32
+#ifndef SIGRTMAX
+#define SIGRTMAX	_NSIG
 #endif
-#ifndef SIG_UNBLOCK
-#define SIG_UNBLOCK        1	/* for unblocking signals */
-#endif
-#ifndef SIG_SETMASK
-#define SIG_SETMASK        2	/* for setting the signal mask */
-#endif
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP	0x00000001
+#define SA_NOCLDWAIT	0x00000002
+#define SA_SIGINFO	0x00000004
+#define SA_ONSTACK	0x08000000
+#define SA_RESTART	0x10000000
+#define SA_NODEFER	0x40000000
+#define SA_RESETHAND	0x80000000
+
+#define SA_NOMASK	SA_NODEFER
+#define SA_ONESHOT	SA_RESETHAND
+
+/*
+ * New architectures should not define the obsolete
+ *	SA_RESTORER	0x04000000
+ */
+
+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK	1
+#define SS_DISABLE	2
+
+#define MINSIGSTKSZ	2048
+#define SIGSTKSZ	8192
 
 #ifndef __ASSEMBLY__
-typedef void __signalfn_t(int);
-typedef __signalfn_t __user *__sighandler_t;
+typedef struct {
+	unsigned long sig[_NSIG_WORDS];
+} sigset_t;
 
-typedef void __restorefn_t(void);
-typedef __restorefn_t __user *__sigrestore_t;
+/* not actually used, but required for linux/syscalls.h */
+typedef unsigned long old_sigset_t;
 
-#define SIG_DFL	((__force __sighandler_t)0)	/* default signal handling */
-#define SIG_IGN	((__force __sighandler_t)1)	/* ignore signal */
-#define SIG_ERR	((__force __sighandler_t)-1)	/* error return from signal */
+#include <asm-generic/signal-defs.h>
+
+struct sigaction {
+	__sighandler_t sa_handler;
+	unsigned long sa_flags;
+#ifdef SA_RESTORER
+	__sigrestore_t sa_restorer;
 #endif
+	sigset_t sa_mask;		/* mask last for extensibility */
+};
 
-#endif /* __ASM_GENERIC_SIGNAL_H */
+struct k_sigaction {
+	struct sigaction sa;
+};
+
+typedef struct sigaltstack {
+	void __user *ss_sp;
+	int ss_flags;
+	size_t ss_size;
+} stack_t;
+
+#ifdef __KERNEL__
+
+#include <asm/sigcontext.h>
+#undef __HAVE_ARCH_SIG_BITOPS
+
+#define ptrace_signal_deliver(regs, cookie) do { } while (0)
+
+#endif /* __KERNEL__ */
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_GENERIC_SIGNAL_H */
diff --git a/include/asm-generic/socket.h b/include/asm-generic/socket.h
new file mode 100644
index 0000000..5d79e40
--- /dev/null
+++ b/include/asm-generic/socket.h
@@ -0,0 +1,63 @@
+#ifndef __ASM_GENERIC_SOCKET_H
+#define __ASM_GENERIC_SOCKET_H
+
+#include <asm/sockios.h>
+
+/* For setsockopt(2) */
+#define SOL_SOCKET	1
+
+#define SO_DEBUG	1
+#define SO_REUSEADDR	2
+#define SO_TYPE		3
+#define SO_ERROR	4
+#define SO_DONTROUTE	5
+#define SO_BROADCAST	6
+#define SO_SNDBUF	7
+#define SO_RCVBUF	8
+#define SO_SNDBUFFORCE	32
+#define SO_RCVBUFFORCE	33
+#define SO_KEEPALIVE	9
+#define SO_OOBINLINE	10
+#define SO_NO_CHECK	11
+#define SO_PRIORITY	12
+#define SO_LINGER	13
+#define SO_BSDCOMPAT	14
+/* To add :#define SO_REUSEPORT 15 */
+
+#ifndef SO_PASSCRED /* powerpc only differs in these */
+#define SO_PASSCRED	16
+#define SO_PEERCRED	17
+#define SO_RCVLOWAT	18
+#define SO_SNDLOWAT	19
+#define SO_RCVTIMEO	20
+#define SO_SNDTIMEO	21
+#endif
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION		22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT	23
+#define SO_SECURITY_ENCRYPTION_NETWORK		24
+
+#define SO_BINDTODEVICE	25
+
+/* Socket filtering */
+#define SO_ATTACH_FILTER	26
+#define SO_DETACH_FILTER	27
+
+#define SO_PEERNAME		28
+#define SO_TIMESTAMP		29
+#define SCM_TIMESTAMP		SO_TIMESTAMP
+
+#define SO_ACCEPTCONN		30
+
+#define SO_PEERSEC		31
+#define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+
+#define SO_MARK			36
+
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
+
+#endif /* __ASM_GENERIC_SOCKET_H */
diff --git a/include/asm-generic/sockios.h b/include/asm-generic/sockios.h
new file mode 100644
index 0000000..9a61a36
--- /dev/null
+++ b/include/asm-generic/sockios.h
@@ -0,0 +1,13 @@
+#ifndef __ASM_GENERIC_SOCKIOS_H
+#define __ASM_GENERIC_SOCKIOS_H
+
+/* Socket-level I/O control calls. */
+#define FIOSETOWN	0x8901
+#define SIOCSPGRP	0x8902
+#define FIOGETOWN	0x8903
+#define SIOCGPGRP	0x8904
+#define SIOCATMARK	0x8905
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
+
+#endif /* __ASM_GENERIC_SOCKIOS_H */
diff --git a/include/asm-generic/spinlock.h b/include/asm-generic/spinlock.h
new file mode 100644
index 0000000..1547a03
--- /dev/null
+++ b/include/asm-generic/spinlock.h
@@ -0,0 +1,11 @@
+#ifndef __ASM_GENERIC_SPINLOCK_H
+#define __ASM_GENERIC_SPINLOCK_H
+/*
+ * You need to implement asm/spinlock.h for SMP support. The generic
+ * version does not handle SMP.
+ */
+#ifdef CONFIG_SMP
+#error need an architecture specific asm/spinlock.h
+#endif
+
+#endif /* __ASM_GENERIC_SPINLOCK_H */
diff --git a/include/asm-generic/stat.h b/include/asm-generic/stat.h
new file mode 100644
index 0000000..47e6417
--- /dev/null
+++ b/include/asm-generic/stat.h
@@ -0,0 +1,72 @@
+#ifndef __ASM_GENERIC_STAT_H
+#define __ASM_GENERIC_STAT_H
+
+/*
+ * Everybody gets this wrong and has to stick with it for all
+ * eternity. Hopefully, this version gets used by new architectures
+ * so they don't fall into the same traps.
+ *
+ * stat64 is copied from powerpc64, with explicit padding added.
+ * stat is the same structure layout on 64-bit, without the 'long long'
+ * types.
+ *
+ * By convention, 64 bit architectures use the stat interface, while
+ * 32 bit architectures use the stat64 interface. Note that we don't
+ * provide an __old_kernel_stat here, which new architecture should
+ * not have to start with.
+ */
+
+#include <asm/bitsperlong.h>
+
+#define STAT_HAVE_NSEC 1
+
+struct stat {
+	unsigned long	st_dev;		/* Device.  */
+	unsigned long	st_ino;		/* File serial number.  */
+	unsigned int	st_mode;	/* File mode.  */
+	unsigned int	st_nlink;	/* Link count.  */
+	unsigned int	st_uid;		/* User ID of the file's owner.  */
+	unsigned int	st_gid;		/* Group ID of the file's group. */
+	unsigned long	st_rdev;	/* Device number, if device.  */
+	unsigned long	__pad1;
+	long		st_size;	/* Size of file, in bytes.  */
+	int		st_blksize;	/* Optimal block size for I/O.  */
+	int		__pad2;
+	long		st_blocks;	/* Number 512-byte blocks allocated. */
+	int		st_atime;	/* Time of last access.  */
+	unsigned int	st_atime_nsec;
+	int		st_mtime;	/* Time of last modification.  */
+	unsigned int	st_mtime_nsec;
+	int		st_ctime;	/* Time of last status change.  */
+	unsigned int	st_ctime_nsec;
+	unsigned int	__unused4;
+	unsigned int	__unused5;
+};
+
+#if __BITS_PER_LONG != 64
+/* This matches struct stat64 in glibc2.1. Only used for 32 bit. */
+struct stat64 {
+	unsigned long long st_dev;	/* Device.  */
+	unsigned long long st_ino;	/* File serial number.  */
+	unsigned int	st_mode;	/* File mode.  */
+	unsigned int	st_nlink;	/* Link count.  */
+	unsigned int	st_uid;		/* User ID of the file's owner.  */
+	unsigned int	st_gid;		/* Group ID of the file's group. */
+	unsigned long long st_rdev;	/* Device number, if device.  */
+	unsigned long long __pad1;
+	long long	st_size;	/* Size of file, in bytes.  */
+	int		st_blksize;	/* Optimal block size for I/O.  */
+	int		__pad2;
+	long long	st_blocks;	/* Number 512-byte blocks allocated. */
+	int		st_atime;	/* Time of last access.  */
+	unsigned int	st_atime_nsec;
+	int		st_mtime;	/* Time of last modification.  */
+	unsigned int	st_mtime_nsec;
+	int		st_ctime;	/* Time of last status change.  */
+	unsigned int	st_ctime_nsec;
+	unsigned int	__unused4;
+	unsigned int	__unused5;
+};
+#endif
+
+#endif /* __ASM_GENERIC_STAT_H */
diff --git a/include/asm-generic/string.h b/include/asm-generic/string.h
new file mode 100644
index 0000000..de5e020
--- /dev/null
+++ b/include/asm-generic/string.h
@@ -0,0 +1,10 @@
+#ifndef __ASM_GENERIC_STRING_H
+#define __ASM_GENERIC_STRING_H
+/*
+ * The kernel provides all required functions in lib/string.c
+ *
+ * Architectures probably want to provide at least their own optimized
+ * memcpy and memset functions though.
+ */
+
+#endif /* __ASM_GENERIC_STRING_H */
diff --git a/include/asm-generic/swab.h b/include/asm-generic/swab.h
new file mode 100644
index 0000000..a8e9029
--- /dev/null
+++ b/include/asm-generic/swab.h
@@ -0,0 +1,18 @@
+#ifndef _ASM_GENERIC_SWAB_H
+#define _ASM_GENERIC_SWAB_H
+
+#include <asm/bitsperlong.h>
+
+/*
+ * 32 bit architectures typically (but not always) want to
+ * set __SWAB_64_THRU_32__. In user space, this is only
+ * valid if the compiler supports 64 bit data types.
+ */
+
+#if __BITS_PER_LONG == 32
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+#define __SWAB_64_THRU_32__
+#endif
+#endif
+
+#endif /* _ASM_GENERIC_SWAB_H */
diff --git a/include/asm-generic/syscalls.h b/include/asm-generic/syscalls.h
new file mode 100644
index 0000000..df84e3b
--- /dev/null
+++ b/include/asm-generic/syscalls.h
@@ -0,0 +1,60 @@
+#ifndef __ASM_GENERIC_SYSCALLS_H
+#define __ASM_GENERIC_SYSCALLS_H
+
+#include <linux/compiler.h>
+#include <linux/linkage.h>
+
+/*
+ * Calling conventions for these system calls can differ, so
+ * it's possible to override them.
+ */
+#ifndef sys_clone
+asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
+			void __user *parent_tid, void __user *child_tid,
+			struct pt_regs *regs);
+#endif
+
+#ifndef sys_fork
+asmlinkage long sys_fork(struct pt_regs *regs);
+#endif
+
+#ifndef sys_vfork
+asmlinkage long sys_vfork(struct pt_regs *regs);
+#endif
+
+#ifndef sys_execve
+asmlinkage long sys_execve(char __user *filename, char __user * __user *argv,
+			char __user * __user *envp, struct pt_regs *regs);
+#endif
+
+#ifndef sys_mmap2
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, unsigned long pgoff);
+#endif
+
+#ifndef sys_mmap
+asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, off_t pgoff);
+#endif
+
+#ifndef sys_sigaltstack
+asmlinkage long sys_sigaltstack(const stack_t __user *, stack_t __user *,
+			struct pt_regs *);
+#endif
+
+#ifndef sys_rt_sigreturn
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs);
+#endif
+
+#ifndef sys_rt_sigsuspend
+asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize);
+#endif
+
+#ifndef sys_rt_sigaction
+asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act,
+			 struct sigaction __user *oact, size_t sigsetsize);
+#endif
+
+#endif /* __ASM_GENERIC_SYSCALLS_H */
diff --git a/include/asm-generic/system.h b/include/asm-generic/system.h
new file mode 100644
index 0000000..efa403b
--- /dev/null
+++ b/include/asm-generic/system.h
@@ -0,0 +1,161 @@
+/* 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
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <linux/irqflags.h>
+
+#include <asm/cmpxchg-local.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))))
+
+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)))
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_GENERIC_SYSTEM_H */
diff --git a/include/asm-generic/termbits.h b/include/asm-generic/termbits.h
new file mode 100644
index 0000000..1c9773d
--- /dev/null
+++ b/include/asm-generic/termbits.h
@@ -0,0 +1,198 @@
+#ifndef __ASM_GENERIC_TERMBITS_H
+#define __ASM_GENERIC_TERMBITS_H
+
+#include <linux/posix_types.h>
+
+typedef unsigned char	cc_t;
+typedef unsigned int	speed_t;
+typedef unsigned int	tcflag_t;
+
+#define NCCS 19
+struct termios {
+	tcflag_t c_iflag;		/* input mode flags */
+	tcflag_t c_oflag;		/* output mode flags */
+	tcflag_t c_cflag;		/* control mode flags */
+	tcflag_t c_lflag;		/* local mode flags */
+	cc_t c_line;			/* line discipline */
+	cc_t c_cc[NCCS];		/* control characters */
+};
+
+struct termios2 {
+	tcflag_t c_iflag;		/* input mode flags */
+	tcflag_t c_oflag;		/* output mode flags */
+	tcflag_t c_cflag;		/* control mode flags */
+	tcflag_t c_lflag;		/* local mode flags */
+	cc_t c_line;			/* line discipline */
+	cc_t c_cc[NCCS];		/* control characters */
+	speed_t c_ispeed;		/* input speed */
+	speed_t c_ospeed;		/* output speed */
+};
+
+struct ktermios {
+	tcflag_t c_iflag;		/* input mode flags */
+	tcflag_t c_oflag;		/* output mode flags */
+	tcflag_t c_cflag;		/* control mode flags */
+	tcflag_t c_lflag;		/* local mode flags */
+	cc_t c_line;			/* line discipline */
+	cc_t c_cc[NCCS];		/* control characters */
+	speed_t c_ispeed;		/* input speed */
+	speed_t c_ospeed;		/* output speed */
+};
+
+/* c_cc characters */
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+/* c_iflag bits */
+#define IGNBRK	0000001
+#define BRKINT	0000002
+#define IGNPAR	0000004
+#define PARMRK	0000010
+#define INPCK	0000020
+#define ISTRIP	0000040
+#define INLCR	0000100
+#define IGNCR	0000200
+#define ICRNL	0000400
+#define IUCLC	0001000
+#define IXON	0002000
+#define IXANY	0004000
+#define IXOFF	0010000
+#define IMAXBEL	0020000
+#define IUTF8	0040000
+
+/* c_oflag bits */
+#define OPOST	0000001
+#define OLCUC	0000002
+#define ONLCR	0000004
+#define OCRNL	0000010
+#define ONOCR	0000020
+#define ONLRET	0000040
+#define OFILL	0000100
+#define OFDEL	0000200
+#define NLDLY	0000400
+#define   NL0	0000000
+#define   NL1	0000400
+#define CRDLY	0003000
+#define   CR0	0000000
+#define   CR1	0001000
+#define   CR2	0002000
+#define   CR3	0003000
+#define TABDLY	0014000
+#define   TAB0	0000000
+#define   TAB1	0004000
+#define   TAB2	0010000
+#define   TAB3	0014000
+#define   XTABS	0014000
+#define BSDLY	0020000
+#define   BS0	0000000
+#define   BS1	0020000
+#define VTDLY	0040000
+#define   VT0	0000000
+#define   VT1	0040000
+#define FFDLY	0100000
+#define   FF0	0000000
+#define   FF1	0100000
+
+/* c_cflag bit meaning */
+#define CBAUD	0010017
+#define  B0	0000000		/* hang up */
+#define  B50	0000001
+#define  B75	0000002
+#define  B110	0000003
+#define  B134	0000004
+#define  B150	0000005
+#define  B200	0000006
+#define  B300	0000007
+#define  B600	0000010
+#define  B1200	0000011
+#define  B1800	0000012
+#define  B2400	0000013
+#define  B4800	0000014
+#define  B9600	0000015
+#define  B19200	0000016
+#define  B38400	0000017
+#define EXTA B19200
+#define EXTB B38400
+#define CSIZE	0000060
+#define   CS5	0000000
+#define   CS6	0000020
+#define   CS7	0000040
+#define   CS8	0000060
+#define CSTOPB	0000100
+#define CREAD	0000200
+#define PARENB	0000400
+#define PARODD	0001000
+#define HUPCL	0002000
+#define CLOCAL	0004000
+#define CBAUDEX 0010000
+#define    BOTHER 0010000
+#define    B57600 0010001
+#define   B115200 0010002
+#define   B230400 0010003
+#define   B460800 0010004
+#define   B500000 0010005
+#define   B576000 0010006
+#define   B921600 0010007
+#define  B1000000 0010010
+#define  B1152000 0010011
+#define  B1500000 0010012
+#define  B2000000 0010013
+#define  B2500000 0010014
+#define  B3000000 0010015
+#define  B3500000 0010016
+#define  B4000000 0010017
+#define CIBAUD	  002003600000	/* input baud rate */
+#define CMSPAR	  010000000000	/* mark or space (stick) parity */
+#define CRTSCTS	  020000000000	/* flow control */
+
+#define IBSHIFT	  16		/* Shift from CBAUD to CIBAUD */
+
+/* c_lflag bits */
+#define ISIG	0000001
+#define ICANON	0000002
+#define XCASE	0000004
+#define ECHO	0000010
+#define ECHOE	0000020
+#define ECHOK	0000040
+#define ECHONL	0000100
+#define NOFLSH	0000200
+#define TOSTOP	0000400
+#define ECHOCTL	0001000
+#define ECHOPRT	0002000
+#define ECHOKE	0004000
+#define FLUSHO	0010000
+#define PENDIN	0040000
+#define IEXTEN	0100000
+
+/* tcflow() and TCXONC use these */
+#define	TCOOFF		0
+#define	TCOON		1
+#define	TCIOFF		2
+#define	TCION		3
+
+/* tcflush() and TCFLSH use these */
+#define	TCIFLUSH	0
+#define	TCOFLUSH	1
+#define	TCIOFLUSH	2
+
+/* tcsetattr uses these */
+#define	TCSANOW		0
+#define	TCSADRAIN	1
+#define	TCSAFLUSH	2
+
+#endif /* __ASM_GENERIC_TERMBITS_H */
diff --git a/include/asm-generic/termios-base.h b/include/asm-generic/termios-base.h
new file mode 100644
index 0000000..0a769fe
--- /dev/null
+++ b/include/asm-generic/termios-base.h
@@ -0,0 +1,77 @@
+/* termios.h: generic termios/termio user copying/translation
+ */
+
+#ifndef _ASM_GENERIC_TERMIOS_BASE_H
+#define _ASM_GENERIC_TERMIOS_BASE_H
+
+#include <asm/uaccess.h>
+
+#ifndef __ARCH_TERMIO_GETPUT
+
+/*
+ * Translate a "termio" structure into a "termios". Ugh.
+ */
+static inline int user_termio_to_kernel_termios(struct ktermios *termios,
+						struct termio __user *termio)
+{
+	unsigned short tmp;
+
+	if (get_user(tmp, &termio->c_iflag) < 0)
+		goto fault;
+	termios->c_iflag = (0xffff0000 & termios->c_iflag) | tmp;
+
+	if (get_user(tmp, &termio->c_oflag) < 0)
+		goto fault;
+	termios->c_oflag = (0xffff0000 & termios->c_oflag) | tmp;
+
+	if (get_user(tmp, &termio->c_cflag) < 0)
+		goto fault;
+	termios->c_cflag = (0xffff0000 & termios->c_cflag) | tmp;
+
+	if (get_user(tmp, &termio->c_lflag) < 0)
+		goto fault;
+	termios->c_lflag = (0xffff0000 & termios->c_lflag) | tmp;
+
+	if (get_user(termios->c_line, &termio->c_line) < 0)
+		goto fault;
+
+	if (copy_from_user(termios->c_cc, termio->c_cc, NCC) != 0)
+		goto fault;
+
+	return 0;
+
+ fault:
+	return -EFAULT;
+}
+
+/*
+ * Translate a "termios" structure into a "termio". Ugh.
+ */
+static inline int kernel_termios_to_user_termio(struct termio __user *termio,
+						struct ktermios *termios)
+{
+	if (put_user(termios->c_iflag, &termio->c_iflag) < 0 ||
+	    put_user(termios->c_oflag, &termio->c_oflag) < 0 ||
+	    put_user(termios->c_cflag, &termio->c_cflag) < 0 ||
+	    put_user(termios->c_lflag, &termio->c_lflag) < 0 ||
+	    put_user(termios->c_line,  &termio->c_line) < 0 ||
+	    copy_to_user(termio->c_cc, termios->c_cc, NCC) != 0)
+		return -EFAULT;
+
+	return 0;
+}
+
+#ifndef user_termios_to_kernel_termios
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
+#endif
+
+#ifndef kernel_termios_to_user_termios
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+#endif
+
+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
+
+#endif	/* __ARCH_TERMIO_GETPUT */
+
+#endif /* _ASM_GENERIC_TERMIOS_BASE_H */
diff --git a/include/asm-generic/termios.h b/include/asm-generic/termios.h
index 7d39ecc..d0922ad 100644
--- a/include/asm-generic/termios.h
+++ b/include/asm-generic/termios.h
@@ -1,18 +1,68 @@
-/* termios.h: generic termios/termio user copying/translation
- */
-
 #ifndef _ASM_GENERIC_TERMIOS_H
 #define _ASM_GENERIC_TERMIOS_H
+/*
+ * Most architectures have straight copies of the x86 code, with
+ * varying levels of bug fixes on top. Usually it's a good idea
+ * to use this generic version instead, but be careful to avoid
+ * ABI changes.
+ * New architectures should not provide their own version.
+ */
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+
+struct winsize {
+	unsigned short ws_row;
+	unsigned short ws_col;
+	unsigned short ws_xpixel;
+	unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+	unsigned short c_iflag;		/* input mode flags */
+	unsigned short c_oflag;		/* output mode flags */
+	unsigned short c_cflag;		/* control mode flags */
+	unsigned short c_lflag;		/* local mode flags */
+	unsigned char c_line;		/* line discipline */
+	unsigned char c_cc[NCC];	/* control characters */
+};
+
+/* modem lines */
+#define TIOCM_LE	0x001
+#define TIOCM_DTR	0x002
+#define TIOCM_RTS	0x004
+#define TIOCM_ST	0x008
+#define TIOCM_SR	0x010
+#define TIOCM_CTS	0x020
+#define TIOCM_CAR	0x040
+#define TIOCM_RNG	0x080
+#define TIOCM_DSR	0x100
+#define TIOCM_CD	TIOCM_CAR
+#define TIOCM_RI	TIOCM_RNG
+#define TIOCM_OUT1	0x2000
+#define TIOCM_OUT2	0x4000
+#define TIOCM_LOOP	0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+#ifdef __KERNEL__
 
 #include <asm/uaccess.h>
 
-#ifndef __ARCH_TERMIO_GETPUT
+/*	intr=^C		quit=^\		erase=del	kill=^U
+	eof=^D		vtime=\0	vmin=\1		sxtc=\0
+	start=^Q	stop=^S		susp=^Z		eol=\0
+	reprint=^R	discard=^U	werase=^W	lnext=^V
+	eol2=\0
+*/
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
 
 /*
  * Translate a "termio" structure into a "termios". Ugh.
  */
 static inline int user_termio_to_kernel_termios(struct ktermios *termios,
-						struct termio __user *termio)
+						const struct termio __user *termio)
 {
 	unsigned short tmp;
 
@@ -61,17 +111,44 @@
 	return 0;
 }
 
-#ifndef user_termios_to_kernel_termios
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#endif
+#ifdef TCGETS2
+static inline int user_termios_to_kernel_termios(struct ktermios *k,
+						 struct termios2 __user *u)
+{
+	return copy_from_user(k, u, sizeof(struct termios2));
+}
 
-#ifndef kernel_termios_to_user_termios
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
-#endif
+static inline int kernel_termios_to_user_termios(struct termios2 __user *u,
+						 struct ktermios *k)
+{
+	return copy_to_user(u, k, sizeof(struct termios2));
+}
 
-#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
+static inline int user_termios_to_kernel_termios_1(struct ktermios *k,
+						   struct termios __user *u)
+{
+	return copy_from_user(k, u, sizeof(struct termios));
+}
 
-#endif	/* __ARCH_TERMIO_GETPUT */
+static inline int kernel_termios_to_user_termios_1(struct termios __user *u,
+						   struct ktermios *k)
+{
+	return copy_to_user(u, k, sizeof(struct termios));
+}
+#else /* TCGETS2 */
+static inline int user_termios_to_kernel_termios(struct ktermios *k,
+						 struct termios __user *u)
+{
+	return copy_from_user(k, u, sizeof(struct termios));
+}
+
+static inline int kernel_termios_to_user_termios(struct termios __user *u,
+						 struct ktermios *k)
+{
+	return copy_to_user(u, k, sizeof(struct termios));
+}
+#endif /* TCGETS2 */
+
+#endif	/* __KERNEL__ */
 
 #endif /* _ASM_GENERIC_TERMIOS_H */
diff --git a/include/asm-generic/timex.h b/include/asm-generic/timex.h
new file mode 100644
index 0000000..b2243cb
--- /dev/null
+++ b/include/asm-generic/timex.h
@@ -0,0 +1,22 @@
+#ifndef __ASM_GENERIC_TIMEX_H
+#define __ASM_GENERIC_TIMEX_H
+
+/*
+ * If you have a cycle counter, return the value here.
+ */
+typedef unsigned long cycles_t;
+#ifndef get_cycles
+static inline cycles_t get_cycles(void)
+{
+	return 0;
+}
+#endif
+
+/*
+ * Architectures are encouraged to implement read_current_timer
+ * and define this in order to avoid the expensive delay loop
+ * calibration during boot.
+ */
+#undef ARCH_HAS_READ_CURRENT_TIMER
+
+#endif /* __ASM_GENERIC_TIMEX_H */
diff --git a/include/asm-generic/tlbflush.h b/include/asm-generic/tlbflush.h
new file mode 100644
index 0000000..c7af037
--- /dev/null
+++ b/include/asm-generic/tlbflush.h
@@ -0,0 +1,18 @@
+#ifndef __ASM_GENERIC_TLBFLUSH_H
+#define __ASM_GENERIC_TLBFLUSH_H
+/*
+ * This is a dummy tlbflush implementation that can be used on all
+ * nommu architectures.
+ * If you have an MMU, you need to write your own functions.
+ */
+#ifdef CONFIG_MMU
+#error need to implement an architecture specific asm/tlbflush.h
+#endif
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+	BUG();
+}
+
+
+#endif /* __ASM_GENERIC_TLBFLUSH_H */
diff --git a/include/asm-generic/types.h b/include/asm-generic/types.h
new file mode 100644
index 0000000..fba7d33
--- /dev/null
+++ b/include/asm-generic/types.h
@@ -0,0 +1,42 @@
+#ifndef _ASM_GENERIC_TYPES_H
+#define _ASM_GENERIC_TYPES_H
+/*
+ * int-ll64 is used practically everywhere now,
+ * so use it as a reasonable default.
+ */
+#include <asm-generic/int-ll64.h>
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned short umode_t;
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+/*
+ * DMA addresses may be very different from physical addresses
+ * and pointers. i386 and powerpc may have 64 bit DMA on 32 bit
+ * systems, while sparc64 uses 32 bit DMA addresses for 64 bit
+ * physical addresses.
+ * This default defines dma_addr_t to have the same size as
+ * phys_addr_t, which is the most common way.
+ * Do not define the dma64_addr_t type, which never really
+ * worked.
+ */
+#ifndef dma_addr_t
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+typedef u64 dma_addr_t;
+#else
+typedef u32 dma_addr_t;
+#endif /* CONFIG_PHYS_ADDR_T_64BIT */
+#endif /* dma_addr_t */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_GENERIC_TYPES_H */
diff --git a/include/asm-generic/uaccess-unaligned.h b/include/asm-generic/uaccess-unaligned.h
new file mode 100644
index 0000000..67deb89
--- /dev/null
+++ b/include/asm-generic/uaccess-unaligned.h
@@ -0,0 +1,26 @@
+#ifndef __ASM_GENERIC_UACCESS_UNALIGNED_H
+#define __ASM_GENERIC_UACCESS_UNALIGNED_H
+
+/*
+ * This macro should be used instead of __get_user() when accessing
+ * values at locations that are not known to be aligned.
+ */
+#define __get_user_unaligned(x, ptr)					\
+({									\
+	__typeof__ (*(ptr)) __x;					\
+	__copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0;	\
+	(x) = __x;							\
+})
+
+
+/*
+ * This macro should be used instead of __put_user() when accessing
+ * values at locations that are not known to be aligned.
+ */
+#define __put_user_unaligned(x, ptr)					\
+({									\
+	__typeof__ (*(ptr)) __x = (x);					\
+	__copy_to_user((ptr), &__x, sizeof(*(ptr))) ? -EFAULT : 0;	\
+})
+
+#endif /* __ASM_GENERIC_UACCESS_UNALIGNED_H */
diff --git a/include/asm-generic/uaccess.h b/include/asm-generic/uaccess.h
index 549cb3a..6d8cab2 100644
--- a/include/asm-generic/uaccess.h
+++ b/include/asm-generic/uaccess.h
@@ -1,26 +1,325 @@
-#ifndef _ASM_GENERIC_UACCESS_H_
-#define _ASM_GENERIC_UACCESS_H_
+#ifndef __ASM_GENERIC_UACCESS_H
+#define __ASM_GENERIC_UACCESS_H
 
 /*
- * This macro should be used instead of __get_user() when accessing
- * values at locations that are not known to be aligned.
+ * User space memory access functions, these should work
+ * on a ny machine that has kernel and user data in the same
+ * address space, e.g. all NOMMU machines.
  */
-#define __get_user_unaligned(x, ptr)					\
-({									\
-	__typeof__ (*(ptr)) __x;					\
-	__copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0;	\
-	(x) = __x;							\
-})
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
 
+#include <asm/segment.h>
+
+#define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
+
+#ifndef KERNEL_DS
+#define KERNEL_DS	MAKE_MM_SEG(~0UL)
+#endif
+
+#ifndef USER_DS
+#define USER_DS		MAKE_MM_SEG(TASK_SIZE - 1)
+#endif
+
+#ifndef get_fs
+#define get_ds()	(KERNEL_DS)
+#define get_fs()	(current_thread_info()->addr_limit)
+
+static inline void set_fs(mm_segment_t fs)
+{
+	current_thread_info()->addr_limit = fs;
+}
+#endif
+
+#define segment_eq(a, b) ((a).seg == (b).seg)
+
+#define VERIFY_READ	0
+#define VERIFY_WRITE	1
+
+#define access_ok(type, addr, size) __access_ok((unsigned long)(addr),(size))
 
 /*
- * This macro should be used instead of __put_user() when accessing
- * values at locations that are not known to be aligned.
+ * The architecture should really override this if possible, at least
+ * doing a check on the get_fs()
  */
-#define __put_user_unaligned(x, ptr)					\
-({									\
-	__typeof__ (*(ptr)) __x = (x);					\
-	__copy_to_user((ptr), &__x, sizeof(*(ptr))) ? -EFAULT : 0;	\
+#ifndef __access_ok
+static inline int __access_ok(unsigned long addr, unsigned long size)
+{
+	return 1;
+}
+#endif
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry
+{
+	unsigned long insn, fixup;
+};
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/*
+ * architectures with an MMU should override these two
+ */
+#ifndef __copy_from_user
+static inline __must_check long __copy_from_user(void *to,
+		const void __user * from, unsigned long n)
+{
+	if (__builtin_constant_p(n)) {
+		switch(n) {
+		case 1:
+			*(u8 *)to = *(u8 __force *)from;
+			return 0;
+		case 2:
+			*(u16 *)to = *(u16 __force *)from;
+			return 0;
+		case 4:
+			*(u32 *)to = *(u32 __force *)from;
+			return 0;
+#ifdef CONFIG_64BIT
+		case 8:
+			*(u64 *)to = *(u64 __force *)from;
+			return 0;
+#endif
+		default:
+			break;
+		}
+	}
+
+	memcpy(to, (const void __force *)from, n);
+	return 0;
+}
+#endif
+
+#ifndef __copy_to_user
+static inline __must_check long __copy_to_user(void __user *to,
+		const void *from, unsigned long n)
+{
+	if (__builtin_constant_p(n)) {
+		switch(n) {
+		case 1:
+			*(u8 __force *)to = *(u8 *)from;
+			return 0;
+		case 2:
+			*(u16 __force *)to = *(u16 *)from;
+			return 0;
+		case 4:
+			*(u32 __force *)to = *(u32 *)from;
+			return 0;
+#ifdef CONFIG_64BIT
+		case 8:
+			*(u64 __force *)to = *(u64 *)from;
+			return 0;
+#endif
+		default:
+			break;
+		}
+	}
+
+	memcpy((void __force *)to, from, n);
+	return 0;
+}
+#endif
+
+/*
+ * These are the main single-value transfer routines.  They automatically
+ * use the right size if we just have the right pointer type.
+ * This version just falls back to copy_{from,to}_user, which should
+ * provide a fast-path for small values.
+ */
+#define __put_user(x, ptr) \
+({								\
+	__typeof__(*(ptr)) __x = (x);				\
+	int __pu_err = -EFAULT;					\
+        __chk_user_ptr(ptr);                                    \
+	switch (sizeof (*(ptr))) {				\
+	case 1:							\
+	case 2:							\
+	case 4:							\
+	case 8:							\
+		__pu_err = __put_user_fn(sizeof (*(ptr)),	\
+					 ptr, &__x);		\
+		break;						\
+	default:						\
+		__put_user_bad();				\
+		break;						\
+	 }							\
+	__pu_err;						\
 })
 
-#endif /* _ASM_GENERIC_UACCESS_H */
+#define put_user(x, ptr)					\
+({								\
+	might_sleep();						\
+	__access_ok(ptr, sizeof (*ptr)) ?			\
+		__put_user(x, ptr) :				\
+		-EFAULT;					\
+})
+
+static inline int __put_user_fn(size_t size, void __user *ptr, void *x)
+{
+	size = __copy_to_user(ptr, x, size);
+	return size ? -EFAULT : size;
+}
+
+extern int __put_user_bad(void) __attribute__((noreturn));
+
+#define __get_user(x, ptr)					\
+({								\
+	int __gu_err = -EFAULT;					\
+	__chk_user_ptr(ptr);					\
+	switch (sizeof(*(ptr))) {				\
+	case 1: {						\
+		unsigned char __x;				\
+		__gu_err = __get_user_fn(sizeof (*(ptr)),	\
+					 ptr, &__x);		\
+		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
+		break;						\
+	};							\
+	case 2: {						\
+		unsigned short __x;				\
+		__gu_err = __get_user_fn(sizeof (*(ptr)),	\
+					 ptr, &__x);		\
+		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
+		break;						\
+	};							\
+	case 4: {						\
+		unsigned int __x;				\
+		__gu_err = __get_user_fn(sizeof (*(ptr)),	\
+					 ptr, &__x);		\
+		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
+		break;						\
+	};							\
+	case 8: {						\
+		unsigned long long __x;				\
+		__gu_err = __get_user_fn(sizeof (*(ptr)),	\
+					 ptr, &__x);		\
+		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
+		break;						\
+	};							\
+	default:						\
+		__get_user_bad();				\
+		break;						\
+	}							\
+	__gu_err;						\
+})
+
+#define get_user(x, ptr)					\
+({								\
+	might_sleep();						\
+	__access_ok(ptr, sizeof (*ptr)) ?			\
+		__get_user(x, ptr) :				\
+		-EFAULT;					\
+})
+
+static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
+{
+	size = __copy_from_user(x, ptr, size);
+	return size ? -EFAULT : size;
+}
+
+extern int __get_user_bad(void) __attribute__((noreturn));
+
+#ifndef __copy_from_user_inatomic
+#define __copy_from_user_inatomic __copy_from_user
+#endif
+
+#ifndef __copy_to_user_inatomic
+#define __copy_to_user_inatomic __copy_to_user
+#endif
+
+static inline long copy_from_user(void *to,
+		const void __user * from, unsigned long n)
+{
+	might_sleep();
+	if (__access_ok(from, n))
+		return __copy_from_user(to, from, n);
+	else
+		return n;
+}
+
+static inline long copy_to_user(void __user *to,
+		const void *from, unsigned long n)
+{
+	might_sleep();
+	if (__access_ok(to, n))
+		return __copy_to_user(to, from, n);
+	else
+		return n;
+}
+
+/*
+ * Copy a null terminated string from userspace.
+ */
+#ifndef __strncpy_from_user
+static inline long
+__strncpy_from_user(char *dst, const char __user *src, long count)
+{
+	char *tmp;
+	strncpy(dst, (const char __force *)src, count);
+	for (tmp = dst; *tmp && count > 0; tmp++, count--)
+		;
+	return (tmp - dst);
+}
+#endif
+
+static inline long
+strncpy_from_user(char *dst, const char __user *src, long count)
+{
+	if (!__access_ok(src, 1))
+		return -EFAULT;
+	return __strncpy_from_user(dst, src, count);
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 on exception, a value greater than N if too long
+ */
+#ifndef strnlen_user
+static inline long strnlen_user(const char __user *src, long n)
+{
+	return strlen((void * __force)src) + 1;
+}
+#endif
+
+static inline long strlen_user(const char __user *src)
+{
+	return strnlen_user(src, 32767);
+}
+
+/*
+ * Zero Userspace
+ */
+#ifndef __clear_user
+static inline __must_check unsigned long
+__clear_user(void __user *to, unsigned long n)
+{
+	memset((void __force *)to, 0, n);
+	return 0;
+}
+#endif
+
+static inline __must_check unsigned long
+clear_user(void __user *to, unsigned long n)
+{
+	might_sleep();
+	if (!__access_ok(to, n))
+		return n;
+
+	return __clear_user(to, n);
+}
+
+#endif /* __ASM_GENERIC_UACCESS_H */
diff --git a/include/asm-generic/ucontext.h b/include/asm-generic/ucontext.h
new file mode 100644
index 0000000..ad77343
--- /dev/null
+++ b/include/asm-generic/ucontext.h
@@ -0,0 +1,12 @@
+#ifndef __ASM_GENERIC_UCONTEXT_H
+#define __ASM_GENERIC_UCONTEXT_H
+
+struct ucontext {
+	unsigned long	  uc_flags;
+	struct ucontext  *uc_link;
+	stack_t		  uc_stack;
+	struct sigcontext uc_mcontext;
+	sigset_t	  uc_sigmask;	/* mask last for extensibility */
+};
+
+#endif /* __ASM_GENERIC_UCONTEXT_H */
diff --git a/include/asm-generic/unaligned.h b/include/asm-generic/unaligned.h
new file mode 100644
index 0000000..03cf593
--- /dev/null
+++ b/include/asm-generic/unaligned.h
@@ -0,0 +1,30 @@
+#ifndef __ASM_GENERIC_UNALIGNED_H
+#define __ASM_GENERIC_UNALIGNED_H
+
+/*
+ * This is the most generic implementation of unaligned accesses
+ * and should work almost anywhere.
+ *
+ * If an architecture can handle unaligned accesses in hardware,
+ * it may want to use the linux/unaligned/access_ok.h implementation
+ * instead.
+ */
+#include <asm/byteorder.h>
+
+#if defined(__LITTLE_ENDIAN)
+# include <linux/unaligned/le_struct.h>
+# include <linux/unaligned/be_byteshift.h>
+# include <linux/unaligned/generic.h>
+# define get_unaligned	__get_unaligned_le
+# define put_unaligned	__put_unaligned_le
+#elif defined(__BIG_ENDIAN)
+# include <linux/unaligned/be_struct.h>
+# include <linux/unaligned/le_byteshift.h>
+# include <linux/unaligned/generic.h>
+# define get_unaligned	__get_unaligned_be
+# define put_unaligned	__put_unaligned_be
+#else
+# error need to define endianess
+#endif
+
+#endif /* __ASM_GENERIC_UNALIGNED_H */
diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h
new file mode 100644
index 0000000..5b34b62
--- /dev/null
+++ b/include/asm-generic/unistd.h
@@ -0,0 +1,854 @@
+#if !defined(_ASM_GENERIC_UNISTD_H) || defined(__SYSCALL)
+#define _ASM_GENERIC_UNISTD_H
+
+#include <asm/bitsperlong.h>
+
+/*
+ * This file contains the system call numbers, based on the
+ * layout of the x86-64 architecture, which embeds the
+ * pointer to the syscall in the table.
+ *
+ * As a basic principle, no duplication of functionality
+ * should be added, e.g. we don't use lseek when llseek
+ * is present. New architectures should use this file
+ * and implement the less feature-full calls in user space.
+ */
+
+#ifndef __SYSCALL
+#define __SYSCALL(x, y)
+#endif
+
+#if __BITS_PER_LONG == 32
+#define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _32)
+#else
+#define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _64)
+#endif
+
+#define __NR_io_setup 0
+__SYSCALL(__NR_io_setup, sys_io_setup)
+#define __NR_io_destroy 1
+__SYSCALL(__NR_io_destroy, sys_io_destroy)
+#define __NR_io_submit 2
+__SYSCALL(__NR_io_submit, sys_io_submit)
+#define __NR_io_cancel 3
+__SYSCALL(__NR_io_cancel, sys_io_cancel)
+#define __NR_io_getevents 4
+__SYSCALL(__NR_io_getevents, sys_io_getevents)
+
+/* fs/xattr.c */
+#define __NR_setxattr 5
+__SYSCALL(__NR_setxattr, sys_setxattr)
+#define __NR_lsetxattr 6
+__SYSCALL(__NR_lsetxattr, sys_lsetxattr)
+#define __NR_fsetxattr 7
+__SYSCALL(__NR_fsetxattr, sys_fsetxattr)
+#define __NR_getxattr 8
+__SYSCALL(__NR_getxattr, sys_getxattr)
+#define __NR_lgetxattr 9
+__SYSCALL(__NR_lgetxattr, sys_lgetxattr)
+#define __NR_fgetxattr 10
+__SYSCALL(__NR_fgetxattr, sys_fgetxattr)
+#define __NR_listxattr 11
+__SYSCALL(__NR_listxattr, sys_listxattr)
+#define __NR_llistxattr 12
+__SYSCALL(__NR_llistxattr, sys_llistxattr)
+#define __NR_flistxattr 13
+__SYSCALL(__NR_flistxattr, sys_flistxattr)
+#define __NR_removexattr 14
+__SYSCALL(__NR_removexattr, sys_removexattr)
+#define __NR_lremovexattr 15
+__SYSCALL(__NR_lremovexattr, sys_lremovexattr)
+#define __NR_fremovexattr 16
+__SYSCALL(__NR_fremovexattr, sys_fremovexattr)
+
+/* fs/dcache.c */
+#define __NR_getcwd 17
+__SYSCALL(__NR_getcwd, sys_getcwd)
+
+/* fs/cookies.c */
+#define __NR_lookup_dcookie 18
+__SYSCALL(__NR_lookup_dcookie, sys_lookup_dcookie)
+
+/* fs/eventfd.c */
+#define __NR_eventfd2 19
+__SYSCALL(__NR_eventfd2, sys_eventfd2)
+
+/* fs/eventpoll.c */
+#define __NR_epoll_create1 20
+__SYSCALL(__NR_epoll_create1, sys_epoll_create1)
+#define __NR_epoll_ctl 21
+__SYSCALL(__NR_epoll_ctl, sys_epoll_ctl)
+#define __NR_epoll_pwait 22
+__SYSCALL(__NR_epoll_pwait, sys_epoll_pwait)
+
+/* fs/fcntl.c */
+#define __NR_dup 23
+__SYSCALL(__NR_dup, sys_dup)
+#define __NR_dup3 24
+__SYSCALL(__NR_dup3, sys_dup3)
+#define __NR3264_fcntl 25
+__SC_3264(__NR3264_fcntl, sys_fcntl64, sys_fcntl)
+
+/* fs/inotify_user.c */
+#define __NR_inotify_init1 26
+__SYSCALL(__NR_inotify_init1, sys_inotify_init1)
+#define __NR_inotify_add_watch 27
+__SYSCALL(__NR_inotify_add_watch, sys_inotify_add_watch)
+#define __NR_inotify_rm_watch 28
+__SYSCALL(__NR_inotify_rm_watch, sys_inotify_rm_watch)
+
+/* fs/ioctl.c */
+#define __NR_ioctl 29
+__SYSCALL(__NR_ioctl, sys_ioctl)
+
+/* fs/ioprio.c */
+#define __NR_ioprio_set 30
+__SYSCALL(__NR_ioprio_set, sys_ioprio_set)
+#define __NR_ioprio_get 31
+__SYSCALL(__NR_ioprio_get, sys_ioprio_get)
+
+/* fs/locks.c */
+#define __NR_flock 32
+__SYSCALL(__NR_flock, sys_flock)
+
+/* fs/namei.c */
+#define __NR_mknodat 33
+__SYSCALL(__NR_mknodat, sys_mknodat)
+#define __NR_mkdirat 34
+__SYSCALL(__NR_mkdirat, sys_mkdirat)
+#define __NR_unlinkat 35
+__SYSCALL(__NR_unlinkat, sys_unlinkat)
+#define __NR_symlinkat 36
+__SYSCALL(__NR_symlinkat, sys_symlinkat)
+#define __NR_linkat 37
+__SYSCALL(__NR_linkat, sys_linkat)
+#define __NR_renameat 38
+__SYSCALL(__NR_renameat, sys_renameat)
+
+/* fs/namespace.c */
+#define __NR_umount2 39
+__SYSCALL(__NR_umount2, sys_umount)
+#define __NR_mount 40
+__SYSCALL(__NR_mount, sys_mount)
+#define __NR_pivot_root 41
+__SYSCALL(__NR_pivot_root, sys_pivot_root)
+
+/* fs/nfsctl.c */
+#define __NR_nfsservctl 42
+__SYSCALL(__NR_nfsservctl, sys_nfsservctl)
+
+/* fs/open.c */
+#define __NR3264_statfs 43
+__SC_3264(__NR3264_statfs, sys_statfs64, sys_statfs)
+#define __NR3264_fstatfs 44
+__SC_3264(__NR3264_fstatfs, sys_fstatfs64, sys_fstatfs)
+#define __NR3264_truncate 45
+__SC_3264(__NR3264_truncate, sys_truncate64, sys_truncate)
+#define __NR3264_ftruncate 46
+__SC_3264(__NR3264_ftruncate, sys_ftruncate64, sys_ftruncate)
+
+#define __NR_fallocate 47
+__SYSCALL(__NR_fallocate, sys_fallocate)
+#define __NR_faccessat 48
+__SYSCALL(__NR_faccessat, sys_faccessat)
+#define __NR_chdir 49
+__SYSCALL(__NR_chdir, sys_chdir)
+#define __NR_fchdir 50
+__SYSCALL(__NR_fchdir, sys_fchdir)
+#define __NR_chroot 51
+__SYSCALL(__NR_chroot, sys_chroot)
+#define __NR_fchmod 52
+__SYSCALL(__NR_fchmod, sys_fchmod)
+#define __NR_fchmodat 53
+__SYSCALL(__NR_fchmodat, sys_fchmodat)
+#define __NR_fchownat 54
+__SYSCALL(__NR_fchownat, sys_fchownat)
+#define __NR_fchown 55
+__SYSCALL(__NR_fchown, sys_fchown)
+#define __NR_openat 56
+__SYSCALL(__NR_openat, sys_openat)
+#define __NR_close 57
+__SYSCALL(__NR_close, sys_close)
+#define __NR_vhangup 58
+__SYSCALL(__NR_vhangup, sys_vhangup)
+
+/* fs/pipe.c */
+#define __NR_pipe2 59
+__SYSCALL(__NR_pipe2, sys_pipe2)
+
+/* fs/quota.c */
+#define __NR_quotactl 60
+__SYSCALL(__NR_quotactl, sys_quotactl)
+
+/* fs/readdir.c */
+#define __NR_getdents64 61
+__SYSCALL(__NR_getdents64, sys_getdents64)
+
+/* fs/read_write.c */
+#define __NR3264_lseek 62
+__SC_3264(__NR3264_lseek, sys_llseek, sys_lseek)
+#define __NR_read 63
+__SYSCALL(__NR_read, sys_read)
+#define __NR_write 64
+__SYSCALL(__NR_write, sys_write)
+#define __NR_readv 65
+__SYSCALL(__NR_readv, sys_readv)
+#define __NR_writev 66
+__SYSCALL(__NR_writev, sys_writev)
+#define __NR_pread64 67
+__SYSCALL(__NR_pread64, sys_pread64)
+#define __NR_pwrite64 68
+__SYSCALL(__NR_pwrite64, sys_pwrite64)
+#define __NR_preadv 69
+__SYSCALL(__NR_preadv, sys_preadv)
+#define __NR_pwritev 70
+__SYSCALL(__NR_pwritev, sys_pwritev)
+
+/* fs/sendfile.c */
+#define __NR3264_sendfile 71
+__SC_3264(__NR3264_sendfile, sys_sendfile64, sys_sendfile)
+
+/* fs/select.c */
+#define __NR_pselect6 72
+__SYSCALL(__NR_pselect6, sys_pselect6)
+#define __NR_ppoll 73
+__SYSCALL(__NR_ppoll, sys_ppoll)
+
+/* fs/signalfd.c */
+#define __NR_signalfd4 74
+__SYSCALL(__NR_signalfd4, sys_signalfd4)
+
+/* fs/splice.c */
+#define __NR_vmsplice 75
+__SYSCALL(__NR_vmsplice, sys_vmsplice)
+#define __NR_splice 76
+__SYSCALL(__NR_splice, sys_splice)
+#define __NR_tee 77
+__SYSCALL(__NR_tee, sys_tee)
+
+/* fs/stat.c */
+#define __NR_readlinkat 78
+__SYSCALL(__NR_readlinkat, sys_readlinkat)
+#define __NR3264_fstatat 79
+__SC_3264(__NR3264_fstatat, sys_fstatat64, sys_newfstatat)
+#define __NR3264_fstat 80
+__SC_3264(__NR3264_fstat, sys_fstat64, sys_newfstat)
+
+/* fs/sync.c */
+#define __NR_sync 81
+__SYSCALL(__NR_sync, sys_sync)
+#define __NR_fsync 82
+__SYSCALL(__NR_fsync, sys_fsync)
+#define __NR_fdatasync 83
+__SYSCALL(__NR_fdatasync, sys_fdatasync)
+#define __NR_sync_file_range 84
+__SYSCALL(__NR_sync_file_range, sys_sync_file_range) /* .long sys_sync_file_range2, */
+
+/* fs/timerfd.c */
+#define __NR_timerfd_create 85
+__SYSCALL(__NR_timerfd_create, sys_timerfd_create)
+#define __NR_timerfd_settime 86
+__SYSCALL(__NR_timerfd_settime, sys_timerfd_settime)
+#define __NR_timerfd_gettime 87
+__SYSCALL(__NR_timerfd_gettime, sys_timerfd_gettime)
+
+/* fs/utimes.c */
+#define __NR_utimensat 88
+__SYSCALL(__NR_utimensat, sys_utimensat)
+
+/* kernel/acct.c */
+#define __NR_acct 89
+__SYSCALL(__NR_acct, sys_acct)
+
+/* kernel/capability.c */
+#define __NR_capget 90
+__SYSCALL(__NR_capget, sys_capget)
+#define __NR_capset 91
+__SYSCALL(__NR_capset, sys_capset)
+
+/* kernel/exec_domain.c */
+#define __NR_personality 92
+__SYSCALL(__NR_personality, sys_personality)
+
+/* kernel/exit.c */
+#define __NR_exit 93
+__SYSCALL(__NR_exit, sys_exit)
+#define __NR_exit_group 94
+__SYSCALL(__NR_exit_group, sys_exit_group)
+#define __NR_waitid 95
+__SYSCALL(__NR_waitid, sys_waitid)
+
+/* kernel/fork.c */
+#define __NR_set_tid_address 96
+__SYSCALL(__NR_set_tid_address, sys_set_tid_address)
+#define __NR_unshare 97
+__SYSCALL(__NR_unshare, sys_unshare)
+
+/* kernel/futex.c */
+#define __NR_futex 98
+__SYSCALL(__NR_futex, sys_futex)
+#define __NR_set_robust_list 99
+__SYSCALL(__NR_set_robust_list, sys_set_robust_list)
+#define __NR_get_robust_list 100
+__SYSCALL(__NR_get_robust_list, sys_get_robust_list)
+
+/* kernel/hrtimer.c */
+#define __NR_nanosleep 101
+__SYSCALL(__NR_nanosleep, sys_nanosleep)
+
+/* kernel/itimer.c */
+#define __NR_getitimer 102
+__SYSCALL(__NR_getitimer, sys_getitimer)
+#define __NR_setitimer 103
+__SYSCALL(__NR_setitimer, sys_setitimer)
+
+/* kernel/kexec.c */
+#define __NR_kexec_load 104
+__SYSCALL(__NR_kexec_load, sys_kexec_load)
+
+/* kernel/module.c */
+#define __NR_init_module 105
+__SYSCALL(__NR_init_module, sys_init_module)
+#define __NR_delete_module 106
+__SYSCALL(__NR_delete_module, sys_delete_module)
+
+/* kernel/posix-timers.c */
+#define __NR_timer_create 107
+__SYSCALL(__NR_timer_create, sys_timer_create)
+#define __NR_timer_gettime 108
+__SYSCALL(__NR_timer_gettime, sys_timer_gettime)
+#define __NR_timer_getoverrun 109
+__SYSCALL(__NR_timer_getoverrun, sys_timer_getoverrun)
+#define __NR_timer_settime 110
+__SYSCALL(__NR_timer_settime, sys_timer_settime)
+#define __NR_timer_delete 111
+__SYSCALL(__NR_timer_delete, sys_timer_delete)
+#define __NR_clock_settime 112
+__SYSCALL(__NR_clock_settime, sys_clock_settime)
+#define __NR_clock_gettime 113
+__SYSCALL(__NR_clock_gettime, sys_clock_gettime)
+#define __NR_clock_getres 114
+__SYSCALL(__NR_clock_getres, sys_clock_getres)
+#define __NR_clock_nanosleep 115
+__SYSCALL(__NR_clock_nanosleep, sys_clock_nanosleep)
+
+/* kernel/printk.c */
+#define __NR_syslog 116
+__SYSCALL(__NR_syslog, sys_syslog)
+
+/* kernel/ptrace.c */
+#define __NR_ptrace 117
+__SYSCALL(__NR_ptrace, sys_ptrace)
+
+/* kernel/sched.c */
+#define __NR_sched_setparam 118
+__SYSCALL(__NR_sched_setparam, sys_sched_setparam)
+#define __NR_sched_setscheduler 119
+__SYSCALL(__NR_sched_setscheduler, sys_sched_setscheduler)
+#define __NR_sched_getscheduler 120
+__SYSCALL(__NR_sched_getscheduler, sys_sched_getscheduler)
+#define __NR_sched_getparam 121
+__SYSCALL(__NR_sched_getparam, sys_sched_getparam)
+#define __NR_sched_setaffinity 122
+__SYSCALL(__NR_sched_setaffinity, sys_sched_setaffinity)
+#define __NR_sched_getaffinity 123
+__SYSCALL(__NR_sched_getaffinity, sys_sched_getaffinity)
+#define __NR_sched_yield 124
+__SYSCALL(__NR_sched_yield, sys_sched_yield)
+#define __NR_sched_get_priority_max 125
+__SYSCALL(__NR_sched_get_priority_max, sys_sched_get_priority_max)
+#define __NR_sched_get_priority_min 126
+__SYSCALL(__NR_sched_get_priority_min, sys_sched_get_priority_min)
+#define __NR_sched_rr_get_interval 127
+__SYSCALL(__NR_sched_rr_get_interval, sys_sched_rr_get_interval)
+
+/* kernel/signal.c */
+#define __NR_restart_syscall 128
+__SYSCALL(__NR_restart_syscall, sys_restart_syscall)
+#define __NR_kill 129
+__SYSCALL(__NR_kill, sys_kill)
+#define __NR_tkill 130
+__SYSCALL(__NR_tkill, sys_tkill)
+#define __NR_tgkill 131
+__SYSCALL(__NR_tgkill, sys_tgkill)
+#define __NR_sigaltstack 132
+__SYSCALL(__NR_sigaltstack, sys_sigaltstack)
+#define __NR_rt_sigsuspend 133
+__SYSCALL(__NR_rt_sigsuspend, sys_rt_sigsuspend) /* __ARCH_WANT_SYS_RT_SIGSUSPEND */
+#define __NR_rt_sigaction 134
+__SYSCALL(__NR_rt_sigaction, sys_rt_sigaction) /* __ARCH_WANT_SYS_RT_SIGACTION */
+#define __NR_rt_sigprocmask 135
+__SYSCALL(__NR_rt_sigprocmask, sys_rt_sigprocmask)
+#define __NR_rt_sigpending 136
+__SYSCALL(__NR_rt_sigpending, sys_rt_sigpending)
+#define __NR_rt_sigtimedwait 137
+__SYSCALL(__NR_rt_sigtimedwait, sys_rt_sigtimedwait)
+#define __NR_rt_sigqueueinfo 138
+__SYSCALL(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo)
+#define __NR_rt_sigreturn 139
+__SYSCALL(__NR_rt_sigreturn, sys_rt_sigreturn) /* sys_rt_sigreturn_wrapper, */
+
+/* kernel/sys.c */
+#define __NR_setpriority 140
+__SYSCALL(__NR_setpriority, sys_setpriority)
+#define __NR_getpriority 141
+__SYSCALL(__NR_getpriority, sys_getpriority)
+#define __NR_reboot 142
+__SYSCALL(__NR_reboot, sys_reboot)
+#define __NR_setregid 143
+__SYSCALL(__NR_setregid, sys_setregid)
+#define __NR_setgid 144
+__SYSCALL(__NR_setgid, sys_setgid)
+#define __NR_setreuid 145
+__SYSCALL(__NR_setreuid, sys_setreuid)
+#define __NR_setuid 146
+__SYSCALL(__NR_setuid, sys_setuid)
+#define __NR_setresuid 147
+__SYSCALL(__NR_setresuid, sys_setresuid)
+#define __NR_getresuid 148
+__SYSCALL(__NR_getresuid, sys_getresuid)
+#define __NR_setresgid 149
+__SYSCALL(__NR_setresgid, sys_setresgid)
+#define __NR_getresgid 150
+__SYSCALL(__NR_getresgid, sys_getresgid)
+#define __NR_setfsuid 151
+__SYSCALL(__NR_setfsuid, sys_setfsuid)
+#define __NR_setfsgid 152
+__SYSCALL(__NR_setfsgid, sys_setfsgid)
+#define __NR_times 153
+__SYSCALL(__NR_times, sys_times)
+#define __NR_setpgid 154
+__SYSCALL(__NR_setpgid, sys_setpgid)
+#define __NR_getpgid 155
+__SYSCALL(__NR_getpgid, sys_getpgid)
+#define __NR_getsid 156
+__SYSCALL(__NR_getsid, sys_getsid)
+#define __NR_setsid 157
+__SYSCALL(__NR_setsid, sys_setsid)
+#define __NR_getgroups 158
+__SYSCALL(__NR_getgroups, sys_getgroups)
+#define __NR_setgroups 159
+__SYSCALL(__NR_setgroups, sys_setgroups)
+#define __NR_uname 160
+__SYSCALL(__NR_uname, sys_newuname)
+#define __NR_sethostname 161
+__SYSCALL(__NR_sethostname, sys_sethostname)
+#define __NR_setdomainname 162
+__SYSCALL(__NR_setdomainname, sys_setdomainname)
+#define __NR_getrlimit 163
+__SYSCALL(__NR_getrlimit, sys_getrlimit)
+#define __NR_setrlimit 164
+__SYSCALL(__NR_setrlimit, sys_setrlimit)
+#define __NR_getrusage 165
+__SYSCALL(__NR_getrusage, sys_getrusage)
+#define __NR_umask 166
+__SYSCALL(__NR_umask, sys_umask)
+#define __NR_prctl 167
+__SYSCALL(__NR_prctl, sys_prctl)
+#define __NR_getcpu 168
+__SYSCALL(__NR_getcpu, sys_getcpu)
+
+/* kernel/time.c */
+#define __NR_gettimeofday 169
+__SYSCALL(__NR_gettimeofday, sys_gettimeofday)
+#define __NR_settimeofday 170
+__SYSCALL(__NR_settimeofday, sys_settimeofday)
+#define __NR_adjtimex 171
+__SYSCALL(__NR_adjtimex, sys_adjtimex)
+
+/* kernel/timer.c */
+#define __NR_getpid 172
+__SYSCALL(__NR_getpid, sys_getpid)
+#define __NR_getppid 173
+__SYSCALL(__NR_getppid, sys_getppid)
+#define __NR_getuid 174
+__SYSCALL(__NR_getuid, sys_getuid)
+#define __NR_geteuid 175
+__SYSCALL(__NR_geteuid, sys_geteuid)
+#define __NR_getgid 176
+__SYSCALL(__NR_getgid, sys_getgid)
+#define __NR_getegid 177
+__SYSCALL(__NR_getegid, sys_getegid)
+#define __NR_gettid 178
+__SYSCALL(__NR_gettid, sys_gettid)
+#define __NR_sysinfo 179
+__SYSCALL(__NR_sysinfo, sys_sysinfo)
+
+/* ipc/mqueue.c */
+#define __NR_mq_open 180
+__SYSCALL(__NR_mq_open, sys_mq_open)
+#define __NR_mq_unlink 181
+__SYSCALL(__NR_mq_unlink, sys_mq_unlink)
+#define __NR_mq_timedsend 182
+__SYSCALL(__NR_mq_timedsend, sys_mq_timedsend)
+#define __NR_mq_timedreceive 183
+__SYSCALL(__NR_mq_timedreceive, sys_mq_timedreceive)
+#define __NR_mq_notify 184
+__SYSCALL(__NR_mq_notify, sys_mq_notify)
+#define __NR_mq_getsetattr 185
+__SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr)
+
+/* ipc/msg.c */
+#define __NR_msgget 186
+__SYSCALL(__NR_msgget, sys_msgget)
+#define __NR_msgctl 187
+__SYSCALL(__NR_msgctl, sys_msgctl)
+#define __NR_msgrcv 188
+__SYSCALL(__NR_msgrcv, sys_msgrcv)
+#define __NR_msgsnd 189
+__SYSCALL(__NR_msgsnd, sys_msgsnd)
+
+/* ipc/sem.c */
+#define __NR_semget 190
+__SYSCALL(__NR_semget, sys_semget)
+#define __NR_semctl 191
+__SYSCALL(__NR_semctl, sys_semctl)
+#define __NR_semtimedop 192
+__SYSCALL(__NR_semtimedop, sys_semtimedop)
+#define __NR_semop 193
+__SYSCALL(__NR_semop, sys_semop)
+
+/* ipc/shm.c */
+#define __NR_shmget 194
+__SYSCALL(__NR_shmget, sys_shmget)
+#define __NR_shmctl 195
+__SYSCALL(__NR_shmctl, sys_shmctl)
+#define __NR_shmat 196
+__SYSCALL(__NR_shmat, sys_shmat)
+#define __NR_shmdt 197
+__SYSCALL(__NR_shmdt, sys_shmdt)
+
+/* net/socket.c */
+#define __NR_socket 198
+__SYSCALL(__NR_socket, sys_socket)
+#define __NR_socketpair 199
+__SYSCALL(__NR_socketpair, sys_socketpair)
+#define __NR_bind 200
+__SYSCALL(__NR_bind, sys_bind)
+#define __NR_listen 201
+__SYSCALL(__NR_listen, sys_listen)
+#define __NR_accept 202
+__SYSCALL(__NR_accept, sys_accept)
+#define __NR_connect 203
+__SYSCALL(__NR_connect, sys_connect)
+#define __NR_getsockname 204
+__SYSCALL(__NR_getsockname, sys_getsockname)
+#define __NR_getpeername 205
+__SYSCALL(__NR_getpeername, sys_getpeername)
+#define __NR_sendto 206
+__SYSCALL(__NR_sendto, sys_sendto)
+#define __NR_recvfrom 207
+__SYSCALL(__NR_recvfrom, sys_recvfrom)
+#define __NR_setsockopt 208
+__SYSCALL(__NR_setsockopt, sys_setsockopt)
+#define __NR_getsockopt 209
+__SYSCALL(__NR_getsockopt, sys_getsockopt)
+#define __NR_shutdown 210
+__SYSCALL(__NR_shutdown, sys_shutdown)
+#define __NR_sendmsg 211
+__SYSCALL(__NR_sendmsg, sys_sendmsg)
+#define __NR_recvmsg 212
+__SYSCALL(__NR_recvmsg, sys_recvmsg)
+
+/* mm/filemap.c */
+#define __NR_readahead 213
+__SYSCALL(__NR_readahead, sys_readahead)
+
+/* mm/nommu.c, also with MMU */
+#define __NR_brk 214
+__SYSCALL(__NR_brk, sys_brk)
+#define __NR_munmap 215
+__SYSCALL(__NR_munmap, sys_munmap)
+#define __NR_mremap 216
+__SYSCALL(__NR_mremap, sys_mremap)
+
+/* security/keys/keyctl.c */
+#define __NR_add_key 217
+__SYSCALL(__NR_add_key, sys_add_key)
+#define __NR_request_key 218
+__SYSCALL(__NR_request_key, sys_request_key)
+#define __NR_keyctl 219
+__SYSCALL(__NR_keyctl, sys_keyctl)
+
+/* arch/example/kernel/sys_example.c */
+#define __NR_clone 220
+__SYSCALL(__NR_clone, sys_clone)	/* .long sys_clone_wrapper */
+#define __NR_execve 221
+__SYSCALL(__NR_execve, sys_execve)	/* .long sys_execve_wrapper */
+
+#define __NR3264_mmap 222
+__SC_3264(__NR3264_mmap, sys_mmap2, sys_mmap)
+/* mm/fadvise.c */
+#define __NR3264_fadvise64 223
+__SC_3264(__NR3264_fadvise64, sys_fadvise64_64, sys_fadvise64)
+
+/* mm/, CONFIG_MMU only */
+#ifndef __ARCH_NOMMU
+#define __NR_swapon 224
+__SYSCALL(__NR_swapon, sys_swapon)
+#define __NR_swapoff 225
+__SYSCALL(__NR_swapoff, sys_swapoff)
+#define __NR_mprotect 226
+__SYSCALL(__NR_mprotect, sys_mprotect)
+#define __NR_msync 227
+__SYSCALL(__NR_msync, sys_msync)
+#define __NR_mlock 228
+__SYSCALL(__NR_mlock, sys_mlock)
+#define __NR_munlock 229
+__SYSCALL(__NR_munlock, sys_munlock)
+#define __NR_mlockall 230
+__SYSCALL(__NR_mlockall, sys_mlockall)
+#define __NR_munlockall 231
+__SYSCALL(__NR_munlockall, sys_munlockall)
+#define __NR_mincore 232
+__SYSCALL(__NR_mincore, sys_mincore)
+#define __NR_madvise 233
+__SYSCALL(__NR_madvise, sys_madvise)
+#define __NR_remap_file_pages 234
+__SYSCALL(__NR_remap_file_pages, sys_remap_file_pages)
+#define __NR_mbind 235
+__SYSCALL(__NR_mbind, sys_mbind)
+#define __NR_get_mempolicy 236
+__SYSCALL(__NR_get_mempolicy, sys_get_mempolicy)
+#define __NR_set_mempolicy 237
+__SYSCALL(__NR_set_mempolicy, sys_set_mempolicy)
+#define __NR_migrate_pages 238
+__SYSCALL(__NR_migrate_pages, sys_migrate_pages)
+#define __NR_move_pages 239
+__SYSCALL(__NR_move_pages, sys_move_pages)
+#endif
+
+#undef __NR_syscalls
+#define __NR_syscalls 240
+
+/*
+ * All syscalls below here should go away really,
+ * these are provided for both review and as a porting
+ * help for the C library version.
+*
+ * Last chance: are any of these important enought to
+ * enable by default?
+ */
+#ifdef __ARCH_WANT_SYSCALL_NO_AT
+#define __NR_open 1024
+__SYSCALL(__NR_open, sys_open)
+#define __NR_link 1025
+__SYSCALL(__NR_link, sys_link)
+#define __NR_unlink 1026
+__SYSCALL(__NR_unlink, sys_unlink)
+#define __NR_mknod 1027
+__SYSCALL(__NR_mknod, sys_mknod)
+#define __NR_chmod 1028
+__SYSCALL(__NR_chmod, sys_chmod)
+#define __NR_chown 1029
+__SYSCALL(__NR_chown, sys_chown)
+#define __NR_mkdir 1030
+__SYSCALL(__NR_mkdir, sys_mkdir)
+#define __NR_rmdir 1031
+__SYSCALL(__NR_rmdir, sys_rmdir)
+#define __NR_lchown 1032
+__SYSCALL(__NR_lchown, sys_lchown)
+#define __NR_access 1033
+__SYSCALL(__NR_access, sys_access)
+#define __NR_rename 1034
+__SYSCALL(__NR_rename, sys_rename)
+#define __NR_readlink 1035
+__SYSCALL(__NR_readlink, sys_readlink)
+#define __NR_symlink 1036
+__SYSCALL(__NR_symlink, sys_symlink)
+#define __NR_utimes 1037
+__SYSCALL(__NR_utimes, sys_utimes)
+#define __NR3264_stat 1038
+__SC_3264(__NR3264_stat, sys_stat64, sys_newstat)
+#define __NR3264_lstat 1039
+__SC_3264(__NR3264_lstat, sys_lstat64, sys_newlstat)
+
+#undef __NR_syscalls
+#define __NR_syscalls (__NR3264_lstat+1)
+#endif /* __ARCH_WANT_SYSCALL_NO_AT */
+
+#ifdef __ARCH_WANT_SYSCALL_NO_FLAGS
+#define __NR_pipe 1040
+__SYSCALL(__NR_pipe, sys_pipe)
+#define __NR_dup2 1041
+__SYSCALL(__NR_dup2, sys_dup2)
+#define __NR_epoll_create 1042
+__SYSCALL(__NR_epoll_create, sys_epoll_create)
+#define __NR_inotify_init 1043
+__SYSCALL(__NR_inotify_init, sys_inotify_init)
+#define __NR_eventfd 1044
+__SYSCALL(__NR_eventfd, sys_eventfd)
+#define __NR_signalfd 1045
+__SYSCALL(__NR_signalfd, sys_signalfd)
+
+#undef __NR_syscalls
+#define __NR_syscalls (__NR_signalfd+1)
+#endif /* __ARCH_WANT_SYSCALL_NO_FLAGS */
+
+#if __BITS_PER_LONG == 32 && defined(__ARCH_WANT_SYSCALL_OFF_T)
+#define __NR_sendfile 1046
+__SYSCALL(__NR_sendfile, sys_sendfile)
+#define __NR_ftruncate 1047
+__SYSCALL(__NR_ftruncate, sys_ftruncate)
+#define __NR_truncate 1048
+__SYSCALL(__NR_truncate, sys_truncate)
+#define __NR_stat 1049
+__SYSCALL(__NR_stat, sys_newstat)
+#define __NR_lstat 1050
+__SYSCALL(__NR_lstat, sys_newlstat)
+#define __NR_fstat 1051
+__SYSCALL(__NR_fstat, sys_newfstat)
+#define __NR_fcntl 1052
+__SYSCALL(__NR_fcntl, sys_fcntl)
+#define __NR_fadvise64 1053
+#define __ARCH_WANT_SYS_FADVISE64
+__SYSCALL(__NR_fadvise64, sys_fadvise64)
+#define __NR_newfstatat 1054
+#define __ARCH_WANT_SYS_NEWFSTATAT
+__SYSCALL(__NR_newfstatat, sys_newfstatat)
+#define __NR_fstatfs 1055
+__SYSCALL(__NR_fstatfs, sys_fstatfs)
+#define __NR_statfs 1056
+__SYSCALL(__NR_statfs, sys_statfs)
+#define __NR_lseek 1057
+__SYSCALL(__NR_lseek, sys_lseek)
+#define __NR_mmap 1058
+__SYSCALL(__NR_mmap, sys_mmap)
+
+#undef __NR_syscalls
+#define __NR_syscalls (__NR_mmap+1)
+#endif /* 32 bit off_t syscalls */
+
+#ifdef __ARCH_WANT_SYSCALL_DEPRECATED
+#define __NR_alarm 1059
+#define __ARCH_WANT_SYS_ALARM
+__SYSCALL(__NR_alarm, sys_alarm)
+#define __NR_getpgrp 1060
+#define __ARCH_WANT_SYS_GETPGRP
+__SYSCALL(__NR_getpgrp, sys_getpgrp)
+#define __NR_pause 1061
+#define __ARCH_WANT_SYS_PAUSE
+__SYSCALL(__NR_pause, sys_pause)
+#define __NR_time 1062
+#define __ARCH_WANT_SYS_TIME
+__SYSCALL(__NR_time, sys_time)
+#define __NR_utime 1063
+#define __ARCH_WANT_SYS_UTIME
+__SYSCALL(__NR_utime, sys_utime)
+
+#define __NR_creat 1064
+__SYSCALL(__NR_creat, sys_creat)
+#define __NR_getdents 1065
+#define __ARCH_WANT_SYS_GETDENTS
+__SYSCALL(__NR_getdents, sys_getdents)
+#define __NR_futimesat 1066
+__SYSCALL(__NR_futimesat, sys_futimesat)
+#define __NR_select 1067
+#define __ARCH_WANT_SYS_SELECT
+__SYSCALL(__NR_select, sys_select)
+#define __NR_poll 1068
+__SYSCALL(__NR_poll, sys_poll)
+#define __NR_epoll_wait 1069
+__SYSCALL(__NR_epoll_wait, sys_epoll_wait)
+#define __NR_ustat 1070
+__SYSCALL(__NR_ustat, sys_ustat)
+#define __NR_vfork 1071
+__SYSCALL(__NR_vfork, sys_vfork)
+#define __NR_wait4 1072
+__SYSCALL(__NR_wait4, sys_wait4)
+#define __NR_recv 1073
+__SYSCALL(__NR_recv, sys_recv)
+#define __NR_send 1074
+__SYSCALL(__NR_send, sys_send)
+#define __NR_bdflush 1075
+__SYSCALL(__NR_bdflush, sys_bdflush)
+#define __NR_umount 1076
+__SYSCALL(__NR_umount, sys_oldumount)
+#define __ARCH_WANT_SYS_OLDUMOUNT
+#define __NR_uselib 1077
+__SYSCALL(__NR_uselib, sys_uselib)
+#define __NR__sysctl 1078
+__SYSCALL(__NR__sysctl, sys_sysctl)
+
+#define __NR_fork 1079
+#ifdef CONFIG_MMU
+__SYSCALL(__NR_fork, sys_fork)
+#else
+__SYSCALL(__NR_fork, sys_ni_syscall)
+#endif /* CONFIG_MMU */
+
+#undef __NR_syscalls
+#define __NR_syscalls (__NR_fork+1)
+
+#endif /* __ARCH_WANT_SYSCALL_DEPRECATED */
+
+/*
+ * 32 bit systems traditionally used different
+ * syscalls for off_t and loff_t arguments, while
+ * 64 bit systems only need the off_t version.
+ * For new 32 bit platforms, there is no need to
+ * implement the old 32 bit off_t syscalls, so
+ * they take different names.
+ * Here we map the numbers so that both versions
+ * use the same syscall table layout.
+ */
+#if __BITS_PER_LONG == 64
+#define __NR_fcntl __NR3264_fcntl
+#define __NR_statfs __NR3264_statfs
+#define __NR_fstatfs __NR3264_fstatfs
+#define __NR_truncate __NR3264_truncate
+#define __NR_ftruncate __NR3264_truncate
+#define __NR_lseek __NR3264_lseek
+#define __NR_sendfile __NR3264_sendfile
+#define __NR_newfstatat __NR3264_fstatat
+#define __NR_fstat __NR3264_fstat
+#define __NR_mmap __NR3264_mmap
+#define __NR_fadvise64 __NR3264_fadvise64
+#ifdef __NR3264_stat
+#define __NR_stat __NR3264_stat
+#define __NR_lstat __NR3264_lstat
+#endif
+#else
+#define __NR_fcntl64 __NR3264_fcntl
+#define __NR_statfs64 __NR3264_statfs
+#define __NR_fstatfs64 __NR3264_fstatfs
+#define __NR_truncate64 __NR3264_truncate
+#define __NR_ftruncate64 __NR3264_truncate
+#define __NR_llseek __NR3264_lseek
+#define __NR_sendfile64 __NR3264_sendfile
+#define __NR_fstatat64 __NR3264_fstatat
+#define __NR_fstat64 __NR3264_fstat
+#define __NR_mmap2 __NR3264_mmap
+#define __NR_fadvise64_64 __NR3264_fadvise64
+#ifdef __NR3264_stat
+#define __NR_stat64 __NR3264_stat
+#define __NR_lstat64 __NR3264_lstat
+#endif
+#endif
+
+#ifdef __KERNEL__
+
+/*
+ * These are required system calls, we should
+ * invert the logic eventually and let them
+ * be selected by default.
+ */
+#if __BITS_PER_LONG == 32
+#define __ARCH_WANT_STAT64
+#define __ARCH_WANT_SYS_LLSEEK
+#endif
+#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_GENERIC_UNISTD_H */
diff --git a/include/asm-generic/user.h b/include/asm-generic/user.h
new file mode 100644
index 0000000..8b9c3c9
--- /dev/null
+++ b/include/asm-generic/user.h
@@ -0,0 +1,8 @@
+#ifndef __ASM_GENERIC_USER_H
+#define __ASM_GENERIC_USER_H
+/*
+ * This file may define a 'struct user' structure. However, it it only
+ * used for a.out file, which are not supported on new architectures.
+ */
+
+#endif	/* __ASM_GENERIC_USER_H */
diff --git a/include/asm-generic/vga.h b/include/asm-generic/vga.h
new file mode 100644
index 0000000..36c8ff5
--- /dev/null
+++ b/include/asm-generic/vga.h
@@ -0,0 +1,24 @@
+/*
+ *	Access to VGA videoram
+ *
+ *	(c) 1998 Martin Mares <mj@ucw.cz>
+ */
+#ifndef __ASM_GENERIC_VGA_H
+#define __ASM_GENERIC_VGA_H
+
+/*
+ *	On most architectures that support VGA, we can just
+ *	recalculate addresses and then access the videoram
+ *	directly without any black magic.
+ *
+ *	Everyone else needs to ioremap the address and use
+ *	proper I/O accesses.
+ */
+#ifndef VGA_MAP_MEM
+#define VGA_MAP_MEM(x, s) (unsigned long)phys_to_virt(x)
+#endif
+
+#define vga_readb(x) (*(x))
+#define vga_writeb(x, y) (*(y) = (x))
+
+#endif /* _ASM_GENERIC_VGA_H */
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index b84d8ae..d4ddc22 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -86,7 +86,17 @@
 
 #include "drm_os_linux.h"
 #include "drm_hashtab.h"
+#include "drm_mm.h"
 
+#define DRM_UT_CORE 		0x01
+#define DRM_UT_DRIVER		0x02
+#define DRM_UT_KMS		0x04
+#define DRM_UT_MODE		0x08
+
+extern void drm_ut_debug_printk(unsigned int request_level,
+				const char *prefix,
+				const char *function_name,
+				const char *format, ...);
 /***********************************************************************/
 /** \name DRM template customization defaults */
 /*@{*/
@@ -186,15 +196,57 @@
  * \param arg arguments
  */
 #if DRM_DEBUG_CODE
-#define DRM_DEBUG(fmt, arg...)						\
+#define DRM_DEBUG(fmt, args...)						\
 	do {								\
-		if ( drm_debug )			\
-			printk(KERN_DEBUG				\
-			       "[" DRM_NAME ":%s] " fmt ,	\
-			       __func__ , ##arg);			\
+		drm_ut_debug_printk(DRM_UT_CORE, DRM_NAME, 		\
+					__func__, fmt, ##args);		\
+	} while (0)
+
+#define DRM_DEBUG_DRIVER(prefix, fmt, args...)				\
+	do {								\
+		drm_ut_debug_printk(DRM_UT_DRIVER, prefix,		\
+					__func__, fmt, ##args);		\
+	} while (0)
+#define DRM_DEBUG_KMS(prefix, fmt, args...)				\
+	do {								\
+		drm_ut_debug_printk(DRM_UT_KMS, prefix, 		\
+					 __func__, fmt, ##args);	\
+	} while (0)
+#define DRM_DEBUG_MODE(prefix, fmt, args...)				\
+	do {								\
+		drm_ut_debug_printk(DRM_UT_MODE, prefix, 		\
+					 __func__, fmt, ##args);	\
+	} while (0)
+#define DRM_LOG(fmt, args...)						\
+	do {								\
+		drm_ut_debug_printk(DRM_UT_CORE, NULL,			\
+					NULL, fmt, ##args);		\
+	} while (0)
+#define DRM_LOG_KMS(fmt, args...)					\
+	do {								\
+		drm_ut_debug_printk(DRM_UT_KMS, NULL,			\
+					NULL, fmt, ##args);		\
+	} while (0)
+#define DRM_LOG_MODE(fmt, args...)					\
+	do {								\
+		drm_ut_debug_printk(DRM_UT_MODE, NULL,			\
+					NULL, fmt, ##args);		\
+	} while (0)
+#define DRM_LOG_DRIVER(fmt, args...)					\
+	do {								\
+		drm_ut_debug_printk(DRM_UT_DRIVER, NULL,		\
+					NULL, fmt, ##args);		\
 	} while (0)
 #else
+#define DRM_DEBUG_DRIVER(prefix, fmt, args...) do { } while (0)
+#define DRM_DEBUG_KMS(prefix, fmt, args...)	do { } while (0)
+#define DRM_DEBUG_MODE(prefix, 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)
+#define DRM_LOG_MODE(fmt, arg...) do { } while (0)
+#define DRM_LOG_DRIVER(fmt, arg...) do { } while (0)
+
 #endif
 
 #define DRM_PROC_LIMIT (PAGE_SIZE-80)
@@ -237,15 +289,15 @@
  * \param dev DRM device.
  * \param filp file pointer of the caller.
  */
-#define LOCK_TEST_WITH_RETURN( dev, file_priv )				\
-do {									\
-	if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock) ||		\
-	    file_priv->master->lock.file_priv != file_priv)	{			\
+#define LOCK_TEST_WITH_RETURN( dev, _file_priv )				\
+do {										\
+	if (!_DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock) ||	\
+	    _file_priv->master->lock.file_priv != _file_priv)	{		\
 		DRM_ERROR( "%s called without lock held, held  %d owner %p %p\n",\
-			   __func__, _DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock),\
-			   file_priv->master->lock.file_priv, file_priv);		\
-		return -EINVAL;						\
-	}								\
+			   __func__, _DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock),\
+			   _file_priv->master->lock.file_priv, _file_priv);	\
+		return -EINVAL;							\
+	}									\
 } while (0)
 
 /**
@@ -502,26 +554,6 @@
 };
 
 
-/*
- * Generic memory manager structs
- */
-
-struct drm_mm_node {
-	struct list_head fl_entry;
-	struct list_head ml_entry;
-	int free;
-	unsigned long start;
-	unsigned long size;
-	struct drm_mm *mm;
-	void *private;
-};
-
-struct drm_mm {
-	struct list_head fl_entry;
-	struct list_head ml_entry;
-};
-
-
 /**
  * Kernel side of a mapping
  */
@@ -1385,22 +1417,6 @@
 extern int drm_sysfs_connector_add(struct drm_connector *connector);
 extern void drm_sysfs_connector_remove(struct drm_connector *connector);
 
-/*
- * Basic memory manager support (drm_mm.c)
- */
-extern struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
-				       unsigned long size,
-				       unsigned alignment);
-extern void drm_mm_put_block(struct drm_mm_node * cur);
-extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, unsigned long size,
-					 unsigned alignment, int best_match);
-extern int drm_mm_init(struct drm_mm *mm, unsigned long start, unsigned long size);
-extern void drm_mm_takedown(struct drm_mm *mm);
-extern int drm_mm_clean(struct drm_mm *mm);
-extern unsigned long drm_mm_tail_space(struct drm_mm *mm);
-extern int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size);
-extern int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size);
-
 /* Graphics Execution Manager library functions (drm_gem.c) */
 int drm_gem_init(struct drm_device *dev);
 void drm_gem_destroy(struct drm_device *dev);
@@ -1522,18 +1538,14 @@
 
 static __inline__ void *drm_calloc_large(size_t nmemb, size_t size)
 {
-	u8 *addr;
-
-	if (size <= PAGE_SIZE)
+	if (size * nmemb <= PAGE_SIZE)
 	    return kcalloc(nmemb, size, GFP_KERNEL);
 
-	addr = vmalloc(nmemb * size);
-	if (!addr)
+	if (size != 0 && nmemb > ULONG_MAX / size)
 		return NULL;
 
-	memset(addr, 0, nmemb * size);
-
-	return addr;
+	return __vmalloc(size * nmemb,
+			 GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL);
 }
 
 static __inline void drm_free_large(void *ptr)
diff --git a/include/drm/drm_hashtab.h b/include/drm/drm_hashtab.h
index cd2b189..0af087a 100644
--- a/include/drm/drm_hashtab.h
+++ b/include/drm/drm_hashtab.h
@@ -35,6 +35,8 @@
 #ifndef DRM_HASHTAB_H
 #define DRM_HASHTAB_H
 
+#include <linux/list.h>
+
 #define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
 
 struct drm_hash_item {
diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h
new file mode 100644
index 0000000..5662f42
--- /dev/null
+++ b/include/drm/drm_mm.h
@@ -0,0 +1,90 @@
+/**************************************************************************
+ *
+ * Copyright 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX. USA.
+ * 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
+ * THE COPYRIGHT HOLDERS, AUTHORS 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:
+ * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
+ */
+
+#ifndef _DRM_MM_H_
+#define _DRM_MM_H_
+
+/*
+ * Generic range manager structs
+ */
+#include <linux/list.h>
+
+struct drm_mm_node {
+	struct list_head fl_entry;
+	struct list_head ml_entry;
+	int free;
+	unsigned long start;
+	unsigned long size;
+	struct drm_mm *mm;
+	void *private;
+};
+
+struct drm_mm {
+	struct list_head fl_entry;
+	struct list_head ml_entry;
+	struct list_head unused_nodes;
+	int num_unused;
+	spinlock_t unused_lock;
+};
+
+/*
+ * Basic range manager support (drm_mm.c)
+ */
+
+extern struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent,
+					    unsigned long size,
+					    unsigned alignment);
+extern struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent,
+						   unsigned long size,
+						   unsigned alignment);
+extern void drm_mm_put_block(struct drm_mm_node *cur);
+extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
+					      unsigned long size,
+					      unsigned alignment,
+					      int best_match);
+extern int drm_mm_init(struct drm_mm *mm, unsigned long start,
+		       unsigned long size);
+extern void drm_mm_takedown(struct drm_mm *mm);
+extern int drm_mm_clean(struct drm_mm *mm);
+extern unsigned long drm_mm_tail_space(struct drm_mm *mm);
+extern int drm_mm_remove_space_from_tail(struct drm_mm *mm,
+					 unsigned long size);
+extern int drm_mm_add_space_to_tail(struct drm_mm *mm,
+				    unsigned long size, int atomic);
+extern int drm_mm_pre_get(struct drm_mm *mm);
+
+static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block)
+{
+	return block->mm;
+}
+
+#endif
diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h
index fc55db7..f8634ab 100644
--- a/include/drm/drm_pciids.h
+++ b/include/drm/drm_pciids.h
@@ -254,6 +254,11 @@
 	{0x1002, 0x940A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x940B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x940F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x94A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x94A1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x94B1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x94B3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x94B5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x9441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x9442, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
@@ -268,6 +273,8 @@
 	{0x1002, 0x9456, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x945A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x945B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x9460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x9462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x946A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x946B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x947A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
@@ -536,4 +543,6 @@
 	{0x8086, 0xa001, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
 	{0x8086, 0xa011, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
 	{0x8086, 0x35e8, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
+	{0x8086, 0x0042, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
+	{0x8086, 0x0046, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
 	{0, 0, 0}
diff --git a/include/linux/amba/pl022.h b/include/linux/amba/pl022.h
new file mode 100644
index 0000000..dcad0ff
--- /dev/null
+++ b/include/linux/amba/pl022.h
@@ -0,0 +1,264 @@
+/*
+ * include/linux/amba/pl022.h
+ *
+ * Copyright (C) 2008-2009 ST-Ericsson AB
+ * Copyright (C) 2006 STMicroelectronics Pvt. Ltd.
+ *
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ *
+ * Initial version inspired by:
+ *	linux-2.6.17-rc3-mm1/drivers/spi/pxa2xx_spi.c
+ * Initial adoption to PL022 by:
+ *      Sachin Verma <sachin.verma@st.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.
+ */
+
+#ifndef _SSP_PL022_H
+#define _SSP_PL022_H
+
+#include <linux/device.h>
+
+/**
+ * whether SSP is in loopback mode or not
+ */
+enum ssp_loopback {
+	LOOPBACK_DISABLED,
+	LOOPBACK_ENABLED
+};
+
+/**
+ * enum ssp_interface - interfaces allowed for this SSP Controller
+ * @SSP_INTERFACE_MOTOROLA_SPI: Motorola Interface
+ * @SSP_INTERFACE_TI_SYNC_SERIAL: Texas Instrument Synchronous Serial
+ * interface
+ * @SSP_INTERFACE_NATIONAL_MICROWIRE: National Semiconductor Microwire
+ * interface
+ * @SSP_INTERFACE_UNIDIRECTIONAL: Unidirectional interface (STn8810
+ * &STn8815 only)
+ */
+enum ssp_interface {
+	SSP_INTERFACE_MOTOROLA_SPI,
+	SSP_INTERFACE_TI_SYNC_SERIAL,
+	SSP_INTERFACE_NATIONAL_MICROWIRE,
+	SSP_INTERFACE_UNIDIRECTIONAL
+};
+
+/**
+ * enum ssp_hierarchy - whether SSP is configured as Master or Slave
+ */
+enum ssp_hierarchy {
+	SSP_MASTER,
+	SSP_SLAVE
+};
+
+/**
+ * enum ssp_clock_params - clock parameters, to set SSP clock at a
+ * desired freq
+ */
+struct ssp_clock_params {
+	u8 cpsdvsr; /* value from 2 to 254 (even only!) */
+	u8 scr;	    /* value from 0 to 255 */
+};
+
+/**
+ * enum ssp_rx_endian - endianess of Rx FIFO Data
+ */
+enum ssp_rx_endian {
+	SSP_RX_MSB,
+	SSP_RX_LSB
+};
+
+/**
+ * enum ssp_tx_endian - endianess of Tx FIFO Data
+ */
+enum ssp_tx_endian {
+	SSP_TX_MSB,
+	SSP_TX_LSB
+};
+
+/**
+ * enum ssp_data_size - number of bits in one data element
+ */
+enum ssp_data_size {
+	SSP_DATA_BITS_4 = 0x03, SSP_DATA_BITS_5, SSP_DATA_BITS_6,
+	SSP_DATA_BITS_7, SSP_DATA_BITS_8, SSP_DATA_BITS_9,
+	SSP_DATA_BITS_10, SSP_DATA_BITS_11, SSP_DATA_BITS_12,
+	SSP_DATA_BITS_13, SSP_DATA_BITS_14, SSP_DATA_BITS_15,
+	SSP_DATA_BITS_16, SSP_DATA_BITS_17, SSP_DATA_BITS_18,
+	SSP_DATA_BITS_19, SSP_DATA_BITS_20, SSP_DATA_BITS_21,
+	SSP_DATA_BITS_22, SSP_DATA_BITS_23, SSP_DATA_BITS_24,
+	SSP_DATA_BITS_25, SSP_DATA_BITS_26, SSP_DATA_BITS_27,
+	SSP_DATA_BITS_28, SSP_DATA_BITS_29, SSP_DATA_BITS_30,
+	SSP_DATA_BITS_31, SSP_DATA_BITS_32
+};
+
+/**
+ * enum ssp_mode - SSP mode of operation (Communication modes)
+ */
+enum ssp_mode {
+	INTERRUPT_TRANSFER,
+	POLLING_TRANSFER,
+	DMA_TRANSFER
+};
+
+/**
+ * enum ssp_rx_level_trig - receive FIFO watermark level which triggers
+ * IT: Interrupt fires when _N_ or more elements in RX FIFO.
+ */
+enum ssp_rx_level_trig {
+	SSP_RX_1_OR_MORE_ELEM,
+	SSP_RX_4_OR_MORE_ELEM,
+	SSP_RX_8_OR_MORE_ELEM,
+	SSP_RX_16_OR_MORE_ELEM,
+	SSP_RX_32_OR_MORE_ELEM
+};
+
+/**
+ * Transmit FIFO watermark level which triggers (IT Interrupt fires
+ * when _N_ or more empty locations in TX FIFO)
+ */
+enum ssp_tx_level_trig {
+	SSP_TX_1_OR_MORE_EMPTY_LOC,
+	SSP_TX_4_OR_MORE_EMPTY_LOC,
+	SSP_TX_8_OR_MORE_EMPTY_LOC,
+	SSP_TX_16_OR_MORE_EMPTY_LOC,
+	SSP_TX_32_OR_MORE_EMPTY_LOC
+};
+
+/**
+ * enum SPI Clock Phase - clock phase (Motorola SPI interface only)
+ * @SSP_CLK_RISING_EDGE: Receive data on rising edge
+ * @SSP_CLK_FALLING_EDGE: Receive data on falling edge
+ */
+enum ssp_spi_clk_phase {
+	SSP_CLK_RISING_EDGE,
+	SSP_CLK_FALLING_EDGE
+};
+
+/**
+ * enum SPI Clock Polarity - clock polarity (Motorola SPI interface only)
+ * @SSP_CLK_POL_IDLE_LOW: Low inactive level
+ * @SSP_CLK_POL_IDLE_HIGH: High inactive level
+ */
+enum ssp_spi_clk_pol {
+	SSP_CLK_POL_IDLE_LOW,
+	SSP_CLK_POL_IDLE_HIGH
+};
+
+/**
+ * Microwire Conrol Lengths Command size in microwire format
+ */
+enum ssp_microwire_ctrl_len {
+	SSP_BITS_4 = 0x03, SSP_BITS_5, SSP_BITS_6,
+	SSP_BITS_7, SSP_BITS_8, SSP_BITS_9,
+	SSP_BITS_10, SSP_BITS_11, SSP_BITS_12,
+	SSP_BITS_13, SSP_BITS_14, SSP_BITS_15,
+	SSP_BITS_16, SSP_BITS_17, SSP_BITS_18,
+	SSP_BITS_19, SSP_BITS_20, SSP_BITS_21,
+	SSP_BITS_22, SSP_BITS_23, SSP_BITS_24,
+	SSP_BITS_25, SSP_BITS_26, SSP_BITS_27,
+	SSP_BITS_28, SSP_BITS_29, SSP_BITS_30,
+	SSP_BITS_31, SSP_BITS_32
+};
+
+/**
+ * enum Microwire Wait State
+ * @SSP_MWIRE_WAIT_ZERO: No wait state inserted after last command bit
+ * @SSP_MWIRE_WAIT_ONE: One wait state inserted after last command bit
+ */
+enum ssp_microwire_wait_state {
+	SSP_MWIRE_WAIT_ZERO,
+	SSP_MWIRE_WAIT_ONE
+};
+
+/**
+ * enum Microwire - whether Full/Half Duplex
+ * @SSP_MICROWIRE_CHANNEL_FULL_DUPLEX: SSPTXD becomes bi-directional,
+ *     SSPRXD not used
+ * @SSP_MICROWIRE_CHANNEL_HALF_DUPLEX: SSPTXD is an output, SSPRXD is
+ *     an input.
+ */
+enum ssp_duplex {
+	SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
+	SSP_MICROWIRE_CHANNEL_HALF_DUPLEX
+};
+
+/**
+ * CHIP select/deselect commands
+ */
+enum ssp_chip_select {
+	SSP_CHIP_SELECT,
+	SSP_CHIP_DESELECT
+};
+
+
+/**
+ * struct pl022_ssp_master - device.platform_data for SPI controller devices.
+ * @num_chipselect: chipselects are used to distinguish individual
+ *     SPI slaves, and are numbered from zero to num_chipselects - 1.
+ *     each slave has a chipselect signal, but it's common that not
+ *     every chipselect is connected to a slave.
+ * @enable_dma: if true enables DMA driven transfers.
+ */
+struct pl022_ssp_controller {
+	u16 bus_id;
+	u8 num_chipselect;
+	u8 enable_dma:1;
+};
+
+/**
+ * struct ssp_config_chip - spi_board_info.controller_data for SPI
+ * slave devices, copied to spi_device.controller_data.
+ *
+ * @lbm: used for test purpose to internally connect RX and TX
+ * @iface: Interface type(Motorola, TI, Microwire, Universal)
+ * @hierarchy: sets whether interface is master or slave
+ * @slave_tx_disable: SSPTXD is disconnected (in slave mode only)
+ * @clk_freq: Tune freq parameters of SSP(when in master mode)
+ * @endian_rx: Endianess of Data in Rx FIFO
+ * @endian_tx: Endianess of Data in Tx FIFO
+ * @data_size: Width of data element(4 to 32 bits)
+ * @com_mode: communication mode: polling, Interrupt or DMA
+ * @rx_lev_trig: Rx FIFO watermark level (for IT & DMA mode)
+ * @tx_lev_trig: Tx FIFO watermark level (for IT & DMA mode)
+ * @clk_phase: Motorola SPI interface Clock phase
+ * @clk_pol: Motorola SPI interface Clock polarity
+ * @ctrl_len: Microwire interface: Control length
+ * @wait_state: Microwire interface: Wait state
+ * @duplex: Microwire interface: Full/Half duplex
+ * @cs_control: function pointer to board-specific function to
+ * assert/deassert I/O port to control HW generation of devices chip-select.
+ * @dma_xfer_type: Type of DMA xfer (Mem-to-periph or Periph-to-Periph)
+ * @dma_config: DMA configuration for SSP controller and peripheral
+ */
+struct pl022_config_chip {
+	struct device *dev;
+	enum ssp_loopback lbm;
+	enum ssp_interface iface;
+	enum ssp_hierarchy hierarchy;
+	bool slave_tx_disable;
+	struct ssp_clock_params clk_freq;
+	enum ssp_rx_endian endian_rx;
+	enum ssp_tx_endian endian_tx;
+	enum ssp_data_size data_size;
+	enum ssp_mode com_mode;
+	enum ssp_rx_level_trig rx_lev_trig;
+	enum ssp_tx_level_trig tx_lev_trig;
+	enum ssp_spi_clk_phase clk_phase;
+	enum ssp_spi_clk_pol clk_pol;
+	enum ssp_microwire_ctrl_len ctrl_len;
+	enum ssp_microwire_wait_state wait_state;
+	enum ssp_duplex duplex;
+	void (*cs_control) (u32 control);
+};
+
+#endif /* _SSP_PL022_H */
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index 64a982e..5a5a7fd 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -114,6 +114,9 @@
 #define UART011_IFLS_TX4_8	(2 << 0)
 #define UART011_IFLS_TX6_8	(3 << 0)
 #define UART011_IFLS_TX7_8	(4 << 0)
+/* special values for ST vendor with deeper fifo */
+#define UART011_IFLS_RX_HALF	(5 << 3)
+#define UART011_IFLS_TX_HALF	(5 << 0)
 
 #define UART011_OEIM		(1 << 10)	/* overrun error interrupt mask */
 #define UART011_BEIM		(1 << 9)	/* break error interrupt mask */
diff --git a/include/linux/atmel-mci.h b/include/linux/atmel-mci.h
index 2f1f957..57b1846 100644
--- a/include/linux/atmel-mci.h
+++ b/include/linux/atmel-mci.h
@@ -10,6 +10,7 @@
  * @bus_width: Number of data lines wired up the slot
  * @detect_pin: GPIO pin wired to the card detect switch
  * @wp_pin: GPIO pin wired to the write protect sensor
+ * @detect_is_active_high: The state of the detect pin when it is active
  *
  * If a given slot is not present on the board, @bus_width should be
  * set to 0. The other fields are ignored in this case.
@@ -24,6 +25,7 @@
 	unsigned int		bus_width;
 	int			detect_pin;
 	int			wp_pin;
+	bool			detect_is_active_high;
 };
 
 /**
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index ebdfde8..0b1a6ca 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1226,6 +1226,8 @@
 	int (*direct_access) (struct block_device *, sector_t,
 						void **, unsigned long *);
 	int (*media_changed) (struct gendisk *);
+	unsigned long long (*set_capacity) (struct gendisk *,
+						unsigned long long);
 	int (*revalidate_disk) (struct gendisk *);
 	int (*getgeo)(struct block_device *, struct hd_geometry *);
 	struct module *owner;
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1db9bbf..1d37f42 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -142,4 +142,17 @@
  */
 struct clk *clk_get_sys(const char *dev_id, const char *con_id);
 
+/**
+ * clk_add_alias - add a new clock alias
+ * @alias: name for clock alias
+ * @alias_dev_name: device name
+ * @id: platform specific clock name
+ * @dev: device
+ *
+ * Allows using generic clock names for drivers by adding a new alias.
+ * Assumes clkdev, see clkdev.h for more info.
+ */
+int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
+			struct device *dev);
+
 #endif
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 37bcb50..04fb513 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -261,6 +261,11 @@
 # define __section(S) __attribute__ ((__section__(#S)))
 #endif
 
+/* Are two types/vars the same type (ignoring qualifiers)? */
+#ifndef __same_type
+# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
+#endif
+
 /*
  * Prevent the compiler from merging or refetching accesses.  The compiler
  * is also forbidden from reordering successive instances of ACCESS_ONCE(),
diff --git a/include/linux/device.h b/include/linux/device.h
index 5d5c197..a4a7b10 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -62,8 +62,6 @@
 	void (*shutdown)(struct device *dev);
 
 	int (*suspend)(struct device *dev, pm_message_t state);
-	int (*suspend_late)(struct device *dev, pm_message_t state);
-	int (*resume_early)(struct device *dev);
 	int (*resume)(struct device *dev);
 
 	struct dev_pm_ops *pm;
@@ -291,9 +289,6 @@
 	int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
 	void (*release)(struct device *dev);
 
-	int (*suspend)(struct device *dev, pm_message_t state);
-	int (*resume)(struct device *dev);
-
 	struct dev_pm_ops *pm;
 };
 
diff --git a/include/linux/dlm.h b/include/linux/dlm.h
index b9cd386..0b3518c 100644
--- a/include/linux/dlm.h
+++ b/include/linux/dlm.h
@@ -81,8 +81,8 @@
  * the cluster, the calling node joins it.
  */
 
-int dlm_new_lockspace(char *name, int namelen, dlm_lockspace_t **lockspace,
-		      uint32_t flags, int lvblen);
+int dlm_new_lockspace(const char *name, int namelen,
+		      dlm_lockspace_t **lockspace, uint32_t flags, int lvblen);
 
 /*
  * dlm_release_lockspace
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 162e5de..d41ed59 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -121,6 +121,13 @@
 #define FUSE_BIG_WRITES		(1 << 5)
 
 /**
+ * CUSE INIT request/reply flags
+ *
+ * CUSE_UNRESTRICTED_IOCTL:  use unrestricted ioctl
+ */
+#define CUSE_UNRESTRICTED_IOCTL	(1 << 0)
+
+/**
  * Release flags
  */
 #define FUSE_RELEASE_FLUSH	(1 << 0)
@@ -210,6 +217,9 @@
 	FUSE_DESTROY       = 38,
 	FUSE_IOCTL         = 39,
 	FUSE_POLL          = 40,
+
+	/* CUSE specific operations */
+	CUSE_INIT          = 4096,
 };
 
 enum fuse_notify_code {
@@ -401,6 +411,27 @@
 	__u32	max_write;
 };
 
+#define CUSE_INIT_INFO_MAX 4096
+
+struct cuse_init_in {
+	__u32	major;
+	__u32	minor;
+	__u32	unused;
+	__u32	flags;
+};
+
+struct cuse_init_out {
+	__u32	major;
+	__u32	minor;
+	__u32	unused;
+	__u32	flags;
+	__u32	max_read;
+	__u32	max_write;
+	__u32	dev_major;		/* chardev major */
+	__u32	dev_minor;		/* chardev minor */
+	__u32	spare[10];
+};
+
 struct fuse_interrupt_in {
 	__u64	unique;
 };
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 149fda2..7cbd38d 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -114,6 +114,7 @@
 #define GENHD_FL_UP				16
 #define GENHD_FL_SUPPRESS_PARTITION_INFO	32
 #define GENHD_FL_EXT_DEVT			64 /* allow extended devt */
+#define GENHD_FL_NATIVE_CAPACITY		128
 
 #define BLK_SCSI_MAX_CMDS	(256)
 #define BLK_SCSI_CMD_PER_LONG	(BLK_SCSI_MAX_CMDS / (sizeof(long) * 8))
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 0bbc15f..3760e7c 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -85,6 +85,9 @@
 			__GFP_NOWARN|__GFP_REPEAT|__GFP_NOFAIL|\
 			__GFP_NORETRY|__GFP_NOMEMALLOC)
 
+/* Control slab gfp mask during early boot */
+#define SLAB_GFP_BOOT_MASK __GFP_BITS_MASK & ~(__GFP_WAIT|__GFP_IO|__GFP_FS)
+
 /* Control allocation constraints */
 #define GFP_CONSTRAINT_MASK (__GFP_HARDWALL|__GFP_THISNODE)
 
diff --git a/include/linux/hid.h b/include/linux/hid.h
index a72876e..53489fd 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -238,6 +238,42 @@
 #define HID_GD_RIGHT		0x00010092
 #define HID_GD_LEFT		0x00010093
 
+#define HID_DG_DIGITIZER	0x000d0001
+#define HID_DG_PEN		0x000d0002
+#define HID_DG_LIGHTPEN		0x000d0003
+#define HID_DG_TOUCHSCREEN	0x000d0004
+#define HID_DG_TOUCHPAD		0x000d0005
+#define HID_DG_STYLUS		0x000d0020
+#define HID_DG_PUCK		0x000d0021
+#define HID_DG_FINGER		0x000d0022
+#define HID_DG_TIPPRESSURE	0x000d0030
+#define HID_DG_BARRELPRESSURE	0x000d0031
+#define HID_DG_INRANGE		0x000d0032
+#define HID_DG_TOUCH		0x000d0033
+#define HID_DG_UNTOUCH		0x000d0034
+#define HID_DG_TAP		0x000d0035
+#define HID_DG_TABLETFUNCTIONKEY	0x000d0039
+#define HID_DG_PROGRAMCHANGEKEY	0x000d003a
+#define HID_DG_INVERT		0x000d003c
+#define HID_DG_TIPSWITCH	0x000d0042
+#define HID_DG_TIPSWITCH2	0x000d0043
+#define HID_DG_BARRELSWITCH	0x000d0044
+#define HID_DG_ERASER		0x000d0045
+#define HID_DG_TABLETPICK	0x000d0046
+/*
+ * as of May 20, 2009 the usages below are not yet in the official USB spec
+ * but are being pushed by Microsft as described in their paper "Digitizer
+ * Drivers for Windows Touch and Pen-Based Computers"
+ */
+#define HID_DG_CONFIDENCE	0x000d0047
+#define HID_DG_WIDTH		0x000d0048
+#define HID_DG_HEIGHT		0x000d0049
+#define HID_DG_CONTACTID	0x000d0051
+#define HID_DG_INPUTMODE	0x000d0052
+#define HID_DG_DEVICEINDEX	0x000d0053
+#define HID_DG_CONTACTCOUNT	0x000d0054
+#define HID_DG_CONTACTMAX	0x000d0055
+
 /*
  * HID report types --- Ouch! HID spec says 1 2 3!
  */
diff --git a/include/linux/i2c-ocores.h b/include/linux/i2c-ocores.h
index 8ed591b..4d5e57f 100644
--- a/include/linux/i2c-ocores.h
+++ b/include/linux/i2c-ocores.h
@@ -14,6 +14,8 @@
 struct ocores_i2c_platform_data {
 	u32 regstep;   /* distance between registers */
 	u32 clock_khz; /* input clock in kHz */
+	u8 num_devices; /* number of devices in the devices list */
+	struct i2c_board_info const *devices; /* devices connected to the bus */
 };
 
 #endif /* _LINUX_I2C_OCORES_H */
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 867cb68..a6c6a2f 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -178,7 +178,7 @@
 /*
  * Structure to hold all information about the location of this port
  */
-typedef struct hw_regs_s {
+struct ide_hw {
 	union {
 		struct ide_io_ports	io_ports;
 		unsigned long		io_ports_array[IDE_NR_PORTS];
@@ -186,12 +186,11 @@
 
 	int		irq;			/* our irq number */
 	ide_ack_intr_t	*ack_intr;		/* acknowledge interrupt */
-	hwif_chipset_t  chipset;
 	struct device	*dev, *parent;
 	unsigned long	config;
-} hw_regs_t;
+};
 
-static inline void ide_std_init_ports(hw_regs_t *hw,
+static inline void ide_std_init_ports(struct ide_hw *hw,
 				      unsigned long io_addr,
 				      unsigned long ctl_addr)
 {
@@ -218,21 +217,12 @@
 
 /*
  * Special Driver Flags
- *
- * set_geometry	: respecify drive geometry
- * recalibrate	: seek to cyl 0
- * set_multmode	: set multmode count
- * reserved	: unused
  */
-typedef union {
-	unsigned all			: 8;
-	struct {
-		unsigned set_geometry	: 1;
-		unsigned recalibrate	: 1;
-		unsigned set_multmode	: 1;
-		unsigned reserved	: 5;
-	} b;
-} special_t;
+enum {
+	IDE_SFLAG_SET_GEOMETRY		= (1 << 0),
+	IDE_SFLAG_RECALIBRATE		= (1 << 1),
+	IDE_SFLAG_SET_MULTMODE		= (1 << 2),
+};
 
 /*
  * Status returned from various ide_ functions
@@ -391,6 +381,7 @@
 struct ide_disk_ops {
 	int		(*check)(struct ide_drive_s *, const char *);
 	int		(*get_capacity)(struct ide_drive_s *);
+	u64		(*set_capacity)(struct ide_drive_s *, u64);
 	void		(*setup)(struct ide_drive_s *);
 	void		(*flush)(struct ide_drive_s *);
 	int		(*init_media)(struct ide_drive_s *, struct gendisk *);
@@ -468,6 +459,8 @@
 	IDE_DFLAG_NICE1			= (1 << 5),
 	/* device is physically present */
 	IDE_DFLAG_PRESENT		= (1 << 6),
+	/* disable Host Protected Area */
+	IDE_DFLAG_NOHPA			= (1 << 7),
 	/* id read from device (synthetic if not set) */
 	IDE_DFLAG_ID_READ		= (1 << 8),
 	IDE_DFLAG_NOPROBE		= (1 << 9),
@@ -506,6 +499,7 @@
 	/* write protect */
 	IDE_DFLAG_WP			= (1 << 29),
 	IDE_DFLAG_FORMAT_IN_PROGRESS	= (1 << 30),
+	IDE_DFLAG_NIEN_QUIRK		= (1 << 31),
 };
 
 struct ide_drive_s {
@@ -530,14 +524,13 @@
 	unsigned long sleep;		/* sleep until this time */
 	unsigned long timeout;		/* max time to wait for irq */
 
-	special_t	special;	/* special action flags */
+	u8	special_flags;		/* special action flags */
 
 	u8	select;			/* basic drive/head select reg value */
 	u8	retry_pio;		/* retrying dma capable host in pio */
 	u8	waiting_for_dma;	/* dma currently in progress */
 	u8	dma;			/* atapi dma flag */
 
-        u8	quirk_list;	/* considered quirky, set for a specific host */
         u8	init_speed;	/* transfer rate set at boot */
         u8	current_speed;	/* current transfer rate set */
 	u8	desired_speed;	/* desired transfer rate set */
@@ -562,8 +555,7 @@
 	unsigned int	drive_data;	/* used by set_pio_mode/dev_select() */
 	unsigned int	failures;	/* current failure count */
 	unsigned int	max_failures;	/* maximum allowed failure count */
-	u64		probed_capacity;/* initial reported media capacity (ide-cd only currently) */
-
+	u64		probed_capacity;/* initial/native media capacity */
 	u64		capacity64;	/* total number of sectors */
 
 	int		lun;		/* logical unit */
@@ -1222,7 +1214,7 @@
 }
 
 void ide_pci_setup_ports(struct pci_dev *, const struct ide_port_info *,
-			 hw_regs_t *, hw_regs_t **);
+			 struct ide_hw *, struct ide_hw **);
 void ide_setup_pci_noise(struct pci_dev *, const struct ide_port_info *);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
@@ -1461,16 +1453,18 @@
 void ide_register_region(struct gendisk *);
 void ide_unregister_region(struct gendisk *);
 
+void ide_check_nien_quirk_list(ide_drive_t *);
 void ide_undecoded_slave(ide_drive_t *);
 
 void ide_port_apply_params(ide_hwif_t *);
 int ide_sysfs_register_port(ide_hwif_t *);
 
-struct ide_host *ide_host_alloc(const struct ide_port_info *, hw_regs_t **);
+struct ide_host *ide_host_alloc(const struct ide_port_info *, struct ide_hw **,
+				unsigned int);
 void ide_host_free(struct ide_host *);
 int ide_host_register(struct ide_host *, const struct ide_port_info *,
-		      hw_regs_t **);
-int ide_host_add(const struct ide_port_info *, hw_regs_t **,
+		      struct ide_hw **);
+int ide_host_add(const struct ide_port_info *, struct ide_hw **, unsigned int,
 		 struct ide_host **);
 void ide_host_remove(struct ide_host *);
 int ide_legacy_device_add(const struct ide_port_info *, unsigned long);
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index cfe4fe1..60e8934 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -79,6 +79,7 @@
 #define ETH_P_AOE	0x88A2		/* ATA over Ethernet		*/
 #define ETH_P_TIPC	0x88CA		/* TIPC 			*/
 #define ETH_P_FCOE	0x8906		/* Fibre Channel over Ethernet  */
+#define ETH_P_FIP	0x8914		/* FCoE Initialization Protocol */
 #define ETH_P_EDSA	0xDADA		/* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
 
 /*
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index ff374ce..c41e812 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -183,6 +183,7 @@
 extern void enable_irq(unsigned int irq);
 
 /* The following three functions are for the core kernel use only. */
+#ifdef CONFIG_GENERIC_HARDIRQS
 extern void suspend_device_irqs(void);
 extern void resume_device_irqs(void);
 #ifdef CONFIG_PM_SLEEP
@@ -190,6 +191,11 @@
 #else
 static inline int check_wakeup_irqs(void) { return 0; }
 #endif
+#else
+static inline void suspend_device_irqs(void) { };
+static inline void resume_device_irqs(void) { };
+static inline int check_wakeup_irqs(void) { return 0; }
+#endif
 
 #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS)
 
diff --git a/include/linux/lguest.h b/include/linux/lguest.h
index 175e63f..7bc1440 100644
--- a/include/linux/lguest.h
+++ b/include/linux/lguest.h
@@ -30,6 +30,10 @@
 	/* Wallclock time set by the Host. */
 	struct timespec time;
 
+	/* Interrupt pending set by the Host.  The Guest should do a hypercall
+	 * if it re-enables interrupts and sees this set (to X86_EFLAGS_IF). */
+	int irq_pending;
+
 	/* Async hypercall ring.  Instead of directly making hypercalls, we can
 	 * place them in here for processing the next time the Host wants.
 	 * This batching can be quite efficient. */
diff --git a/include/linux/lguest_launcher.h b/include/linux/lguest_launcher.h
index a53407a..bfefbdf 100644
--- a/include/linux/lguest_launcher.h
+++ b/include/linux/lguest_launcher.h
@@ -57,7 +57,8 @@
 	LHREQ_INITIALIZE, /* + base, pfnlimit, start */
 	LHREQ_GETDMA, /* No longer used */
 	LHREQ_IRQ, /* + irq */
-	LHREQ_BREAK, /* + on/off flag (on blocks until someone does off) */
+	LHREQ_BREAK, /* No longer used */
+	LHREQ_EVENTFD, /* + address, fd. */
 };
 
 /* The alignment to use between consumer and producer parts of vring.
diff --git a/include/linux/module.h b/include/linux/module.h
index a8f2c0a..a7bc6e7 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -77,6 +77,7 @@
 void sort_extable(struct exception_table_entry *start,
 		  struct exception_table_entry *finish);
 void sort_main_extable(void);
+void trim_init_extable(struct module *m);
 
 #ifdef MODULE
 #define MODULE_GENERIC_TABLE(gtype,name)			\
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index a4f0b93..6547c3c 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -36,9 +36,14 @@
 /* Returns length written or -errno.  Buffer is 4k (ie. be short!) */
 typedef int (*param_get_fn)(char *buffer, struct kernel_param *kp);
 
+/* Flag bits for kernel_param.flags */
+#define KPARAM_KMALLOCED	1
+#define KPARAM_ISBOOL		2
+
 struct kernel_param {
 	const char *name;
-	unsigned int perm;
+	u16 perm;
+	u16 flags;
 	param_set_fn set;
 	param_get_fn get;
 	union {
@@ -79,7 +84,7 @@
    parameters.  perm sets the visibility in sysfs: 000 means it's
    not there, read bits mean it's readable, write bits mean it's
    writable. */
-#define __module_param_call(prefix, name, set, get, arg, perm)		\
+#define __module_param_call(prefix, name, set, get, arg, isbool, perm)	\
 	/* Default value instead of permissions? */			\
 	static int __param_perm_check_##name __attribute__((unused)) =	\
 	BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2))	\
@@ -88,10 +93,13 @@
 	static struct kernel_param __moduleparam_const __param_##name	\
 	__used								\
     __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
-	= { __param_str_##name, perm, set, get, { arg } }
+	= { __param_str_##name, perm, isbool ? KPARAM_ISBOOL : 0,	\
+	    set, get, { arg } }
 
 #define module_param_call(name, set, get, arg, perm)			      \
-	__module_param_call(MODULE_PARAM_PREFIX, name, set, get, arg, perm)
+	__module_param_call(MODULE_PARAM_PREFIX,			      \
+			    name, set, get, arg,			      \
+			    __same_type(*(arg), bool), perm)
 
 /* Helper functions: type is byte, short, ushort, int, uint, long,
    ulong, charp, bool or invbool, or XXX if you define param_get_XXX,
@@ -120,15 +128,16 @@
 #define core_param(name, var, type, perm)				\
 	param_check_##type(name, &(var));				\
 	__module_param_call("", name, param_set_##type, param_get_##type, \
-			    &var, perm)
+			    &var, __same_type(var, bool), perm)
 #endif /* !MODULE */
 
 /* Actually copy string: maxlen param is usually sizeof(string). */
 #define module_param_string(name, string, len, perm)			\
 	static const struct kparam_string __param_string_##name		\
 		= { len, string };					\
-	module_param_call(name, param_set_copystring, param_get_string,	\
-			  .str = &__param_string_##name, perm);		\
+	__module_param_call(MODULE_PARAM_PREFIX, name,			\
+			    param_set_copystring, param_get_string,	\
+			    .str = &__param_string_##name, 0, perm);	\
 	__MODULE_PARM_TYPE(name, "string")
 
 /* Called on module insert or kernel boot */
@@ -186,21 +195,30 @@
 extern int param_get_charp(char *buffer, struct kernel_param *kp);
 #define param_check_charp(name, p) __param_check(name, p, char *)
 
+/* For historical reasons "bool" parameters can be (unsigned) "int". */
 extern int param_set_bool(const char *val, struct kernel_param *kp);
 extern int param_get_bool(char *buffer, struct kernel_param *kp);
-#define param_check_bool(name, p) __param_check(name, p, int)
+#define param_check_bool(name, p)					\
+	static inline void __check_##name(void)				\
+	{								\
+		BUILD_BUG_ON(!__same_type(*(p), bool) &&		\
+			     !__same_type(*(p), unsigned int) &&	\
+			     !__same_type(*(p), int));			\
+	}
 
 extern int param_set_invbool(const char *val, struct kernel_param *kp);
 extern int param_get_invbool(char *buffer, struct kernel_param *kp);
-#define param_check_invbool(name, p) __param_check(name, p, int)
+#define param_check_invbool(name, p) __param_check(name, p, bool)
 
 /* Comma-separated array: *nump is set to number they actually specified. */
 #define module_param_array_named(name, array, type, nump, perm)		\
 	static const struct kparam_array __param_arr_##name		\
 	= { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type,\
 	    sizeof(array[0]), array };					\
-	module_param_call(name, param_array_set, param_array_get, 	\
-			  .arr = &__param_arr_##name, perm);		\
+	__module_param_call(MODULE_PARAM_PREFIX, name,			\
+			    param_array_set, param_array_get,		\
+			    .arr = &__param_arr_##name,			\
+			    __same_type(array[0], bool), perm);		\
 	__MODULE_PARM_TYPE(name, "array of " #type)
 
 #define module_param_array(name, type, nump, perm)		\
diff --git a/include/linux/page_cgroup.h b/include/linux/page_cgroup.h
index 7339c7b..13f126c 100644
--- a/include/linux/page_cgroup.h
+++ b/include/linux/page_cgroup.h
@@ -18,7 +18,19 @@
 };
 
 void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat);
-void __init page_cgroup_init(void);
+
+#ifdef CONFIG_SPARSEMEM
+static inline void __init page_cgroup_init_flatmem(void)
+{
+}
+extern void __init page_cgroup_init(void);
+#else
+void __init page_cgroup_init_flatmem(void);
+static inline void __init page_cgroup_init(void)
+{
+}
+#endif
+
 struct page_cgroup *lookup_page_cgroup(struct page *page);
 
 enum {
@@ -87,6 +99,10 @@
 {
 }
 
+static inline void __init page_cgroup_init_flatmem(void)
+{
+}
+
 #endif
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index d7d1c41..19f8e6d 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1005,6 +1005,7 @@
 #define PCI_DEVICE_ID_PLX_PCI200SYN	0x3196
 #define PCI_DEVICE_ID_PLX_9030          0x9030
 #define PCI_DEVICE_ID_PLX_9050		0x9050
+#define PCI_DEVICE_ID_PLX_9056		0x9056
 #define PCI_DEVICE_ID_PLX_9080		0x9080
 #define PCI_DEVICE_ID_PLX_GTEK_SERIAL2	0xa001
 
@@ -1314,6 +1315,13 @@
 
 #define PCI_VENDOR_ID_CREATIVE		0x1102 /* duplicate: ECTIVA */
 #define PCI_DEVICE_ID_CREATIVE_EMU10K1	0x0002
+#define PCI_DEVICE_ID_CREATIVE_20K1	0x0005
+#define PCI_DEVICE_ID_CREATIVE_20K2	0x000b
+#define PCI_SUBDEVICE_ID_CREATIVE_SB0760	0x0024
+#define PCI_SUBDEVICE_ID_CREATIVE_SB08801	0x0041
+#define PCI_SUBDEVICE_ID_CREATIVE_SB08802	0x0042
+#define PCI_SUBDEVICE_ID_CREATIVE_SB08803	0x0043
+#define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX	0x6000
 
 #define PCI_VENDOR_ID_ECTIVA		0x1102 /* duplicate: CREATIVE */
 #define PCI_DEVICE_ID_ECTIVA_EV1938	0x8938
@@ -1847,6 +1855,10 @@
 #define PCI_SUBDEVICE_ID_HYPERCOPE_METRO	0x0107
 #define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2	0x0108
 
+#define PCI_VENDOR_ID_DIGIGRAM		0x1369
+#define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM	0xc001
+#define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM	0xc002
+
 #define PCI_VENDOR_ID_KAWASAKI		0x136b
 #define PCI_DEVICE_ID_MCHIP_KL5A72002	0xff01
 
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
index 6e13395..1b3118a 100644
--- a/include/linux/perf_counter.h
+++ b/include/linux/perf_counter.h
@@ -120,6 +120,8 @@
 	PERF_SAMPLE_ID				= 1U << 6,
 	PERF_SAMPLE_CPU				= 1U << 7,
 	PERF_SAMPLE_PERIOD			= 1U << 8,
+
+	PERF_SAMPLE_MAX = 1U << 9,		/* non-ABI */
 };
 
 /*
@@ -131,17 +133,26 @@
 	PERF_FORMAT_TOTAL_TIME_ENABLED		= 1U << 0,
 	PERF_FORMAT_TOTAL_TIME_RUNNING		= 1U << 1,
 	PERF_FORMAT_ID				= 1U << 2,
+
+	PERF_FORMAT_MAX = 1U << 3, 		/* non-ABI */
 };
 
+#define PERF_ATTR_SIZE_VER0	64	/* sizeof first published struct */
+
 /*
  * Hardware event to monitor via a performance monitoring counter:
  */
 struct perf_counter_attr {
+
 	/*
 	 * Major type: hardware/software/tracepoint/etc.
 	 */
 	__u32			type;
-	__u32			__reserved_1;
+
+	/*
+	 * Size of the attr structure, for fwd/bwd compat.
+	 */
+	__u32			size;
 
 	/*
 	 * Type specific configuration information.
@@ -168,12 +179,12 @@
 				comm	       :  1, /* include comm data     */
 				freq           :  1, /* use freq, not period  */
 
-				__reserved_2   : 53;
+				__reserved_1   : 53;
 
 	__u32			wakeup_events;	/* wakeup every n events */
-	__u32			__reserved_3;
+	__u32			__reserved_2;
 
-	__u64			__reserved_4;
+	__u64			__reserved_3;
 };
 
 /*
@@ -621,7 +632,8 @@
 static inline int is_software_counter(struct perf_counter *counter)
 {
 	return (counter->attr.type != PERF_TYPE_RAW) &&
-		(counter->attr.type != PERF_TYPE_HARDWARE);
+		(counter->attr.type != PERF_TYPE_HARDWARE) &&
+		(counter->attr.type != PERF_TYPE_HW_CACHE);
 }
 
 extern void perf_swcounter_event(u32, u64, int, struct pt_regs *, u64);
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 1d4e2d2..b3f7476 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -382,14 +382,13 @@
 #ifdef CONFIG_PM_SLEEP
 extern void device_pm_lock(void);
 extern int sysdev_resume(void);
-extern void device_power_up(pm_message_t state);
-extern void device_resume(pm_message_t state);
+extern void dpm_resume_noirq(pm_message_t state);
+extern void dpm_resume_end(pm_message_t state);
 
 extern void device_pm_unlock(void);
 extern int sysdev_suspend(pm_message_t state);
-extern int device_power_down(pm_message_t state);
-extern int device_suspend(pm_message_t state);
-extern int device_prepare_suspend(pm_message_t state);
+extern int dpm_suspend_noirq(pm_message_t state);
+extern int dpm_suspend_start(pm_message_t state);
 
 extern void __suspend_report_result(const char *function, void *fn, int ret);
 
@@ -403,7 +402,7 @@
 #define device_pm_lock() do {} while (0)
 #define device_pm_unlock() do {} while (0)
 
-static inline int device_suspend(pm_message_t state)
+static inline int dpm_suspend_start(pm_message_t state)
 {
 	return 0;
 }
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index ca3c887..b063c73 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -446,6 +446,7 @@
 int pnp_stop_dev(struct pnp_dev *dev);
 int pnp_activate_dev(struct pnp_dev *dev);
 int pnp_disable_dev(struct pnp_dev *dev);
+int pnp_range_reserved(resource_size_t start, resource_size_t end);
 
 /* protocol helpers */
 int pnp_is_active(struct pnp_dev *dev);
@@ -476,6 +477,7 @@
 static inline int pnp_stop_dev(struct pnp_dev *dev) { return -ENODEV; }
 static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; }
 static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; }
+static inline int pnp_range_reserved(resource_size_t start, resource_size_t end) { return 0;}
 
 /* protocol helpers */
 static inline int pnp_is_active(struct pnp_dev *dev) { return 0; }
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 4880306..219b8fb 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -319,4 +319,6 @@
 	return kmalloc_node(size, flags | __GFP_ZERO, node);
 }
 
+void __init kmem_cache_init_late(void);
+
 #endif	/* _LINUX_SLAB_H */
diff --git a/include/linux/slob_def.h b/include/linux/slob_def.h
index 0ec00b3..bb5368d 100644
--- a/include/linux/slob_def.h
+++ b/include/linux/slob_def.h
@@ -34,4 +34,9 @@
 	return kmalloc(size, flags);
 }
 
+static inline void kmem_cache_init_late(void)
+{
+	/* Nothing to do */
+}
+
 #endif /* __LINUX_SLOB_DEF_H */
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index be5d40c..4dcbc2c 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -302,4 +302,6 @@
 }
 #endif
 
+void __init kmem_cache_init_late(void);
+
 #endif /* _LINUX_SLUB_DEF_H */
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 795032e..cd15df6 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -245,11 +245,6 @@
 
 extern void hibernation_set_ops(struct platform_hibernation_ops *ops);
 extern int hibernate(void);
-extern int hibernate_nvs_register(unsigned long start, unsigned long size);
-extern int hibernate_nvs_alloc(void);
-extern void hibernate_nvs_free(void);
-extern void hibernate_nvs_save(void);
-extern void hibernate_nvs_restore(void);
 extern bool system_entering_hibernation(void);
 #else /* CONFIG_HIBERNATION */
 static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
@@ -258,6 +253,16 @@
 
 static inline void hibernation_set_ops(struct platform_hibernation_ops *ops) {}
 static inline int hibernate(void) { return -ENOSYS; }
+static inline bool system_entering_hibernation(void) { return false; }
+#endif /* CONFIG_HIBERNATION */
+
+#ifdef CONFIG_HIBERNATION_NVS
+extern int hibernate_nvs_register(unsigned long start, unsigned long size);
+extern int hibernate_nvs_alloc(void);
+extern void hibernate_nvs_free(void);
+extern void hibernate_nvs_save(void);
+extern void hibernate_nvs_restore(void);
+#else /* CONFIG_HIBERNATION_NVS */
 static inline int hibernate_nvs_register(unsigned long a, unsigned long b)
 {
 	return 0;
@@ -266,8 +271,7 @@
 static inline void hibernate_nvs_free(void) {}
 static inline void hibernate_nvs_save(void) {}
 static inline void hibernate_nvs_restore(void) {}
-static inline bool system_entering_hibernation(void) { return false; }
-#endif /* CONFIG_HIBERNATION */
+#endif /* CONFIG_HIBERNATION_NVS */
 
 #ifdef CONFIG_PM_SLEEP
 void save_processor_state(void);
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index c6c84ad..418d90f 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -758,6 +758,6 @@
 
 
 asmlinkage long sys_perf_counter_open(
-		const struct perf_counter_attr __user *attr_uptr,
+		struct perf_counter_attr __user *attr_uptr,
 		pid_t pid, int cpu, int group_fd, unsigned long flags);
 #endif
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index 06005fa..4fca4f5 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -10,14 +10,17 @@
 
 /**
  * virtqueue - a queue to register buffers for sending or receiving.
+ * @list: the chain of virtqueues for this device
  * @callback: the function to call when buffers are consumed (can be NULL).
+ * @name: the name of this virtqueue (mainly for debugging)
  * @vdev: the virtio device this queue was created for.
  * @vq_ops: the operations for this virtqueue (see below).
  * @priv: a pointer for the virtqueue implementation to use.
  */
-struct virtqueue
-{
+struct virtqueue {
+	struct list_head list;
 	void (*callback)(struct virtqueue *vq);
+	const char *name;
 	struct virtio_device *vdev;
 	struct virtqueue_ops *vq_ops;
 	void *priv;
@@ -76,15 +79,16 @@
  * @dev: underlying device.
  * @id: the device type identification (used to match it with a driver).
  * @config: the configuration ops for this device.
+ * @vqs: the list of virtqueues for this device.
  * @features: the features supported by both driver and device.
  * @priv: private pointer for the driver's use.
  */
-struct virtio_device
-{
+struct virtio_device {
 	int index;
 	struct device dev;
 	struct virtio_device_id id;
 	struct virtio_config_ops *config;
+	struct list_head vqs;
 	/* Note that this is a Linux set_bit-style bitmap. */
 	unsigned long features[1];
 	void *priv;
@@ -99,8 +103,7 @@
  * @id_table: the ids serviced by this driver.
  * @feature_table: an array of feature numbers supported by this device.
  * @feature_table_size: number of entries in the feature table array.
- * @probe: the function to call when a device is found.  Returns a token for
- *    remove, or PTR_ERR().
+ * @probe: the function to call when a device is found.  Returns 0 or -errno.
  * @remove: the function when a device is removed.
  * @config_changed: optional function to call when the device configuration
  *    changes; may be called in interrupt context.
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index bf8ec28..99f5145 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -29,6 +29,7 @@
 #define VIRTIO_F_NOTIFY_ON_EMPTY	24
 
 #ifdef __KERNEL__
+#include <linux/err.h>
 #include <linux/virtio.h>
 
 /**
@@ -49,15 +50,26 @@
  * @set_status: write the status byte
  *	vdev: the virtio_device
  *	status: the new status byte
+ * @request_vqs: request the specified number of virtqueues
+ *	vdev: the virtio_device
+ *	max_vqs: the max number of virtqueues we want
+ *      If supplied, must call before any virtqueues are instantiated.
+ *      To modify the max number of virtqueues after request_vqs has been
+ *      called, call free_vqs and then request_vqs with a new value.
+ * @free_vqs: cleanup resources allocated by request_vqs
+ *	vdev: the virtio_device
+ *      If supplied, must call after all virtqueues have been deleted.
  * @reset: reset the device
  *	vdev: the virtio device
  *	After this, status and feature negotiation must be done again
- * @find_vq: find a virtqueue and instantiate it.
+ * @find_vqs: find virtqueues and instantiate them.
  *	vdev: the virtio_device
- *	index: the 0-based virtqueue number in case there's more than one.
- *	callback: the virqtueue callback
- *	Returns the new virtqueue or ERR_PTR() (eg. -ENOENT).
- * @del_vq: free a virtqueue found by find_vq().
+ *	nvqs: the number of virtqueues to find
+ *	vqs: on success, includes new virtqueues
+ *	callbacks: array of callbacks, for each virtqueue
+ *	names: array of virtqueue names (mainly for debugging)
+ *	Returns 0 on success or error status
+ * @del_vqs: free virtqueues found by find_vqs().
  * @get_features: get the array of feature bits for this device.
  *	vdev: the virtio_device
  *	Returns the first 32 feature bits (all we currently need).
@@ -66,6 +78,7 @@
  *	This gives the final feature bits for the device: it can change
  *	the dev->feature bits if it wants.
  */
+typedef void vq_callback_t(struct virtqueue *);
 struct virtio_config_ops
 {
 	void (*get)(struct virtio_device *vdev, unsigned offset,
@@ -75,10 +88,11 @@
 	u8 (*get_status)(struct virtio_device *vdev);
 	void (*set_status)(struct virtio_device *vdev, u8 status);
 	void (*reset)(struct virtio_device *vdev);
-	struct virtqueue *(*find_vq)(struct virtio_device *vdev,
-				     unsigned index,
-				     void (*callback)(struct virtqueue *));
-	void (*del_vq)(struct virtqueue *vq);
+	int (*find_vqs)(struct virtio_device *, unsigned nvqs,
+			struct virtqueue *vqs[],
+			vq_callback_t *callbacks[],
+			const char *names[]);
+	void (*del_vqs)(struct virtio_device *);
 	u32 (*get_features)(struct virtio_device *vdev);
 	void (*finalize_features)(struct virtio_device *vdev);
 };
@@ -99,7 +113,9 @@
 	if (__builtin_constant_p(fbit))
 		BUILD_BUG_ON(fbit >= 32);
 
-	virtio_check_driver_offered_feature(vdev, fbit);
+	if (fbit < VIRTIO_TRANSPORT_F_START)
+		virtio_check_driver_offered_feature(vdev, fbit);
+
 	return test_bit(fbit, vdev->features);
 }
 
@@ -126,5 +142,18 @@
 	vdev->config->get(vdev, offset, buf, len);
 	return 0;
 }
+
+static inline
+struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev,
+					vq_callback_t *c, const char *n)
+{
+	vq_callback_t *callbacks[] = { c };
+	const char *names[] = { n };
+	struct virtqueue *vq;
+	int err = vdev->config->find_vqs(vdev, 1, &vq, callbacks, names);
+	if (err < 0)
+		return ERR_PTR(err);
+	return vq;
+}
 #endif /* __KERNEL__ */
 #endif /* _LINUX_VIRTIO_CONFIG_H */
diff --git a/include/linux/virtio_pci.h b/include/linux/virtio_pci.h
index cd0fd5d..9a3d7c4 100644
--- a/include/linux/virtio_pci.h
+++ b/include/linux/virtio_pci.h
@@ -47,9 +47,17 @@
 /* The bit of the ISR which indicates a device configuration change. */
 #define VIRTIO_PCI_ISR_CONFIG		0x2
 
+/* MSI-X registers: only enabled if MSI-X is enabled. */
+/* A 16-bit vector for configuration changes. */
+#define VIRTIO_MSI_CONFIG_VECTOR        20
+/* A 16-bit vector for selected queue notifications. */
+#define VIRTIO_MSI_QUEUE_VECTOR         22
+/* Vector value used to disable MSI for queue */
+#define VIRTIO_MSI_NO_VECTOR            0xffff
+
 /* The remaining space is defined by each driver as the per-driver
  * configuration space */
-#define VIRTIO_PCI_CONFIG		20
+#define VIRTIO_PCI_CONFIG(dev)		((dev)->msix_enabled ? 24 : 20)
 
 /* Virtio ABI version, this must match exactly */
 #define VIRTIO_PCI_ABI_VERSION		0
diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
index 71e0372..693e0ec 100644
--- a/include/linux/virtio_ring.h
+++ b/include/linux/virtio_ring.h
@@ -14,6 +14,8 @@
 #define VRING_DESC_F_NEXT	1
 /* This marks a buffer as write-only (otherwise read-only). */
 #define VRING_DESC_F_WRITE	2
+/* This means the buffer contains a list of buffer descriptors. */
+#define VRING_DESC_F_INDIRECT	4
 
 /* The Host uses this in used->flags to advise the Guest: don't kick me when
  * you add a buffer.  It's unreliable, so it's simply an optimization.  Guest
@@ -24,6 +26,9 @@
  * optimization.  */
 #define VRING_AVAIL_F_NO_INTERRUPT	1
 
+/* We support indirect buffer descriptors */
+#define VIRTIO_RING_F_INDIRECT_DESC	28
+
 /* Virtio ring descriptors: 16 bytes.  These can chain together via "next". */
 struct vring_desc
 {
@@ -119,7 +124,8 @@
 				      struct virtio_device *vdev,
 				      void *pages,
 				      void (*notify)(struct virtqueue *vq),
-				      void (*callback)(struct virtqueue *vq));
+				      void (*callback)(struct virtqueue *vq),
+				      const char *name);
 void vring_del_virtqueue(struct virtqueue *vq);
 /* Filter out transport-specific feature bits. */
 void vring_transport_features(struct virtio_device *vdev);
diff --git a/include/scsi/fc/fc_fip.h b/include/scsi/fc/fc_fip.h
index 0627a9a..3d138c1 100644
--- a/include/scsi/fc/fc_fip.h
+++ b/include/scsi/fc/fc_fip.h
@@ -22,13 +22,6 @@
  * http://www.t11.org/ftp/t11/pub/fc/bb-5/08-543v1.pdf
  */
 
-/*
- * The FIP ethertype eventually goes in net/if_ether.h.
- */
-#ifndef ETH_P_FIP
-#define ETH_P_FIP	0x8914	/* FIP Ethertype */
-#endif
-
 #define FIP_DEF_PRI	128	/* default selection priority */
 #define FIP_DEF_FC_MAP	0x0efc00 /* default FCoE MAP (MAC OUI) value */
 #define FIP_DEF_FKA	8000	/* default FCF keep-alive/advert period (mS) */
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index d0ed522..4426f00 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -22,6 +22,11 @@
 #define ISCSI_IF_H
 
 #include <scsi/iscsi_proto.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+
+#define ISCSI_NL_GRP_ISCSID	1
+#define ISCSI_NL_GRP_UIP	2
 
 #define UEVENT_BASE			10
 #define KEVENT_BASE			100
@@ -50,7 +55,10 @@
 	ISCSI_UEVENT_TGT_DSCVR		= UEVENT_BASE + 15,
 	ISCSI_UEVENT_SET_HOST_PARAM	= UEVENT_BASE + 16,
 	ISCSI_UEVENT_UNBIND_SESSION	= UEVENT_BASE + 17,
-	ISCSI_UEVENT_CREATE_BOUND_SESSION	= UEVENT_BASE + 18,
+	ISCSI_UEVENT_CREATE_BOUND_SESSION		= UEVENT_BASE + 18,
+	ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST	= UEVENT_BASE + 19,
+
+	ISCSI_UEVENT_PATH_UPDATE	= UEVENT_BASE + 20,
 
 	/* up events */
 	ISCSI_KEVENT_RECV_PDU		= KEVENT_BASE + 1,
@@ -59,6 +67,9 @@
 	ISCSI_KEVENT_DESTROY_SESSION	= KEVENT_BASE + 4,
 	ISCSI_KEVENT_UNBIND_SESSION	= KEVENT_BASE + 5,
 	ISCSI_KEVENT_CREATE_SESSION	= KEVENT_BASE + 6,
+
+	ISCSI_KEVENT_PATH_REQ		= KEVENT_BASE + 7,
+	ISCSI_KEVENT_IF_DOWN		= KEVENT_BASE + 8,
 };
 
 enum iscsi_tgt_dscvr {
@@ -131,6 +142,10 @@
 		struct msg_transport_connect {
 			uint32_t	non_blocking;
 		} ep_connect;
+		struct msg_transport_connect_through_host {
+			uint32_t	host_no;
+			uint32_t	non_blocking;
+		} ep_connect_through_host;
 		struct msg_transport_poll {
 			uint64_t	ep_handle;
 			uint32_t	timeout_ms;
@@ -154,6 +169,9 @@
 			uint32_t	param; /* enum iscsi_host_param */
 			uint32_t	len;
 		} set_host_param;
+		struct msg_set_path {
+			uint32_t	host_no;
+		} set_path;
 	} u;
 	union {
 		/* messages k -> u */
@@ -187,10 +205,39 @@
 		struct msg_transport_connect_ret {
 			uint64_t	handle;
 		} ep_connect_ret;
+		struct msg_req_path {
+			uint32_t	host_no;
+		} req_path;
+		struct msg_notify_if_down {
+			uint32_t	host_no;
+		} notify_if_down;
 	} r;
 } __attribute__ ((aligned (sizeof(uint64_t))));
 
 /*
+ * To keep the struct iscsi_uevent size the same for userspace code
+ * compatibility, the main structure for ISCSI_UEVENT_PATH_UPDATE and
+ * ISCSI_KEVENT_PATH_REQ is defined separately and comes after the
+ * struct iscsi_uevent in the NETLINK_ISCSI message.
+ */
+struct iscsi_path {
+	uint64_t	handle;
+	uint8_t		mac_addr[6];
+	uint8_t		mac_addr_old[6];
+	uint32_t	ip_addr_len;	/* 4 or 16 */
+	union {
+		struct in_addr	v4_addr;
+		struct in6_addr	v6_addr;
+	} src;
+	union {
+		struct in_addr	v4_addr;
+		struct in6_addr	v6_addr;
+	} dst;
+	uint16_t	vlan_id;
+	uint16_t	pmtu;
+} __attribute__ ((aligned (sizeof(uint64_t))));
+
+/*
  * Common error codes
  */
 enum iscsi_err {
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index 45f9cc6..ebdd9f4 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -679,6 +679,7 @@
 	unsigned int		e_d_tov;
 	unsigned int		r_a_tov;
 	u8			max_retry_count;
+	u8			max_rport_retry_count;
 	u16			link_speed;
 	u16			link_supported_speeds;
 	u16			lro_xid;	/* max xid for fcoe lro */
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 0289f57..196525c 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -82,9 +82,12 @@
 
 
 enum {
+	ISCSI_TASK_FREE,
 	ISCSI_TASK_COMPLETED,
 	ISCSI_TASK_PENDING,
 	ISCSI_TASK_RUNNING,
+	ISCSI_TASK_ABRT_TMF,		/* aborted due to TMF */
+	ISCSI_TASK_ABRT_SESS_RECOV,	/* aborted due to session recovery */
 };
 
 struct iscsi_r2t_info {
@@ -181,9 +184,7 @@
 
 	/* xmit */
 	struct list_head	mgmtqueue;	/* mgmt (control) xmit queue */
-	struct list_head	mgmt_run_list;	/* list of control tasks */
-	struct list_head	xmitqueue;	/* data-path cmd queue */
-	struct list_head	run_list;	/* list of cmds in progress */
+	struct list_head	cmdqueue;	/* data-path cmd queue */
 	struct list_head	requeue;	/* tasks needing another run */
 	struct work_struct	xmitwork;	/* per-conn. xmit workqueue */
 	unsigned long		suspend_tx;	/* suspend Tx */
@@ -406,6 +407,7 @@
 				char *, int);
 extern int iscsi_verify_itt(struct iscsi_conn *, itt_t);
 extern struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *, itt_t);
+extern struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *, itt_t);
 extern void iscsi_requeue_task(struct iscsi_task *task);
 extern void iscsi_put_task(struct iscsi_task *task);
 extern void __iscsi_get_task(struct iscsi_task *task);
diff --git a/include/scsi/osd_attributes.h b/include/scsi/osd_attributes.h
index f888a6f..56e920a 100644
--- a/include/scsi/osd_attributes.h
+++ b/include/scsi/osd_attributes.h
@@ -29,6 +29,7 @@
 	OSD_APAGE_PARTITION_INFORMATION = OSD_APAGE_PARTITION_FIRST + 1,
 	OSD_APAGE_PARTITION_QUOTAS	= OSD_APAGE_PARTITION_FIRST + 2,
 	OSD_APAGE_PARTITION_TIMESTAMP	= OSD_APAGE_PARTITION_FIRST + 3,
+	OSD_APAGE_PARTITION_ATTR_ACCESS = OSD_APAGE_PARTITION_FIRST + 4,
 	OSD_APAGE_PARTITION_SECURITY	= OSD_APAGE_PARTITION_FIRST + 5,
 	OSD_APAGE_PARTITION_LAST	= 0x5FFFFFFF,
 
@@ -51,7 +52,9 @@
 	OSD_APAGE_RESERVED_TYPE_LAST	= 0xEFFFFFFF,
 
 	OSD_APAGE_COMMON_FIRST		= 0xF0000000,
-	OSD_APAGE_COMMON_LAST		= 0xFFFFFFFE,
+	OSD_APAGE_COMMON_LAST		= 0xFFFFFFFD,
+
+	OSD_APAGE_CURRENT_COMMAND	= 0xFFFFFFFE,
 
 	OSD_APAGE_REQUEST_ALL		= 0xFFFFFFFF,
 };
@@ -106,10 +109,30 @@
 	OSD_ATTR_RI_PRODUCT_REVISION_LEVEL   = 0x7,   /* 4        */
 	OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER    = 0x8,   /* variable */
 	OSD_ATTR_RI_OSD_NAME                 = 0x9,   /* variable */
+	OSD_ATTR_RI_MAX_CDB_CONTINUATION_LEN = 0xA,   /* 4        */
 	OSD_ATTR_RI_TOTAL_CAPACITY           = 0x80,  /* 8        */
 	OSD_ATTR_RI_USED_CAPACITY            = 0x81,  /* 8        */
 	OSD_ATTR_RI_NUMBER_OF_PARTITIONS     = 0xC0,  /* 8        */
 	OSD_ATTR_RI_CLOCK                    = 0x100, /* 6        */
+	OARI_DEFAULT_ISOLATION_METHOD        = 0X110, /* 1        */
+	OARI_SUPPORTED_ISOLATION_METHODS     = 0X111, /* 32       */
+
+	OARI_DATA_ATOMICITY_GUARANTEE                   = 0X120,   /* 8       */
+	OARI_DATA_ATOMICITY_ALIGNMENT                   = 0X121,   /* 8       */
+	OARI_ATTRIBUTES_ATOMICITY_GUARANTEE             = 0X122,   /* 8       */
+	OARI_DATA_ATTRIBUTES_ATOMICITY_MULTIPLIER       = 0X123,   /* 1       */
+
+	OARI_MAXIMUM_SNAPSHOTS_COUNT                    = 0X1C1,    /* 0 or 4 */
+	OARI_MAXIMUM_CLONES_COUNT                       = 0X1C2,    /* 0 or 4 */
+	OARI_MAXIMUM_BRANCH_DEPTH                       = 0X1CC,    /* 0 or 4 */
+	OARI_SUPPORTED_OBJECT_DUPLICATION_METHOD_FIRST  = 0X200,    /* 0 or 4 */
+	OARI_SUPPORTED_OBJECT_DUPLICATION_METHOD_LAST   = 0X2ff,    /* 0 or 4 */
+	OARI_SUPPORTED_TIME_OF_DUPLICATION_METHOD_FIRST = 0X300,    /* 0 or 4 */
+	OARI_SUPPORTED_TIME_OF_DUPLICATION_METHOD_LAST  = 0X30F,    /* 0 or 4 */
+	OARI_SUPPORT_FOR_DUPLICATED_OBJECT_FREEZING     = 0X310,    /* 0 or 4 */
+	OARI_SUPPORT_FOR_SNAPSHOT_REFRESHING            = 0X311,    /* 0 or 1 */
+	OARI_SUPPORTED_CDB_CONTINUATION_DESC_TYPE_FIRST = 0X7000001,/* 0 or 4 */
+	OARI_SUPPORTED_CDB_CONTINUATION_DESC_TYPE_LAST  = 0X700FFFF,/* 0 or 4 */
 };
 /* Root_Information_attributes_page does not have a get_page structure */
 
@@ -120,7 +143,15 @@
 	OSD_ATTR_PI_PARTITION_ID            = 0x1,     /* 8        */
 	OSD_ATTR_PI_USERNAME                = 0x9,     /* variable */
 	OSD_ATTR_PI_USED_CAPACITY           = 0x81,    /* 8        */
+	OSD_ATTR_PI_USED_CAPACITY_INCREMENT = 0x84,    /* 0 or 8   */
 	OSD_ATTR_PI_NUMBER_OF_OBJECTS       = 0xC1,    /* 8        */
+
+	OSD_ATTR_PI_ACTUAL_DATA_SPACE                      = 0xD1, /* 0 or 8 */
+	OSD_ATTR_PI_RESERVED_DATA_SPACE                    = 0xD2, /* 0 or 8 */
+	OSD_ATTR_PI_DEFAULT_SNAPSHOT_DUPLICATION_METHOD    = 0x200,/* 0 or 4 */
+	OSD_ATTR_PI_DEFAULT_CLONE_DUPLICATION_METHOD       = 0x201,/* 0 or 4 */
+	OSD_ATTR_PI_DEFAULT_SP_TIME_OF_DUPLICATION         = 0x300,/* 0 or 4 */
+	OSD_ATTR_PI_DEFAULT_CLONE_TIME_OF_DUPLICATION      = 0x301,/* 0 or 4 */
 };
 /* Partition Information attributes page does not have a get_page structure */
 
@@ -131,6 +162,7 @@
 	OSD_ATTR_CI_PARTITION_ID           = 0x1,       /* 8        */
 	OSD_ATTR_CI_COLLECTION_OBJECT_ID   = 0x2,       /* 8        */
 	OSD_ATTR_CI_USERNAME               = 0x9,       /* variable */
+	OSD_ATTR_CI_COLLECTION_TYPE        = 0xA,       /* 1        */
 	OSD_ATTR_CI_USED_CAPACITY          = 0x81,      /* 8        */
 };
 /* Collection Information attributes page does not have a get_page structure */
@@ -144,6 +176,8 @@
 	OSD_ATTR_OI_USERNAME             = 0x9,       /* variable */
 	OSD_ATTR_OI_USED_CAPACITY        = 0x81,      /* 8        */
 	OSD_ATTR_OI_LOGICAL_LENGTH       = 0x82,      /* 8        */
+	SD_ATTR_OI_ACTUAL_DATA_SPACE     = 0XD1,      /* 0 OR 8   */
+	SD_ATTR_OI_RESERVED_DATA_SPACE   = 0XD2,      /* 0 OR 8   */
 };
 /* Object Information attributes page does not have a get_page structure */
 
@@ -248,7 +282,18 @@
 	struct osd_timestamp data_modified_time;
 }  __packed;
 
-/* 7.1.2.19 Collections attributes page */
+/* OSD2r05: 7.1.3.19 Attributes Access attributes page
+ * (OSD_APAGE_PARTITION_ATTR_ACCESS)
+ *
+ * each attribute is of the form below. Total array length is deduced
+ * from the attribute's length
+ * (See allowed_attributes_access of the struct osd_cap_object_descriptor)
+ */
+struct attributes_access_attr {
+	struct osd_attributes_list_attrid attr_list[0];
+} __packed;
+
+/* OSD2r05: 7.1.2.21 Collections attributes page */
 /* TBD */
 
 /* 7.1.2.20 Root Policy/Security attributes page (OSD_APAGE_ROOT_SECURITY) */
@@ -324,4 +369,29 @@
 	__be32 policy_access_tag;
 }  __packed;
 
+/* OSD2r05: 7.1.3.31 Current Command attributes page
+ * (OSD_APAGE_CURRENT_COMMAND)
+ */
+enum {
+	OSD_ATTR_CC_RESPONSE_INTEGRITY_CHECK_VALUE     = 0x1, /* 32  */
+	OSD_ATTR_CC_OBJECT_TYPE                        = 0x2, /* 1   */
+	OSD_ATTR_CC_PARTITION_ID                       = 0x3, /* 8   */
+	OSD_ATTR_CC_OBJECT_ID                          = 0x4, /* 8   */
+	OSD_ATTR_CC_STARTING_BYTE_ADDRESS_OF_APPEND    = 0x5, /* 8   */
+	OSD_ATTR_CC_CHANGE_IN_USED_CAPACITY            = 0x6, /* 8   */
+};
+
+/*TBD: osdv1_current_command_attributes_page */
+
+struct osdv2_current_command_attributes_page {
+	struct osd_attr_page_header hdr;  /* id=0xFFFFFFFE, size=0x44 */
+	u8 response_integrity_check_value[OSD_CRYPTO_KEYID_SIZE];
+	u8 object_type;
+	u8 reserved[3];
+	__be64 partition_id;
+	__be64 object_id;
+	__be64 starting_byte_address_of_append;
+	__be64 change_in_used_capacity;
+};
+
 #endif /*ndef __OSD_ATTRIBUTES_H__*/
diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
index b24d961..02bd9f7 100644
--- a/include/scsi/osd_initiator.h
+++ b/include/scsi/osd_initiator.h
@@ -18,6 +18,7 @@
 #include "osd_types.h"
 
 #include <linux/blkdev.h>
+#include <scsi/scsi_device.h>
 
 /* Note: "NI" in comments below means "Not Implemented yet" */
 
@@ -47,6 +48,7 @@
  */
 struct osd_dev {
 	struct scsi_device *scsi_device;
+	struct file *file;
 	unsigned def_timeout;
 
 #ifdef OSD_VER1_SUPPORT
@@ -69,6 +71,10 @@
 
 /* some hi level device operations */
 int osd_auto_detect_ver(struct osd_dev *od, void *caps);    /* GFP_KERNEL */
+static inline struct request_queue *osd_request_queue(struct osd_dev *od)
+{
+	return od->scsi_device->request_queue;
+}
 
 /* we might want to use function vector in the future */
 static inline void osd_dev_set_ver(struct osd_dev *od, enum osd_std_version v)
@@ -363,7 +369,9 @@
 void osd_req_remove_object(struct osd_request *or, struct osd_obj_id *);
 
 void osd_req_write(struct osd_request *or,
-	const struct osd_obj_id *, struct bio *data_out, u64 offset);
+	const struct osd_obj_id *obj, u64 offset, struct bio *bio, u64 len);
+int osd_req_write_kern(struct osd_request *or,
+	const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
 void osd_req_append(struct osd_request *or,
 	const struct osd_obj_id *, struct bio *data_out);/* NI */
 void osd_req_create_write(struct osd_request *or,
@@ -378,7 +386,9 @@
 	/*V2*/ u64 offset, /*V2*/ u64 len);
 
 void osd_req_read(struct osd_request *or,
-	const struct osd_obj_id *, struct bio *data_in, u64 offset);
+	const struct osd_obj_id *obj, u64 offset, struct bio *bio, u64 len);
+int osd_req_read_kern(struct osd_request *or,
+	const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
 
 /*
  * Root/Partition/Collection/Object Attributes commands
diff --git a/include/scsi/osd_protocol.h b/include/scsi/osd_protocol.h
index 62b2ab8..2cc8e8b 100644
--- a/include/scsi/osd_protocol.h
+++ b/include/scsi/osd_protocol.h
@@ -303,7 +303,15 @@
 	OSD_ACT_V2(REMOVE_MEMBER_OBJECTS,	0x21)
 	OSD_ACT_V2(GET_MEMBER_ATTRIBUTES,	0x22)
 	OSD_ACT_V2(SET_MEMBER_ATTRIBUTES,	0x23)
+
+	OSD_ACT_V2(CREATE_CLONE,		0x28)
+	OSD_ACT_V2(CREATE_SNAPSHOT,		0x29)
+	OSD_ACT_V2(DETACH_CLONE,		0x2A)
+	OSD_ACT_V2(REFRESH_SNAPSHOT_CLONE,	0x2B)
+	OSD_ACT_V2(RESTORE_PARTITION_FROM_SNAPSHOT, 0x2C)
+
 	OSD_ACT_V2(READ_MAP,			0x31)
+	OSD_ACT_V2(READ_MAPS_COMPARE,		0x32)
 
 	OSD_ACT_V1_V2(PERFORM_SCSI_COMMAND,	0x8F7E, 0x8F7C)
 	OSD_ACT_V1_V2(SCSI_TASK_MANAGEMENT,	0x8F7F, 0x8F7D)
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 457588e..349c7f3 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -126,12 +126,14 @@
 			       int *index, int *age);
 
 	void (*session_recovery_timedout) (struct iscsi_cls_session *session);
-	struct iscsi_endpoint *(*ep_connect) (struct sockaddr *dst_addr,
+	struct iscsi_endpoint *(*ep_connect) (struct Scsi_Host *shost,
+					      struct sockaddr *dst_addr,
 					      int non_blocking);
 	int (*ep_poll) (struct iscsi_endpoint *ep, int timeout_ms);
 	void (*ep_disconnect) (struct iscsi_endpoint *ep);
 	int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type,
 			  uint32_t enable, struct sockaddr *dst_addr);
+	int (*set_path) (struct Scsi_Host *shost, struct iscsi_path *params);
 };
 
 /*
@@ -148,6 +150,10 @@
 extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
 			  char *data, uint32_t data_size);
 
+extern int iscsi_offload_mesg(struct Scsi_Host *shost,
+			      struct iscsi_transport *transport, uint32_t type,
+			      char *data, uint16_t data_size);
+
 struct iscsi_cls_conn {
 	struct list_head conn_list;	/* item in connlist */
 	void *dd_data;			/* LLD private data */
diff --git a/include/sound/asound.h b/include/sound/asound.h
index 6add80f..82aed3f 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -255,6 +255,7 @@
 #define SNDRV_PCM_INFO_HALF_DUPLEX	0x00100000	/* only half duplex */
 #define SNDRV_PCM_INFO_JOINT_DUPLEX	0x00200000	/* playback and capture stream are somewhat correlated */
 #define SNDRV_PCM_INFO_SYNC_START	0x00400000	/* pcm support some kind of sync go */
+#define SNDRV_PCM_INFO_FIFO_IN_FRAMES	0x80000000	/* internal kernel flag - FIFO size is in frames */
 
 typedef int __bitwise snd_pcm_state_t;
 #define	SNDRV_PCM_STATE_OPEN		((__force snd_pcm_state_t) 0) /* stream is open */
diff --git a/include/sound/core.h b/include/sound/core.h
index 3dea798..309cb96 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -300,19 +300,10 @@
 		    struct module *module, int extra_size,
 		    struct snd_card **card_ret);
 
-static inline __deprecated
-struct snd_card *snd_card_new(int idx, const char *id,
-			      struct module *module, int extra_size)
-{
-	struct snd_card *card;
-	if (snd_card_create(idx, id, module, extra_size, &card) < 0)
-		return NULL;
-	return card;
-}
-
 int snd_card_disconnect(struct snd_card *card);
 int snd_card_free(struct snd_card *card);
 int snd_card_free_when_closed(struct snd_card *card);
+void snd_card_set_id(struct snd_card *card, const char *id);
 int snd_card_register(struct snd_card *card);
 int snd_card_info_init(void);
 int snd_card_info_done(void);
diff --git a/include/sound/driver.h b/include/sound/driver.h
deleted file mode 100644
index f035943..0000000
--- a/include/sound/driver.h
+++ /dev/null
@@ -1 +0,0 @@
-#warning "This file is deprecated"
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index c172968..2389352 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -98,6 +98,7 @@
 #define SNDRV_PCM_IOCTL1_INFO		1
 #define SNDRV_PCM_IOCTL1_CHANNEL_INFO	2
 #define SNDRV_PCM_IOCTL1_GSTATE		3
+#define SNDRV_PCM_IOCTL1_FIFO_SIZE	4
 
 #define SNDRV_PCM_TRIGGER_STOP		0
 #define SNDRV_PCM_TRIGGER_START		1
@@ -270,6 +271,7 @@
 	snd_pcm_uframes_t hw_ptr_base;	/* Position at buffer restart */
 	snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
 	unsigned long hw_ptr_jiffies;	/* Time when hw_ptr is updated */
+	snd_pcm_sframes_t delay;	/* extra delay; typically FIFO size */
 
 	/* -- HW params -- */
 	snd_pcm_access_t access;	/* access mode */
@@ -486,80 +488,6 @@
 void snd_pcm_vma_notify_data(void *client, void *data);
 int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area);
 
-#if BITS_PER_LONG >= 64
-
-static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem)
-{
-	*rem = *n % div;
-	*n /= div;
-}
-
-#elif defined(i386)
-
-static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem)
-{
-	u_int32_t low, high;
-	low = *n & 0xffffffff;
-	high = *n >> 32;
-	if (high) {
-		u_int32_t high1 = high % div;
-		high /= div;
-		asm("divl %2":"=a" (low), "=d" (*rem):"rm" (div), "a" (low), "d" (high1));
-		*n = (u_int64_t)high << 32 | low;
-	} else {
-		*n = low / div;
-		*rem = low % div;
-	}
-}
-#else
-
-static inline void divl(u_int32_t high, u_int32_t low,
-			u_int32_t div,
-			u_int32_t *q, u_int32_t *r)
-{
-	u_int64_t n = (u_int64_t)high << 32 | low;
-	u_int64_t d = (u_int64_t)div << 31;
-	u_int32_t q1 = 0;
-	int c = 32;
-	while (n > 0xffffffffU) {
-		q1 <<= 1;
-		if (n >= d) {
-			n -= d;
-			q1 |= 1;
-		}
-		d >>= 1;
-		c--;
-	}
-	q1 <<= c;
-	if (n) {
-		low = n;
-		*q = q1 | (low / div);
-		*r = low % div;
-	} else {
-		*r = 0;
-		*q = q1;
-	}
-	return;
-}
-
-static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem)
-{
-	u_int32_t low, high;
-	low = *n & 0xffffffff;
-	high = *n >> 32;
-	if (high) {
-		u_int32_t high1 = high % div;
-		u_int32_t low1 = low;
-		high /= div;
-		divl(high1, low1, div, &low, rem);
-		*n = (u_int64_t)high << 32 | low;
-	} else {
-		*n = low / div;
-		*rem = low % div;
-	}
-}
-#endif
-
 /*
  *  PCM library
  */
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 1367647..352d7ee 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -45,24 +45,6 @@
 #define SND_SOC_DAIFMT_GATED		(1 << 4) /* clock is gated */
 
 /*
- * DAI Left/Right Clocks.
- *
- * Specifies whether the DAI can support different samples for similtanious
- * playback and capture. This usually requires a seperate physical frame
- * clock for playback and capture.
- */
-#define SND_SOC_DAIFMT_SYNC		(0 << 5) /* Tx FRM = Rx FRM */
-#define SND_SOC_DAIFMT_ASYNC		(1 << 5) /* Tx FRM ~ Rx FRM */
-
-/*
- * TDM
- *
- * Time Division Multiplexing. Allows PCM data to be multplexed with other
- * data on the DAI.
- */
-#define SND_SOC_DAIFMT_TDM		(1 << 6)
-
-/*
  * DAI hardware signal inversions.
  *
  * Specifies whether the DAI can also support inverted clocks for the specified
@@ -96,6 +78,10 @@
 #define SND_SOC_CLOCK_IN		0
 #define SND_SOC_CLOCK_OUT		1
 
+#define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S16_LE |\
+                               SNDRV_PCM_FMTBIT_S32_LE |\
+                               SNDRV_PCM_FMTBIT_S32_BE)
+
 struct snd_soc_dai_ops;
 struct snd_soc_dai;
 struct snd_ac97_bus_ops;
@@ -208,6 +194,7 @@
 	/* DAI capabilities */
 	struct snd_soc_pcm_stream capture;
 	struct snd_soc_pcm_stream playback;
+	unsigned int symmetric_rates:1;
 
 	/* DAI runtime info */
 	struct snd_pcm_runtime *runtime;
@@ -219,11 +206,8 @@
 	/* DAI private data */
 	void *private_data;
 
-	/* parent codec/platform */
-	union {
-		struct snd_soc_codec *codec;
-		struct snd_soc_platform *platform;
-	};
+	/* parent platform */
+	struct snd_soc_platform *platform;
 
 	struct list_head list;
 };
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index a7def6a..ec8a45f 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -140,16 +140,30 @@
 #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
 {	.id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
 	.shift = wshift, .invert = winvert}
+#define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \
+			   wevent, wflags)				\
+{	.id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
+	.shift = wshift, .invert = winvert, \
+	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
 {	.id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
 	.shift = wshift, .invert = winvert}
+#define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \
+			   wevent, wflags)				\
+{	.id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
+	.shift = wshift, .invert = winvert, \
+	.event = wevent, .event_flags = wflags}
 
-/* generic register modifier widget */
+/* generic widgets */
 #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
 {	.id = wid, .name = wname, .kcontrols = NULL, .num_kcontrols = 0, \
 	.reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \
 	.on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
+#define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \
+{	.id = snd_soc_dapm_supply, .name = wname, .reg = wreg,	\
+	.shift = wshift, .invert = winvert, .event = wevent, \
+	.event_flags = wflags}
 
 /* dapm kcontrol types */
 #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
@@ -265,8 +279,6 @@
 /* dapm events */
 int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
 	int event);
-int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
-	enum snd_soc_bias_level level);
 
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);
@@ -298,6 +310,7 @@
 	snd_soc_dapm_vmid,			/* codec bias/vmid - to minimise pops */
 	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 */
 };
 
 /*
@@ -357,6 +370,8 @@
 	unsigned char suspend:1;		/* was active before suspend */
 	unsigned char pmdown:1;			/* waiting for timeout */
 
+	int (*power_check)(struct snd_soc_dapm_widget *w);
+
 	/* external events */
 	unsigned short event_flags;		/* flags to specify event types */
 	int (*event)(struct snd_soc_dapm_widget*, struct snd_kcontrol *, int);
@@ -368,6 +383,9 @@
 	/* widget input and outputs */
 	struct list_head sources;
 	struct list_head sinks;
+
+	/* used during DAPM updates */
+	struct list_head power_list;
 };
 
 #endif
diff --git a/include/sound/soc.h b/include/sound/soc.h
index a40bc6f..cf6111d 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -118,6 +118,14 @@
 	.info = snd_soc_info_volsw, \
 	.get = xhandler_get, .put = xhandler_put, \
 	.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
+#define SOC_DOUBLE_EXT(xname, xreg, shift_left, shift_right, xmax, xinvert,\
+	 xhandler_get, xhandler_put) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+	.info = snd_soc_info_volsw, \
+	.get = xhandler_get, .put = xhandler_put, \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = xreg, .shift = shift_left, .rshift = shift_right, \
+		 .max = xmax, .invert = xinvert} }
 #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
 	 xhandler_get, xhandler_put, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@@ -206,10 +214,6 @@
 			struct snd_soc_jack_gpio *gpios);
 #endif
 
-/* codec IO */
-#define snd_soc_read(codec, reg) codec->read(codec, reg)
-#define snd_soc_write(codec, reg, value) codec->write(codec, reg, value)
-
 /* codec register bit access */
 int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
 				unsigned short mask, unsigned short value);
@@ -331,6 +335,7 @@
 	struct module *owner;
 	struct mutex mutex;
 	struct device *dev;
+	struct snd_soc_device *socdev;
 
 	struct list_head list;
 
@@ -364,6 +369,8 @@
 	enum snd_soc_bias_level bias_level;
 	enum snd_soc_bias_level suspend_bias_level;
 	struct delayed_work delayed_work;
+	struct list_head up_list;
+	struct list_head down_list;
 
 	/* codec DAI's */
 	struct snd_soc_dai *dai;
@@ -417,6 +424,12 @@
 	/* codec/machine specific init - e.g. add machine controls */
 	int (*init)(struct snd_soc_codec *codec);
 
+	/* Symmetry requirements */
+	unsigned int symmetric_rates:1;
+
+	/* Symmetry data - only valid if symmetry is being enforced */
+	unsigned int rate;
+
 	/* DAI pcm */
 	struct snd_pcm *pcm;
 };
@@ -490,6 +503,19 @@
 	void *dapm;
 };
 
+/* codec IO */
+static inline unsigned int snd_soc_read(struct snd_soc_codec *codec,
+					unsigned int reg)
+{
+	return codec->read(codec, reg);
+}
+
+static inline unsigned int snd_soc_write(struct snd_soc_codec *codec,
+					 unsigned int reg, unsigned int val)
+{
+	return codec->write(codec, reg, val);
+}
+
 #include <sound/soc-dai.h>
 
 #endif
diff --git a/include/sound/wm9081.h b/include/sound/wm9081.h
new file mode 100644
index 0000000..e173ddb
--- /dev/null
+++ b/include/sound/wm9081.h
@@ -0,0 +1,25 @@
+/*
+ * linux/sound/wm9081.h -- Platform data for WM9081
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_SND_WM_9081_H
+#define __LINUX_SND_WM_9081_H
+
+struct wm9081_retune_mobile_setting {
+	const char *name;
+	unsigned int rate;
+	u16 config[20];
+};
+
+struct wm9081_retune_mobile_config {
+	struct wm9081_retune_mobile_setting *configs;
+	int num_configs;
+};
+
+#endif
diff --git a/include/video/pxa168fb.h b/include/video/pxa168fb.h
new file mode 100644
index 0000000..b5cc72f
--- /dev/null
+++ b/include/video/pxa168fb.h
@@ -0,0 +1,127 @@
+/*
+ * linux/arch/arm/mach-mmp/include/mach/pxa168fb.h
+ *
+ *  Copyright (C) 2009 Marvell International 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.
+ */
+
+#ifndef __ASM_MACH_PXA168FB_H
+#define __ASM_MACH_PXA168FB_H
+
+#include <linux/fb.h>
+#include <linux/interrupt.h>
+
+/* Dumb interface */
+#define PIN_MODE_DUMB_24		0
+#define PIN_MODE_DUMB_18_SPI		1
+#define PIN_MODE_DUMB_18_GPIO		2
+#define PIN_MODE_DUMB_16_SPI		3
+#define PIN_MODE_DUMB_16_GPIO		4
+#define PIN_MODE_DUMB_12_SPI_GPIO	5
+#define PIN_MODE_SMART_18_SPI		6
+#define PIN_MODE_SMART_16_SPI		7
+#define PIN_MODE_SMART_8_SPI_GPIO	8
+
+/* Dumb interface pin allocation */
+#define DUMB_MODE_RGB565		0
+#define DUMB_MODE_RGB565_UPPER		1
+#define DUMB_MODE_RGB666		2
+#define DUMB_MODE_RGB666_UPPER		3
+#define DUMB_MODE_RGB444		4
+#define DUMB_MODE_RGB444_UPPER		5
+#define DUMB_MODE_RGB888		6
+
+/* default fb buffer size WVGA-32bits */
+#define DEFAULT_FB_SIZE	(800 * 480 * 4)
+
+/*
+ * Buffer pixel format
+ * bit0 is for rb swap.
+ * bit12 is for Y UorV swap
+ */
+#define PIX_FMT_RGB565		0
+#define PIX_FMT_BGR565		1
+#define PIX_FMT_RGB1555		2
+#define PIX_FMT_BGR1555		3
+#define PIX_FMT_RGB888PACK	4
+#define PIX_FMT_BGR888PACK	5
+#define PIX_FMT_RGB888UNPACK	6
+#define PIX_FMT_BGR888UNPACK	7
+#define PIX_FMT_RGBA888		8
+#define PIX_FMT_BGRA888		9
+#define PIX_FMT_YUV422PACK	10
+#define PIX_FMT_YVU422PACK	11
+#define PIX_FMT_YUV422PLANAR	12
+#define PIX_FMT_YVU422PLANAR	13
+#define PIX_FMT_YUV420PLANAR	14
+#define PIX_FMT_YVU420PLANAR	15
+#define PIX_FMT_PSEUDOCOLOR	20
+#define PIX_FMT_UYVY422PACK	(0x1000|PIX_FMT_YUV422PACK)
+
+/*
+ * PXA LCD controller private state.
+ */
+struct pxa168fb_info {
+	struct device		*dev;
+	struct clk		*clk;
+	struct fb_info		*info;
+
+	void __iomem		*reg_base;
+	dma_addr_t		fb_start_dma;
+	u32			pseudo_palette[16];
+
+	int			pix_fmt;
+	unsigned		is_blanked:1;
+	unsigned		panel_rbswap:1;
+	unsigned		active:1;
+};
+
+/*
+ * PXA fb machine information
+ */
+struct pxa168fb_mach_info {
+	char	id[16];
+
+	int		num_modes;
+	struct fb_videomode *modes;
+
+	/*
+	 * Pix_fmt
+	 */
+	unsigned	pix_fmt;
+
+	/*
+	 * I/O pin allocation.
+	 */
+	unsigned	io_pin_allocation_mode:4;
+
+	/*
+	 * Dumb panel -- assignment of R/G/B component info to the 24
+	 * available external data lanes.
+	 */
+	unsigned	dumb_mode:4;
+	unsigned	panel_rgb_reverse_lanes:1;
+
+	/*
+	 * Dumb panel -- GPIO output data.
+	 */
+	unsigned	gpio_output_mask:8;
+	unsigned	gpio_output_data:8;
+
+	/*
+	 * Dumb panel -- configurable output signal polarity.
+	 */
+	unsigned	invert_composite_blank:1;
+	unsigned	invert_pix_val_ena:1;
+	unsigned	invert_pixclock:1;
+	unsigned	invert_vsync:1;
+	unsigned	invert_hsync:1;
+	unsigned	panel_rbswap:1;
+	unsigned	active:1;
+	unsigned	enable_lcd:1;
+};
+
+#endif /* __ASM_MACH_PXA168FB_H */
diff --git a/init/Kconfig b/init/Kconfig
index c649657..d3a5096 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -936,6 +936,8 @@
 
 config HAVE_PERF_COUNTERS
 	bool
+	help
+	  See tools/perf/design.txt for details.
 
 menu "Performance Counters"
 
diff --git a/init/main.c b/init/main.c
index 5616661..f6204f7 100644
--- a/init/main.c
+++ b/init/main.c
@@ -539,6 +539,11 @@
  */
 static void __init mm_init(void)
 {
+	/*
+	 * page_cgroup requires countinous pages as memmap
+	 * and it's bigger than MAX_ORDER unless SPARSEMEM.
+	 */
+	page_cgroup_init_flatmem();
 	mem_init();
 	kmem_cache_init();
 	vmalloc_init();
@@ -635,6 +640,7 @@
 				 "enabled early\n");
 	early_boot_irqs_on();
 	local_irq_enable();
+	kmem_cache_init_late();
 
 	/*
 	 * HACK ALERT! This is early. We're enabling the console before
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 1045785..065205b 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -45,7 +45,7 @@
 #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS)
 static void __init init_irq_default_affinity(void)
 {
-	alloc_bootmem_cpumask_var(&irq_default_affinity);
+	alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
 	cpumask_setall(irq_default_affinity);
 }
 #else
diff --git a/kernel/kexec.c b/kernel/kexec.c
index e498377..ae1c352 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -1448,17 +1448,17 @@
 			goto Restore_console;
 		}
 		suspend_console();
-		error = device_suspend(PMSG_FREEZE);
+		error = dpm_suspend_start(PMSG_FREEZE);
 		if (error)
 			goto Resume_console;
-		/* At this point, device_suspend() has been called,
-		 * but *not* device_power_down(). We *must*
-		 * device_power_down() now.  Otherwise, drivers for
+		/* At this point, dpm_suspend_start() has been called,
+		 * but *not* dpm_suspend_noirq(). We *must* call
+		 * dpm_suspend_noirq() now.  Otherwise, drivers for
 		 * some devices (e.g. interrupt controllers) become
 		 * desynchronized with the actual state of the
 		 * hardware at resume time, and evil weirdness ensues.
 		 */
-		error = device_power_down(PMSG_FREEZE);
+		error = dpm_suspend_noirq(PMSG_FREEZE);
 		if (error)
 			goto Resume_devices;
 		error = disable_nonboot_cpus();
@@ -1486,9 +1486,9 @@
 		local_irq_enable();
  Enable_cpus:
 		enable_nonboot_cpus();
-		device_power_up(PMSG_RESTORE);
+		dpm_resume_noirq(PMSG_RESTORE);
  Resume_devices:
-		device_resume(PMSG_RESTORE);
+		dpm_resume_end(PMSG_RESTORE);
  Resume_console:
 		resume_console();
 		thaw_processes();
diff --git a/kernel/module.c b/kernel/module.c
index 35f7de0..e4ab36c 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2455,6 +2455,7 @@
 	mutex_lock(&module_mutex);
 	/* Drop initial reference. */
 	module_put(mod);
+	trim_init_extable(mod);
 	module_free(mod, mod->module_init);
 	mod->module_init = NULL;
 	mod->init_size = 0;
diff --git a/kernel/params.c b/kernel/params.c
index de273ec..7f6912c 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -24,9 +24,6 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 
-/* We abuse the high bits of "perm" to record whether we kmalloc'ed. */
-#define KPARAM_KMALLOCED	0x80000000
-
 #if 0
 #define DEBUGP printk
 #else
@@ -220,13 +217,13 @@
 		return -ENOSPC;
 	}
 
-	if (kp->perm & KPARAM_KMALLOCED)
+	if (kp->flags & KPARAM_KMALLOCED)
 		kfree(*(char **)kp->arg);
 
 	/* This is a hack.  We can't need to strdup in early boot, and we
 	 * don't need to; this mangled commandline is preserved. */
 	if (slab_is_available()) {
-		kp->perm |= KPARAM_KMALLOCED;
+		kp->flags |= KPARAM_KMALLOCED;
 		*(char **)kp->arg = kstrdup(val, GFP_KERNEL);
 		if (!kp->arg)
 			return -ENOMEM;
@@ -241,44 +238,63 @@
 	return sprintf(buffer, "%s", *((char **)kp->arg));
 }
 
+/* Actually could be a bool or an int, for historical reasons. */
 int param_set_bool(const char *val, struct kernel_param *kp)
 {
+	bool v;
+
 	/* No equals means "set"... */
 	if (!val) val = "1";
 
 	/* One of =[yYnN01] */
 	switch (val[0]) {
 	case 'y': case 'Y': case '1':
-		*(int *)kp->arg = 1;
-		return 0;
+		v = true;
+		break;
 	case 'n': case 'N': case '0':
-		*(int *)kp->arg = 0;
-		return 0;
+		v = false;
+		break;
+	default:
+		return -EINVAL;
 	}
-	return -EINVAL;
+
+	if (kp->flags & KPARAM_ISBOOL)
+		*(bool *)kp->arg = v;
+	else
+		*(int *)kp->arg = v;
+	return 0;
 }
 
 int param_get_bool(char *buffer, 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", (*(int *)kp->arg) ? 'Y' : 'N');
+	return sprintf(buffer, "%c", val ? 'Y' : 'N');
 }
 
+/* This one must be bool. */
 int param_set_invbool(const char *val, struct kernel_param *kp)
 {
-	int boolval, ret;
+	int ret;
+	bool boolval;
 	struct kernel_param dummy;
 
 	dummy.arg = &boolval;
+	dummy.flags = KPARAM_ISBOOL;
 	ret = param_set_bool(val, &dummy);
 	if (ret == 0)
-		*(int *)kp->arg = !boolval;
+		*(bool *)kp->arg = !boolval;
 	return ret;
 }
 
 int param_get_invbool(char *buffer, struct kernel_param *kp)
 {
-	return sprintf(buffer, "%c", (*(int *)kp->arg) ? 'N' : 'Y');
+	return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y');
 }
 
 /* We break the rule and mangle the string. */
@@ -591,7 +607,7 @@
 	unsigned int i;
 
 	for (i = 0; i < num; i++)
-		if (params[i].perm & KPARAM_KMALLOCED)
+		if (params[i].flags & KPARAM_KMALLOCED)
 			kfree(*(char **)params[i].arg);
 }
 
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index ef5d8a5..29b685f 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -3570,12 +3570,8 @@
 	if (attr->inherit && (attr->sample_type & PERF_SAMPLE_GROUP))
 		goto done;
 
-	if (attr->type == PERF_TYPE_RAW) {
-		pmu = hw_perf_counter_init(counter);
-		goto done;
-	}
-
 	switch (attr->type) {
+	case PERF_TYPE_RAW:
 	case PERF_TYPE_HARDWARE:
 	case PERF_TYPE_HW_CACHE:
 		pmu = hw_perf_counter_init(counter);
@@ -3588,6 +3584,9 @@
 	case PERF_TYPE_TRACEPOINT:
 		pmu = tp_perf_counter_init(counter);
 		break;
+
+	default:
+		break;
 	}
 done:
 	err = 0;
@@ -3614,6 +3613,85 @@
 	return counter;
 }
 
+static int perf_copy_attr(struct perf_counter_attr __user *uattr,
+			  struct perf_counter_attr *attr)
+{
+	int ret;
+	u32 size;
+
+	if (!access_ok(VERIFY_WRITE, uattr, PERF_ATTR_SIZE_VER0))
+		return -EFAULT;
+
+	/*
+	 * zero the full structure, so that a short copy will be nice.
+	 */
+	memset(attr, 0, sizeof(*attr));
+
+	ret = get_user(size, &uattr->size);
+	if (ret)
+		return ret;
+
+	if (size > PAGE_SIZE)	/* silly large */
+		goto err_size;
+
+	if (!size)		/* abi compat */
+		size = PERF_ATTR_SIZE_VER0;
+
+	if (size < PERF_ATTR_SIZE_VER0)
+		goto err_size;
+
+	/*
+	 * If we're handed a bigger struct than we know of,
+	 * ensure all the unknown bits are 0.
+	 */
+	if (size > sizeof(*attr)) {
+		unsigned long val;
+		unsigned long __user *addr;
+		unsigned long __user *end;
+
+		addr = PTR_ALIGN((void __user *)uattr + sizeof(*attr),
+				sizeof(unsigned long));
+		end  = PTR_ALIGN((void __user *)uattr + size,
+				sizeof(unsigned long));
+
+		for (; addr < end; addr += sizeof(unsigned long)) {
+			ret = get_user(val, addr);
+			if (ret)
+				return ret;
+			if (val)
+				goto err_size;
+		}
+	}
+
+	ret = copy_from_user(attr, uattr, size);
+	if (ret)
+		return -EFAULT;
+
+	/*
+	 * If the type exists, the corresponding creation will verify
+	 * the attr->config.
+	 */
+	if (attr->type >= PERF_TYPE_MAX)
+		return -EINVAL;
+
+	if (attr->__reserved_1 || attr->__reserved_2 || attr->__reserved_3)
+		return -EINVAL;
+
+	if (attr->sample_type & ~(PERF_SAMPLE_MAX-1))
+		return -EINVAL;
+
+	if (attr->read_format & ~(PERF_FORMAT_MAX-1))
+		return -EINVAL;
+
+out:
+	return ret;
+
+err_size:
+	put_user(sizeof(*attr), &uattr->size);
+	ret = -E2BIG;
+	goto out;
+}
+
 /**
  * sys_perf_counter_open - open a performance counter, associate it to a task/cpu
  *
@@ -3623,7 +3701,7 @@
  * @group_fd:		group leader counter fd
  */
 SYSCALL_DEFINE5(perf_counter_open,
-		const struct perf_counter_attr __user *, attr_uptr,
+		struct perf_counter_attr __user *, attr_uptr,
 		pid_t, pid, int, cpu, int, group_fd, unsigned long, flags)
 {
 	struct perf_counter *counter, *group_leader;
@@ -3639,8 +3717,9 @@
 	if (flags)
 		return -EINVAL;
 
-	if (copy_from_user(&attr, attr_uptr, sizeof(attr)) != 0)
-		return -EFAULT;
+	ret = perf_copy_attr(attr_uptr, &attr);
+	if (ret)
+		return ret;
 
 	if (!attr.exclude_kernel) {
 		if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN))
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 23bd4da..72067cb 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -116,9 +116,13 @@
 
 	  Turning OFF this setting is NOT recommended! If in doubt, say Y.
 
+config HIBERNATION_NVS
+	bool
+
 config HIBERNATION
 	bool "Hibernation (aka 'suspend to disk')"
 	depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
+	select HIBERNATION_NVS if HAS_IOMEM
 	---help---
 	  Enable the suspend to disk (STD) functionality, which is usually
 	  called "hibernation" in user interfaces.  STD checkpoints the
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 720ea4f..c3b81c3 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -6,6 +6,9 @@
 obj-$(CONFIG_PM)		+= main.o
 obj-$(CONFIG_PM_SLEEP)		+= console.o
 obj-$(CONFIG_FREEZER)		+= process.o
-obj-$(CONFIG_HIBERNATION)	+= swsusp.o disk.o snapshot.o swap.o user.o
+obj-$(CONFIG_SUSPEND)		+= suspend.o
+obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
+obj-$(CONFIG_HIBERNATION)	+= swsusp.o hibernate.o snapshot.o swap.o user.o
+obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
deleted file mode 100644
index 5cb080e..0000000
--- a/kernel/power/disk.c
+++ /dev/null
@@ -1,955 +0,0 @@
-/*
- * kernel/power/disk.c - Suspend-to-disk support.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Lab
- * Copyright (c) 2004 Pavel Machek <pavel@suse.cz>
- *
- * This file is released under the GPLv2.
- *
- */
-
-#include <linux/suspend.h>
-#include <linux/syscalls.h>
-#include <linux/reboot.h>
-#include <linux/string.h>
-#include <linux/device.h>
-#include <linux/kmod.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/pm.h>
-#include <linux/console.h>
-#include <linux/cpu.h>
-#include <linux/freezer.h>
-#include <scsi/scsi_scan.h>
-#include <asm/suspend.h>
-
-#include "power.h"
-
-
-static int noresume = 0;
-static char resume_file[256] = CONFIG_PM_STD_PARTITION;
-dev_t swsusp_resume_device;
-sector_t swsusp_resume_block;
-
-enum {
-	HIBERNATION_INVALID,
-	HIBERNATION_PLATFORM,
-	HIBERNATION_TEST,
-	HIBERNATION_TESTPROC,
-	HIBERNATION_SHUTDOWN,
-	HIBERNATION_REBOOT,
-	/* keep last */
-	__HIBERNATION_AFTER_LAST
-};
-#define HIBERNATION_MAX (__HIBERNATION_AFTER_LAST-1)
-#define HIBERNATION_FIRST (HIBERNATION_INVALID + 1)
-
-static int hibernation_mode = HIBERNATION_SHUTDOWN;
-
-static struct platform_hibernation_ops *hibernation_ops;
-
-/**
- * hibernation_set_ops - set the global hibernate operations
- * @ops: the hibernation operations to use in subsequent hibernation transitions
- */
-
-void hibernation_set_ops(struct platform_hibernation_ops *ops)
-{
-	if (ops && !(ops->begin && ops->end &&  ops->pre_snapshot
-	    && ops->prepare && ops->finish && ops->enter && ops->pre_restore
-	    && ops->restore_cleanup)) {
-		WARN_ON(1);
-		return;
-	}
-	mutex_lock(&pm_mutex);
-	hibernation_ops = ops;
-	if (ops)
-		hibernation_mode = HIBERNATION_PLATFORM;
-	else if (hibernation_mode == HIBERNATION_PLATFORM)
-		hibernation_mode = HIBERNATION_SHUTDOWN;
-
-	mutex_unlock(&pm_mutex);
-}
-
-static bool entering_platform_hibernation;
-
-bool system_entering_hibernation(void)
-{
-	return entering_platform_hibernation;
-}
-EXPORT_SYMBOL(system_entering_hibernation);
-
-#ifdef CONFIG_PM_DEBUG
-static void hibernation_debug_sleep(void)
-{
-	printk(KERN_INFO "hibernation debug: Waiting for 5 seconds.\n");
-	mdelay(5000);
-}
-
-static int hibernation_testmode(int mode)
-{
-	if (hibernation_mode == mode) {
-		hibernation_debug_sleep();
-		return 1;
-	}
-	return 0;
-}
-
-static int hibernation_test(int level)
-{
-	if (pm_test_level == level) {
-		hibernation_debug_sleep();
-		return 1;
-	}
-	return 0;
-}
-#else /* !CONFIG_PM_DEBUG */
-static int hibernation_testmode(int mode) { return 0; }
-static int hibernation_test(int level) { return 0; }
-#endif /* !CONFIG_PM_DEBUG */
-
-/**
- *	platform_begin - tell the platform driver that we're starting
- *	hibernation
- */
-
-static int platform_begin(int platform_mode)
-{
-	return (platform_mode && hibernation_ops) ?
-		hibernation_ops->begin() : 0;
-}
-
-/**
- *	platform_end - tell the platform driver that we've entered the
- *	working state
- */
-
-static void platform_end(int platform_mode)
-{
-	if (platform_mode && hibernation_ops)
-		hibernation_ops->end();
-}
-
-/**
- *	platform_pre_snapshot - prepare the machine for hibernation using the
- *	platform driver if so configured and return an error code if it fails
- */
-
-static int platform_pre_snapshot(int platform_mode)
-{
-	return (platform_mode && hibernation_ops) ?
-		hibernation_ops->pre_snapshot() : 0;
-}
-
-/**
- *	platform_leave - prepare the machine for switching to the normal mode
- *	of operation using the platform driver (called with interrupts disabled)
- */
-
-static void platform_leave(int platform_mode)
-{
-	if (platform_mode && hibernation_ops)
-		hibernation_ops->leave();
-}
-
-/**
- *	platform_finish - switch the machine to the normal mode of operation
- *	using the platform driver (must be called after platform_prepare())
- */
-
-static void platform_finish(int platform_mode)
-{
-	if (platform_mode && hibernation_ops)
-		hibernation_ops->finish();
-}
-
-/**
- *	platform_pre_restore - prepare the platform for the restoration from a
- *	hibernation image.  If the restore fails after this function has been
- *	called, platform_restore_cleanup() must be called.
- */
-
-static int platform_pre_restore(int platform_mode)
-{
-	return (platform_mode && hibernation_ops) ?
-		hibernation_ops->pre_restore() : 0;
-}
-
-/**
- *	platform_restore_cleanup - switch the platform to the normal mode of
- *	operation after a failing restore.  If platform_pre_restore() has been
- *	called before the failing restore, this function must be called too,
- *	regardless of the result of platform_pre_restore().
- */
-
-static void platform_restore_cleanup(int platform_mode)
-{
-	if (platform_mode && hibernation_ops)
-		hibernation_ops->restore_cleanup();
-}
-
-/**
- *	platform_recover - recover the platform from a failure to suspend
- *	devices.
- */
-
-static void platform_recover(int platform_mode)
-{
-	if (platform_mode && hibernation_ops && hibernation_ops->recover)
-		hibernation_ops->recover();
-}
-
-/**
- *	create_image - freeze devices that need to be frozen with interrupts
- *	off, create the hibernation image and thaw those devices.  Control
- *	reappears in this routine after a restore.
- */
-
-static int create_image(int platform_mode)
-{
-	int error;
-
-	error = arch_prepare_suspend();
-	if (error)
-		return error;
-
-	/* At this point, device_suspend() has been called, but *not*
-	 * device_power_down(). We *must* call device_power_down() now.
-	 * Otherwise, drivers for some devices (e.g. interrupt controllers)
-	 * become desynchronized with the actual state of the hardware
-	 * at resume time, and evil weirdness ensues.
-	 */
-	error = device_power_down(PMSG_FREEZE);
-	if (error) {
-		printk(KERN_ERR "PM: Some devices failed to power down, "
-			"aborting hibernation\n");
-		return error;
-	}
-
-	error = platform_pre_snapshot(platform_mode);
-	if (error || hibernation_test(TEST_PLATFORM))
-		goto Platform_finish;
-
-	error = disable_nonboot_cpus();
-	if (error || hibernation_test(TEST_CPUS)
-	    || hibernation_testmode(HIBERNATION_TEST))
-		goto Enable_cpus;
-
-	local_irq_disable();
-
-	error = sysdev_suspend(PMSG_FREEZE);
-	if (error) {
-		printk(KERN_ERR "PM: Some system devices failed to power down, "
-			"aborting hibernation\n");
-		goto Enable_irqs;
-	}
-
-	if (hibernation_test(TEST_CORE))
-		goto Power_up;
-
-	in_suspend = 1;
-	save_processor_state();
-	error = swsusp_arch_suspend();
-	if (error)
-		printk(KERN_ERR "PM: Error %d creating hibernation image\n",
-			error);
-	/* Restore control flow magically appears here */
-	restore_processor_state();
-	if (!in_suspend)
-		platform_leave(platform_mode);
-
- Power_up:
-	sysdev_resume();
-	/* NOTE:  device_power_up() is just a resume() for devices
-	 * that suspended with irqs off ... no overall powerup.
-	 */
-
- Enable_irqs:
-	local_irq_enable();
-
- Enable_cpus:
-	enable_nonboot_cpus();
-
- Platform_finish:
-	platform_finish(platform_mode);
-
-	device_power_up(in_suspend ?
-		(error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
-
-	return error;
-}
-
-/**
- *	hibernation_snapshot - quiesce devices and create the hibernation
- *	snapshot image.
- *	@platform_mode - if set, use the platform driver, if available, to
- *			 prepare the platform firmware for the power transition.
- *
- *	Must be called with pm_mutex held
- */
-
-int hibernation_snapshot(int platform_mode)
-{
-	int error;
-
-	error = platform_begin(platform_mode);
-	if (error)
-		return error;
-
-	/* Free memory before shutting down devices. */
-	error = swsusp_shrink_memory();
-	if (error)
-		goto Close;
-
-	suspend_console();
-	error = device_suspend(PMSG_FREEZE);
-	if (error)
-		goto Recover_platform;
-
-	if (hibernation_test(TEST_DEVICES))
-		goto Recover_platform;
-
-	error = create_image(platform_mode);
-	/* Control returns here after successful restore */
-
- Resume_devices:
-	device_resume(in_suspend ?
-		(error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
-	resume_console();
- Close:
-	platform_end(platform_mode);
-	return error;
-
- Recover_platform:
-	platform_recover(platform_mode);
-	goto Resume_devices;
-}
-
-/**
- *	resume_target_kernel - prepare devices that need to be suspended with
- *	interrupts off, restore the contents of highmem that have not been
- *	restored yet from the image and run the low level code that will restore
- *	the remaining contents of memory and switch to the just restored target
- *	kernel.
- */
-
-static int resume_target_kernel(bool platform_mode)
-{
-	int error;
-
-	error = device_power_down(PMSG_QUIESCE);
-	if (error) {
-		printk(KERN_ERR "PM: Some devices failed to power down, "
-			"aborting resume\n");
-		return error;
-	}
-
-	error = platform_pre_restore(platform_mode);
-	if (error)
-		goto Cleanup;
-
-	error = disable_nonboot_cpus();
-	if (error)
-		goto Enable_cpus;
-
-	local_irq_disable();
-
-	error = sysdev_suspend(PMSG_QUIESCE);
-	if (error)
-		goto Enable_irqs;
-
-	/* We'll ignore saved state, but this gets preempt count (etc) right */
-	save_processor_state();
-	error = restore_highmem();
-	if (!error) {
-		error = swsusp_arch_resume();
-		/*
-		 * The code below is only ever reached in case of a failure.
-		 * Otherwise execution continues at place where
-		 * swsusp_arch_suspend() was called
-		 */
-		BUG_ON(!error);
-		/* This call to restore_highmem() undos the previous one */
-		restore_highmem();
-	}
-	/*
-	 * The only reason why swsusp_arch_resume() can fail is memory being
-	 * very tight, so we have to free it as soon as we can to avoid
-	 * subsequent failures
-	 */
-	swsusp_free();
-	restore_processor_state();
-	touch_softlockup_watchdog();
-
-	sysdev_resume();
-
- Enable_irqs:
-	local_irq_enable();
-
- Enable_cpus:
-	enable_nonboot_cpus();
-
- Cleanup:
-	platform_restore_cleanup(platform_mode);
-
-	device_power_up(PMSG_RECOVER);
-
-	return error;
-}
-
-/**
- *	hibernation_restore - quiesce devices and restore the hibernation
- *	snapshot image.  If successful, control returns in hibernation_snaphot()
- *	@platform_mode - if set, use the platform driver, if available, to
- *			 prepare the platform firmware for the transition.
- *
- *	Must be called with pm_mutex held
- */
-
-int hibernation_restore(int platform_mode)
-{
-	int error;
-
-	pm_prepare_console();
-	suspend_console();
-	error = device_suspend(PMSG_QUIESCE);
-	if (!error) {
-		error = resume_target_kernel(platform_mode);
-		device_resume(PMSG_RECOVER);
-	}
-	resume_console();
-	pm_restore_console();
-	return error;
-}
-
-/**
- *	hibernation_platform_enter - enter the hibernation state using the
- *	platform driver (if available)
- */
-
-int hibernation_platform_enter(void)
-{
-	int error;
-
-	if (!hibernation_ops)
-		return -ENOSYS;
-
-	/*
-	 * We have cancelled the power transition by running
-	 * hibernation_ops->finish() before saving the image, so we should let
-	 * the firmware know that we're going to enter the sleep state after all
-	 */
-	error = hibernation_ops->begin();
-	if (error)
-		goto Close;
-
-	entering_platform_hibernation = true;
-	suspend_console();
-	error = device_suspend(PMSG_HIBERNATE);
-	if (error) {
-		if (hibernation_ops->recover)
-			hibernation_ops->recover();
-		goto Resume_devices;
-	}
-
-	error = device_power_down(PMSG_HIBERNATE);
-	if (error)
-		goto Resume_devices;
-
-	error = hibernation_ops->prepare();
-	if (error)
-		goto Platofrm_finish;
-
-	error = disable_nonboot_cpus();
-	if (error)
-		goto Platofrm_finish;
-
-	local_irq_disable();
-	sysdev_suspend(PMSG_HIBERNATE);
-	hibernation_ops->enter();
-	/* We should never get here */
-	while (1);
-
-	/*
-	 * We don't need to reenable the nonboot CPUs or resume consoles, since
-	 * the system is going to be halted anyway.
-	 */
- Platofrm_finish:
-	hibernation_ops->finish();
-
-	device_power_up(PMSG_RESTORE);
-
- Resume_devices:
-	entering_platform_hibernation = false;
-	device_resume(PMSG_RESTORE);
-	resume_console();
-
- Close:
-	hibernation_ops->end();
-
-	return error;
-}
-
-/**
- *	power_down - Shut the machine down for hibernation.
- *
- *	Use the platform driver, if configured so; otherwise try
- *	to power off or reboot.
- */
-
-static void power_down(void)
-{
-	switch (hibernation_mode) {
-	case HIBERNATION_TEST:
-	case HIBERNATION_TESTPROC:
-		break;
-	case HIBERNATION_REBOOT:
-		kernel_restart(NULL);
-		break;
-	case HIBERNATION_PLATFORM:
-		hibernation_platform_enter();
-	case HIBERNATION_SHUTDOWN:
-		kernel_power_off();
-		break;
-	}
-	kernel_halt();
-	/*
-	 * Valid image is on the disk, if we continue we risk serious data
-	 * corruption after resume.
-	 */
-	printk(KERN_CRIT "PM: Please power down manually\n");
-	while(1);
-}
-
-static int prepare_processes(void)
-{
-	int error = 0;
-
-	if (freeze_processes()) {
-		error = -EBUSY;
-		thaw_processes();
-	}
-	return error;
-}
-
-/**
- *	hibernate - The granpappy of the built-in hibernation management
- */
-
-int hibernate(void)
-{
-	int error;
-
-	mutex_lock(&pm_mutex);
-	/* The snapshot device should not be opened while we're running */
-	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
-		error = -EBUSY;
-		goto Unlock;
-	}
-
-	pm_prepare_console();
-	error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
-	if (error)
-		goto Exit;
-
-	error = usermodehelper_disable();
-	if (error)
-		goto Exit;
-
-	/* Allocate memory management structures */
-	error = create_basic_memory_bitmaps();
-	if (error)
-		goto Exit;
-
-	printk(KERN_INFO "PM: Syncing filesystems ... ");
-	sys_sync();
-	printk("done.\n");
-
-	error = prepare_processes();
-	if (error)
-		goto Finish;
-
-	if (hibernation_test(TEST_FREEZER))
-		goto Thaw;
-
-	if (hibernation_testmode(HIBERNATION_TESTPROC))
-		goto Thaw;
-
-	error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
-	if (in_suspend && !error) {
-		unsigned int flags = 0;
-
-		if (hibernation_mode == HIBERNATION_PLATFORM)
-			flags |= SF_PLATFORM_MODE;
-		pr_debug("PM: writing image.\n");
-		error = swsusp_write(flags);
-		swsusp_free();
-		if (!error)
-			power_down();
-	} else {
-		pr_debug("PM: Image restored successfully.\n");
-		swsusp_free();
-	}
- Thaw:
-	thaw_processes();
- Finish:
-	free_basic_memory_bitmaps();
-	usermodehelper_enable();
- Exit:
-	pm_notifier_call_chain(PM_POST_HIBERNATION);
-	pm_restore_console();
-	atomic_inc(&snapshot_device_available);
- Unlock:
-	mutex_unlock(&pm_mutex);
-	return error;
-}
-
-
-/**
- *	software_resume - Resume from a saved image.
- *
- *	Called as a late_initcall (so all devices are discovered and
- *	initialized), we call swsusp to see if we have a saved image or not.
- *	If so, we quiesce devices, the restore the saved image. We will
- *	return above (in hibernate() ) if everything goes well.
- *	Otherwise, we fail gracefully and return to the normally
- *	scheduled program.
- *
- */
-
-static int software_resume(void)
-{
-	int error;
-	unsigned int flags;
-
-	/*
-	 * If the user said "noresume".. bail out early.
-	 */
-	if (noresume)
-		return 0;
-
-	/*
-	 * name_to_dev_t() below takes a sysfs buffer mutex when sysfs
-	 * is configured into the kernel. Since the regular hibernate
-	 * trigger path is via sysfs which takes a buffer mutex before
-	 * calling hibernate functions (which take pm_mutex) this can
-	 * cause lockdep to complain about a possible ABBA deadlock
-	 * which cannot happen since we're in the boot code here and
-	 * sysfs can't be invoked yet. Therefore, we use a subclass
-	 * here to avoid lockdep complaining.
-	 */
-	mutex_lock_nested(&pm_mutex, SINGLE_DEPTH_NESTING);
-
-	if (swsusp_resume_device)
-		goto Check_image;
-
-	if (!strlen(resume_file)) {
-		error = -ENOENT;
-		goto Unlock;
-	}
-
-	pr_debug("PM: Checking image partition %s\n", resume_file);
-
-	/* Check if the device is there */
-	swsusp_resume_device = name_to_dev_t(resume_file);
-	if (!swsusp_resume_device) {
-		/*
-		 * Some device discovery might still be in progress; we need
-		 * to wait for this to finish.
-		 */
-		wait_for_device_probe();
-		/*
-		 * We can't depend on SCSI devices being available after loading
-		 * one of their modules until scsi_complete_async_scans() is
-		 * called and the resume device usually is a SCSI one.
-		 */
-		scsi_complete_async_scans();
-
-		swsusp_resume_device = name_to_dev_t(resume_file);
-		if (!swsusp_resume_device) {
-			error = -ENODEV;
-			goto Unlock;
-		}
-	}
-
- Check_image:
-	pr_debug("PM: Resume from partition %d:%d\n",
-		MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
-
-	pr_debug("PM: Checking hibernation image.\n");
-	error = swsusp_check();
-	if (error)
-		goto Unlock;
-
-	/* The snapshot device should not be opened while we're running */
-	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
-		error = -EBUSY;
-		goto Unlock;
-	}
-
-	pm_prepare_console();
-	error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
-	if (error)
-		goto Finish;
-
-	error = usermodehelper_disable();
-	if (error)
-		goto Finish;
-
-	error = create_basic_memory_bitmaps();
-	if (error)
-		goto Finish;
-
-	pr_debug("PM: Preparing processes for restore.\n");
-	error = prepare_processes();
-	if (error) {
-		swsusp_close(FMODE_READ);
-		goto Done;
-	}
-
-	pr_debug("PM: Reading hibernation image.\n");
-
-	error = swsusp_read(&flags);
-	if (!error)
-		hibernation_restore(flags & SF_PLATFORM_MODE);
-
-	printk(KERN_ERR "PM: Restore failed, recovering.\n");
-	swsusp_free();
-	thaw_processes();
- Done:
-	free_basic_memory_bitmaps();
-	usermodehelper_enable();
- Finish:
-	pm_notifier_call_chain(PM_POST_RESTORE);
-	pm_restore_console();
-	atomic_inc(&snapshot_device_available);
-	/* For success case, the suspend path will release the lock */
- Unlock:
-	mutex_unlock(&pm_mutex);
-	pr_debug("PM: Resume from disk failed.\n");
-	return error;
-}
-
-late_initcall(software_resume);
-
-
-static const char * const hibernation_modes[] = {
-	[HIBERNATION_PLATFORM]	= "platform",
-	[HIBERNATION_SHUTDOWN]	= "shutdown",
-	[HIBERNATION_REBOOT]	= "reboot",
-	[HIBERNATION_TEST]	= "test",
-	[HIBERNATION_TESTPROC]	= "testproc",
-};
-
-/**
- *	disk - Control hibernation mode
- *
- *	Suspend-to-disk can be handled in several ways. We have a few options
- *	for putting the system to sleep - using the platform driver (e.g. ACPI
- *	or other hibernation_ops), powering off the system or rebooting the
- *	system (for testing) as well as the two test modes.
- *
- *	The system can support 'platform', and that is known a priori (and
- *	encoded by the presence of hibernation_ops). However, the user may
- *	choose 'shutdown' or 'reboot' as alternatives, as well as one fo the
- *	test modes, 'test' or 'testproc'.
- *
- *	show() will display what the mode is currently set to.
- *	store() will accept one of
- *
- *	'platform'
- *	'shutdown'
- *	'reboot'
- *	'test'
- *	'testproc'
- *
- *	It will only change to 'platform' if the system
- *	supports it (as determined by having hibernation_ops).
- */
-
-static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
-			 char *buf)
-{
-	int i;
-	char *start = buf;
-
-	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
-		if (!hibernation_modes[i])
-			continue;
-		switch (i) {
-		case HIBERNATION_SHUTDOWN:
-		case HIBERNATION_REBOOT:
-		case HIBERNATION_TEST:
-		case HIBERNATION_TESTPROC:
-			break;
-		case HIBERNATION_PLATFORM:
-			if (hibernation_ops)
-				break;
-			/* not a valid mode, continue with loop */
-			continue;
-		}
-		if (i == hibernation_mode)
-			buf += sprintf(buf, "[%s] ", hibernation_modes[i]);
-		else
-			buf += sprintf(buf, "%s ", hibernation_modes[i]);
-	}
-	buf += sprintf(buf, "\n");
-	return buf-start;
-}
-
-
-static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
-			  const char *buf, size_t n)
-{
-	int error = 0;
-	int i;
-	int len;
-	char *p;
-	int mode = HIBERNATION_INVALID;
-
-	p = memchr(buf, '\n', n);
-	len = p ? p - buf : n;
-
-	mutex_lock(&pm_mutex);
-	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
-		if (len == strlen(hibernation_modes[i])
-		    && !strncmp(buf, hibernation_modes[i], len)) {
-			mode = i;
-			break;
-		}
-	}
-	if (mode != HIBERNATION_INVALID) {
-		switch (mode) {
-		case HIBERNATION_SHUTDOWN:
-		case HIBERNATION_REBOOT:
-		case HIBERNATION_TEST:
-		case HIBERNATION_TESTPROC:
-			hibernation_mode = mode;
-			break;
-		case HIBERNATION_PLATFORM:
-			if (hibernation_ops)
-				hibernation_mode = mode;
-			else
-				error = -EINVAL;
-		}
-	} else
-		error = -EINVAL;
-
-	if (!error)
-		pr_debug("PM: Hibernation mode set to '%s'\n",
-			 hibernation_modes[mode]);
-	mutex_unlock(&pm_mutex);
-	return error ? error : n;
-}
-
-power_attr(disk);
-
-static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
-			   char *buf)
-{
-	return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device),
-		       MINOR(swsusp_resume_device));
-}
-
-static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
-			    const char *buf, size_t n)
-{
-	unsigned int maj, min;
-	dev_t res;
-	int ret = -EINVAL;
-
-	if (sscanf(buf, "%u:%u", &maj, &min) != 2)
-		goto out;
-
-	res = MKDEV(maj,min);
-	if (maj != MAJOR(res) || min != MINOR(res))
-		goto out;
-
-	mutex_lock(&pm_mutex);
-	swsusp_resume_device = res;
-	mutex_unlock(&pm_mutex);
-	printk(KERN_INFO "PM: Starting manual resume from disk\n");
-	noresume = 0;
-	software_resume();
-	ret = n;
- out:
-	return ret;
-}
-
-power_attr(resume);
-
-static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr,
-			       char *buf)
-{
-	return sprintf(buf, "%lu\n", image_size);
-}
-
-static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr,
-				const char *buf, size_t n)
-{
-	unsigned long size;
-
-	if (sscanf(buf, "%lu", &size) == 1) {
-		image_size = size;
-		return n;
-	}
-
-	return -EINVAL;
-}
-
-power_attr(image_size);
-
-static struct attribute * g[] = {
-	&disk_attr.attr,
-	&resume_attr.attr,
-	&image_size_attr.attr,
-	NULL,
-};
-
-
-static struct attribute_group attr_group = {
-	.attrs = g,
-};
-
-
-static int __init pm_disk_init(void)
-{
-	return sysfs_create_group(power_kobj, &attr_group);
-}
-
-core_initcall(pm_disk_init);
-
-
-static int __init resume_setup(char *str)
-{
-	if (noresume)
-		return 1;
-
-	strncpy( resume_file, str, 255 );
-	return 1;
-}
-
-static int __init resume_offset_setup(char *str)
-{
-	unsigned long long offset;
-
-	if (noresume)
-		return 1;
-
-	if (sscanf(str, "%llu", &offset) == 1)
-		swsusp_resume_block = offset;
-
-	return 1;
-}
-
-static int __init noresume_setup(char *str)
-{
-	noresume = 1;
-	return 1;
-}
-
-__setup("noresume", noresume_setup);
-__setup("resume_offset=", resume_offset_setup);
-__setup("resume=", resume_setup);
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
new file mode 100644
index 0000000..81d2e74
--- /dev/null
+++ b/kernel/power/hibernate.c
@@ -0,0 +1,955 @@
+/*
+ * kernel/power/hibernate.c - Hibernation (a.k.a suspend-to-disk) support.
+ *
+ * Copyright (c) 2003 Patrick Mochel
+ * Copyright (c) 2003 Open Source Development Lab
+ * Copyright (c) 2004 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/suspend.h>
+#include <linux/syscalls.h>
+#include <linux/reboot.h>
+#include <linux/string.h>
+#include <linux/device.h>
+#include <linux/kmod.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/pm.h>
+#include <linux/console.h>
+#include <linux/cpu.h>
+#include <linux/freezer.h>
+#include <scsi/scsi_scan.h>
+#include <asm/suspend.h>
+
+#include "power.h"
+
+
+static int noresume = 0;
+static char resume_file[256] = CONFIG_PM_STD_PARTITION;
+dev_t swsusp_resume_device;
+sector_t swsusp_resume_block;
+
+enum {
+	HIBERNATION_INVALID,
+	HIBERNATION_PLATFORM,
+	HIBERNATION_TEST,
+	HIBERNATION_TESTPROC,
+	HIBERNATION_SHUTDOWN,
+	HIBERNATION_REBOOT,
+	/* keep last */
+	__HIBERNATION_AFTER_LAST
+};
+#define HIBERNATION_MAX (__HIBERNATION_AFTER_LAST-1)
+#define HIBERNATION_FIRST (HIBERNATION_INVALID + 1)
+
+static int hibernation_mode = HIBERNATION_SHUTDOWN;
+
+static struct platform_hibernation_ops *hibernation_ops;
+
+/**
+ * hibernation_set_ops - set the global hibernate operations
+ * @ops: the hibernation operations to use in subsequent hibernation transitions
+ */
+
+void hibernation_set_ops(struct platform_hibernation_ops *ops)
+{
+	if (ops && !(ops->begin && ops->end &&  ops->pre_snapshot
+	    && ops->prepare && ops->finish && ops->enter && ops->pre_restore
+	    && ops->restore_cleanup)) {
+		WARN_ON(1);
+		return;
+	}
+	mutex_lock(&pm_mutex);
+	hibernation_ops = ops;
+	if (ops)
+		hibernation_mode = HIBERNATION_PLATFORM;
+	else if (hibernation_mode == HIBERNATION_PLATFORM)
+		hibernation_mode = HIBERNATION_SHUTDOWN;
+
+	mutex_unlock(&pm_mutex);
+}
+
+static bool entering_platform_hibernation;
+
+bool system_entering_hibernation(void)
+{
+	return entering_platform_hibernation;
+}
+EXPORT_SYMBOL(system_entering_hibernation);
+
+#ifdef CONFIG_PM_DEBUG
+static void hibernation_debug_sleep(void)
+{
+	printk(KERN_INFO "hibernation debug: Waiting for 5 seconds.\n");
+	mdelay(5000);
+}
+
+static int hibernation_testmode(int mode)
+{
+	if (hibernation_mode == mode) {
+		hibernation_debug_sleep();
+		return 1;
+	}
+	return 0;
+}
+
+static int hibernation_test(int level)
+{
+	if (pm_test_level == level) {
+		hibernation_debug_sleep();
+		return 1;
+	}
+	return 0;
+}
+#else /* !CONFIG_PM_DEBUG */
+static int hibernation_testmode(int mode) { return 0; }
+static int hibernation_test(int level) { return 0; }
+#endif /* !CONFIG_PM_DEBUG */
+
+/**
+ *	platform_begin - tell the platform driver that we're starting
+ *	hibernation
+ */
+
+static int platform_begin(int platform_mode)
+{
+	return (platform_mode && hibernation_ops) ?
+		hibernation_ops->begin() : 0;
+}
+
+/**
+ *	platform_end - tell the platform driver that we've entered the
+ *	working state
+ */
+
+static void platform_end(int platform_mode)
+{
+	if (platform_mode && hibernation_ops)
+		hibernation_ops->end();
+}
+
+/**
+ *	platform_pre_snapshot - prepare the machine for hibernation using the
+ *	platform driver if so configured and return an error code if it fails
+ */
+
+static int platform_pre_snapshot(int platform_mode)
+{
+	return (platform_mode && hibernation_ops) ?
+		hibernation_ops->pre_snapshot() : 0;
+}
+
+/**
+ *	platform_leave - prepare the machine for switching to the normal mode
+ *	of operation using the platform driver (called with interrupts disabled)
+ */
+
+static void platform_leave(int platform_mode)
+{
+	if (platform_mode && hibernation_ops)
+		hibernation_ops->leave();
+}
+
+/**
+ *	platform_finish - switch the machine to the normal mode of operation
+ *	using the platform driver (must be called after platform_prepare())
+ */
+
+static void platform_finish(int platform_mode)
+{
+	if (platform_mode && hibernation_ops)
+		hibernation_ops->finish();
+}
+
+/**
+ *	platform_pre_restore - prepare the platform for the restoration from a
+ *	hibernation image.  If the restore fails after this function has been
+ *	called, platform_restore_cleanup() must be called.
+ */
+
+static int platform_pre_restore(int platform_mode)
+{
+	return (platform_mode && hibernation_ops) ?
+		hibernation_ops->pre_restore() : 0;
+}
+
+/**
+ *	platform_restore_cleanup - switch the platform to the normal mode of
+ *	operation after a failing restore.  If platform_pre_restore() has been
+ *	called before the failing restore, this function must be called too,
+ *	regardless of the result of platform_pre_restore().
+ */
+
+static void platform_restore_cleanup(int platform_mode)
+{
+	if (platform_mode && hibernation_ops)
+		hibernation_ops->restore_cleanup();
+}
+
+/**
+ *	platform_recover - recover the platform from a failure to suspend
+ *	devices.
+ */
+
+static void platform_recover(int platform_mode)
+{
+	if (platform_mode && hibernation_ops && hibernation_ops->recover)
+		hibernation_ops->recover();
+}
+
+/**
+ *	create_image - freeze devices that need to be frozen with interrupts
+ *	off, create the hibernation image and thaw those devices.  Control
+ *	reappears in this routine after a restore.
+ */
+
+static int create_image(int platform_mode)
+{
+	int error;
+
+	error = arch_prepare_suspend();
+	if (error)
+		return error;
+
+	/* At this point, dpm_suspend_start() has been called, but *not*
+	 * dpm_suspend_noirq(). We *must* call dpm_suspend_noirq() now.
+	 * Otherwise, drivers for some devices (e.g. interrupt controllers)
+	 * become desynchronized with the actual state of the hardware
+	 * at resume time, and evil weirdness ensues.
+	 */
+	error = dpm_suspend_noirq(PMSG_FREEZE);
+	if (error) {
+		printk(KERN_ERR "PM: Some devices failed to power down, "
+			"aborting hibernation\n");
+		return error;
+	}
+
+	error = platform_pre_snapshot(platform_mode);
+	if (error || hibernation_test(TEST_PLATFORM))
+		goto Platform_finish;
+
+	error = disable_nonboot_cpus();
+	if (error || hibernation_test(TEST_CPUS)
+	    || hibernation_testmode(HIBERNATION_TEST))
+		goto Enable_cpus;
+
+	local_irq_disable();
+
+	error = sysdev_suspend(PMSG_FREEZE);
+	if (error) {
+		printk(KERN_ERR "PM: Some system devices failed to power down, "
+			"aborting hibernation\n");
+		goto Enable_irqs;
+	}
+
+	if (hibernation_test(TEST_CORE))
+		goto Power_up;
+
+	in_suspend = 1;
+	save_processor_state();
+	error = swsusp_arch_suspend();
+	if (error)
+		printk(KERN_ERR "PM: Error %d creating hibernation image\n",
+			error);
+	/* Restore control flow magically appears here */
+	restore_processor_state();
+	if (!in_suspend)
+		platform_leave(platform_mode);
+
+ Power_up:
+	sysdev_resume();
+	/* NOTE:  dpm_resume_noirq() is just a resume() for devices
+	 * that suspended with irqs off ... no overall powerup.
+	 */
+
+ Enable_irqs:
+	local_irq_enable();
+
+ Enable_cpus:
+	enable_nonboot_cpus();
+
+ Platform_finish:
+	platform_finish(platform_mode);
+
+	dpm_resume_noirq(in_suspend ?
+		(error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
+
+	return error;
+}
+
+/**
+ *	hibernation_snapshot - quiesce devices and create the hibernation
+ *	snapshot image.
+ *	@platform_mode - if set, use the platform driver, if available, to
+ *			 prepare the platform firmware for the power transition.
+ *
+ *	Must be called with pm_mutex held
+ */
+
+int hibernation_snapshot(int platform_mode)
+{
+	int error;
+
+	error = platform_begin(platform_mode);
+	if (error)
+		return error;
+
+	/* Free memory before shutting down devices. */
+	error = swsusp_shrink_memory();
+	if (error)
+		goto Close;
+
+	suspend_console();
+	error = dpm_suspend_start(PMSG_FREEZE);
+	if (error)
+		goto Recover_platform;
+
+	if (hibernation_test(TEST_DEVICES))
+		goto Recover_platform;
+
+	error = create_image(platform_mode);
+	/* Control returns here after successful restore */
+
+ Resume_devices:
+	dpm_resume_end(in_suspend ?
+		(error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
+	resume_console();
+ Close:
+	platform_end(platform_mode);
+	return error;
+
+ Recover_platform:
+	platform_recover(platform_mode);
+	goto Resume_devices;
+}
+
+/**
+ *	resume_target_kernel - prepare devices that need to be suspended with
+ *	interrupts off, restore the contents of highmem that have not been
+ *	restored yet from the image and run the low level code that will restore
+ *	the remaining contents of memory and switch to the just restored target
+ *	kernel.
+ */
+
+static int resume_target_kernel(bool platform_mode)
+{
+	int error;
+
+	error = dpm_suspend_noirq(PMSG_QUIESCE);
+	if (error) {
+		printk(KERN_ERR "PM: Some devices failed to power down, "
+			"aborting resume\n");
+		return error;
+	}
+
+	error = platform_pre_restore(platform_mode);
+	if (error)
+		goto Cleanup;
+
+	error = disable_nonboot_cpus();
+	if (error)
+		goto Enable_cpus;
+
+	local_irq_disable();
+
+	error = sysdev_suspend(PMSG_QUIESCE);
+	if (error)
+		goto Enable_irqs;
+
+	/* We'll ignore saved state, but this gets preempt count (etc) right */
+	save_processor_state();
+	error = restore_highmem();
+	if (!error) {
+		error = swsusp_arch_resume();
+		/*
+		 * The code below is only ever reached in case of a failure.
+		 * Otherwise execution continues at place where
+		 * swsusp_arch_suspend() was called
+		 */
+		BUG_ON(!error);
+		/* This call to restore_highmem() undos the previous one */
+		restore_highmem();
+	}
+	/*
+	 * The only reason why swsusp_arch_resume() can fail is memory being
+	 * very tight, so we have to free it as soon as we can to avoid
+	 * subsequent failures
+	 */
+	swsusp_free();
+	restore_processor_state();
+	touch_softlockup_watchdog();
+
+	sysdev_resume();
+
+ Enable_irqs:
+	local_irq_enable();
+
+ Enable_cpus:
+	enable_nonboot_cpus();
+
+ Cleanup:
+	platform_restore_cleanup(platform_mode);
+
+	dpm_resume_noirq(PMSG_RECOVER);
+
+	return error;
+}
+
+/**
+ *	hibernation_restore - quiesce devices and restore the hibernation
+ *	snapshot image.  If successful, control returns in hibernation_snaphot()
+ *	@platform_mode - if set, use the platform driver, if available, to
+ *			 prepare the platform firmware for the transition.
+ *
+ *	Must be called with pm_mutex held
+ */
+
+int hibernation_restore(int platform_mode)
+{
+	int error;
+
+	pm_prepare_console();
+	suspend_console();
+	error = dpm_suspend_start(PMSG_QUIESCE);
+	if (!error) {
+		error = resume_target_kernel(platform_mode);
+		dpm_resume_end(PMSG_RECOVER);
+	}
+	resume_console();
+	pm_restore_console();
+	return error;
+}
+
+/**
+ *	hibernation_platform_enter - enter the hibernation state using the
+ *	platform driver (if available)
+ */
+
+int hibernation_platform_enter(void)
+{
+	int error;
+
+	if (!hibernation_ops)
+		return -ENOSYS;
+
+	/*
+	 * We have cancelled the power transition by running
+	 * hibernation_ops->finish() before saving the image, so we should let
+	 * the firmware know that we're going to enter the sleep state after all
+	 */
+	error = hibernation_ops->begin();
+	if (error)
+		goto Close;
+
+	entering_platform_hibernation = true;
+	suspend_console();
+	error = dpm_suspend_start(PMSG_HIBERNATE);
+	if (error) {
+		if (hibernation_ops->recover)
+			hibernation_ops->recover();
+		goto Resume_devices;
+	}
+
+	error = dpm_suspend_noirq(PMSG_HIBERNATE);
+	if (error)
+		goto Resume_devices;
+
+	error = hibernation_ops->prepare();
+	if (error)
+		goto Platofrm_finish;
+
+	error = disable_nonboot_cpus();
+	if (error)
+		goto Platofrm_finish;
+
+	local_irq_disable();
+	sysdev_suspend(PMSG_HIBERNATE);
+	hibernation_ops->enter();
+	/* We should never get here */
+	while (1);
+
+	/*
+	 * We don't need to reenable the nonboot CPUs or resume consoles, since
+	 * the system is going to be halted anyway.
+	 */
+ Platofrm_finish:
+	hibernation_ops->finish();
+
+	dpm_suspend_noirq(PMSG_RESTORE);
+
+ Resume_devices:
+	entering_platform_hibernation = false;
+	dpm_resume_end(PMSG_RESTORE);
+	resume_console();
+
+ Close:
+	hibernation_ops->end();
+
+	return error;
+}
+
+/**
+ *	power_down - Shut the machine down for hibernation.
+ *
+ *	Use the platform driver, if configured so; otherwise try
+ *	to power off or reboot.
+ */
+
+static void power_down(void)
+{
+	switch (hibernation_mode) {
+	case HIBERNATION_TEST:
+	case HIBERNATION_TESTPROC:
+		break;
+	case HIBERNATION_REBOOT:
+		kernel_restart(NULL);
+		break;
+	case HIBERNATION_PLATFORM:
+		hibernation_platform_enter();
+	case HIBERNATION_SHUTDOWN:
+		kernel_power_off();
+		break;
+	}
+	kernel_halt();
+	/*
+	 * Valid image is on the disk, if we continue we risk serious data
+	 * corruption after resume.
+	 */
+	printk(KERN_CRIT "PM: Please power down manually\n");
+	while(1);
+}
+
+static int prepare_processes(void)
+{
+	int error = 0;
+
+	if (freeze_processes()) {
+		error = -EBUSY;
+		thaw_processes();
+	}
+	return error;
+}
+
+/**
+ *	hibernate - The granpappy of the built-in hibernation management
+ */
+
+int hibernate(void)
+{
+	int error;
+
+	mutex_lock(&pm_mutex);
+	/* The snapshot device should not be opened while we're running */
+	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+		error = -EBUSY;
+		goto Unlock;
+	}
+
+	pm_prepare_console();
+	error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
+	if (error)
+		goto Exit;
+
+	error = usermodehelper_disable();
+	if (error)
+		goto Exit;
+
+	/* Allocate memory management structures */
+	error = create_basic_memory_bitmaps();
+	if (error)
+		goto Exit;
+
+	printk(KERN_INFO "PM: Syncing filesystems ... ");
+	sys_sync();
+	printk("done.\n");
+
+	error = prepare_processes();
+	if (error)
+		goto Finish;
+
+	if (hibernation_test(TEST_FREEZER))
+		goto Thaw;
+
+	if (hibernation_testmode(HIBERNATION_TESTPROC))
+		goto Thaw;
+
+	error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
+	if (in_suspend && !error) {
+		unsigned int flags = 0;
+
+		if (hibernation_mode == HIBERNATION_PLATFORM)
+			flags |= SF_PLATFORM_MODE;
+		pr_debug("PM: writing image.\n");
+		error = swsusp_write(flags);
+		swsusp_free();
+		if (!error)
+			power_down();
+	} else {
+		pr_debug("PM: Image restored successfully.\n");
+		swsusp_free();
+	}
+ Thaw:
+	thaw_processes();
+ Finish:
+	free_basic_memory_bitmaps();
+	usermodehelper_enable();
+ Exit:
+	pm_notifier_call_chain(PM_POST_HIBERNATION);
+	pm_restore_console();
+	atomic_inc(&snapshot_device_available);
+ Unlock:
+	mutex_unlock(&pm_mutex);
+	return error;
+}
+
+
+/**
+ *	software_resume - Resume from a saved image.
+ *
+ *	Called as a late_initcall (so all devices are discovered and
+ *	initialized), we call swsusp to see if we have a saved image or not.
+ *	If so, we quiesce devices, the restore the saved image. We will
+ *	return above (in hibernate() ) if everything goes well.
+ *	Otherwise, we fail gracefully and return to the normally
+ *	scheduled program.
+ *
+ */
+
+static int software_resume(void)
+{
+	int error;
+	unsigned int flags;
+
+	/*
+	 * If the user said "noresume".. bail out early.
+	 */
+	if (noresume)
+		return 0;
+
+	/*
+	 * name_to_dev_t() below takes a sysfs buffer mutex when sysfs
+	 * is configured into the kernel. Since the regular hibernate
+	 * trigger path is via sysfs which takes a buffer mutex before
+	 * calling hibernate functions (which take pm_mutex) this can
+	 * cause lockdep to complain about a possible ABBA deadlock
+	 * which cannot happen since we're in the boot code here and
+	 * sysfs can't be invoked yet. Therefore, we use a subclass
+	 * here to avoid lockdep complaining.
+	 */
+	mutex_lock_nested(&pm_mutex, SINGLE_DEPTH_NESTING);
+
+	if (swsusp_resume_device)
+		goto Check_image;
+
+	if (!strlen(resume_file)) {
+		error = -ENOENT;
+		goto Unlock;
+	}
+
+	pr_debug("PM: Checking image partition %s\n", resume_file);
+
+	/* Check if the device is there */
+	swsusp_resume_device = name_to_dev_t(resume_file);
+	if (!swsusp_resume_device) {
+		/*
+		 * Some device discovery might still be in progress; we need
+		 * to wait for this to finish.
+		 */
+		wait_for_device_probe();
+		/*
+		 * We can't depend on SCSI devices being available after loading
+		 * one of their modules until scsi_complete_async_scans() is
+		 * called and the resume device usually is a SCSI one.
+		 */
+		scsi_complete_async_scans();
+
+		swsusp_resume_device = name_to_dev_t(resume_file);
+		if (!swsusp_resume_device) {
+			error = -ENODEV;
+			goto Unlock;
+		}
+	}
+
+ Check_image:
+	pr_debug("PM: Resume from partition %d:%d\n",
+		MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
+
+	pr_debug("PM: Checking hibernation image.\n");
+	error = swsusp_check();
+	if (error)
+		goto Unlock;
+
+	/* The snapshot device should not be opened while we're running */
+	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+		error = -EBUSY;
+		goto Unlock;
+	}
+
+	pm_prepare_console();
+	error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
+	if (error)
+		goto Finish;
+
+	error = usermodehelper_disable();
+	if (error)
+		goto Finish;
+
+	error = create_basic_memory_bitmaps();
+	if (error)
+		goto Finish;
+
+	pr_debug("PM: Preparing processes for restore.\n");
+	error = prepare_processes();
+	if (error) {
+		swsusp_close(FMODE_READ);
+		goto Done;
+	}
+
+	pr_debug("PM: Reading hibernation image.\n");
+
+	error = swsusp_read(&flags);
+	if (!error)
+		hibernation_restore(flags & SF_PLATFORM_MODE);
+
+	printk(KERN_ERR "PM: Restore failed, recovering.\n");
+	swsusp_free();
+	thaw_processes();
+ Done:
+	free_basic_memory_bitmaps();
+	usermodehelper_enable();
+ Finish:
+	pm_notifier_call_chain(PM_POST_RESTORE);
+	pm_restore_console();
+	atomic_inc(&snapshot_device_available);
+	/* For success case, the suspend path will release the lock */
+ Unlock:
+	mutex_unlock(&pm_mutex);
+	pr_debug("PM: Resume from disk failed.\n");
+	return error;
+}
+
+late_initcall(software_resume);
+
+
+static const char * const hibernation_modes[] = {
+	[HIBERNATION_PLATFORM]	= "platform",
+	[HIBERNATION_SHUTDOWN]	= "shutdown",
+	[HIBERNATION_REBOOT]	= "reboot",
+	[HIBERNATION_TEST]	= "test",
+	[HIBERNATION_TESTPROC]	= "testproc",
+};
+
+/**
+ *	disk - Control hibernation mode
+ *
+ *	Suspend-to-disk can be handled in several ways. We have a few options
+ *	for putting the system to sleep - using the platform driver (e.g. ACPI
+ *	or other hibernation_ops), powering off the system or rebooting the
+ *	system (for testing) as well as the two test modes.
+ *
+ *	The system can support 'platform', and that is known a priori (and
+ *	encoded by the presence of hibernation_ops). However, the user may
+ *	choose 'shutdown' or 'reboot' as alternatives, as well as one fo the
+ *	test modes, 'test' or 'testproc'.
+ *
+ *	show() will display what the mode is currently set to.
+ *	store() will accept one of
+ *
+ *	'platform'
+ *	'shutdown'
+ *	'reboot'
+ *	'test'
+ *	'testproc'
+ *
+ *	It will only change to 'platform' if the system
+ *	supports it (as determined by having hibernation_ops).
+ */
+
+static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
+			 char *buf)
+{
+	int i;
+	char *start = buf;
+
+	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
+		if (!hibernation_modes[i])
+			continue;
+		switch (i) {
+		case HIBERNATION_SHUTDOWN:
+		case HIBERNATION_REBOOT:
+		case HIBERNATION_TEST:
+		case HIBERNATION_TESTPROC:
+			break;
+		case HIBERNATION_PLATFORM:
+			if (hibernation_ops)
+				break;
+			/* not a valid mode, continue with loop */
+			continue;
+		}
+		if (i == hibernation_mode)
+			buf += sprintf(buf, "[%s] ", hibernation_modes[i]);
+		else
+			buf += sprintf(buf, "%s ", hibernation_modes[i]);
+	}
+	buf += sprintf(buf, "\n");
+	return buf-start;
+}
+
+
+static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
+			  const char *buf, size_t n)
+{
+	int error = 0;
+	int i;
+	int len;
+	char *p;
+	int mode = HIBERNATION_INVALID;
+
+	p = memchr(buf, '\n', n);
+	len = p ? p - buf : n;
+
+	mutex_lock(&pm_mutex);
+	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
+		if (len == strlen(hibernation_modes[i])
+		    && !strncmp(buf, hibernation_modes[i], len)) {
+			mode = i;
+			break;
+		}
+	}
+	if (mode != HIBERNATION_INVALID) {
+		switch (mode) {
+		case HIBERNATION_SHUTDOWN:
+		case HIBERNATION_REBOOT:
+		case HIBERNATION_TEST:
+		case HIBERNATION_TESTPROC:
+			hibernation_mode = mode;
+			break;
+		case HIBERNATION_PLATFORM:
+			if (hibernation_ops)
+				hibernation_mode = mode;
+			else
+				error = -EINVAL;
+		}
+	} else
+		error = -EINVAL;
+
+	if (!error)
+		pr_debug("PM: Hibernation mode set to '%s'\n",
+			 hibernation_modes[mode]);
+	mutex_unlock(&pm_mutex);
+	return error ? error : n;
+}
+
+power_attr(disk);
+
+static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
+			   char *buf)
+{
+	return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device),
+		       MINOR(swsusp_resume_device));
+}
+
+static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
+			    const char *buf, size_t n)
+{
+	unsigned int maj, min;
+	dev_t res;
+	int ret = -EINVAL;
+
+	if (sscanf(buf, "%u:%u", &maj, &min) != 2)
+		goto out;
+
+	res = MKDEV(maj,min);
+	if (maj != MAJOR(res) || min != MINOR(res))
+		goto out;
+
+	mutex_lock(&pm_mutex);
+	swsusp_resume_device = res;
+	mutex_unlock(&pm_mutex);
+	printk(KERN_INFO "PM: Starting manual resume from disk\n");
+	noresume = 0;
+	software_resume();
+	ret = n;
+ out:
+	return ret;
+}
+
+power_attr(resume);
+
+static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr,
+			       char *buf)
+{
+	return sprintf(buf, "%lu\n", image_size);
+}
+
+static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr,
+				const char *buf, size_t n)
+{
+	unsigned long size;
+
+	if (sscanf(buf, "%lu", &size) == 1) {
+		image_size = size;
+		return n;
+	}
+
+	return -EINVAL;
+}
+
+power_attr(image_size);
+
+static struct attribute * g[] = {
+	&disk_attr.attr,
+	&resume_attr.attr,
+	&image_size_attr.attr,
+	NULL,
+};
+
+
+static struct attribute_group attr_group = {
+	.attrs = g,
+};
+
+
+static int __init pm_disk_init(void)
+{
+	return sysfs_create_group(power_kobj, &attr_group);
+}
+
+core_initcall(pm_disk_init);
+
+
+static int __init resume_setup(char *str)
+{
+	if (noresume)
+		return 1;
+
+	strncpy( resume_file, str, 255 );
+	return 1;
+}
+
+static int __init resume_offset_setup(char *str)
+{
+	unsigned long long offset;
+
+	if (noresume)
+		return 1;
+
+	if (sscanf(str, "%llu", &offset) == 1)
+		swsusp_resume_block = offset;
+
+	return 1;
+}
+
+static int __init noresume_setup(char *str)
+{
+	noresume = 1;
+	return 1;
+}
+
+__setup("noresume", noresume_setup);
+__setup("resume_offset=", resume_offset_setup);
+__setup("resume=", resume_setup);
diff --git a/kernel/power/hibernate_nvs.c b/kernel/power/hibernate_nvs.c
new file mode 100644
index 0000000..39ac698
--- /dev/null
+++ b/kernel/power/hibernate_nvs.c
@@ -0,0 +1,135 @@
+/*
+ * linux/kernel/power/hibernate_nvs.c - Routines for handling NVS memory
+ *
+ * Copyright (C) 2008,2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/suspend.h>
+
+/*
+ * Platforms, like ACPI, may want us to save some memory used by them during
+ * hibernation and to restore the contents of this memory during the subsequent
+ * resume.  The code below implements a mechanism allowing us to do that.
+ */
+
+struct nvs_page {
+	unsigned long phys_start;
+	unsigned int size;
+	void *kaddr;
+	void *data;
+	struct list_head node;
+};
+
+static LIST_HEAD(nvs_list);
+
+/**
+ *	hibernate_nvs_register - register platform NVS memory region to save
+ *	@start - physical address of the region
+ *	@size - size of the region
+ *
+ *	The NVS region need not be page-aligned (both ends) and we arrange
+ *	things so that the data from page-aligned addresses in this region will
+ *	be copied into separate RAM pages.
+ */
+int hibernate_nvs_register(unsigned long start, unsigned long size)
+{
+	struct nvs_page *entry, *next;
+
+	while (size > 0) {
+		unsigned int nr_bytes;
+
+		entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL);
+		if (!entry)
+			goto Error;
+
+		list_add_tail(&entry->node, &nvs_list);
+		entry->phys_start = start;
+		nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK);
+		entry->size = (size < nr_bytes) ? size : nr_bytes;
+
+		start += entry->size;
+		size -= entry->size;
+	}
+	return 0;
+
+ Error:
+	list_for_each_entry_safe(entry, next, &nvs_list, node) {
+		list_del(&entry->node);
+		kfree(entry);
+	}
+	return -ENOMEM;
+}
+
+/**
+ *	hibernate_nvs_free - free data pages allocated for saving NVS regions
+ */
+void hibernate_nvs_free(void)
+{
+	struct nvs_page *entry;
+
+	list_for_each_entry(entry, &nvs_list, node)
+		if (entry->data) {
+			free_page((unsigned long)entry->data);
+			entry->data = NULL;
+			if (entry->kaddr) {
+				iounmap(entry->kaddr);
+				entry->kaddr = NULL;
+			}
+		}
+}
+
+/**
+ *	hibernate_nvs_alloc - allocate memory necessary for saving NVS regions
+ */
+int hibernate_nvs_alloc(void)
+{
+	struct nvs_page *entry;
+
+	list_for_each_entry(entry, &nvs_list, node) {
+		entry->data = (void *)__get_free_page(GFP_KERNEL);
+		if (!entry->data) {
+			hibernate_nvs_free();
+			return -ENOMEM;
+		}
+	}
+	return 0;
+}
+
+/**
+ *	hibernate_nvs_save - save NVS memory regions
+ */
+void hibernate_nvs_save(void)
+{
+	struct nvs_page *entry;
+
+	printk(KERN_INFO "PM: Saving platform NVS memory\n");
+
+	list_for_each_entry(entry, &nvs_list, node)
+		if (entry->data) {
+			entry->kaddr = ioremap(entry->phys_start, entry->size);
+			memcpy(entry->data, entry->kaddr, entry->size);
+		}
+}
+
+/**
+ *	hibernate_nvs_restore - restore NVS memory regions
+ *
+ *	This function is going to be called with interrupts disabled, so it
+ *	cannot iounmap the virtual addresses used to access the NVS region.
+ */
+void hibernate_nvs_restore(void)
+{
+	struct nvs_page *entry;
+
+	printk(KERN_INFO "PM: Restoring platform NVS memory\n");
+
+	list_for_each_entry(entry, &nvs_list, node)
+		if (entry->data)
+			memcpy(entry->kaddr, entry->data, entry->size);
+}
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 8680282..f710e36 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -8,20 +8,9 @@
  *
  */
 
-#include <linux/module.h>
-#include <linux/suspend.h>
 #include <linux/kobject.h>
 #include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/kmod.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/cpu.h>
 #include <linux/resume-trace.h>
-#include <linux/freezer.h>
-#include <linux/vmstat.h>
-#include <linux/syscalls.h>
 
 #include "power.h"
 
@@ -119,373 +108,6 @@
 
 #endif /* CONFIG_PM_SLEEP */
 
-#ifdef CONFIG_SUSPEND
-
-static int suspend_test(int level)
-{
-#ifdef CONFIG_PM_DEBUG
-	if (pm_test_level == level) {
-		printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
-		mdelay(5000);
-		return 1;
-	}
-#endif /* !CONFIG_PM_DEBUG */
-	return 0;
-}
-
-#ifdef CONFIG_PM_TEST_SUSPEND
-
-/*
- * We test the system suspend code by setting an RTC wakealarm a short
- * time in the future, then suspending.  Suspending the devices won't
- * normally take long ... some systems only need a few milliseconds.
- *
- * The time it takes is system-specific though, so when we test this
- * during system bootup we allow a LOT of time.
- */
-#define TEST_SUSPEND_SECONDS	5
-
-static unsigned long suspend_test_start_time;
-
-static void suspend_test_start(void)
-{
-	/* FIXME Use better timebase than "jiffies", ideally a clocksource.
-	 * What we want is a hardware counter that will work correctly even
-	 * during the irqs-are-off stages of the suspend/resume cycle...
-	 */
-	suspend_test_start_time = jiffies;
-}
-
-static void suspend_test_finish(const char *label)
-{
-	long nj = jiffies - suspend_test_start_time;
-	unsigned msec;
-
-	msec = jiffies_to_msecs(abs(nj));
-	pr_info("PM: %s took %d.%03d seconds\n", label,
-			msec / 1000, msec % 1000);
-
-	/* Warning on suspend means the RTC alarm period needs to be
-	 * larger -- the system was sooo slooowwww to suspend that the
-	 * alarm (should have) fired before the system went to sleep!
-	 *
-	 * Warning on either suspend or resume also means the system
-	 * has some performance issues.  The stack dump of a WARN_ON
-	 * is more likely to get the right attention than a printk...
-	 */
-	WARN(msec > (TEST_SUSPEND_SECONDS * 1000), "Component: %s\n", label);
-}
-
-#else
-
-static void suspend_test_start(void)
-{
-}
-
-static void suspend_test_finish(const char *label)
-{
-}
-
-#endif
-
-/* This is just an arbitrary number */
-#define FREE_PAGE_NUMBER (100)
-
-static struct platform_suspend_ops *suspend_ops;
-
-/**
- *	suspend_set_ops - Set the global suspend method table.
- *	@ops:	Pointer to ops structure.
- */
-
-void suspend_set_ops(struct platform_suspend_ops *ops)
-{
-	mutex_lock(&pm_mutex);
-	suspend_ops = ops;
-	mutex_unlock(&pm_mutex);
-}
-
-/**
- * suspend_valid_only_mem - generic memory-only valid callback
- *
- * Platform drivers that implement mem suspend only and only need
- * to check for that in their .valid callback can use this instead
- * of rolling their own .valid callback.
- */
-int suspend_valid_only_mem(suspend_state_t state)
-{
-	return state == PM_SUSPEND_MEM;
-}
-
-/**
- *	suspend_prepare - Do prep work before entering low-power state.
- *
- *	This is common code that is called for each state that we're entering.
- *	Run suspend notifiers, allocate a console and stop all processes.
- */
-static int suspend_prepare(void)
-{
-	int error;
-	unsigned int free_pages;
-
-	if (!suspend_ops || !suspend_ops->enter)
-		return -EPERM;
-
-	pm_prepare_console();
-
-	error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
-	if (error)
-		goto Finish;
-
-	error = usermodehelper_disable();
-	if (error)
-		goto Finish;
-
-	if (suspend_freeze_processes()) {
-		error = -EAGAIN;
-		goto Thaw;
-	}
-
-	free_pages = global_page_state(NR_FREE_PAGES);
-	if (free_pages < FREE_PAGE_NUMBER) {
-		pr_debug("PM: free some memory\n");
-		shrink_all_memory(FREE_PAGE_NUMBER - free_pages);
-		if (nr_free_pages() < FREE_PAGE_NUMBER) {
-			error = -ENOMEM;
-			printk(KERN_ERR "PM: No enough memory\n");
-		}
-	}
-	if (!error)
-		return 0;
-
- Thaw:
-	suspend_thaw_processes();
-	usermodehelper_enable();
- Finish:
-	pm_notifier_call_chain(PM_POST_SUSPEND);
-	pm_restore_console();
-	return error;
-}
-
-/* default implementation */
-void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
-{
-	local_irq_disable();
-}
-
-/* default implementation */
-void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
-{
-	local_irq_enable();
-}
-
-/**
- *	suspend_enter - enter the desired system sleep state.
- *	@state:		state to enter
- *
- *	This function should be called after devices have been suspended.
- */
-static int suspend_enter(suspend_state_t state)
-{
-	int error;
-
-	if (suspend_ops->prepare) {
-		error = suspend_ops->prepare();
-		if (error)
-			return error;
-	}
-
-	error = device_power_down(PMSG_SUSPEND);
-	if (error) {
-		printk(KERN_ERR "PM: Some devices failed to power down\n");
-		goto Platfrom_finish;
-	}
-
-	if (suspend_ops->prepare_late) {
-		error = suspend_ops->prepare_late();
-		if (error)
-			goto Power_up_devices;
-	}
-
-	if (suspend_test(TEST_PLATFORM))
-		goto Platform_wake;
-
-	error = disable_nonboot_cpus();
-	if (error || suspend_test(TEST_CPUS))
-		goto Enable_cpus;
-
-	arch_suspend_disable_irqs();
-	BUG_ON(!irqs_disabled());
-
-	error = sysdev_suspend(PMSG_SUSPEND);
-	if (!error) {
-		if (!suspend_test(TEST_CORE))
-			error = suspend_ops->enter(state);
-		sysdev_resume();
-	}
-
-	arch_suspend_enable_irqs();
-	BUG_ON(irqs_disabled());
-
- Enable_cpus:
-	enable_nonboot_cpus();
-
- Platform_wake:
-	if (suspend_ops->wake)
-		suspend_ops->wake();
-
- Power_up_devices:
-	device_power_up(PMSG_RESUME);
-
- Platfrom_finish:
-	if (suspend_ops->finish)
-		suspend_ops->finish();
-
-	return error;
-}
-
-/**
- *	suspend_devices_and_enter - suspend devices and enter the desired system
- *				    sleep state.
- *	@state:		  state to enter
- */
-int suspend_devices_and_enter(suspend_state_t state)
-{
-	int error;
-
-	if (!suspend_ops)
-		return -ENOSYS;
-
-	if (suspend_ops->begin) {
-		error = suspend_ops->begin(state);
-		if (error)
-			goto Close;
-	}
-	suspend_console();
-	suspend_test_start();
-	error = device_suspend(PMSG_SUSPEND);
-	if (error) {
-		printk(KERN_ERR "PM: Some devices failed to suspend\n");
-		goto Recover_platform;
-	}
-	suspend_test_finish("suspend devices");
-	if (suspend_test(TEST_DEVICES))
-		goto Recover_platform;
-
-	suspend_enter(state);
-
- Resume_devices:
-	suspend_test_start();
-	device_resume(PMSG_RESUME);
-	suspend_test_finish("resume devices");
-	resume_console();
- Close:
-	if (suspend_ops->end)
-		suspend_ops->end();
-	return error;
-
- Recover_platform:
-	if (suspend_ops->recover)
-		suspend_ops->recover();
-	goto Resume_devices;
-}
-
-/**
- *	suspend_finish - Do final work before exiting suspend sequence.
- *
- *	Call platform code to clean up, restart processes, and free the 
- *	console that we've allocated. This is not called for suspend-to-disk.
- */
-static void suspend_finish(void)
-{
-	suspend_thaw_processes();
-	usermodehelper_enable();
-	pm_notifier_call_chain(PM_POST_SUSPEND);
-	pm_restore_console();
-}
-
-
-
-
-static const char * const pm_states[PM_SUSPEND_MAX] = {
-	[PM_SUSPEND_STANDBY]	= "standby",
-	[PM_SUSPEND_MEM]	= "mem",
-};
-
-static inline int valid_state(suspend_state_t state)
-{
-	/* All states need lowlevel support and need to be valid
-	 * to the lowlevel implementation, no valid callback
-	 * implies that none are valid. */
-	if (!suspend_ops || !suspend_ops->valid || !suspend_ops->valid(state))
-		return 0;
-	return 1;
-}
-
-
-/**
- *	enter_state - Do common work of entering low-power state.
- *	@state:		pm_state structure for state we're entering.
- *
- *	Make sure we're the only ones trying to enter a sleep state. Fail
- *	if someone has beat us to it, since we don't want anything weird to
- *	happen when we wake up.
- *	Then, do the setup for suspend, enter the state, and cleaup (after
- *	we've woken up).
- */
-static int enter_state(suspend_state_t state)
-{
-	int error;
-
-	if (!valid_state(state))
-		return -ENODEV;
-
-	if (!mutex_trylock(&pm_mutex))
-		return -EBUSY;
-
-	printk(KERN_INFO "PM: Syncing filesystems ... ");
-	sys_sync();
-	printk("done.\n");
-
-	pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
-	error = suspend_prepare();
-	if (error)
-		goto Unlock;
-
-	if (suspend_test(TEST_FREEZER))
-		goto Finish;
-
-	pr_debug("PM: Entering %s sleep\n", pm_states[state]);
-	error = suspend_devices_and_enter(state);
-
- Finish:
-	pr_debug("PM: Finishing wakeup.\n");
-	suspend_finish();
- Unlock:
-	mutex_unlock(&pm_mutex);
-	return error;
-}
-
-
-/**
- *	pm_suspend - Externally visible function for suspending system.
- *	@state:		Enumerated value of state to enter.
- *
- *	Determine whether or not value is within range, get state 
- *	structure, and enter (above).
- */
-
-int pm_suspend(suspend_state_t state)
-{
-	if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
-		return enter_state(state);
-	return -EINVAL;
-}
-
-EXPORT_SYMBOL(pm_suspend);
-
-#endif /* CONFIG_SUSPEND */
-
 struct kobject *power_kobj;
 
 /**
@@ -498,7 +120,6 @@
  *	store() accepts one of those strings, translates it into the 
  *	proper enumerated value, and initiates a suspend transition.
  */
-
 static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
 			  char *buf)
 {
@@ -596,7 +217,6 @@
 	.attrs = g,
 };
 
-
 static int __init pm_init(void)
 {
 	power_kobj = kobject_create_and_add("power", NULL);
@@ -606,144 +226,3 @@
 }
 
 core_initcall(pm_init);
-
-
-#ifdef CONFIG_PM_TEST_SUSPEND
-
-#include <linux/rtc.h>
-
-/*
- * To test system suspend, we need a hands-off mechanism to resume the
- * system.  RTCs wake alarms are a common self-contained mechanism.
- */
-
-static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state)
-{
-	static char err_readtime[] __initdata =
-		KERN_ERR "PM: can't read %s time, err %d\n";
-	static char err_wakealarm [] __initdata =
-		KERN_ERR "PM: can't set %s wakealarm, err %d\n";
-	static char err_suspend[] __initdata =
-		KERN_ERR "PM: suspend test failed, error %d\n";
-	static char info_test[] __initdata =
-		KERN_INFO "PM: test RTC wakeup from '%s' suspend\n";
-
-	unsigned long		now;
-	struct rtc_wkalrm	alm;
-	int			status;
-
-	/* this may fail if the RTC hasn't been initialized */
-	status = rtc_read_time(rtc, &alm.time);
-	if (status < 0) {
-		printk(err_readtime, dev_name(&rtc->dev), status);
-		return;
-	}
-	rtc_tm_to_time(&alm.time, &now);
-
-	memset(&alm, 0, sizeof alm);
-	rtc_time_to_tm(now + TEST_SUSPEND_SECONDS, &alm.time);
-	alm.enabled = true;
-
-	status = rtc_set_alarm(rtc, &alm);
-	if (status < 0) {
-		printk(err_wakealarm, dev_name(&rtc->dev), status);
-		return;
-	}
-
-	if (state == PM_SUSPEND_MEM) {
-		printk(info_test, pm_states[state]);
-		status = pm_suspend(state);
-		if (status == -ENODEV)
-			state = PM_SUSPEND_STANDBY;
-	}
-	if (state == PM_SUSPEND_STANDBY) {
-		printk(info_test, pm_states[state]);
-		status = pm_suspend(state);
-	}
-	if (status < 0)
-		printk(err_suspend, status);
-
-	/* Some platforms can't detect that the alarm triggered the
-	 * wakeup, or (accordingly) disable it after it afterwards.
-	 * It's supposed to give oneshot behavior; cope.
-	 */
-	alm.enabled = false;
-	rtc_set_alarm(rtc, &alm);
-}
-
-static int __init has_wakealarm(struct device *dev, void *name_ptr)
-{
-	struct rtc_device *candidate = to_rtc_device(dev);
-
-	if (!candidate->ops->set_alarm)
-		return 0;
-	if (!device_may_wakeup(candidate->dev.parent))
-		return 0;
-
-	*(const char **)name_ptr = dev_name(dev);
-	return 1;
-}
-
-/*
- * Kernel options like "test_suspend=mem" force suspend/resume sanity tests
- * at startup time.  They're normally disabled, for faster boot and because
- * we can't know which states really work on this particular system.
- */
-static suspend_state_t test_state __initdata = PM_SUSPEND_ON;
-
-static char warn_bad_state[] __initdata =
-	KERN_WARNING "PM: can't test '%s' suspend state\n";
-
-static int __init setup_test_suspend(char *value)
-{
-	unsigned i;
-
-	/* "=mem" ==> "mem" */
-	value++;
-	for (i = 0; i < PM_SUSPEND_MAX; i++) {
-		if (!pm_states[i])
-			continue;
-		if (strcmp(pm_states[i], value) != 0)
-			continue;
-		test_state = (__force suspend_state_t) i;
-		return 0;
-	}
-	printk(warn_bad_state, value);
-	return 0;
-}
-__setup("test_suspend", setup_test_suspend);
-
-static int __init test_suspend(void)
-{
-	static char		warn_no_rtc[] __initdata =
-		KERN_WARNING "PM: no wakealarm-capable RTC driver is ready\n";
-
-	char			*pony = NULL;
-	struct rtc_device	*rtc = NULL;
-
-	/* PM is initialized by now; is that state testable? */
-	if (test_state == PM_SUSPEND_ON)
-		goto done;
-	if (!valid_state(test_state)) {
-		printk(warn_bad_state, pm_states[test_state]);
-		goto done;
-	}
-
-	/* RTCs have initialized by now too ... can we use one? */
-	class_find_device(rtc_class, NULL, &pony, has_wakealarm);
-	if (pony)
-		rtc = rtc_class_open(pony);
-	if (!rtc) {
-		printk(warn_no_rtc);
-		goto done;
-	}
-
-	/* go for it */
-	test_wakealarm(rtc, test_state);
-	rtc_class_close(rtc);
-done:
-	return 0;
-}
-late_initcall(test_suspend);
-
-#endif /* CONFIG_PM_TEST_SUSPEND */
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 46b5ec7..26d5a26 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -45,7 +45,7 @@
  */
 #define SPARE_PAGES	((1024 * 1024) >> PAGE_SHIFT)
 
-/* kernel/power/disk.c */
+/* kernel/power/hibernate.c */
 extern int hibernation_snapshot(int platform_mode);
 extern int hibernation_restore(int platform_mode);
 extern int hibernation_platform_enter(void);
@@ -74,7 +74,7 @@
 
 extern int create_basic_memory_bitmaps(void);
 extern void free_basic_memory_bitmaps(void);
-extern unsigned int count_data_pages(void);
+extern int swsusp_shrink_memory(void);
 
 /**
  *	Auxiliary structure used for reading the snapshot image data and
@@ -147,9 +147,8 @@
  */
 #define SF_PLATFORM_MODE	1
 
-/* kernel/power/disk.c */
+/* kernel/power/hibernate.c */
 extern int swsusp_check(void);
-extern int swsusp_shrink_memory(void);
 extern void swsusp_free(void);
 extern int swsusp_read(unsigned int *flags_p);
 extern int swsusp_write(unsigned int flags);
@@ -161,22 +160,36 @@
 				unsigned int, char *);
 
 #ifdef CONFIG_SUSPEND
-/* kernel/power/main.c */
+/* kernel/power/suspend.c */
+extern const char *const pm_states[];
+
+extern bool valid_state(suspend_state_t state);
 extern int suspend_devices_and_enter(suspend_state_t state);
+extern int enter_state(suspend_state_t state);
 #else /* !CONFIG_SUSPEND */
 static inline int suspend_devices_and_enter(suspend_state_t state)
 {
 	return -ENOSYS;
 }
+static inline int enter_state(suspend_state_t state) { return -ENOSYS; }
+static inline bool valid_state(suspend_state_t state) { return false; }
 #endif /* !CONFIG_SUSPEND */
 
+#ifdef CONFIG_PM_TEST_SUSPEND
+/* kernel/power/suspend_test.c */
+extern void suspend_test_start(void);
+extern void suspend_test_finish(const char *label);
+#else /* !CONFIG_PM_TEST_SUSPEND */
+static inline void suspend_test_start(void) {}
+static inline void suspend_test_finish(const char *label) {}
+#endif /* !CONFIG_PM_TEST_SUSPEND */
+
 #ifdef CONFIG_PM_SLEEP
 /* kernel/power/main.c */
 extern int pm_notifier_call_chain(unsigned long val);
 #endif
 
 #ifdef CONFIG_HIGHMEM
-unsigned int count_highmem_pages(void);
 int restore_highmem(void);
 #else
 static inline unsigned int count_highmem_pages(void) { return 0; }
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 33e2e4a..523a451 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -39,6 +39,14 @@
 static void swsusp_set_page_forbidden(struct page *);
 static void swsusp_unset_page_forbidden(struct page *);
 
+/*
+ * Preferred image size in bytes (tunable via /sys/power/image_size).
+ * When it is set to N, swsusp will do its best to ensure the image
+ * size will not exceed N bytes, but if that is impossible, it will
+ * try to create the smallest image possible.
+ */
+unsigned long image_size = 500 * 1024 * 1024;
+
 /* List of PBEs needed for restoring the pages that were allocated before
  * the suspend and included in the suspend image, but have also been
  * allocated by the "resume" kernel, so their contents cannot be written
@@ -840,7 +848,7 @@
  *	pages.
  */
 
-unsigned int count_highmem_pages(void)
+static unsigned int count_highmem_pages(void)
 {
 	struct zone *zone;
 	unsigned int n = 0;
@@ -902,7 +910,7 @@
  *	pages.
  */
 
-unsigned int count_data_pages(void)
+static unsigned int count_data_pages(void)
 {
 	struct zone *zone;
 	unsigned long pfn, max_zone_pfn;
@@ -1058,6 +1066,74 @@
 	buffer = NULL;
 }
 
+/**
+ *	swsusp_shrink_memory -  Try to free as much memory as needed
+ *
+ *	... but do not OOM-kill anyone
+ *
+ *	Notice: all userland should be stopped before it is called, or
+ *	livelock is possible.
+ */
+
+#define SHRINK_BITE	10000
+static inline unsigned long __shrink_memory(long tmp)
+{
+	if (tmp > SHRINK_BITE)
+		tmp = SHRINK_BITE;
+	return shrink_all_memory(tmp);
+}
+
+int swsusp_shrink_memory(void)
+{
+	long tmp;
+	struct zone *zone;
+	unsigned long pages = 0;
+	unsigned int i = 0;
+	char *p = "-\\|/";
+	struct timeval start, stop;
+
+	printk(KERN_INFO "PM: Shrinking memory...  ");
+	do_gettimeofday(&start);
+	do {
+		long size, highmem_size;
+
+		highmem_size = count_highmem_pages();
+		size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES;
+		tmp = size;
+		size += highmem_size;
+		for_each_populated_zone(zone) {
+			tmp += snapshot_additional_pages(zone);
+			if (is_highmem(zone)) {
+				highmem_size -=
+					zone_page_state(zone, NR_FREE_PAGES);
+			} else {
+				tmp -= zone_page_state(zone, NR_FREE_PAGES);
+				tmp += zone->lowmem_reserve[ZONE_NORMAL];
+			}
+		}
+
+		if (highmem_size < 0)
+			highmem_size = 0;
+
+		tmp += highmem_size;
+		if (tmp > 0) {
+			tmp = __shrink_memory(tmp);
+			if (!tmp)
+				return -ENOMEM;
+			pages += tmp;
+		} else if (size > image_size / PAGE_SIZE) {
+			tmp = __shrink_memory(size - (image_size / PAGE_SIZE));
+			pages += tmp;
+		}
+		printk("\b%c", p[i++%4]);
+	} while (tmp > 0);
+	do_gettimeofday(&stop);
+	printk("\bdone (%lu pages freed)\n", pages);
+	swsusp_show_speed(&start, &stop, pages, "Freed");
+
+	return 0;
+}
+
 #ifdef CONFIG_HIGHMEM
 /**
   *	count_pages_for_highmem - compute the number of non-highmem pages
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
new file mode 100644
index 0000000..6f10dfc
--- /dev/null
+++ b/kernel/power/suspend.c
@@ -0,0 +1,300 @@
+/*
+ * kernel/power/suspend.c - Suspend to RAM and standby functionality.
+ *
+ * Copyright (c) 2003 Patrick Mochel
+ * Copyright (c) 2003 Open Source Development Lab
+ * Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/cpu.h>
+#include <linux/syscalls.h>
+
+#include "power.h"
+
+const char *const pm_states[PM_SUSPEND_MAX] = {
+	[PM_SUSPEND_STANDBY]	= "standby",
+	[PM_SUSPEND_MEM]	= "mem",
+};
+
+static struct platform_suspend_ops *suspend_ops;
+
+/**
+ *	suspend_set_ops - Set the global suspend method table.
+ *	@ops:	Pointer to ops structure.
+ */
+void suspend_set_ops(struct platform_suspend_ops *ops)
+{
+	mutex_lock(&pm_mutex);
+	suspend_ops = ops;
+	mutex_unlock(&pm_mutex);
+}
+
+bool valid_state(suspend_state_t state)
+{
+	/*
+	 * All states need lowlevel support and need to be valid to the lowlevel
+	 * implementation, no valid callback implies that none are valid.
+	 */
+	return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
+}
+
+/**
+ * suspend_valid_only_mem - generic memory-only valid callback
+ *
+ * Platform drivers that implement mem suspend only and only need
+ * to check for that in their .valid callback can use this instead
+ * of rolling their own .valid callback.
+ */
+int suspend_valid_only_mem(suspend_state_t state)
+{
+	return state == PM_SUSPEND_MEM;
+}
+
+static int suspend_test(int level)
+{
+#ifdef CONFIG_PM_DEBUG
+	if (pm_test_level == level) {
+		printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
+		mdelay(5000);
+		return 1;
+	}
+#endif /* !CONFIG_PM_DEBUG */
+	return 0;
+}
+
+/**
+ *	suspend_prepare - Do prep work before entering low-power state.
+ *
+ *	This is common code that is called for each state that we're entering.
+ *	Run suspend notifiers, allocate a console and stop all processes.
+ */
+static int suspend_prepare(void)
+{
+	int error;
+
+	if (!suspend_ops || !suspend_ops->enter)
+		return -EPERM;
+
+	pm_prepare_console();
+
+	error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
+	if (error)
+		goto Finish;
+
+	error = usermodehelper_disable();
+	if (error)
+		goto Finish;
+
+	error = suspend_freeze_processes();
+	if (!error)
+		return 0;
+
+	suspend_thaw_processes();
+	usermodehelper_enable();
+ Finish:
+	pm_notifier_call_chain(PM_POST_SUSPEND);
+	pm_restore_console();
+	return error;
+}
+
+/* default implementation */
+void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
+{
+	local_irq_disable();
+}
+
+/* default implementation */
+void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
+{
+	local_irq_enable();
+}
+
+/**
+ *	suspend_enter - enter the desired system sleep state.
+ *	@state:		state to enter
+ *
+ *	This function should be called after devices have been suspended.
+ */
+static int suspend_enter(suspend_state_t state)
+{
+	int error;
+
+	if (suspend_ops->prepare) {
+		error = suspend_ops->prepare();
+		if (error)
+			return error;
+	}
+
+	error = dpm_suspend_noirq(PMSG_SUSPEND);
+	if (error) {
+		printk(KERN_ERR "PM: Some devices failed to power down\n");
+		goto Platfrom_finish;
+	}
+
+	if (suspend_ops->prepare_late) {
+		error = suspend_ops->prepare_late();
+		if (error)
+			goto Power_up_devices;
+	}
+
+	if (suspend_test(TEST_PLATFORM))
+		goto Platform_wake;
+
+	error = disable_nonboot_cpus();
+	if (error || suspend_test(TEST_CPUS))
+		goto Enable_cpus;
+
+	arch_suspend_disable_irqs();
+	BUG_ON(!irqs_disabled());
+
+	error = sysdev_suspend(PMSG_SUSPEND);
+	if (!error) {
+		if (!suspend_test(TEST_CORE))
+			error = suspend_ops->enter(state);
+		sysdev_resume();
+	}
+
+	arch_suspend_enable_irqs();
+	BUG_ON(irqs_disabled());
+
+ Enable_cpus:
+	enable_nonboot_cpus();
+
+ Platform_wake:
+	if (suspend_ops->wake)
+		suspend_ops->wake();
+
+ Power_up_devices:
+	dpm_resume_noirq(PMSG_RESUME);
+
+ Platfrom_finish:
+	if (suspend_ops->finish)
+		suspend_ops->finish();
+
+	return error;
+}
+
+/**
+ *	suspend_devices_and_enter - suspend devices and enter the desired system
+ *				    sleep state.
+ *	@state:		  state to enter
+ */
+int suspend_devices_and_enter(suspend_state_t state)
+{
+	int error;
+
+	if (!suspend_ops)
+		return -ENOSYS;
+
+	if (suspend_ops->begin) {
+		error = suspend_ops->begin(state);
+		if (error)
+			goto Close;
+	}
+	suspend_console();
+	suspend_test_start();
+	error = dpm_suspend_start(PMSG_SUSPEND);
+	if (error) {
+		printk(KERN_ERR "PM: Some devices failed to suspend\n");
+		goto Recover_platform;
+	}
+	suspend_test_finish("suspend devices");
+	if (suspend_test(TEST_DEVICES))
+		goto Recover_platform;
+
+	suspend_enter(state);
+
+ Resume_devices:
+	suspend_test_start();
+	dpm_resume_end(PMSG_RESUME);
+	suspend_test_finish("resume devices");
+	resume_console();
+ Close:
+	if (suspend_ops->end)
+		suspend_ops->end();
+	return error;
+
+ Recover_platform:
+	if (suspend_ops->recover)
+		suspend_ops->recover();
+	goto Resume_devices;
+}
+
+/**
+ *	suspend_finish - Do final work before exiting suspend sequence.
+ *
+ *	Call platform code to clean up, restart processes, and free the
+ *	console that we've allocated. This is not called for suspend-to-disk.
+ */
+static void suspend_finish(void)
+{
+	suspend_thaw_processes();
+	usermodehelper_enable();
+	pm_notifier_call_chain(PM_POST_SUSPEND);
+	pm_restore_console();
+}
+
+/**
+ *	enter_state - Do common work of entering low-power state.
+ *	@state:		pm_state structure for state we're entering.
+ *
+ *	Make sure we're the only ones trying to enter a sleep state. Fail
+ *	if someone has beat us to it, since we don't want anything weird to
+ *	happen when we wake up.
+ *	Then, do the setup for suspend, enter the state, and cleaup (after
+ *	we've woken up).
+ */
+int enter_state(suspend_state_t state)
+{
+	int error;
+
+	if (!valid_state(state))
+		return -ENODEV;
+
+	if (!mutex_trylock(&pm_mutex))
+		return -EBUSY;
+
+	printk(KERN_INFO "PM: Syncing filesystems ... ");
+	sys_sync();
+	printk("done.\n");
+
+	pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
+	error = suspend_prepare();
+	if (error)
+		goto Unlock;
+
+	if (suspend_test(TEST_FREEZER))
+		goto Finish;
+
+	pr_debug("PM: Entering %s sleep\n", pm_states[state]);
+	error = suspend_devices_and_enter(state);
+
+ Finish:
+	pr_debug("PM: Finishing wakeup.\n");
+	suspend_finish();
+ Unlock:
+	mutex_unlock(&pm_mutex);
+	return error;
+}
+
+/**
+ *	pm_suspend - Externally visible function for suspending system.
+ *	@state:		Enumerated value of state to enter.
+ *
+ *	Determine whether or not value is within range, get state
+ *	structure, and enter (above).
+ */
+int pm_suspend(suspend_state_t state)
+{
+	if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
+		return enter_state(state);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(pm_suspend);
diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c
new file mode 100644
index 0000000..17d8bb1
--- /dev/null
+++ b/kernel/power/suspend_test.c
@@ -0,0 +1,187 @@
+/*
+ * kernel/power/suspend_test.c - Suspend to RAM and standby test facility.
+ *
+ * Copyright (c) 2009 Pavel Machek <pavel@ucw.cz>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/init.h>
+#include <linux/rtc.h>
+
+#include "power.h"
+
+/*
+ * We test the system suspend code by setting an RTC wakealarm a short
+ * time in the future, then suspending.  Suspending the devices won't
+ * normally take long ... some systems only need a few milliseconds.
+ *
+ * The time it takes is system-specific though, so when we test this
+ * during system bootup we allow a LOT of time.
+ */
+#define TEST_SUSPEND_SECONDS	5
+
+static unsigned long suspend_test_start_time;
+
+void suspend_test_start(void)
+{
+	/* FIXME Use better timebase than "jiffies", ideally a clocksource.
+	 * What we want is a hardware counter that will work correctly even
+	 * during the irqs-are-off stages of the suspend/resume cycle...
+	 */
+	suspend_test_start_time = jiffies;
+}
+
+void suspend_test_finish(const char *label)
+{
+	long nj = jiffies - suspend_test_start_time;
+	unsigned msec;
+
+	msec = jiffies_to_msecs(abs(nj));
+	pr_info("PM: %s took %d.%03d seconds\n", label,
+			msec / 1000, msec % 1000);
+
+	/* Warning on suspend means the RTC alarm period needs to be
+	 * larger -- the system was sooo slooowwww to suspend that the
+	 * alarm (should have) fired before the system went to sleep!
+	 *
+	 * Warning on either suspend or resume also means the system
+	 * has some performance issues.  The stack dump of a WARN_ON
+	 * is more likely to get the right attention than a printk...
+	 */
+	WARN(msec > (TEST_SUSPEND_SECONDS * 1000), "Component: %s\n", label);
+}
+
+/*
+ * To test system suspend, we need a hands-off mechanism to resume the
+ * system.  RTCs wake alarms are a common self-contained mechanism.
+ */
+
+static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state)
+{
+	static char err_readtime[] __initdata =
+		KERN_ERR "PM: can't read %s time, err %d\n";
+	static char err_wakealarm [] __initdata =
+		KERN_ERR "PM: can't set %s wakealarm, err %d\n";
+	static char err_suspend[] __initdata =
+		KERN_ERR "PM: suspend test failed, error %d\n";
+	static char info_test[] __initdata =
+		KERN_INFO "PM: test RTC wakeup from '%s' suspend\n";
+
+	unsigned long		now;
+	struct rtc_wkalrm	alm;
+	int			status;
+
+	/* this may fail if the RTC hasn't been initialized */
+	status = rtc_read_time(rtc, &alm.time);
+	if (status < 0) {
+		printk(err_readtime, dev_name(&rtc->dev), status);
+		return;
+	}
+	rtc_tm_to_time(&alm.time, &now);
+
+	memset(&alm, 0, sizeof alm);
+	rtc_time_to_tm(now + TEST_SUSPEND_SECONDS, &alm.time);
+	alm.enabled = true;
+
+	status = rtc_set_alarm(rtc, &alm);
+	if (status < 0) {
+		printk(err_wakealarm, dev_name(&rtc->dev), status);
+		return;
+	}
+
+	if (state == PM_SUSPEND_MEM) {
+		printk(info_test, pm_states[state]);
+		status = pm_suspend(state);
+		if (status == -ENODEV)
+			state = PM_SUSPEND_STANDBY;
+	}
+	if (state == PM_SUSPEND_STANDBY) {
+		printk(info_test, pm_states[state]);
+		status = pm_suspend(state);
+	}
+	if (status < 0)
+		printk(err_suspend, status);
+
+	/* Some platforms can't detect that the alarm triggered the
+	 * wakeup, or (accordingly) disable it after it afterwards.
+	 * It's supposed to give oneshot behavior; cope.
+	 */
+	alm.enabled = false;
+	rtc_set_alarm(rtc, &alm);
+}
+
+static int __init has_wakealarm(struct device *dev, void *name_ptr)
+{
+	struct rtc_device *candidate = to_rtc_device(dev);
+
+	if (!candidate->ops->set_alarm)
+		return 0;
+	if (!device_may_wakeup(candidate->dev.parent))
+		return 0;
+
+	*(const char **)name_ptr = dev_name(dev);
+	return 1;
+}
+
+/*
+ * Kernel options like "test_suspend=mem" force suspend/resume sanity tests
+ * at startup time.  They're normally disabled, for faster boot and because
+ * we can't know which states really work on this particular system.
+ */
+static suspend_state_t test_state __initdata = PM_SUSPEND_ON;
+
+static char warn_bad_state[] __initdata =
+	KERN_WARNING "PM: can't test '%s' suspend state\n";
+
+static int __init setup_test_suspend(char *value)
+{
+	unsigned i;
+
+	/* "=mem" ==> "mem" */
+	value++;
+	for (i = 0; i < PM_SUSPEND_MAX; i++) {
+		if (!pm_states[i])
+			continue;
+		if (strcmp(pm_states[i], value) != 0)
+			continue;
+		test_state = (__force suspend_state_t) i;
+		return 0;
+	}
+	printk(warn_bad_state, value);
+	return 0;
+}
+__setup("test_suspend", setup_test_suspend);
+
+static int __init test_suspend(void)
+{
+	static char		warn_no_rtc[] __initdata =
+		KERN_WARNING "PM: no wakealarm-capable RTC driver is ready\n";
+
+	char			*pony = NULL;
+	struct rtc_device	*rtc = NULL;
+
+	/* PM is initialized by now; is that state testable? */
+	if (test_state == PM_SUSPEND_ON)
+		goto done;
+	if (!valid_state(test_state)) {
+		printk(warn_bad_state, pm_states[test_state]);
+		goto done;
+	}
+
+	/* RTCs have initialized by now too ... can we use one? */
+	class_find_device(rtc_class, NULL, &pony, has_wakealarm);
+	if (pony)
+		rtc = rtc_class_open(pony);
+	if (!rtc) {
+		printk(warn_no_rtc);
+		goto done;
+	}
+
+	/* go for it */
+	test_wakealarm(rtc, test_state);
+	rtc_class_close(rtc);
+done:
+	return 0;
+}
+late_initcall(test_suspend);
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index 78c3504..6a07f4d 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -55,14 +55,6 @@
 
 #include "power.h"
 
-/*
- * Preferred image size in bytes (tunable via /sys/power/image_size).
- * When it is set to N, swsusp will do its best to ensure the image
- * size will not exceed N bytes, but if that is impossible, it will
- * try to create the smallest image possible.
- */
-unsigned long image_size = 500 * 1024 * 1024;
-
 int in_suspend __nosavedata = 0;
 
 /**
@@ -194,193 +186,3 @@
 			centisecs / 100, centisecs % 100,
 			kps / 1000, (kps % 1000) / 10);
 }
-
-/**
- *	swsusp_shrink_memory -  Try to free as much memory as needed
- *
- *	... but do not OOM-kill anyone
- *
- *	Notice: all userland should be stopped before it is called, or
- *	livelock is possible.
- */
-
-#define SHRINK_BITE	10000
-static inline unsigned long __shrink_memory(long tmp)
-{
-	if (tmp > SHRINK_BITE)
-		tmp = SHRINK_BITE;
-	return shrink_all_memory(tmp);
-}
-
-int swsusp_shrink_memory(void)
-{
-	long tmp;
-	struct zone *zone;
-	unsigned long pages = 0;
-	unsigned int i = 0;
-	char *p = "-\\|/";
-	struct timeval start, stop;
-
-	printk(KERN_INFO "PM: Shrinking memory...  ");
-	do_gettimeofday(&start);
-	do {
-		long size, highmem_size;
-
-		highmem_size = count_highmem_pages();
-		size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES;
-		tmp = size;
-		size += highmem_size;
-		for_each_populated_zone(zone) {
-			tmp += snapshot_additional_pages(zone);
-			if (is_highmem(zone)) {
-				highmem_size -=
-					zone_page_state(zone, NR_FREE_PAGES);
-			} else {
-				tmp -= zone_page_state(zone, NR_FREE_PAGES);
-				tmp += zone->lowmem_reserve[ZONE_NORMAL];
-			}
-		}
-
-		if (highmem_size < 0)
-			highmem_size = 0;
-
-		tmp += highmem_size;
-		if (tmp > 0) {
-			tmp = __shrink_memory(tmp);
-			if (!tmp)
-				return -ENOMEM;
-			pages += tmp;
-		} else if (size > image_size / PAGE_SIZE) {
-			tmp = __shrink_memory(size - (image_size / PAGE_SIZE));
-			pages += tmp;
-		}
-		printk("\b%c", p[i++%4]);
-	} while (tmp > 0);
-	do_gettimeofday(&stop);
-	printk("\bdone (%lu pages freed)\n", pages);
-	swsusp_show_speed(&start, &stop, pages, "Freed");
-
-	return 0;
-}
-
-/*
- * Platforms, like ACPI, may want us to save some memory used by them during
- * hibernation and to restore the contents of this memory during the subsequent
- * resume.  The code below implements a mechanism allowing us to do that.
- */
-
-struct nvs_page {
-	unsigned long phys_start;
-	unsigned int size;
-	void *kaddr;
-	void *data;
-	struct list_head node;
-};
-
-static LIST_HEAD(nvs_list);
-
-/**
- *	hibernate_nvs_register - register platform NVS memory region to save
- *	@start - physical address of the region
- *	@size - size of the region
- *
- *	The NVS region need not be page-aligned (both ends) and we arrange
- *	things so that the data from page-aligned addresses in this region will
- *	be copied into separate RAM pages.
- */
-int hibernate_nvs_register(unsigned long start, unsigned long size)
-{
-	struct nvs_page *entry, *next;
-
-	while (size > 0) {
-		unsigned int nr_bytes;
-
-		entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL);
-		if (!entry)
-			goto Error;
-
-		list_add_tail(&entry->node, &nvs_list);
-		entry->phys_start = start;
-		nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK);
-		entry->size = (size < nr_bytes) ? size : nr_bytes;
-
-		start += entry->size;
-		size -= entry->size;
-	}
-	return 0;
-
- Error:
-	list_for_each_entry_safe(entry, next, &nvs_list, node) {
-		list_del(&entry->node);
-		kfree(entry);
-	}
-	return -ENOMEM;
-}
-
-/**
- *	hibernate_nvs_free - free data pages allocated for saving NVS regions
- */
-void hibernate_nvs_free(void)
-{
-	struct nvs_page *entry;
-
-	list_for_each_entry(entry, &nvs_list, node)
-		if (entry->data) {
-			free_page((unsigned long)entry->data);
-			entry->data = NULL;
-			if (entry->kaddr) {
-				iounmap(entry->kaddr);
-				entry->kaddr = NULL;
-			}
-		}
-}
-
-/**
- *	hibernate_nvs_alloc - allocate memory necessary for saving NVS regions
- */
-int hibernate_nvs_alloc(void)
-{
-	struct nvs_page *entry;
-
-	list_for_each_entry(entry, &nvs_list, node) {
-		entry->data = (void *)__get_free_page(GFP_KERNEL);
-		if (!entry->data) {
-			hibernate_nvs_free();
-			return -ENOMEM;
-		}
-	}
-	return 0;
-}
-
-/**
- *	hibernate_nvs_save - save NVS memory regions
- */
-void hibernate_nvs_save(void)
-{
-	struct nvs_page *entry;
-
-	printk(KERN_INFO "PM: Saving platform NVS memory\n");
-
-	list_for_each_entry(entry, &nvs_list, node)
-		if (entry->data) {
-			entry->kaddr = ioremap(entry->phys_start, entry->size);
-			memcpy(entry->data, entry->kaddr, entry->size);
-		}
-}
-
-/**
- *	hibernate_nvs_restore - restore NVS memory regions
- *
- *	This function is going to be called with interrupts disabled, so it
- *	cannot iounmap the virtual addresses used to access the NVS region.
- */
-void hibernate_nvs_restore(void)
-{
-	struct nvs_page *entry;
-
-	printk(KERN_INFO "PM: Restoring platform NVS memory\n");
-
-	list_for_each_entry(entry, &nvs_list, node)
-		if (entry->data)
-			memcpy(entry->kaddr, entry->data, entry->size);
-}
diff --git a/kernel/sched.c b/kernel/sched.c
index f04aa96..8ec9d13 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -2192,6 +2192,7 @@
 		smp_send_reschedule(cpu);
 	preempt_enable();
 }
+EXPORT_SYMBOL_GPL(kick_process);
 
 /*
  * Return a low guess at the load of a migration-source cpu weighted
diff --git a/kernel/timer.c b/kernel/timer.c
index c01e568..faf2db8 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -757,6 +757,7 @@
 	wake_up_idle_cpu(cpu);
 	spin_unlock_irqrestore(&base->lock, flags);
 }
+EXPORT_SYMBOL_GPL(add_timer_on);
 
 /**
  * del_timer - deactive a timer.
diff --git a/lib/Makefile b/lib/Makefile
index 1f6edef..34c5c0e 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -93,6 +93,8 @@
 
 obj-$(CONFIG_DMA_API_DEBUG) += dma-debug.o
 
+obj-$(CONFIG_GENERIC_CSUM) += checksum.o
+
 hostprogs-y	:= gen_crc32table
 clean-files	:= crc32table.h
 
diff --git a/lib/checksum.c b/lib/checksum.c
new file mode 100644
index 0000000..12e5a1c
--- /dev/null
+++ b/lib/checksum.c
@@ -0,0 +1,193 @@
+/*
+ *
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the  BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		IP/TCP/UDP checksumming routines
+ *
+ * Authors:	Jorge Cwik, <jorge@laser.satlink.net>
+ *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ *		Tom May, <ftom@netcom.com>
+ *		Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
+ *		Lots of code moved from tcp.c and ip.c; see those files
+ *		for more names.
+ *
+ * 03/02/96	Jes Sorensen, Andreas Schwab, Roman Hodek:
+ *		Fixed some nasty bugs, causing some horrible crashes.
+ *		A: At some points, the sum (%0) was used as
+ *		length-counter instead of the length counter
+ *		(%1). Thanks to Roman Hodek for pointing this out.
+ *		B: GCC seems to mess up if one uses too many
+ *		data-registers to hold input values and one tries to
+ *		specify d0 and d1 as scratch registers. Letting gcc
+ *		choose these registers itself solves the problem.
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+
+/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access
+ kills, so most of the assembly has to go. */
+
+#include <linux/module.h>
+#include <net/checksum.h>
+
+#include <asm/byteorder.h>
+
+static inline unsigned short from32to16(unsigned long x)
+{
+	/* add up 16-bit and 16-bit for 16+c bit */
+	x = (x & 0xffff) + (x >> 16);
+	/* add up carry.. */
+	x = (x & 0xffff) + (x >> 16);
+	return x;
+}
+
+static unsigned int do_csum(const unsigned char *buff, int len)
+{
+	int odd, count;
+	unsigned long result = 0;
+
+	if (len <= 0)
+		goto out;
+	odd = 1 & (unsigned long) buff;
+	if (odd) {
+		result = *buff;
+		len--;
+		buff++;
+	}
+	count = len >> 1;		/* nr of 16-bit words.. */
+	if (count) {
+		if (2 & (unsigned long) buff) {
+			result += *(unsigned short *) buff;
+			count--;
+			len -= 2;
+			buff += 2;
+		}
+		count >>= 1;		/* nr of 32-bit words.. */
+		if (count) {
+			unsigned long carry = 0;
+			do {
+				unsigned long w = *(unsigned long *) buff;
+				count--;
+				buff += 4;
+				result += carry;
+				result += w;
+				carry = (w > result);
+			} while (count);
+			result += carry;
+			result = (result & 0xffff) + (result >> 16);
+		}
+		if (len & 2) {
+			result += *(unsigned short *) buff;
+			buff += 2;
+		}
+	}
+	if (len & 1)
+		result += (*buff << 8);
+	result = from32to16(result);
+	if (odd)
+		result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+out:
+	return result;
+}
+
+/*
+ *	This is a version of ip_compute_csum() optimized for IP headers,
+ *	which always checksum on 4 octet boundaries.
+ */
+__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
+{
+	return (__force __sum16)~do_csum(iph, ihl*4);
+}
+EXPORT_SYMBOL(ip_fast_csum);
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+__wsum csum_partial(const void *buff, int len, __wsum wsum)
+{
+	unsigned int sum = (__force unsigned int)wsum;
+	unsigned int result = do_csum(buff, len);
+
+	/* add in old sum, and carry.. */
+	result += sum;
+	if (sum > result)
+		result += 1;
+	return (__force __wsum)result;
+}
+EXPORT_SYMBOL(csum_partial);
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+__sum16 ip_compute_csum(const void *buff, int len)
+{
+	return (__force __sum16)~do_csum(buff, len);
+}
+EXPORT_SYMBOL(ip_compute_csum);
+
+/*
+ * copy from fs while checksumming, otherwise like csum_partial
+ */
+__wsum
+csum_partial_copy_from_user(const void __user *src, void *dst, int len,
+						__wsum sum, int *csum_err)
+{
+	int missing;
+
+	missing = __copy_from_user(dst, src, len);
+	if (missing) {
+		memset(dst + len - missing, 0, missing);
+		*csum_err = -EFAULT;
+	} else
+		*csum_err = 0;
+
+	return csum_partial(dst, len, sum);
+}
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+
+/*
+ * copy from ds while checksumming, otherwise like csum_partial
+ */
+__wsum
+csum_partial_copy(const void *src, void *dst, int len, __wsum sum)
+{
+	memcpy(dst, src, len);
+	return csum_partial(dst, len, sum);
+}
+EXPORT_SYMBOL(csum_partial_copy);
+
+#ifndef csum_tcpudp_nofold
+__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
+			unsigned short len,
+			unsigned short proto,
+			__wsum sum)
+{
+	unsigned long long s = (__force u32)sum;
+
+	s += (__force u32)saddr;
+	s += (__force u32)daddr;
+#ifdef __BIG_ENDIAN
+	s += proto + len;
+#else
+	s += (proto + len) << 8;
+#endif
+	s += (s >> 32);
+	return (__force __wsum)s;
+}
+EXPORT_SYMBOL(csum_tcpudp_nofold);
+#endif
diff --git a/lib/extable.c b/lib/extable.c
index 179c087..4cac81e 100644
--- a/lib/extable.c
+++ b/lib/extable.c
@@ -39,7 +39,26 @@
 	sort(start, finish - start, sizeof(struct exception_table_entry),
 	     cmp_ex, NULL);
 }
-#endif
+
+#ifdef CONFIG_MODULES
+/*
+ * If the exception table is sorted, any referring to the module init
+ * will be at the beginning or the end.
+ */
+void trim_init_extable(struct module *m)
+{
+	/*trim the beginning*/
+	while (m->num_exentries && within_module_init(m->extable[0].insn, m)) {
+		m->extable++;
+		m->num_exentries--;
+	}
+	/*trim the end*/
+	while (m->num_exentries &&
+		within_module_init(m->extable[m->num_exentries-1].insn, m))
+		m->num_exentries--;
+}
+#endif /* CONFIG_MODULES */
+#endif /* !ARCH_HAS_SORT_EXTABLE */
 
 #ifndef ARCH_HAS_SEARCH_EXTABLE
 /*
diff --git a/mm/maccess.c b/mm/maccess.c
index ac40796..9073695 100644
--- a/mm/maccess.c
+++ b/mm/maccess.c
@@ -39,7 +39,7 @@
  * Safely write to address @dst from the buffer at @src.  If a kernel fault
  * happens, handle that and return -EFAULT.
  */
-long probe_kernel_write(void *dst, void *src, size_t size)
+long notrace __weak probe_kernel_write(void *dst, void *src, size_t size)
 {
 	long ret;
 	mm_segment_t old_fs = get_fs();
diff --git a/mm/page_cgroup.c b/mm/page_cgroup.c
index 3dd4a90..11a8a10 100644
--- a/mm/page_cgroup.c
+++ b/mm/page_cgroup.c
@@ -47,8 +47,6 @@
 	struct page_cgroup *base, *pc;
 	unsigned long table_size;
 	unsigned long start_pfn, nr_pages, index;
-	struct page *page;
-	unsigned int order;
 
 	start_pfn = NODE_DATA(nid)->node_start_pfn;
 	nr_pages = NODE_DATA(nid)->node_spanned_pages;
@@ -57,13 +55,11 @@
 		return 0;
 
 	table_size = sizeof(struct page_cgroup) * nr_pages;
-	order = get_order(table_size);
-	page = alloc_pages_node(nid, GFP_NOWAIT | __GFP_ZERO, order);
-	if (!page)
-		page = alloc_pages_node(-1, GFP_NOWAIT | __GFP_ZERO, order);
-	if (!page)
+
+	base = __alloc_bootmem_node_nopanic(NODE_DATA(nid),
+			table_size, PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
+	if (!base)
 		return -ENOMEM;
-	base = page_address(page);
 	for (index = 0; index < nr_pages; index++) {
 		pc = base + index;
 		__init_page_cgroup(pc, start_pfn + index);
@@ -73,7 +69,7 @@
 	return 0;
 }
 
-void __init page_cgroup_init(void)
+void __init page_cgroup_init_flatmem(void)
 {
 
 	int nid, fail;
@@ -117,16 +113,11 @@
 	if (!section->page_cgroup) {
 		nid = page_to_nid(pfn_to_page(pfn));
 		table_size = sizeof(struct page_cgroup) * PAGES_PER_SECTION;
-		if (slab_is_available()) {
-			base = kmalloc_node(table_size,
-					GFP_KERNEL | __GFP_NOWARN, nid);
-			if (!base)
-				base = vmalloc_node(table_size, nid);
-		} else {
-			base = __alloc_bootmem_node_nopanic(NODE_DATA(nid),
-				table_size,
-				PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
-		}
+		VM_BUG_ON(!slab_is_available());
+		base = kmalloc_node(table_size,
+				GFP_KERNEL | __GFP_NOWARN, nid);
+		if (!base)
+			base = vmalloc_node(table_size, nid);
 	} else {
 		/*
  		 * We don't have to allocate page_cgroup again, but
diff --git a/mm/slab.c b/mm/slab.c
index f46b65d..18e3164 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -304,6 +304,12 @@
 };
 
 /*
+ * The slab allocator is initialized with interrupts disabled. Therefore, make
+ * sure early boot allocations don't accidentally enable interrupts.
+ */
+static gfp_t slab_gfp_mask __read_mostly = SLAB_GFP_BOOT_MASK;
+
+/*
  * Need this for bootstrapping a per node allocator.
  */
 #define NUM_INIT_LISTS (3 * MAX_NUMNODES)
@@ -753,6 +759,7 @@
 	NONE,
 	PARTIAL_AC,
 	PARTIAL_L3,
+	EARLY,
 	FULL
 } g_cpucache_up;
 
@@ -761,7 +768,7 @@
  */
 int slab_is_available(void)
 {
-	return g_cpucache_up == FULL;
+	return g_cpucache_up >= EARLY;
 }
 
 static DEFINE_PER_CPU(struct delayed_work, reap_work);
@@ -1625,19 +1632,27 @@
 		}
 	}
 
-	/* 6) resize the head arrays to their final sizes */
-	{
-		struct kmem_cache *cachep;
-		mutex_lock(&cache_chain_mutex);
-		list_for_each_entry(cachep, &cache_chain, next)
-			if (enable_cpucache(cachep, GFP_NOWAIT))
-				BUG();
-		mutex_unlock(&cache_chain_mutex);
-	}
+	g_cpucache_up = EARLY;
 
 	/* Annotate slab for lockdep -- annotate the malloc caches */
 	init_lock_keys();
+}
 
+void __init kmem_cache_init_late(void)
+{
+	struct kmem_cache *cachep;
+
+	/*
+	 * Interrupts are enabled now so all GFP allocations are safe.
+	 */
+	slab_gfp_mask = __GFP_BITS_MASK;
+
+	/* 6) resize the head arrays to their final sizes */
+	mutex_lock(&cache_chain_mutex);
+	list_for_each_entry(cachep, &cache_chain, next)
+		if (enable_cpucache(cachep, GFP_NOWAIT))
+			BUG();
+	mutex_unlock(&cache_chain_mutex);
 
 	/* Done! */
 	g_cpucache_up = FULL;
@@ -2102,7 +2117,7 @@
 			for_each_online_node(node) {
 				cachep->nodelists[node] =
 				    kmalloc_node(sizeof(struct kmem_list3),
-						GFP_KERNEL, node);
+						gfp, node);
 				BUG_ON(!cachep->nodelists[node]);
 				kmem_list3_init(cachep->nodelists[node]);
 			}
@@ -3354,6 +3369,8 @@
 	unsigned long save_flags;
 	void *ptr;
 
+	flags &= slab_gfp_mask;
+
 	lockdep_trace_alloc(flags);
 
 	if (slab_should_failslab(cachep, flags))
@@ -3434,6 +3451,8 @@
 	unsigned long save_flags;
 	void *objp;
 
+	flags &= slab_gfp_mask;
+
 	lockdep_trace_alloc(flags);
 
 	if (slab_should_failslab(cachep, flags))
diff --git a/mm/slub.c b/mm/slub.c
index 3964d3c..30354bf 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -178,6 +178,12 @@
 	SYSFS		/* Sysfs up */
 } slab_state = DOWN;
 
+/*
+ * The slab allocator is initialized with interrupts disabled. Therefore, make
+ * sure early boot allocations don't accidentally enable interrupts.
+ */
+static gfp_t slab_gfp_mask __read_mostly = SLAB_GFP_BOOT_MASK;
+
 /* A list of all slab caches on the system */
 static DECLARE_RWSEM(slub_lock);
 static LIST_HEAD(slab_caches);
@@ -1595,6 +1601,8 @@
 	unsigned long flags;
 	unsigned int objsize;
 
+	gfpflags &= slab_gfp_mask;
+
 	lockdep_trace_alloc(gfpflags);
 	might_sleep_if(gfpflags & __GFP_WAIT);
 
@@ -3104,6 +3112,14 @@
 		nr_cpu_ids, nr_node_ids);
 }
 
+void __init kmem_cache_init_late(void)
+{
+	/*
+	 * Interrupts are enabled now so all GFP allocations are safe.
+	 */
+	slab_gfp_mask = __GFP_BITS_MASK;
+}
+
 /*
  * Find a mergeable slab cache
  */
diff --git a/mm/vmscan.c b/mm/vmscan.c
index d254306..95c08a8 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2056,7 +2056,7 @@
 		+ global_page_state(NR_INACTIVE_FILE);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_HIBERNATION
 /*
  * Helper function for shrink_all_memory().  Tries to reclaim 'nr_pages' pages
  * from LRU lists system-wide, for given pass and priority.
@@ -2196,7 +2196,7 @@
 
 	return sc.nr_reclaimed;
 }
-#endif
+#endif /* CONFIG_HIBERNATION */
 
 /* It's optimal to keep kswapds on the same CPUs as their memory, but
    not required for correctness.  So if the last cpu in a node goes
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index bb8579a..a49484e 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -246,7 +246,7 @@
 	chan->vdev = vdev;
 
 	/* We expect one virtqueue, for requests. */
-	chan->vq = vdev->config->find_vq(vdev, 0, req_done);
+	chan->vq = virtio_find_single_vq(vdev, req_done, "requests");
 	if (IS_ERR(chan->vq)) {
 		err = PTR_ERR(chan->vq);
 		goto out_free_vq;
@@ -261,7 +261,7 @@
 	return 0;
 
 out_free_vq:
-	vdev->config->del_vq(chan->vq);
+	vdev->config->del_vqs(vdev);
 fail:
 	mutex_lock(&virtio_9p_lock);
 	chan_index--;
@@ -332,7 +332,7 @@
 	BUG_ON(chan->inuse);
 
 	if (chan->initialized) {
-		vdev->config->del_vq(chan->vq);
+		vdev->config->del_vqs(vdev);
 		chan->initialized = false;
 	}
 }
diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh
index 60d00d1..66ad375 100755
--- a/scripts/checksyscalls.sh
+++ b/scripts/checksyscalls.sh
@@ -14,6 +14,57 @@
 #include <asm/types.h>
 #include <asm/unistd.h>
 
+/* *at */
+#define __IGNORE_open		/* openat */
+#define __IGNORE_link		/* linkat */
+#define __IGNORE_unlink		/* unlinkat */
+#define __IGNORE_mknod		/* mknodat */
+#define __IGNORE_chmod		/* fchmodat */
+#define __IGNORE_chown		/* fchownat */
+#define __IGNORE_mkdir		/* mkdirat */
+#define __IGNORE_rmdir		/* unlinkat */
+#define __IGNORE_lchown		/* fchownat */
+#define __IGNORE_access		/* faccessat */
+#define __IGNORE_rename		/* renameat */
+#define __IGNORE_readlink	/* readlinkat */
+#define __IGNORE_symlink	/* symlinkat */
+#define __IGNORE_utimes		/* futimesat */
+#if BITS_PER_LONG == 64
+#define __IGNORE_stat		/* fstatat */
+#define __IGNORE_lstat		/* fstatat */
+#else
+#define __IGNORE_stat64		/* fstatat64 */
+#define __IGNORE_lstat64	/* fstatat64 */
+#endif
+
+/* CLOEXEC flag */
+#define __IGNORE_pipe		/* pipe2 */
+#define __IGNORE_dup2		/* dup3 */
+#define __IGNORE_epoll_create	/* epoll_create1 */
+#define __IGNORE_inotify_init	/* inotify_init1 */
+#define __IGNORE_eventfd	/* eventfd2 */
+#define __IGNORE_signalfd	/* signalfd4 */
+
+/* MMU */
+#ifndef CONFIG_MMU
+#define __IGNORE_madvise
+#define __IGNORE_mbind
+#define __IGNORE_mincore
+#define __IGNORE_mlock
+#define __IGNORE_mlockall
+#define __IGNORE_munlock
+#define __IGNORE_munlockall
+#define __IGNORE_mprotect
+#define __IGNORE_msync
+#define __IGNORE_migrate_pages
+#define __IGNORE_move_pages
+#define __IGNORE_remap_file_pages
+#define __IGNORE_get_mempolicy
+#define __IGNORE_set_mempolicy
+#define __IGNORE_swapoff
+#define __IGNORE_swapon
+#endif
+
 /* System calls for 32-bit kernels only */
 #if BITS_PER_LONG == 64
 #define __IGNORE_sendfile64
@@ -27,6 +78,22 @@
 #define __IGNORE_fstatat64
 #define __IGNORE_fstatfs64
 #define __IGNORE_statfs64
+#define __IGNORE_llseek
+#define __IGNORE_mmap2
+#else
+#define __IGNORE_sendfile
+#define __IGNORE_ftruncate
+#define __IGNORE_truncate
+#define __IGNORE_stat
+#define __IGNORE_lstat
+#define __IGNORE_fstat
+#define __IGNORE_fcntl
+#define __IGNORE_fadvise64
+#define __IGNORE_newfstatat
+#define __IGNORE_fstatfs
+#define __IGNORE_statfs
+#define __IGNORE_lseek
+#define __IGNORE_mmap
 #endif
 
 /* i386-specific or historical system calls */
@@ -44,7 +111,6 @@
 #define __IGNORE_idle
 #define __IGNORE_modify_ldt
 #define __IGNORE_ugetrlimit
-#define __IGNORE_mmap2
 #define __IGNORE_vm86
 #define __IGNORE_vm86old
 #define __IGNORE_set_thread_area
@@ -55,7 +121,6 @@
 #define __IGNORE_oldlstat
 #define __IGNORE_oldolduname
 #define __IGNORE_olduname
-#define __IGNORE_umount2
 #define __IGNORE_umount
 #define __IGNORE_waitpid
 #define __IGNORE_stime
@@ -75,9 +140,12 @@
 #define __IGNORE__llseek
 #define __IGNORE__newselect
 #define __IGNORE_create_module
-#define __IGNORE_delete_module
 #define __IGNORE_query_module
 #define __IGNORE_get_kernel_syms
+#define __IGNORE_sysfs
+#define __IGNORE_uselib
+#define __IGNORE__sysctl
+
 /* ... including the "new" 32-bit uid syscalls */
 #define __IGNORE_lchown32
 #define __IGNORE_getuid32
@@ -99,6 +167,24 @@
 #define __IGNORE_setfsuid32
 #define __IGNORE_setfsgid32
 
+/* these can be expressed using other calls */
+#define __IGNORE_alarm		/* setitimer */
+#define __IGNORE_creat		/* open */
+#define __IGNORE_fork		/* clone */
+#define __IGNORE_futimesat	/* utimensat */
+#define __IGNORE_getpgrp	/* getpgid */
+#define __IGNORE_getdents	/* getdents64 */
+#define __IGNORE_pause		/* sigsuspend */
+#define __IGNORE_poll		/* ppoll */
+#define __IGNORE_select		/* pselect6 */
+#define __IGNORE_epoll_wait	/* epoll_pwait */
+#define __IGNORE_time		/* gettimeofday */
+#define __IGNORE_uname		/* newuname */
+#define __IGNORE_ustat		/* statfs */
+#define __IGNORE_utime		/* utimes */
+#define __IGNORE_vfork		/* clone */
+#define __IGNORE_wait4		/* waitid */
+
 /* sync_file_range had a stupid ABI. Allow sync_file_range2 instead */
 #ifdef __NR_sync_file_range2
 #define __IGNORE_sync_file_range
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index a334428..40e0045 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -641,7 +641,7 @@
 	id->vendor = TO_NATIVE(id->vendor);
 
 	strcpy(alias, "virtio:");
-	ADD(alias, "d", 1, id->device);
+	ADD(alias, "d", id->device != VIRTIO_DEV_ANY_ID, id->device);
 	ADD(alias, "v", id->vendor != VIRTIO_DEV_ANY_ID, id->vendor);
 
 	add_wildcard(alias);
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
index 0fae7da..91033e6 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -185,6 +185,19 @@
     $objcopy .= " -O elf32-i386";
     $cc .= " -m32";
 
+} elsif ($arch eq "s390" && $bits == 32) {
+    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_32\\s+_mcount\$";
+    $alignment = 4;
+    $ld .= " -m elf_s390";
+    $cc .= " -m31";
+
+} elsif ($arch eq "s390" && $bits == 64) {
+    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
+    $alignment = 8;
+    $type = ".quad";
+    $ld .= " -m elf64_s390";
+    $cc .= " -m64";
+
 } elsif ($arch eq "sh") {
     $alignment = 2;
 
diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c
index fbf5c93..586965f 100644
--- a/sound/aoa/fabrics/layout.c
+++ b/sound/aoa/fabrics/layout.c
@@ -1037,7 +1037,7 @@
 	}
 	ldev->selfptr_headphone.ptr = ldev;
 	ldev->selfptr_lineout.ptr = ldev;
-	sdev->ofdev.dev.driver_data = ldev;
+	dev_set_drvdata(&sdev->ofdev.dev, ldev);
 	list_add(&ldev->list, &layouts_list);
 	layouts_list_items++;
 
@@ -1081,7 +1081,7 @@
 
 static int aoa_fabric_layout_remove(struct soundbus_dev *sdev)
 {
-	struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+	struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev);
 	int i;
 
 	for (i=0; i<MAX_CODECS_PER_BUS; i++) {
@@ -1114,7 +1114,7 @@
 #ifdef CONFIG_PM
 static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t state)
 {
-	struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+	struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev);
 
 	if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
 		ldev->gpio.methods->all_amps_off(&ldev->gpio);
@@ -1124,7 +1124,7 @@
 
 static int aoa_fabric_layout_resume(struct soundbus_dev *sdev)
 {
-	struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+	struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev);
 
 	if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
 		ldev->gpio.methods->all_amps_restore(&ldev->gpio);
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c
index 418c84c..4e3b819 100644
--- a/sound/aoa/soundbus/i2sbus/core.c
+++ b/sound/aoa/soundbus/i2sbus/core.c
@@ -358,14 +358,14 @@
 		return -ENODEV;
 	}
 
-	dev->ofdev.dev.driver_data = control;
+	dev_set_drvdata(&dev->ofdev.dev, control);
 
 	return 0;
 }
 
 static int i2sbus_remove(struct macio_dev* dev)
 {
-	struct i2sbus_control *control = dev->ofdev.dev.driver_data;
+	struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev);
 	struct i2sbus_dev *i2sdev, *tmp;
 
 	list_for_each_entry_safe(i2sdev, tmp, &control->list, item)
@@ -377,7 +377,7 @@
 #ifdef CONFIG_PM
 static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
 {
-	struct i2sbus_control *control = dev->ofdev.dev.driver_data;
+	struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev);
 	struct codec_info_item *cii;
 	struct i2sbus_dev* i2sdev;
 	int err, ret = 0;
@@ -407,7 +407,7 @@
 
 static int i2sbus_resume(struct macio_dev* dev)
 {
-	struct i2sbus_control *control = dev->ofdev.dev.driver_data;
+	struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev);
 	struct codec_info_item *cii;
 	struct i2sbus_dev* i2sdev;
 	int err, ret = 0;
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index 5c48e36..dc78272 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -1089,7 +1089,7 @@
 		goto out;
 	}
 
-	aaci->base = ioremap(dev->res.start, SZ_4K);
+	aaci->base = ioremap(dev->res.start, resource_size(&dev->res));
 	if (!aaci->base) {
 		ret = -ENOMEM;
 		goto out;
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index 7bbdda0..6061fb5 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -205,3 +205,5 @@
 
 config SND_VMASTER
 	bool
+
+source "sound/core/seq/Kconfig"
diff --git a/sound/core/init.c b/sound/core/init.c
index fd56afe..d5d40d7 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -152,15 +152,8 @@
 	card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
 	if (!card)
 		return -ENOMEM;
-	if (xid) {
-		if (!snd_info_check_reserved_words(xid)) {
-			snd_printk(KERN_ERR
-				   "given id string '%s' is reserved.\n", xid);
-			err = -EBUSY;
-			goto __error;
-		}
+	if (xid)
 		strlcpy(card->id, xid, sizeof(card->id));
-	}
 	err = 0;
 	mutex_lock(&snd_card_mutex);
 	if (idx < 0) {
@@ -483,22 +476,28 @@
 
 EXPORT_SYMBOL(snd_card_free);
 
-static void choose_default_id(struct snd_card *card)
+static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid)
 {
 	int i, len, idx_flag = 0, loops = SNDRV_CARDS;
-	char *id, *spos;
+	const char *spos, *src;
+	char *id;
 	
-	id = spos = card->shortname;	
-	while (*id != '\0') {
-		if (*id == ' ')
-			spos = id + 1;
-		id++;
+	if (nid == NULL) {
+		id = card->shortname;
+		spos = src = id;
+		while (*id != '\0') {
+			if (*id == ' ')
+				spos = id + 1;
+			id++;
+		}
+	} else {
+		spos = src = nid;
 	}
 	id = card->id;
 	while (*spos != '\0' && !isalnum(*spos))
 		spos++;
 	if (isdigit(*spos))
-		*id++ = isalpha(card->shortname[0]) ? card->shortname[0] : 'D';
+		*id++ = isalpha(src[0]) ? src[0] : 'D';
 	while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) {
 		if (isalnum(*spos))
 			*id++ = *spos;
@@ -513,7 +512,7 @@
 
 	while (1) {
 	      	if (loops-- == 0) {
-      			snd_printk(KERN_ERR "unable to choose default card id (%s)\n", id);
+			snd_printk(KERN_ERR "unable to set card id (%s)\n", id);
       			strcpy(card->id, card->proc_root->name);
       			return;
       		}
@@ -539,14 +538,33 @@
 			spos = id + len - 2;
 			if ((size_t)len <= sizeof(card->id) - 2)
 				spos++;
-			*spos++ = '_';
-			*spos++ = '1';
-			*spos++ = '\0';
+			*(char *)spos++ = '_';
+			*(char *)spos++ = '1';
+			*(char *)spos++ = '\0';
 			idx_flag++;
 		}
 	}
 }
 
+/**
+ *  snd_card_set_id - set card identification name
+ *  @card: soundcard structure
+ *  @nid: new identification string
+ *
+ *  This function sets the card identification and checks for name
+ *  collisions.
+ */
+void snd_card_set_id(struct snd_card *card, const char *nid)
+{
+	/* check if user specified own card->id */
+	if (card->id[0] != '\0')
+		return;
+	mutex_lock(&snd_card_mutex);
+	snd_card_set_id_no_lock(card, nid);
+	mutex_unlock(&snd_card_mutex);
+}
+EXPORT_SYMBOL(snd_card_set_id);
+
 #ifndef CONFIG_SYSFS_DEPRECATED
 static ssize_t
 card_id_show_attr(struct device *dev,
@@ -640,8 +658,7 @@
 		mutex_unlock(&snd_card_mutex);
 		return 0;
 	}
-	if (card->id[0] == '\0')
-		choose_default_id(card);
+	snd_card_set_id_no_lock(card, card->id[0] == '\0' ? NULL : card->id);
 	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 d54d1a0..f705eec 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -63,7 +63,7 @@
 
 	/* Default to the sound card device. */
 	if (!jack->input_dev->dev.parent)
-		jack->input_dev->dev.parent = card->dev;
+		jack->input_dev->dev.parent = snd_card_get_device_link(card);
 
 	err = input_register_device(jack->input_dev);
 	if (err == 0)
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index dda000b..dbe406b 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -31,6 +31,7 @@
 #include <linux/time.h>
 #include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
+#include <linux/math64.h>
 #include <linux/string.h>
 #include <sound/core.h>
 #include <sound/minors.h>
@@ -617,9 +618,7 @@
 #else
 	{
 		u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes;
-		u32 rem;
-		div64_32(&bsize, buffer_size, &rem);
-		return (long)bsize;
+		return div_u64(bsize, buffer_size);
 	}
 #endif
 }
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index d659995..333e4dd 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -22,6 +22,7 @@
 
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/math64.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -126,24 +127,37 @@
 }
 
 #ifdef CONFIG_SND_PCM_XRUN_DEBUG
-#define xrun_debug(substream)	((substream)->pstr->xrun_debug)
+#define xrun_debug(substream, mask)	((substream)->pstr->xrun_debug & (mask))
 #else
-#define xrun_debug(substream)	0
+#define xrun_debug(substream, mask)	0
 #endif
 
-#define dump_stack_on_xrun(substream) do {	\
-		if (xrun_debug(substream) > 1)	\
-			dump_stack();		\
+#define dump_stack_on_xrun(substream) do {		\
+		if (xrun_debug(substream, 2))		\
+			dump_stack();			\
 	} while (0)
 
+static void pcm_debug_name(struct snd_pcm_substream *substream,
+			   char *name, size_t len)
+{
+	snprintf(name, len, "pcmC%dD%d%c:%d",
+		 substream->pcm->card->number,
+		 substream->pcm->device,
+		 substream->stream ? 'c' : 'p',
+		 substream->number);
+}
+
 static void xrun(struct snd_pcm_substream *substream)
 {
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+		snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
 	snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-	if (xrun_debug(substream)) {
-		snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n",
-			   substream->pcm->card->number,
-			   substream->pcm->device,
-			   substream->stream ? 'c' : 'p');
+	if (xrun_debug(substream, 1)) {
+		char name[16];
+		pcm_debug_name(substream, name, sizeof(name));
+		snd_printd(KERN_DEBUG "XRUN: %s\n", name);
 		dump_stack_on_xrun(substream);
 	}
 }
@@ -154,16 +168,16 @@
 {
 	snd_pcm_uframes_t pos;
 
-	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
-		snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
 	pos = substream->ops->pointer(substream);
 	if (pos == SNDRV_PCM_POS_XRUN)
 		return pos; /* XRUN */
 	if (pos >= runtime->buffer_size) {
 		if (printk_ratelimit()) {
-			snd_printd(KERN_ERR  "BUG: stream = %i, pos = 0x%lx, "
+			char name[16];
+			pcm_debug_name(substream, name, sizeof(name));
+			snd_printd(KERN_ERR  "BUG: %s, pos = 0x%lx, "
 				   "buffer size = 0x%lx, period size = 0x%lx\n",
-				   substream->stream, pos, runtime->buffer_size,
+				   name, pos, runtime->buffer_size,
 				   runtime->period_size);
 		}
 		pos = 0;
@@ -197,7 +211,7 @@
 
 #define hw_ptr_error(substream, fmt, args...)				\
 	do {								\
-		if (xrun_debug(substream)) {				\
+		if (xrun_debug(substream, 1)) {				\
 			if (printk_ratelimit()) {			\
 				snd_printd("PCM: " fmt, ##args);	\
 			}						\
@@ -251,7 +265,7 @@
 	}
 
 	/* Do jiffies check only in xrun_debug mode */
-	if (!xrun_debug(substream))
+	if (!xrun_debug(substream, 4))
 		goto no_jiffies_check;
 
 	/* Skip the jiffies check for hardwares with BATCH flag.
@@ -261,6 +275,9 @@
 	if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
 		goto no_jiffies_check;
 	hdelta = new_hw_ptr - old_hw_ptr;
+	if (hdelta < runtime->delay)
+		goto no_jiffies_check;
+	hdelta -= runtime->delay;
 	jdelta = jiffies - runtime->hw_ptr_jiffies;
 	if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) {
 		delta = jdelta /
@@ -294,14 +311,20 @@
 		hw_ptr_interrupt =
 			new_hw_ptr - new_hw_ptr % runtime->period_size;
 	}
+	runtime->hw_ptr_interrupt = hw_ptr_interrupt;
+
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
 	    runtime->silence_size > 0)
 		snd_pcm_playback_silence(substream, new_hw_ptr);
 
+	if (runtime->status->hw_ptr == new_hw_ptr)
+		return 0;
+
 	runtime->hw_ptr_base = hw_base;
 	runtime->status->hw_ptr = new_hw_ptr;
 	runtime->hw_ptr_jiffies = jiffies;
-	runtime->hw_ptr_interrupt = hw_ptr_interrupt;
+	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+		snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
 
 	return snd_pcm_update_hw_ptr_post(substream, runtime);
 }
@@ -342,8 +365,12 @@
 		new_hw_ptr = hw_base + pos;
 	}
 	/* Do jiffies check only in xrun_debug mode */
-	if (xrun_debug(substream) &&
-	    ((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
+	if (!xrun_debug(substream, 4))
+		goto no_jiffies_check;
+	if (delta < runtime->delay)
+		goto no_jiffies_check;
+	delta -= runtime->delay;
+	if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
 		hw_ptr_error(substream,
 			     "hw_ptr skipping! "
 			     "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
@@ -352,13 +379,19 @@
 			     ((delta * HZ) / runtime->rate));
 		return 0;
 	}
+ no_jiffies_check:
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
 	    runtime->silence_size > 0)
 		snd_pcm_playback_silence(substream, new_hw_ptr);
 
+	if (runtime->status->hw_ptr == new_hw_ptr)
+		return 0;
+
 	runtime->hw_ptr_base = hw_base;
 	runtime->status->hw_ptr = new_hw_ptr;
 	runtime->hw_ptr_jiffies = jiffies;
+	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+		snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
 
 	return snd_pcm_update_hw_ptr_post(substream, runtime);
 }
@@ -452,7 +485,7 @@
 		*r = 0;
 		return UINT_MAX;
 	}
-	div64_32(&n, c, r);
+	n = div_u64_rem(n, c, r);
 	if (n >= UINT_MAX) {
 		*r = 0;
 		return UINT_MAX;
@@ -1524,6 +1557,23 @@
 	return 0;
 }
 
+static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream,
+				       void *arg)
+{
+	struct snd_pcm_hw_params *params = arg;
+	snd_pcm_format_t format;
+	int channels, width;
+
+	params->fifo_size = substream->runtime->hw.fifo_size;
+	if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) {
+		format = params_format(params);
+		channels = params_channels(params);
+		width = snd_pcm_format_physical_width(format);
+		params->fifo_size /= width * channels;
+	}
+	return 0;
+}
+
 /**
  * snd_pcm_lib_ioctl - a generic PCM ioctl callback
  * @substream: the pcm substream instance
@@ -1545,6 +1595,8 @@
 		return snd_pcm_lib_ioctl_reset(substream, arg);
 	case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
 		return snd_pcm_lib_ioctl_channel_info(substream, arg);
+	case SNDRV_PCM_IOCTL1_FIFO_SIZE:
+		return snd_pcm_lib_ioctl_fifo_size(substream, arg);
 	}
 	return -ENXIO;
 }
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index b5da656..84da3ba 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -312,9 +312,18 @@
 
 	hw = &substream->runtime->hw;
 	if (!params->info)
-		params->info = hw->info;
-	if (!params->fifo_size)
-		params->fifo_size = hw->fifo_size;
+		params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
+	if (!params->fifo_size) {
+		if (snd_mask_min(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT]) ==
+		    snd_mask_max(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT]) &&
+                    snd_mask_min(&params->masks[SNDRV_PCM_HW_PARAM_CHANNELS]) ==
+                    snd_mask_max(&params->masks[SNDRV_PCM_HW_PARAM_CHANNELS])) {
+			changed = substream->ops->ioctl(substream,
+					SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
+			if (params < 0)
+				return changed;
+		}
+	}
 	params->rmask = 0;
 	return 0;
 }
@@ -587,14 +596,15 @@
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		status->avail = snd_pcm_playback_avail(runtime);
 		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING ||
-		    runtime->status->state == SNDRV_PCM_STATE_DRAINING)
+		    runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
 			status->delay = runtime->buffer_size - status->avail;
-		else
+			status->delay += runtime->delay;
+		} else
 			status->delay = 0;
 	} else {
 		status->avail = snd_pcm_capture_avail(runtime);
 		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-			status->delay = status->avail;
+			status->delay = status->avail + runtime->delay;
 		else
 			status->delay = 0;
 	}
@@ -2410,6 +2420,7 @@
 			n = snd_pcm_playback_hw_avail(runtime);
 		else
 			n = snd_pcm_capture_avail(runtime);
+		n += runtime->delay;
 		break;
 	case SNDRV_PCM_STATE_XRUN:
 		err = -EPIPE;
diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig
new file mode 100644
index 0000000..b851fd8
--- /dev/null
+++ b/sound/core/seq/Kconfig
@@ -0,0 +1,16 @@
+# define SND_XXX_SEQ to min(SND_SEQUENCER,SND_XXX)
+
+config SND_RAWMIDI_SEQ
+	def_tristate SND_SEQUENCER && SND_RAWMIDI
+
+config SND_OPL3_LIB_SEQ
+	def_tristate SND_SEQUENCER && SND_OPL3_LIB
+
+config SND_OPL4_LIB_SEQ
+	def_tristate SND_SEQUENCER && SND_OPL4_LIB
+
+config SND_SBAWE_SEQ
+	def_tristate SND_SEQUENCER && SND_SBAWE
+
+config SND_EMU10K1_SEQ
+	def_tristate SND_SEQUENCER && SND_EMU10K1
diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile
index 0695937..1bcb360 100644
--- a/sound/core/seq/Makefile
+++ b/sound/core/seq/Makefile
@@ -17,14 +17,6 @@
 snd-seq-dummy-objs := seq_dummy.o
 snd-seq-virmidi-objs := seq_virmidi.o
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o
 ifeq ($(CONFIG_SND_SEQUENCER_OSS),y)
 obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o
@@ -33,8 +25,8 @@
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o
-obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o
-obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o
-obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o
-obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o
-obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o
+obj-$(CONFIG_SND_RAWMIDI_SEQ) += snd-seq-midi.o snd-seq-midi-event.o
+obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o
+obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o
+obj-$(CONFIG_SND_SBAWE_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o
+obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o
diff --git a/sound/drivers/opl3/Makefile b/sound/drivers/opl3/Makefile
index 19767a6..7f2c2a1 100644
--- a/sound/drivers/opl3/Makefile
+++ b/sound/drivers/opl3/Makefile
@@ -7,14 +7,6 @@
 snd-opl3-synth-y := opl3_seq.o opl3_midi.o opl3_drums.o
 snd-opl3-synth-$(CONFIG_SND_SEQUENCER_OSS) += opl3_oss.o
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 obj-$(CONFIG_SND_OPL3_LIB) += snd-opl3-lib.o
 obj-$(CONFIG_SND_OPL4_LIB) += snd-opl3-lib.o
-obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-opl3-synth.o
+obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-opl3-synth.o
diff --git a/sound/drivers/opl4/Makefile b/sound/drivers/opl4/Makefile
index d178b39..b94009b 100644
--- a/sound/drivers/opl4/Makefile
+++ b/sound/drivers/opl4/Makefile
@@ -6,13 +6,5 @@
 snd-opl4-lib-objs := opl4_lib.o opl4_mixer.o opl4_proc.o
 snd-opl4-synth-objs := opl4_seq.o opl4_synth.o yrw801.o
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 obj-$(CONFIG_SND_OPL4_LIB) += snd-opl4-lib.o
-obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-opl4-synth.o
+obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-opl4-synth.o
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index c6942a4..51a7e37 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -177,15 +177,18 @@
 	  will be called snd-es18xx.
 
 config SND_SC6000
-	tristate "Gallant SC-6000, Audio Excel DSP 16"
+	tristate "Gallant SC-6000/6600/7000 and Audio Excel DSP 16"
 	depends on HAS_IOPORT
 	select SND_WSS_LIB
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
 	help
-	  Say Y here to include support for Gallant SC-6000 card and clones:
+	  Say Y here to include support for Gallant SC-6000, SC-6600, SC-7000
+	  cards and clones:
 	  Audio Excel DSP 16 and Zoltrix AV302.
 
+	  These cards are based on CompuMedia ASC-9308 or ASC-9408 chips.
+
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-sc6000.
 
diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c
index 442b081..07df201 100644
--- a/sound/isa/es1688/es1688.c
+++ b/sound/isa/es1688/es1688.c
@@ -193,7 +193,7 @@
 static struct isa_driver snd_es1688_driver = {
 	.match		= snd_es1688_match,
 	.probe		= snd_es1688_probe,
-	.remove		= snd_es1688_remove,
+	.remove		= __devexit_p(snd_es1688_remove),
 #if 0	/* FIXME */
 	.suspend	= snd_es1688_suspend,
 	.resume		= snd_es1688_resume,
diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c
index 180a8de..65e4b18 100644
--- a/sound/isa/gus/gusextreme.c
+++ b/sound/isa/gus/gusextreme.c
@@ -348,7 +348,7 @@
 static struct isa_driver snd_gusextreme_driver = {
 	.match		= snd_gusextreme_match,
 	.probe		= snd_gusextreme_probe,
-	.remove		= snd_gusextreme_remove,
+	.remove		= __devexit_p(snd_gusextreme_remove),
 #if 0	/* FIXME */
 	.suspend	= snd_gusextreme_suspend,
 	.resume		= snd_gusextreme_resume,
diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile
index 1098a56..faeffceb 100644
--- a/sound/isa/sb/Makefile
+++ b/sound/isa/sb/Makefile
@@ -13,14 +13,6 @@
 snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o
 snd-es968-objs := es968.o
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o
 obj-$(CONFIG_SND_SB16_DSP) += snd-sb16-dsp.o
@@ -33,4 +25,4 @@
   obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
   obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o
 endif
-obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emu8000-synth.o
+obj-$(CONFIG_SND_SBAWE_SEQ) += snd-emu8000-synth.o
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c
index 7820106..9a8bbf6 100644
--- a/sound/isa/sc6000.c
+++ b/sound/isa/sc6000.c
@@ -2,6 +2,8 @@
  *  Driver for Gallant SC-6000 soundcard. This card is also known as
  *  Audio Excel DSP 16 or Zoltrix AV302.
  *  These cards use CompuMedia ASC-9308 chip + AD1848 codec.
+ *  SC-6600 and SC-7000 cards are also supported. They are based on
+ *  CompuMedia ASC-9408 chip and CS4231 codec.
  *
  *  Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl>
  *
@@ -54,6 +56,7 @@
 						/* 0x300, 0x310, 0x320, 0x330 */
 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 5, 7, 9, 10, 0 */
 static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0, 1, 3 */
+static bool joystick[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = false };
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for sc-6000 based soundcard.");
@@ -73,6 +76,8 @@
 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for sc-6000 driver.");
 module_param_array(dma, int, NULL, 0444);
 MODULE_PARM_DESC(dma, "DMA # for sc-6000 driver.");
+module_param_array(joystick, bool, NULL, 0444);
+MODULE_PARM_DESC(joystick, "Enable gameport.");
 
 /*
  * Commands of SC6000's DSP (SBPRO+special).
@@ -191,7 +196,7 @@
 	return val;
 }
 
-static __devinit int sc6000_wait_data(char __iomem *vport)
+static int sc6000_wait_data(char __iomem *vport)
 {
 	int loop = 1000;
 	unsigned char val = 0;
@@ -206,7 +211,7 @@
 	return -EAGAIN;
 }
 
-static __devinit int sc6000_read(char __iomem *vport)
+static int sc6000_read(char __iomem *vport)
 {
 	if (sc6000_wait_data(vport))
 		return -EBUSY;
@@ -215,7 +220,7 @@
 
 }
 
-static __devinit int sc6000_write(char __iomem *vport, int cmd)
+static int sc6000_write(char __iomem *vport, int cmd)
 {
 	unsigned char val;
 	int loop = 500000;
@@ -276,8 +281,33 @@
 }
 
 /* detection and initialization */
-static int __devinit sc6000_cfg_write(char __iomem *vport,
-				      unsigned char softcfg)
+static int __devinit sc6000_hw_cfg_write(char __iomem *vport, const int *cfg)
+{
+	if (sc6000_write(vport, COMMAND_6C) < 0) {
+		snd_printk(KERN_WARNING "CMD 0x%x: failed!\n", COMMAND_6C);
+		return -EIO;
+	}
+	if (sc6000_write(vport, COMMAND_5C) < 0) {
+		snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_5C);
+		return -EIO;
+	}
+	if (sc6000_write(vport, cfg[0]) < 0) {
+		snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[0]);
+		return -EIO;
+	}
+	if (sc6000_write(vport, cfg[1]) < 0) {
+		snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[1]);
+		return -EIO;
+	}
+	if (sc6000_write(vport, COMMAND_C5) < 0) {
+		snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_C5);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int sc6000_cfg_write(char __iomem *vport, unsigned char softcfg)
 {
 
 	if (sc6000_write(vport, WRITE_MDIRQ_CFG)) {
@@ -291,7 +321,7 @@
 	return 0;
 }
 
-static int __devinit sc6000_setup_board(char __iomem *vport, int config)
+static int sc6000_setup_board(char __iomem *vport, int config)
 {
 	int loop = 10;
 
@@ -334,16 +364,39 @@
 	return 0;
 }
 
-static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma,
-					char __iomem *vmss_port, int mpu_irq)
+static void __devinit sc6000_hw_cfg_encode(char __iomem *vport, int *cfg,
+					   long xport, long xmpu,
+					   long xmss_port, int joystick)
+{
+	cfg[0] = 0;
+	cfg[1] = 0;
+	if (xport == 0x240)
+		cfg[0] |= 1;
+	if (xmpu != SNDRV_AUTO_PORT) {
+		cfg[0] |= (xmpu & 0x30) >> 2;
+		cfg[1] |= 0x20;
+	}
+	if (xmss_port == 0xe80)
+		cfg[0] |= 0x10;
+	cfg[0] |= 0x40;		/* always set */
+	if (!joystick)
+		cfg[0] |= 0x02;
+	cfg[1] |= 0x80;		/* enable WSS system */
+	cfg[1] &= ~0x40;	/* disable IDE */
+	snd_printd("hw cfg %x, %x\n", cfg[0], cfg[1]);
+}
+
+static int __devinit sc6000_init_board(char __iomem *vport,
+					char __iomem *vmss_port, int dev)
 {
 	char answer[15];
 	char version[2];
-	int mss_config = sc6000_irq_to_softcfg(irq) |
-			 sc6000_dma_to_softcfg(dma);
+	int mss_config = sc6000_irq_to_softcfg(irq[dev]) |
+			 sc6000_dma_to_softcfg(dma[dev]);
 	int config = mss_config |
-		     sc6000_mpu_irq_to_softcfg(mpu_irq);
+		     sc6000_mpu_irq_to_softcfg(mpu_irq[dev]);
 	int err;
+	int old = 0;
 
 	err = sc6000_dsp_reset(vport);
 	if (err < 0) {
@@ -360,7 +413,6 @@
 	/*
 	 * My SC-6000 card return "SC-6000" in DSPCopyright, so
 	 * if we have something different, we have to be warned.
-	 * Mine returns "SC-6000A " - KH
 	 */
 	if (strncmp("SC-6000", answer, 7))
 		snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n");
@@ -372,13 +424,32 @@
 	printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n",
 		answer, version[0], version[1]);
 
-	/*
-	 * 0x0A == (IRQ 7, DMA 1, MIRQ 0)
-	 */
-	err = sc6000_cfg_write(vport, 0x0a);
+	/* set configuration */
+	sc6000_write(vport, COMMAND_5C);
+	if (sc6000_read(vport) < 0)
+		old = 1;
+
+	if (!old) {
+		int cfg[2];
+		sc6000_hw_cfg_encode(vport, &cfg[0], port[dev], mpu_port[dev],
+				     mss_port[dev], joystick[dev]);
+		if (sc6000_hw_cfg_write(vport, cfg) < 0) {
+			snd_printk(KERN_ERR "sc6000_hw_cfg_write: failed!\n");
+			return -EIO;
+		}
+	}
+	err = sc6000_setup_board(vport, config);
 	if (err < 0) {
-		snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n");
-		return -EFAULT;
+		snd_printk(KERN_ERR "sc6000_setup_board: failed!\n");
+		return -ENODEV;
+	}
+
+	sc6000_dsp_reset(vport);
+
+	if (!old) {
+		sc6000_write(vport, COMMAND_60);
+		sc6000_write(vport, 0x02);
+		sc6000_dsp_reset(vport);
 	}
 
 	err = sc6000_setup_board(vport, config);
@@ -386,10 +457,9 @@
 		snd_printk(KERN_ERR "sc6000_setup_board: failed!\n");
 		return -ENODEV;
 	}
-
 	err = sc6000_init_mss(vport, config, vmss_port, mss_config);
 	if (err < 0) {
-		snd_printk(KERN_ERR "Can not initialize "
+		snd_printk(KERN_ERR "Cannot initialize "
 			   "Microsoft Sound System mode.\n");
 		return -ENODEV;
 	}
@@ -485,14 +555,16 @@
 	struct snd_card *card;
 	struct snd_wss *chip;
 	struct snd_opl3 *opl3;
-	char __iomem *vport;
+	char __iomem **vport;
 	char __iomem *vmss_port;
 
 
-	err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+	err = snd_card_create(index[dev], id[dev], THIS_MODULE, sizeof(vport),
+				&card);
 	if (err < 0)
 		return err;
 
+	vport = card->private_data;
 	if (xirq == SNDRV_AUTO_IRQ) {
 		xirq = snd_legacy_find_free_irq(possible_irqs);
 		if (xirq < 0) {
@@ -517,8 +589,8 @@
 		err = -EBUSY;
 		goto err_exit;
 	}
-	vport = devm_ioport_map(devptr, port[dev], 0x10);
-	if (!vport) {
+	*vport = devm_ioport_map(devptr, port[dev], 0x10);
+	if (*vport == NULL) {
 		snd_printk(KERN_ERR PFX
 			   "I/O port cannot be iomaped.\n");
 		err = -EBUSY;
@@ -533,7 +605,7 @@
 		goto err_unmap1;
 	}
 	vmss_port = devm_ioport_map(devptr, mss_port[dev], 4);
-	if (!vport) {
+	if (!vmss_port) {
 		snd_printk(KERN_ERR PFX
 			   "MSS port I/O cannot be iomaped.\n");
 		err = -EBUSY;
@@ -544,7 +616,7 @@
 		   port[dev], xirq, xdma,
 		   mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]);
 
-	err = sc6000_init_board(vport, xirq, xdma, vmss_port, mpu_irq[dev]);
+	err = sc6000_init_board(*vport, vmss_port, dev);
 	if (err < 0)
 		goto err_unmap2;
 
@@ -552,7 +624,6 @@
 			     WSS_HW_DETECT, 0, &chip);
 	if (err < 0)
 		goto err_unmap2;
-	card->private_data = chip;
 
 	err = snd_wss_pcm(chip, 0, NULL);
 	if (err < 0) {
@@ -608,6 +679,7 @@
 	return 0;
 
 err_unmap2:
+	sc6000_setup_board(*vport, 0);
 	release_region(mss_port[dev], 4);
 err_unmap1:
 	release_region(port[dev], 0x10);
@@ -618,11 +690,17 @@
 
 static int __devexit snd_sc6000_remove(struct device *devptr, unsigned int dev)
 {
+	struct snd_card *card = dev_get_drvdata(devptr);
+	char __iomem **vport = card->private_data;
+
+	if (sc6000_setup_board(*vport, 0) < 0)
+		snd_printk(KERN_WARNING "sc6000_setup_board failed on exit!\n");
+
 	release_region(port[dev], 0x10);
 	release_region(mss_port[dev], 4);
 
-	snd_card_free(dev_get_drvdata(devptr));
 	dev_set_drvdata(devptr, NULL);
+	snd_card_free(card);
 	return 0;
 }
 
diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c
index 66f3b48..e497525 100644
--- a/sound/mips/sgio2audio.c
+++ b/sound/mips/sgio2audio.c
@@ -619,8 +619,7 @@
 /* hw_free callback */
 static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-	if (substream->runtime->dma_area)
-		vfree(substream->runtime->dma_area);
+	vfree(substream->runtime->dma_area);
 	substream->runtime->dma_area = NULL;
 	return 0;
 }
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index 6055fd6..e924492 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -935,7 +935,7 @@
 	h->iobase = ioremap_nocache(padev->hpa.start, HARMONY_SIZE);
 	if (h->iobase == NULL) {
 		printk(KERN_ERR PFX "unable to remap hpa 0x%lx\n",
-		       padev->hpa.start);
+		       (unsigned long)padev->hpa.start);
 		err = -EBUSY;
 		goto free_and_ret;
 	}
@@ -1020,7 +1020,7 @@
 	.name = "harmony",
 	.id_table = snd_harmony_devtable,
 	.probe = snd_harmony_probe,
-	.remove = snd_harmony_remove,
+	.remove = __devexit_p(snd_harmony_remove),
 };
 
 static int __init 
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 93422e3..748f6b7 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -275,6 +275,16 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-cs5535audio.
 
+config SND_CTXFI
+	tristate "Creative Sound Blaster X-Fi"
+	select SND_PCM
+	help
+	  If you want to use soundcards based on Creative Sound Blastr X-Fi
+	  boards with 20k1 or 20k2 chips, say Y here.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-ctxfi.
+
 config SND_DARLA20
 	tristate "(Echoaudio) Darla20"
 	select FW_LOADER
@@ -532,6 +542,9 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-hdsp.
 
+comment "Don't forget to add built-in firmwares for HDSP driver"
+	depends on SND_HDSP=y
+
 config SND_HDSPM
 	tristate "RME Hammerfall DSP MADI"
 	select SND_HWDEP
@@ -622,6 +635,16 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-korg1212.
 
+config SND_LX6464ES
+	tristate "Digigram LX6464ES"
+	select SND_PCM
+	help
+	  Say Y here to include support for Digigram LX6464ES boards.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-lx6464es.
+
+
 config SND_MAESTRO3
 	tristate "ESS Allegro/Maestro3"
 	select SND_AC97_CODEC
@@ -764,8 +787,8 @@
 	select SND_OXYGEN_LIB
 	help
 	  Say Y here to include support for sound cards based on the
-	  Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, and
-	  Essence STX.
+	  Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X,
+	  Essence ST (Deluxe), and Essence STX.
 	  Support for the HDAV1.3 (Deluxe) is very experimental.
 
 	  To compile this driver as a module, choose M here: the module
diff --git a/sound/pci/Makefile b/sound/pci/Makefile
index 65b25d2..ecfc609 100644
--- a/sound/pci/Makefile
+++ b/sound/pci/Makefile
@@ -59,9 +59,11 @@
 	ali5451/ \
 	au88x0/ \
 	aw2/ \
+	ctxfi/ \
 	ca0106/ \
 	cs46xx/ \
 	cs5535audio/ \
+	lx6464es/ \
 	echoaudio/ \
 	emu10k1/ \
 	hda/ \
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index 3906f5a..23f49f3 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -1255,8 +1255,8 @@
 	int temp;
 
 	temp = hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2));
-	temp = (dma->period_virt * dma->period_bytes) + (temp & POS_MASK);
-	return (temp);
+	temp = (dma->period_virt * dma->period_bytes) + (temp & (dma->period_bytes - 1));
+	return temp;
 }
 
 static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma)
@@ -1504,8 +1504,7 @@
 	int temp;
 
 	temp = hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2));
-	//temp = (temp & POS_MASK) + (((temp>>WT_SUBBUF_SHIFT) & WT_SUBBUF_MASK)*(dma->cfg0&POS_MASK));
-	temp = (temp & POS_MASK) + ((dma->period_virt) * (dma->period_bytes));
+	temp = (dma->period_virt * dma->period_bytes) + (temp & (dma->period_bytes - 1));
 	return temp;
 }
 
@@ -2441,7 +2440,8 @@
 		spin_lock(&vortex->lock);
 		for (i = 0; i < NR_ADB; i++) {
 			if (vortex->dma_adb[i].fifo_status == FIFO_START) {
-				if (vortex_adbdma_bufshift(vortex, i)) ;
+				if (!vortex_adbdma_bufshift(vortex, i))
+					continue;
 				spin_unlock(&vortex->lock);
 				snd_pcm_period_elapsed(vortex->dma_adb[i].
 						       substream);
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index ce3f2e9..24585c6 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -810,6 +810,8 @@
 	BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, GENERIC),
 	/* Voodoo TV 200 */
 	BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, GENERIC),
+	/* Askey Computer Corp. MagicTView'99 */
+	BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x144f, 0x3000, GENERIC),
 	/* AVerMedia Studio No. 103, 203, ...? */
 	BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, AVPHONE98),
 	/* Prolink PixelView PV-M4900 */
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index bfac30f..57b992a 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1319,7 +1319,6 @@
         }
 
 	pcm->info_flags = 0;
-	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
 	strcpy(pcm->name, "CA0106");
 
 	for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index c111efe..c8c6f43 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -739,7 +739,7 @@
 	} while (0)
 
 static __devinitdata
-DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 50, 1);
+DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 25, 1);
 
 static char *slave_vols[] __devinitdata = {
 	"Analog Front Playback Volume",
@@ -841,6 +841,9 @@
 					      snd_ca0106_master_db_scale);
 	if (!vmaster)
 		return -ENOMEM;
+	err = snd_ctl_add(card, vmaster);
+	if (err < 0)
+		return err;
 	add_slaves(card, vmaster, slave_vols);
 
 	if (emu->details->spi_dac == 1) {
@@ -848,8 +851,13 @@
 						      NULL);
 		if (!vmaster)
 			return -ENOMEM;
+		err = snd_ctl_add(card, vmaster);
+		if (err < 0)
+			return err;
 		add_slaves(card, vmaster, slave_sws);
 	}
+
+	strcpy(card->mixername, "CA0106");
         return 0;
 }
 
diff --git a/sound/pci/ctxfi/Makefile b/sound/pci/ctxfi/Makefile
new file mode 100644
index 0000000..15075f8
--- /dev/null
+++ b/sound/pci/ctxfi/Makefile
@@ -0,0 +1,5 @@
+snd-ctxfi-objs := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \
+	ctsrc.o ctamixer.o ctdaio.o ctimap.o cthardware.o cttimer.o \
+	cthw20k2.o cthw20k1.o
+
+obj-$(CONFIG_SND_CTXFI) += snd-ctxfi.o
diff --git a/sound/pci/ctxfi/ct20k1reg.h b/sound/pci/ctxfi/ct20k1reg.h
new file mode 100644
index 0000000..f2e34e3
--- /dev/null
+++ b/sound/pci/ctxfi/ct20k1reg.h
@@ -0,0 +1,636 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ */
+
+#ifndef CT20K1REG_H
+#define CT20k1REG_H
+
+/* 20k1 registers */
+#define 	DSPXRAM_START 			0x000000
+#define 	DSPXRAM_END 			0x013FFC
+#define 	DSPAXRAM_START 			0x020000
+#define 	DSPAXRAM_END 			0x023FFC
+#define 	DSPYRAM_START 			0x040000
+#define 	DSPYRAM_END 			0x04FFFC
+#define 	DSPAYRAM_START 			0x020000
+#define 	DSPAYRAM_END 			0x063FFC
+#define 	DSPMICRO_START 			0x080000
+#define 	DSPMICRO_END 			0x0B3FFC
+#define 	DSP0IO_START 			0x100000
+#define 	DSP0IO_END	 		0x101FFC
+#define 	AUDIORINGIPDSP0_START 		0x100000
+#define 	AUDIORINGIPDSP0_END 		0x1003FC
+#define 	AUDIORINGOPDSP0_START 		0x100400
+#define 	AUDIORINGOPDSP0_END 		0x1007FC
+#define 	AUDPARARINGIODSP0_START 	0x100800
+#define 	AUDPARARINGIODSP0_END	 	0x100BFC
+#define 	DSP0LOCALHWREG_START 		0x100C00
+#define 	DSP0LOCALHWREG_END	 	0x100C3C
+#define 	DSP0XYRAMAGINDEX_START 		0x100C40
+#define 	DSP0XYRAMAGINDEX_END	 	0x100C5C
+#define 	DSP0XYRAMAGMDFR_START 		0x100C60
+#define 	DSP0XYRAMAGMDFR_END	 	0x100C7C
+#define 	DSP0INTCONTLVEC_START 		0x100C80
+#define 	DSP0INTCONTLVEC_END	 	0x100CD8
+#define 	INTCONTLGLOBALREG_START 	0x100D1C
+#define 	INTCONTLGLOBALREG_END	 	0x100D3C
+#define		HOSTINTFPORTADDRCONTDSP0	0x100D40
+#define		HOSTINTFPORTDATADSP0		0x100D44
+#define		TIME0PERENBDSP0			0x100D60
+#define		TIME0COUNTERDSP0		0x100D64
+#define		TIME1PERENBDSP0			0x100D68
+#define		TIME1COUNTERDSP0		0x100D6C
+#define		TIME2PERENBDSP0			0x100D70
+#define		TIME2COUNTERDSP0		0x100D74
+#define		TIME3PERENBDSP0			0x100D78
+#define		TIME3COUNTERDSP0		0x100D7C
+#define 	XRAMINDOPERREFNOUP_STARTDSP0 	0x100D80
+#define 	XRAMINDOPERREFNOUP_ENDDSP0	0x100D9C
+#define 	XRAMINDOPERREFUP_STARTDSP0	0x100DA0
+#define 	XRAMINDOPERREFUP_ENDDSP0	0x100DBC
+#define 	YRAMINDOPERREFNOUP_STARTDSP0 	0x100DC0
+#define 	YRAMINDOPERREFNOUP_ENDDSP0 	0x100DDC
+#define 	YRAMINDOPERREFUP_STARTDSP0	0x100DE0
+#define 	YRAMINDOPERREFUP_ENDDSP0 	0x100DFC
+#define 	DSP0CONDCODE 			0x100E00
+#define 	DSP0STACKFLAG 			0x100E04
+#define 	DSP0PROGCOUNTSTACKPTREG 	0x100E08
+#define 	DSP0PROGCOUNTSTACKDATAREG 	0x100E0C
+#define 	DSP0CURLOOPADDRREG 		0x100E10
+#define 	DSP0CURLOOPCOUNT 		0x100E14
+#define 	DSP0TOPLOOPCOUNTSTACK 		0x100E18
+#define 	DSP0TOPLOOPADDRSTACK 		0x100E1C
+#define 	DSP0LOOPSTACKPTR 		0x100E20
+#define 	DSP0STASSTACKDATAREG 		0x100E24
+#define 	DSP0STASSTACKPTR 		0x100E28
+#define 	DSP0PROGCOUNT 			0x100E2C
+#define  	GLOBDSPDEBGREG			0x100E30
+#define  	GLOBDSPBREPTRREG		0x100E30
+#define 	DSP0XYRAMBASE_START 		0x100EA0
+#define 	DSP0XYRAMBASE_END 		0x100EBC
+#define 	DSP0XYRAMLENG_START 		0x100EC0
+#define 	DSP0XYRAMLENG_END 		0x100EDC
+#define		SEMAPHOREREGDSP0		0x100EE0
+#define		DSP0INTCONTMASKREG		0x100EE4
+#define		DSP0INTCONTPENDREG		0x100EE8
+#define		DSP0INTCONTSERVINT		0x100EEC
+#define		DSPINTCONTEXTINTMODREG		0x100EEC
+#define		GPIODSP0			0x100EFC
+#define 	DMADSPBASEADDRREG_STARTDSP0	0x100F00
+#define 	DMADSPBASEADDRREG_ENDDSP0	0x100F1C
+#define 	DMAHOSTBASEADDRREG_STARTDSP0	0x100F20
+#define 	DMAHOSTBASEADDRREG_ENDDSP0	0x100F3C
+#define 	DMADSPCURADDRREG_STARTDSP0	0x100F40
+#define 	DMADSPCURADDRREG_ENDDSP0	0x100F5C
+#define 	DMAHOSTCURADDRREG_STARTDSP0	0x100F60
+#define 	DMAHOSTCURADDRREG_ENDDSP0	0x100F7C
+#define 	DMATANXCOUNTREG_STARTDSP0	0x100F80
+#define 	DMATANXCOUNTREG_ENDDSP0		0x100F9C
+#define 	DMATIMEBUGREG_STARTDSP0		0x100FA0
+#define 	DMATIMEBUGREG_ENDDSP0		0x100FAC
+#define 	DMACNTLMODFREG_STARTDSP0	0x100FA0
+#define 	DMACNTLMODFREG_ENDDSP0		0x100FAC
+
+#define 	DMAGLOBSTATSREGDSP0		0x100FEC
+#define 	DSP0XGPRAM_START 		0x101000
+#define 	DSP0XGPRAM_END 			0x1017FC
+#define 	DSP0YGPRAM_START 		0x101800
+#define 	DSP0YGPRAM_END 			0x101FFC
+
+
+
+
+#define 	AUDIORINGIPDSP1_START 		0x102000
+#define 	AUDIORINGIPDSP1_END	 	0x1023FC
+#define 	AUDIORINGOPDSP1_START 		0x102400
+#define 	AUDIORINGOPDSP1_END	 	0x1027FC
+#define 	AUDPARARINGIODSP1_START 	0x102800
+#define 	AUDPARARINGIODSP1_END	 	0x102BFC
+#define 	DSP1LOCALHWREG_START 		0x102C00
+#define 	DSP1LOCALHWREG_END	 	0x102C3C
+#define 	DSP1XYRAMAGINDEX_START 		0x102C40
+#define 	DSP1XYRAMAGINDEX_END	 	0x102C5C
+#define 	DSP1XYRAMAGMDFR_START 		0x102C60
+#define 	DSP1XYRAMAGMDFR_END	 	0x102C7C
+#define 	DSP1INTCONTLVEC_START 		0x102C80
+#define 	DSP1INTCONTLVEC_END	 	0x102CD8
+#define		HOSTINTFPORTADDRCONTDSP1	0x102D40
+#define		HOSTINTFPORTDATADSP1		0x102D44
+#define		TIME0PERENBDSP1			0x102D60
+#define		TIME0COUNTERDSP1		0x102D64
+#define		TIME1PERENBDSP1			0x102D68
+#define		TIME1COUNTERDSP1		0x102D6C
+#define		TIME2PERENBDSP1			0x102D70
+#define		TIME2COUNTERDSP1		0x102D74
+#define		TIME3PERENBDSP1			0x102D78
+#define		TIME3COUNTERDSP1		0x102D7C
+#define 	XRAMINDOPERREFNOUP_STARTDSP1 	0x102D80
+#define 	XRAMINDOPERREFNOUP_ENDDSP1	0x102D9C
+#define 	XRAMINDOPERREFUP_STARTDSP1	0x102DA0
+#define 	XRAMINDOPERREFUP_ENDDSP1	0x102DBC
+#define 	YRAMINDOPERREFNOUP_STARTDSP1 	0x102DC0
+#define 	YRAMINDOPERREFNOUP_ENDDSP1	0x102DDC
+#define 	YRAMINDOPERREFUP_STARTDSP1	0x102DE0
+#define 	YRAMINDOPERREFUP_ENDDSP1	0x102DFC
+
+#define 	DSP1CONDCODE 			0x102E00
+#define 	DSP1STACKFLAG 			0x102E04
+#define 	DSP1PROGCOUNTSTACKPTREG 	0x102E08
+#define 	DSP1PROGCOUNTSTACKDATAREG 	0x102E0C
+#define 	DSP1CURLOOPADDRREG 		0x102E10
+#define 	DSP1CURLOOPCOUNT 		0x102E14
+#define 	DSP1TOPLOOPCOUNTSTACK 		0x102E18
+#define 	DSP1TOPLOOPADDRSTACK 		0x102E1C
+#define 	DSP1LOOPSTACKPTR 		0x102E20
+#define 	DSP1STASSTACKDATAREG 		0x102E24
+#define 	DSP1STASSTACKPTR 		0x102E28
+#define 	DSP1PROGCOUNT 			0x102E2C
+#define 	DSP1XYRAMBASE_START 		0x102EA0
+#define 	DSP1XYRAMBASE_END 		0x102EBC
+#define 	DSP1XYRAMLENG_START 		0x102EC0
+#define 	DSP1XYRAMLENG_END 		0x102EDC
+#define		SEMAPHOREREGDSP1		0x102EE0
+#define		DSP1INTCONTMASKREG		0x102EE4
+#define		DSP1INTCONTPENDREG		0x102EE8
+#define		DSP1INTCONTSERVINT		0x102EEC
+#define		GPIODSP1			0x102EFC
+#define 	DMADSPBASEADDRREG_STARTDSP1	0x102F00
+#define 	DMADSPBASEADDRREG_ENDDSP1	0x102F1C
+#define 	DMAHOSTBASEADDRREG_STARTDSP1	0x102F20
+#define 	DMAHOSTBASEADDRREG_ENDDSP1	0x102F3C
+#define 	DMADSPCURADDRREG_STARTDSP1	0x102F40
+#define 	DMADSPCURADDRREG_ENDDSP1	0x102F5C
+#define 	DMAHOSTCURADDRREG_STARTDSP1	0x102F60
+#define 	DMAHOSTCURADDRREG_ENDDSP1	0x102F7C
+#define 	DMATANXCOUNTREG_STARTDSP1	0x102F80
+#define 	DMATANXCOUNTREG_ENDDSP1		0x102F9C
+#define 	DMATIMEBUGREG_STARTDSP1		0x102FA0
+#define 	DMATIMEBUGREG_ENDDSP1		0x102FAC
+#define 	DMACNTLMODFREG_STARTDSP1	0x102FA0
+#define 	DMACNTLMODFREG_ENDDSP1		0x102FAC
+
+#define 	DMAGLOBSTATSREGDSP1		0x102FEC
+#define 	DSP1XGPRAM_START 		0x103000
+#define 	DSP1XGPRAM_END 			0x1033FC
+#define 	DSP1YGPRAM_START 		0x103400
+#define 	DSP1YGPRAM_END 			0x1037FC
+
+
+
+#define 	AUDIORINGIPDSP2_START 		0x104000
+#define 	AUDIORINGIPDSP2_END	 	0x1043FC
+#define 	AUDIORINGOPDSP2_START 		0x104400
+#define 	AUDIORINGOPDSP2_END	 	0x1047FC
+#define 	AUDPARARINGIODSP2_START 	0x104800
+#define 	AUDPARARINGIODSP2_END	 	0x104BFC
+#define 	DSP2LOCALHWREG_START 		0x104C00
+#define 	DSP2LOCALHWREG_END	 	0x104C3C
+#define 	DSP2XYRAMAGINDEX_START 		0x104C40
+#define 	DSP2XYRAMAGINDEX_END	 	0x104C5C
+#define 	DSP2XYRAMAGMDFR_START 		0x104C60
+#define 	DSP2XYRAMAGMDFR_END		0x104C7C
+#define 	DSP2INTCONTLVEC_START 		0x104C80
+#define 	DSP2INTCONTLVEC_END	 	0x104CD8
+#define		HOSTINTFPORTADDRCONTDSP2	0x104D40
+#define		HOSTINTFPORTDATADSP2		0x104D44
+#define		TIME0PERENBDSP2			0x104D60
+#define		TIME0COUNTERDSP2		0x104D64
+#define		TIME1PERENBDSP2			0x104D68
+#define		TIME1COUNTERDSP2		0x104D6C
+#define		TIME2PERENBDSP2			0x104D70
+#define		TIME2COUNTERDSP2		0x104D74
+#define		TIME3PERENBDSP2			0x104D78
+#define		TIME3COUNTERDSP2		0x104D7C
+#define 	XRAMINDOPERREFNOUP_STARTDSP2 	0x104D80
+#define 	XRAMINDOPERREFNOUP_ENDDSP2	0x104D9C
+#define 	XRAMINDOPERREFUP_STARTDSP2	0x104DA0
+#define 	XRAMINDOPERREFUP_ENDDSP2	0x104DBC
+#define 	YRAMINDOPERREFNOUP_STARTDSP2 	0x104DC0
+#define 	YRAMINDOPERREFNOUP_ENDDSP2	0x104DDC
+#define 	YRAMINDOPERREFUP_STARTDSP2	0x104DE0
+#define 	YRAMINDOPERREFUP_ENDDSP2 	0x104DFC
+#define 	DSP2CONDCODE 			0x104E00
+#define 	DSP2STACKFLAG 			0x104E04
+#define 	DSP2PROGCOUNTSTACKPTREG 	0x104E08
+#define 	DSP2PROGCOUNTSTACKDATAREG 	0x104E0C
+#define 	DSP2CURLOOPADDRREG 		0x104E10
+#define 	DSP2CURLOOPCOUNT 		0x104E14
+#define 	DSP2TOPLOOPCOUNTSTACK 		0x104E18
+#define 	DSP2TOPLOOPADDRSTACK 		0x104E1C
+#define 	DSP2LOOPSTACKPTR 		0x104E20
+#define 	DSP2STASSTACKDATAREG 		0x104E24
+#define 	DSP2STASSTACKPTR 		0x104E28
+#define 	DSP2PROGCOUNT 			0x104E2C
+#define 	DSP2XYRAMBASE_START 		0x104EA0
+#define 	DSP2XYRAMBASE_END 		0x104EBC
+#define 	DSP2XYRAMLENG_START 		0x104EC0
+#define 	DSP2XYRAMLENG_END 		0x104EDC
+#define		SEMAPHOREREGDSP2		0x104EE0
+#define		DSP2INTCONTMASKREG		0x104EE4
+#define		DSP2INTCONTPENDREG		0x104EE8
+#define		DSP2INTCONTSERVINT		0x104EEC
+#define		GPIODSP2			0x104EFC
+#define 	DMADSPBASEADDRREG_STARTDSP2	0x104F00
+#define 	DMADSPBASEADDRREG_ENDDSP2	0x104F1C
+#define 	DMAHOSTBASEADDRREG_STARTDSP2	0x104F20
+#define 	DMAHOSTBASEADDRREG_ENDDSP2	0x104F3C
+#define 	DMADSPCURADDRREG_STARTDSP2	0x104F40
+#define 	DMADSPCURADDRREG_ENDDSP2	0x104F5C
+#define 	DMAHOSTCURADDRREG_STARTDSP2	0x104F60
+#define 	DMAHOSTCURADDRREG_ENDDSP2	0x104F7C
+#define 	DMATANXCOUNTREG_STARTDSP2	0x104F80
+#define 	DMATANXCOUNTREG_ENDDSP2		0x104F9C
+#define 	DMATIMEBUGREG_STARTDSP2		0x104FA0
+#define 	DMATIMEBUGREG_ENDDSP2		0x104FAC
+#define 	DMACNTLMODFREG_STARTDSP2	0x104FA0
+#define 	DMACNTLMODFREG_ENDDSP2		0x104FAC
+
+#define 	DMAGLOBSTATSREGDSP2		0x104FEC
+#define 	DSP2XGPRAM_START 		0x105000
+#define 	DSP2XGPRAM_END 			0x1051FC
+#define 	DSP2YGPRAM_START 		0x105800
+#define 	DSP2YGPRAM_END 			0x1059FC
+
+
+
+#define 	AUDIORINGIPDSP3_START 		0x106000
+#define 	AUDIORINGIPDSP3_END	 	0x1063FC
+#define 	AUDIORINGOPDSP3_START 		0x106400
+#define 	AUDIORINGOPDSP3_END	 	0x1067FC
+#define 	AUDPARARINGIODSP3_START 	0x106800
+#define 	AUDPARARINGIODSP3_END	 	0x106BFC
+#define 	DSP3LOCALHWREG_START 		0x106C00
+#define 	DSP3LOCALHWREG_END	 	0x106C3C
+#define 	DSP3XYRAMAGINDEX_START 		0x106C40
+#define 	DSP3XYRAMAGINDEX_END	 	0x106C5C
+#define 	DSP3XYRAMAGMDFR_START 		0x106C60
+#define 	DSP3XYRAMAGMDFR_END		0x106C7C
+#define 	DSP3INTCONTLVEC_START 		0x106C80
+#define 	DSP3INTCONTLVEC_END	 	0x106CD8
+#define		HOSTINTFPORTADDRCONTDSP3	0x106D40
+#define		HOSTINTFPORTDATADSP3		0x106D44
+#define		TIME0PERENBDSP3			0x106D60
+#define		TIME0COUNTERDSP3		0x106D64
+#define		TIME1PERENBDSP3			0x106D68
+#define		TIME1COUNTERDSP3		0x106D6C
+#define		TIME2PERENBDSP3			0x106D70
+#define		TIME2COUNTERDSP3		0x106D74
+#define		TIME3PERENBDSP3			0x106D78
+#define		TIME3COUNTERDSP3		0x106D7C
+#define 	XRAMINDOPERREFNOUP_STARTDSP3 	0x106D80
+#define 	XRAMINDOPERREFNOUP_ENDDSP3	0x106D9C
+#define 	XRAMINDOPERREFUP_STARTDSP3	0x106DA0
+#define 	XRAMINDOPERREFUP_ENDDSP3	0x106DBC
+#define 	YRAMINDOPERREFNOUP_STARTDSP3 	0x106DC0
+#define 	YRAMINDOPERREFNOUP_ENDDSP3	0x106DDC
+#define 	YRAMINDOPERREFUP_STARTDSP3	0x106DE0
+#define 	YRAMINDOPERREFUP_ENDDSP3	0x100DFC
+
+#define 	DSP3CONDCODE 			0x106E00
+#define 	DSP3STACKFLAG 			0x106E04
+#define 	DSP3PROGCOUNTSTACKPTREG 	0x106E08
+#define 	DSP3PROGCOUNTSTACKDATAREG 	0x106E0C
+#define 	DSP3CURLOOPADDRREG 		0x106E10
+#define 	DSP3CURLOOPCOUNT 		0x106E14
+#define 	DSP3TOPLOOPCOUNTSTACK 		0x106E18
+#define 	DSP3TOPLOOPADDRSTACK 		0x106E1C
+#define 	DSP3LOOPSTACKPTR 		0x106E20
+#define 	DSP3STASSTACKDATAREG 		0x106E24
+#define 	DSP3STASSTACKPTR 		0x106E28
+#define 	DSP3PROGCOUNT 			0x106E2C
+#define 	DSP3XYRAMBASE_START 		0x106EA0
+#define 	DSP3XYRAMBASE_END 		0x106EBC
+#define 	DSP3XYRAMLENG_START 		0x106EC0
+#define 	DSP3XYRAMLENG_END 		0x106EDC
+#define		SEMAPHOREREGDSP3		0x106EE0
+#define		DSP3INTCONTMASKREG		0x106EE4
+#define		DSP3INTCONTPENDREG		0x106EE8
+#define		DSP3INTCONTSERVINT		0x106EEC
+#define		GPIODSP3			0x106EFC
+#define 	DMADSPBASEADDRREG_STARTDSP3	0x106F00
+#define 	DMADSPBASEADDRREG_ENDDSP3	0x106F1C
+#define 	DMAHOSTBASEADDRREG_STARTDSP3	0x106F20
+#define 	DMAHOSTBASEADDRREG_ENDDSP3	0x106F3C
+#define 	DMADSPCURADDRREG_STARTDSP3	0x106F40
+#define 	DMADSPCURADDRREG_ENDDSP3	0x106F5C
+#define 	DMAHOSTCURADDRREG_STARTDSP3	0x106F60
+#define 	DMAHOSTCURADDRREG_ENDDSP3	0x106F7C
+#define 	DMATANXCOUNTREG_STARTDSP3	0x106F80
+#define 	DMATANXCOUNTREG_ENDDSP3		0x106F9C
+#define 	DMATIMEBUGREG_STARTDSP3		0x106FA0
+#define 	DMATIMEBUGREG_ENDDSP3		0x106FAC
+#define 	DMACNTLMODFREG_STARTDSP3	0x106FA0
+#define 	DMACNTLMODFREG_ENDDSP3		0x106FAC
+
+#define 	DMAGLOBSTATSREGDSP3		0x106FEC
+#define 	DSP3XGPRAM_START 		0x107000
+#define 	DSP3XGPRAM_END 			0x1071FC
+#define 	DSP3YGPRAM_START 		0x107800
+#define 	DSP3YGPRAM_END 			0x1079FC
+
+/* end of DSP reg definitions */
+
+#define  	DSPAIMAP_START			0x108000
+#define  	DSPAIMAP_END			0x1083FC
+#define  	DSPPIMAP_START			0x108400
+#define  	DSPPIMAP_END			0x1087FC
+#define  	DSPPOMAP_START			0x108800
+#define  	DSPPOMAP_END			0x108BFC
+#define  	DSPPOCTL			0x108C00
+#define 	TKCTL_START			0x110000
+#define 	TKCTL_END			0x110FFC
+#define 	TKCC_START			0x111000
+#define 	TKCC_END			0x111FFC
+#define 	TKIMAP_START			0x112000
+#define 	TKIMAP_END			0x112FFC
+#define		TKDCTR16			0x113000
+#define		TKPB16				0x113004
+#define		TKBS16				0x113008
+#define		TKDCTR32			0x11300C
+#define		TKPB32				0x113010
+#define		TKBS32				0x113014
+#define		ICDCTR16			0x113018
+#define		ITBS16				0x11301C
+#define		ICDCTR32			0x113020
+#define		ITBS32				0x113024
+#define		ITSTART				0x113028
+#define		TKSQ				0x11302C
+
+#define		TKSCCTL_START			0x114000
+#define		TKSCCTL_END			0x11403C
+#define		TKSCADR_START			0x114100
+#define		TKSCADR_END			0x11413C
+#define		TKSCDATAX_START			0x114800
+#define		TKSCDATAX_END			0x1149FC
+#define		TKPCDATAX_START			0x120000
+#define		TKPCDATAX_END			0x12FFFC
+
+#define		MALSA				0x130000
+#define		MAPPHA				0x130004
+#define		MAPPLA				0x130008
+#define		MALSB				0x130010
+#define		MAPPHB				0x130014
+#define		MAPPLB				0x130018
+
+#define 	TANSPORTMAPABREGS_START		0x130020
+#define 	TANSPORTMAPABREGS_END		0x13A2FC
+
+#define		PTPAHX				0x13B000
+#define		PTPALX				0x13B004
+
+#define		TANSPPAGETABLEPHYADDR015_START	0x13B008
+#define		TANSPPAGETABLEPHYADDR015_END	0x13B07C
+#define		TRNQADRX_START			0x13B100
+#define		TRNQADRX_END			0x13B13C
+#define		TRNQTIMX_START			0x13B200
+#define		TRNQTIMX_END			0x13B23C
+#define		TRNQAPARMX_START		0x13B300
+#define		TRNQAPARMX_END			0x13B33C
+
+#define		TRNQCNT				0x13B400
+#define		TRNCTL				0x13B404
+#define		TRNIS				0x13B408
+#define		TRNCURTS			0x13B40C
+
+#define		AMOP_START			0x140000
+#define		AMOPLO				0x140000
+#define		AMOPHI				0x140004
+#define		AMOP_END			0x147FFC
+#define		PMOP_START			0x148000
+#define		PMOPLO				0x148000
+#define		PMOPHI				0x148004
+#define		PMOP_END			0x14FFFC
+#define		PCURR_START			0x150000
+#define		PCURR_END			0x153FFC
+#define		PTRAG_START			0x154000
+#define		PTRAG_END			0x157FFC
+#define		PSR_START			0x158000
+#define		PSR_END				0x15BFFC
+
+#define		PFSTAT4SEG_START		0x160000
+#define		PFSTAT4SEG_END			0x160BFC
+#define		PFSTAT2SEG_START		0x160C00
+#define		PFSTAT2SEG_END			0x1617FC
+#define		PFTARG4SEG_START		0x164000
+#define		PFTARG4SEG_END			0x164BFC
+#define		PFTARG2SEG_START		0x164C00
+#define		PFTARG2SEG_END			0x1657FC
+#define		PFSR4SEG_START			0x168000
+#define		PFSR4SEG_END			0x168BFC
+#define		PFSR2SEG_START			0x168C00
+#define		PFSR2SEG_END			0x1697FC
+#define		PCURRMS4SEG_START		0x16C000
+#define		PCURRMS4SEG_END			0x16CCFC
+#define		PCURRMS2SEG_START		0x16CC00
+#define		PCURRMS2SEG_END			0x16D7FC
+#define		PTARGMS4SEG_START		0x170000
+#define		PTARGMS4SEG_END			0x172FFC
+#define		PTARGMS2SEG_START		0x173000
+#define		PTARGMS2SEG_END			0x1747FC
+#define		PSRMS4SEG_START			0x170000
+#define		PSRMS4SEG_END			0x172FFC
+#define		PSRMS2SEG_START			0x173000
+#define		PSRMS2SEG_END			0x1747FC
+
+#define		PRING_LO_START			0x190000
+#define		PRING_LO_END			0x193FFC
+#define		PRING_HI_START			0x194000
+#define		PRING_HI_END			0x197FFC
+#define		PRING_LO_HI_START		0x198000
+#define		PRING_LO_HI			0x198000
+#define		PRING_LO_HI_END			0x19BFFC
+
+#define		PINTFIFO			0x1A0000
+#define		SRCCTL				0x1B0000
+#define		SRCCCR				0x1B0004
+#define		SRCIMAP				0x1B0008
+#define		SRCODDC				0x1B000C
+#define		SRCCA				0x1B0010
+#define		SRCCF				0x1B0014
+#define		SRCSA				0x1B0018
+#define		SRCLA				0x1B001C
+#define		SRCCTLSWR			0x1B0020
+
+/* SRC HERE */
+#define		SRCALBA				0x1B002C
+#define		SRCMCTL				0x1B012C
+#define		SRCCERR				0x1B022C
+#define		SRCITB				0x1B032C
+#define		SRCIPM				0x1B082C
+#define		SRCIP				0x1B102C
+#define		SRCENBSTAT			0x1B202C
+#define		SRCENBLO			0x1B212C
+#define		SRCENBHI			0x1B222C
+#define		SRCENBS				0x1B232C
+#define		SRCENB				0x1B282C
+#define		SRCENB07			0x1B282C
+#define		SRCENBS07			0x1B302C
+
+#define		SRCDN0Z				0x1B0030
+#define		SRCDN0Z0			0x1B0030
+#define		SRCDN0Z1			0x1B0034
+#define		SRCDN0Z2			0x1B0038
+#define		SRCDN0Z3			0x1B003C
+#define		SRCDN1Z				0x1B0040
+#define		SRCDN1Z0			0x1B0040
+#define		SRCDN1Z1			0x1B0044
+#define		SRCDN1Z2			0x1B0048
+#define		SRCDN1Z3			0x1B004C
+#define		SRCDN1Z4			0x1B0050
+#define		SRCDN1Z5			0x1B0054
+#define		SRCDN1Z6			0x1B0058
+#define		SRCDN1Z7			0x1B005C
+#define		SRCUPZ				0x1B0060
+#define		SRCUPZ0				0x1B0060
+#define		SRCUPZ1				0x1B0064
+#define		SRCUPZ2				0x1B0068
+#define		SRCUPZ3				0x1B006C
+#define		SRCUPZ4				0x1B0070
+#define		SRCUPZ5				0x1B0074
+#define		SRCUPZ6				0x1B0078
+#define		SRCUPZ7				0x1B007C
+#define		SRCCD0				0x1B0080
+#define		SRCCD1				0x1B0084
+#define		SRCCD2				0x1B0088
+#define		SRCCD3				0x1B008C
+#define		SRCCD4				0x1B0090
+#define		SRCCD5				0x1B0094
+#define		SRCCD6				0x1B0098
+#define		SRCCD7				0x1B009C
+#define		SRCCD8				0x1B00A0
+#define		SRCCD9				0x1B00A4
+#define		SRCCDA				0x1B00A8
+#define		SRCCDB				0x1B00AC
+#define		SRCCDC				0x1B00B0
+#define		SRCCDD				0x1B00B4
+#define		SRCCDE				0x1B00B8
+#define		SRCCDF				0x1B00BC
+#define		SRCCD10				0x1B00C0
+#define		SRCCD11				0x1B00C4
+#define		SRCCD12				0x1B00C8
+#define		SRCCD13				0x1B00CC
+#define		SRCCD14				0x1B00D0
+#define		SRCCD15				0x1B00D4
+#define		SRCCD16				0x1B00D8
+#define		SRCCD17				0x1B00DC
+#define		SRCCD18				0x1B00E0
+#define		SRCCD19				0x1B00E4
+#define		SRCCD1A				0x1B00E8
+#define		SRCCD1B				0x1B00EC
+#define		SRCCD1C				0x1B00F0
+#define		SRCCD1D				0x1B00F4
+#define		SRCCD1E				0x1B00F8
+#define		SRCCD1F				0x1B00FC
+
+#define		SRCCONTRBLOCK_START		0x1B0100
+#define		SRCCONTRBLOCK_END		0x1BFFFC
+#define		FILTOP_START	0x1C0000
+#define		FILTOP_END	0x1C05FC
+#define		FILTIMAP_START	0x1C0800
+#define		FILTIMAP_END	0x1C0DFC
+#define		FILTZ1_START	0x1C1000
+#define		FILTZ1_END	0x1C15FC
+#define		FILTZ2_START	0x1C1800
+#define		FILTZ2_END	0x1C1DFC
+#define		DAOIMAP_START	0x1C5000
+#define		DAOIMAP		0x1C5000
+#define		DAOIMAP_END	0x1C5124
+
+#define		AC97D		0x1C5400
+#define		AC97A		0x1C5404
+#define		AC97CTL		0x1C5408
+#define		I2SCTL		0x1C5420
+
+#define		SPOS		0x1C5440
+#define		SPOSA		0x1C5440
+#define		SPOSB		0x1C5444
+#define		SPOSC		0x1C5448
+#define		SPOSD		0x1C544C
+
+#define		SPISA		0x1C5450
+#define		SPISB		0x1C5454
+#define		SPISC		0x1C5458
+#define		SPISD		0x1C545C
+
+#define		SPFSCTL		0x1C5460
+
+#define		SPFS0		0x1C5468
+#define		SPFS1		0x1C546C
+#define		SPFS2		0x1C5470
+#define		SPFS3		0x1C5474
+#define		SPFS4		0x1C5478
+#define		SPFS5		0x1C547C
+
+#define		SPOCTL		0x1C5480
+#define		SPICTL		0x1C5484
+#define		SPISTS		0x1C5488
+#define		SPINTP		0x1C548C
+#define		SPINTE		0x1C5490
+#define		SPUTCTLAB	0x1C5494
+#define		SPUTCTLCD	0x1C5498
+
+#define		SRTSPA		0x1C54C0
+#define		SRTSPB		0x1C54C4
+#define		SRTSPC		0x1C54C8
+#define		SRTSPD		0x1C54CC
+
+#define		SRTSCTL		0x1C54D0
+#define		SRTSCTLA	0x1C54D0
+#define		SRTSCTLB	0x1C54D4
+#define		SRTSCTLC	0x1C54D8
+#define		SRTSCTLD	0x1C54DC
+
+#define		SRTI2S		0x1C54E0
+#define		SRTICTL		0x1C54F0
+
+#define		WC		0x1C6000
+#define		TIMR		0x1C6004
+# define	TIMR_IE		(1<<15)
+# define	TIMR_IP		(1<<14)
+
+#define		GIP		0x1C6010
+#define		GIE		0x1C6014
+#define		DIE		0x1C6018
+#define		DIC		0x1C601C
+#define		GPIO		0x1C6020
+#define		GPIOCTL		0x1C6024
+#define		GPIP		0x1C6028
+#define		GPIE		0x1C602C
+#define		DSPINT0		0x1C6030
+#define		DSPEIOC		0x1C6034
+#define		MUADAT		0x1C6040
+#define		MUACMD		0x1C6044
+#define 	MUASTAT		0x1C6044
+#define		MUBDAT		0x1C6048
+#define		MUBCMD		0x1C604C
+#define		MUBSTAT		0x1C604C
+#define		UARTCMA		0x1C6050
+#define		UARTCMB		0x1C6054
+#define		UARTIP		0x1C6058
+#define		UARTIE		0x1C605C
+#define		PLLCTL		0x1C6060
+#define		PLLDCD		0x1C6064
+#define		GCTL		0x1C6070
+#define		ID0		0x1C6080
+#define		ID1		0x1C6084
+#define		ID2		0x1C6088
+#define		ID3		0x1C608C
+#define		SDRCTL		0x1C7000
+
+
+#define I2SA_L    0x0L
+#define I2SA_R    0x1L
+#define I2SB_L    0x8L
+#define I2SB_R    0x9L
+#define I2SC_L    0x10L
+#define I2SC_R    0x11L
+#define I2SD_L    0x18L
+#define I2SD_R    0x19L
+
+#endif /* CT20K1REG_H */
+
+
diff --git a/sound/pci/ctxfi/ct20k2reg.h b/sound/pci/ctxfi/ct20k2reg.h
new file mode 100644
index 0000000..2d07986
--- /dev/null
+++ b/sound/pci/ctxfi/ct20k2reg.h
@@ -0,0 +1,85 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ */
+
+#ifndef _20K2REGISTERS_H_
+#define _20K2REGISTERS_H_
+
+
+/* Timer Registers */
+#define TIMER_TIMR          0x1B7004
+#define INTERRUPT_GIP       0x1B7010
+#define INTERRUPT_GIE       0x1B7014
+
+/* I2C Registers */
+#define I2C_IF_ADDRESS   0x1B9000
+#define I2C_IF_WDATA     0x1B9004
+#define I2C_IF_RDATA     0x1B9008
+#define I2C_IF_STATUS    0x1B900C
+#define I2C_IF_WLOCK     0x1B9010
+
+/* Global Control Registers */
+#define GLOBAL_CNTL_GCTL    0x1B7090
+
+/* PLL Registers */
+#define PLL_CTL 		0x1B7080
+#define PLL_STAT		0x1B7084
+#define PLL_ENB			0x1B7088
+
+/* SRC Registers */
+#define SRC_CTL             0x1A0000 /* 0x1A0000 + (256 * Chn) */
+#define SRC_CCR             0x1A0004 /* 0x1A0004 + (256 * Chn) */
+#define SRC_IMAP            0x1A0008 /* 0x1A0008 + (256 * Chn) */
+#define SRC_CA              0x1A0010 /* 0x1A0010 + (256 * Chn) */
+#define SRC_CF              0x1A0014 /* 0x1A0014 + (256 * Chn) */
+#define SRC_SA              0x1A0018 /* 0x1A0018 + (256 * Chn) */
+#define SRC_LA              0x1A001C /* 0x1A001C + (256 * Chn) */
+#define SRC_CTLSWR	    0x1A0020 /* 0x1A0020 + (256 * Chn) */
+#define SRC_CD		    0x1A0080 /* 0x1A0080 + (256 * Chn) + (4 * Regn) */
+#define SRC_MCTL		0x1A012C
+#define SRC_IP			0x1A102C /* 0x1A102C + (256 * Regn) */
+#define SRC_ENB			0x1A282C /* 0x1A282C + (256 * Regn) */
+#define SRC_ENBSTAT		0x1A202C
+#define SRC_ENBSA		0x1A232C
+#define SRC_DN0Z		0x1A0030
+#define SRC_DN1Z		0x1A0040
+#define SRC_UPZ			0x1A0060
+
+/* GPIO Registers */
+#define GPIO_DATA           0x1B7020
+#define GPIO_CTRL           0x1B7024
+
+/* Virtual memory registers */
+#define VMEM_PTPAL          0x1C6300 /* 0x1C6300 + (16 * Chn) */
+#define VMEM_PTPAH          0x1C6304 /* 0x1C6304 + (16 * Chn) */
+#define VMEM_CTL            0x1C7000
+
+/* Transport Registers */
+#define TRANSPORT_ENB       0x1B6000
+#define TRANSPORT_CTL       0x1B6004
+#define TRANSPORT_INT       0x1B6008
+
+/* Audio IO */
+#define AUDIO_IO_AIM        0x1B5000 /* 0x1B5000 + (0x04 * Chn) */
+#define AUDIO_IO_TX_CTL     0x1B5400 /* 0x1B5400 + (0x40 * Chn) */
+#define AUDIO_IO_TX_CSTAT_L 0x1B5408 /* 0x1B5408 + (0x40 * Chn) */
+#define AUDIO_IO_TX_CSTAT_H 0x1B540C /* 0x1B540C + (0x40 * Chn) */
+#define AUDIO_IO_RX_CTL     0x1B5410 /* 0x1B5410 + (0x40 * Chn) */
+#define AUDIO_IO_RX_SRT_CTL 0x1B5420 /* 0x1B5420 + (0x40 * Chn) */
+#define AUDIO_IO_MCLK       0x1B5600
+#define AUDIO_IO_TX_BLRCLK  0x1B5604
+#define AUDIO_IO_RX_BLRCLK  0x1B5608
+
+/* Mixer */
+#define MIXER_AMOPLO		0x130000 /* 0x130000 + (8 * Chn) [4095 : 0] */
+#define MIXER_AMOPHI		0x130004 /* 0x130004 + (8 * Chn) [4095 : 0] */
+#define MIXER_PRING_LO_HI	0x188000 /* 0x188000 + (4 * Chn) [4095 : 0] */
+#define MIXER_PMOPLO		0x138000 /* 0x138000 + (8 * Chn) [4095 : 0] */
+#define MIXER_PMOPHI		0x138004 /* 0x138004 + (8 * Chn) [4095 : 0] */
+#define MIXER_AR_ENABLE		0x19000C
+
+#endif
diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c
new file mode 100644
index 0000000..a1db51b3
--- /dev/null
+++ b/sound/pci/ctxfi/ctamixer.c
@@ -0,0 +1,488 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctamixer.c
+ *
+ * @Brief
+ * This file contains the implementation of the Audio Mixer
+ * resource management object.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 21 2008
+ *
+ */
+
+#include "ctamixer.h"
+#include "cthardware.h"
+#include <linux/slab.h>
+
+#define AMIXER_RESOURCE_NUM	256
+#define SUM_RESOURCE_NUM	256
+
+#define AMIXER_Y_IMMEDIATE	1
+
+#define BLANK_SLOT		4094
+
+static int amixer_master(struct rsc *rsc)
+{
+	rsc->conj = 0;
+	return rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0];
+}
+
+static int amixer_next_conj(struct rsc *rsc)
+{
+	rsc->conj++;
+	return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
+}
+
+static int amixer_index(const struct rsc *rsc)
+{
+	return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
+}
+
+static int amixer_output_slot(const struct rsc *rsc)
+{
+	return (amixer_index(rsc) << 4) + 0x4;
+}
+
+static struct rsc_ops amixer_basic_rsc_ops = {
+	.master		= amixer_master,
+	.next_conj	= amixer_next_conj,
+	.index		= amixer_index,
+	.output_slot	= amixer_output_slot,
+};
+
+static int amixer_set_input(struct amixer *amixer, struct rsc *rsc)
+{
+	struct hw *hw;
+
+	hw = amixer->rsc.hw;
+	hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE);
+	amixer->input = rsc;
+	if (NULL == rsc)
+		hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT);
+	else
+		hw->amixer_set_x(amixer->rsc.ctrl_blk,
+					rsc->ops->output_slot(rsc));
+
+	return 0;
+}
+
+/* y is a 14-bit immediate constant */
+static int amixer_set_y(struct amixer *amixer, unsigned int y)
+{
+	struct hw *hw;
+
+	hw = amixer->rsc.hw;
+	hw->amixer_set_y(amixer->rsc.ctrl_blk, y);
+
+	return 0;
+}
+
+static int amixer_set_invalid_squash(struct amixer *amixer, unsigned int iv)
+{
+	struct hw *hw;
+
+	hw = amixer->rsc.hw;
+	hw->amixer_set_iv(amixer->rsc.ctrl_blk, iv);
+
+	return 0;
+}
+
+static int amixer_set_sum(struct amixer *amixer, struct sum *sum)
+{
+	struct hw *hw;
+
+	hw = amixer->rsc.hw;
+	amixer->sum = sum;
+	if (NULL == sum) {
+		hw->amixer_set_se(amixer->rsc.ctrl_blk, 0);
+	} else {
+		hw->amixer_set_se(amixer->rsc.ctrl_blk, 1);
+		hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
+					sum->rsc.ops->index(&sum->rsc));
+	}
+
+	return 0;
+}
+
+static int amixer_commit_write(struct amixer *amixer)
+{
+	struct hw *hw;
+	unsigned int index;
+	int i;
+	struct rsc *input;
+	struct sum *sum;
+
+	hw = amixer->rsc.hw;
+	input = amixer->input;
+	sum = amixer->sum;
+
+	/* Program master and conjugate resources */
+	amixer->rsc.ops->master(&amixer->rsc);
+	if (NULL != input)
+		input->ops->master(input);
+
+	if (NULL != sum)
+		sum->rsc.ops->master(&sum->rsc);
+
+	for (i = 0; i < amixer->rsc.msr; i++) {
+		hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk);
+		if (NULL != input) {
+			hw->amixer_set_x(amixer->rsc.ctrl_blk,
+						input->ops->output_slot(input));
+			input->ops->next_conj(input);
+		}
+		if (NULL != sum) {
+			hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
+						sum->rsc.ops->index(&sum->rsc));
+			sum->rsc.ops->next_conj(&sum->rsc);
+		}
+		index = amixer->rsc.ops->output_slot(&amixer->rsc);
+		hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
+		amixer->rsc.ops->next_conj(&amixer->rsc);
+	}
+	amixer->rsc.ops->master(&amixer->rsc);
+	if (NULL != input)
+		input->ops->master(input);
+
+	if (NULL != sum)
+		sum->rsc.ops->master(&sum->rsc);
+
+	return 0;
+}
+
+static int amixer_commit_raw_write(struct amixer *amixer)
+{
+	struct hw *hw;
+	unsigned int index;
+
+	hw = amixer->rsc.hw;
+	index = amixer->rsc.ops->output_slot(&amixer->rsc);
+	hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
+
+	return 0;
+}
+
+static int amixer_get_y(struct amixer *amixer)
+{
+	struct hw *hw;
+
+	hw = amixer->rsc.hw;
+	return hw->amixer_get_y(amixer->rsc.ctrl_blk);
+}
+
+static int amixer_setup(struct amixer *amixer, struct rsc *input,
+			unsigned int scale, struct sum *sum)
+{
+	amixer_set_input(amixer, input);
+	amixer_set_y(amixer, scale);
+	amixer_set_sum(amixer, sum);
+	amixer_commit_write(amixer);
+	return 0;
+}
+
+static struct amixer_rsc_ops amixer_ops = {
+	.set_input		= amixer_set_input,
+	.set_invalid_squash	= amixer_set_invalid_squash,
+	.set_scale		= amixer_set_y,
+	.set_sum		= amixer_set_sum,
+	.commit_write		= amixer_commit_write,
+	.commit_raw_write	= amixer_commit_raw_write,
+	.setup			= amixer_setup,
+	.get_scale		= amixer_get_y,
+};
+
+static int amixer_rsc_init(struct amixer *amixer,
+			   const struct amixer_desc *desc,
+			   struct amixer_mgr *mgr)
+{
+	int err;
+
+	err = rsc_init(&amixer->rsc, amixer->idx[0],
+			AMIXER, desc->msr, mgr->mgr.hw);
+	if (err)
+		return err;
+
+	/* Set amixer specific operations */
+	amixer->rsc.ops = &amixer_basic_rsc_ops;
+	amixer->ops = &amixer_ops;
+	amixer->input = NULL;
+	amixer->sum = NULL;
+
+	amixer_setup(amixer, NULL, 0, NULL);
+
+	return 0;
+}
+
+static int amixer_rsc_uninit(struct amixer *amixer)
+{
+	amixer_setup(amixer, NULL, 0, NULL);
+	rsc_uninit(&amixer->rsc);
+	amixer->ops = NULL;
+	amixer->input = NULL;
+	amixer->sum = NULL;
+	return 0;
+}
+
+static int get_amixer_rsc(struct amixer_mgr *mgr,
+			  const struct amixer_desc *desc,
+			  struct amixer **ramixer)
+{
+	int err, i;
+	unsigned int idx;
+	struct amixer *amixer;
+	unsigned long flags;
+
+	*ramixer = NULL;
+
+	/* Allocate mem for amixer resource */
+	amixer = kzalloc(sizeof(*amixer), GFP_KERNEL);
+	if (NULL == amixer) {
+		err = -ENOMEM;
+		return err;
+	}
+
+	/* Check whether there are sufficient
+	 * amixer resources to meet request. */
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	for (i = 0; i < desc->msr; i++) {
+		err = mgr_get_resource(&mgr->mgr, 1, &idx);
+		if (err)
+			break;
+
+		amixer->idx[i] = idx;
+	}
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+	if (err) {
+		printk(KERN_ERR "ctxfi: Can't meet AMIXER resource request!\n");
+		goto error;
+	}
+
+	err = amixer_rsc_init(amixer, desc, mgr);
+	if (err)
+		goto error;
+
+	*ramixer = amixer;
+
+	return 0;
+
+error:
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	for (i--; i >= 0; i--)
+		mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
+
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+	kfree(amixer);
+	return err;
+}
+
+static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer)
+{
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	for (i = 0; i < amixer->rsc.msr; i++)
+		mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
+
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+	amixer_rsc_uninit(amixer);
+	kfree(amixer);
+
+	return 0;
+}
+
+int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr)
+{
+	int err;
+	struct amixer_mgr *amixer_mgr;
+
+	*ramixer_mgr = NULL;
+	amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL);
+	if (NULL == amixer_mgr)
+		return -ENOMEM;
+
+	err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw);
+	if (err)
+		goto error;
+
+	spin_lock_init(&amixer_mgr->mgr_lock);
+
+	amixer_mgr->get_amixer = get_amixer_rsc;
+	amixer_mgr->put_amixer = put_amixer_rsc;
+
+	*ramixer_mgr = amixer_mgr;
+
+	return 0;
+
+error:
+	kfree(amixer_mgr);
+	return err;
+}
+
+int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr)
+{
+	rsc_mgr_uninit(&amixer_mgr->mgr);
+	kfree(amixer_mgr);
+	return 0;
+}
+
+/* SUM resource management */
+
+static int sum_master(struct rsc *rsc)
+{
+	rsc->conj = 0;
+	return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
+}
+
+static int sum_next_conj(struct rsc *rsc)
+{
+	rsc->conj++;
+	return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
+}
+
+static int sum_index(const struct rsc *rsc)
+{
+	return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
+}
+
+static int sum_output_slot(const struct rsc *rsc)
+{
+	return (sum_index(rsc) << 4) + 0xc;
+}
+
+static struct rsc_ops sum_basic_rsc_ops = {
+	.master		= sum_master,
+	.next_conj	= sum_next_conj,
+	.index		= sum_index,
+	.output_slot	= sum_output_slot,
+};
+
+static int sum_rsc_init(struct sum *sum,
+			const struct sum_desc *desc,
+			struct sum_mgr *mgr)
+{
+	int err;
+
+	err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw);
+	if (err)
+		return err;
+
+	sum->rsc.ops = &sum_basic_rsc_ops;
+
+	return 0;
+}
+
+static int sum_rsc_uninit(struct sum *sum)
+{
+	rsc_uninit(&sum->rsc);
+	return 0;
+}
+
+static int get_sum_rsc(struct sum_mgr *mgr,
+		       const struct sum_desc *desc,
+		       struct sum **rsum)
+{
+	int err, i;
+	unsigned int idx;
+	struct sum *sum;
+	unsigned long flags;
+
+	*rsum = NULL;
+
+	/* Allocate mem for sum resource */
+	sum = kzalloc(sizeof(*sum), GFP_KERNEL);
+	if (NULL == sum) {
+		err = -ENOMEM;
+		return err;
+	}
+
+	/* Check whether there are sufficient sum resources to meet request. */
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	for (i = 0; i < desc->msr; i++) {
+		err = mgr_get_resource(&mgr->mgr, 1, &idx);
+		if (err)
+			break;
+
+		sum->idx[i] = idx;
+	}
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+	if (err) {
+		printk(KERN_ERR "ctxfi: Can't meet SUM resource request!\n");
+		goto error;
+	}
+
+	err = sum_rsc_init(sum, desc, mgr);
+	if (err)
+		goto error;
+
+	*rsum = sum;
+
+	return 0;
+
+error:
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	for (i--; i >= 0; i--)
+		mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
+
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+	kfree(sum);
+	return err;
+}
+
+static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum)
+{
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	for (i = 0; i < sum->rsc.msr; i++)
+		mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
+
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+	sum_rsc_uninit(sum);
+	kfree(sum);
+
+	return 0;
+}
+
+int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr)
+{
+	int err;
+	struct sum_mgr *sum_mgr;
+
+	*rsum_mgr = NULL;
+	sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL);
+	if (NULL == sum_mgr)
+		return -ENOMEM;
+
+	err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw);
+	if (err)
+		goto error;
+
+	spin_lock_init(&sum_mgr->mgr_lock);
+
+	sum_mgr->get_sum = get_sum_rsc;
+	sum_mgr->put_sum = put_sum_rsc;
+
+	*rsum_mgr = sum_mgr;
+
+	return 0;
+
+error:
+	kfree(sum_mgr);
+	return err;
+}
+
+int sum_mgr_destroy(struct sum_mgr *sum_mgr)
+{
+	rsc_mgr_uninit(&sum_mgr->mgr);
+	kfree(sum_mgr);
+	return 0;
+}
+
diff --git a/sound/pci/ctxfi/ctamixer.h b/sound/pci/ctxfi/ctamixer.h
new file mode 100644
index 0000000..cc49e5a
--- /dev/null
+++ b/sound/pci/ctxfi/ctamixer.h
@@ -0,0 +1,96 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctamixer.h
+ *
+ * @Brief
+ * This file contains the definition of the Audio Mixer
+ * resource management object.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 21 2008
+ *
+ */
+
+#ifndef CTAMIXER_H
+#define CTAMIXER_H
+
+#include "ctresource.h"
+#include <linux/spinlock.h>
+
+/* Define the descriptor of a summation node resource */
+struct sum {
+	struct rsc rsc;		/* Basic resource info */
+	unsigned char idx[8];
+};
+
+/* Define sum resource request description info */
+struct sum_desc {
+	unsigned int msr;
+};
+
+struct sum_mgr {
+	struct rsc_mgr mgr;	/* Basic resource manager info */
+	spinlock_t mgr_lock;
+
+	 /* request one sum resource */
+	int (*get_sum)(struct sum_mgr *mgr,
+			const struct sum_desc *desc, struct sum **rsum);
+	/* return one sum resource */
+	int (*put_sum)(struct sum_mgr *mgr, struct sum *sum);
+};
+
+/* Constructor and destructor of daio resource manager */
+int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr);
+int sum_mgr_destroy(struct sum_mgr *sum_mgr);
+
+/* Define the descriptor of a amixer resource */
+struct amixer_rsc_ops;
+
+struct amixer {
+	struct rsc rsc;		/* Basic resource info */
+	unsigned char idx[8];
+	struct rsc *input;	/* pointer to a resource acting as source */
+	struct sum *sum;	/* Put amixer output to this summation node */
+	struct amixer_rsc_ops *ops;	/* AMixer specific operations */
+};
+
+struct amixer_rsc_ops {
+	int (*set_input)(struct amixer *amixer, struct rsc *rsc);
+	int (*set_scale)(struct amixer *amixer, unsigned int scale);
+	int (*set_invalid_squash)(struct amixer *amixer, unsigned int iv);
+	int (*set_sum)(struct amixer *amixer, struct sum *sum);
+	int (*commit_write)(struct amixer *amixer);
+	/* Only for interleaved recording */
+	int (*commit_raw_write)(struct amixer *amixer);
+	int (*setup)(struct amixer *amixer, struct rsc *input,
+			unsigned int scale, struct sum *sum);
+	int (*get_scale)(struct amixer *amixer);
+};
+
+/* Define amixer resource request description info */
+struct amixer_desc {
+	unsigned int msr;
+};
+
+struct amixer_mgr {
+	struct rsc_mgr mgr;	/* Basic resource manager info */
+	spinlock_t mgr_lock;
+
+	 /* request one amixer resource */
+	int (*get_amixer)(struct amixer_mgr *mgr,
+			  const struct amixer_desc *desc,
+			  struct amixer **ramixer);
+	/* return one amixer resource */
+	int (*put_amixer)(struct amixer_mgr *mgr, struct amixer *amixer);
+};
+
+/* Constructor and destructor of amixer resource manager */
+int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr);
+int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr);
+
+#endif /* CTAMIXER_H */
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
new file mode 100644
index 0000000..80fb2ba
--- /dev/null
+++ b/sound/pci/ctxfi/ctatc.c
@@ -0,0 +1,1619 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File    ctatc.c
+ *
+ * @Brief
+ * This file contains the implementation of the device resource management
+ * object.
+ *
+ * @Author Liu Chun
+ * @Date Mar 28 2008
+ */
+
+#include "ctatc.h"
+#include "ctpcm.h"
+#include "ctmixer.h"
+#include "cthardware.h"
+#include "ctsrc.h"
+#include "ctamixer.h"
+#include "ctdaio.h"
+#include "cttimer.h"
+#include <linux/delay.h>
+#include <sound/pcm.h>
+#include <sound/control.h>
+#include <sound/asoundef.h>
+
+#define MONO_SUM_SCALE	0x19a8	/* 2^(-0.5) in 14-bit floating format */
+#define DAIONUM		7
+#define MAX_MULTI_CHN	8
+
+#define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \
+			    | IEC958_AES0_CON_NOT_COPYRIGHT) \
+			    | ((IEC958_AES1_CON_MIXER \
+			    | IEC958_AES1_CON_ORIGINAL) << 8) \
+			    | (0x10 << 16) \
+			    | ((IEC958_AES3_CON_FS_48000) << 24))
+
+static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = {
+	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0022, "SB055x", CTSB055X),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x002f, "SB055x", CTSB055X),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0029, "SB073x", CTSB073X),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0031, "SB073x", CTSB073X),
+	SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 0x6000,
+			   "UAA", CTUAA),
+	SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_CREATIVE,
+			     "Unknown", CT20K1_UNKNOWN),
+	{ } /* terminator */
+};
+
+static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = {
+	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760,
+		      "SB0760", CTSB0760),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801,
+		      "SB0880", CTSB0880),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802,
+		      "SB0880", CTSB0880),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08803,
+		      "SB0880", CTSB0880),
+	SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000,
+			   PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX",
+			   CTHENDRIX),
+	{ } /* terminator */
+};
+
+static const char *ct_subsys_name[NUM_CTCARDS] = {
+	[CTSB055X]	= "SB055x",
+	[CTSB073X]	= "SB073x",
+	[CTSB0760]	= "SB076x",
+	[CTUAA]		= "UAA",
+	[CT20K1_UNKNOWN] = "Unknown",
+	[CTHENDRIX]	= "Hendrix",
+	[CTSB0880]	= "SB0880",
+};
+
+static struct {
+	int (*create)(struct ct_atc *atc,
+			enum CTALSADEVS device, const char *device_name);
+	int (*destroy)(void *alsa_dev);
+	const char *public_name;
+} alsa_dev_funcs[NUM_CTALSADEVS] = {
+	[FRONT]		= { .create = ct_alsa_pcm_create,
+			    .destroy = NULL,
+			    .public_name = "Front/WaveIn"},
+	[SURROUND]	= { .create = ct_alsa_pcm_create,
+			    .destroy = NULL,
+			    .public_name = "Surround"},
+	[CLFE]		= { .create = ct_alsa_pcm_create,
+			    .destroy = NULL,
+			    .public_name = "Center/LFE"},
+	[SIDE]		= { .create = ct_alsa_pcm_create,
+			    .destroy = NULL,
+			    .public_name = "Side"},
+	[IEC958]	= { .create = ct_alsa_pcm_create,
+			    .destroy = NULL,
+			    .public_name = "IEC958 Non-audio"},
+
+	[MIXER]		= { .create = ct_alsa_mix_create,
+			    .destroy = NULL,
+			    .public_name = "Mixer"}
+};
+
+typedef int (*create_t)(void *, void **);
+typedef int (*destroy_t)(void *);
+
+static struct {
+	int (*create)(void *hw, void **rmgr);
+	int (*destroy)(void *mgr);
+} rsc_mgr_funcs[NUM_RSCTYP] = {
+	[SRC] 		= { .create 	= (create_t)src_mgr_create,
+			    .destroy 	= (destroy_t)src_mgr_destroy	},
+	[SRCIMP] 	= { .create 	= (create_t)srcimp_mgr_create,
+			    .destroy 	= (destroy_t)srcimp_mgr_destroy	},
+	[AMIXER]	= { .create	= (create_t)amixer_mgr_create,
+			    .destroy	= (destroy_t)amixer_mgr_destroy	},
+	[SUM]		= { .create	= (create_t)sum_mgr_create,
+			    .destroy	= (destroy_t)sum_mgr_destroy	},
+	[DAIO]		= { .create	= (create_t)daio_mgr_create,
+			    .destroy	= (destroy_t)daio_mgr_destroy	}
+};
+
+static int
+atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+
+/* *
+ * Only mono and interleaved modes are supported now.
+ * Always allocates a contiguous channel block.
+ * */
+
+static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+	struct snd_pcm_runtime *runtime;
+	struct ct_vm *vm;
+
+	if (NULL == apcm->substream)
+		return 0;
+
+	runtime = apcm->substream->runtime;
+	vm = atc->vm;
+
+	apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes);
+
+	if (NULL == apcm->vm_block)
+		return -ENOENT;
+
+	return 0;
+}
+
+static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+	struct ct_vm *vm;
+
+	if (NULL == apcm->vm_block)
+		return;
+
+	vm = atc->vm;
+
+	vm->unmap(vm, apcm->vm_block);
+
+	apcm->vm_block = NULL;
+}
+
+static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index)
+{
+	struct ct_vm *vm;
+	void *kvirt_addr;
+	unsigned long phys_addr;
+
+	vm = atc->vm;
+	kvirt_addr = vm->get_ptp_virt(vm, index);
+	if (kvirt_addr == NULL)
+		phys_addr = (~0UL);
+	else
+		phys_addr = virt_to_phys(kvirt_addr);
+
+	return phys_addr;
+}
+
+static unsigned int convert_format(snd_pcm_format_t snd_format)
+{
+	switch (snd_format) {
+	case SNDRV_PCM_FORMAT_U8:
+		return SRC_SF_U8;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		return SRC_SF_S16;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		return SRC_SF_S24;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		return SRC_SF_S32;
+	case SNDRV_PCM_FORMAT_FLOAT_LE:
+		return SRC_SF_F32;
+	default:
+		printk(KERN_ERR "ctxfi: not recognized snd format is %d \n",
+			snd_format);
+		return SRC_SF_S16;
+	}
+}
+
+static unsigned int
+atc_get_pitch(unsigned int input_rate, unsigned int output_rate)
+{
+	unsigned int pitch;
+	int b;
+
+	/* get pitch and convert to fixed-point 8.24 format. */
+	pitch = (input_rate / output_rate) << 24;
+	input_rate %= output_rate;
+	input_rate /= 100;
+	output_rate /= 100;
+	for (b = 31; ((b >= 0) && !(input_rate >> b)); )
+		b--;
+
+	if (b >= 0) {
+		input_rate <<= (31 - b);
+		input_rate /= output_rate;
+		b = 24 - (31 - b);
+		if (b >= 0)
+			input_rate <<= b;
+		else
+			input_rate >>= -b;
+
+		pitch |= input_rate;
+	}
+
+	return pitch;
+}
+
+static int select_rom(unsigned int pitch)
+{
+	if ((pitch > 0x00428f5c) && (pitch < 0x01b851ec)) {
+		/* 0.26 <= pitch <= 1.72 */
+		return 1;
+	} else if ((0x01d66666 == pitch) || (0x01d66667 == pitch)) {
+		/* pitch == 1.8375 */
+		return 2;
+	} else if (0x02000000 == pitch) {
+		/* pitch == 2 */
+		return 3;
+	} else if ((pitch >= 0x0) && (pitch <= 0x08000000)) {
+		/* 0 <= pitch <= 8 */
+		return 0;
+	} else {
+		return -ENOENT;
+	}
+}
+
+static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+	struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
+	struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
+	struct src_desc desc = {0};
+	struct amixer_desc mix_dsc = {0};
+	struct src *src;
+	struct amixer *amixer;
+	int err;
+	int n_amixer = apcm->substream->runtime->channels, i = 0;
+	int device = apcm->substream->pcm->device;
+	unsigned int pitch;
+	unsigned long flags;
+
+	if (NULL != apcm->src) {
+		/* Prepared pcm playback */
+		return 0;
+	}
+
+	/* first release old resources */
+	atc->pcm_release_resources(atc, apcm);
+
+	/* Get SRC resource */
+	desc.multi = apcm->substream->runtime->channels;
+	desc.msr = atc->msr;
+	desc.mode = MEMRD;
+	err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src);
+	if (err)
+		goto error1;
+
+	pitch = atc_get_pitch(apcm->substream->runtime->rate,
+						(atc->rsr * atc->msr));
+	src = apcm->src;
+	src->ops->set_pitch(src, pitch);
+	src->ops->set_rom(src, select_rom(pitch));
+	src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
+	src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL));
+
+	/* Get AMIXER resource */
+	n_amixer = (n_amixer < 2) ? 2 : n_amixer;
+	apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
+	if (NULL == apcm->amixers) {
+		err = -ENOMEM;
+		goto error1;
+	}
+	mix_dsc.msr = atc->msr;
+	for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) {
+		err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc,
+					(struct amixer **)&apcm->amixers[i]);
+		if (err)
+			goto error1;
+
+		apcm->n_amixer++;
+	}
+
+	/* Set up device virtual mem map */
+	err = ct_map_audio_buffer(atc, apcm);
+	if (err < 0)
+		goto error1;
+
+	/* Connect resources */
+	src = apcm->src;
+	for (i = 0; i < n_amixer; i++) {
+		amixer = apcm->amixers[i];
+		spin_lock_irqsave(&atc->atc_lock, flags);
+		amixer->ops->setup(amixer, &src->rsc,
+					INIT_VOL, atc->pcm[i+device*2]);
+		spin_unlock_irqrestore(&atc->atc_lock, flags);
+		src = src->ops->next_interleave(src);
+		if (NULL == src)
+			src = apcm->src;
+	}
+
+	ct_timer_prepare(apcm->timer);
+
+	return 0;
+
+error1:
+	atc_pcm_release_resources(atc, apcm);
+	return err;
+}
+
+static int
+atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+	struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
+	struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP];
+	struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
+	struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM];
+	struct srcimp *srcimp;
+	int i;
+
+	if (NULL != apcm->srcimps) {
+		for (i = 0; i < apcm->n_srcimp; i++) {
+			srcimp = apcm->srcimps[i];
+			srcimp->ops->unmap(srcimp);
+			srcimp_mgr->put_srcimp(srcimp_mgr, srcimp);
+			apcm->srcimps[i] = NULL;
+		}
+		kfree(apcm->srcimps);
+		apcm->srcimps = NULL;
+	}
+
+	if (NULL != apcm->srccs) {
+		for (i = 0; i < apcm->n_srcc; i++) {
+			src_mgr->put_src(src_mgr, apcm->srccs[i]);
+			apcm->srccs[i] = NULL;
+		}
+		kfree(apcm->srccs);
+		apcm->srccs = NULL;
+	}
+
+	if (NULL != apcm->amixers) {
+		for (i = 0; i < apcm->n_amixer; i++) {
+			amixer_mgr->put_amixer(amixer_mgr, apcm->amixers[i]);
+			apcm->amixers[i] = NULL;
+		}
+		kfree(apcm->amixers);
+		apcm->amixers = NULL;
+	}
+
+	if (NULL != apcm->mono) {
+		sum_mgr->put_sum(sum_mgr, apcm->mono);
+		apcm->mono = NULL;
+	}
+
+	if (NULL != apcm->src) {
+		src_mgr->put_src(src_mgr, apcm->src);
+		apcm->src = NULL;
+	}
+
+	if (NULL != apcm->vm_block) {
+		/* Undo device virtual mem map */
+		ct_unmap_audio_buffer(atc, apcm);
+		apcm->vm_block = NULL;
+	}
+
+	return 0;
+}
+
+static int atc_pcm_playback_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+	unsigned int max_cisz;
+	struct src *src = apcm->src;
+
+	if (apcm->started)
+		return 0;
+	apcm->started = 1;
+
+	max_cisz = src->multi * src->rsc.msr;
+	max_cisz = 0x80 * (max_cisz < 8 ? max_cisz : 8);
+
+	src->ops->set_sa(src, apcm->vm_block->addr);
+	src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size);
+	src->ops->set_ca(src, apcm->vm_block->addr + max_cisz);
+	src->ops->set_cisz(src, max_cisz);
+
+	src->ops->set_bm(src, 1);
+	src->ops->set_state(src, SRC_STATE_INIT);
+	src->ops->commit_write(src);
+
+	ct_timer_start(apcm->timer);
+	return 0;
+}
+
+static int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+	struct src *src;
+	int i;
+
+	ct_timer_stop(apcm->timer);
+
+	src = apcm->src;
+	src->ops->set_bm(src, 0);
+	src->ops->set_state(src, SRC_STATE_OFF);
+	src->ops->commit_write(src);
+
+	if (NULL != apcm->srccs) {
+		for (i = 0; i < apcm->n_srcc; i++) {
+			src = apcm->srccs[i];
+			src->ops->set_bm(src, 0);
+			src->ops->set_state(src, SRC_STATE_OFF);
+			src->ops->commit_write(src);
+		}
+	}
+
+	apcm->started = 0;
+
+	return 0;
+}
+
+static int
+atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+	struct src *src = apcm->src;
+	u32 size, max_cisz;
+	int position;
+
+	if (!src)
+		return 0;
+	position = src->ops->get_ca(src);
+
+	size = apcm->vm_block->size;
+	max_cisz = src->multi * src->rsc.msr;
+	max_cisz = 128 * (max_cisz < 8 ? max_cisz : 8);
+
+	return (position + size - max_cisz - apcm->vm_block->addr) % size;
+}
+
+struct src_node_conf_t {
+	unsigned int pitch;
+	unsigned int msr:8;
+	unsigned int mix_msr:8;
+	unsigned int imp_msr:8;
+	unsigned int vo:1;
+};
+
+static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm,
+				struct src_node_conf_t *conf, int *n_srcc)
+{
+	unsigned int pitch;
+
+	/* get pitch and convert to fixed-point 8.24 format. */
+	pitch = atc_get_pitch((atc->rsr * atc->msr),
+				apcm->substream->runtime->rate);
+	*n_srcc = 0;
+
+	if (1 == atc->msr) {
+		*n_srcc = apcm->substream->runtime->channels;
+		conf[0].pitch = pitch;
+		conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1;
+		conf[0].vo = 1;
+	} else if (2 == atc->msr) {
+		if (0x8000000 < pitch) {
+			/* Need two-stage SRCs, SRCIMPs and
+			 * AMIXERs for converting format */
+			conf[0].pitch = (atc->msr << 24);
+			conf[0].msr = conf[0].mix_msr = 1;
+			conf[0].imp_msr = atc->msr;
+			conf[0].vo = 0;
+			conf[1].pitch = atc_get_pitch(atc->rsr,
+					apcm->substream->runtime->rate);
+			conf[1].msr = conf[1].mix_msr = conf[1].imp_msr = 1;
+			conf[1].vo = 1;
+			*n_srcc = apcm->substream->runtime->channels * 2;
+		} else if (0x1000000 < pitch) {
+			/* Need one-stage SRCs, SRCIMPs and
+			 * AMIXERs for converting format */
+			conf[0].pitch = pitch;
+			conf[0].msr = conf[0].mix_msr
+				    = conf[0].imp_msr = atc->msr;
+			conf[0].vo = 1;
+			*n_srcc = apcm->substream->runtime->channels;
+		}
+	}
+}
+
+static int
+atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+	struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
+	struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP];
+	struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
+	struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM];
+	struct src_desc src_dsc = {0};
+	struct src *src;
+	struct srcimp_desc srcimp_dsc = {0};
+	struct srcimp *srcimp;
+	struct amixer_desc mix_dsc = {0};
+	struct sum_desc sum_dsc = {0};
+	unsigned int pitch;
+	int multi, err, i;
+	int n_srcimp, n_amixer, n_srcc, n_sum;
+	struct src_node_conf_t src_node_conf[2] = {{0} };
+
+	/* first release old resources */
+	atc_pcm_release_resources(atc, apcm);
+
+	/* The numbers of converting SRCs and SRCIMPs should be determined
+	 * by pitch value. */
+
+	multi = apcm->substream->runtime->channels;
+
+	/* get pitch and convert to fixed-point 8.24 format. */
+	pitch = atc_get_pitch((atc->rsr * atc->msr),
+				apcm->substream->runtime->rate);
+
+	setup_src_node_conf(atc, apcm, src_node_conf, &n_srcc);
+	n_sum = (1 == multi) ? 1 : 0;
+	n_amixer = n_sum * 2 + n_srcc;
+	n_srcimp = n_srcc;
+	if ((multi > 1) && (0x8000000 >= pitch)) {
+		/* Need extra AMIXERs and SRCIMPs for special treatment
+		 * of interleaved recording of conjugate channels */
+		n_amixer += multi * atc->msr;
+		n_srcimp += multi * atc->msr;
+	} else {
+		n_srcimp += multi;
+	}
+
+	if (n_srcc) {
+		apcm->srccs = kzalloc(sizeof(void *)*n_srcc, GFP_KERNEL);
+		if (NULL == apcm->srccs)
+			return -ENOMEM;
+	}
+	if (n_amixer) {
+		apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
+		if (NULL == apcm->amixers) {
+			err = -ENOMEM;
+			goto error1;
+		}
+	}
+	apcm->srcimps = kzalloc(sizeof(void *)*n_srcimp, GFP_KERNEL);
+	if (NULL == apcm->srcimps) {
+		err = -ENOMEM;
+		goto error1;
+	}
+
+	/* Allocate SRCs for sample rate conversion if needed */
+	src_dsc.multi = 1;
+	src_dsc.mode = ARCRW;
+	for (i = 0, apcm->n_srcc = 0; i < n_srcc; i++) {
+		src_dsc.msr = src_node_conf[i/multi].msr;
+		err = src_mgr->get_src(src_mgr, &src_dsc,
+					(struct src **)&apcm->srccs[i]);
+		if (err)
+			goto error1;
+
+		src = apcm->srccs[i];
+		pitch = src_node_conf[i/multi].pitch;
+		src->ops->set_pitch(src, pitch);
+		src->ops->set_rom(src, select_rom(pitch));
+		src->ops->set_vo(src, src_node_conf[i/multi].vo);
+
+		apcm->n_srcc++;
+	}
+
+	/* Allocate AMIXERs for routing SRCs of conversion if needed */
+	for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) {
+		if (i < (n_sum*2))
+			mix_dsc.msr = atc->msr;
+		else if (i < (n_sum*2+n_srcc))
+			mix_dsc.msr = src_node_conf[(i-n_sum*2)/multi].mix_msr;
+		else
+			mix_dsc.msr = 1;
+
+		err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc,
+					(struct amixer **)&apcm->amixers[i]);
+		if (err)
+			goto error1;
+
+		apcm->n_amixer++;
+	}
+
+	/* Allocate a SUM resource to mix all input channels together */
+	sum_dsc.msr = atc->msr;
+	err = sum_mgr->get_sum(sum_mgr, &sum_dsc, (struct sum **)&apcm->mono);
+	if (err)
+		goto error1;
+
+	pitch = atc_get_pitch((atc->rsr * atc->msr),
+				apcm->substream->runtime->rate);
+	/* Allocate SRCIMP resources */
+	for (i = 0, apcm->n_srcimp = 0; i < n_srcimp; i++) {
+		if (i < (n_srcc))
+			srcimp_dsc.msr = src_node_conf[i/multi].imp_msr;
+		else if (1 == multi)
+			srcimp_dsc.msr = (pitch <= 0x8000000) ? atc->msr : 1;
+		else
+			srcimp_dsc.msr = 1;
+
+		err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, &srcimp);
+		if (err)
+			goto error1;
+
+		apcm->srcimps[i] = srcimp;
+		apcm->n_srcimp++;
+	}
+
+	/* Allocate a SRC for writing data to host memory */
+	src_dsc.multi = apcm->substream->runtime->channels;
+	src_dsc.msr = 1;
+	src_dsc.mode = MEMWR;
+	err = src_mgr->get_src(src_mgr, &src_dsc, (struct src **)&apcm->src);
+	if (err)
+		goto error1;
+
+	src = apcm->src;
+	src->ops->set_pitch(src, pitch);
+
+	/* Set up device virtual mem map */
+	err = ct_map_audio_buffer(atc, apcm);
+	if (err < 0)
+		goto error1;
+
+	return 0;
+
+error1:
+	atc_pcm_release_resources(atc, apcm);
+	return err;
+}
+
+static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+	struct src *src;
+	struct amixer *amixer;
+	struct srcimp *srcimp;
+	struct ct_mixer *mixer = atc->mixer;
+	struct sum *mono;
+	struct rsc *out_ports[8] = {NULL};
+	int err, i, j, n_sum, multi;
+	unsigned int pitch;
+	int mix_base = 0, imp_base = 0;
+
+	if (NULL != apcm->src) {
+		/* Prepared pcm capture */
+		return 0;
+	}
+
+	/* Get needed resources. */
+	err = atc_pcm_capture_get_resources(atc, apcm);
+	if (err)
+		return err;
+
+	/* Connect resources */
+	mixer->get_output_ports(mixer, MIX_PCMO_FRONT,
+				&out_ports[0], &out_ports[1]);
+
+	multi = apcm->substream->runtime->channels;
+	if (1 == multi) {
+		mono = apcm->mono;
+		for (i = 0; i < 2; i++) {
+			amixer = apcm->amixers[i];
+			amixer->ops->setup(amixer, out_ports[i],
+						MONO_SUM_SCALE, mono);
+		}
+		out_ports[0] = &mono->rsc;
+		n_sum = 1;
+		mix_base = n_sum * 2;
+	}
+
+	for (i = 0; i < apcm->n_srcc; i++) {
+		src = apcm->srccs[i];
+		srcimp = apcm->srcimps[imp_base+i];
+		amixer = apcm->amixers[mix_base+i];
+		srcimp->ops->map(srcimp, src, out_ports[i%multi]);
+		amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL);
+		out_ports[i%multi] = &amixer->rsc;
+	}
+
+	pitch = atc_get_pitch((atc->rsr * atc->msr),
+				apcm->substream->runtime->rate);
+
+	if ((multi > 1) && (pitch <= 0x8000000)) {
+		/* Special connection for interleaved
+		 * recording with conjugate channels */
+		for (i = 0; i < multi; i++) {
+			out_ports[i]->ops->master(out_ports[i]);
+			for (j = 0; j < atc->msr; j++) {
+				amixer = apcm->amixers[apcm->n_srcc+j*multi+i];
+				amixer->ops->set_input(amixer, out_ports[i]);
+				amixer->ops->set_scale(amixer, INIT_VOL);
+				amixer->ops->set_sum(amixer, NULL);
+				amixer->ops->commit_raw_write(amixer);
+				out_ports[i]->ops->next_conj(out_ports[i]);
+
+				srcimp = apcm->srcimps[apcm->n_srcc+j*multi+i];
+				srcimp->ops->map(srcimp, apcm->src,
+							&amixer->rsc);
+			}
+		}
+	} else {
+		for (i = 0; i < multi; i++) {
+			srcimp = apcm->srcimps[apcm->n_srcc+i];
+			srcimp->ops->map(srcimp, apcm->src, out_ports[i]);
+		}
+	}
+
+	ct_timer_prepare(apcm->timer);
+
+	return 0;
+}
+
+static int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+	struct src *src;
+	struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
+	int i, multi;
+
+	if (apcm->started)
+		return 0;
+
+	apcm->started = 1;
+	multi = apcm->substream->runtime->channels;
+	/* Set up converting SRCs */
+	for (i = 0; i < apcm->n_srcc; i++) {
+		src = apcm->srccs[i];
+		src->ops->set_pm(src, ((i%multi) != (multi-1)));
+		src_mgr->src_disable(src_mgr, src);
+	}
+
+	/*  Set up recording SRC */
+	src = apcm->src;
+	src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
+	src->ops->set_sa(src, apcm->vm_block->addr);
+	src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size);
+	src->ops->set_ca(src, apcm->vm_block->addr);
+	src_mgr->src_disable(src_mgr, src);
+
+	/* Disable relevant SRCs firstly */
+	src_mgr->commit_write(src_mgr);
+
+	/* Enable SRCs respectively */
+	for (i = 0; i < apcm->n_srcc; i++) {
+		src = apcm->srccs[i];
+		src->ops->set_state(src, SRC_STATE_RUN);
+		src->ops->commit_write(src);
+		src_mgr->src_enable_s(src_mgr, src);
+	}
+	src = apcm->src;
+	src->ops->set_bm(src, 1);
+	src->ops->set_state(src, SRC_STATE_RUN);
+	src->ops->commit_write(src);
+	src_mgr->src_enable_s(src_mgr, src);
+
+	/* Enable relevant SRCs synchronously */
+	src_mgr->commit_write(src_mgr);
+
+	ct_timer_start(apcm->timer);
+	return 0;
+}
+
+static int
+atc_pcm_capture_position(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+	struct src *src = apcm->src;
+
+	if (!src)
+		return 0;
+	return src->ops->get_ca(src) - apcm->vm_block->addr;
+}
+
+static int spdif_passthru_playback_get_resources(struct ct_atc *atc,
+						 struct ct_atc_pcm *apcm)
+{
+	struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
+	struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
+	struct src_desc desc = {0};
+	struct amixer_desc mix_dsc = {0};
+	struct src *src;
+	int err;
+	int n_amixer = apcm->substream->runtime->channels, i;
+	unsigned int pitch, rsr = atc->pll_rate;
+
+	/* first release old resources */
+	atc_pcm_release_resources(atc, apcm);
+
+	/* Get SRC resource */
+	desc.multi = apcm->substream->runtime->channels;
+	desc.msr = 1;
+	while (apcm->substream->runtime->rate > (rsr * desc.msr))
+		desc.msr <<= 1;
+
+	desc.mode = MEMRD;
+	err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src);
+	if (err)
+		goto error1;
+
+	pitch = atc_get_pitch(apcm->substream->runtime->rate, (rsr * desc.msr));
+	src = apcm->src;
+	src->ops->set_pitch(src, pitch);
+	src->ops->set_rom(src, select_rom(pitch));
+	src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
+	src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL));
+	src->ops->set_bp(src, 1);
+
+	/* Get AMIXER resource */
+	n_amixer = (n_amixer < 2) ? 2 : n_amixer;
+	apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
+	if (NULL == apcm->amixers) {
+		err = -ENOMEM;
+		goto error1;
+	}
+	mix_dsc.msr = desc.msr;
+	for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) {
+		err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc,
+					(struct amixer **)&apcm->amixers[i]);
+		if (err)
+			goto error1;
+
+		apcm->n_amixer++;
+	}
+
+	/* Set up device virtual mem map */
+	err = ct_map_audio_buffer(atc, apcm);
+	if (err < 0)
+		goto error1;
+
+	return 0;
+
+error1:
+	atc_pcm_release_resources(atc, apcm);
+	return err;
+}
+
+static int atc_pll_init(struct ct_atc *atc, int rate)
+{
+	struct hw *hw = atc->hw;
+	int err;
+	err = hw->pll_init(hw, rate);
+	atc->pll_rate = err ? 0 : rate;
+	return err;
+}
+
+static int
+spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+	struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
+	unsigned long flags;
+	unsigned int rate = apcm->substream->runtime->rate;
+	unsigned int status;
+	int err;
+	unsigned char iec958_con_fs;
+
+	switch (rate) {
+	case 48000:
+		iec958_con_fs = IEC958_AES3_CON_FS_48000;
+		break;
+	case 44100:
+		iec958_con_fs = IEC958_AES3_CON_FS_44100;
+		break;
+	case 32000:
+		iec958_con_fs = IEC958_AES3_CON_FS_32000;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	spin_lock_irqsave(&atc->atc_lock, flags);
+	dao->ops->get_spos(dao, &status);
+	if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) {
+		status &= ((~IEC958_AES3_CON_FS) << 24);
+		status |= (iec958_con_fs << 24);
+		dao->ops->set_spos(dao, status);
+		dao->ops->commit_write(dao);
+	}
+	if ((rate != atc->pll_rate) && (32000 != rate))
+		err = atc_pll_init(atc, rate);
+	spin_unlock_irqrestore(&atc->atc_lock, flags);
+
+	return err;
+}
+
+static int
+spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+	struct src *src;
+	struct amixer *amixer;
+	struct dao *dao;
+	int err;
+	int i;
+	unsigned long flags;
+
+	if (NULL != apcm->src)
+		return 0;
+
+	/* Configure SPDIFOO and PLL to passthrough mode;
+	 * determine pll_rate. */
+	err = spdif_passthru_playback_setup(atc, apcm);
+	if (err)
+		return err;
+
+	/* Get needed resources. */
+	err = spdif_passthru_playback_get_resources(atc, apcm);
+	if (err)
+		return err;
+
+	/* Connect resources */
+	src = apcm->src;
+	for (i = 0; i < apcm->n_amixer; i++) {
+		amixer = apcm->amixers[i];
+		amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL);
+		src = src->ops->next_interleave(src);
+		if (NULL == src)
+			src = apcm->src;
+	}
+	/* Connect to SPDIFOO */
+	spin_lock_irqsave(&atc->atc_lock, flags);
+	dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
+	amixer = apcm->amixers[0];
+	dao->ops->set_left_input(dao, &amixer->rsc);
+	amixer = apcm->amixers[1];
+	dao->ops->set_right_input(dao, &amixer->rsc);
+	spin_unlock_irqrestore(&atc->atc_lock, flags);
+
+	ct_timer_prepare(apcm->timer);
+
+	return 0;
+}
+
+static int atc_select_line_in(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+	struct ct_mixer *mixer = atc->mixer;
+	struct src *src;
+
+	if (hw->is_adc_source_selected(hw, ADC_LINEIN))
+		return 0;
+
+	mixer->set_input_left(mixer, MIX_MIC_IN, NULL);
+	mixer->set_input_right(mixer, MIX_MIC_IN, NULL);
+
+	hw->select_adc_source(hw, ADC_LINEIN);
+
+	src = atc->srcs[2];
+	mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc);
+	src = atc->srcs[3];
+	mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
+
+	return 0;
+}
+
+static int atc_select_mic_in(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+	struct ct_mixer *mixer = atc->mixer;
+	struct src *src;
+
+	if (hw->is_adc_source_selected(hw, ADC_MICIN))
+		return 0;
+
+	mixer->set_input_left(mixer, MIX_LINE_IN, NULL);
+	mixer->set_input_right(mixer, MIX_LINE_IN, NULL);
+
+	hw->select_adc_source(hw, ADC_MICIN);
+
+	src = atc->srcs[2];
+	mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc);
+	src = atc->srcs[3];
+	mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc);
+
+	return 0;
+}
+
+static int atc_have_digit_io_switch(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->have_digit_io_switch(hw);
+}
+
+static int atc_select_digit_io(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	if (hw->is_adc_source_selected(hw, ADC_NONE))
+		return 0;
+
+	hw->select_adc_source(hw, ADC_NONE);
+
+	return 0;
+}
+
+static int atc_daio_unmute(struct ct_atc *atc, unsigned char state, int type)
+{
+	struct daio_mgr *daio_mgr = atc->rsc_mgrs[DAIO];
+
+	if (state)
+		daio_mgr->daio_enable(daio_mgr, atc->daios[type]);
+	else
+		daio_mgr->daio_disable(daio_mgr, atc->daios[type]);
+
+	daio_mgr->commit_write(daio_mgr);
+
+	return 0;
+}
+
+static int
+atc_dao_get_status(struct ct_atc *atc, unsigned int *status, int type)
+{
+	struct dao *dao = container_of(atc->daios[type], struct dao, daio);
+	return dao->ops->get_spos(dao, status);
+}
+
+static int
+atc_dao_set_status(struct ct_atc *atc, unsigned int status, int type)
+{
+	struct dao *dao = container_of(atc->daios[type], struct dao, daio);
+
+	dao->ops->set_spos(dao, status);
+	dao->ops->commit_write(dao);
+	return 0;
+}
+
+static int atc_line_front_unmute(struct ct_atc *atc, unsigned char state)
+{
+	return atc_daio_unmute(atc, state, LINEO1);
+}
+
+static int atc_line_surround_unmute(struct ct_atc *atc, unsigned char state)
+{
+	return atc_daio_unmute(atc, state, LINEO4);
+}
+
+static int atc_line_clfe_unmute(struct ct_atc *atc, unsigned char state)
+{
+	return atc_daio_unmute(atc, state, LINEO3);
+}
+
+static int atc_line_rear_unmute(struct ct_atc *atc, unsigned char state)
+{
+	return atc_daio_unmute(atc, state, LINEO2);
+}
+
+static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state)
+{
+	return atc_daio_unmute(atc, state, LINEIM);
+}
+
+static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state)
+{
+	return atc_daio_unmute(atc, state, SPDIFOO);
+}
+
+static int atc_spdif_in_unmute(struct ct_atc *atc, unsigned char state)
+{
+	return atc_daio_unmute(atc, state, SPDIFIO);
+}
+
+static int atc_spdif_out_get_status(struct ct_atc *atc, unsigned int *status)
+{
+	return atc_dao_get_status(atc, status, SPDIFOO);
+}
+
+static int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status)
+{
+	return atc_dao_set_status(atc, status, SPDIFOO);
+}
+
+static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
+{
+	unsigned long flags;
+	struct dao_desc da_dsc = {0};
+	struct dao *dao;
+	int err;
+	struct ct_mixer *mixer = atc->mixer;
+	struct rsc *rscs[2] = {NULL};
+	unsigned int spos = 0;
+
+	spin_lock_irqsave(&atc->atc_lock, flags);
+	dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
+	da_dsc.msr = state ? 1 : atc->msr;
+	da_dsc.passthru = state ? 1 : 0;
+	err = dao->ops->reinit(dao, &da_dsc);
+	if (state) {
+		spos = IEC958_DEFAULT_CON;
+	} else {
+		mixer->get_output_ports(mixer, MIX_SPDIF_OUT,
+					&rscs[0], &rscs[1]);
+		dao->ops->set_left_input(dao, rscs[0]);
+		dao->ops->set_right_input(dao, rscs[1]);
+		/* Restore PLL to atc->rsr if needed. */
+		if (atc->pll_rate != atc->rsr)
+			err = atc_pll_init(atc, atc->rsr);
+	}
+	dao->ops->set_spos(dao, spos);
+	dao->ops->commit_write(dao);
+	spin_unlock_irqrestore(&atc->atc_lock, flags);
+
+	return err;
+}
+
+static int ct_atc_destroy(struct ct_atc *atc)
+{
+	struct daio_mgr *daio_mgr;
+	struct dao *dao;
+	struct dai *dai;
+	struct daio *daio;
+	struct sum_mgr *sum_mgr;
+	struct src_mgr *src_mgr;
+	struct srcimp_mgr *srcimp_mgr;
+	struct srcimp *srcimp;
+	struct ct_mixer *mixer;
+	int i = 0;
+
+	if (NULL == atc)
+		return 0;
+
+	if (atc->timer) {
+		ct_timer_free(atc->timer);
+		atc->timer = NULL;
+	}
+
+	/* Stop hardware and disable all interrupts */
+	if (NULL != atc->hw)
+		((struct hw *)atc->hw)->card_stop(atc->hw);
+
+	/* Destroy internal mixer objects */
+	if (NULL != atc->mixer) {
+		mixer = atc->mixer;
+		mixer->set_input_left(mixer, MIX_LINE_IN, NULL);
+		mixer->set_input_right(mixer, MIX_LINE_IN, NULL);
+		mixer->set_input_left(mixer, MIX_MIC_IN, NULL);
+		mixer->set_input_right(mixer, MIX_MIC_IN, NULL);
+		mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL);
+		mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL);
+		ct_mixer_destroy(atc->mixer);
+	}
+
+	if (NULL != atc->daios) {
+		daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
+		for (i = 0; i < atc->n_daio; i++) {
+			daio = atc->daios[i];
+			if (daio->type < LINEIM) {
+				dao = container_of(daio, struct dao, daio);
+				dao->ops->clear_left_input(dao);
+				dao->ops->clear_right_input(dao);
+			} else {
+				dai = container_of(daio, struct dai, daio);
+				/* some thing to do for dai ... */
+			}
+			daio_mgr->put_daio(daio_mgr, daio);
+		}
+		kfree(atc->daios);
+	}
+
+	if (NULL != atc->pcm) {
+		sum_mgr = atc->rsc_mgrs[SUM];
+		for (i = 0; i < atc->n_pcm; i++)
+			sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
+
+		kfree(atc->pcm);
+	}
+
+	if (NULL != atc->srcs) {
+		src_mgr = atc->rsc_mgrs[SRC];
+		for (i = 0; i < atc->n_src; i++)
+			src_mgr->put_src(src_mgr, atc->srcs[i]);
+
+		kfree(atc->srcs);
+	}
+
+	if (NULL != atc->srcimps) {
+		srcimp_mgr = atc->rsc_mgrs[SRCIMP];
+		for (i = 0; i < atc->n_srcimp; i++) {
+			srcimp = atc->srcimps[i];
+			srcimp->ops->unmap(srcimp);
+			srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]);
+		}
+		kfree(atc->srcimps);
+	}
+
+	for (i = 0; i < NUM_RSCTYP; i++) {
+		if ((NULL != rsc_mgr_funcs[i].destroy) &&
+		    (NULL != atc->rsc_mgrs[i]))
+			rsc_mgr_funcs[i].destroy(atc->rsc_mgrs[i]);
+
+	}
+
+	if (NULL != atc->hw)
+		destroy_hw_obj((struct hw *)atc->hw);
+
+	/* Destroy device virtual memory manager object */
+	if (NULL != atc->vm) {
+		ct_vm_destroy(atc->vm);
+		atc->vm = NULL;
+	}
+
+	kfree(atc);
+
+	return 0;
+}
+
+static int atc_dev_free(struct snd_device *dev)
+{
+	struct ct_atc *atc = dev->device_data;
+	return ct_atc_destroy(atc);
+}
+
+static int __devinit atc_identify_card(struct ct_atc *atc)
+{
+	const struct snd_pci_quirk *p;
+	const struct snd_pci_quirk *list;
+
+	switch (atc->chip_type) {
+	case ATC20K1:
+		atc->chip_name = "20K1";
+		list = subsys_20k1_list;
+		break;
+	case ATC20K2:
+		atc->chip_name = "20K2";
+		list = subsys_20k2_list;
+		break;
+	default:
+		return -ENOENT;
+	}
+	p = snd_pci_quirk_lookup(atc->pci, list);
+	if (!p)
+		return -ENOENT;
+	atc->model = p->value;
+	atc->model_name = ct_subsys_name[atc->model];
+	snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n",
+		   atc->chip_name, atc->model_name,
+		   atc->pci->subsystem_vendor,
+		   atc->pci->subsystem_device);
+	return 0;
+}
+
+int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc)
+{
+	enum CTALSADEVS i;
+	int err;
+
+	alsa_dev_funcs[MIXER].public_name = atc->chip_name;
+
+	for (i = 0; i < NUM_CTALSADEVS; i++) {
+		if (NULL == alsa_dev_funcs[i].create)
+			continue;
+
+		err = alsa_dev_funcs[i].create(atc, i,
+				alsa_dev_funcs[i].public_name);
+		if (err) {
+			printk(KERN_ERR "ctxfi: "
+			       "Creating alsa device %d failed!\n", i);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static int __devinit atc_create_hw_devs(struct ct_atc *atc)
+{
+	struct hw *hw;
+	struct card_conf info = {0};
+	int i, err;
+
+	err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw);
+	if (err) {
+		printk(KERN_ERR "Failed to create hw obj!!!\n");
+		return err;
+	}
+	atc->hw = hw;
+
+	/* Initialize card hardware. */
+	info.rsr = atc->rsr;
+	info.msr = atc->msr;
+	info.vm_pgt_phys = atc_get_ptp_phys(atc, 0);
+	err = hw->card_init(hw, &info);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i < NUM_RSCTYP; i++) {
+		if (NULL == rsc_mgr_funcs[i].create)
+			continue;
+
+		err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]);
+		if (err) {
+			printk(KERN_ERR "ctxfi: "
+			       "Failed to create rsc_mgr %d!!!\n", i);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static int __devinit atc_get_resources(struct ct_atc *atc)
+{
+	struct daio_desc da_desc = {0};
+	struct daio_mgr *daio_mgr;
+	struct src_desc src_dsc = {0};
+	struct src_mgr *src_mgr;
+	struct srcimp_desc srcimp_dsc = {0};
+	struct srcimp_mgr *srcimp_mgr;
+	struct sum_desc sum_dsc = {0};
+	struct sum_mgr *sum_mgr;
+	int err, i;
+
+	atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL);
+	if (NULL == atc->daios)
+		return -ENOMEM;
+
+	atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+	if (NULL == atc->srcs)
+		return -ENOMEM;
+
+	atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+	if (NULL == atc->srcimps)
+		return -ENOMEM;
+
+	atc->pcm = kzalloc(sizeof(void *)*(2*4), GFP_KERNEL);
+	if (NULL == atc->pcm)
+		return -ENOMEM;
+
+	daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
+	da_desc.msr = atc->msr;
+	for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) {
+		da_desc.type = i;
+		err = daio_mgr->get_daio(daio_mgr, &da_desc,
+					(struct daio **)&atc->daios[i]);
+		if (err) {
+			printk(KERN_ERR "ctxfi: Failed to get DAIO "
+					"resource %d!!!\n", i);
+			return err;
+		}
+		atc->n_daio++;
+	}
+	if (atc->model == CTSB073X)
+		da_desc.type = SPDIFI1;
+	else
+		da_desc.type = SPDIFIO;
+	err = daio_mgr->get_daio(daio_mgr, &da_desc,
+				(struct daio **)&atc->daios[i]);
+	if (err) {
+		printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n");
+		return err;
+	}
+	atc->n_daio++;
+
+	src_mgr = atc->rsc_mgrs[SRC];
+	src_dsc.multi = 1;
+	src_dsc.msr = atc->msr;
+	src_dsc.mode = ARCRW;
+	for (i = 0, atc->n_src = 0; i < (2*2); i++) {
+		err = src_mgr->get_src(src_mgr, &src_dsc,
+					(struct src **)&atc->srcs[i]);
+		if (err)
+			return err;
+
+		atc->n_src++;
+	}
+
+	srcimp_mgr = atc->rsc_mgrs[SRCIMP];
+	srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */
+	for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) {
+		err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
+					(struct srcimp **)&atc->srcimps[i]);
+		if (err)
+			return err;
+
+		atc->n_srcimp++;
+	}
+	srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */
+	for (i = 0; i < (2*1); i++) {
+		err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
+				(struct srcimp **)&atc->srcimps[2*1+i]);
+		if (err)
+			return err;
+
+		atc->n_srcimp++;
+	}
+
+	sum_mgr = atc->rsc_mgrs[SUM];
+	sum_dsc.msr = atc->msr;
+	for (i = 0, atc->n_pcm = 0; i < (2*4); i++) {
+		err = sum_mgr->get_sum(sum_mgr, &sum_dsc,
+					(struct sum **)&atc->pcm[i]);
+		if (err)
+			return err;
+
+		atc->n_pcm++;
+	}
+
+	err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer);
+	if (err) {
+		printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static void __devinit
+atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai,
+		struct src **srcs, struct srcimp **srcimps)
+{
+	struct rsc *rscs[2] = {NULL};
+	struct src *src;
+	struct srcimp *srcimp;
+	int i = 0;
+
+	rscs[0] = &dai->daio.rscl;
+	rscs[1] = &dai->daio.rscr;
+	for (i = 0; i < 2; i++) {
+		src = srcs[i];
+		srcimp = srcimps[i];
+		srcimp->ops->map(srcimp, src, rscs[i]);
+		src_mgr->src_disable(src_mgr, src);
+	}
+
+	src_mgr->commit_write(src_mgr); /* Actually disable SRCs */
+
+	src = srcs[0];
+	src->ops->set_pm(src, 1);
+	for (i = 0; i < 2; i++) {
+		src = srcs[i];
+		src->ops->set_state(src, SRC_STATE_RUN);
+		src->ops->commit_write(src);
+		src_mgr->src_enable_s(src_mgr, src);
+	}
+
+	dai->ops->set_srt_srcl(dai, &(srcs[0]->rsc));
+	dai->ops->set_srt_srcr(dai, &(srcs[1]->rsc));
+
+	dai->ops->set_enb_src(dai, 1);
+	dai->ops->set_enb_srt(dai, 1);
+	dai->ops->commit_write(dai);
+
+	src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */
+}
+
+static void __devinit atc_connect_resources(struct ct_atc *atc)
+{
+	struct dai *dai;
+	struct dao *dao;
+	struct src *src;
+	struct sum *sum;
+	struct ct_mixer *mixer;
+	struct rsc *rscs[2] = {NULL};
+	int i, j;
+
+	mixer = atc->mixer;
+
+	for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) {
+		mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]);
+		dao = container_of(atc->daios[j], struct dao, daio);
+		dao->ops->set_left_input(dao, rscs[0]);
+		dao->ops->set_right_input(dao, rscs[1]);
+	}
+
+	dai = container_of(atc->daios[LINEIM], struct dai, daio);
+	atc_connect_dai(atc->rsc_mgrs[SRC], dai,
+			(struct src **)&atc->srcs[2],
+			(struct srcimp **)&atc->srcimps[2]);
+	src = atc->srcs[2];
+	mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc);
+	src = atc->srcs[3];
+	mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
+
+	dai = container_of(atc->daios[SPDIFIO], struct dai, daio);
+	atc_connect_dai(atc->rsc_mgrs[SRC], dai,
+			(struct src **)&atc->srcs[0],
+			(struct srcimp **)&atc->srcimps[0]);
+
+	src = atc->srcs[0];
+	mixer->set_input_left(mixer, MIX_SPDIF_IN, &src->rsc);
+	src = atc->srcs[1];
+	mixer->set_input_right(mixer, MIX_SPDIF_IN, &src->rsc);
+
+	for (i = MIX_PCMI_FRONT, j = 0; i <= MIX_PCMI_SURROUND; i++, j += 2) {
+		sum = atc->pcm[j];
+		mixer->set_input_left(mixer, i, &sum->rsc);
+		sum = atc->pcm[j+1];
+		mixer->set_input_right(mixer, i, &sum->rsc);
+	}
+}
+
+static struct ct_atc atc_preset __devinitdata = {
+	.map_audio_buffer = ct_map_audio_buffer,
+	.unmap_audio_buffer = ct_unmap_audio_buffer,
+	.pcm_playback_prepare = atc_pcm_playback_prepare,
+	.pcm_release_resources = atc_pcm_release_resources,
+	.pcm_playback_start = atc_pcm_playback_start,
+	.pcm_playback_stop = atc_pcm_stop,
+	.pcm_playback_position = atc_pcm_playback_position,
+	.pcm_capture_prepare = atc_pcm_capture_prepare,
+	.pcm_capture_start = atc_pcm_capture_start,
+	.pcm_capture_stop = atc_pcm_stop,
+	.pcm_capture_position = atc_pcm_capture_position,
+	.spdif_passthru_playback_prepare = spdif_passthru_playback_prepare,
+	.get_ptp_phys = atc_get_ptp_phys,
+	.select_line_in = atc_select_line_in,
+	.select_mic_in = atc_select_mic_in,
+	.select_digit_io = atc_select_digit_io,
+	.line_front_unmute = atc_line_front_unmute,
+	.line_surround_unmute = atc_line_surround_unmute,
+	.line_clfe_unmute = atc_line_clfe_unmute,
+	.line_rear_unmute = atc_line_rear_unmute,
+	.line_in_unmute = atc_line_in_unmute,
+	.spdif_out_unmute = atc_spdif_out_unmute,
+	.spdif_in_unmute = atc_spdif_in_unmute,
+	.spdif_out_get_status = atc_spdif_out_get_status,
+	.spdif_out_set_status = atc_spdif_out_set_status,
+	.spdif_out_passthru = atc_spdif_out_passthru,
+	.have_digit_io_switch = atc_have_digit_io_switch,
+};
+
+/**
+ *  ct_atc_create - create and initialize a hardware manager
+ *  @card: corresponding alsa card object
+ *  @pci: corresponding kernel pci device object
+ *  @ratc: return created object address in it
+ *
+ *  Creates and initializes a hardware manager.
+ *
+ *  Creates kmallocated ct_atc structure. Initializes hardware.
+ *  Returns 0 if suceeds, or negative error code if fails.
+ */
+
+int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
+			    unsigned int rsr, unsigned int msr,
+			    int chip_type, struct ct_atc **ratc)
+{
+	struct ct_atc *atc;
+	static struct snd_device_ops ops = {
+		.dev_free = atc_dev_free,
+	};
+	int err;
+
+	*ratc = NULL;
+
+	atc = kzalloc(sizeof(*atc), GFP_KERNEL);
+	if (NULL == atc)
+		return -ENOMEM;
+
+	/* Set operations */
+	*atc = atc_preset;
+
+	atc->card = card;
+	atc->pci = pci;
+	atc->rsr = rsr;
+	atc->msr = msr;
+	atc->chip_type = chip_type;
+
+	spin_lock_init(&atc->atc_lock);
+
+	/* Find card model */
+	err = atc_identify_card(atc);
+	if (err < 0) {
+		printk(KERN_ERR "ctatc: Card not recognised\n");
+		goto error1;
+	}
+
+	/* Set up device virtual memory management object */
+	err = ct_vm_create(&atc->vm);
+	if (err < 0)
+		goto error1;
+
+	/* Create all atc hw devices */
+	err = atc_create_hw_devs(atc);
+	if (err < 0)
+		goto error1;
+
+	/* Get resources */
+	err = atc_get_resources(atc);
+	if (err < 0)
+		goto error1;
+
+	/* Build topology */
+	atc_connect_resources(atc);
+
+	atc->timer = ct_timer_new(atc);
+	if (!atc->timer)
+		goto error1;
+
+	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops);
+	if (err < 0)
+		goto error1;
+
+	snd_card_set_dev(card, &pci->dev);
+
+	*ratc = atc;
+	return 0;
+
+error1:
+	ct_atc_destroy(atc);
+	printk(KERN_ERR "ctxfi: Something wrong!!!\n");
+	return err;
+}
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h
new file mode 100644
index 0000000..a033472
--- /dev/null
+++ b/sound/pci/ctxfi/ctatc.h
@@ -0,0 +1,147 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctatc.h
+ *
+ * @Brief
+ * This file contains the definition of the device resource management object.
+ *
+ * @Author	Liu Chun
+ * @Date 	Mar 28 2008
+ *
+ */
+
+#ifndef CTATC_H
+#define CTATC_H
+
+#include <linux/types.h>
+#include <linux/spinlock_types.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+#include <sound/core.h>
+
+#include "ctvmem.h"
+#include "ctresource.h"
+
+enum CTALSADEVS {		/* Types of alsa devices */
+	FRONT,
+	SURROUND,
+	CLFE,
+	SIDE,
+	IEC958,
+	MIXER,
+	NUM_CTALSADEVS		/* This should always be the last */
+};
+
+struct ct_atc_chip_sub_details {
+	u16 subsys;
+	const char *nm_model;
+};
+
+struct ct_atc_chip_details {
+	u16 vendor;
+	u16 device;
+	const struct ct_atc_chip_sub_details *sub_details;
+	const char *nm_card;
+};
+
+struct ct_atc;
+struct ct_timer;
+struct ct_timer_instance;
+
+/* alsa pcm stream descriptor */
+struct ct_atc_pcm {
+	struct snd_pcm_substream *substream;
+	void (*interrupt)(struct ct_atc_pcm *apcm);
+	struct ct_timer_instance *timer;
+	unsigned int started:1;
+
+	/* Only mono and interleaved modes are supported now. */
+	struct ct_vm_block *vm_block;
+	void *src;		/* SRC for interacting with host memory */
+	void **srccs;		/* SRCs for sample rate conversion */
+	void **srcimps;		/* SRC Input Mappers */
+	void **amixers;		/* AMIXERs for routing converted data */
+	void *mono;		/* A SUM resource for mixing chs to one */
+	unsigned char n_srcc;	/* Number of converting SRCs */
+	unsigned char n_srcimp;	/* Number of SRC Input Mappers */
+	unsigned char n_amixer;	/* Number of AMIXERs */
+};
+
+/* Chip resource management object */
+struct ct_atc {
+	struct pci_dev *pci;
+	struct snd_card *card;
+	unsigned int rsr; /* reference sample rate in Hz */
+	unsigned int msr; /* master sample rate in rsr */
+	unsigned int pll_rate; /* current rate of Phase Lock Loop */
+
+	int chip_type;
+	int model;
+	const char *chip_name;
+	const char *model_name;
+
+	struct ct_vm *vm; /* device virtual memory manager for this card */
+	int (*map_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+	void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+	unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index);
+
+	spinlock_t atc_lock;
+
+	int (*pcm_playback_prepare)(struct ct_atc *atc,
+				    struct ct_atc_pcm *apcm);
+	int (*pcm_playback_start)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+	int (*pcm_playback_stop)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+	int (*pcm_playback_position)(struct ct_atc *atc,
+				     struct ct_atc_pcm *apcm);
+	int (*spdif_passthru_playback_prepare)(struct ct_atc *atc,
+					       struct ct_atc_pcm *apcm);
+	int (*pcm_capture_prepare)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+	int (*pcm_capture_start)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+	int (*pcm_capture_stop)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+	int (*pcm_capture_position)(struct ct_atc *atc,
+				    struct ct_atc_pcm *apcm);
+	int (*pcm_release_resources)(struct ct_atc *atc,
+				     struct ct_atc_pcm *apcm);
+	int (*select_line_in)(struct ct_atc *atc);
+	int (*select_mic_in)(struct ct_atc *atc);
+	int (*select_digit_io)(struct ct_atc *atc);
+	int (*line_front_unmute)(struct ct_atc *atc, unsigned char state);
+	int (*line_surround_unmute)(struct ct_atc *atc, unsigned char state);
+	int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state);
+	int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state);
+	int (*line_in_unmute)(struct ct_atc *atc, unsigned char state);
+	int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state);
+	int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state);
+	int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
+	int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
+	int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
+	int (*have_digit_io_switch)(struct ct_atc *atc);
+
+	/* Don't touch! Used for internal object. */
+	void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */
+	void *mixer;		/* internal mixer object */
+	void *hw;		/* chip specific hardware access object */
+	void **daios;		/* digital audio io resources */
+	void **pcm;		/* SUMs for collecting all pcm stream */
+	void **srcs;		/* Sample Rate Converters for input signal */
+	void **srcimps;		/* input mappers for SRCs */
+	unsigned char n_daio;
+	unsigned char n_src;
+	unsigned char n_srcimp;
+	unsigned char n_pcm;
+
+	struct ct_timer *timer;
+};
+
+
+int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
+			    unsigned int rsr, unsigned int msr, int chip_type,
+			    struct ct_atc **ratc);
+int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc);
+
+#endif /* CTATC_H */
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
new file mode 100644
index 0000000..082e35c
--- /dev/null
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -0,0 +1,769 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctdaio.c
+ *
+ * @Brief
+ * This file contains the implementation of Digital Audio Input Output
+ * resource management object.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 23 2008
+ *
+ */
+
+#include "ctdaio.h"
+#include "cthardware.h"
+#include "ctimap.h"
+#include <linux/slab.h>
+#include <linux/kernel.h>
+
+#define DAIO_RESOURCE_NUM	NUM_DAIOTYP
+#define DAIO_OUT_MAX		SPDIFOO
+
+union daio_usage {
+	struct {
+		unsigned short lineo1:1;
+		unsigned short lineo2:1;
+		unsigned short lineo3:1;
+		unsigned short lineo4:1;
+		unsigned short spdifoo:1;
+		unsigned short lineim:1;
+		unsigned short spdifio:1;
+		unsigned short spdifi1:1;
+	} bf;
+	unsigned short data;
+};
+
+struct daio_rsc_idx {
+	unsigned short left;
+	unsigned short right;
+};
+
+struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = {
+	[LINEO1] = {.left = 0x00, .right = 0x01},
+	[LINEO2] = {.left = 0x18, .right = 0x19},
+	[LINEO3] = {.left = 0x08, .right = 0x09},
+	[LINEO4] = {.left = 0x10, .right = 0x11},
+	[LINEIM] = {.left = 0x1b5, .right = 0x1bd},
+	[SPDIFOO] = {.left = 0x20, .right = 0x21},
+	[SPDIFIO] = {.left = 0x15, .right = 0x1d},
+	[SPDIFI1] = {.left = 0x95, .right = 0x9d},
+};
+
+struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
+	[LINEO1] = {.left = 0x40, .right = 0x41},
+	[LINEO2] = {.left = 0x70, .right = 0x71},
+	[LINEO3] = {.left = 0x50, .right = 0x51},
+	[LINEO4] = {.left = 0x60, .right = 0x61},
+	[LINEIM] = {.left = 0x45, .right = 0xc5},
+	[SPDIFOO] = {.left = 0x00, .right = 0x01},
+	[SPDIFIO] = {.left = 0x05, .right = 0x85},
+};
+
+static int daio_master(struct rsc *rsc)
+{
+	/* Actually, this is not the resource index of DAIO.
+	 * For DAO, it is the input mapper index. And, for DAI,
+	 * it is the output time-slot index. */
+	return rsc->conj = rsc->idx;
+}
+
+static int daio_index(const struct rsc *rsc)
+{
+	return rsc->conj;
+}
+
+static int daio_out_next_conj(struct rsc *rsc)
+{
+	return rsc->conj += 2;
+}
+
+static int daio_in_next_conj_20k1(struct rsc *rsc)
+{
+	return rsc->conj += 0x200;
+}
+
+static int daio_in_next_conj_20k2(struct rsc *rsc)
+{
+	return rsc->conj += 0x100;
+}
+
+static struct rsc_ops daio_out_rsc_ops = {
+	.master		= daio_master,
+	.next_conj	= daio_out_next_conj,
+	.index		= daio_index,
+	.output_slot	= NULL,
+};
+
+static struct rsc_ops daio_in_rsc_ops_20k1 = {
+	.master		= daio_master,
+	.next_conj	= daio_in_next_conj_20k1,
+	.index		= NULL,
+	.output_slot	= daio_index,
+};
+
+static struct rsc_ops daio_in_rsc_ops_20k2 = {
+	.master		= daio_master,
+	.next_conj	= daio_in_next_conj_20k2,
+	.index		= NULL,
+	.output_slot	= daio_index,
+};
+
+static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
+{
+	switch (hw->chip_type) {
+	case ATC20K1:
+		switch (type) {
+		case SPDIFOO:	return 0;
+		case SPDIFIO:	return 0;
+		case SPDIFI1:	return 1;
+		case LINEO1:	return 4;
+		case LINEO2:	return 7;
+		case LINEO3:	return 5;
+		case LINEO4:	return 6;
+		case LINEIM:	return 7;
+		default:	return -EINVAL;
+		}
+	case ATC20K2:
+		switch (type) {
+		case SPDIFOO:	return 0;
+		case SPDIFIO:	return 0;
+		case LINEO1:	return 4;
+		case LINEO2:	return 7;
+		case LINEO3:	return 5;
+		case LINEO4:	return 6;
+		case LINEIM:	return 4;
+		default:	return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc);
+
+static int dao_spdif_get_spos(struct dao *dao, unsigned int *spos)
+{
+	((struct hw *)dao->hw)->dao_get_spos(dao->ctrl_blk, spos);
+	return 0;
+}
+
+static int dao_spdif_set_spos(struct dao *dao, unsigned int spos)
+{
+	((struct hw *)dao->hw)->dao_set_spos(dao->ctrl_blk, spos);
+	return 0;
+}
+
+static int dao_commit_write(struct dao *dao)
+{
+	((struct hw *)dao->hw)->dao_commit_write(dao->hw,
+		daio_device_index(dao->daio.type, dao->hw), dao->ctrl_blk);
+	return 0;
+}
+
+static int dao_set_left_input(struct dao *dao, struct rsc *input)
+{
+	struct imapper *entry;
+	struct daio *daio = &dao->daio;
+	int i;
+
+	entry = kzalloc((sizeof(*entry) * daio->rscl.msr), GFP_KERNEL);
+	if (NULL == entry)
+		return -ENOMEM;
+
+	/* Program master and conjugate resources */
+	input->ops->master(input);
+	daio->rscl.ops->master(&daio->rscl);
+	for (i = 0; i < daio->rscl.msr; i++, entry++) {
+		entry->slot = input->ops->output_slot(input);
+		entry->user = entry->addr = daio->rscl.ops->index(&daio->rscl);
+		dao->mgr->imap_add(dao->mgr, entry);
+		dao->imappers[i] = entry;
+
+		input->ops->next_conj(input);
+		daio->rscl.ops->next_conj(&daio->rscl);
+	}
+	input->ops->master(input);
+	daio->rscl.ops->master(&daio->rscl);
+
+	return 0;
+}
+
+static int dao_set_right_input(struct dao *dao, struct rsc *input)
+{
+	struct imapper *entry;
+	struct daio *daio = &dao->daio;
+	int i;
+
+	entry = kzalloc((sizeof(*entry) * daio->rscr.msr), GFP_KERNEL);
+	if (NULL == entry)
+		return -ENOMEM;
+
+	/* Program master and conjugate resources */
+	input->ops->master(input);
+	daio->rscr.ops->master(&daio->rscr);
+	for (i = 0; i < daio->rscr.msr; i++, entry++) {
+		entry->slot = input->ops->output_slot(input);
+		entry->user = entry->addr = daio->rscr.ops->index(&daio->rscr);
+		dao->mgr->imap_add(dao->mgr, entry);
+		dao->imappers[daio->rscl.msr + i] = entry;
+
+		input->ops->next_conj(input);
+		daio->rscr.ops->next_conj(&daio->rscr);
+	}
+	input->ops->master(input);
+	daio->rscr.ops->master(&daio->rscr);
+
+	return 0;
+}
+
+static int dao_clear_left_input(struct dao *dao)
+{
+	struct imapper *entry;
+	struct daio *daio = &dao->daio;
+	int i;
+
+	if (NULL == dao->imappers[0])
+		return 0;
+
+	entry = dao->imappers[0];
+	dao->mgr->imap_delete(dao->mgr, entry);
+	/* Program conjugate resources */
+	for (i = 1; i < daio->rscl.msr; i++) {
+		entry = dao->imappers[i];
+		dao->mgr->imap_delete(dao->mgr, entry);
+		dao->imappers[i] = NULL;
+	}
+
+	kfree(dao->imappers[0]);
+	dao->imappers[0] = NULL;
+
+	return 0;
+}
+
+static int dao_clear_right_input(struct dao *dao)
+{
+	struct imapper *entry;
+	struct daio *daio = &dao->daio;
+	int i;
+
+	if (NULL == dao->imappers[daio->rscl.msr])
+		return 0;
+
+	entry = dao->imappers[daio->rscl.msr];
+	dao->mgr->imap_delete(dao->mgr, entry);
+	/* Program conjugate resources */
+	for (i = 1; i < daio->rscr.msr; i++) {
+		entry = dao->imappers[daio->rscl.msr + i];
+		dao->mgr->imap_delete(dao->mgr, entry);
+		dao->imappers[daio->rscl.msr + i] = NULL;
+	}
+
+	kfree(dao->imappers[daio->rscl.msr]);
+	dao->imappers[daio->rscl.msr] = NULL;
+
+	return 0;
+}
+
+static struct dao_rsc_ops dao_ops = {
+	.set_spos		= dao_spdif_set_spos,
+	.commit_write		= dao_commit_write,
+	.get_spos		= dao_spdif_get_spos,
+	.reinit			= dao_rsc_reinit,
+	.set_left_input		= dao_set_left_input,
+	.set_right_input	= dao_set_right_input,
+	.clear_left_input	= dao_clear_left_input,
+	.clear_right_input	= dao_clear_right_input,
+};
+
+static int dai_set_srt_srcl(struct dai *dai, struct rsc *src)
+{
+	src->ops->master(src);
+	((struct hw *)dai->hw)->dai_srt_set_srcm(dai->ctrl_blk,
+						src->ops->index(src));
+	return 0;
+}
+
+static int dai_set_srt_srcr(struct dai *dai, struct rsc *src)
+{
+	src->ops->master(src);
+	((struct hw *)dai->hw)->dai_srt_set_srco(dai->ctrl_blk,
+						src->ops->index(src));
+	return 0;
+}
+
+static int dai_set_srt_msr(struct dai *dai, unsigned int msr)
+{
+	unsigned int rsr;
+
+	for (rsr = 0; msr > 1; msr >>= 1)
+		rsr++;
+
+	((struct hw *)dai->hw)->dai_srt_set_rsr(dai->ctrl_blk, rsr);
+	return 0;
+}
+
+static int dai_set_enb_src(struct dai *dai, unsigned int enb)
+{
+	((struct hw *)dai->hw)->dai_srt_set_ec(dai->ctrl_blk, enb);
+	return 0;
+}
+
+static int dai_set_enb_srt(struct dai *dai, unsigned int enb)
+{
+	((struct hw *)dai->hw)->dai_srt_set_et(dai->ctrl_blk, enb);
+	return 0;
+}
+
+static int dai_commit_write(struct dai *dai)
+{
+	((struct hw *)dai->hw)->dai_commit_write(dai->hw,
+		daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk);
+	return 0;
+}
+
+static struct dai_rsc_ops dai_ops = {
+	.set_srt_srcl		= dai_set_srt_srcl,
+	.set_srt_srcr		= dai_set_srt_srcr,
+	.set_srt_msr		= dai_set_srt_msr,
+	.set_enb_src		= dai_set_enb_src,
+	.set_enb_srt		= dai_set_enb_srt,
+	.commit_write		= dai_commit_write,
+};
+
+static int daio_rsc_init(struct daio *daio,
+			 const struct daio_desc *desc,
+			 void *hw)
+{
+	int err;
+	unsigned int idx_l, idx_r;
+
+	switch (((struct hw *)hw)->chip_type) {
+	case ATC20K1:
+		idx_l = idx_20k1[desc->type].left;
+		idx_r = idx_20k1[desc->type].right;
+		break;
+	case ATC20K2:
+		idx_l = idx_20k2[desc->type].left;
+		idx_r = idx_20k2[desc->type].right;
+		break;
+	default:
+		return -EINVAL;
+	}
+	err = rsc_init(&daio->rscl, idx_l, DAIO, desc->msr, hw);
+	if (err)
+		return err;
+
+	err = rsc_init(&daio->rscr, idx_r, DAIO, desc->msr, hw);
+	if (err)
+		goto error1;
+
+	/* Set daio->rscl/r->ops to daio specific ones */
+	if (desc->type <= DAIO_OUT_MAX) {
+		daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops;
+	} else {
+		switch (((struct hw *)hw)->chip_type) {
+		case ATC20K1:
+			daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k1;
+			break;
+		case ATC20K2:
+			daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k2;
+			break;
+		default:
+			break;
+		}
+	}
+	daio->type = desc->type;
+
+	return 0;
+
+error1:
+	rsc_uninit(&daio->rscl);
+	return err;
+}
+
+static int daio_rsc_uninit(struct daio *daio)
+{
+	rsc_uninit(&daio->rscl);
+	rsc_uninit(&daio->rscr);
+
+	return 0;
+}
+
+static int dao_rsc_init(struct dao *dao,
+			const struct daio_desc *desc,
+			struct daio_mgr *mgr)
+{
+	struct hw *hw = mgr->mgr.hw;
+	unsigned int conf;
+	int err;
+
+	err = daio_rsc_init(&dao->daio, desc, mgr->mgr.hw);
+	if (err)
+		return err;
+
+	dao->imappers = kzalloc(sizeof(void *)*desc->msr*2, GFP_KERNEL);
+	if (NULL == dao->imappers) {
+		err = -ENOMEM;
+		goto error1;
+	}
+	dao->ops = &dao_ops;
+	dao->mgr = mgr;
+	dao->hw = hw;
+	err = hw->dao_get_ctrl_blk(&dao->ctrl_blk);
+	if (err)
+		goto error2;
+
+	hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,
+			daio_device_index(dao->daio.type, hw));
+	hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
+
+	conf = (desc->msr & 0x7) | (desc->passthru << 3);
+	hw->daio_mgr_dao_init(mgr->mgr.ctrl_blk,
+			daio_device_index(dao->daio.type, hw), conf);
+	hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
+			daio_device_index(dao->daio.type, hw));
+	hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
+
+	return 0;
+
+error2:
+	kfree(dao->imappers);
+	dao->imappers = NULL;
+error1:
+	daio_rsc_uninit(&dao->daio);
+	return err;
+}
+
+static int dao_rsc_uninit(struct dao *dao)
+{
+	if (NULL != dao->imappers) {
+		if (NULL != dao->imappers[0])
+			dao_clear_left_input(dao);
+
+		if (NULL != dao->imappers[dao->daio.rscl.msr])
+			dao_clear_right_input(dao);
+
+		kfree(dao->imappers);
+		dao->imappers = NULL;
+	}
+	((struct hw *)dao->hw)->dao_put_ctrl_blk(dao->ctrl_blk);
+	dao->hw = dao->ctrl_blk = NULL;
+	daio_rsc_uninit(&dao->daio);
+
+	return 0;
+}
+
+static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc)
+{
+	struct daio_mgr *mgr = dao->mgr;
+	struct daio_desc dsc = {0};
+
+	dsc.type = dao->daio.type;
+	dsc.msr = desc->msr;
+	dsc.passthru = desc->passthru;
+	dao_rsc_uninit(dao);
+	return dao_rsc_init(dao, &dsc, mgr);
+}
+
+static int dai_rsc_init(struct dai *dai,
+			const struct daio_desc *desc,
+			struct daio_mgr *mgr)
+{
+	int err;
+	struct hw *hw = mgr->mgr.hw;
+	unsigned int rsr, msr;
+
+	err = daio_rsc_init(&dai->daio, desc, mgr->mgr.hw);
+	if (err)
+		return err;
+
+	dai->ops = &dai_ops;
+	dai->hw = mgr->mgr.hw;
+	err = hw->dai_get_ctrl_blk(&dai->ctrl_blk);
+	if (err)
+		goto error1;
+
+	for (rsr = 0, msr = desc->msr; msr > 1; msr >>= 1)
+		rsr++;
+
+	hw->dai_srt_set_rsr(dai->ctrl_blk, rsr);
+	hw->dai_srt_set_drat(dai->ctrl_blk, 0);
+	/* default to disabling control of a SRC */
+	hw->dai_srt_set_ec(dai->ctrl_blk, 0);
+	hw->dai_srt_set_et(dai->ctrl_blk, 0); /* default to disabling SRT */
+	hw->dai_commit_write(hw,
+		daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk);
+
+	return 0;
+
+error1:
+	daio_rsc_uninit(&dai->daio);
+	return err;
+}
+
+static int dai_rsc_uninit(struct dai *dai)
+{
+	((struct hw *)dai->hw)->dai_put_ctrl_blk(dai->ctrl_blk);
+	dai->hw = dai->ctrl_blk = NULL;
+	daio_rsc_uninit(&dai->daio);
+	return 0;
+}
+
+static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
+{
+	if (((union daio_usage *)mgr->rscs)->data & (0x1 << type))
+		return -ENOENT;
+
+	((union daio_usage *)mgr->rscs)->data |= (0x1 << type);
+
+	return 0;
+}
+
+static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
+{
+	((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
+
+	return 0;
+}
+
+static int get_daio_rsc(struct daio_mgr *mgr,
+			const struct daio_desc *desc,
+			struct daio **rdaio)
+{
+	int err;
+	struct dai *dai = NULL;
+	struct dao *dao = NULL;
+	unsigned long flags;
+
+	*rdaio = NULL;
+
+	/* Check whether there are sufficient daio resources to meet request. */
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	err = daio_mgr_get_rsc(&mgr->mgr, desc->type);
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+	if (err) {
+		printk(KERN_ERR "Can't meet DAIO resource request!\n");
+		return err;
+	}
+
+	/* Allocate mem for daio resource */
+	if (desc->type <= DAIO_OUT_MAX) {
+		dao = kzalloc(sizeof(*dao), GFP_KERNEL);
+		if (NULL == dao) {
+			err = -ENOMEM;
+			goto error;
+		}
+		err = dao_rsc_init(dao, desc, mgr);
+		if (err)
+			goto error;
+
+		*rdaio = &dao->daio;
+	} else {
+		dai = kzalloc(sizeof(*dai), GFP_KERNEL);
+		if (NULL == dai) {
+			err = -ENOMEM;
+			goto error;
+		}
+		err = dai_rsc_init(dai, desc, mgr);
+		if (err)
+			goto error;
+
+		*rdaio = &dai->daio;
+	}
+
+	mgr->daio_enable(mgr, *rdaio);
+	mgr->commit_write(mgr);
+
+	return 0;
+
+error:
+	if (NULL != dao)
+		kfree(dao);
+	else if (NULL != dai)
+		kfree(dai);
+
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	daio_mgr_put_rsc(&mgr->mgr, desc->type);
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+	return err;
+}
+
+static int put_daio_rsc(struct daio_mgr *mgr, struct daio *daio)
+{
+	unsigned long flags;
+
+	mgr->daio_disable(mgr, daio);
+	mgr->commit_write(mgr);
+
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	daio_mgr_put_rsc(&mgr->mgr, daio->type);
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+
+	if (daio->type <= DAIO_OUT_MAX) {
+		dao_rsc_uninit(container_of(daio, struct dao, daio));
+		kfree(container_of(daio, struct dao, daio));
+	} else {
+		dai_rsc_uninit(container_of(daio, struct dai, daio));
+		kfree(container_of(daio, struct dai, daio));
+	}
+
+	return 0;
+}
+
+static int daio_mgr_enb_daio(struct daio_mgr *mgr, struct daio *daio)
+{
+	struct hw *hw = mgr->mgr.hw;
+
+	if (DAIO_OUT_MAX >= daio->type) {
+		hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
+				daio_device_index(daio->type, hw));
+	} else {
+		hw->daio_mgr_enb_dai(mgr->mgr.ctrl_blk,
+				daio_device_index(daio->type, hw));
+	}
+	return 0;
+}
+
+static int daio_mgr_dsb_daio(struct daio_mgr *mgr, struct daio *daio)
+{
+	struct hw *hw = mgr->mgr.hw;
+
+	if (DAIO_OUT_MAX >= daio->type) {
+		hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,
+				daio_device_index(daio->type, hw));
+	} else {
+		hw->daio_mgr_dsb_dai(mgr->mgr.ctrl_blk,
+				daio_device_index(daio->type, hw));
+	}
+	return 0;
+}
+
+static int daio_map_op(void *data, struct imapper *entry)
+{
+	struct rsc_mgr *mgr = &((struct daio_mgr *)data)->mgr;
+	struct hw *hw = mgr->hw;
+
+	hw->daio_mgr_set_imaparc(mgr->ctrl_blk, entry->slot);
+	hw->daio_mgr_set_imapnxt(mgr->ctrl_blk, entry->next);
+	hw->daio_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr);
+	hw->daio_mgr_commit_write(mgr->hw, mgr->ctrl_blk);
+
+	return 0;
+}
+
+static int daio_imap_add(struct daio_mgr *mgr, struct imapper *entry)
+{
+	unsigned long flags;
+	int err;
+
+	spin_lock_irqsave(&mgr->imap_lock, flags);
+	if ((0 == entry->addr) && (mgr->init_imap_added)) {
+		input_mapper_delete(&mgr->imappers, mgr->init_imap,
+							daio_map_op, mgr);
+		mgr->init_imap_added = 0;
+	}
+	err = input_mapper_add(&mgr->imappers, entry, daio_map_op, mgr);
+	spin_unlock_irqrestore(&mgr->imap_lock, flags);
+
+	return err;
+}
+
+static int daio_imap_delete(struct daio_mgr *mgr, struct imapper *entry)
+{
+	unsigned long flags;
+	int err;
+
+	spin_lock_irqsave(&mgr->imap_lock, flags);
+	err = input_mapper_delete(&mgr->imappers, entry, daio_map_op, mgr);
+	if (list_empty(&mgr->imappers)) {
+		input_mapper_add(&mgr->imappers, mgr->init_imap,
+							daio_map_op, mgr);
+		mgr->init_imap_added = 1;
+	}
+	spin_unlock_irqrestore(&mgr->imap_lock, flags);
+
+	return err;
+}
+
+static int daio_mgr_commit_write(struct daio_mgr *mgr)
+{
+	struct hw *hw = mgr->mgr.hw;
+
+	hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
+	return 0;
+}
+
+int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr)
+{
+	int err, i;
+	struct daio_mgr *daio_mgr;
+	struct imapper *entry;
+
+	*rdaio_mgr = NULL;
+	daio_mgr = kzalloc(sizeof(*daio_mgr), GFP_KERNEL);
+	if (NULL == daio_mgr)
+		return -ENOMEM;
+
+	err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw);
+	if (err)
+		goto error1;
+
+	spin_lock_init(&daio_mgr->mgr_lock);
+	spin_lock_init(&daio_mgr->imap_lock);
+	INIT_LIST_HEAD(&daio_mgr->imappers);
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (NULL == entry) {
+		err = -ENOMEM;
+		goto error2;
+	}
+	entry->slot = entry->addr = entry->next = entry->user = 0;
+	list_add(&entry->list, &daio_mgr->imappers);
+	daio_mgr->init_imap = entry;
+	daio_mgr->init_imap_added = 1;
+
+	daio_mgr->get_daio = get_daio_rsc;
+	daio_mgr->put_daio = put_daio_rsc;
+	daio_mgr->daio_enable = daio_mgr_enb_daio;
+	daio_mgr->daio_disable = daio_mgr_dsb_daio;
+	daio_mgr->imap_add = daio_imap_add;
+	daio_mgr->imap_delete = daio_imap_delete;
+	daio_mgr->commit_write = daio_mgr_commit_write;
+
+	for (i = 0; i < 8; i++) {
+		((struct hw *)hw)->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i);
+		((struct hw *)hw)->daio_mgr_dsb_dai(daio_mgr->mgr.ctrl_blk, i);
+	}
+	((struct hw *)hw)->daio_mgr_commit_write(hw, daio_mgr->mgr.ctrl_blk);
+
+	*rdaio_mgr = daio_mgr;
+
+	return 0;
+
+error2:
+	rsc_mgr_uninit(&daio_mgr->mgr);
+error1:
+	kfree(daio_mgr);
+	return err;
+}
+
+int daio_mgr_destroy(struct daio_mgr *daio_mgr)
+{
+	unsigned long flags;
+
+	/* free daio input mapper list */
+	spin_lock_irqsave(&daio_mgr->imap_lock, flags);
+	free_input_mapper_list(&daio_mgr->imappers);
+	spin_unlock_irqrestore(&daio_mgr->imap_lock, flags);
+
+	rsc_mgr_uninit(&daio_mgr->mgr);
+	kfree(daio_mgr);
+
+	return 0;
+}
+
diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h
new file mode 100644
index 0000000..0f52ce5
--- /dev/null
+++ b/sound/pci/ctxfi/ctdaio.h
@@ -0,0 +1,122 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctdaio.h
+ *
+ * @Brief
+ * This file contains the definition of Digital Audio Input Output
+ * resource management object.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 23 2008
+ *
+ */
+
+#ifndef CTDAIO_H
+#define CTDAIO_H
+
+#include "ctresource.h"
+#include "ctimap.h"
+#include <linux/spinlock.h>
+#include <linux/list.h>
+
+/* Define the descriptor of a daio resource */
+enum DAIOTYP {
+	LINEO1,
+	LINEO2,
+	LINEO3,
+	LINEO4,
+	SPDIFOO,	/* S/PDIF Out (Flexijack/Optical) */
+	LINEIM,
+	SPDIFIO,	/* S/PDIF In (Flexijack/Optical) on the card */
+	SPDIFI1,	/* S/PDIF In on internal Drive Bay */
+	NUM_DAIOTYP
+};
+
+struct dao_rsc_ops;
+struct dai_rsc_ops;
+struct daio_mgr;
+
+struct daio {
+	struct rsc rscl;	/* Basic resource info for left TX/RX */
+	struct rsc rscr;	/* Basic resource info for right TX/RX */
+	enum DAIOTYP type;
+};
+
+struct dao {
+	struct daio daio;
+	struct dao_rsc_ops *ops;	/* DAO specific operations */
+	struct imapper **imappers;
+	struct daio_mgr *mgr;
+	void *hw;
+	void *ctrl_blk;
+};
+
+struct dai {
+	struct daio daio;
+	struct dai_rsc_ops *ops;	/* DAI specific operations */
+	void *hw;
+	void *ctrl_blk;
+};
+
+struct dao_desc {
+	unsigned int msr:4;
+	unsigned int passthru:1;
+};
+
+struct dao_rsc_ops {
+	int (*set_spos)(struct dao *dao, unsigned int spos);
+	int (*commit_write)(struct dao *dao);
+	int (*get_spos)(struct dao *dao, unsigned int *spos);
+	int (*reinit)(struct dao *dao, const struct dao_desc *desc);
+	int (*set_left_input)(struct dao *dao, struct rsc *input);
+	int (*set_right_input)(struct dao *dao, struct rsc *input);
+	int (*clear_left_input)(struct dao *dao);
+	int (*clear_right_input)(struct dao *dao);
+};
+
+struct dai_rsc_ops {
+	int (*set_srt_srcl)(struct dai *dai, struct rsc *src);
+	int (*set_srt_srcr)(struct dai *dai, struct rsc *src);
+	int (*set_srt_msr)(struct dai *dai, unsigned int msr);
+	int (*set_enb_src)(struct dai *dai, unsigned int enb);
+	int (*set_enb_srt)(struct dai *dai, unsigned int enb);
+	int (*commit_write)(struct dai *dai);
+};
+
+/* Define daio resource request description info */
+struct daio_desc {
+	unsigned int type:4;
+	unsigned int msr:4;
+	unsigned int passthru:1;
+};
+
+struct daio_mgr {
+	struct rsc_mgr mgr;	/* Basic resource manager info */
+	spinlock_t mgr_lock;
+	spinlock_t imap_lock;
+	struct list_head imappers;
+	struct imapper *init_imap;
+	unsigned int init_imap_added;
+
+	 /* request one daio resource */
+	int (*get_daio)(struct daio_mgr *mgr,
+			const struct daio_desc *desc, struct daio **rdaio);
+	/* return one daio resource */
+	int (*put_daio)(struct daio_mgr *mgr, struct daio *daio);
+	int (*daio_enable)(struct daio_mgr *mgr, struct daio *daio);
+	int (*daio_disable)(struct daio_mgr *mgr, struct daio *daio);
+	int (*imap_add)(struct daio_mgr *mgr, struct imapper *entry);
+	int (*imap_delete)(struct daio_mgr *mgr, struct imapper *entry);
+	int (*commit_write)(struct daio_mgr *mgr);
+};
+
+/* Constructor and destructor of daio resource manager */
+int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr);
+int daio_mgr_destroy(struct daio_mgr *daio_mgr);
+
+#endif /* CTDAIO_H */
diff --git a/sound/pci/ctxfi/cthardware.c b/sound/pci/ctxfi/cthardware.c
new file mode 100644
index 0000000..8e64f48
--- /dev/null
+++ b/sound/pci/ctxfi/cthardware.c
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	cthardware.c
+ *
+ * @Brief
+ * This file contains the implementation of hardware access methord.
+ *
+ * @Author	Liu Chun
+ * @Date 	Jun 26 2008
+ *
+ */
+
+#include "cthardware.h"
+#include "cthw20k1.h"
+#include "cthw20k2.h"
+#include <linux/bug.h>
+
+int __devinit create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type,
+			    enum CTCARDS model, struct hw **rhw)
+{
+	int err;
+
+	switch (chip_type) {
+	case ATC20K1:
+		err = create_20k1_hw_obj(rhw);
+		break;
+	case ATC20K2:
+		err = create_20k2_hw_obj(rhw);
+		break;
+	default:
+		err = -ENODEV;
+		break;
+	}
+	if (err)
+		return err;
+
+	(*rhw)->pci = pci;
+	(*rhw)->chip_type = chip_type;
+	(*rhw)->model = model;
+
+	return 0;
+}
+
+int destroy_hw_obj(struct hw *hw)
+{
+	int err;
+
+	switch (hw->pci->device) {
+	case 0x0005:	/* 20k1 device */
+		err = destroy_20k1_hw_obj(hw);
+		break;
+	case 0x000B:	/* 20k2 device */
+		err = destroy_20k2_hw_obj(hw);
+		break;
+	default:
+		err = -ENODEV;
+		break;
+	}
+
+	return err;
+}
+
+unsigned int get_field(unsigned int data, unsigned int field)
+{
+	int i;
+
+	BUG_ON(!field);
+	/* @field should always be greater than 0 */
+	for (i = 0; !(field & (1 << i)); )
+		i++;
+
+	return (data & field) >> i;
+}
+
+void set_field(unsigned int *data, unsigned int field, unsigned int value)
+{
+	int i;
+
+	BUG_ON(!field);
+	/* @field should always be greater than 0 */
+	for (i = 0; !(field & (1 << i)); )
+		i++;
+
+	*data = (*data & (~field)) | ((value << i) & field);
+}
+
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h
new file mode 100644
index 0000000..4a8e04f
--- /dev/null
+++ b/sound/pci/ctxfi/cthardware.h
@@ -0,0 +1,196 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	cthardware.h
+ *
+ * @Brief
+ * This file contains the definition of hardware access methord.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 13 2008
+ *
+ */
+
+#ifndef CTHARDWARE_H
+#define CTHARDWARE_H
+
+#include <linux/types.h>
+#include <linux/pci.h>
+
+enum CHIPTYP {
+	ATC20K1,
+	ATC20K2,
+	ATCNONE
+};
+
+enum CTCARDS {
+	/* 20k1 models */
+	CTSB055X,
+	CTSB073X,
+	CTUAA,
+	CT20K1_UNKNOWN,
+	/* 20k2 models */
+	CTSB0760,
+	CTHENDRIX,
+	CTSB0880,
+	NUM_CTCARDS		/* This should always be the last */
+};
+
+/* Type of input source for ADC */
+enum ADCSRC{
+	ADC_MICIN,
+	ADC_LINEIN,
+	ADC_VIDEO,
+	ADC_AUX,
+	ADC_NONE	/* Switch to digital input */
+};
+
+struct card_conf {
+	/* device virtual mem page table page physical addr
+	 * (supporting one page table page now) */
+	unsigned long vm_pgt_phys;
+	unsigned int rsr;	/* reference sample rate in Hzs*/
+	unsigned int msr;	/* master sample rate in rsrs */
+};
+
+struct hw {
+	int (*card_init)(struct hw *hw, struct card_conf *info);
+	int (*card_stop)(struct hw *hw);
+	int (*pll_init)(struct hw *hw, unsigned int rsr);
+	int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source);
+	int (*select_adc_source)(struct hw *hw, enum ADCSRC source);
+	int (*have_digit_io_switch)(struct hw *hw);
+
+	/* SRC operations */
+	int (*src_rsc_get_ctrl_blk)(void **rblk);
+	int (*src_rsc_put_ctrl_blk)(void *blk);
+	int (*src_set_state)(void *blk, unsigned int state);
+	int (*src_set_bm)(void *blk, unsigned int bm);
+	int (*src_set_rsr)(void *blk, unsigned int rsr);
+	int (*src_set_sf)(void *blk, unsigned int sf);
+	int (*src_set_wr)(void *blk, unsigned int wr);
+	int (*src_set_pm)(void *blk, unsigned int pm);
+	int (*src_set_rom)(void *blk, unsigned int rom);
+	int (*src_set_vo)(void *blk, unsigned int vo);
+	int (*src_set_st)(void *blk, unsigned int st);
+	int (*src_set_ie)(void *blk, unsigned int ie);
+	int (*src_set_ilsz)(void *blk, unsigned int ilsz);
+	int (*src_set_bp)(void *blk, unsigned int bp);
+	int (*src_set_cisz)(void *blk, unsigned int cisz);
+	int (*src_set_ca)(void *blk, unsigned int ca);
+	int (*src_set_sa)(void *blk, unsigned int sa);
+	int (*src_set_la)(void *blk, unsigned int la);
+	int (*src_set_pitch)(void *blk, unsigned int pitch);
+	int (*src_set_clear_zbufs)(void *blk, unsigned int clear);
+	int (*src_set_dirty)(void *blk, unsigned int flags);
+	int (*src_set_dirty_all)(void *blk);
+	int (*src_commit_write)(struct hw *hw, unsigned int idx, void *blk);
+	int (*src_get_ca)(struct hw *hw, unsigned int idx, void *blk);
+	unsigned int (*src_get_dirty)(void *blk);
+	unsigned int (*src_dirty_conj_mask)(void);
+	int (*src_mgr_get_ctrl_blk)(void **rblk);
+	int (*src_mgr_put_ctrl_blk)(void *blk);
+	/* syncly enable src @idx */
+	int (*src_mgr_enbs_src)(void *blk, unsigned int idx);
+	/* enable src @idx */
+	int (*src_mgr_enb_src)(void *blk, unsigned int idx);
+	/* disable src @idx */
+	int (*src_mgr_dsb_src)(void *blk, unsigned int idx);
+	int (*src_mgr_commit_write)(struct hw *hw, void *blk);
+
+	/* SRC Input Mapper operations */
+	int (*srcimp_mgr_get_ctrl_blk)(void **rblk);
+	int (*srcimp_mgr_put_ctrl_blk)(void *blk);
+	int (*srcimp_mgr_set_imaparc)(void *blk, unsigned int slot);
+	int (*srcimp_mgr_set_imapuser)(void *blk, unsigned int user);
+	int (*srcimp_mgr_set_imapnxt)(void *blk, unsigned int next);
+	int (*srcimp_mgr_set_imapaddr)(void *blk, unsigned int addr);
+	int (*srcimp_mgr_commit_write)(struct hw *hw, void *blk);
+
+	/* AMIXER operations */
+	int (*amixer_rsc_get_ctrl_blk)(void **rblk);
+	int (*amixer_rsc_put_ctrl_blk)(void *blk);
+	int (*amixer_mgr_get_ctrl_blk)(void **rblk);
+	int (*amixer_mgr_put_ctrl_blk)(void *blk);
+	int (*amixer_set_mode)(void *blk, unsigned int mode);
+	int (*amixer_set_iv)(void *blk, unsigned int iv);
+	int (*amixer_set_x)(void *blk, unsigned int x);
+	int (*amixer_set_y)(void *blk, unsigned int y);
+	int (*amixer_set_sadr)(void *blk, unsigned int sadr);
+	int (*amixer_set_se)(void *blk, unsigned int se);
+	int (*amixer_set_dirty)(void *blk, unsigned int flags);
+	int (*amixer_set_dirty_all)(void *blk);
+	int (*amixer_commit_write)(struct hw *hw, unsigned int idx, void *blk);
+	int (*amixer_get_y)(void *blk);
+	unsigned int (*amixer_get_dirty)(void *blk);
+
+	/* DAIO operations */
+	int (*dai_get_ctrl_blk)(void **rblk);
+	int (*dai_put_ctrl_blk)(void *blk);
+	int (*dai_srt_set_srco)(void *blk, unsigned int src);
+	int (*dai_srt_set_srcm)(void *blk, unsigned int src);
+	int (*dai_srt_set_rsr)(void *blk, unsigned int rsr);
+	int (*dai_srt_set_drat)(void *blk, unsigned int drat);
+	int (*dai_srt_set_ec)(void *blk, unsigned int ec);
+	int (*dai_srt_set_et)(void *blk, unsigned int et);
+	int (*dai_commit_write)(struct hw *hw, unsigned int idx, void *blk);
+	int (*dao_get_ctrl_blk)(void **rblk);
+	int (*dao_put_ctrl_blk)(void *blk);
+	int (*dao_set_spos)(void *blk, unsigned int spos);
+	int (*dao_commit_write)(struct hw *hw, unsigned int idx, void *blk);
+	int (*dao_get_spos)(void *blk, unsigned int *spos);
+
+	int (*daio_mgr_get_ctrl_blk)(struct hw *hw, void **rblk);
+	int (*daio_mgr_put_ctrl_blk)(void *blk);
+	int (*daio_mgr_enb_dai)(void *blk, unsigned int idx);
+	int (*daio_mgr_dsb_dai)(void *blk, unsigned int idx);
+	int (*daio_mgr_enb_dao)(void *blk, unsigned int idx);
+	int (*daio_mgr_dsb_dao)(void *blk, unsigned int idx);
+	int (*daio_mgr_dao_init)(void *blk, unsigned int idx,
+						unsigned int conf);
+	int (*daio_mgr_set_imaparc)(void *blk, unsigned int slot);
+	int (*daio_mgr_set_imapnxt)(void *blk, unsigned int next);
+	int (*daio_mgr_set_imapaddr)(void *blk, unsigned int addr);
+	int (*daio_mgr_commit_write)(struct hw *hw, void *blk);
+
+	int (*set_timer_irq)(struct hw *hw, int enable);
+	int (*set_timer_tick)(struct hw *hw, unsigned int tick);
+	unsigned int (*get_wc)(struct hw *hw);
+
+	void (*irq_callback)(void *data, unsigned int bit);
+	void *irq_callback_data;
+
+	struct pci_dev *pci;	/* the pci kernel structure of this card */
+	int irq;
+	unsigned long io_base;
+	unsigned long mem_base;
+
+	enum CHIPTYP chip_type;
+	enum CTCARDS model;
+};
+
+int create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type,
+		  enum CTCARDS model, struct hw **rhw);
+int destroy_hw_obj(struct hw *hw);
+
+unsigned int get_field(unsigned int data, unsigned int field);
+void set_field(unsigned int *data, unsigned int field, unsigned int value);
+
+/* IRQ bits */
+#define	PLL_INT		(1 << 10) /* PLL input-clock out-of-range */
+#define FI_INT		(1 << 9)  /* forced interrupt */
+#define IT_INT		(1 << 8)  /* timer interrupt */
+#define PCI_INT		(1 << 7)  /* PCI bus error pending */
+#define URT_INT		(1 << 6)  /* UART Tx/Rx */
+#define GPI_INT		(1 << 5)  /* GPI pin */
+#define MIX_INT		(1 << 4)  /* mixer parameter segment FIFO channels */
+#define DAI_INT		(1 << 3)  /* DAI (SR-tracker or SPDIF-receiver) */
+#define TP_INT		(1 << 2)  /* transport priority queue */
+#define DSP_INT		(1 << 1)  /* DSP */
+#define SRC_INT		(1 << 0)  /* SRC channels */
+
+#endif /* CTHARDWARE_H */
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
new file mode 100644
index 0000000..cb69d9d
--- /dev/null
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -0,0 +1,2248 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	cthw20k1.c
+ *
+ * @Brief
+ * This file contains the implementation of hardware access methord for 20k1.
+ *
+ * @Author	Liu Chun
+ * @Date 	Jun 24 2008
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include "cthw20k1.h"
+#include "ct20k1reg.h"
+
+#if BITS_PER_LONG == 32
+#define CT_XFI_DMA_MASK		DMA_BIT_MASK(32) /* 32 bit PTE */
+#else
+#define CT_XFI_DMA_MASK		DMA_BIT_MASK(64) /* 64 bit PTE */
+#endif
+
+struct hw20k1 {
+	struct hw hw;
+	spinlock_t reg_20k1_lock;
+	spinlock_t reg_pci_lock;
+};
+
+static u32 hw_read_20kx(struct hw *hw, u32 reg);
+static void hw_write_20kx(struct hw *hw, u32 reg, u32 data);
+static u32 hw_read_pci(struct hw *hw, u32 reg);
+static void hw_write_pci(struct hw *hw, u32 reg, u32 data);
+
+/*
+ * Type definition block.
+ * The layout of control structures can be directly applied on 20k2 chip.
+ */
+
+/*
+ * SRC control block definitions.
+ */
+
+/* SRC resource control block */
+#define SRCCTL_STATE	0x00000007
+#define SRCCTL_BM	0x00000008
+#define SRCCTL_RSR	0x00000030
+#define SRCCTL_SF	0x000001C0
+#define SRCCTL_WR	0x00000200
+#define SRCCTL_PM	0x00000400
+#define SRCCTL_ROM	0x00001800
+#define SRCCTL_VO	0x00002000
+#define SRCCTL_ST	0x00004000
+#define SRCCTL_IE	0x00008000
+#define SRCCTL_ILSZ	0x000F0000
+#define SRCCTL_BP	0x00100000
+
+#define SRCCCR_CISZ	0x000007FF
+#define SRCCCR_CWA	0x001FF800
+#define SRCCCR_D	0x00200000
+#define SRCCCR_RS	0x01C00000
+#define SRCCCR_NAL	0x3E000000
+#define SRCCCR_RA	0xC0000000
+
+#define SRCCA_CA	0x03FFFFFF
+#define SRCCA_RS	0x1C000000
+#define SRCCA_NAL	0xE0000000
+
+#define SRCSA_SA	0x03FFFFFF
+
+#define SRCLA_LA	0x03FFFFFF
+
+/* Mixer Parameter Ring ram Low and Hight register.
+ * Fixed-point value in 8.24 format for parameter channel */
+#define MPRLH_PITCH	0xFFFFFFFF
+
+/* SRC resource register dirty flags */
+union src_dirty {
+	struct {
+		u16 ctl:1;
+		u16 ccr:1;
+		u16 sa:1;
+		u16 la:1;
+		u16 ca:1;
+		u16 mpr:1;
+		u16 czbfs:1;	/* Clear Z-Buffers */
+		u16 rsv:9;
+	} bf;
+	u16 data;
+};
+
+struct src_rsc_ctrl_blk {
+	unsigned int	ctl;
+	unsigned int 	ccr;
+	unsigned int	ca;
+	unsigned int	sa;
+	unsigned int	la;
+	unsigned int	mpr;
+	union src_dirty	dirty;
+};
+
+/* SRC manager control block */
+union src_mgr_dirty {
+	struct {
+		u16 enb0:1;
+		u16 enb1:1;
+		u16 enb2:1;
+		u16 enb3:1;
+		u16 enb4:1;
+		u16 enb5:1;
+		u16 enb6:1;
+		u16 enb7:1;
+		u16 enbsa:1;
+		u16 rsv:7;
+	} bf;
+	u16 data;
+};
+
+struct src_mgr_ctrl_blk {
+	unsigned int		enbsa;
+	unsigned int		enb[8];
+	union src_mgr_dirty	dirty;
+};
+
+/* SRCIMP manager control block */
+#define SRCAIM_ARC	0x00000FFF
+#define SRCAIM_NXT	0x00FF0000
+#define SRCAIM_SRC	0xFF000000
+
+struct srcimap {
+	unsigned int srcaim;
+	unsigned int idx;
+};
+
+/* SRCIMP manager register dirty flags */
+union srcimp_mgr_dirty {
+	struct {
+		u16 srcimap:1;
+		u16 rsv:15;
+	} bf;
+	u16 data;
+};
+
+struct srcimp_mgr_ctrl_blk {
+	struct srcimap		srcimap;
+	union srcimp_mgr_dirty	dirty;
+};
+
+/*
+ * Function implementation block.
+ */
+
+static int src_get_rsc_ctrl_blk(void **rblk)
+{
+	struct src_rsc_ctrl_blk *blk;
+
+	*rblk = NULL;
+	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	*rblk = blk;
+
+	return 0;
+}
+
+static int src_put_rsc_ctrl_blk(void *blk)
+{
+	kfree((struct src_rsc_ctrl_blk *)blk);
+
+	return 0;
+}
+
+static int src_set_state(void *blk, unsigned int state)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_STATE, state);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_bm(void *blk, unsigned int bm)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_BM, bm);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_rsr(void *blk, unsigned int rsr)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_RSR, rsr);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_sf(void *blk, unsigned int sf)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_SF, sf);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_wr(void *blk, unsigned int wr)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_WR, wr);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_pm(void *blk, unsigned int pm)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_PM, pm);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_rom(void *blk, unsigned int rom)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_ROM, rom);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_vo(void *blk, unsigned int vo)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_VO, vo);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_st(void *blk, unsigned int st)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_ST, st);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_ie(void *blk, unsigned int ie)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_IE, ie);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_ilsz(void *blk, unsigned int ilsz)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_bp(void *blk, unsigned int bp)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_BP, bp);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_cisz(void *blk, unsigned int cisz)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ccr, SRCCCR_CISZ, cisz);
+	ctl->dirty.bf.ccr = 1;
+	return 0;
+}
+
+static int src_set_ca(void *blk, unsigned int ca)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ca, SRCCA_CA, ca);
+	ctl->dirty.bf.ca = 1;
+	return 0;
+}
+
+static int src_set_sa(void *blk, unsigned int sa)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->sa, SRCSA_SA, sa);
+	ctl->dirty.bf.sa = 1;
+	return 0;
+}
+
+static int src_set_la(void *blk, unsigned int la)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->la, SRCLA_LA, la);
+	ctl->dirty.bf.la = 1;
+	return 0;
+}
+
+static int src_set_pitch(void *blk, unsigned int pitch)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->mpr, MPRLH_PITCH, pitch);
+	ctl->dirty.bf.mpr = 1;
+	return 0;
+}
+
+static int src_set_clear_zbufs(void *blk, unsigned int clear)
+{
+	((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0);
+	return 0;
+}
+
+static int src_set_dirty(void *blk, unsigned int flags)
+{
+	((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
+	return 0;
+}
+
+static int src_set_dirty_all(void *blk)
+{
+	((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
+	return 0;
+}
+
+#define AR_SLOT_SIZE		4096
+#define AR_SLOT_BLOCK_SIZE	16
+#define AR_PTS_PITCH		6
+#define AR_PARAM_SRC_OFFSET	0x60
+
+static unsigned int src_param_pitch_mixer(unsigned int src_idx)
+{
+	return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE
+			- AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE;
+
+}
+
+static int src_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+	int i;
+
+	if (ctl->dirty.bf.czbfs) {
+		/* Clear Z-Buffer registers */
+		for (i = 0; i < 8; i++)
+			hw_write_20kx(hw, SRCUPZ+idx*0x100+i*0x4, 0);
+
+		for (i = 0; i < 4; i++)
+			hw_write_20kx(hw, SRCDN0Z+idx*0x100+i*0x4, 0);
+
+		for (i = 0; i < 8; i++)
+			hw_write_20kx(hw, SRCDN1Z+idx*0x100+i*0x4, 0);
+
+		ctl->dirty.bf.czbfs = 0;
+	}
+	if (ctl->dirty.bf.mpr) {
+		/* Take the parameter mixer resource in the same group as that
+		 * the idx src is in for simplicity. Unlike src, all conjugate
+		 * parameter mixer resources must be programmed for
+		 * corresponding conjugate src resources. */
+		unsigned int pm_idx = src_param_pitch_mixer(idx);
+		hw_write_20kx(hw, PRING_LO_HI+4*pm_idx, ctl->mpr);
+		hw_write_20kx(hw, PMOPLO+8*pm_idx, 0x3);
+		hw_write_20kx(hw, PMOPHI+8*pm_idx, 0x0);
+		ctl->dirty.bf.mpr = 0;
+	}
+	if (ctl->dirty.bf.sa) {
+		hw_write_20kx(hw, SRCSA+idx*0x100, ctl->sa);
+		ctl->dirty.bf.sa = 0;
+	}
+	if (ctl->dirty.bf.la) {
+		hw_write_20kx(hw, SRCLA+idx*0x100, ctl->la);
+		ctl->dirty.bf.la = 0;
+	}
+	if (ctl->dirty.bf.ca) {
+		hw_write_20kx(hw, SRCCA+idx*0x100, ctl->ca);
+		ctl->dirty.bf.ca = 0;
+	}
+
+	/* Write srccf register */
+	hw_write_20kx(hw, SRCCF+idx*0x100, 0x0);
+
+	if (ctl->dirty.bf.ccr) {
+		hw_write_20kx(hw, SRCCCR+idx*0x100, ctl->ccr);
+		ctl->dirty.bf.ccr = 0;
+	}
+	if (ctl->dirty.bf.ctl) {
+		hw_write_20kx(hw, SRCCTL+idx*0x100, ctl->ctl);
+		ctl->dirty.bf.ctl = 0;
+	}
+
+	return 0;
+}
+
+static int src_get_ca(struct hw *hw, unsigned int idx, void *blk)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	ctl->ca = hw_read_20kx(hw, SRCCA+idx*0x100);
+	ctl->dirty.bf.ca = 0;
+
+	return get_field(ctl->ca, SRCCA_CA);
+}
+
+static unsigned int src_get_dirty(void *blk)
+{
+	return ((struct src_rsc_ctrl_blk *)blk)->dirty.data;
+}
+
+static unsigned int src_dirty_conj_mask(void)
+{
+	return 0x20;
+}
+
+static int src_mgr_enbs_src(void *blk, unsigned int idx)
+{
+	((struct src_mgr_ctrl_blk *)blk)->enbsa = ~(0x0);
+	((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1;
+	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
+	return 0;
+}
+
+static int src_mgr_enb_src(void *blk, unsigned int idx)
+{
+	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
+	((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
+	return 0;
+}
+
+static int src_mgr_dsb_src(void *blk, unsigned int idx)
+{
+	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32));
+	((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
+	return 0;
+}
+
+static int src_mgr_commit_write(struct hw *hw, void *blk)
+{
+	struct src_mgr_ctrl_blk *ctl = blk;
+	int i;
+	unsigned int ret;
+
+	if (ctl->dirty.bf.enbsa) {
+		do {
+			ret = hw_read_20kx(hw, SRCENBSTAT);
+		} while (ret & 0x1);
+		hw_write_20kx(hw, SRCENBS, ctl->enbsa);
+		ctl->dirty.bf.enbsa = 0;
+	}
+	for (i = 0; i < 8; i++) {
+		if ((ctl->dirty.data & (0x1 << i))) {
+			hw_write_20kx(hw, SRCENB+(i*0x100), ctl->enb[i]);
+			ctl->dirty.data &= ~(0x1 << i);
+		}
+	}
+
+	return 0;
+}
+
+static int src_mgr_get_ctrl_blk(void **rblk)
+{
+	struct src_mgr_ctrl_blk *blk;
+
+	*rblk = NULL;
+	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	*rblk = blk;
+
+	return 0;
+}
+
+static int src_mgr_put_ctrl_blk(void *blk)
+{
+	kfree((struct src_mgr_ctrl_blk *)blk);
+
+	return 0;
+}
+
+static int srcimp_mgr_get_ctrl_blk(void **rblk)
+{
+	struct srcimp_mgr_ctrl_blk *blk;
+
+	*rblk = NULL;
+	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	*rblk = blk;
+
+	return 0;
+}
+
+static int srcimp_mgr_put_ctrl_blk(void *blk)
+{
+	kfree((struct srcimp_mgr_ctrl_blk *)blk);
+
+	return 0;
+}
+
+static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot)
+{
+	struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot);
+	ctl->dirty.bf.srcimap = 1;
+	return 0;
+}
+
+static int srcimp_mgr_set_imapuser(void *blk, unsigned int user)
+{
+	struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user);
+	ctl->dirty.bf.srcimap = 1;
+	return 0;
+}
+
+static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next)
+{
+	struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next);
+	ctl->dirty.bf.srcimap = 1;
+	return 0;
+}
+
+static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr)
+{
+	struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+	ctl->srcimap.idx = addr;
+	ctl->dirty.bf.srcimap = 1;
+	return 0;
+}
+
+static int srcimp_mgr_commit_write(struct hw *hw, void *blk)
+{
+	struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+	if (ctl->dirty.bf.srcimap) {
+		hw_write_20kx(hw, SRCIMAP+ctl->srcimap.idx*0x100,
+						ctl->srcimap.srcaim);
+		ctl->dirty.bf.srcimap = 0;
+	}
+
+	return 0;
+}
+
+/*
+ * AMIXER control block definitions.
+ */
+
+#define AMOPLO_M	0x00000003
+#define AMOPLO_X	0x0003FFF0
+#define AMOPLO_Y	0xFFFC0000
+
+#define AMOPHI_SADR	0x000000FF
+#define AMOPHI_SE	0x80000000
+
+/* AMIXER resource register dirty flags */
+union amixer_dirty {
+	struct {
+		u16 amoplo:1;
+		u16 amophi:1;
+		u16 rsv:14;
+	} bf;
+	u16 data;
+};
+
+/* AMIXER resource control block */
+struct amixer_rsc_ctrl_blk {
+	unsigned int		amoplo;
+	unsigned int		amophi;
+	union amixer_dirty	dirty;
+};
+
+static int amixer_set_mode(void *blk, unsigned int mode)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->amoplo, AMOPLO_M, mode);
+	ctl->dirty.bf.amoplo = 1;
+	return 0;
+}
+
+static int amixer_set_iv(void *blk, unsigned int iv)
+{
+	/* 20k1 amixer does not have this field */
+	return 0;
+}
+
+static int amixer_set_x(void *blk, unsigned int x)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->amoplo, AMOPLO_X, x);
+	ctl->dirty.bf.amoplo = 1;
+	return 0;
+}
+
+static int amixer_set_y(void *blk, unsigned int y)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->amoplo, AMOPLO_Y, y);
+	ctl->dirty.bf.amoplo = 1;
+	return 0;
+}
+
+static int amixer_set_sadr(void *blk, unsigned int sadr)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->amophi, AMOPHI_SADR, sadr);
+	ctl->dirty.bf.amophi = 1;
+	return 0;
+}
+
+static int amixer_set_se(void *blk, unsigned int se)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->amophi, AMOPHI_SE, se);
+	ctl->dirty.bf.amophi = 1;
+	return 0;
+}
+
+static int amixer_set_dirty(void *blk, unsigned int flags)
+{
+	((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
+	return 0;
+}
+
+static int amixer_set_dirty_all(void *blk)
+{
+	((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
+	return 0;
+}
+
+static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) {
+		hw_write_20kx(hw, AMOPLO+idx*8, ctl->amoplo);
+		ctl->dirty.bf.amoplo = 0;
+		hw_write_20kx(hw, AMOPHI+idx*8, ctl->amophi);
+		ctl->dirty.bf.amophi = 0;
+	}
+
+	return 0;
+}
+
+static int amixer_get_y(void *blk)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	return get_field(ctl->amoplo, AMOPLO_Y);
+}
+
+static unsigned int amixer_get_dirty(void *blk)
+{
+	return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data;
+}
+
+static int amixer_rsc_get_ctrl_blk(void **rblk)
+{
+	struct amixer_rsc_ctrl_blk *blk;
+
+	*rblk = NULL;
+	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	*rblk = blk;
+
+	return 0;
+}
+
+static int amixer_rsc_put_ctrl_blk(void *blk)
+{
+	kfree((struct amixer_rsc_ctrl_blk *)blk);
+
+	return 0;
+}
+
+static int amixer_mgr_get_ctrl_blk(void **rblk)
+{
+	/*amixer_mgr_ctrl_blk_t *blk;*/
+
+	*rblk = NULL;
+	/*blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	*rblk = blk;*/
+
+	return 0;
+}
+
+static int amixer_mgr_put_ctrl_blk(void *blk)
+{
+	/*kfree((amixer_mgr_ctrl_blk_t *)blk);*/
+
+	return 0;
+}
+
+/*
+ * DAIO control block definitions.
+ */
+
+/* Receiver Sample Rate Tracker Control register */
+#define SRTCTL_SRCR	0x000000FF
+#define SRTCTL_SRCL	0x0000FF00
+#define SRTCTL_RSR	0x00030000
+#define SRTCTL_DRAT	0x000C0000
+#define SRTCTL_RLE	0x10000000
+#define SRTCTL_RLP	0x20000000
+#define SRTCTL_EC	0x40000000
+#define SRTCTL_ET	0x80000000
+
+/* DAIO Receiver register dirty flags */
+union dai_dirty {
+	struct {
+		u16 srtctl:1;
+		u16 rsv:15;
+	} bf;
+	u16 data;
+};
+
+/* DAIO Receiver control block */
+struct dai_ctrl_blk {
+	unsigned int	srtctl;
+	union dai_dirty	dirty;
+};
+
+/* S/PDIF Transmitter register dirty flags */
+union dao_dirty {
+	struct {
+		u16 spos:1;
+		u16 rsv:15;
+	} bf;
+	u16 data;
+};
+
+/* S/PDIF Transmitter control block */
+struct dao_ctrl_blk {
+	unsigned int 	spos; /* S/PDIF Output Channel Status Register */
+	union dao_dirty	dirty;
+};
+
+/* Audio Input Mapper RAM */
+#define AIM_ARC		0x00000FFF
+#define AIM_NXT		0x007F0000
+
+struct daoimap {
+	unsigned int aim;
+	unsigned int idx;
+};
+
+/* I2S Transmitter/Receiver Control register */
+#define I2SCTL_EA	0x00000004
+#define I2SCTL_EI	0x00000010
+
+/* S/PDIF Transmitter Control register */
+#define SPOCTL_OE	0x00000001
+#define SPOCTL_OS	0x0000000E
+#define SPOCTL_RIV	0x00000010
+#define SPOCTL_LIV	0x00000020
+#define SPOCTL_SR	0x000000C0
+
+/* S/PDIF Receiver Control register */
+#define SPICTL_EN	0x00000001
+#define SPICTL_I24	0x00000002
+#define SPICTL_IB	0x00000004
+#define SPICTL_SM	0x00000008
+#define SPICTL_VM	0x00000010
+
+/* DAIO manager register dirty flags */
+union daio_mgr_dirty {
+	struct {
+		u32 i2soctl:4;
+		u32 i2sictl:4;
+		u32 spoctl:4;
+		u32 spictl:4;
+		u32 daoimap:1;
+		u32 rsv:15;
+	} bf;
+	u32 data;
+};
+
+/* DAIO manager control block */
+struct daio_mgr_ctrl_blk {
+	unsigned int		i2sctl;
+	unsigned int		spoctl;
+	unsigned int		spictl;
+	struct daoimap		daoimap;
+	union daio_mgr_dirty	dirty;
+};
+
+static int dai_srt_set_srcr(void *blk, unsigned int src)
+{
+	struct dai_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srtctl, SRTCTL_SRCR, src);
+	ctl->dirty.bf.srtctl = 1;
+	return 0;
+}
+
+static int dai_srt_set_srcl(void *blk, unsigned int src)
+{
+	struct dai_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srtctl, SRTCTL_SRCL, src);
+	ctl->dirty.bf.srtctl = 1;
+	return 0;
+}
+
+static int dai_srt_set_rsr(void *blk, unsigned int rsr)
+{
+	struct dai_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srtctl, SRTCTL_RSR, rsr);
+	ctl->dirty.bf.srtctl = 1;
+	return 0;
+}
+
+static int dai_srt_set_drat(void *blk, unsigned int drat)
+{
+	struct dai_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srtctl, SRTCTL_DRAT, drat);
+	ctl->dirty.bf.srtctl = 1;
+	return 0;
+}
+
+static int dai_srt_set_ec(void *blk, unsigned int ec)
+{
+	struct dai_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srtctl, SRTCTL_EC, ec ? 1 : 0);
+	ctl->dirty.bf.srtctl = 1;
+	return 0;
+}
+
+static int dai_srt_set_et(void *blk, unsigned int et)
+{
+	struct dai_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srtctl, SRTCTL_ET, et ? 1 : 0);
+	ctl->dirty.bf.srtctl = 1;
+	return 0;
+}
+
+static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+	struct dai_ctrl_blk *ctl = blk;
+
+	if (ctl->dirty.bf.srtctl) {
+		if (idx < 4) {
+			/* S/PDIF SRTs */
+			hw_write_20kx(hw, SRTSCTL+0x4*idx, ctl->srtctl);
+		} else {
+			/* I2S SRT */
+			hw_write_20kx(hw, SRTICTL, ctl->srtctl);
+		}
+		ctl->dirty.bf.srtctl = 0;
+	}
+
+	return 0;
+}
+
+static int dai_get_ctrl_blk(void **rblk)
+{
+	struct dai_ctrl_blk *blk;
+
+	*rblk = NULL;
+	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	*rblk = blk;
+
+	return 0;
+}
+
+static int dai_put_ctrl_blk(void *blk)
+{
+	kfree((struct dai_ctrl_blk *)blk);
+
+	return 0;
+}
+
+static int dao_set_spos(void *blk, unsigned int spos)
+{
+	((struct dao_ctrl_blk *)blk)->spos = spos;
+	((struct dao_ctrl_blk *)blk)->dirty.bf.spos = 1;
+	return 0;
+}
+
+static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+	struct dao_ctrl_blk *ctl = blk;
+
+	if (ctl->dirty.bf.spos) {
+		if (idx < 4) {
+			/* S/PDIF SPOSx */
+			hw_write_20kx(hw, SPOS+0x4*idx, ctl->spos);
+		}
+		ctl->dirty.bf.spos = 0;
+	}
+
+	return 0;
+}
+
+static int dao_get_spos(void *blk, unsigned int *spos)
+{
+	*spos = ((struct dao_ctrl_blk *)blk)->spos;
+	return 0;
+}
+
+static int dao_get_ctrl_blk(void **rblk)
+{
+	struct dao_ctrl_blk *blk;
+
+	*rblk = NULL;
+	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	*rblk = blk;
+
+	return 0;
+}
+
+static int dao_put_ctrl_blk(void *blk)
+{
+	kfree((struct dao_ctrl_blk *)blk);
+
+	return 0;
+}
+
+static int daio_mgr_enb_dai(void *blk, unsigned int idx)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	if (idx < 4) {
+		/* S/PDIF input */
+		set_field(&ctl->spictl, SPICTL_EN << (idx*8), 1);
+		ctl->dirty.bf.spictl |= (0x1 << idx);
+	} else {
+		/* I2S input */
+		idx %= 4;
+		set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 1);
+		ctl->dirty.bf.i2sictl |= (0x1 << idx);
+	}
+	return 0;
+}
+
+static int daio_mgr_dsb_dai(void *blk, unsigned int idx)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	if (idx < 4) {
+		/* S/PDIF input */
+		set_field(&ctl->spictl, SPICTL_EN << (idx*8), 0);
+		ctl->dirty.bf.spictl |= (0x1 << idx);
+	} else {
+		/* I2S input */
+		idx %= 4;
+		set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 0);
+		ctl->dirty.bf.i2sictl |= (0x1 << idx);
+	}
+	return 0;
+}
+
+static int daio_mgr_enb_dao(void *blk, unsigned int idx)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	if (idx < 4) {
+		/* S/PDIF output */
+		set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 1);
+		ctl->dirty.bf.spoctl |= (0x1 << idx);
+	} else {
+		/* I2S output */
+		idx %= 4;
+		set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 1);
+		ctl->dirty.bf.i2soctl |= (0x1 << idx);
+	}
+	return 0;
+}
+
+static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	if (idx < 4) {
+		/* S/PDIF output */
+		set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 0);
+		ctl->dirty.bf.spoctl |= (0x1 << idx);
+	} else {
+		/* I2S output */
+		idx %= 4;
+		set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 0);
+		ctl->dirty.bf.i2soctl |= (0x1 << idx);
+	}
+	return 0;
+}
+
+static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	if (idx < 4) {
+		/* S/PDIF output */
+		switch ((conf & 0x7)) {
+		case 0:
+			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 3);
+			break; /* CDIF */
+		case 1:
+			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 0);
+			break;
+		case 2:
+			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 1);
+			break;
+		case 4:
+			set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 2);
+			break;
+		default:
+			break;
+		}
+		set_field(&ctl->spoctl, SPOCTL_LIV << (idx*8),
+			  (conf >> 4) & 0x1); /* Non-audio */
+		set_field(&ctl->spoctl, SPOCTL_RIV << (idx*8),
+			  (conf >> 4) & 0x1); /* Non-audio */
+		set_field(&ctl->spoctl, SPOCTL_OS << (idx*8),
+			  ((conf >> 3) & 0x1) ? 2 : 2); /* Raw */
+
+		ctl->dirty.bf.spoctl |= (0x1 << idx);
+	} else {
+		/* I2S output */
+		/*idx %= 4; */
+	}
+	return 0;
+}
+
+static int daio_mgr_set_imaparc(void *blk, unsigned int slot)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->daoimap.aim, AIM_ARC, slot);
+	ctl->dirty.bf.daoimap = 1;
+	return 0;
+}
+
+static int daio_mgr_set_imapnxt(void *blk, unsigned int next)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->daoimap.aim, AIM_NXT, next);
+	ctl->dirty.bf.daoimap = 1;
+	return 0;
+}
+
+static int daio_mgr_set_imapaddr(void *blk, unsigned int addr)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	ctl->daoimap.idx = addr;
+	ctl->dirty.bf.daoimap = 1;
+	return 0;
+}
+
+static int daio_mgr_commit_write(struct hw *hw, void *blk)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+	int i;
+
+	if (ctl->dirty.bf.i2sictl || ctl->dirty.bf.i2soctl) {
+		for (i = 0; i < 4; i++) {
+			if ((ctl->dirty.bf.i2sictl & (0x1 << i)))
+				ctl->dirty.bf.i2sictl &= ~(0x1 << i);
+
+			if ((ctl->dirty.bf.i2soctl & (0x1 << i)))
+				ctl->dirty.bf.i2soctl &= ~(0x1 << i);
+		}
+		hw_write_20kx(hw, I2SCTL, ctl->i2sctl);
+		mdelay(1);
+	}
+	if (ctl->dirty.bf.spoctl) {
+		for (i = 0; i < 4; i++) {
+			if ((ctl->dirty.bf.spoctl & (0x1 << i)))
+				ctl->dirty.bf.spoctl &= ~(0x1 << i);
+		}
+		hw_write_20kx(hw, SPOCTL, ctl->spoctl);
+		mdelay(1);
+	}
+	if (ctl->dirty.bf.spictl) {
+		for (i = 0; i < 4; i++) {
+			if ((ctl->dirty.bf.spictl & (0x1 << i)))
+				ctl->dirty.bf.spictl &= ~(0x1 << i);
+		}
+		hw_write_20kx(hw, SPICTL, ctl->spictl);
+		mdelay(1);
+	}
+	if (ctl->dirty.bf.daoimap) {
+		hw_write_20kx(hw, DAOIMAP+ctl->daoimap.idx*4,
+					ctl->daoimap.aim);
+		ctl->dirty.bf.daoimap = 0;
+	}
+
+	return 0;
+}
+
+static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk)
+{
+	struct daio_mgr_ctrl_blk *blk;
+
+	*rblk = NULL;
+	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	blk->i2sctl = hw_read_20kx(hw, I2SCTL);
+	blk->spoctl = hw_read_20kx(hw, SPOCTL);
+	blk->spictl = hw_read_20kx(hw, SPICTL);
+
+	*rblk = blk;
+
+	return 0;
+}
+
+static int daio_mgr_put_ctrl_blk(void *blk)
+{
+	kfree((struct daio_mgr_ctrl_blk *)blk);
+
+	return 0;
+}
+
+/* Timer interrupt */
+static int set_timer_irq(struct hw *hw, int enable)
+{
+	hw_write_20kx(hw, GIE, enable ? IT_INT : 0);
+	return 0;
+}
+
+static int set_timer_tick(struct hw *hw, unsigned int ticks)
+{
+	if (ticks)
+		ticks |= TIMR_IE | TIMR_IP;
+	hw_write_20kx(hw, TIMR, ticks);
+	return 0;
+}
+
+static unsigned int get_wc(struct hw *hw)
+{
+	return hw_read_20kx(hw, WC);
+}
+
+/* Card hardware initialization block */
+struct dac_conf {
+	unsigned int msr; /* master sample rate in rsrs */
+};
+
+struct adc_conf {
+	unsigned int msr; 	/* master sample rate in rsrs */
+	unsigned char input; 	/* the input source of ADC */
+	unsigned char mic20db; 	/* boost mic by 20db if input is microphone */
+};
+
+struct daio_conf {
+	unsigned int msr; /* master sample rate in rsrs */
+};
+
+struct trn_conf {
+	unsigned long vm_pgt_phys;
+};
+
+static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
+{
+	u32 i2sorg;
+	u32 spdorg;
+
+	/* Read I2S CTL.  Keep original value. */
+	/*i2sorg = hw_read_20kx(hw, I2SCTL);*/
+	i2sorg = 0x94040404; /* enable all audio out and I2S-D input */
+	/* Program I2S with proper master sample rate and enable
+	 * the correct I2S channel. */
+	i2sorg &= 0xfffffffc;
+
+	/* Enable S/PDIF-out-A in fixed 24-bit data
+	 * format and default to 48kHz. */
+	/* Disable all before doing any changes. */
+	hw_write_20kx(hw, SPOCTL, 0x0);
+	spdorg = 0x05;
+
+	switch (info->msr) {
+	case 1:
+		i2sorg |= 1;
+		spdorg |= (0x0 << 6);
+		break;
+	case 2:
+		i2sorg |= 2;
+		spdorg |= (0x1 << 6);
+		break;
+	case 4:
+		i2sorg |= 3;
+		spdorg |= (0x2 << 6);
+		break;
+	default:
+		i2sorg |= 1;
+		break;
+	}
+
+	hw_write_20kx(hw, I2SCTL, i2sorg);
+	hw_write_20kx(hw, SPOCTL, spdorg);
+
+	/* Enable S/PDIF-in-A in fixed 24-bit data format. */
+	/* Disable all before doing any changes. */
+	hw_write_20kx(hw, SPICTL, 0x0);
+	mdelay(1);
+	spdorg = 0x0a0a0a0a;
+	hw_write_20kx(hw, SPICTL, spdorg);
+	mdelay(1);
+
+	return 0;
+}
+
+/* TRANSPORT operations */
+static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
+{
+	u32 trnctl;
+	u32 ptp_phys_low, ptp_phys_high;
+
+	/* Set up device page table */
+	if ((~0UL) == info->vm_pgt_phys) {
+		printk(KERN_ERR "Wrong device page table page address!\n");
+		return -1;
+	}
+
+	trnctl = 0x13;  /* 32-bit, 4k-size page */
+	ptp_phys_low = (u32)info->vm_pgt_phys;
+	ptp_phys_high = upper_32_bits(info->vm_pgt_phys);
+	if (sizeof(void *) == 8) /* 64bit address */
+		trnctl |= (1 << 2);
+#if 0 /* Only 4k h/w pages for simplicitiy */
+#if PAGE_SIZE == 8192
+	trnctl |= (1<<5);
+#endif
+#endif
+	hw_write_20kx(hw, PTPALX, ptp_phys_low);
+	hw_write_20kx(hw, PTPAHX, ptp_phys_high);
+	hw_write_20kx(hw, TRNCTL, trnctl);
+	hw_write_20kx(hw, TRNIS, 0x200c01); /* realy needed? */
+
+	return 0;
+}
+
+/* Card initialization */
+#define GCTL_EAC	0x00000001
+#define GCTL_EAI	0x00000002
+#define GCTL_BEP	0x00000004
+#define GCTL_BES	0x00000008
+#define GCTL_DSP	0x00000010
+#define GCTL_DBP	0x00000020
+#define GCTL_ABP	0x00000040
+#define GCTL_TBP	0x00000080
+#define GCTL_SBP	0x00000100
+#define GCTL_FBP	0x00000200
+#define GCTL_XA		0x00000400
+#define GCTL_ET		0x00000800
+#define GCTL_PR		0x00001000
+#define GCTL_MRL	0x00002000
+#define GCTL_SDE	0x00004000
+#define GCTL_SDI	0x00008000
+#define GCTL_SM		0x00010000
+#define GCTL_SR		0x00020000
+#define GCTL_SD		0x00040000
+#define GCTL_SE		0x00080000
+#define GCTL_AID	0x00100000
+
+static int hw_pll_init(struct hw *hw, unsigned int rsr)
+{
+	unsigned int pllctl;
+	int i;
+
+	pllctl = (48000 == rsr) ? 0x1480a001 : 0x1480a731;
+	for (i = 0; i < 3; i++) {
+		if (hw_read_20kx(hw, PLLCTL) == pllctl)
+			break;
+
+		hw_write_20kx(hw, PLLCTL, pllctl);
+		mdelay(40);
+	}
+	if (i >= 3) {
+		printk(KERN_ALERT "PLL initialization failed!!!\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int hw_auto_init(struct hw *hw)
+{
+	unsigned int gctl;
+	int i;
+
+	gctl = hw_read_20kx(hw, GCTL);
+	set_field(&gctl, GCTL_EAI, 0);
+	hw_write_20kx(hw, GCTL, gctl);
+	set_field(&gctl, GCTL_EAI, 1);
+	hw_write_20kx(hw, GCTL, gctl);
+	mdelay(10);
+	for (i = 0; i < 400000; i++) {
+		gctl = hw_read_20kx(hw, GCTL);
+		if (get_field(gctl, GCTL_AID))
+			break;
+	}
+	if (!get_field(gctl, GCTL_AID)) {
+		printk(KERN_ALERT "Card Auto-init failed!!!\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int i2c_unlock(struct hw *hw)
+{
+	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
+		return 0;
+
+	hw_write_pci(hw, 0xcc, 0x8c);
+	hw_write_pci(hw, 0xcc, 0x0e);
+	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
+		return 0;
+
+	hw_write_pci(hw, 0xcc, 0xee);
+	hw_write_pci(hw, 0xcc, 0xaa);
+	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
+		return 0;
+
+	return -1;
+}
+
+static void i2c_lock(struct hw *hw)
+{
+	if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
+		hw_write_pci(hw, 0xcc, 0x00);
+}
+
+static void i2c_write(struct hw *hw, u32 device, u32 addr, u32 data)
+{
+	unsigned int ret;
+
+	do {
+		ret = hw_read_pci(hw, 0xEC);
+	} while (!(ret & 0x800000));
+	hw_write_pci(hw, 0xE0, device);
+	hw_write_pci(hw, 0xE4, (data << 8) | (addr & 0xff));
+}
+
+/* DAC operations */
+
+static int hw_reset_dac(struct hw *hw)
+{
+	u32 i;
+	u16 gpioorg;
+	unsigned int ret;
+
+	if (i2c_unlock(hw))
+		return -1;
+
+	do {
+		ret = hw_read_pci(hw, 0xEC);
+	} while (!(ret & 0x800000));
+	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
+
+	/* To be effective, need to reset the DAC twice. */
+	for (i = 0; i < 2;  i++) {
+		/* set gpio */
+		mdelay(100);
+		gpioorg = (u16)hw_read_20kx(hw, GPIO);
+		gpioorg &= 0xfffd;
+		hw_write_20kx(hw, GPIO, gpioorg);
+		mdelay(1);
+		hw_write_20kx(hw, GPIO, gpioorg | 0x2);
+	}
+
+	i2c_write(hw, 0x00180080, 0x01, 0x80);
+	i2c_write(hw, 0x00180080, 0x02, 0x10);
+
+	i2c_lock(hw);
+
+	return 0;
+}
+
+static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
+{
+	u32 data;
+	u16 gpioorg;
+	unsigned int ret;
+
+	if (hw->model == CTSB055X) {
+		/* SB055x, unmute outputs */
+		gpioorg = (u16)hw_read_20kx(hw, GPIO);
+		gpioorg &= 0xffbf;	/* set GPIO6 to low */
+		gpioorg |= 2;		/* set GPIO1 to high */
+		hw_write_20kx(hw, GPIO, gpioorg);
+		return 0;
+	}
+
+	/* mute outputs */
+	gpioorg = (u16)hw_read_20kx(hw, GPIO);
+	gpioorg &= 0xffbf;
+	hw_write_20kx(hw, GPIO, gpioorg);
+
+	hw_reset_dac(hw);
+
+	if (i2c_unlock(hw))
+		return -1;
+
+	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
+	do {
+		ret = hw_read_pci(hw, 0xEC);
+	} while (!(ret & 0x800000));
+
+	switch (info->msr) {
+	case 1:
+		data = 0x24;
+		break;
+	case 2:
+		data = 0x25;
+		break;
+	case 4:
+		data = 0x26;
+		break;
+	default:
+		data = 0x24;
+		break;
+	}
+
+	i2c_write(hw, 0x00180080, 0x06, data);
+	i2c_write(hw, 0x00180080, 0x09, data);
+	i2c_write(hw, 0x00180080, 0x0c, data);
+	i2c_write(hw, 0x00180080, 0x0f, data);
+
+	i2c_lock(hw);
+
+	/* unmute outputs */
+	gpioorg = (u16)hw_read_20kx(hw, GPIO);
+	gpioorg = gpioorg | 0x40;
+	hw_write_20kx(hw, GPIO, gpioorg);
+
+	return 0;
+}
+
+/* ADC operations */
+
+static int is_adc_input_selected_SB055x(struct hw *hw, enum ADCSRC type)
+{
+	return 0;
+}
+
+static int is_adc_input_selected_SBx(struct hw *hw, enum ADCSRC type)
+{
+	u32 data;
+
+	data = hw_read_20kx(hw, GPIO);
+	switch (type) {
+	case ADC_MICIN:
+		data = ((data & (0x1<<7)) && (data & (0x1<<8)));
+		break;
+	case ADC_LINEIN:
+		data = (!(data & (0x1<<7)) && (data & (0x1<<8)));
+		break;
+	case ADC_NONE: /* Digital I/O */
+		data = (!(data & (0x1<<8)));
+		break;
+	default:
+		data = 0;
+	}
+	return data;
+}
+
+static int is_adc_input_selected_hendrix(struct hw *hw, enum ADCSRC type)
+{
+	u32 data;
+
+	data = hw_read_20kx(hw, GPIO);
+	switch (type) {
+	case ADC_MICIN:
+		data = (data & (0x1 << 7)) ? 1 : 0;
+		break;
+	case ADC_LINEIN:
+		data = (data & (0x1 << 7)) ? 0 : 1;
+		break;
+	default:
+		data = 0;
+	}
+	return data;
+}
+
+static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
+{
+	switch (hw->model) {
+	case CTSB055X:
+		return is_adc_input_selected_SB055x(hw, type);
+	case CTSB073X:
+		return is_adc_input_selected_hendrix(hw, type);
+	case CTUAA:
+		return is_adc_input_selected_hendrix(hw, type);
+	default:
+		return is_adc_input_selected_SBx(hw, type);
+	}
+}
+
+static int
+adc_input_select_SB055x(struct hw *hw, enum ADCSRC type, unsigned char boost)
+{
+	u32 data;
+
+	/*
+	 * check and set the following GPIO bits accordingly
+	 * ADC_Gain		= GPIO2
+	 * DRM_off		= GPIO3
+	 * Mic_Pwr_on		= GPIO7
+	 * Digital_IO_Sel	= GPIO8
+	 * Mic_Sw		= GPIO9
+	 * Aux/MicLine_Sw	= GPIO12
+	 */
+	data = hw_read_20kx(hw, GPIO);
+	data &= 0xec73;
+	switch (type) {
+	case ADC_MICIN:
+		data |= (0x1<<7) | (0x1<<8) | (0x1<<9) ;
+		data |= boost ? (0x1<<2) : 0;
+		break;
+	case ADC_LINEIN:
+		data |= (0x1<<8);
+		break;
+	case ADC_AUX:
+		data |= (0x1<<8) | (0x1<<12);
+		break;
+	case ADC_NONE:
+		data |= (0x1<<12);  /* set to digital */
+		break;
+	default:
+		return -1;
+	}
+
+	hw_write_20kx(hw, GPIO, data);
+
+	return 0;
+}
+
+
+static int
+adc_input_select_SBx(struct hw *hw, enum ADCSRC type, unsigned char boost)
+{
+	u32 data;
+	u32 i2c_data;
+	unsigned int ret;
+
+	if (i2c_unlock(hw))
+		return -1;
+
+	do {
+		ret = hw_read_pci(hw, 0xEC);
+	} while (!(ret & 0x800000)); /* i2c ready poll */
+	/* set i2c access mode as Direct Control */
+	hw_write_pci(hw, 0xEC, 0x05);
+
+	data = hw_read_20kx(hw, GPIO);
+	switch (type) {
+	case ADC_MICIN:
+		data |= ((0x1 << 7) | (0x1 << 8));
+		i2c_data = 0x1;  /* Mic-in */
+		break;
+	case ADC_LINEIN:
+		data &= ~(0x1 << 7);
+		data |= (0x1 << 8);
+		i2c_data = 0x2; /* Line-in */
+		break;
+	case ADC_NONE:
+		data &= ~(0x1 << 8);
+		i2c_data = 0x0; /* set to Digital */
+		break;
+	default:
+		i2c_lock(hw);
+		return -1;
+	}
+	hw_write_20kx(hw, GPIO, data);
+	i2c_write(hw, 0x001a0080, 0x2a, i2c_data);
+	if (boost) {
+		i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */
+		i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */
+	} else {
+		i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */
+		i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */
+	}
+
+	i2c_lock(hw);
+
+	return 0;
+}
+
+static int
+adc_input_select_hendrix(struct hw *hw, enum ADCSRC type, unsigned char boost)
+{
+	u32 data;
+	u32 i2c_data;
+	unsigned int ret;
+
+	if (i2c_unlock(hw))
+		return -1;
+
+	do {
+		ret = hw_read_pci(hw, 0xEC);
+	} while (!(ret & 0x800000)); /* i2c ready poll */
+	/* set i2c access mode as Direct Control */
+	hw_write_pci(hw, 0xEC, 0x05);
+
+	data = hw_read_20kx(hw, GPIO);
+	switch (type) {
+	case ADC_MICIN:
+		data |= (0x1 << 7);
+		i2c_data = 0x1;  /* Mic-in */
+		break;
+	case ADC_LINEIN:
+		data &= ~(0x1 << 7);
+		i2c_data = 0x2; /* Line-in */
+		break;
+	default:
+		i2c_lock(hw);
+		return -1;
+	}
+	hw_write_20kx(hw, GPIO, data);
+	i2c_write(hw, 0x001a0080, 0x2a, i2c_data);
+	if (boost) {
+		i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */
+		i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */
+	} else {
+		i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */
+		i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */
+	}
+
+	i2c_lock(hw);
+
+	return 0;
+}
+
+static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
+{
+	int state = type == ADC_MICIN;
+
+	switch (hw->model) {
+	case CTSB055X:
+		return adc_input_select_SB055x(hw, type, state);
+	case CTSB073X:
+		return adc_input_select_hendrix(hw, type, state);
+	case CTUAA:
+		return adc_input_select_hendrix(hw, type, state);
+	default:
+		return adc_input_select_SBx(hw, type, state);
+	}
+}
+
+static int adc_init_SB055x(struct hw *hw, int input, int mic20db)
+{
+	return adc_input_select_SB055x(hw, input, mic20db);
+}
+
+static int adc_init_SBx(struct hw *hw, int input, int mic20db)
+{
+	u16 gpioorg;
+	u16 input_source;
+	u32 adcdata;
+	unsigned int ret;
+
+	input_source = 0x100;  /* default to analog */
+	switch (input) {
+	case ADC_MICIN:
+		adcdata = 0x1;
+		input_source = 0x180;  /* set GPIO7 to select Mic */
+		break;
+	case ADC_LINEIN:
+		adcdata = 0x2;
+		break;
+	case ADC_VIDEO:
+		adcdata = 0x4;
+		break;
+	case ADC_AUX:
+		adcdata = 0x8;
+		break;
+	case ADC_NONE:
+		adcdata = 0x0;
+		input_source = 0x0;  /* set to Digital */
+		break;
+	default:
+		adcdata = 0x0;
+		break;
+	}
+
+	if (i2c_unlock(hw))
+		return -1;
+
+	do {
+		ret = hw_read_pci(hw, 0xEC);
+	} while (!(ret & 0x800000)); /* i2c ready poll */
+	hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
+
+	i2c_write(hw, 0x001a0080, 0x0e, 0x08);
+	i2c_write(hw, 0x001a0080, 0x18, 0x0a);
+	i2c_write(hw, 0x001a0080, 0x28, 0x86);
+	i2c_write(hw, 0x001a0080, 0x2a, adcdata);
+
+	if (mic20db) {
+		i2c_write(hw, 0x001a0080, 0x1c, 0xf7);
+		i2c_write(hw, 0x001a0080, 0x1e, 0xf7);
+	} else {
+		i2c_write(hw, 0x001a0080, 0x1c, 0xcf);
+		i2c_write(hw, 0x001a0080, 0x1e, 0xcf);
+	}
+
+	if (!(hw_read_20kx(hw, ID0) & 0x100))
+		i2c_write(hw, 0x001a0080, 0x16, 0x26);
+
+	i2c_lock(hw);
+
+	gpioorg = (u16)hw_read_20kx(hw,  GPIO);
+	gpioorg &= 0xfe7f;
+	gpioorg |= input_source;
+	hw_write_20kx(hw, GPIO, gpioorg);
+
+	return 0;
+}
+
+static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
+{
+	if (hw->model == CTSB055X)
+		return adc_init_SB055x(hw, info->input, info->mic20db);
+	else
+		return adc_init_SBx(hw, info->input, info->mic20db);
+}
+
+static int hw_have_digit_io_switch(struct hw *hw)
+{
+	/* SB073x and Vista compatible cards have no digit IO switch */
+	return !(hw->model == CTSB073X || hw->model == CTUAA);
+}
+
+#define CTLBITS(a, b, c, d)	(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+
+#define UAA_CFG_PWRSTATUS	0x44
+#define UAA_CFG_SPACE_FLAG	0xA0
+#define UAA_CORE_CHANGE		0x3FFC
+static int uaa_to_xfi(struct pci_dev *pci)
+{
+	unsigned int bar0, bar1, bar2, bar3, bar4, bar5;
+	unsigned int cmd, irq, cl_size, l_timer, pwr;
+	unsigned int is_uaa;
+	unsigned int data[4] = {0};
+	unsigned int io_base;
+	void *mem_base;
+	int i;
+	const u32 CTLX = CTLBITS('C', 'T', 'L', 'X');
+	const u32 CTL_ = CTLBITS('C', 'T', 'L', '-');
+	const u32 CTLF = CTLBITS('C', 'T', 'L', 'F');
+	const u32 CTLi = CTLBITS('C', 'T', 'L', 'i');
+	const u32 CTLA = CTLBITS('C', 'T', 'L', 'A');
+	const u32 CTLZ = CTLBITS('C', 'T', 'L', 'Z');
+	const u32 CTLL = CTLBITS('C', 'T', 'L', 'L');
+
+	/* By default, Hendrix card UAA Bar0 should be using memory... */
+	io_base = pci_resource_start(pci, 0);
+	mem_base = ioremap(io_base, pci_resource_len(pci, 0));
+	if (NULL == mem_base)
+		return -ENOENT;
+
+	/* Read current mode from Mode Change Register */
+	for (i = 0; i < 4; i++)
+		data[i] = readl(mem_base + UAA_CORE_CHANGE);
+
+	/* Determine current mode... */
+	if (data[0] == CTLA) {
+		is_uaa = ((data[1] == CTLZ && data[2] == CTLL
+			  && data[3] == CTLA) || (data[1] == CTLA
+			  && data[2] == CTLZ && data[3] == CTLL));
+	} else if (data[0] == CTLZ) {
+		is_uaa = (data[1] == CTLL
+				&& data[2] == CTLA && data[3] == CTLA);
+	} else if (data[0] == CTLL) {
+		is_uaa = (data[1] == CTLA
+				&& data[2] == CTLA && data[3] == CTLZ);
+	} else {
+		is_uaa = 0;
+	}
+
+	if (!is_uaa) {
+		/* Not in UAA mode currently. Return directly. */
+		iounmap(mem_base);
+		return 0;
+	}
+
+	pci_read_config_dword(pci, PCI_BASE_ADDRESS_0, &bar0);
+	pci_read_config_dword(pci, PCI_BASE_ADDRESS_1, &bar1);
+	pci_read_config_dword(pci, PCI_BASE_ADDRESS_2, &bar2);
+	pci_read_config_dword(pci, PCI_BASE_ADDRESS_3, &bar3);
+	pci_read_config_dword(pci, PCI_BASE_ADDRESS_4, &bar4);
+	pci_read_config_dword(pci, PCI_BASE_ADDRESS_5, &bar5);
+	pci_read_config_dword(pci, PCI_INTERRUPT_LINE, &irq);
+	pci_read_config_dword(pci, PCI_CACHE_LINE_SIZE, &cl_size);
+	pci_read_config_dword(pci, PCI_LATENCY_TIMER, &l_timer);
+	pci_read_config_dword(pci, UAA_CFG_PWRSTATUS, &pwr);
+	pci_read_config_dword(pci, PCI_COMMAND, &cmd);
+
+	/* Set up X-Fi core PCI configuration space. */
+	/* Switch to X-Fi config space with BAR0 exposed. */
+	pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x87654321);
+	/* Copy UAA's BAR5 into X-Fi BAR0 */
+	pci_write_config_dword(pci, PCI_BASE_ADDRESS_0, bar5);
+	/* Switch to X-Fi config space without BAR0 exposed. */
+	pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x12345678);
+	pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, bar1);
+	pci_write_config_dword(pci, PCI_BASE_ADDRESS_2, bar2);
+	pci_write_config_dword(pci, PCI_BASE_ADDRESS_3, bar3);
+	pci_write_config_dword(pci, PCI_BASE_ADDRESS_4, bar4);
+	pci_write_config_dword(pci, PCI_INTERRUPT_LINE, irq);
+	pci_write_config_dword(pci, PCI_CACHE_LINE_SIZE, cl_size);
+	pci_write_config_dword(pci, PCI_LATENCY_TIMER, l_timer);
+	pci_write_config_dword(pci, UAA_CFG_PWRSTATUS, pwr);
+	pci_write_config_dword(pci, PCI_COMMAND, cmd);
+
+	/* Switch to X-Fi mode */
+	writel(CTLX, (mem_base + UAA_CORE_CHANGE));
+	writel(CTL_, (mem_base + UAA_CORE_CHANGE));
+	writel(CTLF, (mem_base + UAA_CORE_CHANGE));
+	writel(CTLi, (mem_base + UAA_CORE_CHANGE));
+
+	iounmap(mem_base);
+
+	return 0;
+}
+
+static irqreturn_t ct_20k1_interrupt(int irq, void *dev_id)
+{
+	struct hw *hw = dev_id;
+	unsigned int status;
+
+	status = hw_read_20kx(hw, GIP);
+	if (!status)
+		return IRQ_NONE;
+
+	if (hw->irq_callback)
+		hw->irq_callback(hw->irq_callback_data, status);
+
+	hw_write_20kx(hw, GIP, status);
+	return IRQ_HANDLED;
+}
+
+static int hw_card_start(struct hw *hw)
+{
+	int err;
+	struct pci_dev *pci = hw->pci;
+
+	err = pci_enable_device(pci);
+	if (err < 0)
+		return err;
+
+	/* Set DMA transfer mask */
+	if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
+		printk(KERN_ERR "architecture does not support PCI "
+				"busmaster DMA with mask 0x%llx\n",
+		       CT_XFI_DMA_MASK);
+		err = -ENXIO;
+		goto error1;
+	}
+
+	err = pci_request_regions(pci, "XFi");
+	if (err < 0)
+		goto error1;
+
+	/* Switch to X-Fi mode from UAA mode if neeeded */
+	if (hw->model == CTUAA) {
+		err = uaa_to_xfi(pci);
+		if (err)
+			goto error2;
+
+		hw->io_base = pci_resource_start(pci, 5);
+	} else {
+		hw->io_base = pci_resource_start(pci, 0);
+	}
+
+	err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
+			  "ctxfi", hw);
+	if (err < 0) {
+		printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
+		goto error2;
+	}
+	hw->irq = pci->irq;
+
+	pci_set_master(pci);
+
+	return 0;
+
+error2:
+	pci_release_regions(pci);
+	hw->io_base = 0;
+error1:
+	pci_disable_device(pci);
+	return err;
+}
+
+static int hw_card_stop(struct hw *hw)
+{
+	/* TODO: Disable interrupt and so on... */
+	if (hw->irq >= 0)
+		synchronize_irq(hw->irq);
+	return 0;
+}
+
+static int hw_card_shutdown(struct hw *hw)
+{
+	if (hw->irq >= 0)
+		free_irq(hw->irq, hw);
+
+	hw->irq	= -1;
+
+	if (NULL != ((void *)hw->mem_base))
+		iounmap((void *)hw->mem_base);
+
+	hw->mem_base = (unsigned long)NULL;
+
+	if (hw->io_base)
+		pci_release_regions(hw->pci);
+
+	hw->io_base = 0;
+
+	pci_disable_device(hw->pci);
+
+	return 0;
+}
+
+static int hw_card_init(struct hw *hw, struct card_conf *info)
+{
+	int err;
+	unsigned int gctl;
+	u32 data;
+	struct dac_conf dac_info = {0};
+	struct adc_conf adc_info = {0};
+	struct daio_conf daio_info = {0};
+	struct trn_conf trn_info = {0};
+
+	/* Get PCI io port base address and do Hendrix switch if needed. */
+	if (!hw->io_base) {
+		err = hw_card_start(hw);
+		if (err)
+			return err;
+	}
+
+	/* PLL init */
+	err = hw_pll_init(hw, info->rsr);
+	if (err < 0)
+		return err;
+
+	/* kick off auto-init */
+	err = hw_auto_init(hw);
+	if (err < 0)
+		return err;
+
+	/* Enable audio ring */
+	gctl = hw_read_20kx(hw, GCTL);
+	set_field(&gctl, GCTL_EAC, 1);
+	set_field(&gctl, GCTL_DBP, 1);
+	set_field(&gctl, GCTL_TBP, 1);
+	set_field(&gctl, GCTL_FBP, 1);
+	set_field(&gctl, GCTL_ET, 1);
+	hw_write_20kx(hw, GCTL, gctl);
+	mdelay(10);
+
+	/* Reset all global pending interrupts */
+	hw_write_20kx(hw, GIE, 0);
+	/* Reset all SRC pending interrupts */
+	hw_write_20kx(hw, SRCIP, 0);
+	mdelay(30);
+
+	/* Detect the card ID and configure GPIO accordingly. */
+	switch (hw->model) {
+	case CTSB055X:
+		hw_write_20kx(hw, GPIOCTL, 0x13fe);
+		break;
+	case CTSB073X:
+		hw_write_20kx(hw, GPIOCTL, 0x00e6);
+		break;
+	case CTUAA:
+		hw_write_20kx(hw, GPIOCTL, 0x00c2);
+		break;
+	default:
+		hw_write_20kx(hw, GPIOCTL, 0x01e6);
+		break;
+	}
+
+	trn_info.vm_pgt_phys = info->vm_pgt_phys;
+	err = hw_trn_init(hw, &trn_info);
+	if (err < 0)
+		return err;
+
+	daio_info.msr = info->msr;
+	err = hw_daio_init(hw, &daio_info);
+	if (err < 0)
+		return err;
+
+	dac_info.msr = info->msr;
+	err = hw_dac_init(hw, &dac_info);
+	if (err < 0)
+		return err;
+
+	adc_info.msr = info->msr;
+	adc_info.input = ADC_LINEIN;
+	adc_info.mic20db = 0;
+	err = hw_adc_init(hw, &adc_info);
+	if (err < 0)
+		return err;
+
+	data = hw_read_20kx(hw, SRCMCTL);
+	data |= 0x1; /* Enables input from the audio ring */
+	hw_write_20kx(hw, SRCMCTL, data);
+
+	return 0;
+}
+
+static u32 hw_read_20kx(struct hw *hw, u32 reg)
+{
+	u32 value;
+	unsigned long flags;
+
+	spin_lock_irqsave(
+		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
+	outl(reg, hw->io_base + 0x0);
+	value = inl(hw->io_base + 0x4);
+	spin_unlock_irqrestore(
+		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
+
+	return value;
+}
+
+static void hw_write_20kx(struct hw *hw, u32 reg, u32 data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(
+		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
+	outl(reg, hw->io_base + 0x0);
+	outl(data, hw->io_base + 0x4);
+	spin_unlock_irqrestore(
+		&container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
+
+}
+
+static u32 hw_read_pci(struct hw *hw, u32 reg)
+{
+	u32 value;
+	unsigned long flags;
+
+	spin_lock_irqsave(
+		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
+	outl(reg, hw->io_base + 0x10);
+	value = inl(hw->io_base + 0x14);
+	spin_unlock_irqrestore(
+		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
+
+	return value;
+}
+
+static void hw_write_pci(struct hw *hw, u32 reg, u32 data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(
+		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
+	outl(reg, hw->io_base + 0x10);
+	outl(data, hw->io_base + 0x14);
+	spin_unlock_irqrestore(
+		&container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
+}
+
+static struct hw ct20k1_preset __devinitdata = {
+	.irq = -1,
+
+	.card_init = hw_card_init,
+	.card_stop = hw_card_stop,
+	.pll_init = hw_pll_init,
+	.is_adc_source_selected = hw_is_adc_input_selected,
+	.select_adc_source = hw_adc_input_select,
+	.have_digit_io_switch = hw_have_digit_io_switch,
+
+	.src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk,
+	.src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk,
+	.src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk,
+	.src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk,
+	.src_set_state = src_set_state,
+	.src_set_bm = src_set_bm,
+	.src_set_rsr = src_set_rsr,
+	.src_set_sf = src_set_sf,
+	.src_set_wr = src_set_wr,
+	.src_set_pm = src_set_pm,
+	.src_set_rom = src_set_rom,
+	.src_set_vo = src_set_vo,
+	.src_set_st = src_set_st,
+	.src_set_ie = src_set_ie,
+	.src_set_ilsz = src_set_ilsz,
+	.src_set_bp = src_set_bp,
+	.src_set_cisz = src_set_cisz,
+	.src_set_ca = src_set_ca,
+	.src_set_sa = src_set_sa,
+	.src_set_la = src_set_la,
+	.src_set_pitch = src_set_pitch,
+	.src_set_dirty = src_set_dirty,
+	.src_set_clear_zbufs = src_set_clear_zbufs,
+	.src_set_dirty_all = src_set_dirty_all,
+	.src_commit_write = src_commit_write,
+	.src_get_ca = src_get_ca,
+	.src_get_dirty = src_get_dirty,
+	.src_dirty_conj_mask = src_dirty_conj_mask,
+	.src_mgr_enbs_src = src_mgr_enbs_src,
+	.src_mgr_enb_src = src_mgr_enb_src,
+	.src_mgr_dsb_src = src_mgr_dsb_src,
+	.src_mgr_commit_write = src_mgr_commit_write,
+
+	.srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk,
+	.srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk,
+	.srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc,
+	.srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser,
+	.srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt,
+	.srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr,
+	.srcimp_mgr_commit_write = srcimp_mgr_commit_write,
+
+	.amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk,
+	.amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk,
+	.amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk,
+	.amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk,
+	.amixer_set_mode = amixer_set_mode,
+	.amixer_set_iv = amixer_set_iv,
+	.amixer_set_x = amixer_set_x,
+	.amixer_set_y = amixer_set_y,
+	.amixer_set_sadr = amixer_set_sadr,
+	.amixer_set_se = amixer_set_se,
+	.amixer_set_dirty = amixer_set_dirty,
+	.amixer_set_dirty_all = amixer_set_dirty_all,
+	.amixer_commit_write = amixer_commit_write,
+	.amixer_get_y = amixer_get_y,
+	.amixer_get_dirty = amixer_get_dirty,
+
+	.dai_get_ctrl_blk = dai_get_ctrl_blk,
+	.dai_put_ctrl_blk = dai_put_ctrl_blk,
+	.dai_srt_set_srco = dai_srt_set_srcr,
+	.dai_srt_set_srcm = dai_srt_set_srcl,
+	.dai_srt_set_rsr = dai_srt_set_rsr,
+	.dai_srt_set_drat = dai_srt_set_drat,
+	.dai_srt_set_ec = dai_srt_set_ec,
+	.dai_srt_set_et = dai_srt_set_et,
+	.dai_commit_write = dai_commit_write,
+
+	.dao_get_ctrl_blk = dao_get_ctrl_blk,
+	.dao_put_ctrl_blk = dao_put_ctrl_blk,
+	.dao_set_spos = dao_set_spos,
+	.dao_commit_write = dao_commit_write,
+	.dao_get_spos = dao_get_spos,
+
+	.daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk,
+	.daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk,
+	.daio_mgr_enb_dai = daio_mgr_enb_dai,
+	.daio_mgr_dsb_dai = daio_mgr_dsb_dai,
+	.daio_mgr_enb_dao = daio_mgr_enb_dao,
+	.daio_mgr_dsb_dao = daio_mgr_dsb_dao,
+	.daio_mgr_dao_init = daio_mgr_dao_init,
+	.daio_mgr_set_imaparc = daio_mgr_set_imaparc,
+	.daio_mgr_set_imapnxt = daio_mgr_set_imapnxt,
+	.daio_mgr_set_imapaddr = daio_mgr_set_imapaddr,
+	.daio_mgr_commit_write = daio_mgr_commit_write,
+
+	.set_timer_irq = set_timer_irq,
+	.set_timer_tick = set_timer_tick,
+	.get_wc = get_wc,
+};
+
+int __devinit create_20k1_hw_obj(struct hw **rhw)
+{
+	struct hw20k1 *hw20k1;
+
+	*rhw = NULL;
+	hw20k1 = kzalloc(sizeof(*hw20k1), GFP_KERNEL);
+	if (NULL == hw20k1)
+		return -ENOMEM;
+
+	spin_lock_init(&hw20k1->reg_20k1_lock);
+	spin_lock_init(&hw20k1->reg_pci_lock);
+
+	hw20k1->hw = ct20k1_preset;
+
+	*rhw = &hw20k1->hw;
+
+	return 0;
+}
+
+int destroy_20k1_hw_obj(struct hw *hw)
+{
+	if (hw->io_base)
+		hw_card_shutdown(hw);
+
+	kfree(container_of(hw, struct hw20k1, hw));
+	return 0;
+}
diff --git a/sound/pci/ctxfi/cthw20k1.h b/sound/pci/ctxfi/cthw20k1.h
new file mode 100644
index 0000000..02f72fb
--- /dev/null
+++ b/sound/pci/ctxfi/cthw20k1.h
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	cthw20k1.h
+ *
+ * @Brief
+ * This file contains the definition of hardware access methord.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 13 2008
+ *
+ */
+
+#ifndef CTHW20K1_H
+#define CTHW20K1_H
+
+#include "cthardware.h"
+
+int create_20k1_hw_obj(struct hw **rhw);
+int destroy_20k1_hw_obj(struct hw *hw);
+
+#endif /* CTHW20K1_H */
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
new file mode 100644
index 0000000..4493a51
--- /dev/null
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -0,0 +1,2137 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	cthw20k2.c
+ *
+ * @Brief
+ * This file contains the implementation of hardware access methord for 20k2.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 14 2008
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include "cthw20k2.h"
+#include "ct20k2reg.h"
+
+#if BITS_PER_LONG == 32
+#define CT_XFI_DMA_MASK		DMA_BIT_MASK(32) /* 32 bit PTE */
+#else
+#define CT_XFI_DMA_MASK		DMA_BIT_MASK(64) /* 64 bit PTE */
+#endif
+
+struct hw20k2 {
+	struct hw hw;
+	/* for i2c */
+	unsigned char dev_id;
+	unsigned char addr_size;
+	unsigned char data_size;
+};
+
+static u32 hw_read_20kx(struct hw *hw, u32 reg);
+static void hw_write_20kx(struct hw *hw, u32 reg, u32 data);
+
+/*
+ * Type definition block.
+ * The layout of control structures can be directly applied on 20k2 chip.
+ */
+
+/*
+ * SRC control block definitions.
+ */
+
+/* SRC resource control block */
+#define SRCCTL_STATE	0x00000007
+#define SRCCTL_BM	0x00000008
+#define SRCCTL_RSR	0x00000030
+#define SRCCTL_SF	0x000001C0
+#define SRCCTL_WR	0x00000200
+#define SRCCTL_PM	0x00000400
+#define SRCCTL_ROM	0x00001800
+#define SRCCTL_VO	0x00002000
+#define SRCCTL_ST	0x00004000
+#define SRCCTL_IE	0x00008000
+#define SRCCTL_ILSZ	0x000F0000
+#define SRCCTL_BP	0x00100000
+
+#define SRCCCR_CISZ	0x000007FF
+#define SRCCCR_CWA	0x001FF800
+#define SRCCCR_D	0x00200000
+#define SRCCCR_RS	0x01C00000
+#define SRCCCR_NAL	0x3E000000
+#define SRCCCR_RA	0xC0000000
+
+#define SRCCA_CA	0x0FFFFFFF
+#define SRCCA_RS	0xE0000000
+
+#define SRCSA_SA	0x0FFFFFFF
+
+#define SRCLA_LA	0x0FFFFFFF
+
+/* Mixer Parameter Ring ram Low and Hight register.
+ * Fixed-point value in 8.24 format for parameter channel */
+#define MPRLH_PITCH	0xFFFFFFFF
+
+/* SRC resource register dirty flags */
+union src_dirty {
+	struct {
+		u16 ctl:1;
+		u16 ccr:1;
+		u16 sa:1;
+		u16 la:1;
+		u16 ca:1;
+		u16 mpr:1;
+		u16 czbfs:1;	/* Clear Z-Buffers */
+		u16 rsv:9;
+	} bf;
+	u16 data;
+};
+
+struct src_rsc_ctrl_blk {
+	unsigned int	ctl;
+	unsigned int 	ccr;
+	unsigned int	ca;
+	unsigned int	sa;
+	unsigned int	la;
+	unsigned int	mpr;
+	union src_dirty	dirty;
+};
+
+/* SRC manager control block */
+union src_mgr_dirty {
+	struct {
+		u16 enb0:1;
+		u16 enb1:1;
+		u16 enb2:1;
+		u16 enb3:1;
+		u16 enb4:1;
+		u16 enb5:1;
+		u16 enb6:1;
+		u16 enb7:1;
+		u16 enbsa:1;
+		u16 rsv:7;
+	} bf;
+	u16 data;
+};
+
+struct src_mgr_ctrl_blk {
+	unsigned int		enbsa;
+	unsigned int		enb[8];
+	union src_mgr_dirty	dirty;
+};
+
+/* SRCIMP manager control block */
+#define SRCAIM_ARC	0x00000FFF
+#define SRCAIM_NXT	0x00FF0000
+#define SRCAIM_SRC	0xFF000000
+
+struct srcimap {
+	unsigned int srcaim;
+	unsigned int idx;
+};
+
+/* SRCIMP manager register dirty flags */
+union srcimp_mgr_dirty {
+	struct {
+		u16 srcimap:1;
+		u16 rsv:15;
+	} bf;
+	u16 data;
+};
+
+struct srcimp_mgr_ctrl_blk {
+	struct srcimap		srcimap;
+	union srcimp_mgr_dirty	dirty;
+};
+
+/*
+ * Function implementation block.
+ */
+
+static int src_get_rsc_ctrl_blk(void **rblk)
+{
+	struct src_rsc_ctrl_blk *blk;
+
+	*rblk = NULL;
+	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	*rblk = blk;
+
+	return 0;
+}
+
+static int src_put_rsc_ctrl_blk(void *blk)
+{
+	kfree(blk);
+
+	return 0;
+}
+
+static int src_set_state(void *blk, unsigned int state)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_STATE, state);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_bm(void *blk, unsigned int bm)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_BM, bm);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_rsr(void *blk, unsigned int rsr)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_RSR, rsr);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_sf(void *blk, unsigned int sf)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_SF, sf);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_wr(void *blk, unsigned int wr)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_WR, wr);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_pm(void *blk, unsigned int pm)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_PM, pm);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_rom(void *blk, unsigned int rom)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_ROM, rom);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_vo(void *blk, unsigned int vo)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_VO, vo);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_st(void *blk, unsigned int st)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_ST, st);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_ie(void *blk, unsigned int ie)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_IE, ie);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_ilsz(void *blk, unsigned int ilsz)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_bp(void *blk, unsigned int bp)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ctl, SRCCTL_BP, bp);
+	ctl->dirty.bf.ctl = 1;
+	return 0;
+}
+
+static int src_set_cisz(void *blk, unsigned int cisz)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ccr, SRCCCR_CISZ, cisz);
+	ctl->dirty.bf.ccr = 1;
+	return 0;
+}
+
+static int src_set_ca(void *blk, unsigned int ca)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->ca, SRCCA_CA, ca);
+	ctl->dirty.bf.ca = 1;
+	return 0;
+}
+
+static int src_set_sa(void *blk, unsigned int sa)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->sa, SRCSA_SA, sa);
+	ctl->dirty.bf.sa = 1;
+	return 0;
+}
+
+static int src_set_la(void *blk, unsigned int la)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->la, SRCLA_LA, la);
+	ctl->dirty.bf.la = 1;
+	return 0;
+}
+
+static int src_set_pitch(void *blk, unsigned int pitch)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->mpr, MPRLH_PITCH, pitch);
+	ctl->dirty.bf.mpr = 1;
+	return 0;
+}
+
+static int src_set_clear_zbufs(void *blk, unsigned int clear)
+{
+	((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0);
+	return 0;
+}
+
+static int src_set_dirty(void *blk, unsigned int flags)
+{
+	((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
+	return 0;
+}
+
+static int src_set_dirty_all(void *blk)
+{
+	((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
+	return 0;
+}
+
+#define AR_SLOT_SIZE		4096
+#define AR_SLOT_BLOCK_SIZE	16
+#define AR_PTS_PITCH		6
+#define AR_PARAM_SRC_OFFSET	0x60
+
+static unsigned int src_param_pitch_mixer(unsigned int src_idx)
+{
+	return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE
+			- AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE;
+
+}
+
+static int src_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+	int i;
+
+	if (ctl->dirty.bf.czbfs) {
+		/* Clear Z-Buffer registers */
+		for (i = 0; i < 8; i++)
+			hw_write_20kx(hw, SRC_UPZ+idx*0x100+i*0x4, 0);
+
+		for (i = 0; i < 4; i++)
+			hw_write_20kx(hw, SRC_DN0Z+idx*0x100+i*0x4, 0);
+
+		for (i = 0; i < 8; i++)
+			hw_write_20kx(hw, SRC_DN1Z+idx*0x100+i*0x4, 0);
+
+		ctl->dirty.bf.czbfs = 0;
+	}
+	if (ctl->dirty.bf.mpr) {
+		/* Take the parameter mixer resource in the same group as that
+		 * the idx src is in for simplicity. Unlike src, all conjugate
+		 * parameter mixer resources must be programmed for
+		 * corresponding conjugate src resources. */
+		unsigned int pm_idx = src_param_pitch_mixer(idx);
+		hw_write_20kx(hw, MIXER_PRING_LO_HI+4*pm_idx, ctl->mpr);
+		hw_write_20kx(hw, MIXER_PMOPLO+8*pm_idx, 0x3);
+		hw_write_20kx(hw, MIXER_PMOPHI+8*pm_idx, 0x0);
+		ctl->dirty.bf.mpr = 0;
+	}
+	if (ctl->dirty.bf.sa) {
+		hw_write_20kx(hw, SRC_SA+idx*0x100, ctl->sa);
+		ctl->dirty.bf.sa = 0;
+	}
+	if (ctl->dirty.bf.la) {
+		hw_write_20kx(hw, SRC_LA+idx*0x100, ctl->la);
+		ctl->dirty.bf.la = 0;
+	}
+	if (ctl->dirty.bf.ca) {
+		hw_write_20kx(hw, SRC_CA+idx*0x100, ctl->ca);
+		ctl->dirty.bf.ca = 0;
+	}
+
+	/* Write srccf register */
+	hw_write_20kx(hw, SRC_CF+idx*0x100, 0x0);
+
+	if (ctl->dirty.bf.ccr) {
+		hw_write_20kx(hw, SRC_CCR+idx*0x100, ctl->ccr);
+		ctl->dirty.bf.ccr = 0;
+	}
+	if (ctl->dirty.bf.ctl) {
+		hw_write_20kx(hw, SRC_CTL+idx*0x100, ctl->ctl);
+		ctl->dirty.bf.ctl = 0;
+	}
+
+	return 0;
+}
+
+static int src_get_ca(struct hw *hw, unsigned int idx, void *blk)
+{
+	struct src_rsc_ctrl_blk *ctl = blk;
+
+	ctl->ca = hw_read_20kx(hw, SRC_CA+idx*0x100);
+	ctl->dirty.bf.ca = 0;
+
+	return get_field(ctl->ca, SRCCA_CA);
+}
+
+static unsigned int src_get_dirty(void *blk)
+{
+	return ((struct src_rsc_ctrl_blk *)blk)->dirty.data;
+}
+
+static unsigned int src_dirty_conj_mask(void)
+{
+	return 0x20;
+}
+
+static int src_mgr_enbs_src(void *blk, unsigned int idx)
+{
+	((struct src_mgr_ctrl_blk *)blk)->enbsa |= (0x1 << ((idx%128)/4));
+	((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1;
+	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
+	return 0;
+}
+
+static int src_mgr_enb_src(void *blk, unsigned int idx)
+{
+	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
+	((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
+	return 0;
+}
+
+static int src_mgr_dsb_src(void *blk, unsigned int idx)
+{
+	((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32));
+	((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
+	return 0;
+}
+
+static int src_mgr_commit_write(struct hw *hw, void *blk)
+{
+	struct src_mgr_ctrl_blk *ctl = blk;
+	int i;
+	unsigned int ret;
+
+	if (ctl->dirty.bf.enbsa) {
+		do {
+			ret = hw_read_20kx(hw, SRC_ENBSTAT);
+		} while (ret & 0x1);
+		hw_write_20kx(hw, SRC_ENBSA, ctl->enbsa);
+		ctl->dirty.bf.enbsa = 0;
+	}
+	for (i = 0; i < 8; i++) {
+		if ((ctl->dirty.data & (0x1 << i))) {
+			hw_write_20kx(hw, SRC_ENB+(i*0x100), ctl->enb[i]);
+			ctl->dirty.data &= ~(0x1 << i);
+		}
+	}
+
+	return 0;
+}
+
+static int src_mgr_get_ctrl_blk(void **rblk)
+{
+	struct src_mgr_ctrl_blk *blk;
+
+	*rblk = NULL;
+	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	*rblk = blk;
+
+	return 0;
+}
+
+static int src_mgr_put_ctrl_blk(void *blk)
+{
+	kfree(blk);
+
+	return 0;
+}
+
+static int srcimp_mgr_get_ctrl_blk(void **rblk)
+{
+	struct srcimp_mgr_ctrl_blk *blk;
+
+	*rblk = NULL;
+	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	*rblk = blk;
+
+	return 0;
+}
+
+static int srcimp_mgr_put_ctrl_blk(void *blk)
+{
+	kfree(blk);
+
+	return 0;
+}
+
+static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot)
+{
+	struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot);
+	ctl->dirty.bf.srcimap = 1;
+	return 0;
+}
+
+static int srcimp_mgr_set_imapuser(void *blk, unsigned int user)
+{
+	struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user);
+	ctl->dirty.bf.srcimap = 1;
+	return 0;
+}
+
+static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next)
+{
+	struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next);
+	ctl->dirty.bf.srcimap = 1;
+	return 0;
+}
+
+static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr)
+{
+	((struct srcimp_mgr_ctrl_blk *)blk)->srcimap.idx = addr;
+	((struct srcimp_mgr_ctrl_blk *)blk)->dirty.bf.srcimap = 1;
+	return 0;
+}
+
+static int srcimp_mgr_commit_write(struct hw *hw, void *blk)
+{
+	struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+	if (ctl->dirty.bf.srcimap) {
+		hw_write_20kx(hw, SRC_IMAP+ctl->srcimap.idx*0x100,
+						ctl->srcimap.srcaim);
+		ctl->dirty.bf.srcimap = 0;
+	}
+
+	return 0;
+}
+
+/*
+ * AMIXER control block definitions.
+ */
+
+#define AMOPLO_M	0x00000003
+#define AMOPLO_IV	0x00000004
+#define AMOPLO_X	0x0003FFF0
+#define AMOPLO_Y	0xFFFC0000
+
+#define AMOPHI_SADR	0x000000FF
+#define AMOPHI_SE	0x80000000
+
+/* AMIXER resource register dirty flags */
+union amixer_dirty {
+	struct {
+		u16 amoplo:1;
+		u16 amophi:1;
+		u16 rsv:14;
+	} bf;
+	u16 data;
+};
+
+/* AMIXER resource control block */
+struct amixer_rsc_ctrl_blk {
+	unsigned int		amoplo;
+	unsigned int		amophi;
+	union amixer_dirty	dirty;
+};
+
+static int amixer_set_mode(void *blk, unsigned int mode)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->amoplo, AMOPLO_M, mode);
+	ctl->dirty.bf.amoplo = 1;
+	return 0;
+}
+
+static int amixer_set_iv(void *blk, unsigned int iv)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->amoplo, AMOPLO_IV, iv);
+	ctl->dirty.bf.amoplo = 1;
+	return 0;
+}
+
+static int amixer_set_x(void *blk, unsigned int x)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->amoplo, AMOPLO_X, x);
+	ctl->dirty.bf.amoplo = 1;
+	return 0;
+}
+
+static int amixer_set_y(void *blk, unsigned int y)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->amoplo, AMOPLO_Y, y);
+	ctl->dirty.bf.amoplo = 1;
+	return 0;
+}
+
+static int amixer_set_sadr(void *blk, unsigned int sadr)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->amophi, AMOPHI_SADR, sadr);
+	ctl->dirty.bf.amophi = 1;
+	return 0;
+}
+
+static int amixer_set_se(void *blk, unsigned int se)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->amophi, AMOPHI_SE, se);
+	ctl->dirty.bf.amophi = 1;
+	return 0;
+}
+
+static int amixer_set_dirty(void *blk, unsigned int flags)
+{
+	((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
+	return 0;
+}
+
+static int amixer_set_dirty_all(void *blk)
+{
+	((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
+	return 0;
+}
+
+static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) {
+		hw_write_20kx(hw, MIXER_AMOPLO+idx*8, ctl->amoplo);
+		ctl->dirty.bf.amoplo = 0;
+		hw_write_20kx(hw, MIXER_AMOPHI+idx*8, ctl->amophi);
+		ctl->dirty.bf.amophi = 0;
+	}
+
+	return 0;
+}
+
+static int amixer_get_y(void *blk)
+{
+	struct amixer_rsc_ctrl_blk *ctl = blk;
+
+	return get_field(ctl->amoplo, AMOPLO_Y);
+}
+
+static unsigned int amixer_get_dirty(void *blk)
+{
+	return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data;
+}
+
+static int amixer_rsc_get_ctrl_blk(void **rblk)
+{
+	struct amixer_rsc_ctrl_blk *blk;
+
+	*rblk = NULL;
+	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	*rblk = blk;
+
+	return 0;
+}
+
+static int amixer_rsc_put_ctrl_blk(void *blk)
+{
+	kfree(blk);
+
+	return 0;
+}
+
+static int amixer_mgr_get_ctrl_blk(void **rblk)
+{
+	*rblk = NULL;
+
+	return 0;
+}
+
+static int amixer_mgr_put_ctrl_blk(void *blk)
+{
+	return 0;
+}
+
+/*
+ * DAIO control block definitions.
+ */
+
+/* Receiver Sample Rate Tracker Control register */
+#define SRTCTL_SRCO	0x000000FF
+#define SRTCTL_SRCM	0x0000FF00
+#define SRTCTL_RSR	0x00030000
+#define SRTCTL_DRAT	0x00300000
+#define SRTCTL_EC	0x01000000
+#define SRTCTL_ET	0x10000000
+
+/* DAIO Receiver register dirty flags */
+union dai_dirty {
+	struct {
+		u16 srt:1;
+		u16 rsv:15;
+	} bf;
+	u16 data;
+};
+
+/* DAIO Receiver control block */
+struct dai_ctrl_blk {
+	unsigned int	srt;
+	union dai_dirty	dirty;
+};
+
+/* Audio Input Mapper RAM */
+#define AIM_ARC		0x00000FFF
+#define AIM_NXT		0x007F0000
+
+struct daoimap {
+	unsigned int aim;
+	unsigned int idx;
+};
+
+/* Audio Transmitter Control and Status register */
+#define ATXCTL_EN	0x00000001
+#define ATXCTL_MODE	0x00000010
+#define ATXCTL_CD	0x00000020
+#define ATXCTL_RAW	0x00000100
+#define ATXCTL_MT	0x00000200
+#define ATXCTL_NUC	0x00003000
+#define ATXCTL_BEN	0x00010000
+#define ATXCTL_BMUX	0x00700000
+#define ATXCTL_B24	0x01000000
+#define ATXCTL_CPF	0x02000000
+#define ATXCTL_RIV	0x10000000
+#define ATXCTL_LIV	0x20000000
+#define ATXCTL_RSAT	0x40000000
+#define ATXCTL_LSAT	0x80000000
+
+/* XDIF Transmitter register dirty flags */
+union dao_dirty {
+	struct {
+		u16 atxcsl:1;
+		u16 rsv:15;
+	} bf;
+	u16 data;
+};
+
+/* XDIF Transmitter control block */
+struct dao_ctrl_blk {
+	/* XDIF Transmitter Channel Status Low Register */
+	unsigned int	atxcsl;
+	union dao_dirty	dirty;
+};
+
+/* Audio Receiver Control register */
+#define ARXCTL_EN	0x00000001
+
+/* DAIO manager register dirty flags */
+union daio_mgr_dirty {
+	struct {
+		u32 atxctl:8;
+		u32 arxctl:8;
+		u32 daoimap:1;
+		u32 rsv:15;
+	} bf;
+	u32 data;
+};
+
+/* DAIO manager control block */
+struct daio_mgr_ctrl_blk {
+	struct daoimap		daoimap;
+	unsigned int		txctl[8];
+	unsigned int		rxctl[8];
+	union daio_mgr_dirty	dirty;
+};
+
+static int dai_srt_set_srco(void *blk, unsigned int src)
+{
+	struct dai_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srt, SRTCTL_SRCO, src);
+	ctl->dirty.bf.srt = 1;
+	return 0;
+}
+
+static int dai_srt_set_srcm(void *blk, unsigned int src)
+{
+	struct dai_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srt, SRTCTL_SRCM, src);
+	ctl->dirty.bf.srt = 1;
+	return 0;
+}
+
+static int dai_srt_set_rsr(void *blk, unsigned int rsr)
+{
+	struct dai_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srt, SRTCTL_RSR, rsr);
+	ctl->dirty.bf.srt = 1;
+	return 0;
+}
+
+static int dai_srt_set_drat(void *blk, unsigned int drat)
+{
+	struct dai_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srt, SRTCTL_DRAT, drat);
+	ctl->dirty.bf.srt = 1;
+	return 0;
+}
+
+static int dai_srt_set_ec(void *blk, unsigned int ec)
+{
+	struct dai_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srt, SRTCTL_EC, ec ? 1 : 0);
+	ctl->dirty.bf.srt = 1;
+	return 0;
+}
+
+static int dai_srt_set_et(void *blk, unsigned int et)
+{
+	struct dai_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->srt, SRTCTL_ET, et ? 1 : 0);
+	ctl->dirty.bf.srt = 1;
+	return 0;
+}
+
+static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+	struct dai_ctrl_blk *ctl = blk;
+
+	if (ctl->dirty.bf.srt) {
+		hw_write_20kx(hw, AUDIO_IO_RX_SRT_CTL+0x40*idx, ctl->srt);
+		ctl->dirty.bf.srt = 0;
+	}
+
+	return 0;
+}
+
+static int dai_get_ctrl_blk(void **rblk)
+{
+	struct dai_ctrl_blk *blk;
+
+	*rblk = NULL;
+	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	*rblk = blk;
+
+	return 0;
+}
+
+static int dai_put_ctrl_blk(void *blk)
+{
+	kfree(blk);
+
+	return 0;
+}
+
+static int dao_set_spos(void *blk, unsigned int spos)
+{
+	((struct dao_ctrl_blk *)blk)->atxcsl = spos;
+	((struct dao_ctrl_blk *)blk)->dirty.bf.atxcsl = 1;
+	return 0;
+}
+
+static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+	struct dao_ctrl_blk *ctl = blk;
+
+	if (ctl->dirty.bf.atxcsl) {
+		if (idx < 4) {
+			/* S/PDIF SPOSx */
+			hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+0x40*idx,
+							ctl->atxcsl);
+		}
+		ctl->dirty.bf.atxcsl = 0;
+	}
+
+	return 0;
+}
+
+static int dao_get_spos(void *blk, unsigned int *spos)
+{
+	*spos = ((struct dao_ctrl_blk *)blk)->atxcsl;
+	return 0;
+}
+
+static int dao_get_ctrl_blk(void **rblk)
+{
+	struct dao_ctrl_blk *blk;
+
+	*rblk = NULL;
+	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	*rblk = blk;
+
+	return 0;
+}
+
+static int dao_put_ctrl_blk(void *blk)
+{
+	kfree(blk);
+
+	return 0;
+}
+
+static int daio_mgr_enb_dai(void *blk, unsigned int idx)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->rxctl[idx], ARXCTL_EN, 1);
+	ctl->dirty.bf.arxctl |= (0x1 << idx);
+	return 0;
+}
+
+static int daio_mgr_dsb_dai(void *blk, unsigned int idx)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->rxctl[idx], ARXCTL_EN, 0);
+
+	ctl->dirty.bf.arxctl |= (0x1 << idx);
+	return 0;
+}
+
+static int daio_mgr_enb_dao(void *blk, unsigned int idx)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->txctl[idx], ATXCTL_EN, 1);
+	ctl->dirty.bf.atxctl |= (0x1 << idx);
+	return 0;
+}
+
+static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->txctl[idx], ATXCTL_EN, 0);
+	ctl->dirty.bf.atxctl |= (0x1 << idx);
+	return 0;
+}
+
+static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	if (idx < 4) {
+		/* S/PDIF output */
+		switch ((conf & 0x7)) {
+		case 1:
+			set_field(&ctl->txctl[idx], ATXCTL_NUC, 0);
+			break;
+		case 2:
+			set_field(&ctl->txctl[idx], ATXCTL_NUC, 1);
+			break;
+		case 4:
+			set_field(&ctl->txctl[idx], ATXCTL_NUC, 2);
+			break;
+		case 8:
+			set_field(&ctl->txctl[idx], ATXCTL_NUC, 3);
+			break;
+		default:
+			break;
+		}
+		/* CDIF */
+		set_field(&ctl->txctl[idx], ATXCTL_CD, (!(conf & 0x7)));
+		/* Non-audio */
+		set_field(&ctl->txctl[idx], ATXCTL_LIV, (conf >> 4) & 0x1);
+		/* Non-audio */
+		set_field(&ctl->txctl[idx], ATXCTL_RIV, (conf >> 4) & 0x1);
+		set_field(&ctl->txctl[idx], ATXCTL_RAW,
+			  ((conf >> 3) & 0x1) ? 0 : 0);
+		ctl->dirty.bf.atxctl |= (0x1 << idx);
+	} else {
+		/* I2S output */
+		/*idx %= 4; */
+	}
+	return 0;
+}
+
+static int daio_mgr_set_imaparc(void *blk, unsigned int slot)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->daoimap.aim, AIM_ARC, slot);
+	ctl->dirty.bf.daoimap = 1;
+	return 0;
+}
+
+static int daio_mgr_set_imapnxt(void *blk, unsigned int next)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+
+	set_field(&ctl->daoimap.aim, AIM_NXT, next);
+	ctl->dirty.bf.daoimap = 1;
+	return 0;
+}
+
+static int daio_mgr_set_imapaddr(void *blk, unsigned int addr)
+{
+	((struct daio_mgr_ctrl_blk *)blk)->daoimap.idx = addr;
+	((struct daio_mgr_ctrl_blk *)blk)->dirty.bf.daoimap = 1;
+	return 0;
+}
+
+static int daio_mgr_commit_write(struct hw *hw, void *blk)
+{
+	struct daio_mgr_ctrl_blk *ctl = blk;
+	unsigned int data;
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		if ((ctl->dirty.bf.atxctl & (0x1 << i))) {
+			data = ctl->txctl[i];
+			hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data);
+			ctl->dirty.bf.atxctl &= ~(0x1 << i);
+			mdelay(1);
+		}
+		if ((ctl->dirty.bf.arxctl & (0x1 << i))) {
+			data = ctl->rxctl[i];
+			hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data);
+			ctl->dirty.bf.arxctl &= ~(0x1 << i);
+			mdelay(1);
+		}
+	}
+	if (ctl->dirty.bf.daoimap) {
+		hw_write_20kx(hw, AUDIO_IO_AIM+ctl->daoimap.idx*4,
+						ctl->daoimap.aim);
+		ctl->dirty.bf.daoimap = 0;
+	}
+
+	return 0;
+}
+
+static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk)
+{
+	struct daio_mgr_ctrl_blk *blk;
+	int i;
+
+	*rblk = NULL;
+	blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+	if (NULL == blk)
+		return -ENOMEM;
+
+	for (i = 0; i < 8; i++) {
+		blk->txctl[i] = hw_read_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i));
+		blk->rxctl[i] = hw_read_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i));
+	}
+
+	*rblk = blk;
+
+	return 0;
+}
+
+static int daio_mgr_put_ctrl_blk(void *blk)
+{
+	kfree(blk);
+
+	return 0;
+}
+
+/* Card hardware initialization block */
+struct dac_conf {
+	unsigned int msr; /* master sample rate in rsrs */
+};
+
+struct adc_conf {
+	unsigned int msr; 	/* master sample rate in rsrs */
+	unsigned char input; 	/* the input source of ADC */
+	unsigned char mic20db; 	/* boost mic by 20db if input is microphone */
+};
+
+struct daio_conf {
+	unsigned int msr; /* master sample rate in rsrs */
+};
+
+struct trn_conf {
+	unsigned long vm_pgt_phys;
+};
+
+static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
+{
+	u32 data;
+	int i;
+
+	/* Program I2S with proper sample rate and enable the correct I2S
+	 * channel. ED(0/8/16/24): Enable all I2S/I2X master clock output */
+	if (1 == info->msr) {
+		hw_write_20kx(hw, AUDIO_IO_MCLK, 0x01010101);
+		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101);
+		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
+	} else if (2 == info->msr) {
+		hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
+		/* Specify all playing 96khz
+		 * EA [0]	- Enabled
+		 * RTA [4:5]	- 96kHz
+		 * EB [8]	- Enabled
+		 * RTB [12:13]	- 96kHz
+		 * EC [16]	- Enabled
+		 * RTC [20:21]	- 96kHz
+		 * ED [24]	- Enabled
+		 * RTD [28:29]	- 96kHz */
+		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
+		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
+	} else {
+		printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 8; i++) {
+		if (i <= 3) {
+			/* 1st 3 channels are SPDIFs (SB0960) */
+			if (i == 3)
+				data = 0x1001001;
+			else
+				data = 0x1000001;
+
+			hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data);
+			hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data);
+
+			/* Initialize the SPDIF Out Channel status registers.
+			 * The value specified here is based on the typical
+			 * values provided in the specification, namely: Clock
+			 * Accuracy of 1000ppm, Sample Rate of 48KHz,
+			 * unspecified source number, Generation status = 1,
+			 * Category code = 0x12 (Digital Signal Mixer),
+			 * Mode = 0, Emph = 0, Copy Permitted, AN = 0
+			 * (indicating that we're transmitting digital audio,
+			 * and the Professional Use bit is 0. */
+
+			hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+(0x40*i),
+					0x02109204); /* Default to 48kHz */
+
+			hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B);
+		} else {
+			/* Next 5 channels are I2S (SB0960) */
+			data = 0x11;
+			hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data);
+			if (2 == info->msr) {
+				/* Four channels per sample period */
+				data |= 0x1000;
+			}
+			hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data);
+		}
+	}
+
+	return 0;
+}
+
+/* TRANSPORT operations */
+static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
+{
+	u32 vmctl, data;
+	u32 ptp_phys_low, ptp_phys_high;
+	int i;
+
+	/* Set up device page table */
+	if ((~0UL) == info->vm_pgt_phys) {
+		printk(KERN_ALERT "ctxfi: "
+		       "Wrong device page table page address!!!\n");
+		return -1;
+	}
+
+	vmctl = 0x80000C0F;  /* 32-bit, 4k-size page */
+	ptp_phys_low = (u32)info->vm_pgt_phys;
+	ptp_phys_high = upper_32_bits(info->vm_pgt_phys);
+	if (sizeof(void *) == 8) /* 64bit address */
+		vmctl |= (3 << 8);
+	/* Write page table physical address to all PTPAL registers */
+	for (i = 0; i < 64; i++) {
+		hw_write_20kx(hw, VMEM_PTPAL+(16*i), ptp_phys_low);
+		hw_write_20kx(hw, VMEM_PTPAH+(16*i), ptp_phys_high);
+	}
+	/* Enable virtual memory transfer */
+	hw_write_20kx(hw, VMEM_CTL, vmctl);
+	/* Enable transport bus master and queueing of request */
+	hw_write_20kx(hw, TRANSPORT_CTL, 0x03);
+	hw_write_20kx(hw, TRANSPORT_INT, 0x200c01);
+	/* Enable transport ring */
+	data = hw_read_20kx(hw, TRANSPORT_ENB);
+	hw_write_20kx(hw, TRANSPORT_ENB, (data | 0x03));
+
+	return 0;
+}
+
+/* Card initialization */
+#define GCTL_AIE	0x00000001
+#define GCTL_UAA	0x00000002
+#define GCTL_DPC	0x00000004
+#define GCTL_DBP	0x00000008
+#define GCTL_ABP	0x00000010
+#define GCTL_TBP	0x00000020
+#define GCTL_SBP	0x00000040
+#define GCTL_FBP	0x00000080
+#define GCTL_ME		0x00000100
+#define GCTL_AID	0x00001000
+
+#define PLLCTL_SRC	0x00000007
+#define PLLCTL_SPE	0x00000008
+#define PLLCTL_RD	0x000000F0
+#define PLLCTL_FD	0x0001FF00
+#define PLLCTL_OD	0x00060000
+#define PLLCTL_B	0x00080000
+#define PLLCTL_AS	0x00100000
+#define PLLCTL_LF	0x03E00000
+#define PLLCTL_SPS	0x1C000000
+#define PLLCTL_AD	0x60000000
+
+#define PLLSTAT_CCS	0x00000007
+#define PLLSTAT_SPL	0x00000008
+#define PLLSTAT_CRD	0x000000F0
+#define PLLSTAT_CFD	0x0001FF00
+#define PLLSTAT_SL	0x00020000
+#define PLLSTAT_FAS	0x00040000
+#define PLLSTAT_B	0x00080000
+#define PLLSTAT_PD	0x00100000
+#define PLLSTAT_OCA	0x00200000
+#define PLLSTAT_NCA	0x00400000
+
+static int hw_pll_init(struct hw *hw, unsigned int rsr)
+{
+	unsigned int pllenb;
+	unsigned int pllctl;
+	unsigned int pllstat;
+	int i;
+
+	pllenb = 0xB;
+	hw_write_20kx(hw, PLL_ENB, pllenb);
+	pllctl = 0x20D00000;
+	set_field(&pllctl, PLLCTL_FD, 16 - 4);
+	hw_write_20kx(hw, PLL_CTL, pllctl);
+	mdelay(40);
+	pllctl = hw_read_20kx(hw, PLL_CTL);
+	set_field(&pllctl, PLLCTL_B, 0);
+	if (48000 == rsr) {
+		set_field(&pllctl, PLLCTL_FD, 16 - 2);
+		set_field(&pllctl, PLLCTL_RD, 1 - 1);
+	} else { /* 44100 */
+		set_field(&pllctl, PLLCTL_FD, 147 - 2);
+		set_field(&pllctl, PLLCTL_RD, 10 - 1);
+	}
+	hw_write_20kx(hw, PLL_CTL, pllctl);
+	mdelay(40);
+	for (i = 0; i < 1000; i++) {
+		pllstat = hw_read_20kx(hw, PLL_STAT);
+		if (get_field(pllstat, PLLSTAT_PD))
+			continue;
+
+		if (get_field(pllstat, PLLSTAT_B) !=
+					get_field(pllctl, PLLCTL_B))
+			continue;
+
+		if (get_field(pllstat, PLLSTAT_CCS) !=
+					get_field(pllctl, PLLCTL_SRC))
+			continue;
+
+		if (get_field(pllstat, PLLSTAT_CRD) !=
+					get_field(pllctl, PLLCTL_RD))
+			continue;
+
+		if (get_field(pllstat, PLLSTAT_CFD) !=
+					get_field(pllctl, PLLCTL_FD))
+			continue;
+
+		break;
+	}
+	if (i >= 1000) {
+		printk(KERN_ALERT "ctxfi: PLL initialization failed!!!\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int hw_auto_init(struct hw *hw)
+{
+	unsigned int gctl;
+	int i;
+
+	gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
+	set_field(&gctl, GCTL_AIE, 0);
+	hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
+	set_field(&gctl, GCTL_AIE, 1);
+	hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
+	mdelay(10);
+	for (i = 0; i < 400000; i++) {
+		gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
+		if (get_field(gctl, GCTL_AID))
+			break;
+	}
+	if (!get_field(gctl, GCTL_AID)) {
+		printk(KERN_ALERT "ctxfi: Card Auto-init failed!!!\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+/* DAC operations */
+
+#define CS4382_MC1 		0x1
+#define CS4382_MC2 		0x2
+#define CS4382_MC3		0x3
+#define CS4382_FC		0x4
+#define CS4382_IC		0x5
+#define CS4382_XC1		0x6
+#define CS4382_VCA1 		0x7
+#define CS4382_VCB1 		0x8
+#define CS4382_XC2		0x9
+#define CS4382_VCA2 		0xA
+#define CS4382_VCB2 		0xB
+#define CS4382_XC3		0xC
+#define CS4382_VCA3		0xD
+#define CS4382_VCB3		0xE
+#define CS4382_XC4 		0xF
+#define CS4382_VCA4 		0x10
+#define CS4382_VCB4 		0x11
+#define CS4382_CREV 		0x12
+
+/* I2C status */
+#define STATE_LOCKED		0x00
+#define STATE_UNLOCKED		0xAA
+#define DATA_READY		0x800000    /* Used with I2C_IF_STATUS */
+#define DATA_ABORT		0x10000     /* Used with I2C_IF_STATUS */
+
+#define I2C_STATUS_DCM	0x00000001
+#define I2C_STATUS_BC	0x00000006
+#define I2C_STATUS_APD	0x00000008
+#define I2C_STATUS_AB	0x00010000
+#define I2C_STATUS_DR	0x00800000
+
+#define I2C_ADDRESS_PTAD	0x0000FFFF
+#define I2C_ADDRESS_SLAD	0x007F0000
+
+struct regs_cs4382 {
+	u32 mode_control_1;
+	u32 mode_control_2;
+	u32 mode_control_3;
+
+	u32 filter_control;
+	u32 invert_control;
+
+	u32 mix_control_P1;
+	u32 vol_control_A1;
+	u32 vol_control_B1;
+
+	u32 mix_control_P2;
+	u32 vol_control_A2;
+	u32 vol_control_B2;
+
+	u32 mix_control_P3;
+	u32 vol_control_A3;
+	u32 vol_control_B3;
+
+	u32 mix_control_P4;
+	u32 vol_control_A4;
+	u32 vol_control_B4;
+};
+
+static int hw20k2_i2c_unlock_full_access(struct hw *hw)
+{
+	u8 UnlockKeySequence_FLASH_FULLACCESS_MODE[2] =  {0xB3, 0xD4};
+
+	/* Send keys for forced BIOS mode */
+	hw_write_20kx(hw, I2C_IF_WLOCK,
+			UnlockKeySequence_FLASH_FULLACCESS_MODE[0]);
+	hw_write_20kx(hw, I2C_IF_WLOCK,
+			UnlockKeySequence_FLASH_FULLACCESS_MODE[1]);
+	/* Check whether the chip is unlocked */
+	if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_UNLOCKED)
+		return 0;
+
+	return -1;
+}
+
+static int hw20k2_i2c_lock_chip(struct hw *hw)
+{
+	/* Write twice */
+	hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED);
+	hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED);
+	if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_LOCKED)
+		return 0;
+
+	return -1;
+}
+
+static int hw20k2_i2c_init(struct hw *hw, u8 dev_id, u8 addr_size, u8 data_size)
+{
+	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+	int err;
+	unsigned int i2c_status;
+	unsigned int i2c_addr;
+
+	err = hw20k2_i2c_unlock_full_access(hw);
+	if (err < 0)
+		return err;
+
+	hw20k2->addr_size = addr_size;
+	hw20k2->data_size = data_size;
+	hw20k2->dev_id = dev_id;
+
+	i2c_addr = 0;
+	set_field(&i2c_addr, I2C_ADDRESS_SLAD, dev_id);
+
+	hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr);
+
+	i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
+
+	set_field(&i2c_status, I2C_STATUS_DCM, 1); /* Direct control mode */
+
+	hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
+
+	return 0;
+}
+
+static int hw20k2_i2c_uninit(struct hw *hw)
+{
+	unsigned int i2c_status;
+	unsigned int i2c_addr;
+
+	i2c_addr = 0;
+	set_field(&i2c_addr, I2C_ADDRESS_SLAD, 0x57); /* I2C id */
+
+	hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr);
+
+	i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
+
+	set_field(&i2c_status, I2C_STATUS_DCM, 0); /* I2C mode */
+
+	hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
+
+	return hw20k2_i2c_lock_chip(hw);
+}
+
+static int hw20k2_i2c_wait_data_ready(struct hw *hw)
+{
+	int i = 0x400000;
+	unsigned int ret;
+
+	do {
+		ret = hw_read_20kx(hw, I2C_IF_STATUS);
+	} while ((!(ret & DATA_READY)) && --i);
+
+	return i;
+}
+
+static int hw20k2_i2c_read(struct hw *hw, u16 addr, u32 *datap)
+{
+	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+	unsigned int i2c_status;
+
+	i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
+	set_field(&i2c_status, I2C_STATUS_BC,
+		  (4 == hw20k2->addr_size) ? 0 : hw20k2->addr_size);
+	hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
+	if (!hw20k2_i2c_wait_data_ready(hw))
+		return -1;
+
+	hw_write_20kx(hw, I2C_IF_WDATA, addr);
+	if (!hw20k2_i2c_wait_data_ready(hw))
+		return -1;
+
+	/* Force a read operation */
+	hw_write_20kx(hw, I2C_IF_RDATA, 0);
+	if (!hw20k2_i2c_wait_data_ready(hw))
+		return -1;
+
+	*datap = hw_read_20kx(hw, I2C_IF_RDATA);
+
+	return 0;
+}
+
+static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data)
+{
+	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+	unsigned int i2c_data = (data << (hw20k2->addr_size * 8)) | addr;
+	unsigned int i2c_status;
+
+	i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
+
+	set_field(&i2c_status, I2C_STATUS_BC,
+		  (4 == (hw20k2->addr_size + hw20k2->data_size)) ?
+		  0 : (hw20k2->addr_size + hw20k2->data_size));
+
+	hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
+	hw20k2_i2c_wait_data_ready(hw);
+	/* Dummy write to trigger the write oprtation */
+	hw_write_20kx(hw, I2C_IF_WDATA, 0);
+	hw20k2_i2c_wait_data_ready(hw);
+
+	/* This is the real data */
+	hw_write_20kx(hw, I2C_IF_WDATA, i2c_data);
+	hw20k2_i2c_wait_data_ready(hw);
+
+	return 0;
+}
+
+static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
+{
+	int err;
+	u32 data;
+	int i;
+	struct regs_cs4382 cs_read = {0};
+	struct regs_cs4382 cs_def = {
+				   0x00000001,  /* Mode Control 1 */
+				   0x00000000,  /* Mode Control 2 */
+				   0x00000084,  /* Mode Control 3 */
+				   0x00000000,  /* Filter Control */
+				   0x00000000,  /* Invert Control */
+				   0x00000024,  /* Mixing Control Pair 1 */
+				   0x00000000,  /* Vol Control A1 */
+				   0x00000000,  /* Vol Control B1 */
+				   0x00000024,  /* Mixing Control Pair 2 */
+				   0x00000000,  /* Vol Control A2 */
+				   0x00000000,  /* Vol Control B2 */
+				   0x00000024,  /* Mixing Control Pair 3 */
+				   0x00000000,  /* Vol Control A3 */
+				   0x00000000,  /* Vol Control B3 */
+				   0x00000024,  /* Mixing Control Pair 4 */
+				   0x00000000,  /* Vol Control A4 */
+				   0x00000000   /* Vol Control B4 */
+				 };
+
+	/* Set DAC reset bit as output */
+	data = hw_read_20kx(hw, GPIO_CTRL);
+	data |= 0x02;
+	hw_write_20kx(hw, GPIO_CTRL, data);
+
+	err = hw20k2_i2c_init(hw, 0x18, 1, 1);
+	if (err < 0)
+		goto End;
+
+	for (i = 0; i < 2; i++) {
+		/* Reset DAC twice just in-case the chip
+		 * didn't initialized properly */
+		data = hw_read_20kx(hw, GPIO_DATA);
+		/* GPIO data bit 1 */
+		data &= 0xFFFFFFFD;
+		hw_write_20kx(hw, GPIO_DATA, data);
+		mdelay(10);
+		data |= 0x2;
+		hw_write_20kx(hw, GPIO_DATA, data);
+		mdelay(50);
+
+		/* Reset the 2nd time */
+		data &= 0xFFFFFFFD;
+		hw_write_20kx(hw, GPIO_DATA, data);
+		mdelay(10);
+		data |= 0x2;
+		hw_write_20kx(hw, GPIO_DATA, data);
+		mdelay(50);
+
+		if (hw20k2_i2c_read(hw, CS4382_MC1,  &cs_read.mode_control_1))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_MC2,  &cs_read.mode_control_2))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_MC3,  &cs_read.mode_control_3))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_FC,   &cs_read.filter_control))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_IC,   &cs_read.invert_control))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_XC1,  &cs_read.mix_control_P1))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_VCA1, &cs_read.vol_control_A1))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_VCB1, &cs_read.vol_control_B1))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_XC2,  &cs_read.mix_control_P2))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_VCA2, &cs_read.vol_control_A2))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_VCB2, &cs_read.vol_control_B2))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_XC3,  &cs_read.mix_control_P3))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_VCA3, &cs_read.vol_control_A3))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_VCB3, &cs_read.vol_control_B3))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_XC4,  &cs_read.mix_control_P4))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_VCA4, &cs_read.vol_control_A4))
+			continue;
+
+		if (hw20k2_i2c_read(hw, CS4382_VCB4, &cs_read.vol_control_B4))
+			continue;
+
+		if (memcmp(&cs_read, &cs_def, sizeof(cs_read)))
+			continue;
+		else
+			break;
+	}
+
+	if (i >= 2)
+		goto End;
+
+	/* Note: Every I2C write must have some delay.
+	 * This is not a requirement but the delay works here... */
+	hw20k2_i2c_write(hw, CS4382_MC1, 0x80);
+	hw20k2_i2c_write(hw, CS4382_MC2, 0x10);
+	if (1 == info->msr) {
+		hw20k2_i2c_write(hw, CS4382_XC1, 0x24);
+		hw20k2_i2c_write(hw, CS4382_XC2, 0x24);
+		hw20k2_i2c_write(hw, CS4382_XC3, 0x24);
+		hw20k2_i2c_write(hw, CS4382_XC4, 0x24);
+	} else if (2 == info->msr) {
+		hw20k2_i2c_write(hw, CS4382_XC1, 0x25);
+		hw20k2_i2c_write(hw, CS4382_XC2, 0x25);
+		hw20k2_i2c_write(hw, CS4382_XC3, 0x25);
+		hw20k2_i2c_write(hw, CS4382_XC4, 0x25);
+	} else {
+		hw20k2_i2c_write(hw, CS4382_XC1, 0x26);
+		hw20k2_i2c_write(hw, CS4382_XC2, 0x26);
+		hw20k2_i2c_write(hw, CS4382_XC3, 0x26);
+		hw20k2_i2c_write(hw, CS4382_XC4, 0x26);
+	}
+
+	return 0;
+End:
+
+	hw20k2_i2c_uninit(hw);
+	return -1;
+}
+
+/* ADC operations */
+#define MAKE_WM8775_ADDR(addr, data)	(u32)(((addr<<1)&0xFE)|((data>>8)&0x1))
+#define MAKE_WM8775_DATA(data)	(u32)(data&0xFF)
+
+#define WM8775_IC       0x0B
+#define WM8775_MMC      0x0C
+#define WM8775_AADCL    0x0E
+#define WM8775_AADCR    0x0F
+#define WM8775_ADCMC    0x15
+#define WM8775_RESET    0x17
+
+static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
+{
+	u32 data;
+
+	data = hw_read_20kx(hw, GPIO_DATA);
+	switch (type) {
+	case ADC_MICIN:
+		data = (data & (0x1 << 14)) ? 1 : 0;
+		break;
+	case ADC_LINEIN:
+		data = (data & (0x1 << 14)) ? 0 : 1;
+		break;
+	default:
+		data = 0;
+	}
+	return data;
+}
+
+static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
+{
+	u32 data;
+
+	data = hw_read_20kx(hw, GPIO_DATA);
+	switch (type) {
+	case ADC_MICIN:
+		data |= (0x1 << 14);
+		hw_write_20kx(hw, GPIO_DATA, data);
+		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
+				MAKE_WM8775_DATA(0x101)); /* Mic-in */
+		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7),
+				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
+		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7),
+				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
+		break;
+	case ADC_LINEIN:
+		data &= ~(0x1 << 14);
+		hw_write_20kx(hw, GPIO_DATA, data);
+		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
+				MAKE_WM8775_DATA(0x102)); /* Line-in */
+		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
+				MAKE_WM8775_DATA(0xCF)); /* No boost */
+		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
+				MAKE_WM8775_DATA(0xCF)); /* No boost */
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
+{
+	int err;
+	u32 mux = 2, data, ctl;
+
+	/*  Set ADC reset bit as output */
+	data = hw_read_20kx(hw, GPIO_CTRL);
+	data |= (0x1 << 15);
+	hw_write_20kx(hw, GPIO_CTRL, data);
+
+	/* Initialize I2C */
+	err = hw20k2_i2c_init(hw, 0x1A, 1, 1);
+	if (err < 0) {
+		printk(KERN_ALERT "ctxfi: Failure to acquire I2C!!!\n");
+		goto error;
+	}
+
+	/* Make ADC in normal operation */
+	data = hw_read_20kx(hw, GPIO_DATA);
+	data &= ~(0x1 << 15);
+	mdelay(10);
+	data |= (0x1 << 15);
+	hw_write_20kx(hw, GPIO_DATA, data);
+	mdelay(50);
+
+	/* Set the master mode (256fs) */
+	if (1 == info->msr) {
+		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02),
+						MAKE_WM8775_DATA(0x02));
+	} else if (2 == info->msr) {
+		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A),
+						MAKE_WM8775_DATA(0x0A));
+	} else {
+		printk(KERN_ALERT "ctxfi: Invalid master sampling "
+				  "rate (msr %d)!!!\n", info->msr);
+		err = -EINVAL;
+		goto error;
+	}
+
+	/* Configure GPIO bit 14 change to line-in/mic-in */
+	ctl = hw_read_20kx(hw, GPIO_CTRL);
+	ctl |= 0x1 << 14;
+	hw_write_20kx(hw, GPIO_CTRL, ctl);
+
+	/* Check using Mic-in or Line-in */
+	data = hw_read_20kx(hw, GPIO_DATA);
+
+	if (mux == 1) {
+		/* Configures GPIO data to select Mic-in */
+		data |= 0x1 << 14;
+		hw_write_20kx(hw, GPIO_DATA, data);
+
+		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
+				MAKE_WM8775_DATA(0x101)); /* Mic-in */
+		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7),
+				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
+		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7),
+				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
+	} else if (mux == 2) {
+		/* Configures GPIO data to select Line-in */
+		data &= ~(0x1 << 14);
+		hw_write_20kx(hw, GPIO_DATA, data);
+
+		/* Setup ADC */
+		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
+				MAKE_WM8775_DATA(0x102)); /* Line-in */
+		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
+				MAKE_WM8775_DATA(0xCF)); /* No boost */
+		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
+				MAKE_WM8775_DATA(0xCF)); /* No boost */
+	} else {
+		printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n");
+		err = -EINVAL;
+		goto error;
+	}
+
+	return 0;
+
+error:
+	hw20k2_i2c_uninit(hw);
+	return err;
+}
+
+static int hw_have_digit_io_switch(struct hw *hw)
+{
+	return 0;
+}
+
+static int hw_card_start(struct hw *hw)
+{
+	int err = 0;
+	struct pci_dev *pci = hw->pci;
+	unsigned int gctl;
+
+	err = pci_enable_device(pci);
+	if (err < 0)
+		return err;
+
+	/* Set DMA transfer mask */
+	if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
+		printk(KERN_ERR "ctxfi: architecture does not support PCI "
+		"busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK);
+		err = -ENXIO;
+		goto error1;
+	}
+
+	err = pci_request_regions(pci, "XFi");
+	if (err < 0)
+		goto error1;
+
+	hw->io_base = pci_resource_start(hw->pci, 2);
+	hw->mem_base = (unsigned long)ioremap(hw->io_base,
+					pci_resource_len(hw->pci, 2));
+	if (NULL == (void *)hw->mem_base) {
+		err = -ENOENT;
+		goto error2;
+	}
+
+	/* Switch to 20k2 mode from UAA mode. */
+	gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
+	set_field(&gctl, GCTL_UAA, 0);
+	hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
+
+	/*if ((err = request_irq(pci->irq, ct_atc_interrupt, IRQF_SHARED,
+				atc->chip_details->nm_card, hw))) {
+		goto error3;
+	}
+	hw->irq = pci->irq;
+	*/
+
+	pci_set_master(pci);
+
+	return 0;
+
+/*error3:
+	iounmap((void *)hw->mem_base);
+	hw->mem_base = (unsigned long)NULL;*/
+error2:
+	pci_release_regions(pci);
+	hw->io_base = 0;
+error1:
+	pci_disable_device(pci);
+	return err;
+}
+
+static int hw_card_stop(struct hw *hw)
+{
+	/* TODO: Disable interrupt and so on... */
+	return 0;
+}
+
+static int hw_card_shutdown(struct hw *hw)
+{
+	if (hw->irq >= 0)
+		free_irq(hw->irq, hw);
+
+	hw->irq	= -1;
+
+	if (NULL != ((void *)hw->mem_base))
+		iounmap((void *)hw->mem_base);
+
+	hw->mem_base = (unsigned long)NULL;
+
+	if (hw->io_base)
+		pci_release_regions(hw->pci);
+
+	hw->io_base = 0;
+
+	pci_disable_device(hw->pci);
+
+	return 0;
+}
+
+static int hw_card_init(struct hw *hw, struct card_conf *info)
+{
+	int err;
+	unsigned int gctl;
+	u32 data = 0;
+	struct dac_conf dac_info = {0};
+	struct adc_conf adc_info = {0};
+	struct daio_conf daio_info = {0};
+	struct trn_conf trn_info = {0};
+
+	/* Get PCI io port/memory base address and
+	 * do 20kx core switch if needed. */
+	if (!hw->io_base) {
+		err = hw_card_start(hw);
+		if (err)
+			return err;
+	}
+
+	/* PLL init */
+	err = hw_pll_init(hw, info->rsr);
+	if (err < 0)
+		return err;
+
+	/* kick off auto-init */
+	err = hw_auto_init(hw);
+	if (err < 0)
+		return err;
+
+	gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
+	set_field(&gctl, GCTL_DBP, 1);
+	set_field(&gctl, GCTL_TBP, 1);
+	set_field(&gctl, GCTL_FBP, 1);
+	set_field(&gctl, GCTL_DPC, 0);
+	hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
+
+	/* Reset all global pending interrupts */
+	hw_write_20kx(hw, INTERRUPT_GIE, 0);
+	/* Reset all SRC pending interrupts */
+	hw_write_20kx(hw, SRC_IP, 0);
+
+	/* TODO: detect the card ID and configure GPIO accordingly. */
+	/* Configures GPIO (0xD802 0x98028) */
+	/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
+	/* Configures GPIO (SB0880) */
+	/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
+	hw_write_20kx(hw, GPIO_CTRL, 0xD802);
+
+	/* Enable audio ring */
+	hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01);
+
+	trn_info.vm_pgt_phys = info->vm_pgt_phys;
+	err = hw_trn_init(hw, &trn_info);
+	if (err < 0)
+		return err;
+
+	daio_info.msr = info->msr;
+	err = hw_daio_init(hw, &daio_info);
+	if (err < 0)
+		return err;
+
+	dac_info.msr = info->msr;
+	err = hw_dac_init(hw, &dac_info);
+	if (err < 0)
+		return err;
+
+	adc_info.msr = info->msr;
+	adc_info.input = ADC_LINEIN;
+	adc_info.mic20db = 0;
+	err = hw_adc_init(hw, &adc_info);
+	if (err < 0)
+		return err;
+
+	data = hw_read_20kx(hw, SRC_MCTL);
+	data |= 0x1; /* Enables input from the audio ring */
+	hw_write_20kx(hw, SRC_MCTL, data);
+
+	return 0;
+}
+
+static u32 hw_read_20kx(struct hw *hw, u32 reg)
+{
+	return readl((void *)(hw->mem_base + reg));
+}
+
+static void hw_write_20kx(struct hw *hw, u32 reg, u32 data)
+{
+	writel(data, (void *)(hw->mem_base + reg));
+}
+
+static struct hw ct20k2_preset __devinitdata = {
+	.irq = -1,
+
+	.card_init = hw_card_init,
+	.card_stop = hw_card_stop,
+	.pll_init = hw_pll_init,
+	.is_adc_source_selected = hw_is_adc_input_selected,
+	.select_adc_source = hw_adc_input_select,
+	.have_digit_io_switch = hw_have_digit_io_switch,
+
+	.src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk,
+	.src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk,
+	.src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk,
+	.src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk,
+	.src_set_state = src_set_state,
+	.src_set_bm = src_set_bm,
+	.src_set_rsr = src_set_rsr,
+	.src_set_sf = src_set_sf,
+	.src_set_wr = src_set_wr,
+	.src_set_pm = src_set_pm,
+	.src_set_rom = src_set_rom,
+	.src_set_vo = src_set_vo,
+	.src_set_st = src_set_st,
+	.src_set_ie = src_set_ie,
+	.src_set_ilsz = src_set_ilsz,
+	.src_set_bp = src_set_bp,
+	.src_set_cisz = src_set_cisz,
+	.src_set_ca = src_set_ca,
+	.src_set_sa = src_set_sa,
+	.src_set_la = src_set_la,
+	.src_set_pitch = src_set_pitch,
+	.src_set_dirty = src_set_dirty,
+	.src_set_clear_zbufs = src_set_clear_zbufs,
+	.src_set_dirty_all = src_set_dirty_all,
+	.src_commit_write = src_commit_write,
+	.src_get_ca = src_get_ca,
+	.src_get_dirty = src_get_dirty,
+	.src_dirty_conj_mask = src_dirty_conj_mask,
+	.src_mgr_enbs_src = src_mgr_enbs_src,
+	.src_mgr_enb_src = src_mgr_enb_src,
+	.src_mgr_dsb_src = src_mgr_dsb_src,
+	.src_mgr_commit_write = src_mgr_commit_write,
+
+	.srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk,
+	.srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk,
+	.srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc,
+	.srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser,
+	.srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt,
+	.srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr,
+	.srcimp_mgr_commit_write = srcimp_mgr_commit_write,
+
+	.amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk,
+	.amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk,
+	.amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk,
+	.amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk,
+	.amixer_set_mode = amixer_set_mode,
+	.amixer_set_iv = amixer_set_iv,
+	.amixer_set_x = amixer_set_x,
+	.amixer_set_y = amixer_set_y,
+	.amixer_set_sadr = amixer_set_sadr,
+	.amixer_set_se = amixer_set_se,
+	.amixer_set_dirty = amixer_set_dirty,
+	.amixer_set_dirty_all = amixer_set_dirty_all,
+	.amixer_commit_write = amixer_commit_write,
+	.amixer_get_y = amixer_get_y,
+	.amixer_get_dirty = amixer_get_dirty,
+
+	.dai_get_ctrl_blk = dai_get_ctrl_blk,
+	.dai_put_ctrl_blk = dai_put_ctrl_blk,
+	.dai_srt_set_srco = dai_srt_set_srco,
+	.dai_srt_set_srcm = dai_srt_set_srcm,
+	.dai_srt_set_rsr = dai_srt_set_rsr,
+	.dai_srt_set_drat = dai_srt_set_drat,
+	.dai_srt_set_ec = dai_srt_set_ec,
+	.dai_srt_set_et = dai_srt_set_et,
+	.dai_commit_write = dai_commit_write,
+
+	.dao_get_ctrl_blk = dao_get_ctrl_blk,
+	.dao_put_ctrl_blk = dao_put_ctrl_blk,
+	.dao_set_spos = dao_set_spos,
+	.dao_commit_write = dao_commit_write,
+	.dao_get_spos = dao_get_spos,
+
+	.daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk,
+	.daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk,
+	.daio_mgr_enb_dai = daio_mgr_enb_dai,
+	.daio_mgr_dsb_dai = daio_mgr_dsb_dai,
+	.daio_mgr_enb_dao = daio_mgr_enb_dao,
+	.daio_mgr_dsb_dao = daio_mgr_dsb_dao,
+	.daio_mgr_dao_init = daio_mgr_dao_init,
+	.daio_mgr_set_imaparc = daio_mgr_set_imaparc,
+	.daio_mgr_set_imapnxt = daio_mgr_set_imapnxt,
+	.daio_mgr_set_imapaddr = daio_mgr_set_imapaddr,
+	.daio_mgr_commit_write = daio_mgr_commit_write,
+};
+
+int __devinit create_20k2_hw_obj(struct hw **rhw)
+{
+	struct hw20k2 *hw20k2;
+
+	*rhw = NULL;
+	hw20k2 = kzalloc(sizeof(*hw20k2), GFP_KERNEL);
+	if (!hw20k2)
+		return -ENOMEM;
+
+	hw20k2->hw = ct20k2_preset;
+	*rhw = &hw20k2->hw;
+
+	return 0;
+}
+
+int destroy_20k2_hw_obj(struct hw *hw)
+{
+	if (hw->io_base)
+		hw_card_shutdown(hw);
+
+	kfree(hw);
+	return 0;
+}
diff --git a/sound/pci/ctxfi/cthw20k2.h b/sound/pci/ctxfi/cthw20k2.h
new file mode 100644
index 0000000..d2b7daa
--- /dev/null
+++ b/sound/pci/ctxfi/cthw20k2.h
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	cthw20k2.h
+ *
+ * @Brief
+ * This file contains the definition of hardware access methord.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 13 2008
+ *
+ */
+
+#ifndef CTHW20K2_H
+#define CTHW20K2_H
+
+#include "cthardware.h"
+
+int create_20k2_hw_obj(struct hw **rhw);
+int destroy_20k2_hw_obj(struct hw *hw);
+
+#endif /* CTHW20K2_H */
diff --git a/sound/pci/ctxfi/ctimap.c b/sound/pci/ctxfi/ctimap.c
new file mode 100644
index 0000000..0b73368
--- /dev/null
+++ b/sound/pci/ctxfi/ctimap.c
@@ -0,0 +1,112 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctimap.c
+ *
+ * @Brief
+ * This file contains the implementation of generic input mapper operations
+ * for input mapper management.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 23 2008
+ *
+ */
+
+#include "ctimap.h"
+#include <linux/slab.h>
+
+int input_mapper_add(struct list_head *mappers, struct imapper *entry,
+		     int (*map_op)(void *, struct imapper *), void *data)
+{
+	struct list_head *pos, *pre, *head;
+	struct imapper *pre_ent, *pos_ent;
+
+	head = mappers;
+
+	if (list_empty(head)) {
+		entry->next = entry->addr;
+		map_op(data, entry);
+		list_add(&entry->list, head);
+		return 0;
+	}
+
+	list_for_each(pos, head) {
+		pos_ent = list_entry(pos, struct imapper, list);
+		if (pos_ent->slot > entry->slot) {
+			/* found a position in list */
+			break;
+		}
+	}
+
+	if (pos != head) {
+		pre = pos->prev;
+		if (pre == head)
+			pre = head->prev;
+
+		__list_add(&entry->list, pos->prev, pos);
+	} else {
+		pre = head->prev;
+		pos = head->next;
+		list_add_tail(&entry->list, head);
+	}
+
+	pre_ent = list_entry(pre, struct imapper, list);
+	pos_ent = list_entry(pos, struct imapper, list);
+
+	entry->next = pos_ent->addr;
+	map_op(data, entry);
+	pre_ent->next = entry->addr;
+	map_op(data, pre_ent);
+
+	return 0;
+}
+
+int input_mapper_delete(struct list_head *mappers, struct imapper *entry,
+		     int (*map_op)(void *, struct imapper *), void *data)
+{
+	struct list_head *next, *pre, *head;
+	struct imapper *pre_ent, *next_ent;
+
+	head = mappers;
+
+	if (list_empty(head))
+		return 0;
+
+	pre = (entry->list.prev == head) ? head->prev : entry->list.prev;
+	next = (entry->list.next == head) ? head->next : entry->list.next;
+
+	if (pre == &entry->list) {
+		/* entry is the only one node in mappers list */
+		entry->next = entry->addr = entry->user = entry->slot = 0;
+		map_op(data, entry);
+		list_del(&entry->list);
+		return 0;
+	}
+
+	pre_ent = list_entry(pre, struct imapper, list);
+	next_ent = list_entry(next, struct imapper, list);
+
+	pre_ent->next = next_ent->addr;
+	map_op(data, pre_ent);
+	list_del(&entry->list);
+
+	return 0;
+}
+
+void free_input_mapper_list(struct list_head *head)
+{
+	struct imapper *entry;
+	struct list_head *pos;
+
+	while (!list_empty(head)) {
+		pos = head->next;
+		list_del(pos);
+		entry = list_entry(pos, struct imapper, list);
+		kfree(entry);
+	}
+}
+
diff --git a/sound/pci/ctxfi/ctimap.h b/sound/pci/ctxfi/ctimap.h
new file mode 100644
index 0000000..53ccf9b
--- /dev/null
+++ b/sound/pci/ctxfi/ctimap.h
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctimap.h
+ *
+ * @Brief
+ * This file contains the definition of generic input mapper operations
+ * for input mapper management.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 23 2008
+ *
+ */
+
+#ifndef CTIMAP_H
+#define CTIMAP_H
+
+#include <linux/list.h>
+
+struct imapper {
+	unsigned short slot; /* the id of the slot containing input data */
+	unsigned short user; /* the id of the user resource consuming data */
+	unsigned short addr; /* the input mapper ram id */
+	unsigned short next; /* the next input mapper ram id */
+	struct list_head	list;
+};
+
+int input_mapper_add(struct list_head *mappers, struct imapper *entry,
+		     int (*map_op)(void *, struct imapper *), void *data);
+
+int input_mapper_delete(struct list_head *mappers, struct imapper *entry,
+		     int (*map_op)(void *, struct imapper *), void *data);
+
+void free_input_mapper_list(struct list_head *mappers);
+
+#endif /* CTIMAP_H */
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c
new file mode 100644
index 0000000..666722d
--- /dev/null
+++ b/sound/pci/ctxfi/ctmixer.c
@@ -0,0 +1,1123 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctmixer.c
+ *
+ * @Brief
+ * This file contains the implementation of alsa mixer device functions.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 28 2008
+ *
+ */
+
+
+#include "ctmixer.h"
+#include "ctamixer.h"
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/asoundef.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+
+enum CT_SUM_CTL {
+	SUM_IN_F,
+	SUM_IN_R,
+	SUM_IN_C,
+	SUM_IN_S,
+	SUM_IN_F_C,
+
+	NUM_CT_SUMS
+};
+
+enum CT_AMIXER_CTL {
+	/* volume control mixers */
+	AMIXER_MASTER_F,
+	AMIXER_MASTER_R,
+	AMIXER_MASTER_C,
+	AMIXER_MASTER_S,
+	AMIXER_PCM_F,
+	AMIXER_PCM_R,
+	AMIXER_PCM_C,
+	AMIXER_PCM_S,
+	AMIXER_SPDIFI,
+	AMIXER_LINEIN,
+	AMIXER_MIC,
+	AMIXER_SPDIFO,
+	AMIXER_WAVE_F,
+	AMIXER_WAVE_R,
+	AMIXER_WAVE_C,
+	AMIXER_WAVE_S,
+	AMIXER_MASTER_F_C,
+	AMIXER_PCM_F_C,
+	AMIXER_SPDIFI_C,
+	AMIXER_LINEIN_C,
+	AMIXER_MIC_C,
+
+	/* this should always be the last one */
+	NUM_CT_AMIXERS
+};
+
+enum CTALSA_MIXER_CTL {
+	/* volume control mixers */
+	MIXER_MASTER_P,
+	MIXER_PCM_P,
+	MIXER_LINEIN_P,
+	MIXER_MIC_P,
+	MIXER_SPDIFI_P,
+	MIXER_SPDIFO_P,
+	MIXER_WAVEF_P,
+	MIXER_WAVER_P,
+	MIXER_WAVEC_P,
+	MIXER_WAVES_P,
+	MIXER_MASTER_C,
+	MIXER_PCM_C,
+	MIXER_LINEIN_C,
+	MIXER_MIC_C,
+	MIXER_SPDIFI_C,
+
+	/* switch control mixers */
+	MIXER_PCM_C_S,
+	MIXER_LINEIN_C_S,
+	MIXER_MIC_C_S,
+	MIXER_SPDIFI_C_S,
+	MIXER_LINEIN_P_S,
+	MIXER_SPDIFO_P_S,
+	MIXER_SPDIFI_P_S,
+	MIXER_WAVEF_P_S,
+	MIXER_WAVER_P_S,
+	MIXER_WAVEC_P_S,
+	MIXER_WAVES_P_S,
+	MIXER_DIGITAL_IO_S,
+	MIXER_IEC958_MASK,
+	MIXER_IEC958_DEFAULT,
+	MIXER_IEC958_STREAM,
+
+	/* this should always be the last one */
+	NUM_CTALSA_MIXERS
+};
+
+#define VOL_MIXER_START		MIXER_MASTER_P
+#define VOL_MIXER_END		MIXER_SPDIFI_C
+#define VOL_MIXER_NUM		(VOL_MIXER_END - VOL_MIXER_START + 1)
+#define SWH_MIXER_START		MIXER_PCM_C_S
+#define SWH_MIXER_END		MIXER_DIGITAL_IO_S
+#define SWH_CAPTURE_START	MIXER_PCM_C_S
+#define SWH_CAPTURE_END		MIXER_SPDIFI_C_S
+
+#define CHN_NUM		2
+
+struct ct_kcontrol_init {
+	unsigned char ctl;
+	char *name;
+};
+
+static struct ct_kcontrol_init
+ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
+	[MIXER_MASTER_P] = {
+		.ctl = 1,
+		.name = "Master Playback Volume",
+	},
+	[MIXER_MASTER_C] = {
+		.ctl = 1,
+		.name = "Master Capture Volume",
+	},
+	[MIXER_PCM_P] = {
+		.ctl = 1,
+		.name = "PCM Playback Volume",
+	},
+	[MIXER_PCM_C] = {
+		.ctl = 1,
+		.name = "PCM Capture Volume",
+	},
+	[MIXER_LINEIN_P] = {
+		.ctl = 1,
+		.name = "Line-in Playback Volume",
+	},
+	[MIXER_LINEIN_C] = {
+		.ctl = 1,
+		.name = "Line-in Capture Volume",
+	},
+	[MIXER_MIC_P] = {
+		.ctl = 1,
+		.name = "Mic Playback Volume",
+	},
+	[MIXER_MIC_C] = {
+		.ctl = 1,
+		.name = "Mic Capture Volume",
+	},
+	[MIXER_SPDIFI_P] = {
+		.ctl = 1,
+		.name = "S/PDIF-in Playback Volume",
+	},
+	[MIXER_SPDIFI_C] = {
+		.ctl = 1,
+		.name = "S/PDIF-in Capture Volume",
+	},
+	[MIXER_SPDIFO_P] = {
+		.ctl = 1,
+		.name = "S/PDIF-out Playback Volume",
+	},
+	[MIXER_WAVEF_P] = {
+		.ctl = 1,
+		.name = "Front Playback Volume",
+	},
+	[MIXER_WAVES_P] = {
+		.ctl = 1,
+		.name = "Side Playback Volume",
+	},
+	[MIXER_WAVEC_P] = {
+		.ctl = 1,
+		.name = "Center/LFE Playback Volume",
+	},
+	[MIXER_WAVER_P] = {
+		.ctl = 1,
+		.name = "Surround Playback Volume",
+	},
+
+	[MIXER_PCM_C_S] = {
+		.ctl = 1,
+		.name = "PCM Capture Switch",
+	},
+	[MIXER_LINEIN_C_S] = {
+		.ctl = 1,
+		.name = "Line-in Capture Switch",
+	},
+	[MIXER_MIC_C_S] = {
+		.ctl = 1,
+		.name = "Mic Capture Switch",
+	},
+	[MIXER_SPDIFI_C_S] = {
+		.ctl = 1,
+		.name = "S/PDIF-in Capture Switch",
+	},
+	[MIXER_LINEIN_P_S] = {
+		.ctl = 1,
+		.name = "Line-in Playback Switch",
+	},
+	[MIXER_SPDIFO_P_S] = {
+		.ctl = 1,
+		.name = "S/PDIF-out Playback Switch",
+	},
+	[MIXER_SPDIFI_P_S] = {
+		.ctl = 1,
+		.name = "S/PDIF-in Playback Switch",
+	},
+	[MIXER_WAVEF_P_S] = {
+		.ctl = 1,
+		.name = "Front Playback Switch",
+	},
+	[MIXER_WAVES_P_S] = {
+		.ctl = 1,
+		.name = "Side Playback Switch",
+	},
+	[MIXER_WAVEC_P_S] = {
+		.ctl = 1,
+		.name = "Center/LFE Playback Switch",
+	},
+	[MIXER_WAVER_P_S] = {
+		.ctl = 1,
+		.name = "Surround Playback Switch",
+	},
+	[MIXER_DIGITAL_IO_S] = {
+		.ctl = 0,
+		.name = "Digit-IO Playback Switch",
+	},
+};
+
+static void
+ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
+
+static void
+ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
+
+static struct snd_kcontrol *kctls[2] = {NULL};
+
+static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index)
+{
+	switch (alsa_index) {
+	case MIXER_MASTER_P:	return AMIXER_MASTER_F;
+	case MIXER_MASTER_C:	return AMIXER_MASTER_F_C;
+	case MIXER_PCM_P:	return AMIXER_PCM_F;
+	case MIXER_PCM_C:
+	case MIXER_PCM_C_S:	return AMIXER_PCM_F_C;
+	case MIXER_LINEIN_P:	return AMIXER_LINEIN;
+	case MIXER_LINEIN_C:
+	case MIXER_LINEIN_C_S:	return AMIXER_LINEIN_C;
+	case MIXER_MIC_P:	return AMIXER_MIC;
+	case MIXER_MIC_C:
+	case MIXER_MIC_C_S:	return AMIXER_MIC_C;
+	case MIXER_SPDIFI_P:	return AMIXER_SPDIFI;
+	case MIXER_SPDIFI_C:
+	case MIXER_SPDIFI_C_S:	return AMIXER_SPDIFI_C;
+	case MIXER_SPDIFO_P:	return AMIXER_SPDIFO;
+	case MIXER_WAVEF_P:	return AMIXER_WAVE_F;
+	case MIXER_WAVES_P:	return AMIXER_WAVE_S;
+	case MIXER_WAVEC_P:	return AMIXER_WAVE_C;
+	case MIXER_WAVER_P:	return AMIXER_WAVE_R;
+	default:		return NUM_CT_AMIXERS;
+	}
+}
+
+static enum CT_AMIXER_CTL get_recording_amixer(enum CT_AMIXER_CTL index)
+{
+	switch (index) {
+	case AMIXER_MASTER_F:	return AMIXER_MASTER_F_C;
+	case AMIXER_PCM_F:	return AMIXER_PCM_F_C;
+	case AMIXER_SPDIFI:	return AMIXER_SPDIFI_C;
+	case AMIXER_LINEIN:	return AMIXER_LINEIN_C;
+	case AMIXER_MIC:	return AMIXER_MIC_C;
+	default:		return NUM_CT_AMIXERS;
+	}
+}
+
+static unsigned char
+get_switch_state(struct ct_mixer *mixer, enum CTALSA_MIXER_CTL type)
+{
+	return (mixer->switch_state & (0x1 << (type - SWH_MIXER_START)))
+		? 1 : 0;
+}
+
+static void
+set_switch_state(struct ct_mixer *mixer,
+		 enum CTALSA_MIXER_CTL type, unsigned char state)
+{
+	if (state)
+		mixer->switch_state |= (0x1 << (type - SWH_MIXER_START));
+	else
+		mixer->switch_state &= ~(0x1 << (type - SWH_MIXER_START));
+}
+
+#if 0 /* not used */
+/* Map integer value ranging from 0 to 65535 to 14-bit float value ranging
+ * from 2^-6 to (1+1023/1024) */
+static unsigned int uint16_to_float14(unsigned int x)
+{
+	unsigned int i;
+
+	if (x < 17)
+		return 0;
+
+	x *= 2031;
+	x /= 65535;
+	x += 16;
+
+	/* i <= 6 */
+	for (i = 0; !(x & 0x400); i++)
+		x <<= 1;
+
+	x = (((7 - i) & 0x7) << 10) | (x & 0x3ff);
+
+	return x;
+}
+
+static unsigned int float14_to_uint16(unsigned int x)
+{
+	unsigned int e;
+
+	if (!x)
+		return x;
+
+	e = (x >> 10) & 0x7;
+	x &= 0x3ff;
+	x += 1024;
+	x >>= (7 - e);
+	x -= 16;
+	x *= 65535;
+	x /= 2031;
+
+	return x;
+}
+#endif /* not used */
+
+#define VOL_SCALE	0x1c
+#define VOL_MAX		0x100
+
+static const DECLARE_TLV_DB_SCALE(ct_vol_db_scale, -6400, 25, 1);
+
+static int ct_alsa_mix_volume_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 = VOL_MAX;
+
+	return 0;
+}
+
+static int ct_alsa_mix_volume_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+	enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);
+	struct amixer *amixer;
+	int i, val;
+
+	for (i = 0; i < 2; i++) {
+		amixer = ((struct ct_mixer *)atc->mixer)->
+						amixers[type*CHN_NUM+i];
+		val = amixer->ops->get_scale(amixer) / VOL_SCALE;
+		if (val < 0)
+			val = 0;
+		else if (val > VOL_MAX)
+			val = VOL_MAX;
+		ucontrol->value.integer.value[i] = val;
+	}
+
+	return 0;
+}
+
+static int ct_alsa_mix_volume_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+	struct ct_mixer *mixer = atc->mixer;
+	enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);
+	struct amixer *amixer;
+	int i, j, val, oval, change = 0;
+
+	for (i = 0; i < 2; i++) {
+		val = ucontrol->value.integer.value[i];
+		if (val < 0)
+			val = 0;
+		else if (val > VOL_MAX)
+			val = VOL_MAX;
+		val *= VOL_SCALE;
+		amixer = mixer->amixers[type*CHN_NUM+i];
+		oval = amixer->ops->get_scale(amixer);
+		if (val != oval) {
+			amixer->ops->set_scale(amixer, val);
+			amixer->ops->commit_write(amixer);
+			change = 1;
+			/* Synchronize Master/PCM playback AMIXERs. */
+			if (AMIXER_MASTER_F == type || AMIXER_PCM_F == type) {
+				for (j = 1; j < 4; j++) {
+					amixer = mixer->
+						amixers[(type+j)*CHN_NUM+i];
+					amixer->ops->set_scale(amixer, val);
+					amixer->ops->commit_write(amixer);
+				}
+			}
+		}
+	}
+
+	return change;
+}
+
+static struct snd_kcontrol_new vol_ctl = {
+	.access		= SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+	.iface		= SNDRV_CTL_ELEM_IFACE_MIXER,
+	.info		= ct_alsa_mix_volume_info,
+	.get		= ct_alsa_mix_volume_get,
+	.put		= ct_alsa_mix_volume_put,
+	.tlv		= { .p =  ct_vol_db_scale },
+};
+
+static void
+do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type)
+{
+
+	if (MIXER_LINEIN_C_S == type) {
+		atc->select_line_in(atc);
+		set_switch_state(atc->mixer, MIXER_MIC_C_S, 0);
+		snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
+							&kctls[1]->id);
+	} else if (MIXER_MIC_C_S == type) {
+		atc->select_mic_in(atc);
+		set_switch_state(atc->mixer, MIXER_LINEIN_C_S, 0);
+		snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
+							&kctls[0]->id);
+	}
+}
+
+static void
+do_digit_io_switch(struct ct_atc *atc, int state)
+{
+	struct ct_mixer *mixer = atc->mixer;
+
+	if (state) {
+		atc->select_digit_io(atc);
+		atc->spdif_out_unmute(atc,
+				get_switch_state(mixer, MIXER_SPDIFO_P_S));
+		atc->spdif_in_unmute(atc, 1);
+		atc->line_in_unmute(atc, 0);
+		return;
+	}
+
+	if (get_switch_state(mixer, MIXER_LINEIN_C_S))
+		atc->select_line_in(atc);
+	else if (get_switch_state(mixer, MIXER_MIC_C_S))
+		atc->select_mic_in(atc);
+
+	atc->spdif_out_unmute(atc, 0);
+	atc->spdif_in_unmute(atc, 0);
+	atc->line_in_unmute(atc, 1);
+	return;
+}
+
+static int ct_alsa_mix_switch_info(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	uinfo->value.integer.step = 1;
+
+	return 0;
+}
+
+static int ct_alsa_mix_switch_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_mixer *mixer =
+		((struct ct_atc *)snd_kcontrol_chip(kcontrol))->mixer;
+	enum CTALSA_MIXER_CTL type = kcontrol->private_value;
+
+	ucontrol->value.integer.value[0] = get_switch_state(mixer, type);
+	return 0;
+}
+
+static int ct_alsa_mix_switch_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+	struct ct_mixer *mixer = atc->mixer;
+	enum CTALSA_MIXER_CTL type = kcontrol->private_value;
+	int state;
+
+	state = ucontrol->value.integer.value[0];
+	if (get_switch_state(mixer, type) == state)
+		return 0;
+
+	set_switch_state(mixer, type, state);
+	/* Do changes in mixer. */
+	if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
+		if (state) {
+			ct_mixer_recording_select(mixer,
+						  get_amixer_index(type));
+		} else {
+			ct_mixer_recording_unselect(mixer,
+						    get_amixer_index(type));
+		}
+	}
+	/* Do changes out of mixer. */
+	if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
+		do_line_mic_switch(atc, type);
+	else if (MIXER_WAVEF_P_S == type)
+		atc->line_front_unmute(atc, state);
+	else if (MIXER_WAVES_P_S == type)
+		atc->line_surround_unmute(atc, state);
+	else if (MIXER_WAVEC_P_S == type)
+		atc->line_clfe_unmute(atc, state);
+	else if (MIXER_WAVER_P_S == type)
+		atc->line_rear_unmute(atc, state);
+	else if (MIXER_LINEIN_P_S == type)
+		atc->line_in_unmute(atc, state);
+	else if (MIXER_SPDIFO_P_S == type)
+		atc->spdif_out_unmute(atc, state);
+	else if (MIXER_SPDIFI_P_S == type)
+		atc->spdif_in_unmute(atc, state);
+	else if (MIXER_DIGITAL_IO_S == type)
+		do_digit_io_switch(atc, state);
+
+	return 1;
+}
+
+static struct snd_kcontrol_new swh_ctl = {
+	.access		= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.iface		= SNDRV_CTL_ELEM_IFACE_MIXER,
+	.info		= ct_alsa_mix_switch_info,
+	.get		= ct_alsa_mix_switch_get,
+	.put		= ct_alsa_mix_switch_put
+};
+
+static int ct_spdif_info(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int ct_spdif_get_mask(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.iec958.status[0] = 0xff;
+	ucontrol->value.iec958.status[1] = 0xff;
+	ucontrol->value.iec958.status[2] = 0xff;
+	ucontrol->value.iec958.status[3] = 0xff;
+	return 0;
+}
+
+static int ct_spdif_default_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned int status = SNDRV_PCM_DEFAULT_CON_SPDIF;
+
+	ucontrol->value.iec958.status[0] = (status >> 0) & 0xff;
+	ucontrol->value.iec958.status[1] = (status >> 8) & 0xff;
+	ucontrol->value.iec958.status[2] = (status >> 16) & 0xff;
+	ucontrol->value.iec958.status[3] = (status >> 24) & 0xff;
+
+	return 0;
+}
+
+static int ct_spdif_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+	unsigned int status;
+
+	atc->spdif_out_get_status(atc, &status);
+	ucontrol->value.iec958.status[0] = (status >> 0) & 0xff;
+	ucontrol->value.iec958.status[1] = (status >> 8) & 0xff;
+	ucontrol->value.iec958.status[2] = (status >> 16) & 0xff;
+	ucontrol->value.iec958.status[3] = (status >> 24) & 0xff;
+
+	return 0;
+}
+
+static int ct_spdif_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+	int change;
+	unsigned int status, old_status;
+
+	status = (ucontrol->value.iec958.status[0] << 0) |
+		 (ucontrol->value.iec958.status[1] << 8) |
+		 (ucontrol->value.iec958.status[2] << 16) |
+		 (ucontrol->value.iec958.status[3] << 24);
+
+	atc->spdif_out_get_status(atc, &old_status);
+	change = (old_status != status);
+	if (change)
+		atc->spdif_out_set_status(atc, status);
+
+	return change;
+}
+
+static struct snd_kcontrol_new iec958_mask_ctl = {
+	.access		= SNDRV_CTL_ELEM_ACCESS_READ,
+	.iface		= SNDRV_CTL_ELEM_IFACE_PCM,
+	.name		= SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
+	.count		= 1,
+	.info		= ct_spdif_info,
+	.get		= ct_spdif_get_mask,
+	.private_value	= MIXER_IEC958_MASK
+};
+
+static struct snd_kcontrol_new iec958_default_ctl = {
+	.iface		= SNDRV_CTL_ELEM_IFACE_PCM,
+	.name		= SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+	.count		= 1,
+	.info		= ct_spdif_info,
+	.get		= ct_spdif_default_get,
+	.put		= ct_spdif_put,
+	.private_value	= MIXER_IEC958_DEFAULT
+};
+
+static struct snd_kcontrol_new iec958_ctl = {
+	.access		= SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.iface		= SNDRV_CTL_ELEM_IFACE_PCM,
+	.name		= SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
+	.count		= 1,
+	.info		= ct_spdif_info,
+	.get		= ct_spdif_get,
+	.put		= ct_spdif_put,
+	.private_value	= MIXER_IEC958_STREAM
+};
+
+#define NUM_IEC958_CTL 3
+
+static int
+ct_mixer_kcontrol_new(struct ct_mixer *mixer, struct snd_kcontrol_new *new)
+{
+	struct snd_kcontrol *kctl;
+	int err;
+
+	kctl = snd_ctl_new1(new, mixer->atc);
+	if (NULL == kctl)
+		return -ENOMEM;
+
+	if (SNDRV_CTL_ELEM_IFACE_PCM == kctl->id.iface)
+		kctl->id.device = IEC958;
+
+	err = snd_ctl_add(mixer->atc->card, kctl);
+	if (err)
+		return err;
+
+	switch (new->private_value) {
+	case MIXER_LINEIN_C_S:
+		kctls[0] = kctl; break;
+	case MIXER_MIC_C_S:
+		kctls[1] = kctl; break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
+{
+	enum CTALSA_MIXER_CTL type;
+	struct ct_atc *atc = mixer->atc;
+	int err;
+
+	/* Create snd kcontrol instances on demand */
+	for (type = VOL_MIXER_START; type <= VOL_MIXER_END; type++) {
+		if (ct_kcontrol_init_table[type].ctl) {
+			vol_ctl.name = ct_kcontrol_init_table[type].name;
+			vol_ctl.private_value = (unsigned long)type;
+			err = ct_mixer_kcontrol_new(mixer, &vol_ctl);
+			if (err)
+				return err;
+		}
+	}
+
+	ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl =
+					atc->have_digit_io_switch(atc);
+	for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) {
+		if (ct_kcontrol_init_table[type].ctl) {
+			swh_ctl.name = ct_kcontrol_init_table[type].name;
+			swh_ctl.private_value = (unsigned long)type;
+			err = ct_mixer_kcontrol_new(mixer, &swh_ctl);
+			if (err)
+				return err;
+		}
+	}
+
+	err = ct_mixer_kcontrol_new(mixer, &iec958_mask_ctl);
+	if (err)
+		return err;
+
+	err = ct_mixer_kcontrol_new(mixer, &iec958_default_ctl);
+	if (err)
+		return err;
+
+	err = ct_mixer_kcontrol_new(mixer, &iec958_ctl);
+	if (err)
+		return err;
+
+	atc->line_front_unmute(atc, 1);
+	set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
+	atc->line_surround_unmute(atc, 0);
+	set_switch_state(mixer, MIXER_WAVES_P_S, 0);
+	atc->line_clfe_unmute(atc, 0);
+	set_switch_state(mixer, MIXER_WAVEC_P_S, 0);
+	atc->line_rear_unmute(atc, 0);
+	set_switch_state(mixer, MIXER_WAVER_P_S, 0);
+	atc->spdif_out_unmute(atc, 0);
+	set_switch_state(mixer, MIXER_SPDIFO_P_S, 0);
+	atc->line_in_unmute(atc, 0);
+	set_switch_state(mixer, MIXER_LINEIN_P_S, 0);
+	atc->spdif_in_unmute(atc, 0);
+	set_switch_state(mixer, MIXER_SPDIFI_P_S, 0);
+
+	set_switch_state(mixer, MIXER_PCM_C_S, 1);
+	set_switch_state(mixer, MIXER_LINEIN_C_S, 1);
+	set_switch_state(mixer, MIXER_SPDIFI_C_S, 1);
+
+	return 0;
+}
+
+static void
+ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)
+{
+	struct amixer *amix_d;
+	struct sum *sum_c;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		amix_d = mixer->amixers[type*CHN_NUM+i];
+		sum_c = mixer->sums[SUM_IN_F_C*CHN_NUM+i];
+		amix_d->ops->set_sum(amix_d, sum_c);
+		amix_d->ops->commit_write(amix_d);
+	}
+}
+
+static void
+ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)
+{
+	struct amixer *amix_d;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		amix_d = mixer->amixers[type*CHN_NUM+i];
+		amix_d->ops->set_sum(amix_d, NULL);
+		amix_d->ops->commit_write(amix_d);
+	}
+}
+
+static int ct_mixer_get_resources(struct ct_mixer *mixer)
+{
+	struct sum_mgr *sum_mgr;
+	struct sum *sum;
+	struct sum_desc sum_desc = {0};
+	struct amixer_mgr *amixer_mgr;
+	struct amixer *amixer;
+	struct amixer_desc am_desc = {0};
+	int err;
+	int i;
+
+	/* Allocate sum resources for mixer obj */
+	sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
+	sum_desc.msr = mixer->atc->msr;
+	for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
+		err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum);
+		if (err) {
+			printk(KERN_ERR "ctxfi:Failed to get sum resources for "
+					  "front output!\n");
+			break;
+		}
+		mixer->sums[i] = sum;
+	}
+	if (err)
+		goto error1;
+
+	/* Allocate amixer resources for mixer obj */
+	amixer_mgr = (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];
+	am_desc.msr = mixer->atc->msr;
+	for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
+		err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer);
+		if (err) {
+			printk(KERN_ERR "ctxfi:Failed to get amixer resources "
+			       "for mixer obj!\n");
+			break;
+		}
+		mixer->amixers[i] = amixer;
+	}
+	if (err)
+		goto error2;
+
+	return 0;
+
+error2:
+	for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
+		if (NULL != mixer->amixers[i]) {
+			amixer = mixer->amixers[i];
+			amixer_mgr->put_amixer(amixer_mgr, amixer);
+			mixer->amixers[i] = NULL;
+		}
+	}
+error1:
+	for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
+		if (NULL != mixer->sums[i]) {
+			sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);
+			mixer->sums[i] = NULL;
+		}
+	}
+
+	return err;
+}
+
+static int ct_mixer_get_mem(struct ct_mixer **rmixer)
+{
+	struct ct_mixer *mixer;
+	int err;
+
+	*rmixer = NULL;
+	/* Allocate mem for mixer obj */
+	mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
+	if (NULL == mixer)
+		return -ENOMEM;
+
+	mixer->amixers = kzalloc(sizeof(void *)*(NUM_CT_AMIXERS*CHN_NUM),
+				 GFP_KERNEL);
+	if (NULL == mixer->amixers) {
+		err = -ENOMEM;
+		goto error1;
+	}
+	mixer->sums = kzalloc(sizeof(void *)*(NUM_CT_SUMS*CHN_NUM), GFP_KERNEL);
+	if (NULL == mixer->sums) {
+		err = -ENOMEM;
+		goto error2;
+	}
+
+	*rmixer = mixer;
+	return 0;
+
+error2:
+	kfree(mixer->amixers);
+error1:
+	kfree(mixer);
+	return err;
+}
+
+static int ct_mixer_topology_build(struct ct_mixer *mixer)
+{
+	struct sum *sum;
+	struct amixer *amix_d, *amix_s;
+	enum CT_AMIXER_CTL i, j;
+
+	/* Build topology from destination to source */
+
+	/* Set up Master mixer */
+	for (i = AMIXER_MASTER_F, j = SUM_IN_F;
+					i <= AMIXER_MASTER_S; i++, j++) {
+		amix_d = mixer->amixers[i*CHN_NUM];
+		sum = mixer->sums[j*CHN_NUM];
+		amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
+		amix_d = mixer->amixers[i*CHN_NUM+1];
+		sum = mixer->sums[j*CHN_NUM+1];
+		amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
+	}
+
+	/* Set up Wave-out mixer */
+	for (i = AMIXER_WAVE_F, j = AMIXER_MASTER_F;
+					i <= AMIXER_WAVE_S; i++, j++) {
+		amix_d = mixer->amixers[i*CHN_NUM];
+		amix_s = mixer->amixers[j*CHN_NUM];
+		amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
+		amix_d = mixer->amixers[i*CHN_NUM+1];
+		amix_s = mixer->amixers[j*CHN_NUM+1];
+		amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
+	}
+
+	/* Set up S/PDIF-out mixer */
+	amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM];
+	amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM];
+	amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
+	amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM+1];
+	amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM+1];
+	amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
+
+	/* Set up PCM-in mixer */
+	for (i = AMIXER_PCM_F, j = SUM_IN_F; i <= AMIXER_PCM_S; i++, j++) {
+		amix_d = mixer->amixers[i*CHN_NUM];
+		sum = mixer->sums[j*CHN_NUM];
+		amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+		amix_d = mixer->amixers[i*CHN_NUM+1];
+		sum = mixer->sums[j*CHN_NUM+1];
+		amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+	}
+
+	/* Set up Line-in mixer */
+	amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM];
+	sum = mixer->sums[SUM_IN_F*CHN_NUM];
+	amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+	amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM+1];
+	sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
+	amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+
+	/* Set up Mic-in mixer */
+	amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM];
+	sum = mixer->sums[SUM_IN_F*CHN_NUM];
+	amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+	amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM+1];
+	sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
+	amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+
+	/* Set up S/PDIF-in mixer */
+	amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM];
+	sum = mixer->sums[SUM_IN_F*CHN_NUM];
+	amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+	amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM+1];
+	sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
+	amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+
+	/* Set up Master recording mixer */
+	amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM];
+	sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
+	amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
+	amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM+1];
+	sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
+	amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
+
+	/* Set up PCM-in recording mixer */
+	amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM];
+	sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
+	amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+	amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM+1];
+	sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
+	amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+
+	/* Set up Line-in recording mixer */
+	amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM];
+	sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
+	amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+	amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM+1];
+	sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
+	amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+
+	/* Set up Mic-in recording mixer */
+	amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM];
+	sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
+	amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+	amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM+1];
+	sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
+	amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+
+	/* Set up S/PDIF-in recording mixer */
+	amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM];
+	sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
+	amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+	amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM+1];
+	sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
+	amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+
+	return 0;
+}
+
+static int mixer_set_input_port(struct amixer *amixer, struct rsc *rsc)
+{
+	amixer->ops->set_input(amixer, rsc);
+	amixer->ops->commit_write(amixer);
+
+	return 0;
+}
+
+static enum CT_AMIXER_CTL port_to_amixer(enum MIXER_PORT_T type)
+{
+	switch (type) {
+	case MIX_WAVE_FRONT:	return AMIXER_WAVE_F;
+	case MIX_WAVE_SURROUND:	return AMIXER_WAVE_S;
+	case MIX_WAVE_CENTLFE:	return AMIXER_WAVE_C;
+	case MIX_WAVE_REAR:	return AMIXER_WAVE_R;
+	case MIX_PCMO_FRONT:	return AMIXER_MASTER_F_C;
+	case MIX_SPDIF_OUT:	return AMIXER_SPDIFO;
+	case MIX_LINE_IN:	return AMIXER_LINEIN;
+	case MIX_MIC_IN:	return AMIXER_MIC;
+	case MIX_SPDIF_IN:	return AMIXER_SPDIFI;
+	case MIX_PCMI_FRONT:	return AMIXER_PCM_F;
+	case MIX_PCMI_SURROUND:	return AMIXER_PCM_S;
+	case MIX_PCMI_CENTLFE:	return AMIXER_PCM_C;
+	case MIX_PCMI_REAR:	return AMIXER_PCM_R;
+	default: 		return 0;
+	}
+}
+
+static int mixer_get_output_ports(struct ct_mixer *mixer,
+				  enum MIXER_PORT_T type,
+				  struct rsc **rleft, struct rsc **rright)
+{
+	enum CT_AMIXER_CTL amix = port_to_amixer(type);
+
+	if (NULL != rleft)
+		*rleft = &((struct amixer *)mixer->amixers[amix*CHN_NUM])->rsc;
+
+	if (NULL != rright)
+		*rright =
+			&((struct amixer *)mixer->amixers[amix*CHN_NUM+1])->rsc;
+
+	return 0;
+}
+
+static int mixer_set_input_left(struct ct_mixer *mixer,
+				enum MIXER_PORT_T type, struct rsc *rsc)
+{
+	enum CT_AMIXER_CTL amix = port_to_amixer(type);
+
+	mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);
+	amix = get_recording_amixer(amix);
+	if (amix < NUM_CT_AMIXERS)
+		mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);
+
+	return 0;
+}
+
+static int
+mixer_set_input_right(struct ct_mixer *mixer,
+		      enum MIXER_PORT_T type, struct rsc *rsc)
+{
+	enum CT_AMIXER_CTL amix = port_to_amixer(type);
+
+	mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);
+	amix = get_recording_amixer(amix);
+	if (amix < NUM_CT_AMIXERS)
+		mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);
+
+	return 0;
+}
+
+int ct_mixer_destroy(struct ct_mixer *mixer)
+{
+	struct sum_mgr *sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
+	struct amixer_mgr *amixer_mgr =
+			(struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];
+	struct amixer *amixer;
+	int i = 0;
+
+	/* Release amixer resources */
+	for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
+		if (NULL != mixer->amixers[i]) {
+			amixer = mixer->amixers[i];
+			amixer_mgr->put_amixer(amixer_mgr, amixer);
+		}
+	}
+
+	/* Release sum resources */
+	for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
+		if (NULL != mixer->sums[i])
+			sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);
+	}
+
+	/* Release mem assigned to mixer object */
+	kfree(mixer->sums);
+	kfree(mixer->amixers);
+	kfree(mixer);
+
+	return 0;
+}
+
+int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer)
+{
+	struct ct_mixer *mixer;
+	int err;
+
+	*rmixer = NULL;
+
+	/* Allocate mem for mixer obj */
+	err = ct_mixer_get_mem(&mixer);
+	if (err)
+		return err;
+
+	mixer->switch_state = 0;
+	mixer->atc = atc;
+	/* Set operations */
+	mixer->get_output_ports = mixer_get_output_ports;
+	mixer->set_input_left = mixer_set_input_left;
+	mixer->set_input_right = mixer_set_input_right;
+
+	/* Allocate chip resources for mixer obj */
+	err = ct_mixer_get_resources(mixer);
+	if (err)
+		goto error;
+
+	/* Build internal mixer topology */
+	ct_mixer_topology_build(mixer);
+
+	*rmixer = mixer;
+
+	return 0;
+
+error:
+	ct_mixer_destroy(mixer);
+	return err;
+}
+
+int ct_alsa_mix_create(struct ct_atc *atc,
+		       enum CTALSADEVS device,
+		       const char *device_name)
+{
+	int err;
+
+	/* Create snd kcontrol instances on demand */
+	/* vol_ctl.device = swh_ctl.device = device; */ /* better w/ device 0 */
+	err = ct_mixer_kcontrols_create((struct ct_mixer *)atc->mixer);
+	if (err)
+		return err;
+
+	strcpy(atc->card->mixername, device_name);
+
+	return 0;
+}
diff --git a/sound/pci/ctxfi/ctmixer.h b/sound/pci/ctxfi/ctmixer.h
new file mode 100644
index 0000000..e2d96eb
--- /dev/null
+++ b/sound/pci/ctxfi/ctmixer.h
@@ -0,0 +1,67 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctmixer.h
+ *
+ * @Brief
+ * This file contains the definition of the mixer device functions.
+ *
+ * @Author	Liu Chun
+ * @Date 	Mar 28 2008
+ *
+ */
+
+#ifndef CTMIXER_H
+#define CTMIXER_H
+
+#include "ctatc.h"
+#include "ctresource.h"
+
+#define INIT_VOL	0x1c00
+
+enum MIXER_PORT_T {
+	MIX_WAVE_FRONT,
+	MIX_WAVE_REAR,
+	MIX_WAVE_CENTLFE,
+	MIX_WAVE_SURROUND,
+	MIX_SPDIF_OUT,
+	MIX_PCMO_FRONT,
+	MIX_MIC_IN,
+	MIX_LINE_IN,
+	MIX_SPDIF_IN,
+	MIX_PCMI_FRONT,
+	MIX_PCMI_REAR,
+	MIX_PCMI_CENTLFE,
+	MIX_PCMI_SURROUND,
+
+	NUM_MIX_PORTS
+};
+
+/* alsa mixer descriptor */
+struct ct_mixer {
+	struct ct_atc *atc;
+
+	void **amixers;		/* amixer resources for volume control */
+	void **sums;		/* sum resources for signal collection */
+	unsigned int switch_state; /* A bit-map to indicate state of switches */
+
+	int (*get_output_ports)(struct ct_mixer *mixer, enum MIXER_PORT_T type,
+				  struct rsc **rleft, struct rsc **rright);
+
+	int (*set_input_left)(struct ct_mixer *mixer,
+			      enum MIXER_PORT_T type, struct rsc *rsc);
+	int (*set_input_right)(struct ct_mixer *mixer,
+			       enum MIXER_PORT_T type, struct rsc *rsc);
+};
+
+int ct_alsa_mix_create(struct ct_atc *atc,
+		       enum CTALSADEVS device,
+		       const char *device_name);
+int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer);
+int ct_mixer_destroy(struct ct_mixer *mixer);
+
+#endif /* CTMIXER_H */
diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c
new file mode 100644
index 0000000..9e5c0c4
--- /dev/null
+++ b/sound/pci/ctxfi/ctpcm.c
@@ -0,0 +1,426 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctpcm.c
+ *
+ * @Brief
+ * This file contains the definition of the pcm device functions.
+ *
+ * @Author	Liu Chun
+ * @Date 	Apr 2 2008
+ *
+ */
+
+#include "ctpcm.h"
+#include "cttimer.h"
+#include <sound/pcm.h>
+
+/* Hardware descriptions for playback */
+static struct snd_pcm_hardware ct_pcm_playback_hw = {
+	.info			= (SNDRV_PCM_INFO_MMAP |
+				   SNDRV_PCM_INFO_INTERLEAVED |
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				   SNDRV_PCM_INFO_MMAP_VALID |
+				   SNDRV_PCM_INFO_PAUSE),
+	.formats		= (SNDRV_PCM_FMTBIT_U8 |
+				   SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_3LE |
+				   SNDRV_PCM_FMTBIT_S32_LE |
+				   SNDRV_PCM_FMTBIT_FLOAT_LE),
+	.rates			= (SNDRV_PCM_RATE_CONTINUOUS |
+				   SNDRV_PCM_RATE_8000_192000),
+	.rate_min		= 8000,
+	.rate_max		= 192000,
+	.channels_min		= 1,
+	.channels_max		= 2,
+	.buffer_bytes_max	= (128*1024),
+	.period_bytes_min	= (64),
+	.period_bytes_max	= (128*1024),
+	.periods_min		= 2,
+	.periods_max		= 1024,
+	.fifo_size		= 0,
+};
+
+static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = {
+	.info			= (SNDRV_PCM_INFO_MMAP |
+				   SNDRV_PCM_INFO_INTERLEAVED |
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				   SNDRV_PCM_INFO_MMAP_VALID |
+				   SNDRV_PCM_INFO_PAUSE),
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.rates			= (SNDRV_PCM_RATE_48000 |
+				   SNDRV_PCM_RATE_44100 |
+				   SNDRV_PCM_RATE_32000),
+	.rate_min		= 32000,
+	.rate_max		= 48000,
+	.channels_min		= 2,
+	.channels_max		= 2,
+	.buffer_bytes_max	= (128*1024),
+	.period_bytes_min	= (64),
+	.period_bytes_max	= (128*1024),
+	.periods_min		= 2,
+	.periods_max		= 1024,
+	.fifo_size		= 0,
+};
+
+/* Hardware descriptions for capture */
+static struct snd_pcm_hardware ct_pcm_capture_hw = {
+	.info			= (SNDRV_PCM_INFO_MMAP |
+				   SNDRV_PCM_INFO_INTERLEAVED |
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				   SNDRV_PCM_INFO_PAUSE |
+				   SNDRV_PCM_INFO_MMAP_VALID),
+	.formats		= (SNDRV_PCM_FMTBIT_U8 |
+				   SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_3LE |
+				   SNDRV_PCM_FMTBIT_S32_LE |
+				   SNDRV_PCM_FMTBIT_FLOAT_LE),
+	.rates			= (SNDRV_PCM_RATE_CONTINUOUS |
+				   SNDRV_PCM_RATE_8000_96000),
+	.rate_min		= 8000,
+	.rate_max		= 96000,
+	.channels_min		= 1,
+	.channels_max		= 2,
+	.buffer_bytes_max	= (128*1024),
+	.period_bytes_min	= (384),
+	.period_bytes_max	= (64*1024),
+	.periods_min		= 2,
+	.periods_max		= 1024,
+	.fifo_size		= 0,
+};
+
+static void ct_atc_pcm_interrupt(struct ct_atc_pcm *atc_pcm)
+{
+	struct ct_atc_pcm *apcm = atc_pcm;
+
+	if (NULL == apcm->substream)
+		return;
+
+	snd_pcm_period_elapsed(apcm->substream);
+}
+
+static void ct_atc_pcm_free_substream(struct snd_pcm_runtime *runtime)
+{
+	struct ct_atc_pcm *apcm = runtime->private_data;
+	struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream);
+
+	atc->pcm_release_resources(atc, apcm);
+	ct_timer_instance_free(apcm->timer);
+	kfree(apcm);
+	runtime->private_data = NULL;
+}
+
+/* pcm playback operations */
+static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
+{
+	struct ct_atc *atc = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ct_atc_pcm *apcm;
+	int err;
+
+	apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
+	if (NULL == apcm)
+		return -ENOMEM;
+
+	apcm->substream = substream;
+	apcm->interrupt = ct_atc_pcm_interrupt;
+	runtime->private_data = apcm;
+	runtime->private_free = ct_atc_pcm_free_substream;
+	if (IEC958 == substream->pcm->device) {
+		runtime->hw = ct_spdif_passthru_playback_hw;
+		atc->spdif_out_passthru(atc, 1);
+	} else {
+		runtime->hw = ct_pcm_playback_hw;
+		if (FRONT == substream->pcm->device)
+			runtime->hw.channels_max = 8;
+	}
+
+	err = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (err < 0) {
+		kfree(apcm);
+		return err;
+	}
+	err = snd_pcm_hw_constraint_minmax(runtime,
+					   SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+					   1024, UINT_MAX);
+	if (err < 0) {
+		kfree(apcm);
+		return err;
+	}
+
+	apcm->timer = ct_timer_instance_new(atc->timer, apcm);
+	if (!apcm->timer)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int ct_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	struct ct_atc *atc = snd_pcm_substream_chip(substream);
+
+	/* TODO: Notify mixer inactive. */
+	if (IEC958 == substream->pcm->device)
+		atc->spdif_out_passthru(atc, 0);
+
+	/* The ct_atc_pcm object will be freed by runtime->private_free */
+
+	return 0;
+}
+
+static int ct_pcm_hw_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *hw_params)
+{
+	struct ct_atc *atc = snd_pcm_substream_chip(substream);
+	struct ct_atc_pcm *apcm = substream->runtime->private_data;
+	int err;
+
+	err = snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(hw_params));
+	if (err < 0)
+		return err;
+	/* clear previous resources */
+	atc->pcm_release_resources(atc, apcm);
+	return err;
+}
+
+static int ct_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct ct_atc *atc = snd_pcm_substream_chip(substream);
+	struct ct_atc_pcm *apcm = substream->runtime->private_data;
+
+	/* clear previous resources */
+	atc->pcm_release_resources(atc, apcm);
+	/* Free snd-allocated pages */
+	return snd_pcm_lib_free_pages(substream);
+}
+
+
+static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	int err;
+	struct ct_atc *atc = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ct_atc_pcm *apcm = runtime->private_data;
+
+	if (IEC958 == substream->pcm->device)
+		err = atc->spdif_passthru_playback_prepare(atc, apcm);
+	else
+		err = atc->pcm_playback_prepare(atc, apcm);
+
+	if (err < 0) {
+		printk(KERN_ERR "ctxfi: Preparing pcm playback failed!!!\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int
+ct_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct ct_atc *atc = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ct_atc_pcm *apcm = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		atc->pcm_playback_start(atc, apcm);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		atc->pcm_playback_stop(atc, apcm);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static snd_pcm_uframes_t
+ct_pcm_playback_pointer(struct snd_pcm_substream *substream)
+{
+	unsigned long position;
+	struct ct_atc *atc = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ct_atc_pcm *apcm = runtime->private_data;
+
+	/* Read out playback position */
+	position = atc->pcm_playback_position(atc, apcm);
+	position = bytes_to_frames(runtime, position);
+	if (position >= runtime->buffer_size)
+		position = 0;
+	return position;
+}
+
+/* pcm capture operations */
+static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
+{
+	struct ct_atc *atc = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ct_atc_pcm *apcm;
+	int err;
+
+	apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
+	if (NULL == apcm)
+		return -ENOMEM;
+
+	apcm->started = 0;
+	apcm->substream = substream;
+	apcm->interrupt = ct_atc_pcm_interrupt;
+	runtime->private_data = apcm;
+	runtime->private_free = ct_atc_pcm_free_substream;
+	runtime->hw = ct_pcm_capture_hw;
+	runtime->hw.rate_max = atc->rsr * atc->msr;
+
+	err = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (err < 0) {
+		kfree(apcm);
+		return err;
+	}
+	err = snd_pcm_hw_constraint_minmax(runtime,
+					   SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+					   1024, UINT_MAX);
+	if (err < 0) {
+		kfree(apcm);
+		return err;
+	}
+
+	apcm->timer = ct_timer_instance_new(atc->timer, apcm);
+	if (!apcm->timer)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int ct_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+	/* The ct_atc_pcm object will be freed by runtime->private_free */
+	/* TODO: Notify mixer inactive. */
+	return 0;
+}
+
+static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	int err;
+	struct ct_atc *atc = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ct_atc_pcm *apcm = runtime->private_data;
+
+	err = atc->pcm_capture_prepare(atc, apcm);
+	if (err < 0) {
+		printk(KERN_ERR "ctxfi: Preparing pcm capture failed!!!\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int
+ct_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct ct_atc *atc = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ct_atc_pcm *apcm = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		atc->pcm_capture_start(atc, apcm);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		atc->pcm_capture_stop(atc, apcm);
+		break;
+	default:
+		atc->pcm_capture_stop(atc, apcm);
+		break;
+	}
+
+	return 0;
+}
+
+static snd_pcm_uframes_t
+ct_pcm_capture_pointer(struct snd_pcm_substream *substream)
+{
+	unsigned long position;
+	struct ct_atc *atc = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ct_atc_pcm *apcm = runtime->private_data;
+
+	/* Read out playback position */
+	position = atc->pcm_capture_position(atc, apcm);
+	position = bytes_to_frames(runtime, position);
+	if (position >= runtime->buffer_size)
+		position = 0;
+	return position;
+}
+
+/* PCM operators for playback */
+static struct snd_pcm_ops ct_pcm_playback_ops = {
+	.open	 	= ct_pcm_playback_open,
+	.close		= ct_pcm_playback_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= ct_pcm_hw_params,
+	.hw_free	= ct_pcm_hw_free,
+	.prepare	= ct_pcm_playback_prepare,
+	.trigger	= ct_pcm_playback_trigger,
+	.pointer	= ct_pcm_playback_pointer,
+	.page		= snd_pcm_sgbuf_ops_page,
+};
+
+/* PCM operators for capture */
+static struct snd_pcm_ops ct_pcm_capture_ops = {
+	.open	 	= ct_pcm_capture_open,
+	.close		= ct_pcm_capture_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= ct_pcm_hw_params,
+	.hw_free	= ct_pcm_hw_free,
+	.prepare	= ct_pcm_capture_prepare,
+	.trigger	= ct_pcm_capture_trigger,
+	.pointer	= ct_pcm_capture_pointer,
+	.page		= snd_pcm_sgbuf_ops_page,
+};
+
+/* Create ALSA pcm device */
+int ct_alsa_pcm_create(struct ct_atc *atc,
+		       enum CTALSADEVS device,
+		       const char *device_name)
+{
+	struct snd_pcm *pcm;
+	int err;
+	int playback_count, capture_count;
+
+	playback_count = (IEC958 == device) ? 1 : 8;
+	capture_count = (FRONT == device) ? 1 : 0;
+	err = snd_pcm_new(atc->card, "ctxfi", device,
+			  playback_count, capture_count, &pcm);
+	if (err < 0) {
+		printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err);
+		return err;
+	}
+
+	pcm->private_data = atc;
+	pcm->info_flags = 0;
+	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
+	strlcpy(pcm->name, device_name, sizeof(pcm->name));
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops);
+
+	if (FRONT == device)
+		snd_pcm_set_ops(pcm,
+				SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops);
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+			snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
+
+	return 0;
+}
diff --git a/sound/pci/ctxfi/ctpcm.h b/sound/pci/ctxfi/ctpcm.h
new file mode 100644
index 0000000..178da0d
--- /dev/null
+++ b/sound/pci/ctxfi/ctpcm.h
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctpcm.h
+ *
+ * @Brief
+ * This file contains the definition of the pcm device functions.
+ *
+ * @Author	Liu Chun
+ * @Date 	Mar 28 2008
+ *
+ */
+
+#ifndef CTPCM_H
+#define CTPCM_H
+
+#include "ctatc.h"
+
+int ct_alsa_pcm_create(struct ct_atc *atc,
+		       enum CTALSADEVS device,
+		       const char *device_name);
+
+#endif /* CTPCM_H */
diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c
new file mode 100644
index 0000000..889c495
--- /dev/null
+++ b/sound/pci/ctxfi/ctresource.c
@@ -0,0 +1,301 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctresource.c
+ *
+ * @Brief
+ * This file contains the implementation of some generic helper functions.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 15 2008
+ *
+ */
+
+#include "ctresource.h"
+#include "cthardware.h"
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#define AUDIO_SLOT_BLOCK_NUM 	256
+
+/* Resource allocation based on bit-map management mechanism */
+static int
+get_resource(u8 *rscs, unsigned int amount,
+	     unsigned int multi, unsigned int *ridx)
+{
+	int i, j, k, n;
+
+	/* Check whether there are sufficient resources to meet request. */
+	for (i = 0, n = multi; i < amount; i++) {
+		j = i / 8;
+		k = i % 8;
+		if (rscs[j] & ((u8)1 << k)) {
+			n = multi;
+			continue;
+		}
+		if (!(--n))
+			break; /* found sufficient contiguous resources */
+	}
+
+	if (i >= amount) {
+		/* Can not find sufficient contiguous resources */
+		return -ENOENT;
+	}
+
+	/* Mark the contiguous bits in resource bit-map as used */
+	for (n = multi; n > 0; n--) {
+		j = i / 8;
+		k = i % 8;
+		rscs[j] |= ((u8)1 << k);
+		i--;
+	}
+
+	*ridx = i + 1;
+
+	return 0;
+}
+
+static int put_resource(u8 *rscs, unsigned int multi, unsigned int idx)
+{
+	unsigned int i, j, k, n;
+
+	/* Mark the contiguous bits in resource bit-map as used */
+	for (n = multi, i = idx; n > 0; n--) {
+		j = i / 8;
+		k = i % 8;
+		rscs[j] &= ~((u8)1 << k);
+		i++;
+	}
+
+	return 0;
+}
+
+int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx)
+{
+	int err;
+
+	if (n > mgr->avail)
+		return -ENOENT;
+
+	err = get_resource(mgr->rscs, mgr->amount, n, ridx);
+	if (!err)
+		mgr->avail -= n;
+
+	return err;
+}
+
+int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx)
+{
+	put_resource(mgr->rscs, n, idx);
+	mgr->avail += n;
+
+	return 0;
+}
+
+static unsigned char offset_in_audio_slot_block[NUM_RSCTYP] = {
+	/* SRC channel is at Audio Ring slot 1 every 16 slots. */
+	[SRC]		= 0x1,
+	[AMIXER]	= 0x4,
+	[SUM]		= 0xc,
+};
+
+static int rsc_index(const struct rsc *rsc)
+{
+    return rsc->conj;
+}
+
+static int audio_ring_slot(const struct rsc *rsc)
+{
+    return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type];
+}
+
+static int rsc_next_conj(struct rsc *rsc)
+{
+	unsigned int i;
+	for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); )
+		i++;
+	rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i);
+	return rsc->conj;
+}
+
+static int rsc_master(struct rsc *rsc)
+{
+	return rsc->conj = rsc->idx;
+}
+
+static struct rsc_ops rsc_generic_ops = {
+	.index		= rsc_index,
+	.output_slot	= audio_ring_slot,
+	.master		= rsc_master,
+	.next_conj	= rsc_next_conj,
+};
+
+int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw)
+{
+	int err = 0;
+
+	rsc->idx = idx;
+	rsc->conj = idx;
+	rsc->type = type;
+	rsc->msr = msr;
+	rsc->hw = hw;
+	rsc->ops = &rsc_generic_ops;
+	if (NULL == hw) {
+		rsc->ctrl_blk = NULL;
+		return 0;
+	}
+
+	switch (type) {
+	case SRC:
+		err = ((struct hw *)hw)->src_rsc_get_ctrl_blk(&rsc->ctrl_blk);
+		break;
+	case AMIXER:
+		err = ((struct hw *)hw)->
+				amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk);
+		break;
+	case SRCIMP:
+	case SUM:
+	case DAIO:
+		break;
+	default:
+		printk(KERN_ERR
+		       "ctxfi: Invalid resource type value %d!\n", type);
+		return -EINVAL;
+	}
+
+	if (err) {
+		printk(KERN_ERR
+		       "ctxfi: Failed to get resource control block!\n");
+		return err;
+	}
+
+	return 0;
+}
+
+int rsc_uninit(struct rsc *rsc)
+{
+	if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) {
+		switch (rsc->type) {
+		case SRC:
+			((struct hw *)rsc->hw)->
+				src_rsc_put_ctrl_blk(rsc->ctrl_blk);
+			break;
+		case AMIXER:
+			((struct hw *)rsc->hw)->
+				amixer_rsc_put_ctrl_blk(rsc->ctrl_blk);
+			break;
+		case SUM:
+		case DAIO:
+			break;
+		default:
+			printk(KERN_ERR "ctxfi: "
+			       "Invalid resource type value %d!\n", rsc->type);
+			break;
+		}
+
+		rsc->hw = rsc->ctrl_blk = NULL;
+	}
+
+	rsc->idx = rsc->conj = 0;
+	rsc->type = NUM_RSCTYP;
+	rsc->msr = 0;
+
+	return 0;
+}
+
+int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
+		 unsigned int amount, void *hw_obj)
+{
+	int err = 0;
+	struct hw *hw = hw_obj;
+
+	mgr->type = NUM_RSCTYP;
+
+	mgr->rscs = kzalloc(((amount + 8 - 1) / 8), GFP_KERNEL);
+	if (NULL == mgr->rscs)
+		return -ENOMEM;
+
+	switch (type) {
+	case SRC:
+		err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk);
+		break;
+	case SRCIMP:
+		err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk);
+		break;
+	case AMIXER:
+		err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk);
+		break;
+	case DAIO:
+		err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk);
+		break;
+	case SUM:
+		break;
+	default:
+		printk(KERN_ERR
+		       "ctxfi: Invalid resource type value %d!\n", type);
+		err = -EINVAL;
+		goto error;
+	}
+
+	if (err) {
+		printk(KERN_ERR
+		       "ctxfi: Failed to get manager control block!\n");
+		goto error;
+	}
+
+	mgr->type = type;
+	mgr->avail = mgr->amount = amount;
+	mgr->hw = hw;
+
+	return 0;
+
+error:
+	kfree(mgr->rscs);
+	return err;
+}
+
+int rsc_mgr_uninit(struct rsc_mgr *mgr)
+{
+	if (NULL != mgr->rscs) {
+		kfree(mgr->rscs);
+		mgr->rscs = NULL;
+	}
+
+	if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) {
+		switch (mgr->type) {
+		case SRC:
+			((struct hw *)mgr->hw)->
+				src_mgr_put_ctrl_blk(mgr->ctrl_blk);
+			break;
+		case SRCIMP:
+			((struct hw *)mgr->hw)->
+				srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk);
+			break;
+		case AMIXER:
+			((struct hw *)mgr->hw)->
+				amixer_mgr_put_ctrl_blk(mgr->ctrl_blk);
+			break;
+		case DAIO:
+			((struct hw *)mgr->hw)->
+				daio_mgr_put_ctrl_blk(mgr->ctrl_blk);
+			break;
+		case SUM:
+			break;
+		default:
+			printk(KERN_ERR "ctxfi: "
+			       "Invalid resource type value %d!\n", mgr->type);
+			break;
+		}
+
+		mgr->hw = mgr->ctrl_blk = NULL;
+	}
+
+	mgr->type = NUM_RSCTYP;
+	mgr->avail = mgr->amount = 0;
+
+	return 0;
+}
diff --git a/sound/pci/ctxfi/ctresource.h b/sound/pci/ctxfi/ctresource.h
new file mode 100644
index 0000000..0838c2e
--- /dev/null
+++ b/sound/pci/ctxfi/ctresource.h
@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctresource.h
+ *
+ * @Brief
+ * This file contains the definition of generic hardware resources for
+ * resource management.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 13 2008
+ *
+ */
+
+#ifndef CTRESOURCE_H
+#define CTRESOURCE_H
+
+#include <linux/types.h>
+
+enum RSCTYP {
+	SRC,
+	SRCIMP,
+	AMIXER,
+	SUM,
+	DAIO,
+	NUM_RSCTYP	/* This must be the last one and less than 16 */
+};
+
+struct rsc_ops;
+
+struct rsc {
+	u32 idx:12;	/* The index of a resource */
+	u32 type:4;	/* The type (RSCTYP) of a resource */
+	u32 conj:12;	/* Current conjugate index */
+	u32 msr:4;	/* The Master Sample Rate a resource working on */
+	void *ctrl_blk;	/* Chip specific control info block for a resource */
+	void *hw;	/* Chip specific object for hardware access means */
+	struct rsc_ops *ops;	/* Generic resource operations */
+};
+
+struct rsc_ops {
+	int (*master)(struct rsc *rsc);	/* Move to master resource */
+	int (*next_conj)(struct rsc *rsc); /* Move to next conjugate resource */
+	int (*index)(const struct rsc *rsc); /* Return the index of resource */
+	/* Return the output slot number */
+	int (*output_slot)(const struct rsc *rsc);
+};
+
+int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw);
+int rsc_uninit(struct rsc *rsc);
+
+struct rsc_mgr {
+	enum RSCTYP type; /* The type (RSCTYP) of resource to manage */
+	unsigned int amount; /* The total amount of a kind of resource */
+	unsigned int avail; /* The amount of currently available resources */
+	unsigned char *rscs; /* The bit-map for resource allocation */
+	void *ctrl_blk; /* Chip specific control info block */
+	void *hw; /* Chip specific object for hardware access */
+};
+
+/* Resource management is based on bit-map mechanism */
+int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
+		 unsigned int amount, void *hw);
+int rsc_mgr_uninit(struct rsc_mgr *mgr);
+int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx);
+int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx);
+
+#endif /* CTRESOURCE_H */
diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c
new file mode 100644
index 0000000..e1c145d
--- /dev/null
+++ b/sound/pci/ctxfi/ctsrc.c
@@ -0,0 +1,886 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctsrc.c
+ *
+ * @Brief
+ * This file contains the implementation of the Sample Rate Convertor
+ * resource management object.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 13 2008
+ *
+ */
+
+#include "ctsrc.h"
+#include "cthardware.h"
+#include <linux/slab.h>
+
+#define SRC_RESOURCE_NUM	64
+#define SRCIMP_RESOURCE_NUM	256
+
+static unsigned int conj_mask;
+
+static int src_default_config_memrd(struct src *src);
+static int src_default_config_memwr(struct src *src);
+static int src_default_config_arcrw(struct src *src);
+
+static int (*src_default_config[3])(struct src *) = {
+	[MEMRD] = src_default_config_memrd,
+	[MEMWR] = src_default_config_memwr,
+	[ARCRW] = src_default_config_arcrw
+};
+
+static int src_set_state(struct src *src, unsigned int state)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	hw->src_set_state(src->rsc.ctrl_blk, state);
+
+	return 0;
+}
+
+static int src_set_bm(struct src *src, unsigned int bm)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	hw->src_set_bm(src->rsc.ctrl_blk, bm);
+
+	return 0;
+}
+
+static int src_set_sf(struct src *src, unsigned int sf)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	hw->src_set_sf(src->rsc.ctrl_blk, sf);
+
+	return 0;
+}
+
+static int src_set_pm(struct src *src, unsigned int pm)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	hw->src_set_pm(src->rsc.ctrl_blk, pm);
+
+	return 0;
+}
+
+static int src_set_rom(struct src *src, unsigned int rom)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	hw->src_set_rom(src->rsc.ctrl_blk, rom);
+
+	return 0;
+}
+
+static int src_set_vo(struct src *src, unsigned int vo)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	hw->src_set_vo(src->rsc.ctrl_blk, vo);
+
+	return 0;
+}
+
+static int src_set_st(struct src *src, unsigned int st)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	hw->src_set_st(src->rsc.ctrl_blk, st);
+
+	return 0;
+}
+
+static int src_set_bp(struct src *src, unsigned int bp)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	hw->src_set_bp(src->rsc.ctrl_blk, bp);
+
+	return 0;
+}
+
+static int src_set_cisz(struct src *src, unsigned int cisz)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	hw->src_set_cisz(src->rsc.ctrl_blk, cisz);
+
+	return 0;
+}
+
+static int src_set_ca(struct src *src, unsigned int ca)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	hw->src_set_ca(src->rsc.ctrl_blk, ca);
+
+	return 0;
+}
+
+static int src_set_sa(struct src *src, unsigned int sa)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	hw->src_set_sa(src->rsc.ctrl_blk, sa);
+
+	return 0;
+}
+
+static int src_set_la(struct src *src, unsigned int la)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	hw->src_set_la(src->rsc.ctrl_blk, la);
+
+	return 0;
+}
+
+static int src_set_pitch(struct src *src, unsigned int pitch)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	hw->src_set_pitch(src->rsc.ctrl_blk, pitch);
+
+	return 0;
+}
+
+static int src_set_clear_zbufs(struct src *src)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1);
+
+	return 0;
+}
+
+static int src_commit_write(struct src *src)
+{
+	struct hw *hw;
+	int i;
+	unsigned int dirty = 0;
+
+	hw = src->rsc.hw;
+	src->rsc.ops->master(&src->rsc);
+	if (src->rsc.msr > 1) {
+		/* Save dirty flags for conjugate resource programming */
+		dirty = hw->src_get_dirty(src->rsc.ctrl_blk) & conj_mask;
+	}
+	hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
+						src->rsc.ctrl_blk);
+
+	/* Program conjugate parameter mixer resources */
+	if (MEMWR == src->mode)
+		return 0;
+
+	for (i = 1; i < src->rsc.msr; i++) {
+		src->rsc.ops->next_conj(&src->rsc);
+		hw->src_set_dirty(src->rsc.ctrl_blk, dirty);
+		hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
+							src->rsc.ctrl_blk);
+	}
+	src->rsc.ops->master(&src->rsc);
+
+	return 0;
+}
+
+static int src_get_ca(struct src *src)
+{
+	struct hw *hw;
+
+	hw = src->rsc.hw;
+	return hw->src_get_ca(hw, src->rsc.ops->index(&src->rsc),
+						src->rsc.ctrl_blk);
+}
+
+static int src_init(struct src *src)
+{
+	src_default_config[src->mode](src);
+
+	return 0;
+}
+
+static struct src *src_next_interleave(struct src *src)
+{
+	return src->intlv;
+}
+
+static int src_default_config_memrd(struct src *src)
+{
+	struct hw *hw = src->rsc.hw;
+	unsigned int rsr, msr;
+
+	hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF);
+	hw->src_set_bm(src->rsc.ctrl_blk, 1);
+	for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1)
+		rsr++;
+
+	hw->src_set_rsr(src->rsc.ctrl_blk, rsr);
+	hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16);
+	hw->src_set_wr(src->rsc.ctrl_blk, 0);
+	hw->src_set_pm(src->rsc.ctrl_blk, 0);
+	hw->src_set_rom(src->rsc.ctrl_blk, 0);
+	hw->src_set_vo(src->rsc.ctrl_blk, 0);
+	hw->src_set_st(src->rsc.ctrl_blk, 0);
+	hw->src_set_ilsz(src->rsc.ctrl_blk, src->multi - 1);
+	hw->src_set_cisz(src->rsc.ctrl_blk, 0x80);
+	hw->src_set_sa(src->rsc.ctrl_blk, 0x0);
+	hw->src_set_la(src->rsc.ctrl_blk, 0x1000);
+	hw->src_set_ca(src->rsc.ctrl_blk, 0x80);
+	hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000);
+	hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1);
+
+	src->rsc.ops->master(&src->rsc);
+	hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
+						src->rsc.ctrl_blk);
+
+	for (msr = 1; msr < src->rsc.msr; msr++) {
+		src->rsc.ops->next_conj(&src->rsc);
+		hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000);
+		hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
+							src->rsc.ctrl_blk);
+	}
+	src->rsc.ops->master(&src->rsc);
+
+	return 0;
+}
+
+static int src_default_config_memwr(struct src *src)
+{
+	struct hw *hw = src->rsc.hw;
+
+	hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF);
+	hw->src_set_bm(src->rsc.ctrl_blk, 1);
+	hw->src_set_rsr(src->rsc.ctrl_blk, 0);
+	hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16);
+	hw->src_set_wr(src->rsc.ctrl_blk, 1);
+	hw->src_set_pm(src->rsc.ctrl_blk, 0);
+	hw->src_set_rom(src->rsc.ctrl_blk, 0);
+	hw->src_set_vo(src->rsc.ctrl_blk, 0);
+	hw->src_set_st(src->rsc.ctrl_blk, 0);
+	hw->src_set_ilsz(src->rsc.ctrl_blk, 0);
+	hw->src_set_cisz(src->rsc.ctrl_blk, 0x80);
+	hw->src_set_sa(src->rsc.ctrl_blk, 0x0);
+	hw->src_set_la(src->rsc.ctrl_blk, 0x1000);
+	hw->src_set_ca(src->rsc.ctrl_blk, 0x80);
+	hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000);
+	hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1);
+
+	src->rsc.ops->master(&src->rsc);
+	hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
+						src->rsc.ctrl_blk);
+
+	return 0;
+}
+
+static int src_default_config_arcrw(struct src *src)
+{
+	struct hw *hw = src->rsc.hw;
+	unsigned int rsr, msr;
+	unsigned int dirty;
+
+	hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF);
+	hw->src_set_bm(src->rsc.ctrl_blk, 0);
+	for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1)
+		rsr++;
+
+	hw->src_set_rsr(src->rsc.ctrl_blk, rsr);
+	hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_F32);
+	hw->src_set_wr(src->rsc.ctrl_blk, 0);
+	hw->src_set_pm(src->rsc.ctrl_blk, 0);
+	hw->src_set_rom(src->rsc.ctrl_blk, 0);
+	hw->src_set_vo(src->rsc.ctrl_blk, 0);
+	hw->src_set_st(src->rsc.ctrl_blk, 0);
+	hw->src_set_ilsz(src->rsc.ctrl_blk, 0);
+	hw->src_set_cisz(src->rsc.ctrl_blk, 0x80);
+	hw->src_set_sa(src->rsc.ctrl_blk, 0x0);
+	/*hw->src_set_sa(src->rsc.ctrl_blk, 0x100);*/
+	hw->src_set_la(src->rsc.ctrl_blk, 0x1000);
+	/*hw->src_set_la(src->rsc.ctrl_blk, 0x03ffffe0);*/
+	hw->src_set_ca(src->rsc.ctrl_blk, 0x80);
+	hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000);
+	hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1);
+
+	dirty = hw->src_get_dirty(src->rsc.ctrl_blk);
+	src->rsc.ops->master(&src->rsc);
+	for (msr = 0; msr < src->rsc.msr; msr++) {
+		hw->src_set_dirty(src->rsc.ctrl_blk, dirty);
+		hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
+							src->rsc.ctrl_blk);
+		src->rsc.ops->next_conj(&src->rsc);
+	}
+	src->rsc.ops->master(&src->rsc);
+
+	return 0;
+}
+
+static struct src_rsc_ops src_rsc_ops = {
+	.set_state		= src_set_state,
+	.set_bm			= src_set_bm,
+	.set_sf			= src_set_sf,
+	.set_pm			= src_set_pm,
+	.set_rom		= src_set_rom,
+	.set_vo			= src_set_vo,
+	.set_st			= src_set_st,
+	.set_bp			= src_set_bp,
+	.set_cisz		= src_set_cisz,
+	.set_ca			= src_set_ca,
+	.set_sa			= src_set_sa,
+	.set_la			= src_set_la,
+	.set_pitch		= src_set_pitch,
+	.set_clr_zbufs		= src_set_clear_zbufs,
+	.commit_write		= src_commit_write,
+	.get_ca			= src_get_ca,
+	.init			= src_init,
+	.next_interleave	= src_next_interleave,
+};
+
+static int
+src_rsc_init(struct src *src, u32 idx,
+	     const struct src_desc *desc, struct src_mgr *mgr)
+{
+	int err;
+	int i, n;
+	struct src *p;
+
+	n = (MEMRD == desc->mode) ? desc->multi : 1;
+	for (i = 0, p = src; i < n; i++, p++) {
+		err = rsc_init(&p->rsc, idx + i, SRC, desc->msr, mgr->mgr.hw);
+		if (err)
+			goto error1;
+
+		/* Initialize src specific rsc operations */
+		p->ops = &src_rsc_ops;
+		p->multi = (0 == i) ? desc->multi : 1;
+		p->mode = desc->mode;
+		src_default_config[desc->mode](p);
+		mgr->src_enable(mgr, p);
+		p->intlv = p + 1;
+	}
+	(--p)->intlv = NULL;	/* Set @intlv of the last SRC to NULL */
+
+	mgr->commit_write(mgr);
+
+	return 0;
+
+error1:
+	for (i--, p--; i >= 0; i--, p--) {
+		mgr->src_disable(mgr, p);
+		rsc_uninit(&p->rsc);
+	}
+	mgr->commit_write(mgr);
+	return err;
+}
+
+static int src_rsc_uninit(struct src *src, struct src_mgr *mgr)
+{
+	int i, n;
+	struct src *p;
+
+	n = (MEMRD == src->mode) ? src->multi : 1;
+	for (i = 0, p = src; i < n; i++, p++) {
+		mgr->src_disable(mgr, p);
+		rsc_uninit(&p->rsc);
+		p->multi = 0;
+		p->ops = NULL;
+		p->mode = NUM_SRCMODES;
+		p->intlv = NULL;
+	}
+	mgr->commit_write(mgr);
+
+	return 0;
+}
+
+static int
+get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc)
+{
+	unsigned int idx = SRC_RESOURCE_NUM;
+	int err;
+	struct src *src;
+	unsigned long flags;
+
+	*rsrc = NULL;
+
+	/* Check whether there are sufficient src resources to meet request. */
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	if (MEMRD == desc->mode)
+		err = mgr_get_resource(&mgr->mgr, desc->multi, &idx);
+	else
+		err = mgr_get_resource(&mgr->mgr, 1, &idx);
+
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+	if (err) {
+		printk(KERN_ERR "ctxfi: Can't meet SRC resource request!\n");
+		return err;
+	}
+
+	/* Allocate mem for master src resource */
+	if (MEMRD == desc->mode)
+		src = kzalloc(sizeof(*src)*desc->multi, GFP_KERNEL);
+	else
+		src = kzalloc(sizeof(*src), GFP_KERNEL);
+
+	if (NULL == src) {
+		err = -ENOMEM;
+		goto error1;
+	}
+
+	err = src_rsc_init(src, idx, desc, mgr);
+	if (err)
+		goto error2;
+
+	*rsrc = src;
+
+	return 0;
+
+error2:
+	kfree(src);
+error1:
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	if (MEMRD == desc->mode)
+		mgr_put_resource(&mgr->mgr, desc->multi, idx);
+	else
+		mgr_put_resource(&mgr->mgr, 1, idx);
+
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+	return err;
+}
+
+static int put_src_rsc(struct src_mgr *mgr, struct src *src)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	src->rsc.ops->master(&src->rsc);
+	if (MEMRD == src->mode)
+		mgr_put_resource(&mgr->mgr, src->multi,
+				 src->rsc.ops->index(&src->rsc));
+	else
+		mgr_put_resource(&mgr->mgr, 1, src->rsc.ops->index(&src->rsc));
+
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+	src_rsc_uninit(src, mgr);
+	kfree(src);
+
+	return 0;
+}
+
+static int src_enable_s(struct src_mgr *mgr, struct src *src)
+{
+	struct hw *hw = mgr->mgr.hw;
+	int i;
+
+	src->rsc.ops->master(&src->rsc);
+	for (i = 0; i < src->rsc.msr; i++) {
+		hw->src_mgr_enbs_src(mgr->mgr.ctrl_blk,
+				     src->rsc.ops->index(&src->rsc));
+		src->rsc.ops->next_conj(&src->rsc);
+	}
+	src->rsc.ops->master(&src->rsc);
+
+	return 0;
+}
+
+static int src_enable(struct src_mgr *mgr, struct src *src)
+{
+	struct hw *hw = mgr->mgr.hw;
+	int i;
+
+	src->rsc.ops->master(&src->rsc);
+	for (i = 0; i < src->rsc.msr; i++) {
+		hw->src_mgr_enb_src(mgr->mgr.ctrl_blk,
+				    src->rsc.ops->index(&src->rsc));
+		src->rsc.ops->next_conj(&src->rsc);
+	}
+	src->rsc.ops->master(&src->rsc);
+
+	return 0;
+}
+
+static int src_disable(struct src_mgr *mgr, struct src *src)
+{
+	struct hw *hw = mgr->mgr.hw;
+	int i;
+
+	src->rsc.ops->master(&src->rsc);
+	for (i = 0; i < src->rsc.msr; i++) {
+		hw->src_mgr_dsb_src(mgr->mgr.ctrl_blk,
+				    src->rsc.ops->index(&src->rsc));
+		src->rsc.ops->next_conj(&src->rsc);
+	}
+	src->rsc.ops->master(&src->rsc);
+
+	return 0;
+}
+
+static int src_mgr_commit_write(struct src_mgr *mgr)
+{
+	struct hw *hw = mgr->mgr.hw;
+
+	hw->src_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
+
+	return 0;
+}
+
+int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr)
+{
+	int err, i;
+	struct src_mgr *src_mgr;
+
+	*rsrc_mgr = NULL;
+	src_mgr = kzalloc(sizeof(*src_mgr), GFP_KERNEL);
+	if (NULL == src_mgr)
+		return -ENOMEM;
+
+	err = rsc_mgr_init(&src_mgr->mgr, SRC, SRC_RESOURCE_NUM, hw);
+	if (err)
+		goto error1;
+
+	spin_lock_init(&src_mgr->mgr_lock);
+	conj_mask = ((struct hw *)hw)->src_dirty_conj_mask();
+
+	src_mgr->get_src = get_src_rsc;
+	src_mgr->put_src = put_src_rsc;
+	src_mgr->src_enable_s = src_enable_s;
+	src_mgr->src_enable = src_enable;
+	src_mgr->src_disable = src_disable;
+	src_mgr->commit_write = src_mgr_commit_write;
+
+	/* Disable all SRC resources. */
+	for (i = 0; i < 256; i++)
+		((struct hw *)hw)->src_mgr_dsb_src(src_mgr->mgr.ctrl_blk, i);
+
+	((struct hw *)hw)->src_mgr_commit_write(hw, src_mgr->mgr.ctrl_blk);
+
+	*rsrc_mgr = src_mgr;
+
+	return 0;
+
+error1:
+	kfree(src_mgr);
+	return err;
+}
+
+int src_mgr_destroy(struct src_mgr *src_mgr)
+{
+	rsc_mgr_uninit(&src_mgr->mgr);
+	kfree(src_mgr);
+
+	return 0;
+}
+
+/* SRCIMP resource manager operations */
+
+static int srcimp_master(struct rsc *rsc)
+{
+	rsc->conj = 0;
+	return rsc->idx = container_of(rsc, struct srcimp, rsc)->idx[0];
+}
+
+static int srcimp_next_conj(struct rsc *rsc)
+{
+	rsc->conj++;
+	return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj];
+}
+
+static int srcimp_index(const struct rsc *rsc)
+{
+	return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj];
+}
+
+static struct rsc_ops srcimp_basic_rsc_ops = {
+	.master		= srcimp_master,
+	.next_conj	= srcimp_next_conj,
+	.index		= srcimp_index,
+	.output_slot	= NULL,
+};
+
+static int srcimp_map(struct srcimp *srcimp, struct src *src, struct rsc *input)
+{
+	struct imapper *entry;
+	int i;
+
+	srcimp->rsc.ops->master(&srcimp->rsc);
+	src->rsc.ops->master(&src->rsc);
+	input->ops->master(input);
+
+	/* Program master and conjugate resources */
+	for (i = 0; i < srcimp->rsc.msr; i++) {
+		entry = &srcimp->imappers[i];
+		entry->slot = input->ops->output_slot(input);
+		entry->user = src->rsc.ops->index(&src->rsc);
+		entry->addr = srcimp->rsc.ops->index(&srcimp->rsc);
+		srcimp->mgr->imap_add(srcimp->mgr, entry);
+		srcimp->mapped |= (0x1 << i);
+
+		srcimp->rsc.ops->next_conj(&srcimp->rsc);
+		input->ops->next_conj(input);
+	}
+
+	srcimp->rsc.ops->master(&srcimp->rsc);
+	input->ops->master(input);
+
+	return 0;
+}
+
+static int srcimp_unmap(struct srcimp *srcimp)
+{
+	int i;
+
+	/* Program master and conjugate resources */
+	for (i = 0; i < srcimp->rsc.msr; i++) {
+		if (srcimp->mapped & (0x1 << i)) {
+			srcimp->mgr->imap_delete(srcimp->mgr,
+						 &srcimp->imappers[i]);
+			srcimp->mapped &= ~(0x1 << i);
+		}
+	}
+
+	return 0;
+}
+
+static struct srcimp_rsc_ops srcimp_ops = {
+	.map = srcimp_map,
+	.unmap = srcimp_unmap
+};
+
+static int srcimp_rsc_init(struct srcimp *srcimp,
+			   const struct srcimp_desc *desc,
+			   struct srcimp_mgr *mgr)
+{
+	int err;
+
+	err = rsc_init(&srcimp->rsc, srcimp->idx[0],
+		       SRCIMP, desc->msr, mgr->mgr.hw);
+	if (err)
+		return err;
+
+	/* Reserve memory for imapper nodes */
+	srcimp->imappers = kzalloc(sizeof(struct imapper)*desc->msr,
+				   GFP_KERNEL);
+	if (NULL == srcimp->imappers) {
+		err = -ENOMEM;
+		goto error1;
+	}
+
+	/* Set srcimp specific operations */
+	srcimp->rsc.ops = &srcimp_basic_rsc_ops;
+	srcimp->ops = &srcimp_ops;
+	srcimp->mgr = mgr;
+
+	srcimp->rsc.ops->master(&srcimp->rsc);
+
+	return 0;
+
+error1:
+	rsc_uninit(&srcimp->rsc);
+	return err;
+}
+
+static int srcimp_rsc_uninit(struct srcimp *srcimp)
+{
+	if (NULL != srcimp->imappers) {
+		kfree(srcimp->imappers);
+		srcimp->imappers = NULL;
+	}
+	srcimp->ops = NULL;
+	srcimp->mgr = NULL;
+	rsc_uninit(&srcimp->rsc);
+
+	return 0;
+}
+
+static int get_srcimp_rsc(struct srcimp_mgr *mgr,
+			  const struct srcimp_desc *desc,
+			  struct srcimp **rsrcimp)
+{
+	int err, i;
+	unsigned int idx;
+	struct srcimp *srcimp;
+	unsigned long flags;
+
+	*rsrcimp = NULL;
+
+	/* Allocate mem for SRCIMP resource */
+	srcimp = kzalloc(sizeof(*srcimp), GFP_KERNEL);
+	if (NULL == srcimp) {
+		err = -ENOMEM;
+		return err;
+	}
+
+	/* Check whether there are sufficient SRCIMP resources. */
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	for (i = 0; i < desc->msr; i++) {
+		err = mgr_get_resource(&mgr->mgr, 1, &idx);
+		if (err)
+			break;
+
+		srcimp->idx[i] = idx;
+	}
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+	if (err) {
+		printk(KERN_ERR "ctxfi: Can't meet SRCIMP resource request!\n");
+		goto error1;
+	}
+
+	err = srcimp_rsc_init(srcimp, desc, mgr);
+	if (err)
+		goto error1;
+
+	*rsrcimp = srcimp;
+
+	return 0;
+
+error1:
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	for (i--; i >= 0; i--)
+		mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]);
+
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+	kfree(srcimp);
+	return err;
+}
+
+static int put_srcimp_rsc(struct srcimp_mgr *mgr, struct srcimp *srcimp)
+{
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&mgr->mgr_lock, flags);
+	for (i = 0; i < srcimp->rsc.msr; i++)
+		mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]);
+
+	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+	srcimp_rsc_uninit(srcimp);
+	kfree(srcimp);
+
+	return 0;
+}
+
+static int srcimp_map_op(void *data, struct imapper *entry)
+{
+	struct rsc_mgr *mgr = &((struct srcimp_mgr *)data)->mgr;
+	struct hw *hw = mgr->hw;
+
+	hw->srcimp_mgr_set_imaparc(mgr->ctrl_blk, entry->slot);
+	hw->srcimp_mgr_set_imapuser(mgr->ctrl_blk, entry->user);
+	hw->srcimp_mgr_set_imapnxt(mgr->ctrl_blk, entry->next);
+	hw->srcimp_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr);
+	hw->srcimp_mgr_commit_write(mgr->hw, mgr->ctrl_blk);
+
+	return 0;
+}
+
+static int srcimp_imap_add(struct srcimp_mgr *mgr, struct imapper *entry)
+{
+	unsigned long flags;
+	int err;
+
+	spin_lock_irqsave(&mgr->imap_lock, flags);
+	if ((0 == entry->addr) && (mgr->init_imap_added)) {
+		input_mapper_delete(&mgr->imappers,
+				    mgr->init_imap, srcimp_map_op, mgr);
+		mgr->init_imap_added = 0;
+	}
+	err = input_mapper_add(&mgr->imappers, entry, srcimp_map_op, mgr);
+	spin_unlock_irqrestore(&mgr->imap_lock, flags);
+
+	return err;
+}
+
+static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry)
+{
+	unsigned long flags;
+	int err;
+
+	spin_lock_irqsave(&mgr->imap_lock, flags);
+	err = input_mapper_delete(&mgr->imappers, entry, srcimp_map_op, mgr);
+	if (list_empty(&mgr->imappers)) {
+		input_mapper_add(&mgr->imappers, mgr->init_imap,
+				 srcimp_map_op, mgr);
+		mgr->init_imap_added = 1;
+	}
+	spin_unlock_irqrestore(&mgr->imap_lock, flags);
+
+	return err;
+}
+
+int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrcimp_mgr)
+{
+	int err;
+	struct srcimp_mgr *srcimp_mgr;
+	struct imapper *entry;
+
+	*rsrcimp_mgr = NULL;
+	srcimp_mgr = kzalloc(sizeof(*srcimp_mgr), GFP_KERNEL);
+	if (NULL == srcimp_mgr)
+		return -ENOMEM;
+
+	err = rsc_mgr_init(&srcimp_mgr->mgr, SRCIMP, SRCIMP_RESOURCE_NUM, hw);
+	if (err)
+		goto error1;
+
+	spin_lock_init(&srcimp_mgr->mgr_lock);
+	spin_lock_init(&srcimp_mgr->imap_lock);
+	INIT_LIST_HEAD(&srcimp_mgr->imappers);
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (NULL == entry) {
+		err = -ENOMEM;
+		goto error2;
+	}
+	entry->slot = entry->addr = entry->next = entry->user = 0;
+	list_add(&entry->list, &srcimp_mgr->imappers);
+	srcimp_mgr->init_imap = entry;
+	srcimp_mgr->init_imap_added = 1;
+
+	srcimp_mgr->get_srcimp = get_srcimp_rsc;
+	srcimp_mgr->put_srcimp = put_srcimp_rsc;
+	srcimp_mgr->imap_add = srcimp_imap_add;
+	srcimp_mgr->imap_delete = srcimp_imap_delete;
+
+	*rsrcimp_mgr = srcimp_mgr;
+
+	return 0;
+
+error2:
+	rsc_mgr_uninit(&srcimp_mgr->mgr);
+error1:
+	kfree(srcimp_mgr);
+	return err;
+}
+
+int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr)
+{
+	unsigned long flags;
+
+	/* free src input mapper list */
+	spin_lock_irqsave(&srcimp_mgr->imap_lock, flags);
+	free_input_mapper_list(&srcimp_mgr->imappers);
+	spin_unlock_irqrestore(&srcimp_mgr->imap_lock, flags);
+
+	rsc_mgr_uninit(&srcimp_mgr->mgr);
+	kfree(srcimp_mgr);
+
+	return 0;
+}
diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h
new file mode 100644
index 0000000..259366a
--- /dev/null
+++ b/sound/pci/ctxfi/ctsrc.h
@@ -0,0 +1,149 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File	ctsrc.h
+ *
+ * @Brief
+ * This file contains the definition of the Sample Rate Convertor
+ * resource management object.
+ *
+ * @Author	Liu Chun
+ * @Date 	May 13 2008
+ *
+ */
+
+#ifndef CTSRC_H
+#define CTSRC_H
+
+#include "ctresource.h"
+#include "ctimap.h"
+#include <linux/spinlock.h>
+#include <linux/list.h>
+
+#define SRC_STATE_OFF	0x0
+#define SRC_STATE_INIT	0x4
+#define SRC_STATE_RUN	0x5
+
+#define SRC_SF_U8	0x0
+#define SRC_SF_S16	0x1
+#define SRC_SF_S24	0x2
+#define SRC_SF_S32	0x3
+#define SRC_SF_F32	0x4
+
+/* Define the descriptor of a src resource */
+enum SRCMODE {
+	MEMRD,		/* Read data from host memory */
+	MEMWR,		/* Write data to host memory */
+	ARCRW,		/* Read from and write to audio ring channel */
+	NUM_SRCMODES
+};
+
+struct src_rsc_ops;
+
+struct src {
+	struct rsc rsc; /* Basic resource info */
+	struct src *intlv; /* Pointer to next interleaved SRC in a series */
+	struct src_rsc_ops *ops; /* SRC specific operations */
+	/* Number of contiguous srcs for interleaved usage */
+	unsigned char multi;
+	unsigned char mode; /* Working mode of this SRC resource */
+};
+
+struct src_rsc_ops {
+	int (*set_state)(struct src *src, unsigned int state);
+	int (*set_bm)(struct src *src, unsigned int bm);
+	int (*set_sf)(struct src *src, unsigned int sf);
+	int (*set_pm)(struct src *src, unsigned int pm);
+	int (*set_rom)(struct src *src, unsigned int rom);
+	int (*set_vo)(struct src *src, unsigned int vo);
+	int (*set_st)(struct src *src, unsigned int st);
+	int (*set_bp)(struct src *src, unsigned int bp);
+	int (*set_cisz)(struct src *src, unsigned int cisz);
+	int (*set_ca)(struct src *src, unsigned int ca);
+	int (*set_sa)(struct src *src, unsigned int sa);
+	int (*set_la)(struct src *src, unsigned int la);
+	int (*set_pitch)(struct src *src, unsigned int pitch);
+	int (*set_clr_zbufs)(struct src *src);
+	int (*commit_write)(struct src *src);
+	int (*get_ca)(struct src *src);
+	int (*init)(struct src *src);
+	struct src* (*next_interleave)(struct src *src);
+};
+
+/* Define src resource request description info */
+struct src_desc {
+	/* Number of contiguous master srcs for interleaved usage */
+	unsigned char multi;
+	unsigned char msr;
+	unsigned char mode; /* Working mode of the requested srcs */
+};
+
+/* Define src manager object */
+struct src_mgr {
+	struct rsc_mgr mgr;	/* Basic resource manager info */
+	spinlock_t mgr_lock;
+
+	 /* request src resource */
+	int (*get_src)(struct src_mgr *mgr,
+		       const struct src_desc *desc, struct src **rsrc);
+	/* return src resource */
+	int (*put_src)(struct src_mgr *mgr, struct src *src);
+	int (*src_enable_s)(struct src_mgr *mgr, struct src *src);
+	int (*src_enable)(struct src_mgr *mgr, struct src *src);
+	int (*src_disable)(struct src_mgr *mgr, struct src *src);
+	int (*commit_write)(struct src_mgr *mgr);
+};
+
+/* Define the descriptor of a SRC Input Mapper resource */
+struct srcimp_mgr;
+struct srcimp_rsc_ops;
+
+struct srcimp {
+	struct rsc rsc;
+	unsigned char idx[8];
+	struct imapper *imappers;
+	unsigned int mapped; /* A bit-map indicating which conj rsc is mapped */
+	struct srcimp_mgr *mgr;
+	struct srcimp_rsc_ops *ops;
+};
+
+struct srcimp_rsc_ops {
+	int (*map)(struct srcimp *srcimp, struct src *user, struct rsc *input);
+	int (*unmap)(struct srcimp *srcimp);
+};
+
+/* Define SRCIMP resource request description info */
+struct srcimp_desc {
+	unsigned int msr;
+};
+
+struct srcimp_mgr {
+	struct rsc_mgr mgr;	/* Basic resource manager info */
+	spinlock_t mgr_lock;
+	spinlock_t imap_lock;
+	struct list_head imappers;
+	struct imapper *init_imap;
+	unsigned int init_imap_added;
+
+	 /* request srcimp resource */
+	int (*get_srcimp)(struct srcimp_mgr *mgr,
+			  const struct srcimp_desc *desc,
+			  struct srcimp **rsrcimp);
+	/* return srcimp resource */
+	int (*put_srcimp)(struct srcimp_mgr *mgr, struct srcimp *srcimp);
+	int (*imap_add)(struct srcimp_mgr *mgr, struct imapper *entry);
+	int (*imap_delete)(struct srcimp_mgr *mgr, struct imapper *entry);
+};
+
+/* Constructor and destructor of SRC resource manager */
+int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr);
+int src_mgr_destroy(struct src_mgr *src_mgr);
+/* Constructor and destructor of SRCIMP resource manager */
+int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrc_mgr);
+int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr);
+
+#endif /* CTSRC_H */
diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c
new file mode 100644
index 0000000..779c6c3
--- /dev/null
+++ b/sound/pci/ctxfi/cttimer.c
@@ -0,0 +1,441 @@
+/*
+ * PCM timer handling on ctxfi
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ */
+
+#include <linux/slab.h>
+#include <linux/math64.h>
+#include <linux/moduleparam.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include "ctatc.h"
+#include "cthardware.h"
+#include "cttimer.h"
+
+static int use_system_timer;
+MODULE_PARM_DESC(use_system_timer, "Foce to use system-timer");
+module_param(use_system_timer, bool, S_IRUGO);
+
+struct ct_timer_ops {
+	void (*init)(struct ct_timer_instance *);
+	void (*prepare)(struct ct_timer_instance *);
+	void (*start)(struct ct_timer_instance *);
+	void (*stop)(struct ct_timer_instance *);
+	void (*free_instance)(struct ct_timer_instance *);
+	void (*interrupt)(struct ct_timer *);
+	void (*free_global)(struct ct_timer *);
+};
+
+/* timer instance -- assigned to each PCM stream */
+struct ct_timer_instance {
+	spinlock_t lock;
+	struct ct_timer *timer_base;
+	struct ct_atc_pcm *apcm;
+	struct snd_pcm_substream *substream;
+	struct timer_list timer;
+	struct list_head instance_list;
+	struct list_head running_list;
+	unsigned int position;
+	unsigned int frag_count;
+	unsigned int running:1;
+	unsigned int need_update:1;
+};
+
+/* timer instance manager */
+struct ct_timer {
+	spinlock_t lock;		/* global timer lock (for xfitimer) */
+	spinlock_t list_lock;		/* lock for instance list */
+	struct ct_atc *atc;
+	struct ct_timer_ops *ops;
+	struct list_head instance_head;
+	struct list_head running_head;
+	unsigned int wc;		/* current wallclock */
+	unsigned int irq_handling:1;	/* in IRQ handling */
+	unsigned int reprogram:1;	/* need to reprogram the internval */
+	unsigned int running:1;		/* global timer running */
+};
+
+
+/*
+ * system-timer-based updates
+ */
+
+static void ct_systimer_callback(unsigned long data)
+{
+	struct ct_timer_instance *ti = (struct ct_timer_instance *)data;
+	struct snd_pcm_substream *substream = ti->substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ct_atc_pcm *apcm = ti->apcm;
+	unsigned int period_size = runtime->period_size;
+	unsigned int buffer_size = runtime->buffer_size;
+	unsigned long flags;
+	unsigned int position, dist, interval;
+
+	position = substream->ops->pointer(substream);
+	dist = (position + buffer_size - ti->position) % buffer_size;
+	if (dist >= period_size ||
+	    position / period_size != ti->position / period_size) {
+		apcm->interrupt(apcm);
+		ti->position = position;
+	}
+	/* Add extra HZ*5/1000 to avoid overrun issue when recording
+	 * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */
+	interval = ((period_size - (position % period_size))
+		   * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000;
+	spin_lock_irqsave(&ti->lock, flags);
+	if (ti->running)
+		mod_timer(&ti->timer, jiffies + interval);
+	spin_unlock_irqrestore(&ti->lock, flags);
+}
+
+static void ct_systimer_init(struct ct_timer_instance *ti)
+{
+	setup_timer(&ti->timer, ct_systimer_callback,
+		    (unsigned long)ti);
+}
+
+static void ct_systimer_start(struct ct_timer_instance *ti)
+{
+	struct snd_pcm_runtime *runtime = ti->substream->runtime;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ti->lock, flags);
+	ti->running = 1;
+	mod_timer(&ti->timer,
+		  jiffies + (runtime->period_size * HZ +
+			     (runtime->rate - 1)) / runtime->rate);
+	spin_unlock_irqrestore(&ti->lock, flags);
+}
+
+static void ct_systimer_stop(struct ct_timer_instance *ti)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ti->lock, flags);
+	ti->running = 0;
+	del_timer(&ti->timer);
+	spin_unlock_irqrestore(&ti->lock, flags);
+}
+
+static void ct_systimer_prepare(struct ct_timer_instance *ti)
+{
+	ct_systimer_stop(ti);
+	try_to_del_timer_sync(&ti->timer);
+}
+
+#define ct_systimer_free	ct_systimer_prepare
+
+static struct ct_timer_ops ct_systimer_ops = {
+	.init = ct_systimer_init,
+	.free_instance = ct_systimer_free,
+	.prepare = ct_systimer_prepare,
+	.start = ct_systimer_start,
+	.stop = ct_systimer_stop,
+};
+
+
+/*
+ * Handling multiple streams using a global emu20k1 timer irq
+ */
+
+#define CT_TIMER_FREQ	48000
+#define MIN_TICKS	1
+#define MAX_TICKS	((1 << 13) - 1)
+
+static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks)
+{
+	struct hw *hw = atimer->atc->hw;
+	if (ticks > MAX_TICKS)
+		ticks = MAX_TICKS;
+	hw->set_timer_tick(hw, ticks);
+	if (!atimer->running)
+		hw->set_timer_irq(hw, 1);
+	atimer->running = 1;
+}
+
+static void ct_xfitimer_irq_stop(struct ct_timer *atimer)
+{
+	if (atimer->running) {
+		struct hw *hw = atimer->atc->hw;
+		hw->set_timer_irq(hw, 0);
+		hw->set_timer_tick(hw, 0);
+		atimer->running = 0;
+	}
+}
+
+static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
+{
+	struct hw *hw = atimer->atc->hw;
+	return hw->get_wc(hw);
+}
+
+/*
+ * reprogram the timer interval;
+ * checks the running instance list and determines the next timer interval.
+ * also updates the each stream position, returns the number of streams
+ * to call snd_pcm_period_elapsed() appropriately
+ *
+ * call this inside the lock and irq disabled
+ */
+static int ct_xfitimer_reprogram(struct ct_timer *atimer)
+{
+	struct ct_timer_instance *ti;
+	unsigned int min_intr = (unsigned int)-1;
+	int updates = 0;
+	unsigned int wc, diff;
+
+	if (list_empty(&atimer->running_head)) {
+		ct_xfitimer_irq_stop(atimer);
+		atimer->reprogram = 0; /* clear flag */
+		return 0;
+	}
+
+	wc = ct_xfitimer_get_wc(atimer);
+	diff = wc - atimer->wc;
+	atimer->wc = wc;
+	list_for_each_entry(ti, &atimer->running_head, running_list) {
+		if (ti->frag_count > diff)
+			ti->frag_count -= diff;
+		else {
+			unsigned int pos;
+			unsigned int period_size, rate;
+
+			period_size = ti->substream->runtime->period_size;
+			rate = ti->substream->runtime->rate;
+			pos = ti->substream->ops->pointer(ti->substream);
+			if (pos / period_size != ti->position / period_size) {
+				ti->need_update = 1;
+				ti->position = pos;
+				updates++;
+			}
+			pos %= period_size;
+			pos = period_size - pos;
+			ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
+						 rate - 1, rate);
+		}
+		if (ti->frag_count < min_intr)
+			min_intr = ti->frag_count;
+	}
+
+	if (min_intr < MIN_TICKS)
+		min_intr = MIN_TICKS;
+	ct_xfitimer_irq_rearm(atimer, min_intr);
+	atimer->reprogram = 0; /* clear flag */
+	return updates;
+}
+
+/* look through the instance list and call period_elapsed if needed */
+static void ct_xfitimer_check_period(struct ct_timer *atimer)
+{
+	struct ct_timer_instance *ti;
+	unsigned long flags;
+
+	spin_lock_irqsave(&atimer->list_lock, flags);
+	list_for_each_entry(ti, &atimer->instance_head, instance_list) {
+		if (ti->need_update) {
+			ti->need_update = 0;
+			ti->apcm->interrupt(ti->apcm);
+		}
+	}
+	spin_unlock_irqrestore(&atimer->list_lock, flags);
+}
+
+/* Handle timer-interrupt */
+static void ct_xfitimer_callback(struct ct_timer *atimer)
+{
+	int update;
+	unsigned long flags;
+
+	spin_lock_irqsave(&atimer->lock, flags);
+	atimer->irq_handling = 1;
+	do {
+		update = ct_xfitimer_reprogram(atimer);
+		spin_unlock(&atimer->lock);
+		if (update)
+			ct_xfitimer_check_period(atimer);
+		spin_lock(&atimer->lock);
+	} while (atimer->reprogram);
+	atimer->irq_handling = 0;
+	spin_unlock_irqrestore(&atimer->lock, flags);
+}
+
+static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
+{
+	ti->frag_count = ti->substream->runtime->period_size;
+	ti->need_update = 0;
+}
+
+
+/* start/stop the timer */
+static void ct_xfitimer_update(struct ct_timer *atimer)
+{
+	unsigned long flags;
+	int update;
+
+	spin_lock_irqsave(&atimer->lock, flags);
+	if (atimer->irq_handling) {
+		/* reached from IRQ handler; let it handle later */
+		atimer->reprogram = 1;
+		spin_unlock_irqrestore(&atimer->lock, flags);
+		return;
+	}
+
+	ct_xfitimer_irq_stop(atimer);
+	update = ct_xfitimer_reprogram(atimer);
+	spin_unlock_irqrestore(&atimer->lock, flags);
+	if (update)
+		ct_xfitimer_check_period(atimer);
+}
+
+static void ct_xfitimer_start(struct ct_timer_instance *ti)
+{
+	struct ct_timer *atimer = ti->timer_base;
+	unsigned long flags;
+
+	spin_lock_irqsave(&atimer->lock, flags);
+	if (list_empty(&ti->running_list))
+		atimer->wc = ct_xfitimer_get_wc(atimer);
+	list_add(&ti->running_list, &atimer->running_head);
+	spin_unlock_irqrestore(&atimer->lock, flags);
+	ct_xfitimer_update(atimer);
+}
+
+static void ct_xfitimer_stop(struct ct_timer_instance *ti)
+{
+	struct ct_timer *atimer = ti->timer_base;
+	unsigned long flags;
+
+	spin_lock_irqsave(&atimer->lock, flags);
+	list_del_init(&ti->running_list);
+	ti->need_update = 0;
+	spin_unlock_irqrestore(&atimer->lock, flags);
+	ct_xfitimer_update(atimer);
+}
+
+static void ct_xfitimer_free_global(struct ct_timer *atimer)
+{
+	ct_xfitimer_irq_stop(atimer);
+}
+
+static struct ct_timer_ops ct_xfitimer_ops = {
+	.prepare = ct_xfitimer_prepare,
+	.start = ct_xfitimer_start,
+	.stop = ct_xfitimer_stop,
+	.interrupt = ct_xfitimer_callback,
+	.free_global = ct_xfitimer_free_global,
+};
+
+/*
+ * timer instance
+ */
+
+struct ct_timer_instance *
+ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm)
+{
+	struct ct_timer_instance *ti;
+
+	ti = kzalloc(sizeof(*ti), GFP_KERNEL);
+	if (!ti)
+		return NULL;
+	spin_lock_init(&ti->lock);
+	INIT_LIST_HEAD(&ti->instance_list);
+	INIT_LIST_HEAD(&ti->running_list);
+	ti->timer_base = atimer;
+	ti->apcm = apcm;
+	ti->substream = apcm->substream;
+	if (atimer->ops->init)
+		atimer->ops->init(ti);
+
+	spin_lock_irq(&atimer->list_lock);
+	list_add(&ti->instance_list, &atimer->instance_head);
+	spin_unlock_irq(&atimer->list_lock);
+
+	return ti;
+}
+
+void ct_timer_prepare(struct ct_timer_instance *ti)
+{
+	if (ti->timer_base->ops->prepare)
+		ti->timer_base->ops->prepare(ti);
+	ti->position = 0;
+	ti->running = 0;
+}
+
+void ct_timer_start(struct ct_timer_instance *ti)
+{
+	struct ct_timer *atimer = ti->timer_base;
+	atimer->ops->start(ti);
+}
+
+void ct_timer_stop(struct ct_timer_instance *ti)
+{
+	struct ct_timer *atimer = ti->timer_base;
+	atimer->ops->stop(ti);
+}
+
+void ct_timer_instance_free(struct ct_timer_instance *ti)
+{
+	struct ct_timer *atimer = ti->timer_base;
+
+	atimer->ops->stop(ti); /* to be sure */
+	if (atimer->ops->free_instance)
+		atimer->ops->free_instance(ti);
+
+	spin_lock_irq(&atimer->list_lock);
+	list_del(&ti->instance_list);
+	spin_unlock_irq(&atimer->list_lock);
+
+	kfree(ti);
+}
+
+/*
+ * timer manager
+ */
+
+static void ct_timer_interrupt(void *data, unsigned int status)
+{
+	struct ct_timer *timer = data;
+
+	/* Interval timer interrupt */
+	if ((status & IT_INT) && timer->ops->interrupt)
+		timer->ops->interrupt(timer);
+}
+
+struct ct_timer *ct_timer_new(struct ct_atc *atc)
+{
+	struct ct_timer *atimer;
+	struct hw *hw;
+
+	atimer = kzalloc(sizeof(*atimer), GFP_KERNEL);
+	if (!atimer)
+		return NULL;
+	spin_lock_init(&atimer->lock);
+	spin_lock_init(&atimer->list_lock);
+	INIT_LIST_HEAD(&atimer->instance_head);
+	INIT_LIST_HEAD(&atimer->running_head);
+	atimer->atc = atc;
+	hw = atc->hw;
+	if (!use_system_timer && hw->set_timer_irq) {
+		snd_printd(KERN_INFO "ctxfi: Use xfi-native timer\n");
+		atimer->ops = &ct_xfitimer_ops;
+		hw->irq_callback_data = atimer;
+		hw->irq_callback = ct_timer_interrupt;
+	} else {
+		snd_printd(KERN_INFO "ctxfi: Use system timer\n");
+		atimer->ops = &ct_systimer_ops;
+	}
+	return atimer;
+}
+
+void ct_timer_free(struct ct_timer *atimer)
+{
+	struct hw *hw = atimer->atc->hw;
+	hw->irq_callback = NULL;
+	if (atimer->ops->free_global)
+		atimer->ops->free_global(atimer);
+	kfree(atimer);
+}
+
diff --git a/sound/pci/ctxfi/cttimer.h b/sound/pci/ctxfi/cttimer.h
new file mode 100644
index 0000000..9793482
--- /dev/null
+++ b/sound/pci/ctxfi/cttimer.h
@@ -0,0 +1,29 @@
+/*
+ * Timer handling
+ */
+
+#ifndef __CTTIMER_H
+#define __CTTIMER_H
+
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+
+struct snd_pcm_substream;
+struct ct_atc;
+struct ct_atc_pcm;
+
+struct ct_timer;
+struct ct_timer_instance;
+
+struct ct_timer *ct_timer_new(struct ct_atc *atc);
+void ct_timer_free(struct ct_timer *atimer);
+
+struct ct_timer_instance *
+ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm);
+void ct_timer_instance_free(struct ct_timer_instance *ti);
+void ct_timer_start(struct ct_timer_instance *ti);
+void ct_timer_stop(struct ct_timer_instance *ti);
+void ct_timer_prepare(struct ct_timer_instance *ti);
+
+#endif /* __CTTIMER_H */
diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c
new file mode 100644
index 0000000..67665a7
--- /dev/null
+++ b/sound/pci/ctxfi/ctvmem.c
@@ -0,0 +1,250 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File    ctvmem.c
+ *
+ * @Brief
+ * This file contains the implementation of virtual memory management object
+ * for card device.
+ *
+ * @Author Liu Chun
+ * @Date Apr 1 2008
+ */
+
+#include "ctvmem.h"
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <sound/pcm.h>
+
+#define CT_PTES_PER_PAGE (CT_PAGE_SIZE / sizeof(void *))
+#define CT_ADDRS_PER_PAGE (CT_PTES_PER_PAGE * CT_PAGE_SIZE)
+
+/* *
+ * Find or create vm block based on requested @size.
+ * @size must be page aligned.
+ * */
+static struct ct_vm_block *
+get_vm_block(struct ct_vm *vm, unsigned int size)
+{
+	struct ct_vm_block *block = NULL, *entry;
+	struct list_head *pos;
+
+	size = CT_PAGE_ALIGN(size);
+	if (size > vm->size) {
+		printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural "
+				  "memory space available!\n");
+		return NULL;
+	}
+
+	mutex_lock(&vm->lock);
+	list_for_each(pos, &vm->unused) {
+		entry = list_entry(pos, struct ct_vm_block, list);
+		if (entry->size >= size)
+			break; /* found a block that is big enough */
+	}
+	if (pos == &vm->unused)
+		goto out;
+
+	if (entry->size == size) {
+		/* Move the vm node from unused list to used list directly */
+		list_del(&entry->list);
+		list_add(&entry->list, &vm->used);
+		vm->size -= size;
+		block = entry;
+		goto out;
+	}
+
+	block = kzalloc(sizeof(*block), GFP_KERNEL);
+	if (NULL == block)
+		goto out;
+
+	block->addr = entry->addr;
+	block->size = size;
+	list_add(&block->list, &vm->used);
+	entry->addr += size;
+	entry->size -= size;
+	vm->size -= size;
+
+ out:
+	mutex_unlock(&vm->lock);
+	return block;
+}
+
+static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block)
+{
+	struct ct_vm_block *entry, *pre_ent;
+	struct list_head *pos, *pre;
+
+	block->size = CT_PAGE_ALIGN(block->size);
+
+	mutex_lock(&vm->lock);
+	list_del(&block->list);
+	vm->size += block->size;
+
+	list_for_each(pos, &vm->unused) {
+		entry = list_entry(pos, struct ct_vm_block, list);
+		if (entry->addr >= (block->addr + block->size))
+			break; /* found a position */
+	}
+	if (pos == &vm->unused) {
+		list_add_tail(&block->list, &vm->unused);
+		entry = block;
+	} else {
+		if ((block->addr + block->size) == entry->addr) {
+			entry->addr = block->addr;
+			entry->size += block->size;
+			kfree(block);
+		} else {
+			__list_add(&block->list, pos->prev, pos);
+			entry = block;
+		}
+	}
+
+	pos = &entry->list;
+	pre = pos->prev;
+	while (pre != &vm->unused) {
+		entry = list_entry(pos, struct ct_vm_block, list);
+		pre_ent = list_entry(pre, struct ct_vm_block, list);
+		if ((pre_ent->addr + pre_ent->size) > entry->addr)
+			break;
+
+		pre_ent->size += entry->size;
+		list_del(pos);
+		kfree(entry);
+		pos = pre;
+		pre = pos->prev;
+	}
+	mutex_unlock(&vm->lock);
+}
+
+/* Map host addr (kmalloced/vmalloced) to device logical addr. */
+static struct ct_vm_block *
+ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size)
+{
+	struct ct_vm_block *block;
+	unsigned int pte_start;
+	unsigned i, pages;
+	unsigned long *ptp;
+
+	block = get_vm_block(vm, size);
+	if (block == NULL) {
+		printk(KERN_ERR "ctxfi: No virtual memory block that is big "
+				  "enough to allocate!\n");
+		return NULL;
+	}
+
+	ptp = vm->ptp[0];
+	pte_start = (block->addr >> CT_PAGE_SHIFT);
+	pages = block->size >> CT_PAGE_SHIFT;
+	for (i = 0; i < pages; i++) {
+		unsigned long addr;
+		addr = snd_pcm_sgbuf_get_addr(substream, i << CT_PAGE_SHIFT);
+		ptp[pte_start + i] = addr;
+	}
+
+	block->size = size;
+	return block;
+}
+
+static void ct_vm_unmap(struct ct_vm *vm, struct ct_vm_block *block)
+{
+	/* do unmapping */
+	put_vm_block(vm, block);
+}
+
+/* *
+ * return the host (kmalloced) addr of the @index-th device
+ * page talbe page on success, or NULL on failure.
+ * The first returned NULL indicates the termination.
+ * */
+static void *
+ct_get_ptp_virt(struct ct_vm *vm, int index)
+{
+	void *addr;
+
+	addr = (index >= CT_PTP_NUM) ? NULL : vm->ptp[index];
+
+	return addr;
+}
+
+int ct_vm_create(struct ct_vm **rvm)
+{
+	struct ct_vm *vm;
+	struct ct_vm_block *block;
+	int i;
+
+	*rvm = NULL;
+
+	vm = kzalloc(sizeof(*vm), GFP_KERNEL);
+	if (NULL == vm)
+		return -ENOMEM;
+
+	mutex_init(&vm->lock);
+
+	/* Allocate page table pages */
+	for (i = 0; i < CT_PTP_NUM; i++) {
+		vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL);
+		if (NULL == vm->ptp[i])
+			break;
+	}
+	if (!i) {
+		/* no page table pages are allocated */
+		kfree(vm);
+		return -ENOMEM;
+	}
+	vm->size = CT_ADDRS_PER_PAGE * i;
+	/* Initialise remaining ptps */
+	for (; i < CT_PTP_NUM; i++)
+		vm->ptp[i] = NULL;
+
+	vm->map = ct_vm_map;
+	vm->unmap = ct_vm_unmap;
+	vm->get_ptp_virt = ct_get_ptp_virt;
+	INIT_LIST_HEAD(&vm->unused);
+	INIT_LIST_HEAD(&vm->used);
+	block = kzalloc(sizeof(*block), GFP_KERNEL);
+	if (NULL != block) {
+		block->addr = 0;
+		block->size = vm->size;
+		list_add(&block->list, &vm->unused);
+	}
+
+	*rvm = vm;
+	return 0;
+}
+
+/* The caller must ensure no mapping pages are being used
+ * by hardware before calling this function */
+void ct_vm_destroy(struct ct_vm *vm)
+{
+	int i;
+	struct list_head *pos;
+	struct ct_vm_block *entry;
+
+	/* free used and unused list nodes */
+	while (!list_empty(&vm->used)) {
+		pos = vm->used.next;
+		list_del(pos);
+		entry = list_entry(pos, struct ct_vm_block, list);
+		kfree(entry);
+	}
+	while (!list_empty(&vm->unused)) {
+		pos = vm->unused.next;
+		list_del(pos);
+		entry = list_entry(pos, struct ct_vm_block, list);
+		kfree(entry);
+	}
+
+	/* free allocated page table pages */
+	for (i = 0; i < CT_PTP_NUM; i++)
+		kfree(vm->ptp[i]);
+
+	vm->size = 0;
+
+	kfree(vm);
+}
diff --git a/sound/pci/ctxfi/ctvmem.h b/sound/pci/ctxfi/ctvmem.h
new file mode 100644
index 0000000..01e4fd0
--- /dev/null
+++ b/sound/pci/ctxfi/ctvmem.h
@@ -0,0 +1,61 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File    ctvmem.h
+ *
+ * @Brief
+ * This file contains the definition of virtual memory management object
+ * for card device.
+ *
+ * @Author Liu Chun
+ * @Date Mar 28 2008
+ */
+
+#ifndef CTVMEM_H
+#define CTVMEM_H
+
+#define CT_PTP_NUM	1	/* num of device page table pages */
+
+#include <linux/mutex.h>
+#include <linux/list.h>
+
+/* The chip can handle the page table of 4k pages
+ * (emu20k1 can handle even 8k pages, but we don't use it right now)
+ */
+#define CT_PAGE_SIZE	4096
+#define CT_PAGE_SHIFT	12
+#define CT_PAGE_MASK	(~(PAGE_SIZE - 1))
+#define CT_PAGE_ALIGN(addr)	ALIGN(addr, CT_PAGE_SIZE)
+
+struct ct_vm_block {
+	unsigned int addr;	/* starting logical addr of this block */
+	unsigned int size;	/* size of this device virtual mem block */
+	struct list_head list;
+};
+
+struct snd_pcm_substream;
+
+/* Virtual memory management object for card device */
+struct ct_vm {
+	void *ptp[CT_PTP_NUM];		/* Device page table pages */
+	unsigned int size;		/* Available addr space in bytes */
+	struct list_head unused;	/* List of unused blocks */
+	struct list_head used;		/* List of used blocks */
+	struct mutex lock;
+
+	/* Map host addr (kmalloced/vmalloced) to device logical addr. */
+	struct ct_vm_block *(*map)(struct ct_vm *, struct snd_pcm_substream *,
+				   int size);
+	/* Unmap device logical addr area. */
+	void (*unmap)(struct ct_vm *, struct ct_vm_block *block);
+	void *(*get_ptp_virt)(struct ct_vm *vm, int index);
+};
+
+int ct_vm_create(struct ct_vm **rvm);
+void ct_vm_destroy(struct ct_vm *vm);
+
+#endif /* CTVMEM_H */
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c
new file mode 100644
index 0000000..2d3dd89
--- /dev/null
+++ b/sound/pci/ctxfi/xfi.c
@@ -0,0 +1,142 @@
+/*
+ * xfi linux driver.
+ *
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/moduleparam.h>
+#include <linux/pci_ids.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include "ctatc.h"
+#include "cthardware.h"
+
+MODULE_AUTHOR("Creative Technology Ltd");
+MODULE_DESCRIPTION("X-Fi driver version 1.03");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{{Creative Labs, Sound Blaster X-Fi}");
+
+static unsigned int reference_rate = 48000;
+static unsigned int multiple = 2;
+MODULE_PARM_DESC(reference_rate, "Reference rate (default=48000)");
+module_param(reference_rate, uint, S_IRUGO);
+MODULE_PARM_DESC(multiple, "Rate multiplier (default=2)");
+module_param(multiple, uint, S_IRUGO);
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Creative X-Fi driver");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for Creative X-Fi driver");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver");
+
+static struct pci_device_id ct_pci_dev_ids[] = {
+	/* only X-Fi is supported, so... */
+	{ PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1),
+	  .driver_data = ATC20K1,
+	},
+	{ PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K2),
+	  .driver_data = ATC20K2,
+	},
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, ct_pci_dev_ids);
+
+static int __devinit
+ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+	static int dev;
+	struct snd_card *card;
+	struct ct_atc *atc;
+	int err;
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+	err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+	if (err)
+		return err;
+	if ((reference_rate != 48000) && (reference_rate != 44100)) {
+		printk(KERN_ERR "ctxfi: Invalid reference_rate value %u!!!\n",
+		       reference_rate);
+		printk(KERN_ERR "ctxfi: The valid values for reference_rate "
+		       "are 48000 and 44100, Value 48000 is assumed.\n");
+		reference_rate = 48000;
+	}
+	if ((multiple != 1) && (multiple != 2)) {
+		printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n",
+		       multiple);
+		printk(KERN_ERR "ctxfi: The valid values for multiple are "
+		       "1 and 2, Value 2 is assumed.\n");
+		multiple = 2;
+	}
+	err = ct_atc_create(card, pci, reference_rate, multiple,
+			    pci_id->driver_data, &atc);
+	if (err < 0)
+		goto error;
+
+	card->private_data = atc;
+
+	/* Create alsa devices supported by this card */
+	err = ct_atc_create_alsa_devs(atc);
+	if (err < 0)
+		goto error;
+
+	strcpy(card->driver, "SB-XFi");
+	strcpy(card->shortname, "Creative X-Fi");
+	snprintf(card->longname, sizeof(card->longname), "%s %s %s",
+		 card->shortname, atc->chip_name, atc->model_name);
+
+	err = snd_card_register(card);
+	if (err < 0)
+		goto error;
+
+	pci_set_drvdata(pci, card);
+	dev++;
+
+	return 0;
+
+error:
+	snd_card_free(card);
+	return err;
+}
+
+static void __devexit ct_card_remove(struct pci_dev *pci)
+{
+	snd_card_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_driver ct_driver = {
+	.name = "SB-XFi",
+	.id_table = ct_pci_dev_ids,
+	.probe = ct_card_probe,
+	.remove = __devexit_p(ct_card_remove),
+};
+
+static int __init ct_card_init(void)
+{
+	return pci_register_driver(&ct_driver);
+}
+
+static void __exit ct_card_exit(void)
+{
+	pci_unregister_driver(&ct_driver);
+}
+
+module_init(ct_card_init)
+module_exit(ct_card_exit)
diff --git a/sound/pci/emu10k1/Makefile b/sound/pci/emu10k1/Makefile
index cf2d563..fc5591e 100644
--- a/sound/pci/emu10k1/Makefile
+++ b/sound/pci/emu10k1/Makefile
@@ -9,15 +9,7 @@
 snd-emu10k1-synth-objs := emu10k1_synth.o emu10k1_callback.o emu10k1_patch.o
 snd-emu10k1x-objs := emu10k1x.o
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_EMU10K1) += snd-emu10k1.o
-obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-emu10k1-synth.o
+obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-emu10k1-synth.o
 obj-$(CONFIG_SND_EMU10K1X) += snd-emu10k1x.o
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 1970f0e..4d3ad79 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -858,7 +858,6 @@
 	}
 
 	pcm->info_flags = 0;
-	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
 	switch(device) {
 	case 0:
 		strcpy(pcm->name, "EMU10K1X Front");
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index 78f62fd..55b83ef 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -1736,7 +1736,7 @@
 	.buffer_bytes_max =	(128*1024),
 	.period_bytes_min =	1024,
 	.period_bytes_max =	(128*1024),
-	.periods_min =		1,
+	.periods_min =		2,
 	.periods_max =		1024,
 	.fifo_size =		0,
 };
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index eb2a19b..c710150 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -139,6 +139,19 @@
 	  snd-hda-codec-conexant.
 	  This module is automatically loaded at probing.
 
+config SND_HDA_CODEC_CA0110
+	bool "Build Creative CA0110-IBG codec support"
+	depends on SND_HDA_INTEL
+	default y
+	help
+	  Say Y here to include Creative CA0110-IBG codec support in
+	  snd-hda-intel driver, found on some Creative X-Fi cards.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-ca0110.
+	  This module is automatically loaded at probing.
+
 config SND_HDA_CODEC_CMEDIA
 	bool "Build C-Media HD-audio codec support"
 	default y
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 50f9d09..e3081d4 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -13,6 +13,7 @@
 snd-hda-codec-idt-objs :=	patch_sigmatel.o
 snd-hda-codec-si3054-objs :=	patch_si3054.o
 snd-hda-codec-atihdmi-objs :=	patch_atihdmi.o
+snd-hda-codec-ca0110-objs :=	patch_ca0110.o
 snd-hda-codec-conexant-objs :=	patch_conexant.o
 snd-hda-codec-via-objs :=	patch_via.o
 snd-hda-codec-nvhdmi-objs :=	patch_nvhdmi.o
@@ -40,6 +41,9 @@
 ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
 endif
+ifdef CONFIG_SND_HDA_CODEC_CA0110
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o
+endif
 ifdef CONFIG_SND_HDA_CODEC_CONEXANT
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o
 endif
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 4de5bac..29272f2 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -45,6 +45,46 @@
 			AC_VERB_SET_BEEP_CONTROL, beep->tone);
 }
 
+/* (non-standard) Linear beep tone calculation for IDT/STAC codecs 
+ *
+ * The tone frequency of beep generator on IDT/STAC codecs is
+ * defined from the 8bit tone parameter, in Hz,
+ *    freq = 48000 * (257 - tone) / 1024
+ * that is from 12kHz to 93.75kHz in step of 46.875 hz
+ */
+static int beep_linear_tone(struct hda_beep *beep, int hz)
+{
+	hz *= 1000; /* fixed point */
+	hz = hz - DIGBEEP_HZ_MIN;
+	if (hz < 0)
+		hz = 0; /* turn off PC beep*/
+	else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN))
+		hz = 0xff;
+	else {
+		hz /= DIGBEEP_HZ_STEP;
+		hz++;
+	}
+	return hz;
+}
+
+/* HD-audio standard beep tone parameter calculation
+ *
+ * The tone frequency in Hz is calculated as
+ *   freq = 48000 / (tone * 4)
+ * from 47Hz to 12kHz
+ */
+static int beep_standard_tone(struct hda_beep *beep, int hz)
+{
+	if (hz <= 0)
+		return 0; /* disabled */
+	hz = 12000 / hz;
+	if (hz > 0xff)
+		return 0xff;
+	if (hz <= 0)
+		return 1;
+	return hz;
+}
+
 static int snd_hda_beep_event(struct input_dev *dev, unsigned int type,
 				unsigned int code, int hz)
 {
@@ -55,21 +95,14 @@
 		if (hz)
 			hz = 1000;
 	case SND_TONE:
-		hz *= 1000; /* fixed point */
-		hz = hz - DIGBEEP_HZ_MIN;
-		if (hz < 0)
-			hz = 0; /* turn off PC beep*/
-		else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN))
-			hz = 0xff;
-		else {
-			hz /= DIGBEEP_HZ_STEP;
-			hz++;
-		}
+		if (beep->linear_tone)
+			beep->tone = beep_linear_tone(beep, hz);
+		else
+			beep->tone = beep_standard_tone(beep, hz);
 		break;
 	default:
 		return -1;
 	}
-	beep->tone = hz;
 
 	/* schedule beep event */
 	schedule_work(&beep->beep_work);
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h
index 51bf6a5..0c3de78 100644
--- a/sound/pci/hda/hda_beep.h
+++ b/sound/pci/hda/hda_beep.h
@@ -30,8 +30,9 @@
 	struct hda_codec *codec;
 	char phys[32];
 	int tone;
-	int nid;
-	int enabled;
+	hda_nid_t nid;
+	unsigned int enabled:1;
+	unsigned int linear_tone:1;	/* linear tone for IDT/STAC codec */
 	struct work_struct beep_work; /* scheduled task for beep event */
 };
 
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 8820faf..562403a 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -48,6 +48,7 @@
 	{ 0x1095, "Silicon Image" },
 	{ 0x10de, "Nvidia" },
 	{ 0x10ec, "Realtek" },
+	{ 0x1102, "Creative" },
 	{ 0x1106, "VIA" },
 	{ 0x111d, "IDT" },
 	{ 0x11c1, "LSI" },
@@ -157,6 +158,39 @@
 	return val;
 }
 
+/*
+ * Send and receive a verb
+ */
+static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
+			   unsigned int *res)
+{
+	struct hda_bus *bus = codec->bus;
+	int err;
+
+	if (res)
+		*res = -1;
+ again:
+	snd_hda_power_up(codec);
+	mutex_lock(&bus->cmd_mutex);
+	err = bus->ops.command(bus, cmd);
+	if (!err && res)
+		*res = bus->ops.get_response(bus);
+	mutex_unlock(&bus->cmd_mutex);
+	snd_hda_power_down(codec);
+	if (res && *res == -1 && bus->rirb_error) {
+		if (bus->response_reset) {
+			snd_printd("hda_codec: resetting BUS due to "
+				   "fatal communication error\n");
+			bus->ops.bus_reset(bus);
+		}
+		goto again;
+	}
+	/* clear reset-flag when the communication gets recovered */
+	if (!err)
+		bus->response_reset = 0;
+	return err;
+}
+
 /**
  * snd_hda_codec_read - send a command and get the response
  * @codec: the HDA codec
@@ -173,18 +207,9 @@
 				int direct,
 				unsigned int verb, unsigned int parm)
 {
-	struct hda_bus *bus = codec->bus;
+	unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm);
 	unsigned int res;
-
-	res = make_codec_cmd(codec, nid, direct, verb, parm);
-	snd_hda_power_up(codec);
-	mutex_lock(&bus->cmd_mutex);
-	if (!bus->ops.command(bus, res))
-		res = bus->ops.get_response(bus);
-	else
-		res = (unsigned int)-1;
-	mutex_unlock(&bus->cmd_mutex);
-	snd_hda_power_down(codec);
+	codec_exec_verb(codec, cmd, &res);
 	return res;
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_read);
@@ -204,17 +229,10 @@
 int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
 			 unsigned int verb, unsigned int parm)
 {
-	struct hda_bus *bus = codec->bus;
+	unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm);
 	unsigned int res;
-	int err;
-
-	res = make_codec_cmd(codec, nid, direct, verb, parm);
-	snd_hda_power_up(codec);
-	mutex_lock(&bus->cmd_mutex);
-	err = bus->ops.command(bus, res);
-	mutex_unlock(&bus->cmd_mutex);
-	snd_hda_power_down(codec);
-	return err;
+	return codec_exec_verb(codec, cmd,
+			       codec->bus->sync_write ? &res : NULL);
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_write);
 
@@ -613,7 +631,10 @@
 	const struct hda_vendor_id *c;
 	const char *vendor = NULL;
 	u16 vendor_id = codec->vendor_id >> 16;
-	char tmp[16], name[32];
+	char tmp[16];
+
+	if (codec->vendor_name)
+		goto get_chip_name;
 
 	for (c = hda_vendor_ids; c->id; c++) {
 		if (c->id == vendor_id) {
@@ -625,14 +646,21 @@
 		sprintf(tmp, "Generic %04x", vendor_id);
 		vendor = tmp;
 	}
+	codec->vendor_name = kstrdup(vendor, GFP_KERNEL);
+	if (!codec->vendor_name)
+		return -ENOMEM;
+
+ get_chip_name:
+	if (codec->chip_name)
+		return 0;
+
 	if (codec->preset && codec->preset->name)
-		snprintf(name, sizeof(name), "%s %s", vendor,
-			 codec->preset->name);
-	else
-		snprintf(name, sizeof(name), "%s ID %x", vendor,
-			 codec->vendor_id & 0xffff);
-	codec->name = kstrdup(name, GFP_KERNEL);
-	if (!codec->name)
+		codec->chip_name = kstrdup(codec->preset->name, GFP_KERNEL);
+	else {
+		sprintf(tmp, "ID %x", codec->vendor_id & 0xffff);
+		codec->chip_name = kstrdup(tmp, GFP_KERNEL);
+	}
+	if (!codec->chip_name)
 		return -ENOMEM;
 	return 0;
 }
@@ -838,7 +866,8 @@
 	module_put(codec->owner);
 	free_hda_cache(&codec->amp_cache);
 	free_hda_cache(&codec->cmd_cache);
-	kfree(codec->name);
+	kfree(codec->vendor_name);
+	kfree(codec->chip_name);
 	kfree(codec->modelname);
 	kfree(codec->wcaps);
 	kfree(codec);
@@ -979,15 +1008,16 @@
 	int err;
 
 	codec->preset = find_codec_preset(codec);
-	if (!codec->name) {
+	if (!codec->vendor_name || !codec->chip_name) {
 		err = get_codec_name(codec);
 		if (err < 0)
 			return err;
 	}
 	/* audio codec should override the mixer name */
 	if (codec->afg || !*codec->bus->card->mixername)
-		strlcpy(codec->bus->card->mixername, codec->name,
-			sizeof(codec->bus->card->mixername));
+		snprintf(codec->bus->card->mixername,
+			 sizeof(codec->bus->card->mixername),
+			 "%s %s", codec->vendor_name, codec->chip_name);
 
 	if (is_generic_config(codec)) {
 		err = snd_hda_parse_generic_codec(codec);
@@ -1055,6 +1085,8 @@
 /* FIXME: more better hash key? */
 #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
 #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24))
+#define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24))
+#define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24))
 #define INFO_AMP_CAPS	(1<<0)
 #define INFO_AMP_VOL(ch)	(1 << (1 + (ch)))
 
@@ -1145,19 +1177,32 @@
 }
 EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps);
 
-u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int
+query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key,
+		unsigned int (*func)(struct hda_codec *, hda_nid_t))
 {
 	struct hda_amp_info *info;
 
-	info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid));
+	info = get_alloc_amp_hash(codec, key);
 	if (!info)
 		return 0;
 	if (!info->head.val) {
-		info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
 		info->head.val |= INFO_AMP_CAPS;
+		info->amp_caps = func(codec, nid);
 	}
 	return info->amp_caps;
 }
+
+static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid)
+{
+	return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+}
+
+u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
+{
+	return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid),
+			       read_pin_cap);
+}
 EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
 
 /*
@@ -1432,6 +1477,8 @@
 	memset(&id, 0, sizeof(id));
 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	id.index = idx;
+	if (snd_BUG_ON(strlen(name) >= sizeof(id.name)))
+		return NULL;
 	strcpy(id.name, name);
 	return snd_ctl_find_id(codec->bus->card, &id);
 }
@@ -2242,28 +2289,22 @@
 int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
 			      int direct, unsigned int verb, unsigned int parm)
 {
-	struct hda_bus *bus = codec->bus;
-	unsigned int res;
-	int err;
+	int err = snd_hda_codec_write(codec, nid, direct, verb, parm);
+	struct hda_cache_head *c;
+	u32 key;
 
-	res = make_codec_cmd(codec, nid, direct, verb, parm);
-	snd_hda_power_up(codec);
-	mutex_lock(&bus->cmd_mutex);
-	err = bus->ops.command(bus, res);
-	if (!err) {
-		struct hda_cache_head *c;
-		u32 key;
-		/* parm may contain the verb stuff for get/set amp */
-		verb = verb | (parm >> 8);
-		parm &= 0xff;
-		key = build_cmd_cache_key(nid, verb);
-		c = get_alloc_hash(&codec->cmd_cache, key);
-		if (c)
-			c->val = parm;
-	}
-	mutex_unlock(&bus->cmd_mutex);
-	snd_hda_power_down(codec);
-	return err;
+	if (err < 0)
+		return err;
+	/* parm may contain the verb stuff for get/set amp */
+	verb = verb | (parm >> 8);
+	parm &= 0xff;
+	key = build_cmd_cache_key(nid, verb);
+	mutex_lock(&codec->bus->cmd_mutex);
+	c = get_alloc_hash(&codec->cmd_cache, key);
+	if (c)
+		c->val = parm;
+	mutex_unlock(&codec->bus->cmd_mutex);
+	return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
 
@@ -2321,7 +2362,8 @@
 		if (wcaps & AC_WCAP_POWER) {
 			unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >>
 				AC_WCAP_TYPE_SHIFT;
-			if (wid_type == AC_WID_PIN) {
+			if (power_state == AC_PWRST_D3 &&
+			    wid_type == AC_WID_PIN) {
 				unsigned int pincap;
 				/*
 				 * don't power down the widget if it controls
@@ -2333,7 +2375,7 @@
 						nid, 0,
 						AC_VERB_GET_EAPD_BTLENABLE, 0);
 					eapd &= 0x02;
-					if (power_state == AC_PWRST_D3 && eapd)
+					if (eapd)
 						continue;
 				}
 			}
@@ -2544,6 +2586,41 @@
 }
 EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
 
+static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int val = 0;
+	if (nid != codec->afg &&
+	    (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD))
+		val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
+	if (!val || val == -1)
+		val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+	if (!val || val == -1)
+		return 0;
+	return val;
+}
+
+static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid)
+{
+	return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid),
+			       get_pcm_param);
+}
+
+static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
+	if (!streams || streams == -1)
+		streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
+	if (!streams || streams == -1)
+		return 0;
+	return streams;
+}
+
+static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
+{
+	return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid),
+			       get_stream_param);
+}
+
 /**
  * snd_hda_query_supported_pcm - query the supported PCM rates and formats
  * @codec: the HDA codec
@@ -2562,15 +2639,8 @@
 {
 	unsigned int i, val, wcaps;
 
-	val = 0;
 	wcaps = get_wcaps(codec, nid);
-	if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) {
-		val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
-		if (val == -1)
-			return -EIO;
-	}
-	if (!val)
-		val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+	val = query_pcm_param(codec, nid);
 
 	if (ratesp) {
 		u32 rates = 0;
@@ -2592,15 +2662,9 @@
 		u64 formats = 0;
 		unsigned int streams, bps;
 
-		streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
-		if (streams == -1)
+		streams = query_stream_param(codec, nid);
+		if (!streams)
 			return -EIO;
-		if (!streams) {
-			streams = snd_hda_param_read(codec, codec->afg,
-						     AC_PAR_STREAM);
-			if (streams == -1)
-				return -EIO;
-		}
 
 		bps = 0;
 		if (streams & AC_SUPFMT_PCM) {
@@ -2674,17 +2738,9 @@
 	int i;
 	unsigned int val = 0, rate, stream;
 
-	if (nid != codec->afg &&
-	    (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) {
-		val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
-		if (val == -1)
-			return 0;
-	}
-	if (!val) {
-		val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
-		if (val == -1)
-			return 0;
-	}
+	val = query_pcm_param(codec, nid);
+	if (!val)
+		return 0;
 
 	rate = format & 0xff00;
 	for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++)
@@ -2696,12 +2752,8 @@
 	if (i >= AC_PAR_PCM_RATE_BITS)
 		return 0;
 
-	stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
-	if (stream == -1)
-		return 0;
-	if (!stream && nid != codec->afg)
-		stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
-	if (!stream || stream == -1)
+	stream = query_stream_param(codec, nid);
+	if (!stream)
 		return 0;
 
 	if (stream & AC_SUPFMT_PCM) {
@@ -3835,11 +3887,10 @@
 /**
  * snd_hda_suspend - suspend the codecs
  * @bus: the HDA bus
- * @state: suspsend state
  *
  * Returns 0 if successful.
  */
-int snd_hda_suspend(struct hda_bus *bus, pm_message_t state)
+int snd_hda_suspend(struct hda_bus *bus)
 {
 	struct hda_codec *codec;
 
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 2fdecf4..cad79ef 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -574,6 +574,8 @@
 	/* attach a PCM stream */
 	int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec,
 			  struct hda_pcm *pcm);
+	/* reset bus for retry verb */
+	void (*bus_reset)(struct hda_bus *bus);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	/* notify power-up/down from codec to controller */
 	void (*pm_notify)(struct hda_bus *bus);
@@ -622,7 +624,13 @@
 
 	/* misc op flags */
 	unsigned int needs_damn_long_delay :1;
+	unsigned int allow_bus_reset:1;	/* allow bus reset at fatal error */
+	unsigned int sync_write:1;	/* sync after verb write */
+	/* status for codec/controller */
 	unsigned int shutdown :1;	/* being unloaded */
+	unsigned int rirb_error:1;	/* error in codec communication */
+	unsigned int response_reset:1;	/* controller was reset */
+	unsigned int in_reset:1;	/* during reset operation */
 };
 
 /*
@@ -747,7 +755,8 @@
 	/* detected preset */
 	const struct hda_codec_preset *preset;
 	struct module *owner;
-	const char *name;	/* codec name */
+	const char *vendor_name;	/* codec vendor name */
+	const char *chip_name;		/* codec chip name */
 	const char *modelname;	/* model name for preset */
 
 	/* set by patch */
@@ -905,7 +914,7 @@
  * power management
  */
 #ifdef CONFIG_PM
-int snd_hda_suspend(struct hda_bus *bus, pm_message_t state);
+int snd_hda_suspend(struct hda_bus *bus);
 int snd_hda_resume(struct hda_bus *bus);
 #endif
 
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 1c57505..6812fbe 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -242,7 +242,8 @@
 CODEC_INFO_SHOW(revision_id);
 CODEC_INFO_SHOW(afg);
 CODEC_INFO_SHOW(mfg);
-CODEC_INFO_STR_SHOW(name);
+CODEC_INFO_STR_SHOW(vendor_name);
+CODEC_INFO_STR_SHOW(chip_name);
 CODEC_INFO_STR_SHOW(modelname);
 
 #define CODEC_INFO_STORE(type)					\
@@ -275,7 +276,8 @@
 CODEC_INFO_STORE(vendor_id);
 CODEC_INFO_STORE(subsystem_id);
 CODEC_INFO_STORE(revision_id);
-CODEC_INFO_STR_STORE(name);
+CODEC_INFO_STR_STORE(vendor_name);
+CODEC_INFO_STR_STORE(chip_name);
 CODEC_INFO_STR_STORE(modelname);
 
 #define CODEC_ACTION_STORE(type)				\
@@ -499,7 +501,8 @@
 	CODEC_ATTR_RW(revision_id),
 	CODEC_ATTR_RO(afg),
 	CODEC_ATTR_RO(mfg),
-	CODEC_ATTR_RW(name),
+	CODEC_ATTR_RW(vendor_name),
+	CODEC_ATTR_RW(chip_name),
 	CODEC_ATTR_RW(modelname),
 	CODEC_ATTR_RW(init_verbs),
 	CODEC_ATTR_RW(hints),
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 3128e1a..4e9ea70 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -128,21 +128,33 @@
 			 "{ULI, M5461}}");
 MODULE_DESCRIPTION("Intel HDA driver");
 
+#ifdef CONFIG_SND_VERBOSE_PRINTK
+#define SFX	/* nop */
+#else
 #define SFX	"hda-intel: "
-
+#endif
 
 /*
  * registers
  */
 #define ICH6_REG_GCAP			0x00
+#define   ICH6_GCAP_64OK	(1 << 0)   /* 64bit address support */
+#define   ICH6_GCAP_NSDO	(3 << 1)   /* # of serial data out signals */
+#define   ICH6_GCAP_BSS		(31 << 3)  /* # of bidirectional streams */
+#define   ICH6_GCAP_ISS		(15 << 8)  /* # of input streams */
+#define   ICH6_GCAP_OSS		(15 << 12) /* # of output streams */
 #define ICH6_REG_VMIN			0x02
 #define ICH6_REG_VMAJ			0x03
 #define ICH6_REG_OUTPAY			0x04
 #define ICH6_REG_INPAY			0x06
 #define ICH6_REG_GCTL			0x08
+#define   ICH6_GCTL_RESET	(1 << 0)   /* controller reset */
+#define   ICH6_GCTL_FCNTRL	(1 << 1)   /* flush control */
+#define   ICH6_GCTL_UNSOL	(1 << 8)   /* accept unsol. response enable */
 #define ICH6_REG_WAKEEN			0x0c
 #define ICH6_REG_STATESTS		0x0e
 #define ICH6_REG_GSTS			0x10
+#define   ICH6_GSTS_FSTS	(1 << 1)   /* flush status */
 #define ICH6_REG_INTCTL			0x20
 #define ICH6_REG_INTSTS			0x24
 #define ICH6_REG_WALCLK			0x30
@@ -150,17 +162,27 @@
 #define ICH6_REG_CORBLBASE		0x40
 #define ICH6_REG_CORBUBASE		0x44
 #define ICH6_REG_CORBWP			0x48
-#define ICH6_REG_CORBRP			0x4A
+#define ICH6_REG_CORBRP			0x4a
+#define   ICH6_CORBRP_RST	(1 << 15)  /* read pointer reset */
 #define ICH6_REG_CORBCTL		0x4c
+#define   ICH6_CORBCTL_RUN	(1 << 1)   /* enable DMA */
+#define   ICH6_CORBCTL_CMEIE	(1 << 0)   /* enable memory error irq */
 #define ICH6_REG_CORBSTS		0x4d
+#define   ICH6_CORBSTS_CMEI	(1 << 0)   /* memory error indication */
 #define ICH6_REG_CORBSIZE		0x4e
 
 #define ICH6_REG_RIRBLBASE		0x50
 #define ICH6_REG_RIRBUBASE		0x54
 #define ICH6_REG_RIRBWP			0x58
+#define   ICH6_RIRBWP_RST	(1 << 15)  /* write pointer reset */
 #define ICH6_REG_RINTCNT		0x5a
 #define ICH6_REG_RIRBCTL		0x5c
+#define   ICH6_RBCTL_IRQ_EN	(1 << 0)   /* enable IRQ */
+#define   ICH6_RBCTL_DMA_EN	(1 << 1)   /* enable DMA */
+#define   ICH6_RBCTL_OVERRUN_EN	(1 << 2)   /* enable overrun irq */
 #define ICH6_REG_RIRBSTS		0x5d
+#define   ICH6_RBSTS_IRQ	(1 << 0)   /* response irq */
+#define   ICH6_RBSTS_OVERRUN	(1 << 2)   /* overrun irq */
 #define ICH6_REG_RIRBSIZE		0x5e
 
 #define ICH6_REG_IC			0x60
@@ -257,16 +279,6 @@
 #define ICH6_INT_CTRL_EN	0x40000000 /* controller interrupt enable bit */
 #define ICH6_INT_GLOBAL_EN	0x80000000 /* global interrupt enable bit */
 
-/* GCTL unsolicited response enable bit */
-#define ICH6_GCTL_UREN		(1<<8)
-
-/* GCTL reset bit */
-#define ICH6_GCTL_RESET		(1<<0)
-
-/* CORB/RIRB control, read/write pointer */
-#define ICH6_RBCTL_DMA_EN	0x02	/* enable DMA */
-#define ICH6_RBCTL_IRQ_EN	0x01	/* enable IRQ */
-#define ICH6_RBRWP_CLR		0x8000	/* read/write pointer clear */
 /* below are so far hardcoded - should read registers in future */
 #define ICH6_MAX_CORB_ENTRIES	256
 #define ICH6_MAX_RIRB_ENTRIES	256
@@ -512,25 +524,25 @@
 	/* set the corb write pointer to 0 */
 	azx_writew(chip, CORBWP, 0);
 	/* reset the corb hw read pointer */
-	azx_writew(chip, CORBRP, ICH6_RBRWP_CLR);
+	azx_writew(chip, CORBRP, ICH6_CORBRP_RST);
 	/* enable corb dma */
-	azx_writeb(chip, CORBCTL, ICH6_RBCTL_DMA_EN);
+	azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN);
 
 	/* RIRB set up */
 	chip->rirb.addr = chip->rb.addr + 2048;
 	chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
+	chip->rirb.wp = chip->rirb.rp = chip->rirb.cmds = 0;
 	azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
 	azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr));
 
 	/* set the rirb size to 256 entries (ULI requires explicitly) */
 	azx_writeb(chip, RIRBSIZE, 0x02);
 	/* reset the rirb hw write pointer */
-	azx_writew(chip, RIRBWP, ICH6_RBRWP_CLR);
+	azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
 	/* set N=1, get RIRB response interrupt for new entry */
 	azx_writew(chip, RINTCNT, 1);
 	/* enable rirb dma and response irq */
 	azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
-	chip->rirb.rp = chip->rirb.cmds = 0;
 }
 
 static void azx_free_cmd_io(struct azx *chip)
@@ -606,6 +618,7 @@
 		}
 		if (!chip->rirb.cmds) {
 			smp_rmb();
+			bus->rirb_error = 0;
 			return chip->rirb.res; /* the last value */
 		}
 		if (time_after(jiffies, timeout))
@@ -619,19 +632,21 @@
 	}
 
 	if (chip->msi) {
-		snd_printk(KERN_WARNING "hda_intel: No response from codec, "
+		snd_printk(KERN_WARNING SFX "No response from codec, "
 			   "disabling MSI: last cmd=0x%08x\n", chip->last_cmd);
 		free_irq(chip->irq, chip);
 		chip->irq = -1;
 		pci_disable_msi(chip->pci);
 		chip->msi = 0;
-		if (azx_acquire_irq(chip, 1) < 0)
+		if (azx_acquire_irq(chip, 1) < 0) {
+			bus->rirb_error = 1;
 			return -1;
+		}
 		goto again;
 	}
 
 	if (!chip->polling_mode) {
-		snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, "
+		snd_printk(KERN_WARNING SFX "azx_get_response timeout, "
 			   "switching to polling mode: last cmd=0x%08x\n",
 			   chip->last_cmd);
 		chip->polling_mode = 1;
@@ -646,14 +661,23 @@
 		return -1;
 	}
 
+	/* a fatal communication error; need either to reset or to fallback
+	 * to the single_cmd mode
+	 */
+	bus->rirb_error = 1;
+	if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) {
+		bus->response_reset = 1;
+		return -1; /* give a chance to retry */
+	}
+
 	snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
 		   "switching to single_cmd mode: last cmd=0x%08x\n",
 		   chip->last_cmd);
-	chip->rirb.rp = azx_readb(chip, RIRBWP);
-	chip->rirb.cmds = 0;
-	/* switch to single_cmd mode */
 	chip->single_cmd = 1;
+	bus->response_reset = 0;
+	/* re-initialize CORB/RIRB */
 	azx_free_cmd_io(chip);
+	azx_init_cmd_io(chip);
 	return -1;
 }
 
@@ -667,12 +691,34 @@
  *       I left the codes, however, for debugging/testing purposes.
  */
 
+/* receive a response */
+static int azx_single_wait_for_response(struct azx *chip)
+{
+	int timeout = 50;
+
+	while (timeout--) {
+		/* check IRV busy bit */
+		if (azx_readw(chip, IRS) & ICH6_IRS_VALID) {
+			/* reuse rirb.res as the response return value */
+			chip->rirb.res = azx_readl(chip, IR);
+			return 0;
+		}
+		udelay(1);
+	}
+	if (printk_ratelimit())
+		snd_printd(SFX "get_response timeout: IRS=0x%x\n",
+			   azx_readw(chip, IRS));
+	chip->rirb.res = -1;
+	return -EIO;
+}
+
 /* send a command */
 static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
 {
 	struct azx *chip = bus->private_data;
 	int timeout = 50;
 
+	bus->rirb_error = 0;
 	while (timeout--) {
 		/* check ICB busy bit */
 		if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) {
@@ -682,7 +728,7 @@
 			azx_writel(chip, IC, val);
 			azx_writew(chip, IRS, azx_readw(chip, IRS) |
 				   ICH6_IRS_BUSY);
-			return 0;
+			return azx_single_wait_for_response(chip);
 		}
 		udelay(1);
 	}
@@ -696,18 +742,7 @@
 static unsigned int azx_single_get_response(struct hda_bus *bus)
 {
 	struct azx *chip = bus->private_data;
-	int timeout = 50;
-
-	while (timeout--) {
-		/* check IRV busy bit */
-		if (azx_readw(chip, IRS) & ICH6_IRS_VALID)
-			return azx_readl(chip, IR);
-		udelay(1);
-	}
-	if (printk_ratelimit())
-		snd_printd(SFX "get_response timeout: IRS=0x%x\n",
-			   azx_readw(chip, IRS));
-	return (unsigned int)-1;
+	return chip->rirb.res;
 }
 
 /*
@@ -775,17 +810,17 @@
 
 	/* check to see if controller is ready */
 	if (!azx_readb(chip, GCTL)) {
-		snd_printd("azx_reset: controller not ready!\n");
+		snd_printd(SFX "azx_reset: controller not ready!\n");
 		return -EBUSY;
 	}
 
 	/* Accept unsolicited responses */
-	azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN);
+	azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UNSOL);
 
 	/* detect codecs */
 	if (!chip->codec_mask) {
 		chip->codec_mask = azx_readw(chip, STATESTS);
-		snd_printdd("codec_mask = 0x%x\n", chip->codec_mask);
+		snd_printdd(SFX "codec_mask = 0x%x\n", chip->codec_mask);
 	}
 
 	return 0;
@@ -895,8 +930,7 @@
 	azx_int_enable(chip);
 
 	/* initialize the codec command I/O */
-	if (!chip->single_cmd)
-		azx_init_cmd_io(chip);
+	azx_init_cmd_io(chip);
 
 	/* program the position buffer */
 	azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
@@ -953,12 +987,12 @@
 	case AZX_DRIVER_SCH:
 		pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
 		if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) {
-			pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, \
+			pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC,
 				snoop & (~INTEL_SCH_HDA_DEVC_NOSNOOP));
 			pci_read_config_word(chip->pci,
 				INTEL_SCH_HDA_DEVC, &snoop);
-			snd_printdd("HDA snoop disabled, enabling ... %s\n",\
-				(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) \
+			snd_printdd(SFX "HDA snoop disabled, enabling ... %s\n",
+				(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)
 				? "Failed" : "OK");
 		}
 		break;
@@ -1012,7 +1046,7 @@
 	/* clear rirb int */
 	status = azx_readb(chip, RIRBSTS);
 	if (status & RIRB_INT_MASK) {
-		if (!chip->single_cmd && (status & RIRB_INT_RESPONSE))
+		if (status & RIRB_INT_RESPONSE)
 			azx_update_rirb(chip);
 		azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
 	}
@@ -1098,7 +1132,7 @@
 				pos_align;
 		pos_adj = frames_to_bytes(runtime, pos_adj);
 		if (pos_adj >= period_bytes) {
-			snd_printk(KERN_WARNING "Too big adjustment %d\n",
+			snd_printk(KERN_WARNING SFX "Too big adjustment %d\n",
 				   bdl_pos_adj[chip->dev_index]);
 			pos_adj = 0;
 		} else {
@@ -1122,7 +1156,7 @@
 	return 0;
 
  error:
-	snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n",
+	snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n",
 		   azx_dev->bufsize, period_bytes);
 	return -EINVAL;
 }
@@ -1215,7 +1249,7 @@
 	chip->probing = 0;
 	if (res == -1)
 		return -EIO;
-	snd_printdd("hda_intel: codec #%d probed OK\n", addr);
+	snd_printdd(SFX "codec #%d probed OK\n", addr);
 	return 0;
 }
 
@@ -1223,6 +1257,26 @@
 				 struct hda_pcm *cpcm);
 static void azx_stop_chip(struct azx *chip);
 
+static void azx_bus_reset(struct hda_bus *bus)
+{
+	struct azx *chip = bus->private_data;
+
+	bus->in_reset = 1;
+	azx_stop_chip(chip);
+	azx_init_chip(chip);
+#ifdef CONFIG_PM
+	if (chip->initialized) {
+		int i;
+
+		for (i = 0; i < AZX_MAX_PCMS; i++)
+			snd_pcm_suspend_all(chip->pcm[i]);
+		snd_hda_suspend(chip->bus);
+		snd_hda_resume(chip->bus);
+	}
+#endif
+	bus->in_reset = 0;
+}
+
 /*
  * Codec initialization
  */
@@ -1246,6 +1300,7 @@
 	bus_temp.ops.command = azx_send_cmd;
 	bus_temp.ops.get_response = azx_get_response;
 	bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
+	bus_temp.ops.bus_reset = azx_bus_reset;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	bus_temp.power_save = &power_save;
 	bus_temp.ops.pm_notify = azx_power_notify;
@@ -1270,8 +1325,8 @@
 				/* Some BIOSen give you wrong codec addresses
 				 * that don't exist
 				 */
-				snd_printk(KERN_WARNING
-					   "hda_intel: Codec #%d probe error; "
+				snd_printk(KERN_WARNING SFX
+					   "Codec #%d probe error; "
 					   "disabling it...\n", c);
 				chip->codec_mask &= ~(1 << c);
 				/* More badly, accessing to a non-existing
@@ -1487,7 +1542,7 @@
 	bufsize = snd_pcm_lib_buffer_bytes(substream);
 	period_bytes = snd_pcm_lib_period_bytes(substream);
 
-	snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
+	snd_printdd(SFX "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
 		    bufsize, format_val);
 
 	if (bufsize != azx_dev->bufsize ||
@@ -1830,7 +1885,7 @@
 			  &pcm);
 	if (err < 0)
 		return err;
-	strcpy(pcm->name, cpcm->name);
+	strlcpy(pcm->name, cpcm->name, sizeof(pcm->name));
 	apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
 	if (apcm == NULL)
 		return -ENOMEM;
@@ -1973,7 +2028,7 @@
 	for (i = 0; i < AZX_MAX_PCMS; i++)
 		snd_pcm_suspend_all(chip->pcm[i]);
 	if (chip->initialized)
-		snd_hda_suspend(chip->bus, state);
+		snd_hda_suspend(chip->bus);
 	azx_stop_chip(chip);
 	if (chip->irq >= 0) {
 		free_irq(chip->irq, chip);
@@ -2265,14 +2320,14 @@
 	synchronize_irq(chip->irq);
 
 	gcap = azx_readw(chip, GCAP);
-	snd_printdd("chipset global capabilities = 0x%x\n", gcap);
+	snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap);
 
 	/* ATI chips seems buggy about 64bit DMA addresses */
 	if (chip->driver_type == AZX_DRIVER_ATI)
-		gcap &= ~0x01;
+		gcap &= ~ICH6_GCAP_64OK;
 
 	/* allow 64bit DMA address if supported by H/W */
-	if ((gcap & 0x01) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
+	if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
 		pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
 	else {
 		pci_set_dma_mask(pci, DMA_BIT_MASK(32));
@@ -2309,7 +2364,7 @@
 	chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev),
 				GFP_KERNEL);
 	if (!chip->azx_dev) {
-		snd_printk(KERN_ERR "cannot malloc azx_dev\n");
+		snd_printk(KERN_ERR SFX "cannot malloc azx_dev\n");
 		goto errout;
 	}
 
@@ -2332,11 +2387,9 @@
 		goto errout;
 	}
 	/* allocate CORB/RIRB */
-	if (!chip->single_cmd) {
-		err = azx_alloc_cmd_io(chip);
-		if (err < 0)
-			goto errout;
-	}
+	err = azx_alloc_cmd_io(chip);
+	if (err < 0)
+		goto errout;
 
 	/* initialize streams */
 	azx_init_stream(chip);
@@ -2359,9 +2412,11 @@
 	}
 
 	strcpy(card->driver, "HDA-Intel");
-	strcpy(card->shortname, driver_short_names[chip->driver_type]);
-	sprintf(card->longname, "%s at 0x%lx irq %i",
-		card->shortname, chip->addr, chip->irq);
+	strlcpy(card->shortname, driver_short_names[chip->driver_type],
+		sizeof(card->shortname));
+	snprintf(card->longname, sizeof(card->longname),
+		 "%s at 0x%lx irq %i",
+		 card->shortname, chip->addr, chip->irq);
 
 	*rchip = chip;
 	return 0;
@@ -2514,6 +2569,20 @@
 	{ PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA },
 	/* Teradici */
 	{ PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
+	/* Creative X-Fi (CA0110-IBG) */
+#if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE)
+	/* the following entry conflicts with snd-ctxfi driver,
+	 * as ctxfi driver mutates from HD-audio to native mode with
+	 * a special command sequence.
+	 */
+	{ PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
+	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
+	  .class_mask = 0xffffff,
+	  .driver_data = AZX_DRIVER_GENERIC },
+#else
+	/* this entry seems still valid -- i.e. without emu20kx chip */
+	{ PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC },
+#endif
 	/* AMD Generic, PCI class code and Vendor ID for HD Audio */
 	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
 	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 93d7499..418c5d1 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -466,8 +466,12 @@
 	hda_nid_t nid;
 	int i, nodes;
 
-	snd_iprintf(buffer, "Codec: %s\n",
-		    codec->name ? codec->name : "Not Set");
+	snd_iprintf(buffer, "Codec: ");
+	if (codec->vendor_name && codec->chip_name)
+		snd_iprintf(buffer, "%s %s\n",
+			    codec->vendor_name, codec->chip_name);
+	else
+		snd_iprintf(buffer, "Not Set\n");
 	snd_iprintf(buffer, "Address: %d\n", codec->addr);
 	snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id);
 	snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id);
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c
new file mode 100644
index 0000000..392d108
--- /dev/null
+++ b/sound/pci/hda/patch_ca0110.c
@@ -0,0 +1,573 @@
+/*
+ * HD audio interface patch for Creative X-Fi CA0110-IBG chip
+ *
+ * Copyright (c) 2008 Takashi Iwai <tiwai@suse.de>
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the 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 driver is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+/*
+ */
+
+struct ca0110_spec {
+	struct auto_pin_cfg autocfg;
+	struct hda_multi_out multiout;
+	hda_nid_t out_pins[AUTO_CFG_MAX_OUTS];
+	hda_nid_t dacs[AUTO_CFG_MAX_OUTS];
+	hda_nid_t hp_dac;
+	hda_nid_t input_pins[AUTO_PIN_LAST];
+	hda_nid_t adcs[AUTO_PIN_LAST];
+	hda_nid_t dig_out;
+	hda_nid_t dig_in;
+	unsigned int num_inputs;
+	const char *input_labels[AUTO_PIN_LAST];
+	struct hda_pcm pcm_rec[2];	/* PCM information */
+};
+
+/*
+ * PCM callbacks
+ */
+static int ca0110_playback_pcm_open(struct hda_pcm_stream *hinfo,
+				    struct hda_codec *codec,
+				    struct snd_pcm_substream *substream)
+{
+	struct ca0110_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+					     hinfo);
+}
+
+static int ca0110_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       unsigned int stream_tag,
+				       unsigned int format,
+				       struct snd_pcm_substream *substream)
+{
+	struct ca0110_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
+						stream_tag, format, substream);
+}
+
+static int ca0110_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       struct snd_pcm_substream *substream)
+{
+	struct ca0110_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int ca0110_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					struct snd_pcm_substream *substream)
+{
+	struct ca0110_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int ca0110_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+					 struct hda_codec *codec,
+					 struct snd_pcm_substream *substream)
+{
+	struct ca0110_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int ca0110_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					   struct hda_codec *codec,
+					   unsigned int stream_tag,
+					   unsigned int format,
+					   struct snd_pcm_substream *substream)
+{
+	struct ca0110_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
+					     format, substream);
+}
+
+/*
+ * Analog capture
+ */
+static int ca0110_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      unsigned int stream_tag,
+				      unsigned int format,
+				      struct snd_pcm_substream *substream)
+{
+	struct ca0110_spec *spec = codec->spec;
+
+	snd_hda_codec_setup_stream(codec, spec->adcs[substream->number],
+				   stream_tag, 0, format);
+	return 0;
+}
+
+static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      struct snd_pcm_substream *substream)
+{
+	struct ca0110_spec *spec = codec->spec;
+
+	snd_hda_codec_cleanup_stream(codec, spec->adcs[substream->number]);
+	return 0;
+}
+
+/*
+ */
+
+static char *dirstr[2] = { "Playback", "Capture" };
+
+static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
+		       int chan, int dir)
+{
+	char namestr[44];
+	int type = dir ? HDA_INPUT : HDA_OUTPUT;
+	struct snd_kcontrol_new knew =
+		HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type);
+	sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
+	return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+}
+
+static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
+		       int chan, int dir)
+{
+	char namestr[44];
+	int type = dir ? HDA_INPUT : HDA_OUTPUT;
+	struct snd_kcontrol_new knew =
+		HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type);
+	sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]);
+	return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+}
+
+#define add_out_switch(codec, nid, pfx)	_add_switch(codec, nid, pfx, 3, 0)
+#define add_out_volume(codec, nid, pfx)	_add_volume(codec, nid, pfx, 3, 0)
+#define add_in_switch(codec, nid, pfx)	_add_switch(codec, nid, pfx, 3, 1)
+#define add_in_volume(codec, nid, pfx)	_add_volume(codec, nid, pfx, 3, 1)
+#define add_mono_switch(codec, nid, pfx, chan) \
+	_add_switch(codec, nid, pfx, chan, 0)
+#define add_mono_volume(codec, nid, pfx, chan) \
+	_add_volume(codec, nid, pfx, chan, 0)
+
+static int ca0110_build_controls(struct hda_codec *codec)
+{
+	struct ca0110_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	static char *prefix[AUTO_CFG_MAX_OUTS] = {
+		"Front", "Surround", NULL, "Side", "Multi"
+	};
+	hda_nid_t mutenid;
+	int i, err;
+
+	for (i = 0; i < spec->multiout.num_dacs; i++) {
+		if (get_wcaps(codec, spec->out_pins[i]) & AC_WCAP_OUT_AMP)
+			mutenid = spec->out_pins[i];
+		else
+			mutenid = spec->multiout.dac_nids[i];
+		if (!prefix[i]) {
+			err = add_mono_switch(codec, mutenid,
+					      "Center", 1);
+			if (err < 0)
+				return err;
+			err = add_mono_switch(codec, mutenid,
+					      "LFE", 1);
+			if (err < 0)
+				return err;
+			err = add_mono_volume(codec, spec->multiout.dac_nids[i],
+					      "Center", 1);
+			if (err < 0)
+				return err;
+			err = add_mono_volume(codec, spec->multiout.dac_nids[i],
+					      "LFE", 1);
+			if (err < 0)
+				return err;
+		} else {
+			err = add_out_switch(codec, mutenid,
+					     prefix[i]);
+			if (err < 0)
+				return err;
+			err = add_out_volume(codec, spec->multiout.dac_nids[i],
+					 prefix[i]);
+			if (err < 0)
+				return err;
+		}
+	}
+	if (cfg->hp_outs) {
+		if (get_wcaps(codec, cfg->hp_pins[0]) & AC_WCAP_OUT_AMP)
+			mutenid = cfg->hp_pins[0];
+		else
+			mutenid = spec->multiout.dac_nids[i];
+
+		err = add_out_switch(codec, mutenid, "Headphone");
+		if (err < 0)
+			return err;
+		if (spec->hp_dac) {
+			err = add_out_volume(codec, spec->hp_dac, "Headphone");
+			if (err < 0)
+				return err;
+		}
+	}
+	for (i = 0; i < spec->num_inputs; i++) {
+		const char *label = spec->input_labels[i];
+		if (get_wcaps(codec, spec->input_pins[i]) & AC_WCAP_IN_AMP)
+			mutenid = spec->input_pins[i];
+		else
+			mutenid = spec->adcs[i];
+		err = add_in_switch(codec, mutenid, label);
+		if (err < 0)
+			return err;
+		err = add_in_volume(codec, spec->adcs[i], label);
+		if (err < 0)
+			return err;
+	}
+
+	if (spec->dig_out) {
+		err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out);
+		if (err < 0)
+			return err;
+		err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
+		if (err < 0)
+			return err;
+		spec->multiout.share_spdif = 1;
+	}
+	if (spec->dig_in) {
+		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
+		if (err < 0)
+			return err;
+		err = add_in_volume(codec, spec->dig_in, "IEC958");
+	}
+	return 0;
+}
+
+/*
+ */
+static struct hda_pcm_stream ca0110_pcm_analog_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 8,
+	.ops = {
+		.open = ca0110_playback_pcm_open,
+		.prepare = ca0110_playback_pcm_prepare,
+		.cleanup = ca0110_playback_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream ca0110_pcm_analog_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.ops = {
+		.prepare = ca0110_capture_pcm_prepare,
+		.cleanup = ca0110_capture_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream ca0110_pcm_digital_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.ops = {
+		.open = ca0110_dig_playback_pcm_open,
+		.close = ca0110_dig_playback_pcm_close,
+		.prepare = ca0110_dig_playback_pcm_prepare
+	},
+};
+
+static struct hda_pcm_stream ca0110_pcm_digital_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+};
+
+static int ca0110_build_pcms(struct hda_codec *codec)
+{
+	struct ca0110_spec *spec = codec->spec;
+	struct hda_pcm *info = spec->pcm_rec;
+
+	codec->pcm_info = info;
+	codec->num_pcms = 0;
+
+	info->name = "CA0110 Analog";
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0110_pcm_analog_playback;
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0];
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+		spec->multiout.max_channels;
+	info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0110_pcm_analog_capture;
+	info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs;
+	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
+	codec->num_pcms++;
+
+	if (!spec->dig_out && !spec->dig_in)
+		return 0;
+
+	info++;
+	info->name = "CA0110 Digital";
+	info->pcm_type = HDA_PCM_TYPE_SPDIF;
+	if (spec->dig_out) {
+		info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+			ca0110_pcm_digital_playback;
+		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out;
+	}
+	if (spec->dig_in) {
+		info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+			ca0110_pcm_digital_capture;
+		info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
+	}
+	codec->num_pcms++;
+
+	return 0;
+}
+
+static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
+{
+	if (pin) {
+		snd_hda_codec_write(codec, pin, 0,
+				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+		if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
+			snd_hda_codec_write(codec, pin, 0,
+					    AC_VERB_SET_AMP_GAIN_MUTE,
+					    AMP_OUT_UNMUTE);
+	}
+	if (dac)
+		snd_hda_codec_write(codec, dac, 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO);
+}
+
+static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
+{
+	if (pin) {
+		snd_hda_codec_write(codec, pin, 0,
+				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80);
+		if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
+			snd_hda_codec_write(codec, pin, 0,
+					    AC_VERB_SET_AMP_GAIN_MUTE,
+					    AMP_IN_UNMUTE(0));
+	}
+	if (adc)
+		snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				    AMP_IN_UNMUTE(0));
+}
+
+static int ca0110_init(struct hda_codec *codec)
+{
+	struct ca0110_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int i;
+
+	for (i = 0; i < spec->multiout.num_dacs; i++)
+		init_output(codec, spec->out_pins[i],
+			    spec->multiout.dac_nids[i]);
+	init_output(codec, cfg->hp_pins[0], spec->hp_dac);
+	init_output(codec, cfg->dig_out_pins[0], spec->dig_out);
+
+	for (i = 0; i < spec->num_inputs; i++)
+		init_input(codec, spec->input_pins[i], spec->adcs[i]);
+	init_input(codec, cfg->dig_in_pin, spec->dig_in);
+	return 0;
+}
+
+static void ca0110_free(struct hda_codec *codec)
+{
+	kfree(codec->spec);
+}
+
+static struct hda_codec_ops ca0110_patch_ops = {
+	.build_controls = ca0110_build_controls,
+	.build_pcms = ca0110_build_pcms,
+	.init = ca0110_init,
+	.free = ca0110_free,
+};
+
+
+static void parse_line_outs(struct hda_codec *codec)
+{
+	struct ca0110_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int i, n;
+	unsigned int def_conf;
+	hda_nid_t nid;
+
+	n = 0;
+	for (i = 0; i < cfg->line_outs; i++) {
+		nid = cfg->line_out_pins[i];
+		def_conf = snd_hda_codec_get_pincfg(codec, nid);
+		if (!def_conf)
+			continue; /* invalid pin */
+		if (snd_hda_get_connections(codec, nid, &spec->dacs[i], 1) != 1)
+			continue;
+		spec->out_pins[n++] = nid;
+	}
+	spec->multiout.dac_nids = spec->dacs;
+	spec->multiout.num_dacs = n;
+	spec->multiout.max_channels = n * 2;
+}
+
+static void parse_hp_out(struct hda_codec *codec)
+{
+	struct ca0110_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int i;
+	unsigned int def_conf;
+	hda_nid_t nid, dac;
+
+	if (!cfg->hp_outs)
+		return;
+	nid = cfg->hp_pins[0];
+	def_conf = snd_hda_codec_get_pincfg(codec, nid);
+	if (!def_conf) {
+		cfg->hp_outs = 0;
+		return;
+	}
+	if (snd_hda_get_connections(codec, nid, &dac, 1) != 1)
+		return;
+
+	for (i = 0; i < cfg->line_outs; i++)
+		if (dac == spec->dacs[i])
+			break;
+	if (i >= cfg->line_outs) {
+		spec->hp_dac = dac;
+		spec->multiout.hp_nid = dac;
+	}
+}
+
+static void parse_input(struct hda_codec *codec)
+{
+	struct ca0110_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	hda_nid_t nid, pin;
+	int n, i, j;
+
+	n = 0;
+	nid = codec->start_nid;
+	for (i = 0; i < codec->num_nodes; i++, nid++) {
+		unsigned int wcaps = get_wcaps(codec, nid);
+		unsigned int type = (wcaps & AC_WCAP_TYPE) >>
+			AC_WCAP_TYPE_SHIFT;
+		if (type != AC_WID_AUD_IN)
+			continue;
+		if (snd_hda_get_connections(codec, nid, &pin, 1) != 1)
+			continue;
+		if (pin == cfg->dig_in_pin) {
+			spec->dig_in = nid;
+			continue;
+		}
+		for (j = 0; j < AUTO_PIN_LAST; j++)
+			if (cfg->input_pins[j] == pin)
+				break;
+		if (j >= AUTO_PIN_LAST)
+			continue;
+		spec->input_pins[n] = pin;
+		spec->input_labels[n] = auto_pin_cfg_labels[j];
+		spec->adcs[n] = nid;
+		n++;
+	}
+	spec->num_inputs = n;
+}
+
+static void parse_digital(struct hda_codec *codec)
+{
+	struct ca0110_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+
+	if (cfg->dig_outs &&
+	    snd_hda_get_connections(codec, cfg->dig_out_pins[0],
+				    &spec->dig_out, 1) == 1)
+		spec->multiout.dig_out_nid = cfg->dig_out_pins[0];
+}
+
+static int ca0110_parse_auto_config(struct hda_codec *codec)
+{
+	struct ca0110_spec *spec = codec->spec;
+	int err;
+
+	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+	if (err < 0)
+		return err;
+
+	parse_line_outs(codec);
+	parse_hp_out(codec);
+	parse_digital(codec);
+	parse_input(codec);
+	return 0;
+}
+
+
+int patch_ca0110(struct hda_codec *codec)
+{
+	struct ca0110_spec *spec;
+	int err;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (!spec)
+		return -ENOMEM;
+	codec->spec = spec;
+
+	codec->bus->needs_damn_long_delay = 1;
+
+	err = ca0110_parse_auto_config(codec);
+	if (err < 0)
+		goto error;
+
+	codec->patch_ops = ca0110_patch_ops;
+
+	return 0;
+
+ error:
+	kfree(codec->spec);
+	codec->spec = NULL;
+	return err;
+}
+
+
+/*
+ * patch entries
+ */
+static struct hda_codec_preset snd_hda_preset_ca0110[] = {
+	{ .id = 0x1102000a, .name = "CA0110-IBG", .patch = patch_ca0110 },
+	{ .id = 0x1102000b, .name = "CA0110-IBG", .patch = patch_ca0110 },
+	{ .id = 0x1102000d, .name = "SB0880 X-Fi", .patch = patch_ca0110 },
+	{} /* terminator */
+};
+
+MODULE_ALIAS("snd-hda-codec-id:1102000a");
+MODULE_ALIAS("snd-hda-codec-id:1102000b");
+MODULE_ALIAS("snd-hda-codec-id:1102000d");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec");
+
+static struct hda_codec_preset_list ca0110_list = {
+	.preset = snd_hda_preset_ca0110,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_ca0110_init(void)
+{
+	return snd_hda_add_codec_preset(&ca0110_list);
+}
+
+static void __exit patch_ca0110_exit(void)
+{
+	snd_hda_delete_codec_preset(&ca0110_list);
+}
+
+module_init(patch_ca0110_init)
+module_exit(patch_ca0110_exit)
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c
index d57d813..f5792e2 100644
--- a/sound/pci/hda/patch_nvhdmi.c
+++ b/sound/pci/hda/patch_nvhdmi.c
@@ -35,9 +35,28 @@
 	struct hda_pcm pcm_rec;
 };
 
+#define Nv_VERB_SET_Channel_Allocation          0xF79
+#define Nv_VERB_SET_Info_Frame_Checksum         0xF7A
+#define Nv_VERB_SET_Audio_Protection_On         0xF98
+#define Nv_VERB_SET_Audio_Protection_Off        0xF99
+
+#define Nv_Master_Convert_nid   0x04
+#define Nv_Master_Pin_nid       0x05
+
+static hda_nid_t nvhdmi_convert_nids[4] = {
+	/*front, rear, clfe, rear_surr */
+	0x6, 0x8, 0xa, 0xc,
+};
+
 static struct hda_verb nvhdmi_basic_init[] = {
+	/* set audio protect on */
+	{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
 	/* enable digital output on pin widget */
-	{ 0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+	{ 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+	{ 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+	{ 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+	{ 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
 	{} /* terminator */
 };
 
@@ -66,48 +85,205 @@
  * Digital out
  */
 static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
-				     struct hda_codec *codec,
-				     struct snd_pcm_substream *substream)
+					struct hda_codec *codec,
+					struct snd_pcm_substream *substream)
 {
 	struct nvhdmi_spec *spec = codec->spec;
 	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
 }
 
-static int nvhdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
-				      struct hda_codec *codec,
-				      struct snd_pcm_substream *substream)
+static int nvhdmi_dig_playback_pcm_close_8ch(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					struct snd_pcm_substream *substream)
+{
+	struct nvhdmi_spec *spec = codec->spec;
+	int i;
+
+	snd_hda_codec_write(codec, Nv_Master_Convert_nid,
+			0, AC_VERB_SET_CHANNEL_STREAMID, 0);
+	for (i = 0; i < 4; i++) {
+		/* set the stream id */
+		snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0,
+				AC_VERB_SET_CHANNEL_STREAMID, 0);
+		/* set the stream format */
+		snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0,
+				AC_VERB_SET_STREAM_FORMAT, 0);
+	}
+
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					struct snd_pcm_substream *substream)
 {
 	struct nvhdmi_spec *spec = codec->spec;
 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
-static int nvhdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-					    struct hda_codec *codec,
-					    unsigned int stream_tag,
-					    unsigned int format,
-					    struct snd_pcm_substream *substream)
+static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					unsigned int stream_tag,
+					unsigned int format,
+					struct snd_pcm_substream *substream)
+{
+	int chs;
+	unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id;
+	int i;
+
+	mutex_lock(&codec->spdif_mutex);
+
+	chs = substream->runtime->channels;
+	chan = chs ? (chs - 1) : 1;
+
+	switch (chs) {
+	default:
+	case 0:
+	case 2:
+		chanmask = 0x00;
+		break;
+	case 4:
+		chanmask = 0x08;
+		break;
+	case 6:
+		chanmask = 0x0b;
+		break;
+	case 8:
+		chanmask = 0x13;
+		break;
+	}
+	dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT;
+	dataDCC2 = 0x2;
+
+	/* set the Audio InforFrame Channel Allocation */
+	snd_hda_codec_write(codec, 0x1, 0,
+			Nv_VERB_SET_Channel_Allocation, chanmask);
+
+	/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
+	if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+		snd_hda_codec_write(codec,
+				Nv_Master_Convert_nid,
+				0,
+				AC_VERB_SET_DIGI_CONVERT_1,
+				codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+
+	/* set the stream id */
+	snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0,
+			AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
+
+	/* set the stream format */
+	snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0,
+			AC_VERB_SET_STREAM_FORMAT, format);
+
+	/* turn on again (if needed) */
+	/* enable and set the channel status audio/data flag */
+	if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
+		snd_hda_codec_write(codec,
+				Nv_Master_Convert_nid,
+				0,
+				AC_VERB_SET_DIGI_CONVERT_1,
+				codec->spdif_ctls & 0xff);
+		snd_hda_codec_write(codec,
+				Nv_Master_Convert_nid,
+				0,
+				AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (chs == 2)
+			channel_id = 0;
+		else
+			channel_id = i * 2;
+
+		/* turn off SPDIF once;
+		 *otherwise the IEC958 bits won't be updated
+		 */
+		if (codec->spdif_status_reset &&
+		(codec->spdif_ctls & AC_DIG1_ENABLE))
+			snd_hda_codec_write(codec,
+				nvhdmi_convert_nids[i],
+				0,
+				AC_VERB_SET_DIGI_CONVERT_1,
+				codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+		/* set the stream id */
+		snd_hda_codec_write(codec,
+				nvhdmi_convert_nids[i],
+				0,
+				AC_VERB_SET_CHANNEL_STREAMID,
+				(stream_tag << 4) | channel_id);
+		/* set the stream format */
+		snd_hda_codec_write(codec,
+				nvhdmi_convert_nids[i],
+				0,
+				AC_VERB_SET_STREAM_FORMAT,
+				format);
+		/* turn on again (if needed) */
+		/* enable and set the channel status audio/data flag */
+		if (codec->spdif_status_reset &&
+		(codec->spdif_ctls & AC_DIG1_ENABLE)) {
+			snd_hda_codec_write(codec,
+					nvhdmi_convert_nids[i],
+					0,
+					AC_VERB_SET_DIGI_CONVERT_1,
+					codec->spdif_ctls & 0xff);
+			snd_hda_codec_write(codec,
+					nvhdmi_convert_nids[i],
+					0,
+					AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+		}
+	}
+
+	/* set the Audio Info Frame Checksum */
+	snd_hda_codec_write(codec, 0x1, 0,
+			Nv_VERB_SET_Info_Frame_Checksum,
+			(0x71 - chan - chanmask));
+
+	mutex_unlock(&codec->spdif_mutex);
+	return 0;
+}
+
+static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					unsigned int stream_tag,
+					unsigned int format,
+					struct snd_pcm_substream *substream)
 {
 	struct nvhdmi_spec *spec = codec->spec;
 	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
-					     format, substream);
+					format, substream);
 }
 
-static struct hda_pcm_stream nvhdmi_pcm_digital_playback = {
+static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch = {
 	.substreams = 1,
 	.channels_min = 2,
-	.channels_max = 2,
-	.nid = 0x4, /* NID to query formats and rates and setup streams */
+	.channels_max = 8,
+	.nid = Nv_Master_Convert_nid,
 	.rates = SNDRV_PCM_RATE_48000,
 	.maxbps = 16,
 	.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	.ops = {
 		.open = nvhdmi_dig_playback_pcm_open,
-		.close = nvhdmi_dig_playback_pcm_close,
-		.prepare = nvhdmi_dig_playback_pcm_prepare
+		.close = nvhdmi_dig_playback_pcm_close_8ch,
+		.prepare = nvhdmi_dig_playback_pcm_prepare_8ch
 	},
 };
 
-static int nvhdmi_build_pcms(struct hda_codec *codec)
+static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = Nv_Master_Convert_nid,
+	.rates = SNDRV_PCM_RATE_48000,
+	.maxbps = 16,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.ops = {
+		.open = nvhdmi_dig_playback_pcm_open,
+		.close = nvhdmi_dig_playback_pcm_close_2ch,
+		.prepare = nvhdmi_dig_playback_pcm_prepare_2ch
+	},
+};
+
+static int nvhdmi_build_pcms_8ch(struct hda_codec *codec)
 {
 	struct nvhdmi_spec *spec = codec->spec;
 	struct hda_pcm *info = &spec->pcm_rec;
@@ -117,7 +293,24 @@
 
 	info->name = "NVIDIA HDMI";
 	info->pcm_type = HDA_PCM_TYPE_HDMI;
-	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = nvhdmi_pcm_digital_playback;
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK]
+					= nvhdmi_pcm_digital_playback_8ch;
+
+	return 0;
+}
+
+static int nvhdmi_build_pcms_2ch(struct hda_codec *codec)
+{
+	struct nvhdmi_spec *spec = codec->spec;
+	struct hda_pcm *info = &spec->pcm_rec;
+
+	codec->num_pcms = 1;
+	codec->pcm_info = info;
+
+	info->name = "NVIDIA HDMI";
+	info->pcm_type = HDA_PCM_TYPE_HDMI;
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK]
+					= nvhdmi_pcm_digital_playback_2ch;
 
 	return 0;
 }
@@ -127,14 +320,21 @@
 	kfree(codec->spec);
 }
 
-static struct hda_codec_ops nvhdmi_patch_ops = {
+static struct hda_codec_ops nvhdmi_patch_ops_8ch = {
 	.build_controls = nvhdmi_build_controls,
-	.build_pcms = nvhdmi_build_pcms,
+	.build_pcms = nvhdmi_build_pcms_8ch,
 	.init = nvhdmi_init,
 	.free = nvhdmi_free,
 };
 
-static int patch_nvhdmi(struct hda_codec *codec)
+static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
+	.build_controls = nvhdmi_build_controls,
+	.build_pcms = nvhdmi_build_pcms_2ch,
+	.init = nvhdmi_init,
+	.free = nvhdmi_free,
+};
+
+static int patch_nvhdmi_8ch(struct hda_codec *codec)
 {
 	struct nvhdmi_spec *spec;
 
@@ -144,13 +344,30 @@
 
 	codec->spec = spec;
 
-	spec->multiout.num_dacs = 0;	  /* no analog */
-	spec->multiout.max_channels = 2;
-	spec->multiout.dig_out_nid = 0x4; /* NID for copying analog to digital,
-					   * seems to be unused in pure-digital
-					   * case. */
+	spec->multiout.num_dacs = 0;  /* no analog */
+	spec->multiout.max_channels = 8;
+	spec->multiout.dig_out_nid = Nv_Master_Convert_nid;
 
-	codec->patch_ops = nvhdmi_patch_ops;
+	codec->patch_ops = nvhdmi_patch_ops_8ch;
+
+	return 0;
+}
+
+static int patch_nvhdmi_2ch(struct hda_codec *codec)
+{
+	struct nvhdmi_spec *spec;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	spec->multiout.num_dacs = 0;  /* no analog */
+	spec->multiout.max_channels = 2;
+	spec->multiout.dig_out_nid = Nv_Master_Convert_nid;
+
+	codec->patch_ops = nvhdmi_patch_ops_2ch;
 
 	return 0;
 }
@@ -159,11 +376,11 @@
  * patch entries
  */
 static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
-	{ .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi },
-	{ .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi },
-	{ .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi },
-	{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi },
-	{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi },
+	{ .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch },
+	{ .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch },
+	{ .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch },
+	{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
+	{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
 	{} /* terminator */
 };
 
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 0fd258e..337d2a5 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -190,6 +190,7 @@
 	ALC663_ASUS_MODE6,
 	ALC272_DELL,
 	ALC272_DELL_ZM1,
+	ALC272_SAMSUNG_NC10,
 	ALC662_AUTO,
 	ALC662_MODEL_LAST,
 };
@@ -205,6 +206,7 @@
 	ALC882_ASUS_A7M,
 	ALC885_MACPRO,
 	ALC885_MBP3,
+	ALC885_MB5,
 	ALC885_IMAC24,
 	ALC882_AUTO,
 	ALC882_MODEL_LAST,
@@ -218,9 +220,11 @@
 	ALC883_6ST_DIG,
 	ALC883_TARGA_DIG,
 	ALC883_TARGA_2ch_DIG,
+	ALC883_TARGA_8ch_DIG,
 	ALC883_ACER,
 	ALC883_ACER_ASPIRE,
 	ALC888_ACER_ASPIRE_4930G,
+	ALC888_ACER_ASPIRE_8930G,
 	ALC883_MEDION,
 	ALC883_MEDION_MD2,
 	ALC883_LAPTOP_EAPD,
@@ -238,7 +242,9 @@
 	ALC883_3ST_6ch_INTEL,
 	ALC888_ASUS_M90V,
 	ALC888_ASUS_EEE1601,
+	ALC889A_MB31,
 	ALC1200_ASUS_P5Q,
+	ALC883_SONY_VAIO_TT,
 	ALC883_AUTO,
 	ALC883_MODEL_LAST,
 };
@@ -253,6 +259,15 @@
 /* for GPIO Poll */
 #define GPIO_MASK	0x03
 
+/* extra amp-initialization sequence types */
+enum {
+	ALC_INIT_NONE,
+	ALC_INIT_DEFAULT,
+	ALC_INIT_GPIO1,
+	ALC_INIT_GPIO2,
+	ALC_INIT_GPIO3,
+};
+
 struct alc_spec {
 	/* codec parameterization */
 	struct snd_kcontrol_new *mixers[5];	/* mixer arrays */
@@ -266,13 +281,13 @@
 						 */
 	unsigned int num_init_verbs;
 
-	char *stream_name_analog;	/* analog PCM stream */
+	char stream_name_analog[16];	/* analog PCM stream */
 	struct hda_pcm_stream *stream_analog_playback;
 	struct hda_pcm_stream *stream_analog_capture;
 	struct hda_pcm_stream *stream_analog_alt_playback;
 	struct hda_pcm_stream *stream_analog_alt_capture;
 
-	char *stream_name_digital;	/* digital PCM stream */
+	char stream_name_digital[16];	/* digital PCM stream */
 	struct hda_pcm_stream *stream_digital_playback;
 	struct hda_pcm_stream *stream_digital_capture;
 
@@ -301,6 +316,8 @@
 	const struct hda_channel_mode *channel_mode;
 	int num_channel_mode;
 	int need_dac_fix;
+	int const_channel_count;
+	int ext_channel_count;
 
 	/* PCM information */
 	struct hda_pcm pcm_rec[3];	/* used in alc_build_pcms() */
@@ -322,6 +339,7 @@
 
 	/* other flags */
 	unsigned int no_analog :1; /* digital I/O only */
+	int init_amp;
 
 	/* for virtual master */
 	hda_nid_t vmaster_nid;
@@ -355,6 +373,7 @@
 	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);
@@ -449,7 +468,7 @@
 	struct alc_spec *spec = codec->spec;
 	return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
 				   spec->num_channel_mode,
-				   spec->multiout.max_channels);
+				   spec->ext_channel_count);
 }
 
 static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
@@ -459,9 +478,12 @@
 	struct alc_spec *spec = codec->spec;
 	int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
 				      spec->num_channel_mode,
-				      &spec->multiout.max_channels);
-	if (err >= 0 && spec->need_dac_fix)
-		spec->multiout.num_dacs = spec->multiout.max_channels / 2;
+				      &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;
 }
 
@@ -841,8 +863,13 @@
 	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;
 
-	spec->multiout.max_channels = spec->channel_mode[0].channels;
+	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;
@@ -921,20 +948,26 @@
 	alc_fix_pll(codec);
 }
 
-static void alc_sku_automute(struct hda_codec *codec)
+static void alc_automute_pin(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	unsigned int present;
-	unsigned int hp_nid = spec->autocfg.hp_pins[0];
-	unsigned int sp_nid = spec->autocfg.speaker_pins[0];
+	unsigned int nid = spec->autocfg.hp_pins[0];
+	int i;
 
 	/* need to execute and sync at first */
-	snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
-	present = snd_hda_codec_read(codec, hp_nid, 0,
+	snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
+	present = snd_hda_codec_read(codec, nid, 0,
 				     AC_VERB_GET_PIN_SENSE, 0);
-	spec->jack_present = (present & 0x80000000) != 0;
-	snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    spec->jack_present ? 0 : PIN_OUT);
+	spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+	for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
+		nid = spec->autocfg.speaker_pins[i];
+		if (!nid)
+			break;
+		snd_hda_codec_write(codec, nid, 0,
+				    AC_VERB_SET_PIN_WIDGET_CONTROL,
+				    spec->jack_present ? 0 : PIN_OUT);
+	}
 }
 
 #if 0 /* it's broken in some acses -- temporarily disabled */
@@ -969,16 +1002,19 @@
 		res >>= 28;
 	else
 		res >>= 26;
-	if (res == ALC880_HP_EVENT)
-		alc_sku_automute(codec);
-
-	if (res == ALC880_MIC_EVENT)
+	switch (res) {
+	case ALC880_HP_EVENT:
+		alc_automute_pin(codec);
+		break;
+	case ALC880_MIC_EVENT:
 		alc_mic_automute(codec);
+		break;
+	}
 }
 
 static void alc_inithook(struct hda_codec *codec)
 {
-	alc_sku_automute(codec);
+	alc_automute_pin(codec);
 	alc_mic_automute(codec);
 }
 
@@ -1000,69 +1036,21 @@
 				    AC_VERB_SET_PROC_COEF, 0x3030);
 }
 
-/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
- *	31 ~ 16 :	Manufacture ID
- *	15 ~ 8	:	SKU ID
- *	7  ~ 0	:	Assembly ID
- *	port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
- */
-static void alc_subsystem_id(struct hda_codec *codec,
-			     unsigned int porta, unsigned int porte,
-			     unsigned int portd)
+static void alc_auto_init_amp(struct hda_codec *codec, int type)
 {
-	unsigned int ass, tmp, i;
-	unsigned nid;
-	struct alc_spec *spec = codec->spec;
+	unsigned int tmp;
 
-	ass = codec->subsystem_id & 0xffff;
-	if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
-		goto do_sku;
-
-	/*
-	 * 31~30	: port conetcivity
-	 * 29~21	: reserve
-	 * 20		: PCBEEP input
-	 * 19~16	: Check sum (15:1)
-	 * 15~1		: Custom
-	 * 0		: override
-	*/
-	nid = 0x1d;
-	if (codec->vendor_id == 0x10ec0260)
-		nid = 0x17;
-	ass = snd_hda_codec_get_pincfg(codec, nid);
-	if (!(ass & 1) && !(ass & 0x100000))
-		return;
-	if ((ass >> 30) != 1)	/* no physical connection */
-		return;
-
-	/* check sum */
-	tmp = 0;
-	for (i = 1; i < 16; i++) {
-		if ((ass >> i) & 1)
-			tmp++;
-	}
-	if (((ass >> 16) & 0xf) != tmp)
-		return;
-do_sku:
-	/*
-	 * 0 : override
-	 * 1 :	Swap Jack
-	 * 2 : 0 --> Desktop, 1 --> Laptop
-	 * 3~5 : External Amplifier control
-	 * 7~6 : Reserved
-	*/
-	tmp = (ass & 0x38) >> 3;	/* external Amp control */
-	switch (tmp) {
-	case 1:
+	switch (type) {
+	case ALC_INIT_GPIO1:
 		snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
 		break;
-	case 3:
+	case ALC_INIT_GPIO2:
 		snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
 		break;
-	case 7:
+	case ALC_INIT_GPIO3:
 		snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
 		break;
-	case 5:	/* set EAPD output high */
+	case ALC_INIT_DEFAULT:
 		switch (codec->vendor_id) {
 		case 0x10ec0260:
 			snd_hda_codec_write(codec, 0x0f, 0,
@@ -1116,7 +1104,7 @@
 					    tmp | 0x2010);
 			break;
 		case 0x10ec0888:
-			/*alc888_coef_init(codec);*/ /* called in alc_init() */
+			alc888_coef_init(codec);
 			break;
 		case 0x10ec0267:
 		case 0x10ec0268:
@@ -1131,7 +1119,107 @@
 					    tmp | 0x3000);
 			break;
 		}
-	default:
+		break;
+	}
+}
+
+static void alc_init_auto_hp(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (!spec->autocfg.hp_pins[0])
+		return;
+
+	if (!spec->autocfg.speaker_pins[0]) {
+		if (spec->autocfg.line_out_pins[0] &&
+		    spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
+			spec->autocfg.speaker_pins[0] =
+				spec->autocfg.line_out_pins[0];
+		else
+			return;
+	}
+
+	snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
+		    spec->autocfg.hp_pins[0]);
+	snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0,
+				  AC_VERB_SET_UNSOLICITED_ENABLE,
+				  AC_USRSP_EN | ALC880_HP_EVENT);
+	spec->unsol_event = alc_sku_unsol_event;
+}
+
+/* check subsystem ID and set up device-specific initialization;
+ * return 1 if initialized, 0 if invalid SSID
+ */
+/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
+ *	31 ~ 16 :	Manufacture ID
+ *	15 ~ 8	:	SKU ID
+ *	7  ~ 0	:	Assembly ID
+ *	port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
+ */
+static int alc_subsystem_id(struct hda_codec *codec,
+			    hda_nid_t porta, hda_nid_t porte,
+			    hda_nid_t portd)
+{
+	unsigned int ass, tmp, i;
+	unsigned nid;
+	struct alc_spec *spec = codec->spec;
+
+	ass = codec->subsystem_id & 0xffff;
+	if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
+		goto do_sku;
+
+	/* invalid SSID, check the special NID pin defcfg instead */
+	/*
+	 * 31~30	: port conetcivity
+	 * 29~21	: reserve
+	 * 20		: PCBEEP input
+	 * 19~16	: Check sum (15:1)
+	 * 15~1		: Custom
+	 * 0		: override
+	*/
+	nid = 0x1d;
+	if (codec->vendor_id == 0x10ec0260)
+		nid = 0x17;
+	ass = snd_hda_codec_get_pincfg(codec, nid);
+	snd_printd("realtek: No valid SSID, "
+		   "checking pincfg 0x%08x for NID 0x%x\n",
+		   ass, nid);
+	if (!(ass & 1) && !(ass & 0x100000))
+		return 0;
+	if ((ass >> 30) != 1)	/* no physical connection */
+		return 0;
+
+	/* check sum */
+	tmp = 0;
+	for (i = 1; i < 16; i++) {
+		if ((ass >> i) & 1)
+			tmp++;
+	}
+	if (((ass >> 16) & 0xf) != tmp)
+		return 0;
+do_sku:
+	snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
+		   ass & 0xffff, codec->vendor_id);
+	/*
+	 * 0 : override
+	 * 1 :	Swap Jack
+	 * 2 : 0 --> Desktop, 1 --> Laptop
+	 * 3~5 : External Amplifier control
+	 * 7~6 : Reserved
+	*/
+	tmp = (ass & 0x38) >> 3;	/* external Amp control */
+	switch (tmp) {
+	case 1:
+		spec->init_amp = ALC_INIT_GPIO1;
+		break;
+	case 3:
+		spec->init_amp = ALC_INIT_GPIO2;
+		break;
+	case 7:
+		spec->init_amp = ALC_INIT_GPIO3;
+		break;
+	case 5:
+		spec->init_amp = ALC_INIT_DEFAULT;
 		break;
 	}
 
@@ -1139,7 +1227,7 @@
 	 * when the external headphone out jack is plugged"
 	 */
 	if (!(ass & 0x8000))
-		return;
+		return 1;
 	/*
 	 * 10~8 : Jack location
 	 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
@@ -1147,14 +1235,6 @@
 	 * 15   : 1 --> enable the function "Mute internal speaker
 	 *	        when the external headphone out jack is plugged"
 	 */
-	if (!spec->autocfg.speaker_pins[0]) {
-		if (spec->autocfg.line_out_pins[0])
-			spec->autocfg.speaker_pins[0] =
-				spec->autocfg.line_out_pins[0];
-		else
-			return;
-	}
-
 	if (!spec->autocfg.hp_pins[0]) {
 		tmp = (ass >> 11) & 0x3;	/* HP to chassis */
 		if (tmp == 0)
@@ -1164,23 +1244,23 @@
 		else if (tmp == 2)
 			spec->autocfg.hp_pins[0] = portd;
 		else
-			return;
+			return 1;
 	}
-	if (spec->autocfg.hp_pins[0])
-		snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
-			AC_VERB_SET_UNSOLICITED_ENABLE,
-			AC_USRSP_EN | ALC880_HP_EVENT);
 
-#if 0 /* it's broken in some acses -- temporarily disabled */
-	if (spec->autocfg.input_pins[AUTO_PIN_MIC] &&
-		spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC])
-		snd_hda_codec_write(codec,
-			spec->autocfg.input_pins[AUTO_PIN_MIC], 0,
-			AC_VERB_SET_UNSOLICITED_ENABLE,
-			AC_USRSP_EN | ALC880_MIC_EVENT);
-#endif /* disabled */
+	alc_init_auto_hp(codec);
+	return 1;
+}
 
-	spec->unsol_event = alc_sku_unsol_event;
+static void alc_ssid_check(struct hda_codec *codec,
+			   hda_nid_t porta, hda_nid_t porte, hda_nid_t portd)
+{
+	if (!alc_subsystem_id(codec, porta, porte, portd)) {
+		struct alc_spec *spec = codec->spec;
+		snd_printd("realtek: "
+			   "Enable default setup for auto mode as fallback\n");
+		spec->init_amp = ALC_INIT_DEFAULT;
+		alc_init_auto_hp(codec);
+	}
 }
 
 /*
@@ -1315,32 +1395,58 @@
 	{}
 };
 
-static void alc888_fujitsu_xa3530_automute(struct hda_codec *codec)
+static void alc_automute_amp(struct hda_codec *codec)
 {
-	unsigned int present;
-	unsigned int bits;
-	/* Line out presence */
-	present = snd_hda_codec_read(codec, 0x17, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	/* HP out presence */
-	present = present || snd_hda_codec_read(codec, 0x1b, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	bits = present ? HDA_AMP_MUTE : 0;
+	struct alc_spec *spec = codec->spec;
+	unsigned int val, mute;
+	hda_nid_t nid;
+	int i;
+
+	spec->jack_present = 0;
+	for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
+		nid = spec->autocfg.hp_pins[i];
+		if (!nid)
+			break;
+		val = snd_hda_codec_read(codec, nid, 0,
+					 AC_VERB_GET_PIN_SENSE, 0);
+		if (val & AC_PINSENSE_PRESENCE) {
+			spec->jack_present = 1;
+			break;
+		}
+	}
+
+	mute = spec->jack_present ? HDA_AMP_MUTE : 0;
 	/* Toggle internal speakers muting */
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	/* Toggle internal bass muting */
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
+	for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
+		nid = spec->autocfg.speaker_pins[i];
+		if (!nid)
+			break;
+		snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, mute);
+	}
 }
 
-static void alc888_fujitsu_xa3530_unsol_event(struct hda_codec *codec,
-		unsigned int res)
+static void alc_automute_amp_unsol_event(struct hda_codec *codec,
+					 unsigned int res)
 {
-	if (res >> 26 == ALC880_HP_EVENT)
-		alc888_fujitsu_xa3530_automute(codec);
+	if (codec->vendor_id == 0x10ec0880)
+		res >>= 28;
+	else
+		res >>= 26;
+	if (res == ALC880_HP_EVENT)
+		alc_automute_amp(codec);
 }
 
+static void alc888_fujitsu_xa3530_init_hook(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x17; /* line-out */
+	spec->autocfg.hp_pins[1] = 0x1b; /* hp */
+	spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
+	spec->autocfg.speaker_pins[1] = 0x15; /* bass */
+	alc_automute_amp(codec);
+}
 
 /*
  * ALC888 Acer Aspire 4930G model
@@ -1364,6 +1470,59 @@
 	{ }
 };
 
+/*
+ * ALC889 Acer Aspire 8930G model
+ */
+
+static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
+/* Front Mic: set to PIN_IN (empty by default) */
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Unselect Front Mic by default in input mixer 3 */
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
+/* Enable unsolicited event for HP jack */
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+/* Connect Internal Front to Front */
+	{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},
+/* Connect Internal Rear to Rear */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
+/* Connect Internal CLFE to CLFE */
+	{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},
+/* Connect HP out to Front */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+/* Enable all DACs */
+/*  DAC DISABLE/MUTE 1? */
+/*  setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
+	{0x20, AC_VERB_SET_COEF_INDEX, 0x03},
+	{0x20, AC_VERB_SET_PROC_COEF, 0x0000},
+/*  DAC DISABLE/MUTE 2? */
+/*  some bit here disables the other DACs. Init=0x4900 */
+	{0x20, AC_VERB_SET_COEF_INDEX, 0x08},
+	{0x20, AC_VERB_SET_PROC_COEF, 0x0000},
+/* Enable amplifiers */
+	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+/* DMIC fix
+ * This laptop has a stereo digital microphone. The mics are only 1cm apart
+ * which makes the stereo useless. However, either the mic or the ALC889
+ * makes the signal become a difference/sum signal instead of standard
+ * stereo, which is annoying. So instead we flip this bit which makes the
+ * codec replicate the sum signal to both channels, turning it into a
+ * normal mono mic.
+ */
+/*  DMIC_CONTROL? Init value = 0x0001 */
+	{0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
+	{0x20, AC_VERB_SET_PROC_COEF, 0x0003},
+	{ }
+};
+
 static struct hda_input_mux alc888_2_capture_sources[2] = {
 	/* Front mic only available on one ADC */
 	{
@@ -1385,6 +1544,38 @@
 	}
 };
 
+static struct hda_input_mux alc889_capture_sources[3] = {
+	/* Digital mic only available on first "ADC" */
+	{
+		.num_items = 5,
+		.items = {
+			{ "Mic", 0x0 },
+			{ "Line", 0x2 },
+			{ "CD", 0x4 },
+			{ "Front Mic", 0xb },
+			{ "Input Mix", 0xa },
+		},
+	},
+	{
+		.num_items = 4,
+		.items = {
+			{ "Mic", 0x0 },
+			{ "Line", 0x2 },
+			{ "CD", 0x4 },
+			{ "Input Mix", 0xa },
+		},
+	},
+	{
+		.num_items = 4,
+		.items = {
+			{ "Mic", 0x0 },
+			{ "Line", 0x2 },
+			{ "CD", 0x4 },
+			{ "Input Mix", 0xa },
+		},
+	}
+};
+
 static struct snd_kcontrol_new alc888_base_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -1407,22 +1598,24 @@
 	{ } /* end */
 };
 
-static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec)
+static void alc888_acer_aspire_4930g_init_hook(struct hda_codec *codec)
 {
-	unsigned int present;
-	unsigned int bits;
-	present = snd_hda_codec_read(codec, 0x15, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	alc_automute_amp(codec);
 }
 
-static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec,
-		unsigned int res)
+static void alc889_acer_aspire_8930g_init_hook(struct hda_codec *codec)
 {
-	if (res >> 26 == ALC880_HP_EVENT)
-		alc888_acer_aspire_4930g_automute(codec);
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[1] = 0x16;
+	spec->autocfg.speaker_pins[2] = 0x1b;
+	alc_automute_amp(codec);
 }
 
 /*
@@ -2390,21 +2583,6 @@
 	{ }
 };
 
-/* toggle speaker-output according to the hp-jack state */
-static void alc880_uniwill_hp_automute(struct hda_codec *codec)
-{
- 	unsigned int present;
-	unsigned char bits;
-
- 	present = snd_hda_codec_read(codec, 0x14, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
-
 /* auto-toggle front mic */
 static void alc880_uniwill_mic_automute(struct hda_codec *codec)
 {
@@ -2417,9 +2595,14 @@
 	snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
 }
 
-static void alc880_uniwill_automute(struct hda_codec *codec)
+static void alc880_uniwill_init_hook(struct hda_codec *codec)
 {
-	alc880_uniwill_hp_automute(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_automute_amp(codec);
 	alc880_uniwill_mic_automute(codec);
 }
 
@@ -2430,24 +2613,22 @@
 	 * definition.  4bit tag is placed at 28 bit!
 	 */
 	switch (res >> 28) {
-	case ALC880_HP_EVENT:
-		alc880_uniwill_hp_automute(codec);
-		break;
 	case ALC880_MIC_EVENT:
 		alc880_uniwill_mic_automute(codec);
 		break;
+	default:
+		alc_automute_amp_unsol_event(codec, res);
+		break;
 	}
 }
 
-static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
+static void alc880_uniwill_p53_init_hook(struct hda_codec *codec)
 {
- 	unsigned int present;
-	unsigned char bits;
+	struct alc_spec *spec = codec->spec;
 
- 	present = snd_hda_codec_read(codec, 0x14, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits);
+	spec->autocfg.hp_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	alc_automute_amp(codec);
 }
 
 static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
@@ -2469,10 +2650,10 @@
 	/* Looks like the unsol event is incompatible with the standard
 	 * definition.  4bit tag is placed at 28 bit!
 	 */
-	if ((res >> 28) == ALC880_HP_EVENT)
-		alc880_uniwill_p53_hp_automute(codec);
 	if ((res >> 28) == ALC880_DCVOL_EVENT)
 		alc880_uniwill_p53_dcvol_automute(codec);
+	else
+		alc_automute_amp_unsol_event(codec, res);
 }
 
 /*
@@ -2542,6 +2723,7 @@
 /* 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 struct hda_verb alc880_pin_clevo_init_verbs[] = {
@@ -2704,30 +2886,18 @@
 	{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 | 0x1},
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{ }
 };
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc880_lg_automute(struct hda_codec *codec)
+static void alc880_lg_init_hook(struct hda_codec *codec)
 {
-	unsigned int present;
-	unsigned char bits;
+	struct alc_spec *spec = codec->spec;
 
-	present = snd_hda_codec_read(codec, 0x1b, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc880_lg_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!
-	 */
-	if ((res >> 28) == 0x01)
-		alc880_lg_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x17;
+	alc_automute_amp(codec);
 }
 
 /*
@@ -2801,30 +2971,18 @@
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	/* jack sense */
-	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{ }
 };
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc880_lg_lw_automute(struct hda_codec *codec)
+static void alc880_lg_lw_init_hook(struct hda_codec *codec)
 {
-	unsigned int present;
-	unsigned char bits;
+	struct alc_spec *spec = codec->spec;
 
-	present = snd_hda_codec_read(codec, 0x1b, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc880_lg_lw_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!
-	 */
-	if ((res >> 28) == 0x01)
-		alc880_lg_lw_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	alc_automute_amp(codec);
 }
 
 static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
@@ -2871,16 +3029,10 @@
 /* toggle speaker-output according to the hp-jack state */
 static void alc880_medion_rim_automute(struct hda_codec *codec)
 {
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_codec_read(codec, 0x14, 0,
-				     AC_VERB_GET_PIN_SENSE, 0)
-		& AC_PINSENSE_PRESENCE;
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	if (present)
+	struct alc_spec *spec = codec->spec;
+	alc_automute_amp(codec);
+	/* toggle EAPD */
+	if (spec->jack_present)
 		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
 	else
 		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
@@ -2896,6 +3048,15 @@
 		alc880_medion_rim_automute(codec);
 }
 
+static void alc880_medion_rim_init_hook(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x1b;
+	alc880_medion_rim_automute(codec);
+}
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static struct hda_amp_list alc880_loopbacks[] = {
 	{ 0x0b, HDA_INPUT, 0 },
@@ -2924,8 +3085,7 @@
 	unsigned int i;
 
 	alc_fix_pll(codec);
-	if (codec->vendor_id == 0x10ec0888)
-		alc888_coef_init(codec);
+	alc_auto_init_amp(codec, spec->init_amp);
 
 	for (i = 0; i < spec->num_init_verbs; i++)
 		snd_hda_sequence_write(codec, spec->init_verbs[i]);
@@ -3127,7 +3287,10 @@
 	if (spec->no_analog)
 		goto skip_analog;
 
+	snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
+		 "%s Analog", codec->chip_name);
 	info->name = spec->stream_name_analog;
+	
 	if (spec->stream_analog_playback) {
 		if (snd_BUG_ON(!spec->multiout.dac_nids))
 			return -EINVAL;
@@ -3153,6 +3316,9 @@
  skip_analog:
 	/* SPDIF for stream index #1 */
 	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+		snprintf(spec->stream_name_digital,
+			 sizeof(spec->stream_name_digital),
+			 "%s Digital", codec->chip_name);
 		codec->num_pcms = 2;
 	        codec->slave_dig_outs = spec->multiout.slave_dig_outs;
 		info = spec->pcm_rec + 1;
@@ -3755,7 +3921,7 @@
 		.channel_mode = alc880_2_jack_modes,
 		.input_mux = &alc880_f1734_capture_source,
 		.unsol_event = alc880_uniwill_p53_unsol_event,
-		.init_hook = alc880_uniwill_p53_hp_automute,
+		.init_hook = alc880_uniwill_p53_init_hook,
 	},
 	[ALC880_ASUS] = {
 		.mixers = { alc880_asus_mixer },
@@ -3832,7 +3998,7 @@
 		.need_dac_fix = 1,
 		.input_mux = &alc880_capture_source,
 		.unsol_event = alc880_uniwill_unsol_event,
-		.init_hook = alc880_uniwill_automute,
+		.init_hook = alc880_uniwill_init_hook,
 	},
 	[ALC880_UNIWILL_P53] = {
 		.mixers = { alc880_uniwill_p53_mixer },
@@ -3844,7 +4010,7 @@
 		.channel_mode = alc880_threestack_modes,
 		.input_mux = &alc880_capture_source,
 		.unsol_event = alc880_uniwill_p53_unsol_event,
-		.init_hook = alc880_uniwill_p53_hp_automute,
+		.init_hook = alc880_uniwill_p53_init_hook,
 	},
 	[ALC880_FUJITSU] = {
 		.mixers = { alc880_fujitsu_mixer },
@@ -3858,7 +4024,7 @@
 		.channel_mode = alc880_2_jack_modes,
 		.input_mux = &alc880_capture_source,
 		.unsol_event = alc880_uniwill_p53_unsol_event,
-		.init_hook = alc880_uniwill_p53_hp_automute,
+		.init_hook = alc880_uniwill_p53_init_hook,
 	},
 	[ALC880_CLEVO] = {
 		.mixers = { alc880_three_stack_mixer },
@@ -3883,8 +4049,8 @@
 		.channel_mode = alc880_lg_ch_modes,
 		.need_dac_fix = 1,
 		.input_mux = &alc880_lg_capture_source,
-		.unsol_event = alc880_lg_unsol_event,
-		.init_hook = alc880_lg_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc880_lg_init_hook,
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 		.loopbacks = alc880_lg_loopbacks,
 #endif
@@ -3899,8 +4065,8 @@
 		.num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
 		.channel_mode = alc880_lg_lw_modes,
 		.input_mux = &alc880_lg_lw_capture_source,
-		.unsol_event = alc880_lg_lw_unsol_event,
-		.init_hook = alc880_lg_lw_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc880_lg_lw_init_hook,
 	},
 	[ALC880_MEDION_RIM] = {
 		.mixers = { alc880_medion_rim_mixer },
@@ -3914,7 +4080,7 @@
 		.channel_mode = alc880_2_jack_modes,
 		.input_mux = &alc880_medion_rim_capture_source,
 		.unsol_event = alc880_medion_rim_unsol_event,
-		.init_hook = alc880_medion_rim_automute,
+		.init_hook = alc880_medion_rim_init_hook,
 	},
 #ifdef CONFIG_SND_DEBUG
 	[ALC880_TEST] = {
@@ -4199,7 +4365,6 @@
 	struct alc_spec *spec = codec->spec;
 	int i;
 
-	alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
 	for (i = 0; i < spec->autocfg.line_outs; i++) {
 		hda_nid_t nid = spec->autocfg.line_out_pins[i];
 		int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -4304,6 +4469,8 @@
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux[0];
 
+	alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+
 	return 1;
 }
 
@@ -4361,8 +4528,8 @@
 						  alc880_models,
 						  alc880_cfg_tbl);
 	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
-		       "trying auto-probe from BIOS...\n");
+		printk(KERN_INFO "hda_codec: Unknown model for %s, "
+		       "trying auto-probe from BIOS...\n", codec->chip_name);
 		board_config = ALC880_AUTO;
 	}
 
@@ -4389,12 +4556,10 @@
 	if (board_config != ALC880_AUTO)
 		setup_preset(spec, &alc880_presets[board_config]);
 
-	spec->stream_name_analog = "ALC880 Analog";
 	spec->stream_analog_playback = &alc880_pcm_analog_playback;
 	spec->stream_analog_capture = &alc880_pcm_analog_capture;
 	spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
 
-	spec->stream_name_digital = "ALC880 Digital";
 	spec->stream_digital_playback = &alc880_pcm_digital_playback;
 	spec->stream_digital_capture = &alc880_pcm_digital_capture;
 
@@ -5679,7 +5844,6 @@
 	struct alc_spec *spec = codec->spec;
 	hda_nid_t nid;
 
-	alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
 	nid = spec->autocfg.line_out_pins[0];
 	if (nid) {
 		int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -5789,6 +5953,8 @@
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux[0];
 
+	alc_ssid_check(codec, 0x10, 0x15, 0x0f);
+
 	return 1;
 }
 
@@ -6006,8 +6172,9 @@
 						  alc260_models,
 						  alc260_cfg_tbl);
 	if (board_config < 0) {
-		snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
-			   "trying auto-probe from BIOS...\n");
+		snd_printd(KERN_INFO "hda_codec: Unknown model for %s, "
+			   "trying auto-probe from BIOS...\n",
+			   codec->chip_name);
 		board_config = ALC260_AUTO;
 	}
 
@@ -6034,11 +6201,9 @@
 	if (board_config != ALC260_AUTO)
 		setup_preset(spec, &alc260_presets[board_config]);
 
-	spec->stream_name_analog = "ALC260 Analog";
 	spec->stream_analog_playback = &alc260_pcm_analog_playback;
 	spec->stream_analog_capture = &alc260_pcm_analog_capture;
 
-	spec->stream_name_digital = "ALC260 Digital";
 	spec->stream_digital_playback = &alc260_pcm_digital_playback;
 	spec->stream_digital_capture = &alc260_pcm_digital_capture;
 
@@ -6115,6 +6280,16 @@
 		{ "CD", 0x4 },
 	},
 };
+
+static struct hda_input_mux mb5_capture_source = {
+	.num_items = 3,
+	.items = {
+		{ "Mic", 0x1 },
+		{ "Line", 0x2 },
+		{ "CD", 0x4 },
+	},
+};
+
 /*
  * 2ch mode
  */
@@ -6202,6 +6377,34 @@
 	{ 6, alc885_mbp_ch6_init },
 };
 
+/*
+ * 2ch
+ * Speakers/Woofer/HP = Front
+ * LineIn = Input
+ */
+static 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 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 struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
+	{ 2, alc885_mb5_ch2_init },
+	{ 6, alc885_mb5_ch6_init },
+};
 
 /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
  *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
@@ -6244,6 +6447,25 @@
 	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
 	{ } /* end */
 };
+
+static 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("HP Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
+	HDA_BIND_MUTE   ("HP Playback Switch", 0x0f, 0x02, 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, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
+	{ } /* end */
+};
+
 static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -6471,6 +6693,55 @@
 	{ }
 };
 
+/* Macbook 5,1 */
+static 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},
+	/* 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(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)},
+	{ }
+};
+
 /* Macbook Pro rev3 */
 static struct hda_verb alc885_mbp3_init_verbs[] = {
 	/* Front mixer: unmute input/output amp left and right (volume = 0) */
@@ -6560,45 +6831,23 @@
 };
 
 /* Toggle speaker-output according to the hp-jack state */
-static void alc885_imac24_automute(struct hda_codec *codec)
+static void alc885_imac24_automute_init_hook(struct hda_codec *codec)
 {
- 	unsigned int present;
+	struct alc_spec *spec = codec->spec;
 
- 	present = snd_hda_codec_read(codec, 0x14, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-	snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+	spec->autocfg.hp_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x18;
+	spec->autocfg.speaker_pins[1] = 0x1a;
+	alc_automute_amp(codec);
 }
 
-/* Processes unsolicited events. */
-static void alc885_imac24_unsol_event(struct hda_codec *codec,
-				      unsigned int res)
+static void alc885_mbp3_init_hook(struct hda_codec *codec)
 {
-	/* Headphone insertion or removal. */
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc885_imac24_automute(codec);
-}
+	struct alc_spec *spec = codec->spec;
 
-static void alc885_mbp3_automute(struct hda_codec *codec)
-{
- 	unsigned int present;
-
- 	present = snd_hda_codec_read(codec, 0x15, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	snd_hda_codec_amp_stereo(codec, 0x14,  HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
-
-}
-static void alc885_mbp3_unsol_event(struct hda_codec *codec,
-				    unsigned int res)
-{
-	/* Headphone insertion or removal. */
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc885_mbp3_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	alc_automute_amp(codec);
 }
 
 
@@ -6623,24 +6872,25 @@
 /* toggle speaker-output according to the hp-jack state */
 static void alc882_targa_automute(struct hda_codec *codec)
 {
- 	unsigned int present;
-
- 	present = snd_hda_codec_read(codec, 0x14, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+	struct alc_spec *spec = codec->spec;
+	alc_automute_amp(codec);
 	snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
-				  present ? 1 : 3);
+				  spec->jack_present ? 1 : 3);
+}
+
+static void alc882_targa_init_hook(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x1b;
+	alc882_targa_automute(codec);
 }
 
 static void alc882_targa_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 26 bit!
-	 */
-	if (((res >> 26) == ALC880_HP_EVENT)) {
+	if ((res >> 26) == ALC880_HP_EVENT)
 		alc882_targa_automute(codec);
-	}
 }
 
 static struct hda_verb alc882_asus_a7j_verbs[] = {
@@ -6722,7 +6972,7 @@
 static void alc885_imac24_init_hook(struct hda_codec *codec)
 {
 	alc885_macpro_init_hook(codec);
-	alc885_imac24_automute(codec);
+	alc885_imac24_automute_init_hook(codec);
 }
 
 /*
@@ -6815,6 +7065,7 @@
 	[ALC882_ASUS_A7J]	= "asus-a7j",
 	[ALC882_ASUS_A7M]	= "asus-a7m",
 	[ALC885_MACPRO]		= "macpro",
+	[ALC885_MB5]		= "mb5",
 	[ALC885_MBP3]		= "mbp3",
 	[ALC885_IMAC24]		= "imac24",
 	[ALC882_AUTO]		= "auto",
@@ -6892,8 +7143,20 @@
 		.input_mux = &alc882_capture_source,
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.dig_in_nid = ALC882_DIGIN_NID,
-		.unsol_event = alc885_mbp3_unsol_event,
-		.init_hook = alc885_mbp3_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc885_mbp3_init_hook,
+	},
+	[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,
 	},
 	[ALC885_MACPRO] = {
 		.mixers = { alc882_macpro_mixer },
@@ -6917,7 +7180,7 @@
 		.num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
 		.channel_mode = alc882_ch_modes,
 		.input_mux = &alc882_capture_source,
-		.unsol_event = alc885_imac24_unsol_event,
+		.unsol_event = alc_automute_amp_unsol_event,
 		.init_hook = alc885_imac24_init_hook,
 	},
 	[ALC882_TARGA] = {
@@ -6934,7 +7197,7 @@
 		.need_dac_fix = 1,
 		.input_mux = &alc882_capture_source,
 		.unsol_event = alc882_targa_unsol_event,
-		.init_hook = alc882_targa_automute,
+		.init_hook = alc882_targa_init_hook,
 	},
 	[ALC882_ASUS_A7J] = {
 		.mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
@@ -7014,7 +7277,6 @@
 	struct alc_spec *spec = codec->spec;
 	int i;
 
-	alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
 	for (i = 0; i <= HDA_SIDE; i++) {
 		hda_nid_t nid = spec->autocfg.line_out_pins[i];
 		int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -7197,10 +7459,17 @@
 		case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
 		case 0x106b00a4: /* MacbookPro4,1 */
 		case 0x106b2c00: /* Macbook Pro rev3 */
-		case 0x106b3600: /* Macbook 3.1 */
+		/* Macbook 3.1 (0x106b3600) is handled by patch_alc883() */
 		case 0x106b3800: /* MacbookPro4,1 - latter revision */
 			board_config = ALC885_MBP3;
 			break;
+		case 0x106b3f00: /* Macbook 5,1 */
+		case 0x106b4000: /* Macbook Pro 5,1 - FIXME: HP jack sense
+				  *   seems not working, so apparently
+				  *   no perfect solution yet
+				  */
+			board_config = ALC885_MB5;
+			break;
 		default:
 			/* ALC889A is handled better as ALC888-compatible */
 			if (codec->revision_id == 0x100101 ||
@@ -7208,8 +7477,9 @@
 				alc_free(codec);
 				return patch_alc883(codec);
 			}
-			printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
-		       			 "trying auto-probe from BIOS...\n");
+			printk(KERN_INFO "hda_codec: Unknown model for %s, "
+			       "trying auto-probe from BIOS...\n",
+			       codec->chip_name);
 			board_config = ALC882_AUTO;
 		}
 	}
@@ -7239,14 +7509,6 @@
 	if (board_config != ALC882_AUTO)
 		setup_preset(spec, &alc882_presets[board_config]);
 
-	if (codec->vendor_id == 0x10ec0885) {
-		spec->stream_name_analog = "ALC885 Analog";
-		spec->stream_name_digital = "ALC885 Digital";
-	} else {
-		spec->stream_name_analog = "ALC882 Analog";
-		spec->stream_name_digital = "ALC882 Digital";
-	}
-
 	spec->stream_analog_playback = &alc882_pcm_analog_playback;
 	spec->stream_analog_capture = &alc882_pcm_analog_capture;
 	/* FIXME: setup DAC5 */
@@ -7399,6 +7661,17 @@
 	},
 };
 
+static 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) unsused? */
+	},
+};
+
 /*
  * 2ch mode
  */
@@ -7448,6 +7721,73 @@
 	{ 6, alc883_3ST_ch6_init },
 };
 
+
+/*
+ * 2ch mode
+ */
+static struct hda_verb alc883_4ST_ch2_init[] = {
+	{ 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 },
+	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+	{ } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static struct hda_verb alc883_4ST_ch4_init[] = {
+	{ 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 },
+	{ 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 },
+	{ } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc883_4ST_ch6_init[] = {
+	{ 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_OUT },
+	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+	{ 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+	{ 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 },
+	{ } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static struct hda_verb alc883_4ST_ch8_init[] = {
+	{ 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 },
+	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+	{ 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+	{ 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 },
+	{ } /* end */
+};
+
+static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
+	{ 2, alc883_4ST_ch2_init },
+	{ 4, alc883_4ST_ch4_init },
+	{ 6, alc883_4ST_ch6_init },
+	{ 8, alc883_4ST_ch8_init },
+};
+
+
 /*
  * 2ch mode
  */
@@ -7517,6 +7857,49 @@
 	{ 8, alc883_sixstack_ch8_init },
 };
 
+/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
+static 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 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 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 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 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 struct hda_verb alc883_medion_eapd_verbs[] = {
         /* eanable EAPD on medion laptop */
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
@@ -7782,8 +8165,6 @@
 	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 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_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 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),
@@ -7797,6 +8178,42 @@
 	{ } /* end */
 };
 
+static 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", 0x18, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Boost", 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 struct snd_kcontrol_new alc883_vaiott_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	{ } /* end */
+};
+
 static struct hda_bind_ctls alc883_bind_cap_vol = {
 	.ops = &snd_hda_bind_vol,
 	.values = {
@@ -7932,16 +8349,14 @@
 };
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc883_mitac_hp_automute(struct hda_codec *codec)
+static void alc883_mitac_init_hook(struct hda_codec *codec)
 {
-	unsigned int present;
+	struct alc_spec *spec = codec->spec;
 
-	present = snd_hda_codec_read(codec, 0x15, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-	snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[1] = 0x17;
+	alc_automute_amp(codec);
 }
 
 /* auto-toggle front mic */
@@ -7958,25 +8373,6 @@
 }
 */
 
-static void alc883_mitac_automute(struct hda_codec *codec)
-{
-	alc883_mitac_hp_automute(codec);
-	/* alc883_mitac_mic_automute(codec); */
-}
-
-static void alc883_mitac_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc883_mitac_hp_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		/* alc883_mitac_mic_automute(codec); */
-		break;
-	}
-}
-
 static struct hda_verb alc883_mitac_verbs[] = {
 	/* HP */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -8028,14 +8424,24 @@
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 
-	{0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
-	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
-	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+/* Connect Line-Out side jack (SPDIF) to Side */
+	{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},
+/* Connect Mic jack to CLFE */
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
+/* Connect Line-in jack to Surround */
+	{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},
+/* Connect HP out jack to Front */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
 
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-	{0x01, AC_VERB_SET_GPIO_MASK, 0x03},
-	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
-	{0x01, AC_VERB_SET_GPIO_DATA, 0x03},
 
 	{ } /* end */
 };
@@ -8094,29 +8500,26 @@
 	{ }
 };
 
-static void alc888_3st_hp_front_automute(struct hda_codec *codec)
-{
-	unsigned int present, bits;
+static struct hda_verb alc883_vaiott_verbs[] = {
+	/* HP */
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 
-	present = snd_hda_codec_read(codec, 0x1b, 0,
-			AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
+	/* enable unsolicited event */
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 
-static void alc888_3st_hp_unsol_event(struct hda_codec *codec,
-				      unsigned int res)
+	{ } /* end */
+};
+
+static void alc888_3st_hp_init_hook(struct hda_codec *codec)
 {
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc888_3st_hp_front_automute(codec);
-		break;
-	}
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[1] = 0x16;
+	spec->autocfg.speaker_pins[2] = 0x18;
+	alc_automute_amp(codec);
 }
 
 static struct hda_verb alc888_3st_hp_verbs[] = {
@@ -8213,56 +8616,18 @@
 };
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc883_medion_md2_automute(struct hda_codec *codec)
+static void alc883_medion_md2_init_hook(struct hda_codec *codec)
 {
- 	unsigned int present;
+	struct alc_spec *spec = codec->spec;
 
- 	present = snd_hda_codec_read(codec, 0x14, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
-static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
-					  unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc883_medion_md2_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	alc_automute_amp(codec);
 }
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc883_tagra_automute(struct hda_codec *codec)
-{
- 	unsigned int present;
-	unsigned char bits;
-
- 	present = snd_hda_codec_read(codec, 0x14, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
-				  present ? 1 : 3);
-}
-
-static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc883_tagra_automute(codec);
-}
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_clevo_m720_hp_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
-		& AC_PINSENSE_PRESENCE;
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
+#define alc883_tagra_init_hook		alc882_targa_init_hook
+#define alc883_tagra_unsol_event	alc882_targa_unsol_event
 
 static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
 {
@@ -8274,9 +8639,13 @@
 				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 }
 
-static void alc883_clevo_m720_automute(struct hda_codec *codec)
+static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
 {
-	alc883_clevo_m720_hp_automute(codec);
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	alc_automute_amp(codec);
 	alc883_clevo_m720_mic_automute(codec);
 }
 
@@ -8284,52 +8653,32 @@
 					   unsigned int res)
 {
 	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc883_clevo_m720_hp_automute(codec);
-		break;
 	case ALC880_MIC_EVENT:
 		alc883_clevo_m720_mic_automute(codec);
 		break;
+	default:
+		alc_automute_amp_unsol_event(codec, res);
+		break;
 	}
 }
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec)
+static void alc883_2ch_fujitsu_pi2515_init_hook(struct hda_codec *codec)
 {
- 	unsigned int present;
-	unsigned char bits;
+	struct alc_spec *spec = codec->spec;
 
- 	present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
-		& AC_PINSENSE_PRESENCE;
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
+	spec->autocfg.hp_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	alc_automute_amp(codec);
 }
 
-static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec,
-						  unsigned int res)
+static void alc883_haier_w66_init_hook(struct hda_codec *codec)
 {
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc883_2ch_fujitsu_pi2515_automute(codec);
-}
+	struct alc_spec *spec = codec->spec;
 
-static void alc883_haier_w66_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_codec_read(codec, 0x1b, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	bits = present ? 0x80 : 0;
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 0x80, bits);
-}
-
-static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
-					 unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc883_haier_w66_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	alc_automute_amp(codec);
 }
 
 static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
@@ -8337,8 +8686,8 @@
  	unsigned int present;
 	unsigned char bits;
 
- 	present = snd_hda_codec_read(codec, 0x14, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
+		& AC_PINSENSE_PRESENCE;
 	bits = present ? HDA_AMP_MUTE : 0;
 	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
 				 HDA_AMP_MUTE, bits);
@@ -8368,23 +8717,14 @@
 }
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc883_acer_aspire_automute(struct hda_codec *codec)
+static void alc883_acer_aspire_init_hook(struct hda_codec *codec)
 {
- 	unsigned int present;
+	struct alc_spec *spec = codec->spec;
 
- 	present = snd_hda_codec_read(codec, 0x14, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	snd_hda_codec_amp_stereo(codec, 0x15, 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 alc883_acer_aspire_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc883_acer_aspire_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[1] = 0x16;
+	alc_automute_amp(codec);
 }
 
 static struct hda_verb alc883_acer_eapd_verbs[] = {
@@ -8405,75 +8745,39 @@
 	{ }
 };
 
-static void alc888_6st_dell_front_automute(struct hda_codec *codec)
+static void alc888_6st_dell_init_hook(struct hda_codec *codec)
 {
- 	unsigned int present;
+	struct alc_spec *spec = codec->spec;
 
- 	present = snd_hda_codec_read(codec, 0x1b, 0,
-				AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-	snd_hda_codec_amp_stereo(codec, 0x15, 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);
-	snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
-				HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[1] = 0x15;
+	spec->autocfg.speaker_pins[2] = 0x16;
+	spec->autocfg.speaker_pins[3] = 0x17;
+	alc_automute_amp(codec);
 }
 
-static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
-					     unsigned int res)
+static void alc888_lenovo_sky_init_hook(struct hda_codec *codec)
 {
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		/* printk(KERN_DEBUG "hp_event\n"); */
-		alc888_6st_dell_front_automute(codec);
-		break;
-	}
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[1] = 0x15;
+	spec->autocfg.speaker_pins[2] = 0x16;
+	spec->autocfg.speaker_pins[3] = 0x17;
+	spec->autocfg.speaker_pins[4] = 0x1a;
+	alc_automute_amp(codec);
 }
 
-static void alc888_lenovo_sky_front_automute(struct hda_codec *codec)
+static void alc883_vaiott_init_hook(struct hda_codec *codec)
 {
-	unsigned int mute;
-	unsigned int present;
+	struct alc_spec *spec = codec->spec;
 
-	snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
-	present = snd_hda_codec_read(codec, 0x1b, 0,
-				     AC_VERB_GET_PIN_SENSE, 0);
-	present = (present & 0x80000000) != 0;
-	if (present) {
-		/* mute internal speaker */
-		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-		snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-		snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-		snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-		snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-	} else {
-		/* unmute internal speaker if necessary */
-		mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
-		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-		snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-		snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-		snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-		snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-	}
-}
-
-static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec,
-					     unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc888_lenovo_sky_front_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[1] = 0x17;
+	alc_automute_amp(codec);
 }
 
 /*
@@ -8561,39 +8865,33 @@
 			    0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
 }
 
-static void alc883_M90V_speaker_automute(struct hda_codec *codec)
+static void alc883_M90V_init_hook(struct hda_codec *codec)
 {
-	unsigned int present;
-	unsigned char bits;
+	struct alc_spec *spec = codec->spec;
 
-	present = snd_hda_codec_read(codec, 0x1b, 0,
-				     AC_VERB_GET_PIN_SENSE, 0)
-		& AC_PINSENSE_PRESENCE;
-	bits = present ? 0 : PIN_OUT;
-	snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    bits);
-	snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    bits);
-	snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    bits);
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[1] = 0x15;
+	spec->autocfg.speaker_pins[2] = 0x16;
+	alc_automute_pin(codec);
 }
 
 static void alc883_mode2_unsol_event(struct hda_codec *codec,
 					   unsigned int res)
 {
 	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc883_M90V_speaker_automute(codec);
-		break;
 	case ALC880_MIC_EVENT:
 		alc883_nb_mic_automute(codec);
 		break;
+	default:
+		alc_sku_unsol_event(codec, res);
+		break;
 	}
 }
 
 static void alc883_mode2_inithook(struct hda_codec *codec)
 {
-	alc883_M90V_speaker_automute(codec);
+	alc883_M90V_init_hook(codec);
 	alc883_nb_mic_automute(codec);
 }
 
@@ -8610,32 +8908,49 @@
 	{ } /* end */
 };
 
-static void alc883_eee1601_speaker_automute(struct hda_codec *codec)
+static void alc883_eee1601_inithook(struct hda_codec *codec)
 {
-	unsigned int present;
-	unsigned char bits;
+	struct alc_spec *spec = codec->spec;
 
-	present = snd_hda_codec_read(codec, 0x14, 0,
-				     AC_VERB_GET_PIN_SENSE, 0)
-		& AC_PINSENSE_PRESENCE;
-	bits = present ? 0 : PIN_OUT;
-	snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    bits);
+	spec->autocfg.hp_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x1b;
+	alc_automute_pin(codec);
 }
 
-static void alc883_eee1601_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
+static 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, ALC880_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)
 {
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc883_eee1601_speaker_automute(codec);
-		break;
+	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_codec_read(codec, 0x15, 0,
+			AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
+		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 alc883_eee1601_inithook(struct hda_codec *codec)
+static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-	alc883_eee1601_speaker_automute(codec);
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc889A_mb31_automute(codec);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -8659,9 +8974,11 @@
 	[ALC883_6ST_DIG]	= "6stack-dig",
 	[ALC883_TARGA_DIG]	= "targa-dig",
 	[ALC883_TARGA_2ch_DIG]	= "targa-2ch-dig",
+	[ALC883_TARGA_8ch_DIG]	= "targa-8ch-dig",
 	[ALC883_ACER]		= "acer",
 	[ALC883_ACER_ASPIRE]	= "acer-aspire",
 	[ALC888_ACER_ASPIRE_4930G]	= "acer-aspire-4930g",
+	[ALC888_ACER_ASPIRE_8930G]	= "acer-aspire-8930g",
 	[ALC883_MEDION]		= "medion",
 	[ALC883_MEDION_MD2]	= "medion-md2",
 	[ALC883_LAPTOP_EAPD]	= "laptop-eapd",
@@ -8678,6 +8995,8 @@
 	[ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
 	[ALC883_3ST_6ch_INTEL]	= "3stack-6ch-intel",
 	[ALC1200_ASUS_P5Q]	= "asus-p5q",
+	[ALC889A_MB31]		= "mb31",
+	[ALC883_SONY_VAIO_TT]	= "sony-vaio-tt",
 	[ALC883_AUTO]		= "auto",
 };
 
@@ -8693,14 +9012,18 @@
 		ALC888_ACER_ASPIRE_4930G),
 	SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
 		ALC888_ACER_ASPIRE_4930G),
+	SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
+		ALC888_ACER_ASPIRE_8930G),
 	SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
 	SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
 	SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
 		ALC888_ACER_ASPIRE_4930G),
 	SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
 		ALC888_ACER_ASPIRE_4930G),
-	/* default Acer */
-	SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER),
+	/* default Acer -- disabled as it causes more problems.
+	 *    model=auto should work fine now
+	 */
+	/* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
 	SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
 	SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
@@ -8736,6 +9059,7 @@
 	SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
 	SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
 	SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
+	SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
 	SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
@@ -8768,6 +9092,7 @@
 	SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
 	SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL),
 	SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
+	SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
 	{}
 };
 
@@ -8848,7 +9173,7 @@
 		.need_dac_fix = 1,
 		.input_mux = &alc883_capture_source,
 		.unsol_event = alc883_tagra_unsol_event,
-		.init_hook = alc883_tagra_automute,
+		.init_hook = alc883_tagra_init_hook,
 	},
 	[ALC883_TARGA_2ch_DIG] = {
 		.mixers = { alc883_tagra_2ch_mixer},
@@ -8862,7 +9187,25 @@
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
 		.unsol_event = alc883_tagra_unsol_event,
-		.init_hook = alc883_tagra_automute,
+		.init_hook = alc883_tagra_init_hook,
+	},
+	[ALC883_TARGA_8ch_DIG] = {
+		.mixers = { alc883_base_mixer, alc883_chmode_mixer },
+		.init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
+				alc883_tagra_verbs },
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
+		.adc_nids = alc883_adc_nids_rev,
+		.capsrc_nids = alc883_capsrc_nids_rev,
+		.dig_out_nid = ALC883_DIGOUT_NID,
+		.dig_in_nid = ALC883_DIGIN_NID,
+		.num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
+		.channel_mode = alc883_4ST_8ch_modes,
+		.need_dac_fix = 1,
+		.input_mux = &alc883_capture_source,
+		.unsol_event = alc883_tagra_unsol_event,
+		.init_hook = alc883_tagra_init_hook,
 	},
 	[ALC883_ACER] = {
 		.mixers = { alc883_base_mixer },
@@ -8887,8 +9230,8 @@
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc883_acer_aspire_unsol_event,
-		.init_hook = alc883_acer_aspire_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc883_acer_aspire_init_hook,
 	},
 	[ALC888_ACER_ASPIRE_4930G] = {
 		.mixers = { alc888_base_mixer,
@@ -8907,8 +9250,29 @@
 		.num_mux_defs =
 			ARRAY_SIZE(alc888_2_capture_sources),
 		.input_mux = alc888_2_capture_sources,
-		.unsol_event = alc888_acer_aspire_4930g_unsol_event,
-		.init_hook = alc888_acer_aspire_4930g_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc888_acer_aspire_4930g_init_hook,
+	},
+	[ALC888_ACER_ASPIRE_8930G] = {
+		.mixers = { alc888_base_mixer,
+				alc883_chmode_mixer },
+		.init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
+				alc889_acer_aspire_8930g_verbs },
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
+		.adc_nids = alc889_adc_nids,
+		.capsrc_nids = alc889_capsrc_nids,
+		.dig_out_nid = ALC883_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+		.channel_mode = alc883_3ST_6ch_modes,
+		.need_dac_fix = 1,
+		.const_channel_count = 6,
+		.num_mux_defs =
+			ARRAY_SIZE(alc889_capture_sources),
+		.input_mux = alc889_capture_sources,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc889_acer_aspire_8930g_init_hook,
 	},
 	[ALC883_MEDION] = {
 		.mixers = { alc883_fivestack_mixer,
@@ -8932,8 +9296,8 @@
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc883_medion_md2_unsol_event,
-		.init_hook = alc883_medion_md2_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc883_medion_md2_init_hook,
 	},
 	[ALC883_LAPTOP_EAPD] = {
 		.mixers = { alc883_base_mixer },
@@ -8954,7 +9318,7 @@
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
 		.unsol_event = alc883_clevo_m720_unsol_event,
-		.init_hook = alc883_clevo_m720_automute,
+		.init_hook = alc883_clevo_m720_init_hook,
 	},
 	[ALC883_LENOVO_101E_2ch] = {
 		.mixers = { alc883_lenovo_101e_2ch_mixer},
@@ -8978,8 +9342,8 @@
 		.channel_mode = alc883_3ST_2ch_modes,
 		.need_dac_fix = 1,
 		.input_mux = &alc883_lenovo_nb0763_capture_source,
-		.unsol_event = alc883_medion_md2_unsol_event,
-		.init_hook = alc883_medion_md2_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc883_medion_md2_init_hook,
 	},
 	[ALC888_LENOVO_MS7195_DIG] = {
 		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
@@ -9003,8 +9367,8 @@
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc883_haier_w66_unsol_event,
-		.init_hook = alc883_haier_w66_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc883_haier_w66_init_hook,
 	},
 	[ALC888_3ST_HP] = {
 		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
@@ -9015,8 +9379,8 @@
 		.channel_mode = alc888_3st_hp_modes,
 		.need_dac_fix = 1,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc888_3st_hp_unsol_event,
-		.init_hook = alc888_3st_hp_front_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc888_3st_hp_init_hook,
 	},
 	[ALC888_6ST_DELL] = {
 		.mixers = { alc883_base_mixer, alc883_chmode_mixer },
@@ -9028,8 +9392,8 @@
 		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
 		.channel_mode = alc883_sixstack_modes,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc888_6st_dell_unsol_event,
-		.init_hook = alc888_6st_dell_front_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc888_6st_dell_init_hook,
 	},
 	[ALC883_MITAC] = {
 		.mixers = { alc883_mitac_mixer },
@@ -9039,8 +9403,8 @@
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc883_mitac_unsol_event,
-		.init_hook = alc883_mitac_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc883_mitac_init_hook,
 	},
 	[ALC883_FUJITSU_PI2515] = {
 		.mixers = { alc883_2ch_fujitsu_pi2515_mixer },
@@ -9052,8 +9416,8 @@
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_fujitsu_pi2515_capture_source,
-		.unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
-		.init_hook = alc883_2ch_fujitsu_pi2515_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc883_2ch_fujitsu_pi2515_init_hook,
 	},
 	[ALC888_FUJITSU_XA3530] = {
 		.mixers = { alc888_base_mixer, alc883_chmode_mixer },
@@ -9070,8 +9434,8 @@
 		.num_mux_defs =
 			ARRAY_SIZE(alc888_2_capture_sources),
 		.input_mux = alc888_2_capture_sources,
-		.unsol_event = alc888_fujitsu_xa3530_unsol_event,
-		.init_hook = alc888_fujitsu_xa3530_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc888_fujitsu_xa3530_init_hook,
 	},
 	[ALC888_LENOVO_SKY] = {
 		.mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
@@ -9083,8 +9447,8 @@
 		.channel_mode = alc883_sixstack_modes,
 		.need_dac_fix = 1,
 		.input_mux = &alc883_lenovo_sky_capture_source,
-		.unsol_event = alc883_lenovo_sky_unsol_event,
-		.init_hook = alc888_lenovo_sky_front_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc888_lenovo_sky_init_hook,
 	},
 	[ALC888_ASUS_M90V] = {
 		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
@@ -9112,7 +9476,7 @@
 		.channel_mode = alc883_3ST_2ch_modes,
 		.need_dac_fix = 1,
 		.input_mux = &alc883_asus_eee1601_capture_source,
-		.unsol_event = alc883_eee1601_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.init_hook = alc883_eee1601_inithook,
 	},
 	[ALC1200_ASUS_P5Q] = {
@@ -9127,6 +9491,32 @@
 		.channel_mode = alc883_sixstack_modes,
 		.input_mux = &alc883_capture_source,
 	},
+	[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),
+		.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,
+	},
+	[ALC883_SONY_VAIO_TT] = {
+		.mixers = { alc883_vaiott_mixer },
+		.init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+		.channel_mode = alc883_3ST_2ch_modes,
+		.input_mux = &alc883_capture_source,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc883_vaiott_init_hook,
+	},
 };
 
 
@@ -9155,7 +9545,6 @@
 	struct alc_spec *spec = codec->spec;
 	int i;
 
-	alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
 	for (i = 0; i <= HDA_SIDE; i++) {
 		hda_nid_t nid = spec->autocfg.line_out_pins[i];
 		int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -9273,10 +9662,18 @@
 	board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
 						  alc883_models,
 						  alc883_cfg_tbl);
-	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
-		       "trying auto-probe from BIOS...\n");
-		board_config = ALC883_AUTO;
+	if (board_config < 0 || board_config >= ALC883_MODEL_LAST) {
+		/* Pick up systems that don't supply PCI SSID */
+		switch (codec->subsystem_id) {
+		case 0x106b3600: /* Macbook 3.1 */
+			board_config = ALC889A_MB31;
+			break;
+		default:
+			printk(KERN_INFO
+				"hda_codec: Unknown model for %s, trying "
+				"auto-probe from BIOS...\n", codec->chip_name);
+			board_config = ALC883_AUTO;
+		}
 	}
 
 	if (board_config == ALC883_AUTO) {
@@ -9304,13 +9701,6 @@
 
 	switch (codec->vendor_id) {
 	case 0x10ec0888:
-		if (codec->revision_id == 0x100101) {
-			spec->stream_name_analog = "ALC1200 Analog";
-			spec->stream_name_digital = "ALC1200 Digital";
-		} else {
-			spec->stream_name_analog = "ALC888 Analog";
-			spec->stream_name_digital = "ALC888 Digital";
-		}
 		if (!spec->num_adc_nids) {
 			spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
 			spec->adc_nids = alc883_adc_nids;
@@ -9318,10 +9708,9 @@
 		if (!spec->capsrc_nids)
 			spec->capsrc_nids = alc883_capsrc_nids;
 		spec->capture_style = CAPT_MIX; /* matrix-style capture */
+		spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
 		break;
 	case 0x10ec0889:
-		spec->stream_name_analog = "ALC889 Analog";
-		spec->stream_name_digital = "ALC889 Digital";
 		if (!spec->num_adc_nids) {
 			spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids);
 			spec->adc_nids = alc889_adc_nids;
@@ -9332,8 +9721,6 @@
 							capture */
 		break;
 	default:
-		spec->stream_name_analog = "ALC883 Analog";
-		spec->stream_name_digital = "ALC883 Digital";
 		if (!spec->num_adc_nids) {
 			spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
 			spec->adc_nids = alc883_adc_nids;
@@ -9413,24 +9800,6 @@
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Front 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("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("Mic Boost", 0x18, 0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
-	/*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-	{ } /* end */
-};
-
 /* update HP, line and mono-out pins according to the master switch */
 static void alc262_hp_master_update(struct hda_codec *codec)
 {
@@ -9486,14 +9855,7 @@
 	alc262_hp_wildwest_automute(codec);
 }
 
-static int alc262_hp_master_sw_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;
-	*ucontrol->value.integer.value = spec->master_sw;
-	return 0;
-}
+#define alc262_hp_master_sw_get		alc260_hp_master_sw_get
 
 static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
@@ -9509,14 +9871,17 @@
 	return 1;
 }
 
+#define ALC262_HP_MASTER_SWITCH					\
+	{							\
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		\
+		.name = "Master Playback Switch",		\
+		.info = snd_ctl_boolean_mono_info,		\
+		.get = alc262_hp_master_sw_get,			\
+		.put = alc262_hp_master_sw_put,			\
+	}
+
 static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Switch",
-		.info = snd_ctl_boolean_mono_info,
-		.get = alc262_hp_master_sw_get,
-		.put = alc262_hp_master_sw_put,
-	},
+	ALC262_HP_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
@@ -9540,13 +9905,7 @@
 };
 
 static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Switch",
-		.info = snd_ctl_boolean_mono_info,
-		.get = alc262_hp_master_sw_get,
-		.put = alc262_hp_master_sw_put,
-	},
+	ALC262_HP_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -9573,32 +9932,13 @@
 };
 
 /* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
+static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 
-	if (force || !spec->sense_updated) {
-		unsigned int present;
-		present = snd_hda_codec_read(codec, 0x15, 0,
-					     AC_VERB_GET_PIN_SENSE, 0);
-		spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
-		spec->sense_updated = 1;
-	}
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
-				 spec->jack_present ? HDA_AMP_MUTE : 0);
-}
-
-static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
-					unsigned int res)
-{
-	if ((res >> 26) != ALC880_HP_EVENT)
-		return;
-	alc262_hp_t5735_automute(codec, 1);
-}
-
-static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
-{
-	alc262_hp_t5735_automute(codec, 1);
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x0c; /* HACK: not actually a pin */
+	alc_automute_amp(codec);
 }
 
 static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
@@ -9651,46 +9991,132 @@
 	},
 };
 
-/* bind hp and internal speaker mute (with plug check) */
-static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
-				     struct snd_ctl_elem_value *ucontrol)
+/* bind hp and internal speaker mute (with plug check) as master switch */
+static void alc262_hippo_master_update(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
+	hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
+	hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
+	unsigned int mute;
+
+	/* HP */
+	mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
+	snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
+				 HDA_AMP_MUTE, mute);
+	/* mute internal speaker per jack sense */
+	if (spec->jack_present)
+		mute = HDA_AMP_MUTE;
+	if (line_nid)
+		snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, mute);
+	if (speaker_nid && speaker_nid != line_nid)
+		snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, mute);
+}
+
+#define alc262_hippo_master_sw_get	alc262_hp_master_sw_get
+
+static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	long *valp = ucontrol->value.integer.value;
-	int change;
+	struct alc_spec *spec = codec->spec;
+	int val = !!*ucontrol->value.integer.value;
 
-	/* change hp mute */
-	change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
-					  HDA_AMP_MUTE,
-					  valp[0] ? 0 : HDA_AMP_MUTE);
-	change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
-					   HDA_AMP_MUTE,
-					   valp[1] ? 0 : HDA_AMP_MUTE);
-	if (change) {
-		/* change speaker according to HP jack state */
-		struct alc_spec *spec = codec->spec;
-		unsigned int mute;
-		if (spec->jack_present)
-			mute = HDA_AMP_MUTE;
-		else
-			mute = snd_hda_codec_amp_read(codec, 0x15, 0,
-						      HDA_OUTPUT, 0);
-		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-	}
-	return change;
+	if (val == spec->master_sw)
+		return 0;
+	spec->master_sw = val;
+	alc262_hippo_master_update(codec);
+	return 1;
 }
 
+#define ALC262_HIPPO_MASTER_SWITCH				\
+	{							\
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		\
+		.name = "Master Playback Switch",		\
+		.info = snd_ctl_boolean_mono_info,		\
+		.get = alc262_hippo_master_sw_get,		\
+		.put = alc262_hippo_master_sw_put,		\
+	}
+
+static struct snd_kcontrol_new alc262_hippo_mixer[] = {
+	ALC262_HIPPO_MASTER_SWITCH,
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 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_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	ALC262_HIPPO_MASTER_SWITCH,
+	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("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+	{ } /* end */
+};
+
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc262_hippo_automute(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
+	unsigned int present;
+
+	/* need to execute and sync at first */
+	snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
+	present = snd_hda_codec_read(codec, hp_nid, 0,
+				     AC_VERB_GET_PIN_SENSE, 0);
+	spec->jack_present = (present & 0x80000000) != 0;
+	alc262_hippo_master_update(codec);
+}
+
+static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+	if ((res >> 26) != ALC880_HP_EVENT)
+		return;
+	alc262_hippo_automute(codec);
+}
+
+static void alc262_hippo_init_hook(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	alc262_hippo_automute(codec);
+}
+
+static void alc262_hippo1_init_hook(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	alc262_hippo_automute(codec);
+}
+
+
 static struct snd_kcontrol_new alc262_sony_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Switch",
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
-		.put = alc262_sony_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
-	},
+	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
@@ -9699,8 +10125,8 @@
 };
 
 static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
@@ -9741,34 +10167,15 @@
 };
 
 /* unsolicited event for HP jack sensing */
-static void alc262_tyan_automute(struct hda_codec *codec)
+static void alc262_tyan_init_hook(struct hda_codec *codec)
 {
-	unsigned int mute;
-	unsigned int present;
+	struct alc_spec *spec = codec->spec;
 
-	snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
-	present = snd_hda_codec_read(codec, 0x1b, 0,
-				     AC_VERB_GET_PIN_SENSE, 0);
-	present = (present & 0x80000000) != 0;
-	if (present) {
-		/* mute line output on ATX panel */
-		snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-	} else {
-		/* unmute line output if necessary */
-		mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
-		snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-	}
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	alc_automute_amp(codec);
 }
 
-static void alc262_tyan_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	if ((res >> 26) != ALC880_HP_EVENT)
-		return;
-	alc262_tyan_automute(codec);
-}
 
 #define alc262_capture_mixer		alc882_capture_mixer
 #define alc262_capture_alt_mixer	alc882_capture_alt_mixer
@@ -9923,99 +10330,25 @@
 				AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
 }
 
-/* toggle speaker-output according to the hp-jack state */
-static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_codec_read(codec, 0x15, 0,
-					AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	bits = present ? 0 : PIN_OUT;
-	snd_hda_codec_write(codec, 0x14, 0,
-					AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
-}
-
-
 
 /* unsolicited event for HP jack sensing */
 static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
 				       unsigned int res)
 {
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc262_toshiba_s06_speaker_automute(codec);
 	if ((res >> 26) == ALC880_MIC_EVENT)
 		alc262_dmic_automute(codec);
-
+	else
+		alc_sku_unsol_event(codec, res);
 }
 
 static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
 {
-	alc262_toshiba_s06_speaker_automute(codec);
-	alc262_dmic_automute(codec);
-}
-
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_hippo_automute(struct hda_codec *codec)
-{
 	struct alc_spec *spec = codec->spec;
-	unsigned int mute;
-	unsigned int present;
 
-	/* need to execute and sync at first */
-	snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
-	present = snd_hda_codec_read(codec, 0x15, 0,
-				     AC_VERB_GET_PIN_SENSE, 0);
-	spec->jack_present = (present & 0x80000000) != 0;
-	if (spec->jack_present) {
-		/* mute internal speaker */
-		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-	} else {
-		/* unmute internal speaker if necessary */
-		mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
-		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-	}
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc262_hippo_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	if ((res >> 26) != ALC880_HP_EVENT)
-		return;
-	alc262_hippo_automute(codec);
-}
-
-static void alc262_hippo1_automute(struct hda_codec *codec)
-{
-	unsigned int mute;
-	unsigned int present;
-
-	snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
-	present = snd_hda_codec_read(codec, 0x1b, 0,
-				     AC_VERB_GET_PIN_SENSE, 0);
-	present = (present & 0x80000000) != 0;
-	if (present) {
-		/* mute internal speaker */
-		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-	} else {
-		/* unmute internal speaker if necessary */
-		mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
-		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-	}
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc262_hippo1_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	if ((res >> 26) != ALC880_HP_EVENT)
-		return;
-	alc262_hippo1_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	alc_automute_pin(codec);
+	alc262_dmic_automute(codec);
 }
 
 /*
@@ -10285,14 +10618,7 @@
 
 static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Switch",
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
-		.put = alc262_sony_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
-	},
+	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
@@ -10639,31 +10965,46 @@
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
 
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
         {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
 	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
 
 
 	/* 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 */
+	/* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
+	/* Input mixer1: only unmute Mic */
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
 	/* Input mixer2 */
 	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
 	/* Input mixer3 */
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
 
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 
@@ -10843,6 +11184,8 @@
 	if (err < 0)
 		return err;
 
+	alc_ssid_check(codec, 0x15, 0x14, 0x1b);
+
 	return 1;
 }
 
@@ -10945,7 +11288,7 @@
 		.input_mux = &alc262_capture_source,
 	},
 	[ALC262_HIPPO] = {
-		.mixers = { alc262_base_mixer },
+		.mixers = { alc262_hippo_mixer },
 		.init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
 		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
 		.dac_nids = alc262_dac_nids,
@@ -10955,7 +11298,7 @@
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
 		.unsol_event = alc262_hippo_unsol_event,
-		.init_hook = alc262_hippo_automute,
+		.init_hook = alc262_hippo_init_hook,
 	},
 	[ALC262_HIPPO_1] = {
 		.mixers = { alc262_hippo1_mixer },
@@ -10967,8 +11310,8 @@
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc262_hippo1_unsol_event,
-		.init_hook = alc262_hippo1_automute,
+		.unsol_event = alc262_hippo_unsol_event,
+		.init_hook = alc262_hippo1_init_hook,
 	},
 	[ALC262_FUJITSU] = {
 		.mixers = { alc262_fujitsu_mixer },
@@ -11030,7 +11373,7 @@
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc262_hp_t5735_unsol_event,
+		.unsol_event = alc_automute_amp_unsol_event,
 		.init_hook = alc262_hp_t5735_init_hook,
 	},
 	[ALC262_HP_RP5700] = {
@@ -11062,7 +11405,7 @@
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
 		.unsol_event = alc262_hippo_unsol_event,
-		.init_hook = alc262_hippo_automute,
+		.init_hook = alc262_hippo_init_hook,
 	},
 	[ALC262_BENQ_T31] = {
 		.mixers = { alc262_benq_t31_mixer },
@@ -11074,7 +11417,7 @@
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
 		.unsol_event = alc262_hippo_unsol_event,
-		.init_hook = alc262_hippo_automute,
+		.init_hook = alc262_hippo_init_hook,
 	},
 	[ALC262_ULTRA] = {
 		.mixers = { alc262_ultra_mixer },
@@ -11139,7 +11482,7 @@
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
 		.unsol_event = alc262_hippo_unsol_event,
-		.init_hook = alc262_hippo_automute,
+		.init_hook = alc262_hippo_init_hook,
 	},
 	[ALC262_TYAN] = {
 		.mixers = { alc262_tyan_mixer },
@@ -11151,8 +11494,8 @@
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc262_tyan_unsol_event,
-		.init_hook = alc262_tyan_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc262_tyan_init_hook,
 	},
 };
 
@@ -11187,8 +11530,8 @@
 						  alc262_cfg_tbl);
 
 	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
-		       "trying auto-probe from BIOS...\n");
+		printk(KERN_INFO "hda_codec: Unknown model for %s, "
+		       "trying auto-probe from BIOS...\n", codec->chip_name);
 		board_config = ALC262_AUTO;
 	}
 
@@ -11217,11 +11560,9 @@
 	if (board_config != ALC262_AUTO)
 		setup_preset(spec, &alc262_presets[board_config]);
 
-	spec->stream_name_analog = "ALC262 Analog";
 	spec->stream_analog_playback = &alc262_pcm_analog_playback;
 	spec->stream_analog_capture = &alc262_pcm_analog_capture;
 
-	spec->stream_name_digital = "ALC262 Digital";
 	spec->stream_digital_playback = &alc262_pcm_digital_playback;
 	spec->stream_digital_capture = &alc262_pcm_digital_capture;
 
@@ -11296,6 +11637,17 @@
 	{ }
 };
 
+static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
+	/* output mixer control */
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
+	ALC262_HIPPO_MASTER_SWITCH,
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
+	{ }
+};
+
 /* bind Beep switches of both NID 0x0f and 0x10 */
 static struct hda_bind_ctls alc268_bind_beep_sw = {
 	.ops = &snd_hda_bind_sw,
@@ -11319,8 +11671,6 @@
 };
 
 /* Toshiba specific */
-#define alc268_toshiba_automute	alc262_hippo_automute
-
 static struct hda_verb alc268_toshiba_verbs[] = {
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{ } /* end */
@@ -11456,13 +11806,8 @@
 };
 
 /* unsolicited event for HP jack sensing */
-static void alc268_toshiba_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	if ((res >> 26) != ALC880_HP_EVENT)
-		return;
-	alc268_toshiba_automute(codec);
-}
+#define alc268_toshiba_unsol_event	alc262_hippo_unsol_event
+#define alc268_toshiba_init_hook	alc262_hippo_init_hook
 
 static void alc268_acer_unsol_event(struct hda_codec *codec,
 				       unsigned int res)
@@ -11537,30 +11882,15 @@
 };
 
 /* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc268_dell_automute(struct hda_codec *codec)
+static void alc268_dell_init_hook(struct hda_codec *codec)
 {
-	unsigned int present;
-	unsigned int mute;
+	struct alc_spec *spec = codec->spec;
 
-	present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
-	if (present & 0x80000000)
-		mute = HDA_AMP_MUTE;
-	else
-		mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, mute);
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	alc_automute_pin(codec);
 }
 
-static void alc268_dell_unsol_event(struct hda_codec *codec,
-				    unsigned int res)
-{
-	if ((res >> 26) != ALC880_HP_EVENT)
-		return;
-	alc268_dell_automute(codec);
-}
-
-#define alc268_dell_init_hook	alc268_dell_automute
-
 static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -11579,16 +11909,6 @@
 	{ }
 };
 
-static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-
-	present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
-		& AC_PINSENSE_PRESENCE;
-	snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    present ? 0 : PIN_OUT);
-}
-
 static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
 {
 	unsigned int present;
@@ -11600,9 +11920,13 @@
 			    present ? 0x00 : 0x01);
 }
 
-static void alc267_quanta_il1_automute(struct hda_codec *codec)
+static void alc267_quanta_il1_init_hook(struct hda_codec *codec)
 {
-	alc267_quanta_il1_hp_automute(codec);
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	alc_automute_pin(codec);
 	alc267_quanta_il1_mic_automute(codec);
 }
 
@@ -11610,12 +11934,12 @@
 					   unsigned int res)
 {
 	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc267_quanta_il1_hp_automute(codec);
-		break;
 	case ALC880_MIC_EVENT:
 		alc267_quanta_il1_mic_automute(codec);
 		break;
+	default:
+		alc_sku_unsol_event(codec, res);
+		break;
 	}
 }
 
@@ -12063,16 +12387,16 @@
 						ALC268_ACER_ASPIRE_ONE),
 	SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
 	SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL),
-	SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
-	SND_PCI_QUIRK(0x103c, 0x30f1, "HP TX25xx series", ALC268_TOSHIBA),
+	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
+			   ALC268_TOSHIBA),
 	SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
-	SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
-	SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
-	SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA),
+	SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
+	SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
+			   ALC268_TOSHIBA),
 	SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
 	SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
 	SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
-	SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
+	SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL),
 	{}
 };
 
@@ -12090,7 +12414,7 @@
 		.channel_mode = alc268_modes,
 		.input_mux = &alc268_capture_source,
 		.unsol_event = alc267_quanta_il1_unsol_event,
-		.init_hook = alc267_quanta_il1_automute,
+		.init_hook = alc267_quanta_il1_init_hook,
 	},
 	[ALC268_3ST] = {
 		.mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
@@ -12108,7 +12432,7 @@
 		.input_mux = &alc268_capture_source,
 	},
 	[ALC268_TOSHIBA] = {
-		.mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
+		.mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
 			    alc268_beep_mixer },
 		.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
 				alc268_toshiba_verbs },
@@ -12122,7 +12446,7 @@
 		.channel_mode = alc268_modes,
 		.input_mux = &alc268_capture_source,
 		.unsol_event = alc268_toshiba_unsol_event,
-		.init_hook = alc268_toshiba_automute,
+		.init_hook = alc268_toshiba_init_hook,
 	},
 	[ALC268_ACER] = {
 		.mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
@@ -12185,7 +12509,7 @@
 		.hp_nid = 0x02,
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
-		.unsol_event = alc268_dell_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.init_hook = alc268_dell_init_hook,
 		.input_mux = &alc268_capture_source,
 	},
@@ -12205,7 +12529,7 @@
 		.channel_mode = alc268_modes,
 		.input_mux = &alc268_capture_source,
 		.unsol_event = alc268_toshiba_unsol_event,
-		.init_hook = alc268_toshiba_automute
+		.init_hook = alc268_toshiba_init_hook
 	},
 #ifdef CONFIG_SND_DEBUG
 	[ALC268_TEST] = {
@@ -12243,8 +12567,8 @@
 						  alc268_cfg_tbl);
 
 	if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
-		printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
-		       "trying auto-probe from BIOS...\n");
+		printk(KERN_INFO "hda_codec: Unknown model for %s, "
+		       "trying auto-probe from BIOS...\n", codec->chip_name);
 		board_config = ALC268_AUTO;
 	}
 
@@ -12265,14 +12589,6 @@
 	if (board_config != ALC268_AUTO)
 		setup_preset(spec, &alc268_presets[board_config]);
 
-	if (codec->vendor_id == 0x10ec0267) {
-		spec->stream_name_analog = "ALC267 Analog";
-		spec->stream_name_digital = "ALC267 Digital";
-	} else {
-		spec->stream_name_analog = "ALC268 Analog";
-		spec->stream_name_digital = "ALC268 Digital";
-	}
-
 	spec->stream_analog_playback = &alc268_pcm_analog_playback;
 	spec->stream_analog_capture = &alc268_pcm_analog_capture;
 	spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
@@ -13099,8 +13415,8 @@
 						  alc269_cfg_tbl);
 
 	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
-		       "trying auto-probe from BIOS...\n");
+		printk(KERN_INFO "hda_codec: Unknown model for %s, "
+		       "trying auto-probe from BIOS...\n", codec->chip_name);
 		board_config = ALC269_AUTO;
 	}
 
@@ -13127,7 +13443,6 @@
 	if (board_config != ALC269_AUTO)
 		setup_preset(spec, &alc269_presets[board_config]);
 
-	spec->stream_name_analog = "ALC269 Analog";
 	if (codec->subsystem_id == 0x17aa3bf8) {
 		/* Due to a hardware problem on Lenovo Ideadpad, we need to
 		 * fix the sample rate of analog I/O to 44.1kHz
@@ -13138,7 +13453,6 @@
 		spec->stream_analog_playback = &alc269_pcm_analog_playback;
 		spec->stream_analog_capture = &alc269_pcm_analog_capture;
 	}
-	spec->stream_name_digital = "ALC269 Digital";
 	spec->stream_digital_playback = &alc269_pcm_digital_playback;
 	spec->stream_digital_capture = &alc269_pcm_digital_capture;
 
@@ -13927,7 +14241,6 @@
 	struct alc_spec *spec = codec->spec;
 	int i;
 
-	alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
 	for (i = 0; i < spec->autocfg.line_outs; i++) {
 		hda_nid_t nid = spec->autocfg.line_out_pins[i];
 		int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -14010,6 +14323,8 @@
 	spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
 	set_capture_mixer(spec);
 
+	alc_ssid_check(codec, 0x0e, 0x0f, 0x0b);
+
 	return 1;
 }
 
@@ -14199,8 +14514,8 @@
 						  alc861_cfg_tbl);
 
 	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
-		       "trying auto-probe from BIOS...\n");
+		printk(KERN_INFO "hda_codec: Unknown model for %s, "
+		       "trying auto-probe from BIOS...\n", codec->chip_name);
 		board_config = ALC861_AUTO;
 	}
 
@@ -14227,11 +14542,9 @@
 	if (board_config != ALC861_AUTO)
 		setup_preset(spec, &alc861_presets[board_config]);
 
-	spec->stream_name_analog = "ALC861 Analog";
 	spec->stream_analog_playback = &alc861_pcm_analog_playback;
 	spec->stream_analog_capture = &alc861_pcm_analog_capture;
 
-	spec->stream_name_digital = "ALC861 Digital";
 	spec->stream_digital_playback = &alc861_pcm_digital_playback;
 	spec->stream_digital_capture = &alc861_pcm_digital_capture;
 
@@ -14618,19 +14931,6 @@
 	{}
 };
 
-/* toggle speaker-output according to the hp-jack state */
-static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_codec_read(codec, 0x1b, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
-
 static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
 {
 	unsigned int present;
@@ -14643,9 +14943,13 @@
 				 HDA_AMP_MUTE, bits);
 }
 
-static void alc861vd_lenovo_automute(struct hda_codec *codec)
+static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
 {
-	alc861vd_lenovo_hp_automute(codec);
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	alc_automute_amp(codec);
 	alc861vd_lenovo_mic_automute(codec);
 }
 
@@ -14653,12 +14957,12 @@
 					unsigned int res)
 {
 	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc861vd_lenovo_hp_automute(codec);
-		break;
 	case ALC880_MIC_EVENT:
 		alc861vd_lenovo_mic_automute(codec);
 		break;
+	default:
+		alc_automute_amp_unsol_event(codec, res);
+		break;
 	}
 }
 
@@ -14708,20 +15012,13 @@
 };
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc861vd_dallas_automute(struct hda_codec *codec)
+static void alc861vd_dallas_init_hook(struct hda_codec *codec)
 {
-	unsigned int present;
+	struct alc_spec *spec = codec->spec;
 
-	present = snd_hda_codec_read(codec, 0x15, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
-static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc861vd_dallas_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	alc_automute_amp(codec);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -14835,7 +15132,7 @@
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_capture_source,
 		.unsol_event = alc861vd_lenovo_unsol_event,
-		.init_hook = alc861vd_lenovo_automute,
+		.init_hook = alc861vd_lenovo_init_hook,
 	},
 	[ALC861VD_DALLAS] = {
 		.mixers = { alc861vd_dallas_mixer },
@@ -14845,8 +15142,8 @@
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_dallas_capture_source,
-		.unsol_event = alc861vd_dallas_unsol_event,
-		.init_hook = alc861vd_dallas_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc861vd_dallas_init_hook,
 	},
 	[ALC861VD_HP] = {
 		.mixers = { alc861vd_hp_mixer },
@@ -14857,8 +15154,8 @@
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_hp_capture_source,
-		.unsol_event = alc861vd_dallas_unsol_event,
-		.init_hook = alc861vd_dallas_automute,
+		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc861vd_dallas_init_hook,
 	},
 	[ALC660VD_ASUS_V1S] = {
 		.mixers = { alc861vd_lenovo_mixer },
@@ -14873,7 +15170,7 @@
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_capture_source,
 		.unsol_event = alc861vd_lenovo_unsol_event,
-		.init_hook = alc861vd_lenovo_automute,
+		.init_hook = alc861vd_lenovo_init_hook,
 	},
 };
 
@@ -14891,7 +15188,6 @@
 	struct alc_spec *spec = codec->spec;
 	int i;
 
-	alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
 	for (i = 0; i <= HDA_SIDE; i++) {
 		hda_nid_t nid = spec->autocfg.line_out_pins[i];
 		int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -15109,6 +15405,8 @@
 	if (err < 0)
 		return err;
 
+	alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+
 	return 1;
 }
 
@@ -15140,8 +15438,8 @@
 						  alc861vd_cfg_tbl);
 
 	if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
-		printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
-			"ALC861VD, trying auto-probe from BIOS...\n");
+		printk(KERN_INFO "hda_codec: Unknown model for %s, "
+		       "trying auto-probe from BIOS...\n", codec->chip_name);
 		board_config = ALC861VD_AUTO;
 	}
 
@@ -15169,13 +15467,8 @@
 		setup_preset(spec, &alc861vd_presets[board_config]);
 
 	if (codec->vendor_id == 0x10ec0660) {
-		spec->stream_name_analog = "ALC660-VD Analog";
-		spec->stream_name_digital = "ALC660-VD Digital";
 		/* always turn on EAPD */
 		add_verb(spec, alc660vd_eapd_verbs);
-	} else {
-		spec->stream_name_analog = "ALC861VD Analog";
-		spec->stream_name_digital = "ALC861VD Digital";
 	}
 
 	spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
@@ -15289,6 +15582,38 @@
 	},
 };
 
+#if 1 /* set to 0 for testing other input sources below */
+static struct hda_input_mux alc272_nc10_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "Autoselect Mic", 0x0 },
+		{ "Internal Mic", 0x1 },
+	},
+};
+#else
+static struct hda_input_mux alc272_nc10_capture_source = {
+	.num_items = 16,
+	.items = {
+		{ "Autoselect Mic", 0x0 },
+		{ "Internal Mic", 0x1 },
+		{ "In-0x02", 0x2 },
+		{ "In-0x03", 0x3 },
+		{ "In-0x04", 0x4 },
+		{ "In-0x05", 0x5 },
+		{ "In-0x06", 0x6 },
+		{ "In-0x07", 0x7 },
+		{ "In-0x08", 0x8 },
+		{ "In-0x09", 0x9 },
+		{ "In-0x0a", 0x0a },
+		{ "In-0x0b", 0x0b },
+		{ "In-0x0c", 0x0c },
+		{ "In-0x0d", 0x0d },
+		{ "In-0x0e", 0x0e },
+		{ "In-0x0f", 0x0f },
+	},
+};
+#endif
+
 /*
  * 2ch mode
  */
@@ -15428,10 +15753,8 @@
 };
 
 static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
-	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-
-	HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+	ALC262_HIPPO_MASTER_SWITCH,
 
 	HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -15444,15 +15767,11 @@
 };
 
 static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
-	HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	ALC262_HIPPO_MASTER_SWITCH,
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
-	HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
@@ -15960,51 +16279,25 @@
 static void alc662_eeepc_unsol_event(struct hda_codec *codec,
 				     unsigned int res)
 {
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc262_hippo1_automute( codec );
-
 	if ((res >> 26) == ALC880_MIC_EVENT)
 		alc662_eeepc_mic_automute(codec);
+	else
+		alc262_hippo_unsol_event(codec, res);
 }
 
 static void alc662_eeepc_inithook(struct hda_codec *codec)
 {
-	alc262_hippo1_automute( codec );
+	alc262_hippo1_init_hook(codec);
 	alc662_eeepc_mic_automute(codec);
 }
 
-static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
-{
-	unsigned int mute;
-	unsigned int present;
-
-	snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
-	present = snd_hda_codec_read(codec, 0x14, 0,
-				     AC_VERB_GET_PIN_SENSE, 0);
-	present = (present & 0x80000000) != 0;
-	if (present) {
-		/* mute internal speaker */
-		snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-					HDA_AMP_MUTE, HDA_AMP_MUTE);
-	} else {
-		/* unmute internal speaker if necessary */
-		mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
-		snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-					HDA_AMP_MUTE, mute);
-	}
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
-					  unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc662_eeepc_ep20_automute(codec);
-}
-
 static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
 {
-	alc662_eeepc_ep20_automute(codec);
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x1b;
+	alc262_hippo_master_update(codec);
 }
 
 static void alc663_m51va_speaker_automute(struct hda_codec *codec)
@@ -16338,35 +16631,9 @@
 	alc662_eeepc_mic_automute(codec);
 }
 
-/* bind hp and internal speaker mute (with plug check) */
-static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol,
-				     struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	long *valp = ucontrol->value.integer.value;
-	int change;
-
-	change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
-					  HDA_AMP_MUTE,
-					  valp[0] ? 0 : HDA_AMP_MUTE);
-	change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
-					   HDA_AMP_MUTE,
-					   valp[1] ? 0 : HDA_AMP_MUTE);
-	if (change)
-		alc262_hippo1_automute(codec);
-	return change;
-}
-
 static struct snd_kcontrol_new alc662_ecs_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Switch",
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
-		.put = alc662_ecs_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
-	},
+	ALC262_HIPPO_MASTER_SWITCH,
 
 	HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -16378,6 +16645,23 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new alc272_nc10_mixer[] = {
+	/* Master Playback automatically created from Speaker and Headphone */
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+	{ } /* end */
+};
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc662_loopbacks	alc880_loopbacks
 #endif
@@ -16411,6 +16695,9 @@
 	[ALC663_ASUS_MODE4] = "asus-mode4",
 	[ALC663_ASUS_MODE5] = "asus-mode5",
 	[ALC663_ASUS_MODE6] = "asus-mode6",
+	[ALC272_DELL]		= "dell",
+	[ALC272_DELL_ZM1]	= "dell-zm1",
+	[ALC272_SAMSUNG_NC10]	= "samsung-nc10",
 	[ALC662_AUTO]		= "auto",
 };
 
@@ -16468,6 +16755,7 @@
 	SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
 	SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
 		      ALC662_3ST_6ch_DIG),
+	SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
 	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
 		      ALC662_3ST_6ch_DIG),
 	SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
@@ -16558,7 +16846,7 @@
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
 		.channel_mode = alc662_3ST_6ch_modes,
 		.input_mux = &alc662_lenovo_101e_capture_source,
-		.unsol_event = alc662_eeepc_ep20_unsol_event,
+		.unsol_event = alc662_eeepc_unsol_event,
 		.init_hook = alc662_eeepc_ep20_inithook,
 	},
 	[ALC662_ECS] = {
@@ -16739,6 +17027,18 @@
 		.unsol_event = alc663_m51va_unsol_event,
 		.init_hook = alc663_m51va_inithook,
 	},
+	[ALC272_SAMSUNG_NC10] = {
+		.mixers = { alc272_nc10_mixer },
+		.init_verbs = { alc662_init_verbs,
+				alc663_21jd_amic_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc272_dac_nids),
+		.dac_nids = alc272_dac_nids,
+		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+		.channel_mode = alc662_3ST_2ch_modes,
+		.input_mux = &alc272_nc10_capture_source,
+		.unsol_event = alc663_mode4_unsol_event,
+		.init_hook = alc663_mode4_inithook,
+	},
 };
 
 
@@ -16933,7 +17233,6 @@
 	struct alc_spec *spec = codec->spec;
 	int i;
 
-	alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
 	for (i = 0; i <= HDA_SIDE; i++) {
 		hda_nid_t nid = spec->autocfg.line_out_pins[i];
 		int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -17030,6 +17329,8 @@
 	if (err < 0)
 		return err;
 
+	alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+
 	return 1;
 }
 
@@ -17062,8 +17363,8 @@
 						  alc662_models,
 			  	                  alc662_cfg_tbl);
 	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
-		       "trying auto-probe from BIOS...\n");
+		printk(KERN_INFO "hda_codec: Unknown model for %s, "
+		       "trying auto-probe from BIOS...\n", codec->chip_name);
 		board_config = ALC662_AUTO;
 	}
 
@@ -17090,17 +17391,6 @@
 	if (board_config != ALC662_AUTO)
 		setup_preset(spec, &alc662_presets[board_config]);
 
-	if (codec->vendor_id == 0x10ec0663) {
-		spec->stream_name_analog = "ALC663 Analog";
-		spec->stream_name_digital = "ALC663 Digital";
-	} else if (codec->vendor_id == 0x10ec0272) {
-		spec->stream_name_analog = "ALC272 Analog";
-		spec->stream_name_digital = "ALC272 Digital";
-	} else {
-		spec->stream_name_analog = "ALC662 Analog";
-		spec->stream_name_digital = "ALC662 Digital";
-	}
-
 	spec->stream_analog_playback = &alc662_pcm_analog_playback;
 	spec->stream_analog_capture = &alc662_pcm_analog_capture;
 
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index d2fd8ef..93e47c9 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -100,6 +100,7 @@
 	STAC_HP_M4,
 	STAC_HP_DV5,
 	STAC_HP_HDX,
+	STAC_HP_DV4_1222NR,
 	STAC_92HD71BXX_MODELS
 };
 
@@ -193,6 +194,7 @@
 	unsigned int gpio_dir;
 	unsigned int gpio_data;
 	unsigned int gpio_mute;
+	unsigned int gpio_led;
 
 	/* stream */
 	unsigned int stream_delay;
@@ -634,6 +636,40 @@
 	return 0;
 }
 
+static unsigned int stac92xx_vref_set(struct hda_codec *codec,
+					hda_nid_t nid, unsigned int new_vref)
+{
+	unsigned int error;
+	unsigned int pincfg;
+	pincfg = snd_hda_codec_read(codec, nid, 0,
+				AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+
+	pincfg &= 0xff;
+	pincfg &= ~(AC_PINCTL_VREFEN | AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
+	pincfg |= new_vref;
+
+	if (new_vref == AC_PINCTL_VREF_HIZ)
+		pincfg |= AC_PINCTL_OUT_EN;
+	else
+		pincfg |= AC_PINCTL_IN_EN;
+
+	error = snd_hda_codec_write_cache(codec, nid, 0,
+					AC_VERB_SET_PIN_WIDGET_CONTROL, pincfg);
+	if (error < 0)
+		return error;
+	else
+		return 1;
+}
+
+static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int vref;
+	vref = snd_hda_codec_read(codec, nid, 0,
+				AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+	vref &= AC_PINCTL_VREFEN;
+	return vref;
+}
+
 static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -995,6 +1031,17 @@
 		.private_value = verb_read | (verb_write << 16), \
 	}
 
+#define DC_BIAS(xname, idx, nid) \
+	{ \
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+		.name = xname, \
+		.index = idx, \
+		.info = stac92xx_dc_bias_info, \
+		.get = stac92xx_dc_bias_get, \
+		.put = stac92xx_dc_bias_put, \
+		.private_value = nid, \
+	}
+
 static struct snd_kcontrol_new stac9200_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
@@ -1543,6 +1590,8 @@
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_REF),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30,
+		      "SigmaTel",STAC_9205_REF),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
 		      "DFI LanParty", STAC_REF),
 	/* Dell laptops have BIOS problem */
@@ -1837,6 +1886,7 @@
 	[STAC_HP_M4]		= NULL,
 	[STAC_HP_DV5]		= NULL,
 	[STAC_HP_HDX]           = NULL,
+	[STAC_HP_DV4_1222NR]	= NULL,
 };
 
 static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
@@ -1848,6 +1898,7 @@
 	[STAC_HP_M4] = "hp-m4",
 	[STAC_HP_DV5] = "hp-dv5",
 	[STAC_HP_HDX] = "hp-hdx",
+	[STAC_HP_DV4_1222NR] = "hp-dv4-1222nr",
 };
 
 static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
@@ -1856,6 +1907,8 @@
 		      "DFI LanParty", STAC_92HD71BXX_REF),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
 		      "DFI LanParty", STAC_92HD71BXX_REF),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb,
+		      "HP dv4-1222nr", STAC_HP_DV4_1222NR),
 	SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080,
 		      "HP", STAC_HP_DV5),
 	SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0,
@@ -2545,7 +2598,8 @@
 	return 0;
 }
 
-static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int stac92xx_get_default_vref(struct hda_codec *codec,
+					hda_nid_t nid)
 {
 	unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
 	pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
@@ -2599,15 +2653,108 @@
 	return 1;
 }
 
-#define stac92xx_io_switch_info		snd_ctl_boolean_mono_info
+static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	int i;
+	static char *texts[] = {
+		"Mic In", "Line In", "Line Out"
+	};
+
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	hda_nid_t nid = kcontrol->private_value;
+
+	if (nid == spec->mic_switch || nid == spec->line_switch)
+		i = 3;
+	else
+		i = 2;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->value.enumerated.items = i;
+	uinfo->count = 1;
+	if (uinfo->value.enumerated.item >= i)
+		uinfo->value.enumerated.item = i-1;
+	strcpy(uinfo->value.enumerated.name,
+		texts[uinfo->value.enumerated.item]);
+
+	return 0;
+}
+
+static int stac92xx_dc_bias_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;
+	unsigned int vref = stac92xx_vref_get(codec, nid);
+
+	if (vref == stac92xx_get_default_vref(codec, nid))
+		ucontrol->value.enumerated.item[0] = 0;
+	else if (vref == AC_PINCTL_VREF_GRD)
+		ucontrol->value.enumerated.item[0] = 1;
+	else if (vref == AC_PINCTL_VREF_HIZ)
+		ucontrol->value.enumerated.item[0] = 2;
+
+	return 0;
+}
+
+static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int new_vref = 0;
+	unsigned int error;
+	hda_nid_t nid = kcontrol->private_value;
+
+	if (ucontrol->value.enumerated.item[0] == 0)
+		new_vref = stac92xx_get_default_vref(codec, nid);
+	else if (ucontrol->value.enumerated.item[0] == 1)
+		new_vref = AC_PINCTL_VREF_GRD;
+	else if (ucontrol->value.enumerated.item[0] == 2)
+		new_vref = AC_PINCTL_VREF_HIZ;
+	else
+		return 0;
+
+	if (new_vref != stac92xx_vref_get(codec, nid)) {
+		error = stac92xx_vref_set(codec, nid, new_vref);
+		return error;
+	}
+
+	return 0;
+}
+
+static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[2];
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	if (kcontrol->private_value == spec->line_switch)
+		texts[0] = "Line In";
+	else
+		texts[0] = "Mic In";
+	texts[1] = "Line Out";
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->value.enumerated.items = 2;
+	uinfo->count = 1;
+
+	if (uinfo->value.enumerated.item >= 2)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name,
+		texts[uinfo->value.enumerated.item]);
+
+	return 0;
+}
 
 static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct sigmatel_spec *spec = codec->spec;
-	int io_idx = kcontrol-> private_value & 0xff;
+	hda_nid_t nid = kcontrol->private_value;
+	int io_idx = (nid == spec->mic_switch) ? 1 : 0;
 
-	ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
+	ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx];
 	return 0;
 }
 
@@ -2615,9 +2762,9 @@
 {
         struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct sigmatel_spec *spec = codec->spec;
-        hda_nid_t nid = kcontrol->private_value >> 8;
-	int io_idx = kcontrol-> private_value & 0xff;
-	unsigned short val = !!ucontrol->value.integer.value[0];
+	hda_nid_t nid = kcontrol->private_value;
+	int io_idx = (nid == spec->mic_switch) ? 1 : 0;
+	unsigned short val = !!ucontrol->value.enumerated.item[0];
 
 	spec->io_switch[io_idx] = val;
 
@@ -2626,7 +2773,7 @@
 	else {
 		unsigned int pinctl = AC_PINCTL_IN_EN;
 		if (io_idx) /* set VREF for mic */
-			pinctl |= stac92xx_get_vref(codec, nid);
+			pinctl |= stac92xx_get_default_vref(codec, nid);
 		stac92xx_auto_set_pinctl(codec, nid, pinctl);
 	}
 
@@ -2707,7 +2854,8 @@
 	STAC_CTL_WIDGET_AMP_VOL,
 	STAC_CTL_WIDGET_HP_SWITCH,
 	STAC_CTL_WIDGET_IO_SWITCH,
-	STAC_CTL_WIDGET_CLFE_SWITCH
+	STAC_CTL_WIDGET_CLFE_SWITCH,
+	STAC_CTL_WIDGET_DC_BIAS
 };
 
 static struct snd_kcontrol_new stac92xx_control_templates[] = {
@@ -2719,6 +2867,7 @@
 	STAC_CODEC_HP_SWITCH(NULL),
 	STAC_CODEC_IO_SWITCH(NULL, 0),
 	STAC_CODEC_CLFE_SWITCH(NULL, 0),
+	DC_BIAS(NULL, 0, 0),
 };
 
 /* add dynamic controls */
@@ -2782,6 +2931,34 @@
 	.put = stac92xx_mux_enum_put,
 };
 
+static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
+						hda_nid_t nid, int idx)
+{
+	int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+	int control = 0;
+	struct sigmatel_spec *spec = codec->spec;
+	char name[22];
+
+	if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) {
+		if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
+			&& nid == spec->line_switch)
+			control = STAC_CTL_WIDGET_IO_SWITCH;
+		else if (snd_hda_query_pin_caps(codec, nid)
+			& (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT))
+			control = STAC_CTL_WIDGET_DC_BIAS;
+		else if (nid == spec->mic_switch)
+			control = STAC_CTL_WIDGET_IO_SWITCH;
+	}
+
+	if (control) {
+		strcpy(name, auto_pin_cfg_labels[idx]);
+		return stac92xx_add_control(codec->spec, control,
+					strcat(name, " Jack Mode"), nid);
+	}
+
+	return 0;
+}
+
 static int stac92xx_add_input_source(struct sigmatel_spec *spec)
 {
 	struct snd_kcontrol_new *knew;
@@ -3144,7 +3321,9 @@
 					       const struct auto_pin_cfg *cfg)
 {
 	struct sigmatel_spec *spec = codec->spec;
+	hda_nid_t nid;
 	int err;
+	int idx;
 
 	err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins,
 				    spec->multiout.dac_nids,
@@ -3161,20 +3340,13 @@
 			return err;
 	}
 
-	if (spec->line_switch) {
-		err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
-					   "Line In as Output Switch",
-					   spec->line_switch << 8);
-		if (err < 0)
-			return err;
-	}
-
-	if (spec->mic_switch) {
-		err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
-					   "Mic as Output Switch",
-					   (spec->mic_switch << 8) | 1);
-		if (err < 0)
-			return err;
+	for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) {
+		nid = cfg->input_pins[idx];
+		if (nid) {
+			err = stac92xx_add_jack_mode_control(codec, nid, idx);
+			if (err < 0)
+				return err;
+		}
 	}
 
 	return 0;
@@ -3639,6 +3811,8 @@
 		err = snd_hda_attach_beep_device(codec, nid);
 		if (err < 0)
 			return err;
+		/* IDT/STAC codecs have linear beep tone parameter */
+		codec->beep->linear_tone = 1;
 		/* if no beep switch is available, make its own one */
 		caps = query_amp_caps(codec, nid, HDA_OUTPUT);
 		if (codec->beep &&
@@ -4082,7 +4256,7 @@
 			unsigned int pinctl, conf;
 			if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
 				/* for mic pins, force to initialize */
-				pinctl = stac92xx_get_vref(codec, nid);
+				pinctl = stac92xx_get_default_vref(codec, nid);
 				pinctl |= AC_PINCTL_IN_EN;
 				stac92xx_auto_set_pinctl(codec, nid, pinctl);
 			} else {
@@ -4535,17 +4709,19 @@
 	return 0;
 }
 
-
 /*
- * using power check for controlling mute led of HP HDX notebooks
+ * using power check for controlling mute led of HP notebooks
  * check for mute state only on Speakers (nid = 0x10)
  *
  * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise
  * the LED is NOT working properly !
+ *
+ * Changed name to reflect that it now works for any designated
+ * model, not just HP HDX.
  */
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static int stac92xx_hp_hdx_check_power_status(struct hda_codec *codec,
+static int stac92xx_hp_check_power_status(struct hda_codec *codec,
 					      hda_nid_t nid)
 {
 	struct sigmatel_spec *spec = codec->spec;
@@ -4553,9 +4729,9 @@
 	if (nid == 0x10) {
 		if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
 		    HDA_AMP_MUTE)
-			spec->gpio_data &= ~0x08;  /* orange */
+			spec->gpio_data &= ~spec->gpio_led; /* orange */
 		else
-			spec->gpio_data |= 0x08;   /* white */
+			spec->gpio_data |= spec->gpio_led; /* white */
 
 		stac_gpio_set(codec, spec->gpio_mask,
 			      spec->gpio_dir,
@@ -5201,6 +5377,15 @@
 	if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
 		snd_hda_sequence_write_cache(codec, unmute_init);
 
+	/* Some HP machines seem to have unstable codec communications
+	 * especially with ATI fglrx driver.  For recovering from the
+	 * CORB/RIRB stall, allow the BUS reset and keep always sync
+	 */
+	if (spec->board_config == STAC_HP_DV5) {
+		codec->bus->sync_write = 1;
+		codec->bus->allow_bus_reset = 1;
+	}
+
 	spec->aloopback_ctl = stac92hd71bxx_loopback;
 	spec->aloopback_mask = 0x50;
 	spec->aloopback_shift = 0;
@@ -5234,6 +5419,15 @@
 		spec->num_smuxes = 0;
 		spec->num_dmuxes = 1;
 		break;
+	case STAC_HP_DV4_1222NR:
+		spec->num_dmics = 1;
+		/* I don't know if it needs 1 or 2 smuxes - will wait for
+		 * bug reports to fix if needed
+		 */
+		spec->num_smuxes = 1;
+		spec->num_dmuxes = 1;
+		spec->gpio_led = 0x01;
+		/* fallthrough */
 	case STAC_HP_DV5:
 		snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010);
 		stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN);
@@ -5242,22 +5436,21 @@
 		spec->num_dmics = 1;
 		spec->num_dmuxes = 1;
 		spec->num_smuxes = 1;
-		/*
-		 * For controlling MUTE LED on HP HDX16/HDX18 notebooks,
-		 * the CONFIG_SND_HDA_POWER_SAVE is needed to be set.
-		 */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
 		/* orange/white mute led on GPIO3, orange=0, white=1 */
-		spec->gpio_mask |= 0x08;
-		spec->gpio_dir  |= 0x08;
-		spec->gpio_data |= 0x08;  /* set to white */
+		spec->gpio_led = 0x08;
+		break;
+	}
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	if (spec->gpio_led) {
+		spec->gpio_mask |= spec->gpio_led;
+		spec->gpio_dir |= spec->gpio_led;
+		spec->gpio_data |= spec->gpio_led;
 		/* register check_power_status callback. */
 		codec->patch_ops.check_power_status =
-		    stac92xx_hp_hdx_check_power_status;
+			stac92xx_hp_check_power_status;
+	}
 #endif	
-		break;
-	};
 
 	spec->multiout.dac_nids = spec->dac_nids;
 	if (spec->dinput_mux)
@@ -5282,7 +5475,7 @@
 	codec->proc_widget_hook = stac92hd7x_proc_hook;
 
 	return 0;
-};
+}
 
 static int patch_stac922x(struct hda_codec *codec)
 {
@@ -5437,7 +5630,7 @@
 			/* correct the device field to SPDIF out */
 			snd_hda_codec_set_pincfg(codec, 0x21, 0x01442070);
 			break;
-		};
+		}
 		/* configure the analog microphone on some laptops */
 		snd_hda_codec_set_pincfg(codec, 0x0c, 0x90a79130);
 		/* correct the front output jack as a hp out */
@@ -5747,6 +5940,7 @@
  	{ .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
  	{ .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
  	{ .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
+	{ .id = 0x83847698, .name = "STAC9205", .patch = patch_stac9205 },
  	{ .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
  	{ .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
  	{ .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index b25a5cc..8e004fb 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -205,7 +205,7 @@
 
 	/* playback */
 	struct hda_multi_out multiout;
-	hda_nid_t extra_dig_out_nid;
+	hda_nid_t slave_dig_outs[2];
 
 	/* capture */
 	unsigned int num_adc_nids;
@@ -731,21 +731,6 @@
 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
-/* setup SPDIF output stream */
-static void setup_dig_playback_stream(struct hda_codec *codec, hda_nid_t nid,
-				 unsigned int stream_tag, unsigned int format)
-{
-	/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
-	if (codec->spdif_ctls & AC_DIG1_ENABLE)
-		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
-				    codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
-	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
-	/* turn on again (if needed) */
-	if (codec->spdif_ctls & AC_DIG1_ENABLE)
-		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
-				    codec->spdif_ctls & 0xff);
-}
-
 static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 					struct hda_codec *codec,
 					unsigned int stream_tag,
@@ -753,19 +738,16 @@
 					struct snd_pcm_substream *substream)
 {
 	struct via_spec *spec = codec->spec;
-	hda_nid_t nid;
+	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+					     stream_tag, format, substream);
+}
 
-	/* 1st or 2nd S/PDIF */
-	if (substream->number == 0)
-		nid = spec->multiout.dig_out_nid;
-	else if (substream->number == 1)
-		nid = spec->extra_dig_out_nid;
-	else
-		return -1;
-
-	mutex_lock(&codec->spdif_mutex);
-	setup_dig_playback_stream(codec, nid, stream_tag, format);
-	mutex_unlock(&codec->spdif_mutex);
+static int via_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					struct snd_pcm_substream *substream)
+{
+	struct via_spec *spec = codec->spec;
+	snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
 	return 0;
 }
 
@@ -842,7 +824,8 @@
 	.ops = {
 		.open = via_dig_playback_pcm_open,
 		.close = via_dig_playback_pcm_close,
-		.prepare = via_dig_playback_pcm_prepare
+		.prepare = via_dig_playback_pcm_prepare,
+		.cleanup = via_dig_playback_pcm_cleanup
 	},
 };
 
@@ -874,13 +857,6 @@
 		if (err < 0)
 			return err;
 		spec->multiout.share_spdif = 1;
-
-		if (spec->extra_dig_out_nid) {
-			err = snd_hda_create_spdif_out_ctls(codec,
-						    spec->extra_dig_out_nid);
-			if (err < 0)
-				return err;
-		}
 	}
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -1013,10 +989,6 @@
 		via_gpio_control(codec);
 }
 
-static hda_nid_t slave_dig_outs[] = {
-	0,
-};
-
 static int via_init(struct hda_codec *codec)
 {
 	struct via_spec *spec = codec->spec;
@@ -1051,8 +1023,9 @@
 		snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
 				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
 
-	/* no slave outs */
-	codec->slave_dig_outs = slave_dig_outs;
+	/* assign slave outs */
+	if (spec->slave_dig_outs[0])
+		codec->slave_dig_outs = spec->slave_dig_outs;
 
  	return 0;
 }
@@ -2134,7 +2107,8 @@
 	.ops = {
 		.open = via_dig_playback_pcm_open,
 		.close = via_dig_playback_pcm_close,
-		.prepare = via_dig_playback_pcm_prepare
+		.prepare = via_dig_playback_pcm_prepare,
+		.cleanup = via_dig_playback_pcm_cleanup
 	},
 };
 
@@ -2589,14 +2563,15 @@
 };
 
 static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
-	.substreams = 2,
+	.substreams = 1,
 	.channels_min = 2,
 	.channels_max = 2,
 	/* NID is set in via_build_pcms */
 	.ops = {
 		.open = via_dig_playback_pcm_open,
 		.close = via_dig_playback_pcm_close,
-		.prepare = via_dig_playback_pcm_prepare
+		.prepare = via_dig_playback_pcm_prepare,
+		.cleanup = via_dig_playback_pcm_cleanup
 	},
 };
 
@@ -2805,14 +2780,37 @@
 	return 0;
 }
 
+/* fill out digital output widgets; one for master and one for slave outputs */
+static void fill_dig_outs(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int i;
+
+	for (i = 0; i < spec->autocfg.dig_outs; i++) {
+		hda_nid_t nid;
+		int conn;
+
+		nid = spec->autocfg.dig_out_pins[i];
+		if (!nid)
+			continue;
+		conn = snd_hda_get_connections(codec, nid, &nid, 1);
+		if (conn < 1)
+			continue;
+		if (!spec->multiout.dig_out_nid)
+			spec->multiout.dig_out_nid = nid;
+		else {
+			spec->slave_dig_outs[0] = nid;
+			break; /* at most two dig outs */
+		}
+	}
+}
+
 static int vt1708S_parse_auto_config(struct hda_codec *codec)
 {
 	struct via_spec *spec = codec->spec;
 	int err;
-	static hda_nid_t vt1708s_ignore[] = {0x21, 0};
 
-	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-					   vt1708s_ignore);
+	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
 	if (err < 0)
 		return err;
 	err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
@@ -2833,10 +2831,7 @@
 
 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-	if (spec->autocfg.dig_outs)
-		spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID;
-
-	spec->extra_dig_out_nid = 0x15;
+	fill_dig_outs(codec);
 
 	if (spec->kctls.list)
 		spec->mixers[spec->num_mixers++] = spec->kctls.list;
@@ -3000,7 +2995,8 @@
 	.ops = {
 		.open = via_dig_playback_pcm_open,
 		.close = via_dig_playback_pcm_close,
-		.prepare = via_dig_playback_pcm_prepare
+		.prepare = via_dig_playback_pcm_prepare,
+		.cleanup = via_dig_playback_pcm_cleanup
 	},
 };
 
@@ -3128,10 +3124,8 @@
 {
 	struct via_spec *spec = codec->spec;
 	int err;
-	static hda_nid_t vt1702_ignore[] = {0x1C, 0};
 
-	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-					   vt1702_ignore);
+	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
 	if (err < 0)
 		return err;
 	err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
@@ -3152,10 +3146,7 @@
 
 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-	if (spec->autocfg.dig_outs)
-		spec->multiout.dig_out_nid = VT1702_DIGOUT_NID;
-
-	spec->extra_dig_out_nid = 0x1B;
+	fill_dig_outs(codec);
 
 	if (spec->kctls.list)
 		spec->mixers[spec->num_mixers++] = spec->kctls.list;
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile
index f99fe08..536eae2 100644
--- a/sound/pci/ice1712/Makefile
+++ b/sound/pci/ice1712/Makefile
@@ -5,7 +5,7 @@
 
 snd-ice17xx-ak4xxx-objs := ak4xxx.o
 snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o
-snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o
+snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index fdae6de..adc909e 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -335,6 +335,7 @@
 	unsigned int force_rdma1:1;	/* VT1720/4 - RDMA1 as non-spdif */
 	unsigned int midi_output:1;	/* VT1720/4: MIDI output triggered */
 	unsigned int midi_input:1;	/* VT1720/4: MIDI input triggered */
+	unsigned int own_routing:1;	/* VT1720/4: use own routing ctls */
 	unsigned int num_total_dacs;	/* total DACs */
 	unsigned int num_total_adcs;	/* total ADCs */
 	unsigned int cur_rate;		/* current rate */
@@ -458,10 +459,17 @@
 	return  snd_ice1712_gpio_read(ice) & mask;
 }
 
+/* route access functions */
+int snd_ice1724_get_route_val(struct snd_ice1712 *ice, int shift);
+int snd_ice1724_put_route_val(struct snd_ice1712 *ice, unsigned int val,
+								int shift);
+
 int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice);
 
-int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *template,
-			     const struct snd_ak4xxx_private *priv, struct snd_ice1712 *ice);
+int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak,
+			     const struct snd_akm4xxx *template,
+			     const struct snd_ak4xxx_private *priv,
+			     struct snd_ice1712 *ice);
 void snd_ice1712_akm4xxx_free(struct snd_ice1712 *ice);
 int snd_ice1712_akm4xxx_build_controls(struct snd_ice1712 *ice);
 
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 128510e7..36ade77 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -49,6 +49,7 @@
 #include "prodigy192.h"
 #include "prodigy_hifi.h"
 #include "juli.h"
+#include "maya44.h"
 #include "phase.h"
 #include "wtm.h"
 #include "se.h"
@@ -65,6 +66,7 @@
 	       PRODIGY192_DEVICE_DESC
 	       PRODIGY_HIFI_DEVICE_DESC
 	       JULI_DEVICE_DESC
+	       MAYA44_DEVICE_DESC
 	       PHASE_DEVICE_DESC
 	       WTM_DEVICE_DESC
 	       SE_DEVICE_DESC
@@ -626,7 +628,7 @@
 	return 0;
 }
 
-static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
+static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
 				    int force)
 {
 	unsigned long flags;
@@ -634,17 +636,18 @@
 	unsigned int i, old_rate;
 
 	if (rate > ice->hw_rates->list[ice->hw_rates->count - 1])
-		return;
+		return -EINVAL;
+
 	spin_lock_irqsave(&ice->reg_lock, flags);
 	if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) ||
 	    (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) {
 		/* running? we cannot change the rate now... */
 		spin_unlock_irqrestore(&ice->reg_lock, flags);
-		return;
+		return -EBUSY;
 	}
 	if (!force && is_pro_rate_locked(ice)) {
 		spin_unlock_irqrestore(&ice->reg_lock, flags);
-		return;
+		return (rate == ice->cur_rate) ? 0 : -EBUSY;
 	}
 
 	old_rate = ice->get_rate(ice);
@@ -652,7 +655,7 @@
 		ice->set_rate(ice, rate);
 	else if (rate == ice->cur_rate) {
 		spin_unlock_irqrestore(&ice->reg_lock, flags);
-		return;
+		return 0;
 	}
 
 	ice->cur_rate = rate;
@@ -674,13 +677,15 @@
 	}
 	if (ice->spdif.ops.setup_rate)
 		ice->spdif.ops.setup_rate(ice, rate);
+
+	return 0;
 }
 
 static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream,
 				    struct snd_pcm_hw_params *hw_params)
 {
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
-	int i, chs;
+	int i, chs, err;
 
 	chs = params_channels(hw_params);
 	mutex_lock(&ice->open_mutex);
@@ -715,7 +720,11 @@
 		}
 	}
 	mutex_unlock(&ice->open_mutex);
-	snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0);
+
+	err = snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0);
+	if (err < 0)
+		return err;
+
 	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
 }
 
@@ -848,20 +857,39 @@
 #endif
 }
 
-static const struct vt1724_pcm_reg vt1724_playback_pro_reg = {
+static const struct vt1724_pcm_reg vt1724_pdma0_reg = {
 	.addr = VT1724_MT_PLAYBACK_ADDR,
 	.size = VT1724_MT_PLAYBACK_SIZE,
 	.count = VT1724_MT_PLAYBACK_COUNT,
 	.start = VT1724_PDMA0_START,
 };
 
-static const struct vt1724_pcm_reg vt1724_capture_pro_reg = {
+static const struct vt1724_pcm_reg vt1724_pdma4_reg = {
+	.addr = VT1724_MT_PDMA4_ADDR,
+	.size = VT1724_MT_PDMA4_SIZE,
+	.count = VT1724_MT_PDMA4_COUNT,
+	.start = VT1724_PDMA4_START,
+};
+
+static const struct vt1724_pcm_reg vt1724_rdma0_reg = {
 	.addr = VT1724_MT_CAPTURE_ADDR,
 	.size = VT1724_MT_CAPTURE_SIZE,
 	.count = VT1724_MT_CAPTURE_COUNT,
 	.start = VT1724_RDMA0_START,
 };
 
+static const struct vt1724_pcm_reg vt1724_rdma1_reg = {
+	.addr = VT1724_MT_RDMA1_ADDR,
+	.size = VT1724_MT_RDMA1_SIZE,
+	.count = VT1724_MT_RDMA1_COUNT,
+	.start = VT1724_RDMA1_START,
+};
+
+#define vt1724_playback_pro_reg vt1724_pdma0_reg
+#define vt1724_playback_spdif_reg vt1724_pdma4_reg
+#define vt1724_capture_pro_reg vt1724_rdma0_reg
+#define vt1724_capture_spdif_reg vt1724_rdma1_reg
+
 static const struct snd_pcm_hardware snd_vt1724_playback_pro = {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -1077,20 +1105,6 @@
  * SPDIF PCM
  */
 
-static const struct vt1724_pcm_reg vt1724_playback_spdif_reg = {
-	.addr = VT1724_MT_PDMA4_ADDR,
-	.size = VT1724_MT_PDMA4_SIZE,
-	.count = VT1724_MT_PDMA4_COUNT,
-	.start = VT1724_PDMA4_START,
-};
-
-static const struct vt1724_pcm_reg vt1724_capture_spdif_reg = {
-	.addr = VT1724_MT_RDMA1_ADDR,
-	.size = VT1724_MT_RDMA1_SIZE,
-	.count = VT1724_MT_RDMA1_COUNT,
-	.start = VT1724_RDMA1_START,
-};
-
 /* update spdif control bits; call with reg_lock */
 static void update_spdif_bits(struct snd_ice1712 *ice, unsigned int val)
 {
@@ -1963,7 +1977,7 @@
 	return idx * 3;
 }
 
-static int get_route_val(struct snd_ice1712 *ice, int shift)
+int snd_ice1724_get_route_val(struct snd_ice1712 *ice, int shift)
 {
 	unsigned long val;
 	unsigned char eitem;
@@ -1982,7 +1996,8 @@
 	return eitem;
 }
 
-static int put_route_val(struct snd_ice1712 *ice, unsigned int val, int shift)
+int snd_ice1724_put_route_val(struct snd_ice1712 *ice, unsigned int val,
+								int shift)
 {
 	unsigned int old_val, nval;
 	int change;
@@ -2010,7 +2025,7 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	ucontrol->value.enumerated.item[0] =
-		get_route_val(ice, analog_route_shift(idx));
+		snd_ice1724_get_route_val(ice, analog_route_shift(idx));
 	return 0;
 }
 
@@ -2019,8 +2034,9 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	return put_route_val(ice, ucontrol->value.enumerated.item[0],
-			     analog_route_shift(idx));
+	return snd_ice1724_put_route_val(ice,
+					 ucontrol->value.enumerated.item[0],
+					 analog_route_shift(idx));
 }
 
 static int snd_vt1724_pro_route_spdif_get(struct snd_kcontrol *kcontrol,
@@ -2029,7 +2045,7 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	ucontrol->value.enumerated.item[0] =
-		get_route_val(ice, digital_route_shift(idx));
+		snd_ice1724_get_route_val(ice, digital_route_shift(idx));
 	return 0;
 }
 
@@ -2038,11 +2054,13 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	return put_route_val(ice, ucontrol->value.enumerated.item[0],
-			     digital_route_shift(idx));
+	return snd_ice1724_put_route_val(ice,
+					 ucontrol->value.enumerated.item[0],
+					 digital_route_shift(idx));
 }
 
-static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = {
+static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata =
+{
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "H/W Playback Route",
 	.info = snd_vt1724_pro_route_info,
@@ -2109,6 +2127,7 @@
 	snd_vt1724_prodigy_hifi_cards,
 	snd_vt1724_prodigy192_cards,
 	snd_vt1724_juli_cards,
+	snd_vt1724_maya44_cards,
 	snd_vt1724_phase_cards,
 	snd_vt1724_wtm_cards,
 	snd_vt1724_se_cards,
@@ -2246,8 +2265,10 @@
 static void __devinit snd_vt1724_chip_reset(struct snd_ice1712 *ice)
 {
 	outb(VT1724_RESET , ICEREG1724(ice, CONTROL));
+	inb(ICEREG1724(ice, CONTROL)); /* pci posting flush */
 	msleep(10);
 	outb(0, ICEREG1724(ice, CONTROL));
+	inb(ICEREG1724(ice, CONTROL)); /* pci posting flush */
 	msleep(10);
 }
 
@@ -2277,9 +2298,12 @@
 	if (snd_BUG_ON(!ice->pcm))
 		return -EIO;
 
-	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice));
-	if (err < 0)
-		return err;
+	if (!ice->own_routing) {
+		err = snd_ctl_add(ice->card,
+			snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice));
+		if (err < 0)
+			return err;
+	}
 
 	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_spdif_switch, ice));
 	if (err < 0)
@@ -2326,7 +2350,7 @@
 	if (err < 0)
 		return err;
 
-	if (ice->num_total_dacs > 0) {
+	if (!ice->own_routing && ice->num_total_dacs > 0) {
 		struct snd_kcontrol_new tmp = snd_vt1724_mixer_pro_analog_route;
 		tmp.count = ice->num_total_dacs;
 		if (ice->vt1720 && tmp.count > 2)
diff --git a/sound/pci/ice1712/maya44.c b/sound/pci/ice1712/maya44.c
new file mode 100644
index 0000000..3e1c20a
--- /dev/null
+++ b/sound/pci/ice1712/maya44.c
@@ -0,0 +1,779 @@
+/*
+ *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
+ *
+ *   Lowlevel functions for ESI Maya44 cards
+ *
+ *	Copyright (c) 2009 Takashi Iwai <tiwai@suse.de>
+ *	Based on the patches by Rainer Zimmermann <mail@lightshed.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include "maya44.h"
+
+/* WM8776 register indexes */
+#define WM8776_REG_HEADPHONE_L		0x00
+#define WM8776_REG_HEADPHONE_R		0x01
+#define WM8776_REG_HEADPHONE_MASTER	0x02
+#define WM8776_REG_DAC_ATTEN_L		0x03
+#define WM8776_REG_DAC_ATTEN_R		0x04
+#define WM8776_REG_DAC_ATTEN_MASTER	0x05
+#define WM8776_REG_DAC_PHASE		0x06
+#define WM8776_REG_DAC_CONTROL		0x07
+#define WM8776_REG_DAC_MUTE		0x08
+#define WM8776_REG_DAC_DEEMPH		0x09
+#define WM8776_REG_DAC_IF_CONTROL	0x0a
+#define WM8776_REG_ADC_IF_CONTROL	0x0b
+#define WM8776_REG_MASTER_MODE_CONTROL	0x0c
+#define WM8776_REG_POWERDOWN		0x0d
+#define WM8776_REG_ADC_ATTEN_L		0x0e
+#define WM8776_REG_ADC_ATTEN_R		0x0f
+#define WM8776_REG_ADC_ALC1		0x10
+#define WM8776_REG_ADC_ALC2		0x11
+#define WM8776_REG_ADC_ALC3		0x12
+#define WM8776_REG_ADC_NOISE_GATE	0x13
+#define WM8776_REG_ADC_LIMITER		0x14
+#define WM8776_REG_ADC_MUX		0x15
+#define WM8776_REG_OUTPUT_MUX		0x16
+#define WM8776_REG_RESET		0x17
+
+#define WM8776_NUM_REGS			0x18
+
+/* clock ratio identifiers for snd_wm8776_set_rate() */
+#define WM8776_CLOCK_RATIO_128FS	0
+#define WM8776_CLOCK_RATIO_192FS	1
+#define WM8776_CLOCK_RATIO_256FS	2
+#define WM8776_CLOCK_RATIO_384FS	3
+#define WM8776_CLOCK_RATIO_512FS	4
+#define WM8776_CLOCK_RATIO_768FS	5
+
+enum { WM_VOL_HP, WM_VOL_DAC, WM_VOL_ADC, WM_NUM_VOLS };
+enum { WM_SW_DAC, WM_SW_BYPASS, WM_NUM_SWITCHES };
+
+struct snd_wm8776 {
+	unsigned char addr;
+	unsigned short regs[WM8776_NUM_REGS];
+	unsigned char volumes[WM_NUM_VOLS][2];
+	unsigned int switch_bits;
+};
+
+struct snd_maya44 {
+	struct snd_ice1712 *ice;
+	struct snd_wm8776 wm[2];
+	struct mutex mutex;
+};
+
+
+/* write the given register and save the data to the cache */
+static void wm8776_write(struct snd_ice1712 *ice, struct snd_wm8776 *wm,
+			 unsigned char reg, unsigned short val)
+{
+	/*
+	 * WM8776 registers are up to 9 bits wide, bit 8 is placed in the LSB
+	 * of the address field
+	 */
+	snd_vt1724_write_i2c(ice, wm->addr,
+			     (reg << 1) | ((val >> 8) & 1),
+			     val & 0xff);
+	wm->regs[reg] = val;
+}
+
+/*
+ * update the given register with and/or mask and save the data to the cache
+ */
+static int wm8776_write_bits(struct snd_ice1712 *ice, struct snd_wm8776 *wm,
+			     unsigned char reg,
+			     unsigned short mask, unsigned short val)
+{
+	val |= wm->regs[reg] & ~mask;
+	if (val != wm->regs[reg]) {
+		wm8776_write(ice, wm, reg, val);
+		return 1;
+	}
+	return 0;
+}
+
+
+/*
+ * WM8776 volume controls
+ */
+
+struct maya_vol_info {
+	unsigned int maxval;		/* volume range: 0..maxval */
+	unsigned char regs[2];		/* left and right registers */
+	unsigned short mask;		/* value mask */
+	unsigned short offset;		/* zero-value offset */
+	unsigned short mute;		/* mute bit */
+	unsigned short update;		/* update bits */
+	unsigned char mux_bits[2];	/* extra bits for ADC mute */
+};
+
+static struct maya_vol_info vol_info[WM_NUM_VOLS] = {
+	[WM_VOL_HP] = {
+		.maxval = 80,
+		.regs = { WM8776_REG_HEADPHONE_L, WM8776_REG_HEADPHONE_R },
+		.mask = 0x7f,
+		.offset = 0x30,
+		.mute = 0x00,
+		.update = 0x180,	/* update and zero-cross enable */
+	},
+	[WM_VOL_DAC] = {
+		.maxval = 255,
+		.regs = { WM8776_REG_DAC_ATTEN_L, WM8776_REG_DAC_ATTEN_R },
+		.mask = 0xff,
+		.offset = 0x01,
+		.mute = 0x00,
+		.update = 0x100,	/* zero-cross enable */
+	},
+	[WM_VOL_ADC] = {
+		.maxval = 91,
+		.regs = { WM8776_REG_ADC_ATTEN_L, WM8776_REG_ADC_ATTEN_R },
+		.mask = 0xff,
+		.offset = 0xa5,
+		.mute = 0xa5,
+		.update = 0x100,	/* update */
+		.mux_bits = { 0x80, 0x40 }, /* ADCMUX bits */
+	},
+};
+
+/*
+ * dB tables
+ */
+/* headphone output: mute, -73..+6db (1db step) */
+static const DECLARE_TLV_DB_SCALE(db_scale_hp, -7400, 100, 1);
+/* DAC output: mute, -127..0db (0.5db step) */
+static const DECLARE_TLV_DB_SCALE(db_scale_dac, -12750, 50, 1);
+/* ADC gain: mute, -21..+24db (0.5db step) */
+static const DECLARE_TLV_DB_SCALE(db_scale_adc, -2100, 50, 1);
+
+static int maya_vol_info(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_info *uinfo)
+{
+	unsigned int idx = kcontrol->private_value;
+	struct maya_vol_info *vol = &vol_info[idx];
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = vol->maxval;
+	return 0;
+}
+
+static int maya_vol_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wm8776 *wm =
+		&chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)];
+	unsigned int idx = kcontrol->private_value;
+
+	mutex_lock(&chip->mutex);
+	ucontrol->value.integer.value[0] = wm->volumes[idx][0];
+	ucontrol->value.integer.value[1] = wm->volumes[idx][1];
+	mutex_unlock(&chip->mutex);
+	return 0;
+}
+
+static int maya_vol_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wm8776 *wm =
+		&chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)];
+	unsigned int idx = kcontrol->private_value;
+	struct maya_vol_info *vol = &vol_info[idx];
+	unsigned int val, data;
+	int ch, changed = 0;
+
+	mutex_lock(&chip->mutex);
+	for (ch = 0; ch < 2; ch++) {
+		val = ucontrol->value.integer.value[ch];
+		if (val > vol->maxval)
+			val = vol->maxval;
+		if (val == wm->volumes[idx][ch])
+			continue;
+		if (!val)
+			data = vol->mute;
+		else
+			data = (val - 1) + vol->offset;
+		data |= vol->update;
+		changed |= wm8776_write_bits(chip->ice, wm, vol->regs[ch],
+					     vol->mask | vol->update, data);
+		if (vol->mux_bits[ch])
+			wm8776_write_bits(chip->ice, wm, WM8776_REG_ADC_MUX,
+					  vol->mux_bits[ch],
+					  val ? 0 : vol->mux_bits[ch]);
+		wm->volumes[idx][ch] = val;
+	}
+	mutex_unlock(&chip->mutex);
+	return changed;
+}
+
+/*
+ * WM8776 switch controls
+ */
+
+#define COMPOSE_SW_VAL(idx, reg, mask)	((idx) | ((reg) << 8) | ((mask) << 16))
+#define GET_SW_VAL_IDX(val)	((val) & 0xff)
+#define GET_SW_VAL_REG(val)	(((val) >> 8) & 0xff)
+#define GET_SW_VAL_MASK(val)	(((val) >> 16) & 0xff)
+
+#define maya_sw_info	snd_ctl_boolean_mono_info
+
+static int maya_sw_get(struct snd_kcontrol *kcontrol,
+		       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wm8776 *wm =
+		&chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)];
+	unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value);
+
+	ucontrol->value.integer.value[0] = (wm->switch_bits >> idx) & 1;
+	return 0;
+}
+
+static int maya_sw_put(struct snd_kcontrol *kcontrol,
+		       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+	struct snd_wm8776 *wm =
+		&chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)];
+	unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value);
+	unsigned int mask, val;
+	int changed;
+
+	mutex_lock(&chip->mutex);
+	mask = 1 << idx;
+	wm->switch_bits &= ~mask;
+	val = ucontrol->value.integer.value[0];
+	if (val)
+		wm->switch_bits |= mask;
+	mask = GET_SW_VAL_MASK(kcontrol->private_value);
+	changed = wm8776_write_bits(chip->ice, wm,
+				    GET_SW_VAL_REG(kcontrol->private_value),
+				    mask, val ? mask : 0);
+	mutex_unlock(&chip->mutex);
+	return changed;
+}
+
+/*
+ * GPIO pins (known ones for maya44)
+ */
+#define GPIO_PHANTOM_OFF	2
+#define GPIO_MIC_RELAY		4
+#define GPIO_SPDIF_IN_INV	5
+#define GPIO_MUST_BE_0		7
+
+/*
+ * GPIO switch controls
+ */
+
+#define COMPOSE_GPIO_VAL(shift, inv)	((shift) | ((inv) << 8))
+#define GET_GPIO_VAL_SHIFT(val)		((val) & 0xff)
+#define GET_GPIO_VAL_INV(val)		(((val) >> 8) & 1)
+
+static int maya_set_gpio_bits(struct snd_ice1712 *ice, unsigned int mask,
+			      unsigned int bits)
+{
+	unsigned int data;
+	data = snd_ice1712_gpio_read(ice);
+	if ((data & mask) == bits)
+		return 0;
+	snd_ice1712_gpio_write(ice, (data & ~mask) | bits);
+	return 1;
+}
+
+#define maya_gpio_sw_info	snd_ctl_boolean_mono_info
+
+static int maya_gpio_sw_get(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value);
+	unsigned int val;
+
+	val = (snd_ice1712_gpio_read(chip->ice) >> shift) & 1;
+	if (GET_GPIO_VAL_INV(kcontrol->private_value))
+		val = !val;
+	ucontrol->value.integer.value[0] = val;
+	return 0;
+}
+
+static int maya_gpio_sw_put(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value);
+	unsigned int val, mask;
+	int changed;
+
+	mutex_lock(&chip->mutex);
+	mask = 1 << shift;
+	val = ucontrol->value.integer.value[0];
+	if (GET_GPIO_VAL_INV(kcontrol->private_value))
+		val = !val;
+	val = val ? mask : 0;
+	changed = maya_set_gpio_bits(chip->ice, mask, val);
+	mutex_unlock(&chip->mutex);
+	return changed;
+}
+
+/*
+ * capture source selection
+ */
+
+/* known working input slots (0-4) */
+#define MAYA_LINE_IN	1	/* in-2 */
+#define MAYA_MIC_IN	4	/* in-5 */
+
+static void wm8776_select_input(struct snd_maya44 *chip, int idx, int line)
+{
+	wm8776_write_bits(chip->ice, &chip->wm[idx], WM8776_REG_ADC_MUX,
+			  0x1f, 1 << line);
+}
+
+static int maya_rec_src_info(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[] = { "Line", "Mic" };
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = ARRAY_SIZE(texts);
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item =
+			uinfo->value.enumerated.items - 1;
+	strcpy(uinfo->value.enumerated.name,
+	       texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int maya_rec_src_get(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+	int sel;
+
+	if (snd_ice1712_gpio_read(chip->ice) & (1 << GPIO_MIC_RELAY))
+		sel = 1;
+	else
+		sel = 0;
+	ucontrol->value.enumerated.item[0] = sel;
+	return 0;
+}
+
+static int maya_rec_src_put(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+	int sel = ucontrol->value.enumerated.item[0];
+	int changed;
+
+	mutex_lock(&chip->mutex);
+	changed = maya_set_gpio_bits(chip->ice, GPIO_MIC_RELAY,
+				     sel ? GPIO_MIC_RELAY : 0);
+	wm8776_select_input(chip, 0, sel ? MAYA_MIC_IN : MAYA_LINE_IN);
+	mutex_unlock(&chip->mutex);
+	return changed;
+}
+
+/*
+ * Maya44 routing switch settings have different meanings than the standard
+ * ice1724 switches as defined in snd_vt1724_pro_route_info (ice1724.c).
+ */
+static int maya_pb_route_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[] = {
+		"PCM Out", /* 0 */
+		"Input 1", "Input 2", "Input 3", "Input 4"
+	};
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = ARRAY_SIZE(texts);
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item =
+			uinfo->value.enumerated.items - 1;
+	strcpy(uinfo->value.enumerated.name,
+	       texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int maya_pb_route_shift(int idx)
+{
+	static const unsigned char shift[10] =
+		{ 8, 20, 0, 3, 11, 23, 14, 26, 17, 29 };
+	return shift[idx % 10];
+}
+
+static int maya_pb_route_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	ucontrol->value.enumerated.item[0] =
+		snd_ice1724_get_route_val(chip->ice, maya_pb_route_shift(idx));
+	return 0;
+}
+
+static int maya_pb_route_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	return snd_ice1724_put_route_val(chip->ice,
+					 ucontrol->value.enumerated.item[0],
+					 maya_pb_route_shift(idx));
+}
+
+
+/*
+ * controls to be added
+ */
+
+static struct snd_kcontrol_new maya_controls[] __devinitdata = {
+	{
+		.name = "Crossmix Playback Volume",
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+		.info = maya_vol_info,
+		.get = maya_vol_get,
+		.put = maya_vol_put,
+		.tlv = { .p = db_scale_hp },
+		.private_value = WM_VOL_HP,
+		.count = 2,
+	},
+	{
+		.name = "PCM Playback Volume",
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+		.info = maya_vol_info,
+		.get = maya_vol_get,
+		.put = maya_vol_put,
+		.tlv = { .p = db_scale_dac },
+		.private_value = WM_VOL_DAC,
+		.count = 2,
+	},
+	{
+		.name = "Line Capture Volume",
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+		.info = maya_vol_info,
+		.get = maya_vol_get,
+		.put = maya_vol_put,
+		.tlv = { .p = db_scale_adc },
+		.private_value = WM_VOL_ADC,
+		.count = 2,
+	},
+	{
+		.name = "PCM Playback Switch",
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.info = maya_sw_info,
+		.get = maya_sw_get,
+		.put = maya_sw_put,
+		.private_value = COMPOSE_SW_VAL(WM_SW_DAC,
+						WM8776_REG_OUTPUT_MUX, 0x01),
+		.count = 2,
+	},
+	{
+		.name = "Bypass Playback Switch",
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.info = maya_sw_info,
+		.get = maya_sw_get,
+		.put = maya_sw_put,
+		.private_value = COMPOSE_SW_VAL(WM_SW_BYPASS,
+						WM8776_REG_OUTPUT_MUX, 0x04),
+		.count = 2,
+	},
+	{
+		.name = "Capture Source",
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.info = maya_rec_src_info,
+		.get = maya_rec_src_get,
+		.put = maya_rec_src_put,
+	},
+	{
+		.name = "Mic Phantom Power Switch",
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.info = maya_gpio_sw_info,
+		.get = maya_gpio_sw_get,
+		.put = maya_gpio_sw_put,
+		.private_value = COMPOSE_GPIO_VAL(GPIO_PHANTOM_OFF, 1),
+	},
+	{
+		.name = "SPDIF Capture Switch",
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.info = maya_gpio_sw_info,
+		.get = maya_gpio_sw_get,
+		.put = maya_gpio_sw_put,
+		.private_value = COMPOSE_GPIO_VAL(GPIO_SPDIF_IN_INV, 1),
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "H/W Playback Route",
+		.info = maya_pb_route_info,
+		.get = maya_pb_route_get,
+		.put = maya_pb_route_put,
+		.count = 4,  /* FIXME: do controls 5-9 have any meaning? */
+	},
+};
+
+static int __devinit maya44_add_controls(struct snd_ice1712 *ice)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(maya_controls); i++) {
+		err = snd_ctl_add(ice->card, snd_ctl_new1(&maya_controls[i],
+							  ice->spec));
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+
+/*
+ * initialize a wm8776 chip
+ */
+static void __devinit wm8776_init(struct snd_ice1712 *ice,
+				  struct snd_wm8776 *wm, unsigned int addr)
+{
+	static const unsigned short inits_wm8776[] = {
+		0x02, 0x100, /* R2: headphone L+R muted + update */
+		0x05, 0x100, /* R5: DAC output L+R muted + update */
+		0x06, 0x000, /* R6: DAC output phase normal */
+		0x07, 0x091, /* R7: DAC enable zero cross detection,
+				normal output */
+		0x08, 0x000, /* R8: DAC soft mute off */
+		0x09, 0x000, /* R9: no deemph, DAC zero detect disabled */
+		0x0a, 0x022, /* R10: DAC I2C mode, std polarities, 24bit */
+		0x0b, 0x022, /* R11: ADC I2C mode, std polarities, 24bit,
+				highpass filter enabled */
+		0x0c, 0x042, /* R12: ADC+DAC slave, ADC+DAC 44,1kHz */
+		0x0d, 0x000, /* R13: all power up */
+		0x0e, 0x100, /* R14: ADC left muted,
+				enable zero cross detection */
+		0x0f, 0x100, /* R15: ADC right muted,
+				enable zero cross detection */
+			     /* R16: ALC...*/
+		0x11, 0x000, /* R17: disable ALC */
+			     /* R18: ALC...*/
+			     /* R19: noise gate...*/
+		0x15, 0x000, /* R21: ADC input mux init, mute all inputs */
+		0x16, 0x001, /* R22: output mux, select DAC */
+		0xff, 0xff
+	};
+
+	const unsigned short *ptr;
+	unsigned char reg;
+	unsigned short data;
+
+	wm->addr = addr;
+	/* enable DAC output; mute bypass, aux & all inputs */
+	wm->switch_bits = (1 << WM_SW_DAC);
+
+	ptr = inits_wm8776;
+	while (*ptr != 0xff) {
+		reg = *ptr++;
+		data = *ptr++;
+		wm8776_write(ice, wm, reg, data);
+	}
+}
+
+
+/*
+ * change the rate on the WM8776 codecs.
+ * this assumes that the VT17xx's rate is changed by the calling function.
+ * NOTE: even though the WM8776's are running in slave mode and rate
+ * selection is automatic, we need to call snd_wm8776_set_rate() here
+ * to make sure some flags are set correctly.
+ */
+static void set_rate(struct snd_ice1712 *ice, unsigned int rate)
+{
+	struct snd_maya44 *chip = ice->spec;
+	unsigned int ratio, adc_ratio, val;
+	int i;
+
+	switch (rate) {
+	case 192000:
+		ratio = WM8776_CLOCK_RATIO_128FS;
+		break;
+	case 176400:
+		ratio = WM8776_CLOCK_RATIO_128FS;
+		break;
+	case 96000:
+		ratio = WM8776_CLOCK_RATIO_256FS;
+		break;
+	case 88200:
+		ratio = WM8776_CLOCK_RATIO_384FS;
+		break;
+	case 48000:
+		ratio = WM8776_CLOCK_RATIO_512FS;
+		break;
+	case 44100:
+		ratio = WM8776_CLOCK_RATIO_512FS;
+		break;
+	case 32000:
+		ratio = WM8776_CLOCK_RATIO_768FS;
+		break;
+	case 0:
+		/* no hint - S/PDIF input is master, simply return */
+		return;
+	default:
+		snd_BUG();
+		return;
+	}
+
+	/*
+	 * this currently sets the same rate for ADC and DAC, but limits
+	 * ADC rate to 256X (96kHz). For 256X mode (96kHz), this sets ADC
+	 * oversampling to 64x, as recommended by WM8776 datasheet.
+	 * Setting the rate is not really necessary in slave mode.
+	 */
+	adc_ratio = ratio;
+	if (adc_ratio < WM8776_CLOCK_RATIO_256FS)
+		adc_ratio = WM8776_CLOCK_RATIO_256FS;
+
+	val = adc_ratio;
+	if (adc_ratio == WM8776_CLOCK_RATIO_256FS)
+		val |= 8;
+	val |= ratio << 4;
+
+	mutex_lock(&chip->mutex);
+	for (i = 0; i < 2; i++)
+		wm8776_write_bits(ice, &chip->wm[i],
+				  WM8776_REG_MASTER_MODE_CONTROL,
+				  0x180, val);
+	mutex_unlock(&chip->mutex);
+}
+
+/*
+ * supported sample rates (to override the default one)
+ */
+
+static unsigned int rates[] = {
+	32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000
+};
+
+/* playback rates: 32..192 kHz */
+static struct snd_pcm_hw_constraint_list dac_rates = {
+	.count = ARRAY_SIZE(rates),
+	.list = rates,
+	.mask = 0
+};
+
+
+/*
+ * chip addresses on I2C bus
+ */
+static unsigned char wm8776_addr[2] __devinitdata = {
+	0x34, 0x36, /* codec 0 & 1 */
+};
+
+/*
+ * initialize the chip
+ */
+static int __devinit maya44_init(struct snd_ice1712 *ice)
+{
+	int i;
+	struct snd_maya44 *chip;
+
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+	mutex_init(&chip->mutex);
+	chip->ice = ice;
+	ice->spec = chip;
+
+	/* initialise codecs */
+	ice->num_total_dacs = 4;
+	ice->num_total_adcs = 4;
+	ice->akm_codecs = 0;
+
+	for (i = 0; i < 2; i++) {
+		wm8776_init(ice, &chip->wm[i], wm8776_addr[i]);
+		wm8776_select_input(chip, i, MAYA_LINE_IN);
+	}
+
+	/* set card specific rates */
+	ice->hw_rates = &dac_rates;
+
+	/* register change rate notifier */
+	ice->gpio.set_pro_rate = set_rate;
+
+	/* RDMA1 (2nd input channel) is used for ADC by default */
+	ice->force_rdma1 = 1;
+
+	/* have an own routing control */
+	ice->own_routing = 1;
+
+	return 0;
+}
+
+
+/*
+ * Maya44 boards don't provide the EEPROM data except for the vendor IDs.
+ * hence the driver needs to sets up it properly.
+ */
+
+static unsigned char maya44_eeprom[] __devinitdata = {
+	[ICE_EEP2_SYSCONF]     = 0x45,
+		/* clock xin1=49.152MHz, mpu401, 2 stereo ADCs+DACs */
+	[ICE_EEP2_ACLINK]      = 0x80,
+		/* I2S */
+	[ICE_EEP2_I2S]         = 0xf8,
+		/* vol, 96k, 24bit, 192k */
+	[ICE_EEP2_SPDIF]       = 0xc3,
+		/* enable spdif out, spdif out supp, spdif-in, ext spdif out */
+	[ICE_EEP2_GPIO_DIR]    = 0xff,
+	[ICE_EEP2_GPIO_DIR1]   = 0xff,
+	[ICE_EEP2_GPIO_DIR2]   = 0xff,
+	[ICE_EEP2_GPIO_MASK]   = 0/*0x9f*/,
+	[ICE_EEP2_GPIO_MASK1]  = 0/*0xff*/,
+	[ICE_EEP2_GPIO_MASK2]  = 0/*0x7f*/,
+	[ICE_EEP2_GPIO_STATE]  = (1 << GPIO_PHANTOM_OFF) |
+			(1 << GPIO_SPDIF_IN_INV),
+	[ICE_EEP2_GPIO_STATE1] = 0x00,
+	[ICE_EEP2_GPIO_STATE2] = 0x00,
+};
+
+/* entry point */
+struct snd_ice1712_card_info snd_vt1724_maya44_cards[] __devinitdata = {
+	{
+		.subvendor = VT1724_SUBDEVICE_MAYA44,
+		.name = "ESI Maya44",
+		.model = "maya44",
+		.chip_init = maya44_init,
+		.build_controls = maya44_add_controls,
+		.eeprom_size = sizeof(maya44_eeprom),
+		.eeprom_data = maya44_eeprom,
+	},
+	{ } /* terminator */
+};
diff --git a/sound/pci/ice1712/maya44.h b/sound/pci/ice1712/maya44.h
new file mode 100644
index 0000000..eafd03a
--- /dev/null
+++ b/sound/pci/ice1712/maya44.h
@@ -0,0 +1,10 @@
+#ifndef __SOUND_MAYA44_H
+#define __SOUND_MAYA44_H
+
+#define MAYA44_DEVICE_DESC		"{ESI,Maya44},"
+
+#define VT1724_SUBDEVICE_MAYA44		0x34315441	/* Maya44 */
+
+extern struct snd_ice1712_card_info  snd_vt1724_maya44_cards[];
+
+#endif	/* __SOUND_MAYA44_H */
diff --git a/sound/pci/lx6464es/Makefile b/sound/pci/lx6464es/Makefile
new file mode 100644
index 0000000..eb04a6c
--- /dev/null
+++ b/sound/pci/lx6464es/Makefile
@@ -0,0 +1,2 @@
+snd-lx6464es-objs := lx6464es.o lx_core.o
+obj-$(CONFIG_SND_LX6464ES) += snd-lx6464es.o
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c
new file mode 100644
index 0000000..ccf1b38
--- /dev/null
+++ b/sound/pci/lx6464es/lx6464es.c
@@ -0,0 +1,1159 @@
+/* -*- linux-c -*- *
+ *
+ * ALSA driver for the digigram lx6464es interface
+ *
+ * Copyright (c) 2008, 2009 Tim Blechmann <tim@klingt.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; see the file COPYING.  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/pci.h>
+#include <linux/delay.h>
+
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/info.h>
+
+#include "lx6464es.h"
+
+MODULE_AUTHOR("Tim Blechmann");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("digigram lx6464es");
+MODULE_SUPPORTED_DEVICE("{digigram lx6464es{}}");
+
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Digigram LX6464ES interface.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for  Digigram LX6464ES interface.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable/disable specific Digigram LX6464ES soundcards.");
+
+static const char card_name[] = "LX6464ES";
+
+
+#define PCI_DEVICE_ID_PLX_LX6464ES		PCI_DEVICE_ID_PLX_9056
+
+static struct pci_device_id snd_lx6464es_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES),
+	  .subvendor = PCI_VENDOR_ID_DIGIGRAM,
+	  .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM
+	},			/* LX6464ES */
+	{ PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES),
+	  .subvendor = PCI_VENDOR_ID_DIGIGRAM,
+	  .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM
+	},			/* LX6464ES-CAE */
+	{ 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, snd_lx6464es_ids);
+
+
+
+/* PGO pour USERo dans le registre pci_0x06/loc_0xEC */
+#define CHIPSC_RESET_XILINX (1L<<16)
+
+
+/* alsa callbacks */
+static struct snd_pcm_hardware lx_caps = {
+	.info             = (SNDRV_PCM_INFO_MMAP |
+			     SNDRV_PCM_INFO_INTERLEAVED |
+			     SNDRV_PCM_INFO_MMAP_VALID |
+			     SNDRV_PCM_INFO_SYNC_START),
+	.formats	  = (SNDRV_PCM_FMTBIT_S16_LE |
+			     SNDRV_PCM_FMTBIT_S16_BE |
+			     SNDRV_PCM_FMTBIT_S24_3LE |
+			     SNDRV_PCM_FMTBIT_S24_3BE),
+	.rates            = (SNDRV_PCM_RATE_CONTINUOUS |
+			     SNDRV_PCM_RATE_8000_192000),
+	.rate_min         = 8000,
+	.rate_max         = 192000,
+	.channels_min     = 2,
+	.channels_max     = 64,
+	.buffer_bytes_max = 64*2*3*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER,
+	.period_bytes_min = (2*2*MICROBLAZE_IBL_MIN*2),
+	.period_bytes_max = (4*64*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER),
+	.periods_min      = 2,
+	.periods_max      = MAX_STREAM_BUFFER,
+};
+
+static int lx_set_granularity(struct lx6464es *chip, u32 gran);
+
+
+static int lx_hardware_open(struct lx6464es *chip,
+			    struct snd_pcm_substream *substream)
+{
+	int err = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int channels = runtime->channels;
+	int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	snd_pcm_uframes_t period_size = runtime->period_size;
+
+	snd_printd(LXP "allocating pipe for %d channels\n", channels);
+	err = lx_pipe_allocate(chip, 0, is_capture, channels);
+	if (err < 0) {
+		snd_printk(KERN_ERR LXP "allocating pipe failed\n");
+		return err;
+	}
+
+	err = lx_set_granularity(chip, period_size);
+	if (err < 0) {
+		snd_printk(KERN_ERR LXP "setting granularity to %ld failed\n",
+			   period_size);
+		return err;
+	}
+
+	return 0;
+}
+
+static int lx_hardware_start(struct lx6464es *chip,
+			     struct snd_pcm_substream *substream)
+{
+	int err = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	snd_printd(LXP "setting stream format\n");
+	err = lx_stream_set_format(chip, runtime, 0, is_capture);
+	if (err < 0) {
+		snd_printk(KERN_ERR LXP "setting stream format failed\n");
+		return err;
+	}
+
+	snd_printd(LXP "starting pipe\n");
+	err = lx_pipe_start(chip, 0, is_capture);
+	if (err < 0) {
+		snd_printk(KERN_ERR LXP "starting pipe failed\n");
+		return err;
+	}
+
+	snd_printd(LXP "waiting for pipe to start\n");
+	err = lx_pipe_wait_for_start(chip, 0, is_capture);
+	if (err < 0) {
+		snd_printk(KERN_ERR LXP "waiting for pipe failed\n");
+		return err;
+	}
+
+	return err;
+}
+
+
+static int lx_hardware_stop(struct lx6464es *chip,
+			    struct snd_pcm_substream *substream)
+{
+	int err = 0;
+	int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	snd_printd(LXP "pausing pipe\n");
+	err = lx_pipe_pause(chip, 0, is_capture);
+	if (err < 0) {
+		snd_printk(KERN_ERR LXP "pausing pipe failed\n");
+		return err;
+	}
+
+	snd_printd(LXP "waiting for pipe to become idle\n");
+	err = lx_pipe_wait_for_idle(chip, 0, is_capture);
+	if (err < 0) {
+		snd_printk(KERN_ERR LXP "waiting for pipe failed\n");
+		return err;
+	}
+
+	snd_printd(LXP "stopping pipe\n");
+	err = lx_pipe_stop(chip, 0, is_capture);
+	if (err < 0) {
+		snd_printk(LXP "stopping pipe failed\n");
+		return err;
+	}
+
+	return err;
+}
+
+
+static int lx_hardware_close(struct lx6464es *chip,
+			     struct snd_pcm_substream *substream)
+{
+	int err = 0;
+	int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	snd_printd(LXP "releasing pipe\n");
+	err = lx_pipe_release(chip, 0, is_capture);
+	if (err < 0) {
+		snd_printk(LXP "releasing pipe failed\n");
+		return err;
+	}
+
+	return err;
+}
+
+
+static int lx_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct lx6464es *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int err = 0;
+	int board_rate;
+
+	snd_printdd("->lx_pcm_open\n");
+	mutex_lock(&chip->setup_mutex);
+
+	/* copy the struct snd_pcm_hardware struct */
+	runtime->hw = lx_caps;
+
+#if 0
+	/* buffer-size should better be multiple of period-size */
+	err = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (err < 0) {
+		snd_printk(KERN_WARNING LXP "could not constrain periods\n");
+		goto exit;
+	}
+#endif
+
+	/* the clock rate cannot be changed */
+	board_rate = chip->board_sample_rate;
+	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,
+					   board_rate, board_rate);
+
+	if (err < 0) {
+		snd_printk(KERN_WARNING LXP "could not constrain periods\n");
+		goto exit;
+	}
+
+	/* constrain period size */
+	err = snd_pcm_hw_constraint_minmax(runtime,
+					   SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+					   MICROBLAZE_IBL_MIN,
+					   MICROBLAZE_IBL_MAX);
+	if (err < 0) {
+		snd_printk(KERN_WARNING LXP
+			   "could not constrain period size\n");
+		goto exit;
+	}
+
+	snd_pcm_hw_constraint_step(runtime, 0,
+				   SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32);
+
+	snd_pcm_set_sync(substream);
+	err = 0;
+
+exit:
+	runtime->private_data = chip;
+
+	mutex_unlock(&chip->setup_mutex);
+	snd_printdd("<-lx_pcm_open, %d\n", err);
+	return err;
+}
+
+static int lx_pcm_close(struct snd_pcm_substream *substream)
+{
+	int err = 0;
+	snd_printdd("->lx_pcm_close\n");
+	return err;
+}
+
+static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream
+					       *substream)
+{
+	struct lx6464es *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_uframes_t pos;
+	unsigned long flags;
+	int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	struct lx_stream *lx_stream = is_capture ? &chip->capture_stream :
+		&chip->playback_stream;
+
+	snd_printdd("->lx_pcm_stream_pointer\n");
+
+	spin_lock_irqsave(&chip->lock, flags);
+	pos = lx_stream->frame_pos * substream->runtime->period_size;
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	snd_printdd(LXP "stream_pointer at %ld\n", pos);
+	return pos;
+}
+
+static int lx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct lx6464es *chip = snd_pcm_substream_chip(substream);
+	int err = 0;
+	const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	snd_printdd("->lx_pcm_prepare\n");
+
+	mutex_lock(&chip->setup_mutex);
+
+	if (chip->hardware_running[is_capture]) {
+		err = lx_hardware_stop(chip, substream);
+		if (err < 0) {
+			snd_printk(KERN_ERR LXP "failed to stop hardware. "
+				   "Error code %d\n", err);
+			goto exit;
+		}
+
+		err = lx_hardware_close(chip, substream);
+		if (err < 0) {
+			snd_printk(KERN_ERR LXP "failed to close hardware. "
+				   "Error code %d\n", err);
+			goto exit;
+		}
+	}
+
+	snd_printd(LXP "opening hardware\n");
+	err = lx_hardware_open(chip, substream);
+	if (err < 0) {
+		snd_printk(KERN_ERR LXP "failed to open hardware. "
+			   "Error code %d\n", err);
+		goto exit;
+	}
+
+	err = lx_hardware_start(chip, substream);
+	if (err < 0) {
+		snd_printk(KERN_ERR LXP "failed to start hardware. "
+			   "Error code %d\n", err);
+		goto exit;
+	}
+
+	chip->hardware_running[is_capture] = 1;
+
+	if (chip->board_sample_rate != substream->runtime->rate) {
+		if (!err)
+			chip->board_sample_rate = substream->runtime->rate;
+	}
+
+exit:
+	mutex_unlock(&chip->setup_mutex);
+	return err;
+}
+
+static int lx_pcm_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *hw_params, int is_capture)
+{
+	struct lx6464es *chip = snd_pcm_substream_chip(substream);
+	int err = 0;
+
+	snd_printdd("->lx_pcm_hw_params\n");
+
+	mutex_lock(&chip->setup_mutex);
+
+	/* set dma buffer */
+	err = snd_pcm_lib_malloc_pages(substream,
+				       params_buffer_bytes(hw_params));
+
+	if (is_capture)
+		chip->capture_stream.stream = substream;
+	else
+		chip->playback_stream.stream = substream;
+
+	mutex_unlock(&chip->setup_mutex);
+	return err;
+}
+
+static int lx_pcm_hw_params_playback(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *hw_params)
+{
+	return lx_pcm_hw_params(substream, hw_params, 0);
+}
+
+static int lx_pcm_hw_params_capture(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *hw_params)
+{
+	return lx_pcm_hw_params(substream, hw_params, 1);
+}
+
+static int lx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct lx6464es *chip = snd_pcm_substream_chip(substream);
+	int err = 0;
+	int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	snd_printdd("->lx_pcm_hw_free\n");
+	mutex_lock(&chip->setup_mutex);
+
+	if (chip->hardware_running[is_capture]) {
+		err = lx_hardware_stop(chip, substream);
+		if (err < 0) {
+			snd_printk(KERN_ERR LXP "failed to stop hardware. "
+				   "Error code %d\n", err);
+			goto exit;
+		}
+
+		err = lx_hardware_close(chip, substream);
+		if (err < 0) {
+			snd_printk(KERN_ERR LXP "failed to close hardware. "
+				   "Error code %d\n", err);
+			goto exit;
+		}
+
+		chip->hardware_running[is_capture] = 0;
+	}
+
+	err = snd_pcm_lib_free_pages(substream);
+
+	if (is_capture)
+		chip->capture_stream.stream = 0;
+	else
+		chip->playback_stream.stream = 0;
+
+exit:
+	mutex_unlock(&chip->setup_mutex);
+	return err;
+}
+
+static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream)
+{
+	struct snd_pcm_substream *substream = lx_stream->stream;
+	const int is_capture = lx_stream->is_capture;
+
+	int err;
+
+	const u32 channels = substream->runtime->channels;
+	const u32 bytes_per_frame = channels * 3;
+	const u32 period_size = substream->runtime->period_size;
+	const u32 periods = substream->runtime->periods;
+	const u32 period_bytes = period_size * bytes_per_frame;
+
+	dma_addr_t buf = substream->dma_buffer.addr;
+	int i;
+
+	u32 needed, freed;
+	u32 size_array[5];
+
+	for (i = 0; i != periods; ++i) {
+		u32 buffer_index = 0;
+
+		err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed,
+				    size_array);
+		snd_printdd(LXP "starting: needed %d, freed %d\n",
+			    needed, freed);
+
+		err = lx_buffer_give(chip, 0, is_capture, period_bytes,
+				     lower_32_bits(buf), upper_32_bits(buf),
+				     &buffer_index);
+
+		snd_printdd(LXP "starting: buffer index %x on %p (%d bytes)\n",
+			    buffer_index, (void *)buf, period_bytes);
+		buf += period_bytes;
+	}
+
+	err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array);
+	snd_printdd(LXP "starting: needed %d, freed %d\n", needed, freed);
+
+	snd_printd(LXP "starting: starting stream\n");
+	err = lx_stream_start(chip, 0, is_capture);
+	if (err < 0)
+		snd_printk(KERN_ERR LXP "couldn't start stream\n");
+	else
+		lx_stream->status = LX_STREAM_STATUS_RUNNING;
+
+	lx_stream->frame_pos = 0;
+}
+
+static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream)
+{
+	const int is_capture = lx_stream->is_capture;
+	int err;
+
+	snd_printd(LXP "stopping: stopping stream\n");
+	err = lx_stream_stop(chip, 0, is_capture);
+	if (err < 0)
+		snd_printk(KERN_ERR LXP "couldn't stop stream\n");
+	else
+		lx_stream->status = LX_STREAM_STATUS_FREE;
+
+}
+
+static void lx_trigger_tasklet_dispatch_stream(struct lx6464es *chip,
+					       struct lx_stream *lx_stream)
+{
+	switch (lx_stream->status) {
+	case LX_STREAM_STATUS_SCHEDULE_RUN:
+		lx_trigger_start(chip, lx_stream);
+		break;
+
+	case LX_STREAM_STATUS_SCHEDULE_STOP:
+		lx_trigger_stop(chip, lx_stream);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void lx_trigger_tasklet(unsigned long data)
+{
+	struct lx6464es *chip = (struct lx6464es *)data;
+	unsigned long flags;
+
+	snd_printdd("->lx_trigger_tasklet\n");
+
+	spin_lock_irqsave(&chip->lock, flags);
+	lx_trigger_tasklet_dispatch_stream(chip, &chip->capture_stream);
+	lx_trigger_tasklet_dispatch_stream(chip, &chip->playback_stream);
+	spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static int lx_pcm_trigger_dispatch(struct lx6464es *chip,
+				   struct lx_stream *lx_stream, int cmd)
+{
+	int err = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		lx_stream->status = LX_STREAM_STATUS_SCHEDULE_RUN;
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		lx_stream->status = LX_STREAM_STATUS_SCHEDULE_STOP;
+		break;
+
+	default:
+		err = -EINVAL;
+		goto exit;
+	}
+	tasklet_schedule(&chip->trigger_tasklet);
+
+exit:
+	return err;
+}
+
+
+static int lx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct lx6464es *chip = snd_pcm_substream_chip(substream);
+	const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+	struct lx_stream *stream = is_capture ? &chip->capture_stream :
+		&chip->playback_stream;
+
+	snd_printdd("->lx_pcm_trigger\n");
+
+	return lx_pcm_trigger_dispatch(chip, stream, cmd);
+}
+
+static int snd_lx6464es_free(struct lx6464es *chip)
+{
+	snd_printdd("->snd_lx6464es_free\n");
+
+	lx_irq_disable(chip);
+
+	if (chip->irq >= 0)
+		free_irq(chip->irq, chip);
+
+	iounmap(chip->port_dsp_bar);
+	ioport_unmap(chip->port_plx_remapped);
+
+	pci_release_regions(chip->pci);
+	pci_disable_device(chip->pci);
+
+	kfree(chip);
+
+	return 0;
+}
+
+static int snd_lx6464es_dev_free(struct snd_device *device)
+{
+	return snd_lx6464es_free(device->device_data);
+}
+
+/* reset the dsp during initialization */
+static int __devinit lx_init_xilinx_reset(struct lx6464es *chip)
+{
+	int i;
+	u32 plx_reg = lx_plx_reg_read(chip, ePLX_CHIPSC);
+
+	snd_printdd("->lx_init_xilinx_reset\n");
+
+	/* activate reset of xilinx */
+	plx_reg &= ~CHIPSC_RESET_XILINX;
+
+	lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg);
+	msleep(1);
+
+	lx_plx_reg_write(chip, ePLX_MBOX3, 0);
+	msleep(1);
+
+	plx_reg |= CHIPSC_RESET_XILINX;
+	lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg);
+
+	/* deactivate reset of xilinx */
+	for (i = 0; i != 100; ++i) {
+		u32 reg_mbox3;
+		msleep(10);
+		reg_mbox3 = lx_plx_reg_read(chip, ePLX_MBOX3);
+		if (reg_mbox3) {
+			snd_printd(LXP "xilinx reset done\n");
+			snd_printdd(LXP "xilinx took %d loops\n", i);
+			break;
+		}
+	}
+
+	/* todo: add some error handling? */
+
+	/* clear mr */
+	lx_dsp_reg_write(chip, eReg_CSM, 0);
+
+	/* le xilinx ES peut ne pas etre encore pret, on attend. */
+	msleep(600);
+
+	return 0;
+}
+
+static int __devinit lx_init_xilinx_test(struct lx6464es *chip)
+{
+	u32 reg;
+
+	snd_printdd("->lx_init_xilinx_test\n");
+
+	/* TEST if we have access to Xilinx/MicroBlaze */
+	lx_dsp_reg_write(chip, eReg_CSM, 0);
+
+	reg = lx_dsp_reg_read(chip, eReg_CSM);
+
+	if (reg) {
+		snd_printk(KERN_ERR LXP "Problem: Reg_CSM %x.\n", reg);
+
+		/* PCI9056_SPACE0_REMAP */
+		lx_plx_reg_write(chip, ePLX_PCICR, 1);
+
+		reg = lx_dsp_reg_read(chip, eReg_CSM);
+		if (reg) {
+			snd_printk(KERN_ERR LXP "Error: Reg_CSM %x.\n", reg);
+			return -EAGAIN; /* seems to be appropriate */
+		}
+	}
+
+	snd_printd(LXP "Xilinx/MicroBlaze access test successful\n");
+
+	return 0;
+}
+
+/* initialize ethersound */
+static int __devinit lx_init_ethersound_config(struct lx6464es *chip)
+{
+	int i;
+	u32 orig_conf_es = lx_dsp_reg_read(chip, eReg_CONFES);
+
+	u32 default_conf_es = (64 << IOCR_OUTPUTS_OFFSET) |
+		(64 << IOCR_INPUTS_OFFSET) |
+		(FREQ_RATIO_SINGLE_MODE << FREQ_RATIO_OFFSET);
+
+	u32 conf_es = (orig_conf_es & CONFES_READ_PART_MASK)
+		| (default_conf_es & CONFES_WRITE_PART_MASK);
+
+	snd_printdd("->lx_init_ethersound\n");
+
+	chip->freq_ratio = FREQ_RATIO_SINGLE_MODE;
+
+	/*
+	 * write it to the card !
+	 * this actually kicks the ES xilinx, the first time since poweron.
+	 * the MAC address in the Reg_ADMACESMSB Reg_ADMACESLSB registers
+	 * is not ready before this is done, and the bit 2 in Reg_CSES is set.
+	 * */
+	lx_dsp_reg_write(chip, eReg_CONFES, conf_es);
+
+	for (i = 0; i != 1000; ++i) {
+		if (lx_dsp_reg_read(chip, eReg_CSES) & 4) {
+			snd_printd(LXP "ethersound initialized after %dms\n",
+				   i);
+			goto ethersound_initialized;
+		}
+		msleep(1);
+	}
+	snd_printk(KERN_WARNING LXP
+		   "ethersound could not be initialized after %dms\n", i);
+	return -ETIMEDOUT;
+
+ ethersound_initialized:
+	snd_printd(LXP "ethersound initialized\n");
+	return 0;
+}
+
+static int __devinit lx_init_get_version_features(struct lx6464es *chip)
+{
+	u32 dsp_version;
+
+	int err;
+
+	snd_printdd("->lx_init_get_version_features\n");
+
+	err = lx_dsp_get_version(chip, &dsp_version);
+
+	if (err == 0) {
+		u32 freq;
+
+		snd_printk(LXP "DSP version: V%02d.%02d #%d\n",
+			   (dsp_version>>16) & 0xff, (dsp_version>>8) & 0xff,
+			   dsp_version & 0xff);
+
+		/* later: what firmware version do we expect? */
+
+		/* retrieve Play/Rec features */
+		/* done here because we may have to handle alternate
+		 * DSP files. */
+		/* later */
+
+		/* init the EtherSound sample rate */
+		err = lx_dsp_get_clock_frequency(chip, &freq);
+		if (err == 0)
+			chip->board_sample_rate = freq;
+		snd_printd(LXP "actual clock frequency %d\n", freq);
+	} else {
+		snd_printk(KERN_ERR LXP "DSP corrupted \n");
+		err = -EAGAIN;
+	}
+
+	return err;
+}
+
+static int lx_set_granularity(struct lx6464es *chip, u32 gran)
+{
+	int err = 0;
+	u32 snapped_gran = MICROBLAZE_IBL_MIN;
+
+	snd_printdd("->lx_set_granularity\n");
+
+	/* blocksize is a power of 2 */
+	while ((snapped_gran < gran) &&
+	       (snapped_gran < MICROBLAZE_IBL_MAX)) {
+		snapped_gran *= 2;
+	}
+
+	if (snapped_gran == chip->pcm_granularity)
+		return 0;
+
+	err = lx_dsp_set_granularity(chip, snapped_gran);
+	if (err < 0) {
+		snd_printk(KERN_WARNING LXP "could not set granularity\n");
+		err = -EAGAIN;
+	}
+
+	if (snapped_gran != gran)
+		snd_printk(LXP "snapped blocksize to %d\n", snapped_gran);
+
+	snd_printd(LXP "set blocksize on board %d\n", snapped_gran);
+	chip->pcm_granularity = snapped_gran;
+
+	return err;
+}
+
+/* initialize and test the xilinx dsp chip */
+static int __devinit lx_init_dsp(struct lx6464es *chip)
+{
+	int err;
+	u8 mac_address[6];
+	int i;
+
+	snd_printdd("->lx_init_dsp\n");
+
+	snd_printd(LXP "initialize board\n");
+	err = lx_init_xilinx_reset(chip);
+	if (err)
+		return err;
+
+	snd_printd(LXP "testing board\n");
+	err = lx_init_xilinx_test(chip);
+	if (err)
+		return err;
+
+	snd_printd(LXP "initialize ethersound configuration\n");
+	err = lx_init_ethersound_config(chip);
+	if (err)
+		return err;
+
+	lx_irq_enable(chip);
+
+	/** \todo the mac address should be ready by not, but it isn't,
+	 *  so we wait for it */
+	for (i = 0; i != 1000; ++i) {
+		err = lx_dsp_get_mac(chip, mac_address);
+		if (err)
+			return err;
+		if (mac_address[0] || mac_address[1] || mac_address[2] ||
+		    mac_address[3] || mac_address[4] || mac_address[5])
+			goto mac_ready;
+		msleep(1);
+	}
+	return -ETIMEDOUT;
+
+mac_ready:
+	snd_printd(LXP "mac address ready read after: %dms\n", i);
+	snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n",
+		   mac_address[0], mac_address[1], mac_address[2],
+		   mac_address[3], mac_address[4], mac_address[5]);
+
+	err = lx_init_get_version_features(chip);
+	if (err)
+		return err;
+
+	lx_set_granularity(chip, MICROBLAZE_IBL_DEFAULT);
+
+	chip->playback_mute = 0;
+
+	return err;
+}
+
+static struct snd_pcm_ops lx_ops_playback = {
+	.open      = lx_pcm_open,
+	.close     = lx_pcm_close,
+	.ioctl     = snd_pcm_lib_ioctl,
+	.prepare   = lx_pcm_prepare,
+	.hw_params = lx_pcm_hw_params_playback,
+	.hw_free   = lx_pcm_hw_free,
+	.trigger   = lx_pcm_trigger,
+	.pointer   = lx_pcm_stream_pointer,
+};
+
+static struct snd_pcm_ops lx_ops_capture = {
+	.open      = lx_pcm_open,
+	.close     = lx_pcm_close,
+	.ioctl     = snd_pcm_lib_ioctl,
+	.prepare   = lx_pcm_prepare,
+	.hw_params = lx_pcm_hw_params_capture,
+	.hw_free   = lx_pcm_hw_free,
+	.trigger   = lx_pcm_trigger,
+	.pointer   = lx_pcm_stream_pointer,
+};
+
+static int __devinit lx_pcm_create(struct lx6464es *chip)
+{
+	int err;
+	struct snd_pcm *pcm;
+
+	u32 size = 64 *		     /* channels */
+		3 *		     /* 24 bit samples */
+		MAX_STREAM_BUFFER *  /* periods */
+		MICROBLAZE_IBL_MAX * /* frames per period */
+		2;		     /* duplex */
+
+	size = PAGE_ALIGN(size);
+
+	/* hardcoded device name & channel count */
+	err = snd_pcm_new(chip->card, (char *)card_name, 0,
+			  1, 1, &pcm);
+
+	pcm->private_data = chip;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &lx_ops_playback);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &lx_ops_capture);
+
+	pcm->info_flags = 0;
+	strcpy(pcm->name, card_name);
+
+	err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+						    snd_dma_pci_data(chip->pci),
+						    size, size);
+	if (err < 0)
+		return err;
+
+	chip->pcm = pcm;
+	chip->capture_stream.is_capture = 1;
+
+	return 0;
+}
+
+static int lx_control_playback_info(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int lx_control_playback_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct lx6464es *chip = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.integer.value[0] = chip->playback_mute;
+	return 0;
+}
+
+static int lx_control_playback_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct lx6464es *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	int current_value = chip->playback_mute;
+
+	if (current_value != ucontrol->value.integer.value[0]) {
+		lx_level_unmute(chip, 0, !current_value);
+		chip->playback_mute = !current_value;
+		changed = 1;
+	}
+	return changed;
+}
+
+static struct snd_kcontrol_new lx_control_playback_switch __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "PCM Playback Switch",
+	.index = 0,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.private_value = 0,
+	.info = lx_control_playback_info,
+	.get = lx_control_playback_get,
+	.put = lx_control_playback_put
+};
+
+
+
+static void lx_proc_levels_read(struct snd_info_entry *entry,
+				struct snd_info_buffer *buffer)
+{
+	u32 levels[64];
+	int err;
+	int i, j;
+	struct lx6464es *chip = entry->private_data;
+
+	snd_iprintf(buffer, "capture levels:\n");
+	err = lx_level_peaks(chip, 1, 64, levels);
+	if (err < 0)
+		return;
+
+	for (i = 0; i != 8; ++i) {
+		for (j = 0; j != 8; ++j)
+			snd_iprintf(buffer, "%08x ", levels[i*8+j]);
+		snd_iprintf(buffer, "\n");
+	}
+
+	snd_iprintf(buffer, "\nplayback levels:\n");
+
+	err = lx_level_peaks(chip, 0, 64, levels);
+	if (err < 0)
+		return;
+
+	for (i = 0; i != 8; ++i) {
+		for (j = 0; j != 8; ++j)
+			snd_iprintf(buffer, "%08x ", levels[i*8+j]);
+		snd_iprintf(buffer, "\n");
+	}
+
+	snd_iprintf(buffer, "\n");
+}
+
+static int __devinit lx_proc_create(struct snd_card *card, struct lx6464es *chip)
+{
+	struct snd_info_entry *entry;
+	int err = snd_card_proc_new(card, "levels", &entry);
+	if (err < 0)
+		return err;
+
+	snd_info_set_text_ops(entry, chip, lx_proc_levels_read);
+	return 0;
+}
+
+
+static int __devinit snd_lx6464es_create(struct snd_card *card,
+					 struct pci_dev *pci,
+					 struct lx6464es **rchip)
+{
+	struct lx6464es *chip;
+	int err;
+
+	static struct snd_device_ops ops = {
+		.dev_free = snd_lx6464es_dev_free,
+	};
+
+	snd_printdd("->snd_lx6464es_create\n");
+
+	*rchip = NULL;
+
+	/* enable PCI device */
+	err = pci_enable_device(pci);
+	if (err < 0)
+		return err;
+
+	pci_set_master(pci);
+
+	/* check if we can restrict PCI DMA transfers to 32 bits */
+	err = pci_set_dma_mask(pci, DMA_32BIT_MASK);
+	if (err < 0) {
+		snd_printk(KERN_ERR "architecture does not support "
+			   "32bit PCI busmaster DMA\n");
+		pci_disable_device(pci);
+		return -ENXIO;
+	}
+
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL) {
+		err = -ENOMEM;
+		goto alloc_failed;
+	}
+
+	chip->card = card;
+	chip->pci = pci;
+	chip->irq = -1;
+
+	/* initialize synchronization structs */
+	spin_lock_init(&chip->lock);
+	spin_lock_init(&chip->msg_lock);
+	mutex_init(&chip->setup_mutex);
+	tasklet_init(&chip->trigger_tasklet, lx_trigger_tasklet,
+		     (unsigned long)chip);
+	tasklet_init(&chip->tasklet_capture, lx_tasklet_capture,
+		     (unsigned long)chip);
+	tasklet_init(&chip->tasklet_playback, lx_tasklet_playback,
+		     (unsigned long)chip);
+
+	/* request resources */
+	err = pci_request_regions(pci, card_name);
+	if (err < 0)
+		goto request_regions_failed;
+
+	/* plx port */
+	chip->port_plx = pci_resource_start(pci, 1);
+	chip->port_plx_remapped = ioport_map(chip->port_plx,
+					     pci_resource_len(pci, 1));
+
+	/* dsp port */
+	chip->port_dsp_bar = pci_ioremap_bar(pci, 2);
+
+	err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED,
+			  card_name, chip);
+	if (err) {
+		snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq);
+		goto request_irq_failed;
+	}
+	chip->irq = pci->irq;
+
+	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+	if (err < 0)
+		goto device_new_failed;
+
+	err = lx_init_dsp(chip);
+	if (err < 0) {
+		snd_printk(KERN_ERR LXP "error during DSP initialization\n");
+		return err;
+	}
+
+	err = lx_pcm_create(chip);
+	if (err < 0)
+		return err;
+
+	err = lx_proc_create(card, chip);
+	if (err < 0)
+		return err;
+
+	err = snd_ctl_add(card, snd_ctl_new1(&lx_control_playback_switch,
+					     chip));
+	if (err < 0)
+		return err;
+
+	snd_card_set_dev(card, &pci->dev);
+
+	*rchip = chip;
+	return 0;
+
+device_new_failed:
+	free_irq(pci->irq, chip);
+
+request_irq_failed:
+	pci_release_regions(pci);
+
+request_regions_failed:
+	kfree(chip);
+
+alloc_failed:
+	pci_disable_device(pci);
+
+	return err;
+}
+
+static int __devinit snd_lx6464es_probe(struct pci_dev *pci,
+					const struct pci_device_id *pci_id)
+{
+	static int dev;
+	struct snd_card *card;
+	struct lx6464es *chip;
+	int err;
+
+	snd_printdd("->snd_lx6464es_probe\n");
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+	if (err < 0)
+		return err;
+
+	err = snd_lx6464es_create(card, pci, &chip);
+	if (err < 0) {
+		snd_printk(KERN_ERR LXP "error during snd_lx6464es_create\n");
+		goto out_free;
+	}
+
+	strcpy(card->driver, "lx6464es");
+	strcpy(card->shortname, "Digigram LX6464ES");
+	sprintf(card->longname, "%s at 0x%lx, 0x%p, irq %i",
+		card->shortname, chip->port_plx,
+		chip->port_dsp_bar, chip->irq);
+
+	err = snd_card_register(card);
+	if (err < 0)
+		goto out_free;
+
+	snd_printdd(LXP "initialization successful\n");
+	pci_set_drvdata(pci, card);
+	dev++;
+	return 0;
+
+out_free:
+	snd_card_free(card);
+	return err;
+
+}
+
+static void __devexit snd_lx6464es_remove(struct pci_dev *pci)
+{
+	snd_card_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+
+static struct pci_driver driver = {
+	.name =     "Digigram LX6464ES",
+	.id_table = snd_lx6464es_ids,
+	.probe =    snd_lx6464es_probe,
+	.remove = __devexit_p(snd_lx6464es_remove),
+};
+
+
+/* module initialization */
+static int __init mod_init(void)
+{
+	return pci_register_driver(&driver);
+}
+
+static void __exit mod_exit(void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(mod_init);
+module_exit(mod_exit);
diff --git a/sound/pci/lx6464es/lx6464es.h b/sound/pci/lx6464es/lx6464es.h
new file mode 100644
index 0000000..012c010
--- /dev/null
+++ b/sound/pci/lx6464es/lx6464es.h
@@ -0,0 +1,114 @@
+/* -*- linux-c -*- *
+ *
+ * ALSA driver for the digigram lx6464es interface
+ *
+ * Copyright (c) 2009 Tim Blechmann <tim@klingt.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; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef LX6464ES_H
+#define LX6464ES_H
+
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#include "lx_core.h"
+
+#define LXP "LX6464ES: "
+
+enum {
+    ES_cmd_free         = 0,    /* no command executing */
+    ES_cmd_processing   = 1,	/* execution of a read/write command */
+    ES_read_pending     = 2,    /* a asynchron read command is pending */
+    ES_read_finishing   = 3,    /* a read command has finished waiting (set by
+				 * Interrupt or CancelIrp) */
+};
+
+enum lx_stream_status {
+	LX_STREAM_STATUS_FREE,
+/* 	LX_STREAM_STATUS_OPEN, */
+	LX_STREAM_STATUS_SCHEDULE_RUN,
+/* 	LX_STREAM_STATUS_STARTED, */
+	LX_STREAM_STATUS_RUNNING,
+	LX_STREAM_STATUS_SCHEDULE_STOP,
+/* 	LX_STREAM_STATUS_STOPPED, */
+/* 	LX_STREAM_STATUS_PAUSED */
+};
+
+
+struct lx_stream {
+	struct snd_pcm_substream  *stream;
+	snd_pcm_uframes_t          frame_pos;
+	enum lx_stream_status      status; /* free, open, running, draining
+					    * pause */
+	int                        is_capture:1;
+};
+
+
+struct lx6464es {
+	struct snd_card        *card;
+	struct pci_dev         *pci;
+	int			irq;
+
+	spinlock_t		lock;        /* interrupt spinlock */
+	struct mutex            setup_mutex; /* mutex used in hw_params, open
+					      * and close */
+
+	struct tasklet_struct   trigger_tasklet; /* trigger tasklet */
+	struct tasklet_struct   tasklet_capture;
+	struct tasklet_struct   tasklet_playback;
+
+	/* ports */
+	unsigned long		port_plx;	   /* io port (size=256) */
+	void __iomem           *port_plx_remapped; /* remapped plx port */
+	void __iomem           *port_dsp_bar;      /* memory port (32-bit,
+						    * non-prefetchable,
+						    * size=8K) */
+
+	/* messaging */
+	spinlock_t		msg_lock;          /* message spinlock */
+	atomic_t	        send_message_locked;
+	struct lx_rmh           rmh;
+
+	/* configuration */
+	uint			freq_ratio : 2;
+	uint                    playback_mute : 1;
+	uint                    hardware_running[2];
+	u32                     board_sample_rate; /* sample rate read from
+						    * board */
+	u32                     sample_rate;	   /* our sample rate */
+	u16                     pcm_granularity;   /* board blocksize */
+
+	/* dma */
+	struct snd_dma_buffer   capture_dma_buf;
+	struct snd_dma_buffer   playback_dma_buf;
+
+	/* pcm */
+	struct snd_pcm         *pcm;
+
+	/* streams */
+	struct lx_stream        capture_stream;
+	struct lx_stream        playback_stream;
+};
+
+
+#endif /* LX6464ES_H */
diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c
new file mode 100644
index 0000000..5812780
--- /dev/null
+++ b/sound/pci/lx6464es/lx_core.c
@@ -0,0 +1,1444 @@
+/* -*- linux-c -*- *
+ *
+ * ALSA driver for the digigram lx6464es interface
+ * low-level interface
+ *
+ * Copyright (c) 2009 Tim Blechmann <tim@klingt.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; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+/* #define RMH_DEBUG 1 */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "lx6464es.h"
+#include "lx_core.h"
+
+/* low-level register access */
+
+static const unsigned long dsp_port_offsets[] = {
+	0,
+	0x400,
+	0x401,
+	0x402,
+	0x403,
+	0x404,
+	0x405,
+	0x406,
+	0x407,
+	0x408,
+	0x409,
+	0x40a,
+	0x40b,
+	0x40c,
+
+	0x410,
+	0x411,
+	0x412,
+	0x413,
+	0x414,
+	0x415,
+	0x416,
+
+	0x420,
+	0x430,
+	0x431,
+	0x432,
+	0x433,
+	0x434,
+	0x440
+};
+
+static void __iomem *lx_dsp_register(struct lx6464es *chip, int port)
+{
+	void __iomem *base_address = chip->port_dsp_bar;
+	return base_address + dsp_port_offsets[port]*4;
+}
+
+unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port)
+{
+	void __iomem *address = lx_dsp_register(chip, port);
+	return ioread32(address);
+}
+
+void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len)
+{
+	void __iomem *address = lx_dsp_register(chip, port);
+	memcpy_fromio(data, address, len*sizeof(u32));
+}
+
+
+void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data)
+{
+	void __iomem *address = lx_dsp_register(chip, port);
+	iowrite32(data, address);
+}
+
+void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data,
+			 u32 len)
+{
+	void __iomem *address = lx_dsp_register(chip, port);
+	memcpy_toio(address, data, len*sizeof(u32));
+}
+
+
+static const unsigned long plx_port_offsets[] = {
+	0x04,
+	0x40,
+	0x44,
+	0x48,
+	0x4c,
+	0x50,
+	0x54,
+	0x58,
+	0x5c,
+	0x64,
+	0x68,
+	0x6C
+};
+
+static void __iomem *lx_plx_register(struct lx6464es *chip, int port)
+{
+	void __iomem *base_address = chip->port_plx_remapped;
+	return base_address + plx_port_offsets[port];
+}
+
+unsigned long lx_plx_reg_read(struct lx6464es *chip, int port)
+{
+	void __iomem *address = lx_plx_register(chip, port);
+	return ioread32(address);
+}
+
+void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data)
+{
+	void __iomem *address = lx_plx_register(chip, port);
+	iowrite32(data, address);
+}
+
+u32 lx_plx_mbox_read(struct lx6464es *chip, int mbox_nr)
+{
+	int index;
+
+	switch (mbox_nr) {
+	case 1:
+		index = ePLX_MBOX1;    break;
+	case 2:
+		index = ePLX_MBOX2;    break;
+	case 3:
+		index = ePLX_MBOX3;    break;
+	case 4:
+		index = ePLX_MBOX4;    break;
+	case 5:
+		index = ePLX_MBOX5;    break;
+	case 6:
+		index = ePLX_MBOX6;    break;
+	case 7:
+		index = ePLX_MBOX7;    break;
+	case 0:			/* reserved for HF flags */
+		snd_BUG();
+	default:
+		return 0xdeadbeef;
+	}
+
+	return lx_plx_reg_read(chip, index);
+}
+
+int lx_plx_mbox_write(struct lx6464es *chip, int mbox_nr, u32 value)
+{
+	int index = -1;
+
+	switch (mbox_nr) {
+	case 1:
+		index = ePLX_MBOX1;    break;
+	case 3:
+		index = ePLX_MBOX3;    break;
+	case 4:
+		index = ePLX_MBOX4;    break;
+	case 5:
+		index = ePLX_MBOX5;    break;
+	case 6:
+		index = ePLX_MBOX6;    break;
+	case 7:
+		index = ePLX_MBOX7;    break;
+	case 0:			/* reserved for HF flags */
+	case 2:			/* reserved for Pipe States
+				 * the DSP keeps an image of it */
+		snd_BUG();
+		return -EBADRQC;
+	}
+
+	lx_plx_reg_write(chip, index, value);
+	return 0;
+}
+
+
+/* rmh */
+
+#ifdef CONFIG_SND_DEBUG
+#define CMD_NAME(a) a
+#else
+#define CMD_NAME(a) NULL
+#endif
+
+#define Reg_CSM_MR			0x00000002
+#define Reg_CSM_MC			0x00000001
+
+struct dsp_cmd_info {
+	u32    dcCodeOp;	/* Op Code of the command (usually 1st 24-bits
+				 * word).*/
+	u16    dcCmdLength;	/* Command length in words of 24 bits.*/
+	u16    dcStatusType;	/* Status type: 0 for fixed length, 1 for
+				 * random. */
+	u16    dcStatusLength;	/* Status length (if fixed).*/
+	char  *dcOpName;
+};
+
+/*
+  Initialization and control data for the Microblaze interface
+  - OpCode:
+    the opcode field of the command set at the proper offset
+  - CmdLength
+    the number of command words
+  - StatusType
+    offset in the status registers: 0 means that the return value may be
+    different from 0, and must be read
+  - StatusLength
+    the number of status words (in addition to the return value)
+*/
+
+static struct dsp_cmd_info dsp_commands[] =
+{
+	{ (CMD_00_INFO_DEBUG << OPCODE_OFFSET)			, 1 /*custom*/
+	  , 1	, 0 /**/		    , CMD_NAME("INFO_DEBUG") },
+	{ (CMD_01_GET_SYS_CFG << OPCODE_OFFSET) 		, 1 /**/
+	  , 1      , 2 /**/		    , CMD_NAME("GET_SYS_CFG") },
+	{ (CMD_02_SET_GRANULARITY << OPCODE_OFFSET)	        , 1 /**/
+	  , 1      , 0 /**/		    , CMD_NAME("SET_GRANULARITY") },
+	{ (CMD_03_SET_TIMER_IRQ << OPCODE_OFFSET)		, 1 /**/
+	  , 1      , 0 /**/		    , CMD_NAME("SET_TIMER_IRQ") },
+	{ (CMD_04_GET_EVENT << OPCODE_OFFSET)			, 1 /**/
+	  , 1      , 0 /*up to 10*/     , CMD_NAME("GET_EVENT") },
+	{ (CMD_05_GET_PIPES << OPCODE_OFFSET)			, 1 /**/
+	  , 1      , 2 /*up to 4*/      , CMD_NAME("GET_PIPES") },
+	{ (CMD_06_ALLOCATE_PIPE << OPCODE_OFFSET)		, 1 /**/
+	  , 0      , 0 /**/		    , CMD_NAME("ALLOCATE_PIPE") },
+	{ (CMD_07_RELEASE_PIPE << OPCODE_OFFSET)		, 1 /**/
+	  , 0      , 0 /**/		    , CMD_NAME("RELEASE_PIPE") },
+	{ (CMD_08_ASK_BUFFERS << OPCODE_OFFSET) 		, 1 /**/
+	  , 1      , MAX_STREAM_BUFFER  , CMD_NAME("ASK_BUFFERS") },
+	{ (CMD_09_STOP_PIPE << OPCODE_OFFSET)			, 1 /**/
+	  , 0      , 0 /*up to 2*/      , CMD_NAME("STOP_PIPE") },
+	{ (CMD_0A_GET_PIPE_SPL_COUNT << OPCODE_OFFSET)	        , 1 /**/
+	  , 1      , 1 /*up to 2*/      , CMD_NAME("GET_PIPE_SPL_COUNT") },
+	{ (CMD_0B_TOGGLE_PIPE_STATE << OPCODE_OFFSET)           , 1 /*up to 5*/
+	  , 1      , 0 /**/		    , CMD_NAME("TOGGLE_PIPE_STATE") },
+	{ (CMD_0C_DEF_STREAM << OPCODE_OFFSET)			, 1 /*up to 4*/
+	  , 1      , 0 /**/		    , CMD_NAME("DEF_STREAM") },
+	{ (CMD_0D_SET_MUTE  << OPCODE_OFFSET)			, 3 /**/
+	  , 1      , 0 /**/		    , CMD_NAME("SET_MUTE") },
+	{ (CMD_0E_GET_STREAM_SPL_COUNT << OPCODE_OFFSET)        , 1/**/
+	  , 1      , 2 /**/		    , CMD_NAME("GET_STREAM_SPL_COUNT") },
+	{ (CMD_0F_UPDATE_BUFFER << OPCODE_OFFSET)		, 3 /*up to 4*/
+	  , 0      , 1 /**/		    , CMD_NAME("UPDATE_BUFFER") },
+	{ (CMD_10_GET_BUFFER << OPCODE_OFFSET)			, 1 /**/
+	  , 1      , 4 /**/		    , CMD_NAME("GET_BUFFER") },
+	{ (CMD_11_CANCEL_BUFFER << OPCODE_OFFSET)		, 1 /**/
+	  , 1      , 1 /*up to 4*/      , CMD_NAME("CANCEL_BUFFER") },
+	{ (CMD_12_GET_PEAK << OPCODE_OFFSET)			, 1 /**/
+	  , 1      , 1 /**/		    , CMD_NAME("GET_PEAK") },
+	{ (CMD_13_SET_STREAM_STATE << OPCODE_OFFSET)	        , 1 /**/
+	  , 1      , 0 /**/		    , CMD_NAME("SET_STREAM_STATE") },
+};
+
+static void lx_message_init(struct lx_rmh *rmh, enum cmd_mb_opcodes cmd)
+{
+	snd_BUG_ON(cmd >= CMD_14_INVALID);
+
+	rmh->cmd[0] = dsp_commands[cmd].dcCodeOp;
+	rmh->cmd_len = dsp_commands[cmd].dcCmdLength;
+	rmh->stat_len = dsp_commands[cmd].dcStatusLength;
+	rmh->dsp_stat = dsp_commands[cmd].dcStatusType;
+	rmh->cmd_idx = cmd;
+	memset(&rmh->cmd[1], 0, (REG_CRM_NUMBER - 1) * sizeof(u32));
+
+#ifdef CONFIG_SND_DEBUG
+	memset(rmh->stat, 0, REG_CRM_NUMBER * sizeof(u32));
+#endif
+#ifdef RMH_DEBUG
+	rmh->cmd_idx = cmd;
+#endif
+}
+
+#ifdef RMH_DEBUG
+#define LXRMH "lx6464es rmh: "
+static void lx_message_dump(struct lx_rmh *rmh)
+{
+	u8 idx = rmh->cmd_idx;
+	int i;
+
+	snd_printk(LXRMH "command %s\n", dsp_commands[idx].dcOpName);
+
+	for (i = 0; i != rmh->cmd_len; ++i)
+		snd_printk(LXRMH "\tcmd[%d] %08x\n", i, rmh->cmd[i]);
+
+	for (i = 0; i != rmh->stat_len; ++i)
+		snd_printk(LXRMH "\tstat[%d]: %08x\n", i, rmh->stat[i]);
+	snd_printk("\n");
+}
+#else
+static inline void lx_message_dump(struct lx_rmh *rmh)
+{}
+#endif
+
+
+
+/* sleep 500 - 100 = 400 times 100us -> the timeout is >= 40 ms */
+#define XILINX_TIMEOUT_MS       40
+#define XILINX_POLL_NO_SLEEP    100
+#define XILINX_POLL_ITERATIONS  150
+
+#if 0 /* not used now */
+static int lx_message_send(struct lx6464es *chip, struct lx_rmh *rmh)
+{
+	u32 reg = ED_DSP_TIMED_OUT;
+	int dwloop;
+	int answer_received;
+
+	if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) {
+		snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg);
+		return -EBUSY;
+	}
+
+	/* write command */
+	lx_dsp_reg_writebuf(chip, eReg_CRM1, rmh->cmd, rmh->cmd_len);
+
+	snd_BUG_ON(atomic_read(&chip->send_message_locked) != 0);
+	atomic_set(&chip->send_message_locked, 1);
+
+	/* MicoBlaze gogogo */
+	lx_dsp_reg_write(chip, eReg_CSM, Reg_CSM_MC);
+
+	/* wait for interrupt to answer */
+	for (dwloop = 0; dwloop != XILINX_TIMEOUT_MS; ++dwloop) {
+		answer_received = atomic_read(&chip->send_message_locked);
+		if (answer_received == 0)
+			break;
+		msleep(1);
+	}
+
+	if (answer_received == 0) {
+		/* in Debug mode verify Reg_CSM_MR */
+		snd_BUG_ON(!(lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR));
+
+		/* command finished, read status */
+		if (rmh->dsp_stat == 0)
+			reg = lx_dsp_reg_read(chip, eReg_CRM1);
+		else
+			reg = 0;
+	} else {
+		int i;
+		snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send! "
+			   "Interrupts disabled?\n");
+
+		/* attente bit Reg_CSM_MR */
+		for (i = 0; i != XILINX_POLL_ITERATIONS; i++) {
+			if ((lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR)) {
+				if (rmh->dsp_stat == 0)
+					reg = lx_dsp_reg_read(chip, eReg_CRM1);
+				else
+					reg = 0;
+				goto polling_successful;
+			}
+
+			if (i > XILINX_POLL_NO_SLEEP)
+				msleep(1);
+		}
+		snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send! "
+			   "polling failed\n");
+
+polling_successful:
+		atomic_set(&chip->send_message_locked, 0);
+	}
+
+	if ((reg & ERROR_VALUE) == 0) {
+		/* read response */
+		if (rmh->stat_len) {
+			snd_BUG_ON(rmh->stat_len >= (REG_CRM_NUMBER-1));
+
+			lx_dsp_reg_readbuf(chip, eReg_CRM2, rmh->stat,
+					   rmh->stat_len);
+		}
+	} else
+		snd_printk(KERN_WARNING LXP "lx_message_send: error_value %x\n",
+			   reg);
+
+	/* clear Reg_CSM_MR */
+	lx_dsp_reg_write(chip, eReg_CSM, 0);
+
+	switch (reg) {
+	case ED_DSP_TIMED_OUT:
+		snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n");
+		return -ETIMEDOUT;
+
+	case ED_DSP_CRASHED:
+		snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n");
+		return -EAGAIN;
+	}
+
+	lx_message_dump(rmh);
+	return 0;
+}
+#endif /* not used now */
+
+static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh)
+{
+	u32 reg = ED_DSP_TIMED_OUT;
+	int dwloop;
+
+	if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) {
+		snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg);
+		return -EBUSY;
+	}
+
+	/* write command */
+	lx_dsp_reg_writebuf(chip, eReg_CRM1, rmh->cmd, rmh->cmd_len);
+
+	/* MicoBlaze gogogo */
+	lx_dsp_reg_write(chip, eReg_CSM, Reg_CSM_MC);
+
+	/* wait for interrupt to answer */
+	for (dwloop = 0; dwloop != XILINX_TIMEOUT_MS * 1000; ++dwloop) {
+		if (lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR) {
+			if (rmh->dsp_stat == 0)
+				reg = lx_dsp_reg_read(chip, eReg_CRM1);
+			else
+				reg = 0;
+			goto polling_successful;
+		} else
+			udelay(1);
+	}
+	snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send_atomic! "
+		   "polling failed\n");
+
+polling_successful:
+	if ((reg & ERROR_VALUE) == 0) {
+		/* read response */
+		if (rmh->stat_len) {
+			snd_BUG_ON(rmh->stat_len >= (REG_CRM_NUMBER-1));
+			lx_dsp_reg_readbuf(chip, eReg_CRM2, rmh->stat,
+					   rmh->stat_len);
+		}
+	} else
+		snd_printk(LXP "rmh error: %08x\n", reg);
+
+	/* clear Reg_CSM_MR */
+	lx_dsp_reg_write(chip, eReg_CSM, 0);
+
+	switch (reg) {
+	case ED_DSP_TIMED_OUT:
+		snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n");
+		return -ETIMEDOUT;
+
+	case ED_DSP_CRASHED:
+		snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n");
+		return -EAGAIN;
+	}
+
+	lx_message_dump(rmh);
+
+	return reg;
+}
+
+
+/* low-level dsp access */
+int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version)
+{
+	u16 ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+
+	lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG);
+	ret = lx_message_send_atomic(chip, &chip->rmh);
+
+	*rdsp_version = chip->rmh.stat[1];
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return ret;
+}
+
+int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq)
+{
+	u16 ret = 0;
+	unsigned long flags;
+	u32 freq_raw = 0;
+	u32 freq = 0;
+	u32 frequency = 0;
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+
+	lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG);
+	ret = lx_message_send_atomic(chip, &chip->rmh);
+
+	if (ret == 0) {
+		freq_raw = chip->rmh.stat[0] >> FREQ_FIELD_OFFSET;
+		freq = freq_raw & XES_FREQ_COUNT8_MASK;
+
+		if ((freq < XES_FREQ_COUNT8_48_MAX) ||
+		    (freq > XES_FREQ_COUNT8_44_MIN))
+			frequency = 0; /* unknown */
+		else if (freq >= XES_FREQ_COUNT8_44_MAX)
+			frequency = 44100;
+		else
+			frequency = 48000;
+	}
+
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+
+	*rfreq = frequency * chip->freq_ratio;
+
+	return ret;
+}
+
+int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address)
+{
+	u32 macmsb, maclsb;
+
+	macmsb = lx_dsp_reg_read(chip, eReg_ADMACESMSB) & 0x00FFFFFF;
+	maclsb = lx_dsp_reg_read(chip, eReg_ADMACESLSB) & 0x00FFFFFF;
+
+	/* todo: endianess handling */
+	mac_address[5] = ((u8 *)(&maclsb))[0];
+	mac_address[4] = ((u8 *)(&maclsb))[1];
+	mac_address[3] = ((u8 *)(&maclsb))[2];
+	mac_address[2] = ((u8 *)(&macmsb))[0];
+	mac_address[1] = ((u8 *)(&macmsb))[1];
+	mac_address[0] = ((u8 *)(&macmsb))[2];
+
+	return 0;
+}
+
+
+int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+
+	lx_message_init(&chip->rmh, CMD_02_SET_GRANULARITY);
+	chip->rmh.cmd[0] |= gran;
+
+	ret = lx_message_send_atomic(chip, &chip->rmh);
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return ret;
+}
+
+int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+
+	lx_message_init(&chip->rmh, CMD_04_GET_EVENT);
+	chip->rmh.stat_len = 9;	/* we don't necessarily need the full length */
+
+	ret = lx_message_send_atomic(chip, &chip->rmh);
+
+	if (!ret)
+		memcpy(data, chip->rmh.stat, chip->rmh.stat_len * sizeof(u32));
+
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return ret;
+}
+
+#define CSES_TIMEOUT        100     /* microseconds */
+#define CSES_CE             0x0001
+#define CSES_BROADCAST      0x0002
+#define CSES_UPDATE_LDSV    0x0004
+
+int lx_dsp_es_check_pipeline(struct lx6464es *chip)
+{
+	int i;
+
+	for (i = 0; i != CSES_TIMEOUT; ++i) {
+		/*
+		 * le bit CSES_UPDATE_LDSV est à 1 dés que le macprog
+		 * est pret. il re-passe à 0 lorsque le premier read a
+		 * été fait. pour l'instant on retire le test car ce bit
+		 * passe a 1 environ 200 à 400 ms aprés que le registre
+		 * confES à été écrit (kick du xilinx ES).
+		 *
+		 * On ne teste que le bit CE.
+		 * */
+
+		u32 cses = lx_dsp_reg_read(chip, eReg_CSES);
+
+		if ((cses & CSES_CE) == 0)
+			return 0;
+
+		udelay(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+
+#define PIPE_INFO_TO_CMD(capture, pipe)					\
+	((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET)
+
+
+
+/* low-level pipe handling */
+int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture,
+		     int channels)
+{
+	int err;
+	unsigned long flags;
+
+	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_06_ALLOCATE_PIPE);
+
+	chip->rmh.cmd[0] |= pipe_cmd;
+	chip->rmh.cmd[0] |= channels;
+
+	err = lx_message_send_atomic(chip, &chip->rmh);
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+
+	if (err != 0)
+		snd_printk(KERN_ERR "lx6464es: could not allocate pipe\n");
+
+	return err;
+}
+
+int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture)
+{
+	int err;
+	unsigned long flags;
+
+	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_07_RELEASE_PIPE);
+
+	chip->rmh.cmd[0] |= pipe_cmd;
+
+	err = lx_message_send_atomic(chip, &chip->rmh);
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+
+	return err;
+}
+
+int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
+		  u32 *r_needed, u32 *r_freed, u32 *size_array)
+{
+	int err;
+	unsigned long flags;
+
+	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+#ifdef CONFIG_SND_DEBUG
+	if (size_array)
+		memset(size_array, 0, sizeof(u32)*MAX_STREAM_BUFFER);
+#endif
+
+	*r_needed = 0;
+	*r_freed = 0;
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_08_ASK_BUFFERS);
+
+	chip->rmh.cmd[0] |= pipe_cmd;
+
+	err = lx_message_send_atomic(chip, &chip->rmh);
+
+	if (!err) {
+		int i;
+		for (i = 0; i < MAX_STREAM_BUFFER; ++i) {
+			u32 stat = chip->rmh.stat[i];
+			if (stat & (BF_EOB << BUFF_FLAGS_OFFSET)) {
+				/* finished */
+				*r_freed += 1;
+				if (size_array)
+					size_array[i] = stat & MASK_DATA_SIZE;
+			} else if ((stat & (BF_VALID << BUFF_FLAGS_OFFSET))
+				   == 0)
+				/* free */
+				*r_needed += 1;
+		}
+
+#if 0
+		snd_printdd(LXP "CMD_08_ASK_BUFFERS: needed %d, freed %d\n",
+			    *r_needed, *r_freed);
+		for (i = 0; i < MAX_STREAM_BUFFER; ++i) {
+			for (i = 0; i != chip->rmh.stat_len; ++i)
+				snd_printdd("  stat[%d]: %x, %x\n", i,
+					    chip->rmh.stat[i],
+					    chip->rmh.stat[i] & MASK_DATA_SIZE);
+		}
+#endif
+	}
+
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return err;
+}
+
+
+int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture)
+{
+	int err;
+	unsigned long flags;
+
+	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_09_STOP_PIPE);
+
+	chip->rmh.cmd[0] |= pipe_cmd;
+
+	err = lx_message_send_atomic(chip, &chip->rmh);
+
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return err;
+}
+
+static int lx_pipe_toggle_state(struct lx6464es *chip, u32 pipe, int is_capture)
+{
+	int err;
+	unsigned long flags;
+
+	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_0B_TOGGLE_PIPE_STATE);
+
+	chip->rmh.cmd[0] |= pipe_cmd;
+
+	err = lx_message_send_atomic(chip, &chip->rmh);
+
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return err;
+}
+
+
+int lx_pipe_start(struct lx6464es *chip, u32 pipe, int is_capture)
+{
+	int err;
+
+	err = lx_pipe_wait_for_idle(chip, pipe, is_capture);
+	if (err < 0)
+		return err;
+
+	err = lx_pipe_toggle_state(chip, pipe, is_capture);
+
+	return err;
+}
+
+int lx_pipe_pause(struct lx6464es *chip, u32 pipe, int is_capture)
+{
+	int err = 0;
+
+	err = lx_pipe_wait_for_start(chip, pipe, is_capture);
+	if (err < 0)
+		return err;
+
+	err = lx_pipe_toggle_state(chip, pipe, is_capture);
+
+	return err;
+}
+
+
+int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture,
+			 u64 *rsample_count)
+{
+	int err;
+	unsigned long flags;
+
+	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT);
+
+	chip->rmh.cmd[0] |= pipe_cmd;
+	chip->rmh.stat_len = 2;	/* need all words here! */
+
+	err = lx_message_send_atomic(chip, &chip->rmh); /* don't sleep! */
+
+	if (err != 0)
+		snd_printk(KERN_ERR
+			   "lx6464es: could not query pipe's sample count\n");
+	else {
+		*rsample_count = ((u64)(chip->rmh.stat[0] & MASK_SPL_COUNT_HI)
+				  << 24)     /* hi part */
+			+ chip->rmh.stat[1]; /* lo part */
+	}
+
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return err;
+}
+
+int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate)
+{
+	int err;
+	unsigned long flags;
+
+	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT);
+
+	chip->rmh.cmd[0] |= pipe_cmd;
+
+	err = lx_message_send_atomic(chip, &chip->rmh);
+
+	if (err != 0)
+		snd_printk(KERN_ERR "lx6464es: could not query pipe's state\n");
+	else
+		*rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F;
+
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return err;
+}
+
+static int lx_pipe_wait_for_state(struct lx6464es *chip, u32 pipe,
+				  int is_capture, u16 state)
+{
+	int i;
+
+	/* max 2*PCMOnlyGranularity = 2*1024 at 44100 = < 50 ms:
+	 * timeout 50 ms */
+	for (i = 0; i != 50; ++i) {
+		u16 current_state;
+		int err = lx_pipe_state(chip, pipe, is_capture, &current_state);
+
+		if (err < 0)
+			return err;
+
+		if (current_state == state)
+			return 0;
+
+		mdelay(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+int lx_pipe_wait_for_start(struct lx6464es *chip, u32 pipe, int is_capture)
+{
+	return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_RUN);
+}
+
+int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture)
+{
+	return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_IDLE);
+}
+
+/* low-level stream handling */
+int lx_stream_set_state(struct lx6464es *chip, u32 pipe,
+			       int is_capture, enum stream_state_t state)
+{
+	int err;
+	unsigned long flags;
+
+	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_13_SET_STREAM_STATE);
+
+	chip->rmh.cmd[0] |= pipe_cmd;
+	chip->rmh.cmd[0] |= state;
+
+	err = lx_message_send_atomic(chip, &chip->rmh);
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+
+	return err;
+}
+
+int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime,
+			 u32 pipe, int is_capture)
+{
+	int err;
+	unsigned long flags;
+
+	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+	u32 channels = runtime->channels;
+
+	if (runtime->channels != channels)
+		snd_printk(KERN_ERR LXP "channel count mismatch: %d vs %d",
+			   runtime->channels, channels);
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM);
+
+	chip->rmh.cmd[0] |= pipe_cmd;
+
+	if (runtime->sample_bits == 16)
+		/* 16 bit format */
+		chip->rmh.cmd[0] |= (STREAM_FMT_16b << STREAM_FMT_OFFSET);
+
+	if (snd_pcm_format_little_endian(runtime->format))
+		/* little endian/intel format */
+		chip->rmh.cmd[0] |= (STREAM_FMT_intel << STREAM_FMT_OFFSET);
+
+	chip->rmh.cmd[0] |= channels-1;
+
+	err = lx_message_send_atomic(chip, &chip->rmh);
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+
+	return err;
+}
+
+int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture,
+		    int *rstate)
+{
+	int err;
+	unsigned long flags;
+
+	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT);
+
+	chip->rmh.cmd[0] |= pipe_cmd;
+
+	err = lx_message_send_atomic(chip, &chip->rmh);
+
+	*rstate = (chip->rmh.stat[0] & SF_START) ? START_STATE : PAUSE_STATE;
+
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return err;
+}
+
+int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture,
+			      u64 *r_bytepos)
+{
+	int err;
+	unsigned long flags;
+
+	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT);
+
+	chip->rmh.cmd[0] |= pipe_cmd;
+
+	err = lx_message_send_atomic(chip, &chip->rmh);
+
+	*r_bytepos = ((u64) (chip->rmh.stat[0] & MASK_SPL_COUNT_HI)
+		      << 32)	     /* hi part */
+		+ chip->rmh.stat[1]; /* lo part */
+
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return err;
+}
+
+/* low-level buffer handling */
+int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture,
+		   u32 buffer_size, u32 buf_address_lo, u32 buf_address_hi,
+		   u32 *r_buffer_index)
+{
+	int err;
+	unsigned long flags;
+
+	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_0F_UPDATE_BUFFER);
+
+	chip->rmh.cmd[0] |= pipe_cmd;
+	chip->rmh.cmd[0] |= BF_NOTIFY_EOB; /* request interrupt notification */
+
+	/* todo: pause request, circular buffer */
+
+	chip->rmh.cmd[1] = buffer_size & MASK_DATA_SIZE;
+	chip->rmh.cmd[2] = buf_address_lo;
+
+	if (buf_address_hi) {
+		chip->rmh.cmd_len = 4;
+		chip->rmh.cmd[3] = buf_address_hi;
+		chip->rmh.cmd[0] |= BF_64BITS_ADR;
+	}
+
+	err = lx_message_send_atomic(chip, &chip->rmh);
+
+	if (err == 0) {
+		*r_buffer_index = chip->rmh.stat[0];
+		goto done;
+	}
+
+	if (err == EB_RBUFFERS_TABLE_OVERFLOW)
+		snd_printk(LXP "lx_buffer_give EB_RBUFFERS_TABLE_OVERFLOW\n");
+
+	if (err == EB_INVALID_STREAM)
+		snd_printk(LXP "lx_buffer_give EB_INVALID_STREAM\n");
+
+	if (err == EB_CMD_REFUSED)
+		snd_printk(LXP "lx_buffer_give EB_CMD_REFUSED\n");
+
+ done:
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return err;
+}
+
+int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture,
+		   u32 *r_buffer_size)
+{
+	int err;
+	unsigned long flags;
+
+	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER);
+
+	chip->rmh.cmd[0] |= pipe_cmd;
+	chip->rmh.cmd[0] |= MASK_BUFFER_ID; /* ask for the current buffer: the
+					     * microblaze will seek for it */
+
+	err = lx_message_send_atomic(chip, &chip->rmh);
+
+	if (err == 0)
+		*r_buffer_size = chip->rmh.stat[0]  & MASK_DATA_SIZE;
+
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return err;
+}
+
+int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture,
+		     u32 buffer_index)
+{
+	int err;
+	unsigned long flags;
+
+	u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER);
+
+	chip->rmh.cmd[0] |= pipe_cmd;
+	chip->rmh.cmd[0] |= buffer_index;
+
+	err = lx_message_send_atomic(chip, &chip->rmh);
+
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return err;
+}
+
+
+/* low-level gain/peak handling
+ *
+ * \todo: can we unmute capture/playback channels independently?
+ *
+ * */
+int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute)
+{
+	int err;
+	unsigned long flags;
+
+	/* bit set to 1: channel muted */
+	u64 mute_mask = unmute ? 0 : 0xFFFFFFFFFFFFFFFFLLU;
+
+	spin_lock_irqsave(&chip->msg_lock, flags);
+	lx_message_init(&chip->rmh, CMD_0D_SET_MUTE);
+
+	chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, 0);
+
+	chip->rmh.cmd[1] = (u32)(mute_mask >> (u64)32);	       /* hi part */
+	chip->rmh.cmd[2] = (u32)(mute_mask & (u64)0xFFFFFFFF); /* lo part */
+
+	snd_printk("mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1],
+		   chip->rmh.cmd[2]);
+
+	err = lx_message_send_atomic(chip, &chip->rmh);
+
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return err;
+}
+
+static u32 peak_map[] = {
+	0x00000109, /* -90.308dB */
+	0x0000083B, /* -72.247dB */
+	0x000020C4, /* -60.205dB */
+	0x00008273, /* -48.030dB */
+	0x00020756, /* -36.005dB */
+	0x00040C37, /* -30.001dB */
+	0x00081385, /* -24.002dB */
+	0x00101D3F, /* -18.000dB */
+	0x0016C310, /* -15.000dB */
+	0x002026F2, /* -12.001dB */
+	0x002D6A86, /* -9.000dB */
+	0x004026E6, /* -6.004dB */
+	0x005A9DF6, /* -3.000dB */
+	0x0065AC8B, /* -2.000dB */
+	0x00721481, /* -1.000dB */
+	0x007FFFFF, /* FS */
+};
+
+int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels,
+		   u32 *r_levels)
+{
+	int err = 0;
+	unsigned long flags;
+	int i;
+	spin_lock_irqsave(&chip->msg_lock, flags);
+
+	for (i = 0; i < channels; i += 4) {
+		u32 s0, s1, s2, s3;
+
+		lx_message_init(&chip->rmh, CMD_12_GET_PEAK);
+		chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, i);
+
+		err = lx_message_send_atomic(chip, &chip->rmh);
+
+		if (err == 0) {
+			s0 = peak_map[chip->rmh.stat[0] & 0x0F];
+			s1 = peak_map[(chip->rmh.stat[0] >>  4) & 0xf];
+			s2 = peak_map[(chip->rmh.stat[0] >>  8) & 0xf];
+			s3 = peak_map[(chip->rmh.stat[0] >>  12) & 0xf];
+		} else
+			s0 = s1 = s2 = s3 = 0;
+
+		r_levels[0] = s0;
+		r_levels[1] = s1;
+		r_levels[2] = s2;
+		r_levels[3] = s3;
+
+		r_levels += 4;
+	}
+
+	spin_unlock_irqrestore(&chip->msg_lock, flags);
+	return err;
+}
+
+/* interrupt handling */
+#define PCX_IRQ_NONE 0
+#define IRQCS_ACTIVE_PCIDB  0x00002000L         /* Bit nø 13 */
+#define IRQCS_ENABLE_PCIIRQ 0x00000100L         /* Bit nø 08 */
+#define IRQCS_ENABLE_PCIDB  0x00000200L         /* Bit nø 09 */
+
+static u32 lx_interrupt_test_ack(struct lx6464es *chip)
+{
+	u32 irqcs = lx_plx_reg_read(chip, ePLX_IRQCS);
+
+	/* Test if PCI Doorbell interrupt is active */
+	if (irqcs & IRQCS_ACTIVE_PCIDB)	{
+		u32 temp;
+		irqcs = PCX_IRQ_NONE;
+
+		while ((temp = lx_plx_reg_read(chip, ePLX_L2PCIDB))) {
+			/* RAZ interrupt */
+			irqcs |= temp;
+			lx_plx_reg_write(chip, ePLX_L2PCIDB, temp);
+		}
+
+		return irqcs;
+	}
+	return PCX_IRQ_NONE;
+}
+
+static int lx_interrupt_ack(struct lx6464es *chip, u32 *r_irqsrc,
+			    int *r_async_pending, int *r_async_escmd)
+{
+	u32 irq_async;
+	u32 irqsrc = lx_interrupt_test_ack(chip);
+
+	if (irqsrc == PCX_IRQ_NONE)
+		return 0;
+
+	*r_irqsrc = irqsrc;
+
+	irq_async = irqsrc & MASK_SYS_ASYNC_EVENTS; /* + EtherSound response
+						     * (set by xilinx) + EOB */
+
+	if (irq_async & MASK_SYS_STATUS_ESA) {
+		irq_async &= ~MASK_SYS_STATUS_ESA;
+		*r_async_escmd = 1;
+	}
+
+	if (irqsrc & MASK_SYS_STATUS_CMD_DONE)
+		/* xilinx command notification */
+		atomic_set(&chip->send_message_locked, 0);
+
+	if (irq_async) {
+		/* snd_printd("interrupt: async event pending\n"); */
+		*r_async_pending = 1;
+	}
+
+	return 1;
+}
+
+static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc,
+					    int *r_freq_changed,
+					    u64 *r_notified_in_pipe_mask,
+					    u64 *r_notified_out_pipe_mask)
+{
+	int err;
+	u32 stat[9];		/* answer from CMD_04_GET_EVENT */
+
+	/* On peut optimiser pour ne pas lire les evenements vides
+	 * les mots de rÃĩponse sont dans l'ordre suivant :
+	 * Stat[0]	mot de status gÃĩnÃĩral
+	 * Stat[1]	fin de buffer OUT pF
+	 * Stat[2]	fin de buffer OUT pf
+	 * Stat[3]	fin de buffer IN pF
+	 * Stat[4]	fin de buffer IN pf
+	 * Stat[5]	underrun poid fort
+	 * Stat[6]	underrun poid faible
+	 * Stat[7]	overrun poid fort
+	 * Stat[8]	overrun poid faible
+	 * */
+
+	u64 orun_mask;
+	u64 urun_mask;
+#if 0
+	int has_underrun   = (irqsrc & MASK_SYS_STATUS_URUN) ? 1 : 0;
+	int has_overrun    = (irqsrc & MASK_SYS_STATUS_ORUN) ? 1 : 0;
+#endif
+	int eb_pending_out = (irqsrc & MASK_SYS_STATUS_EOBO) ? 1 : 0;
+	int eb_pending_in  = (irqsrc & MASK_SYS_STATUS_EOBI) ? 1 : 0;
+
+	*r_freq_changed = (irqsrc & MASK_SYS_STATUS_FREQ) ? 1 : 0;
+
+	err = lx_dsp_read_async_events(chip, stat);
+	if (err < 0)
+		return err;
+
+	if (eb_pending_in) {
+		*r_notified_in_pipe_mask = ((u64)stat[3] << 32)
+			+ stat[4];
+		snd_printdd(LXP "interrupt: EOBI pending %llx\n",
+			    *r_notified_in_pipe_mask);
+	}
+	if (eb_pending_out) {
+		*r_notified_out_pipe_mask = ((u64)stat[1] << 32)
+			+ stat[2];
+		snd_printdd(LXP "interrupt: EOBO pending %llx\n",
+			    *r_notified_out_pipe_mask);
+	}
+
+	orun_mask = ((u64)stat[7] << 32) + stat[8];
+	urun_mask = ((u64)stat[5] << 32) + stat[6];
+
+	/* todo: handle xrun notification */
+
+	return err;
+}
+
+static int lx_interrupt_request_new_buffer(struct lx6464es *chip,
+					   struct lx_stream *lx_stream)
+{
+	struct snd_pcm_substream *substream = lx_stream->stream;
+	int is_capture = lx_stream->is_capture;
+	int err;
+	unsigned long flags;
+
+	const u32 channels = substream->runtime->channels;
+	const u32 bytes_per_frame = channels * 3;
+	const u32 period_size = substream->runtime->period_size;
+	const u32 period_bytes = period_size * bytes_per_frame;
+	const u32 pos = lx_stream->frame_pos;
+	const u32 next_pos = ((pos+1) == substream->runtime->periods) ?
+		0 : pos + 1;
+
+	dma_addr_t buf = substream->dma_buffer.addr + pos * period_bytes;
+	u32 buf_hi = 0;
+	u32 buf_lo = 0;
+	u32 buffer_index = 0;
+
+	u32 needed, freed;
+	u32 size_array[MAX_STREAM_BUFFER];
+
+	snd_printdd("->lx_interrupt_request_new_buffer\n");
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array);
+	snd_printdd(LXP "interrupt: needed %d, freed %d\n", needed, freed);
+
+	unpack_pointer(buf, &buf_lo, &buf_hi);
+	err = lx_buffer_give(chip, 0, is_capture, period_bytes, buf_lo, buf_hi,
+			     &buffer_index);
+	snd_printdd(LXP "interrupt: gave buffer index %x on %p (%d bytes)\n",
+		    buffer_index, (void *)buf, period_bytes);
+
+	lx_stream->frame_pos = next_pos;
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return err;
+}
+
+void lx_tasklet_playback(unsigned long data)
+{
+	struct lx6464es *chip = (struct lx6464es *)data;
+	struct lx_stream *lx_stream = &chip->playback_stream;
+	int err;
+
+	snd_printdd("->lx_tasklet_playback\n");
+
+	err = lx_interrupt_request_new_buffer(chip, lx_stream);
+	if (err < 0)
+		snd_printk(KERN_ERR LXP
+			   "cannot request new buffer for playback\n");
+
+	snd_pcm_period_elapsed(lx_stream->stream);
+}
+
+void lx_tasklet_capture(unsigned long data)
+{
+	struct lx6464es *chip = (struct lx6464es *)data;
+	struct lx_stream *lx_stream = &chip->capture_stream;
+	int err;
+
+	snd_printdd("->lx_tasklet_capture\n");
+	err = lx_interrupt_request_new_buffer(chip, lx_stream);
+	if (err < 0)
+		snd_printk(KERN_ERR LXP
+			   "cannot request new buffer for capture\n");
+
+	snd_pcm_period_elapsed(lx_stream->stream);
+}
+
+
+
+static int lx_interrupt_handle_audio_transfer(struct lx6464es *chip,
+					      u64 notified_in_pipe_mask,
+					      u64 notified_out_pipe_mask)
+{
+	int err = 0;
+
+	if (notified_in_pipe_mask) {
+		snd_printdd(LXP "requesting audio transfer for capture\n");
+		tasklet_hi_schedule(&chip->tasklet_capture);
+	}
+
+	if (notified_out_pipe_mask) {
+		snd_printdd(LXP "requesting audio transfer for playback\n");
+		tasklet_hi_schedule(&chip->tasklet_playback);
+	}
+
+	return err;
+}
+
+
+irqreturn_t lx_interrupt(int irq, void *dev_id)
+{
+	struct lx6464es *chip = dev_id;
+	int async_pending, async_escmd;
+	u32 irqsrc;
+
+	spin_lock(&chip->lock);
+
+	snd_printdd("**************************************************\n");
+
+	if (!lx_interrupt_ack(chip, &irqsrc, &async_pending, &async_escmd)) {
+		spin_unlock(&chip->lock);
+		snd_printdd("IRQ_NONE\n");
+		return IRQ_NONE; /* this device did not cause the interrupt */
+	}
+
+	if (irqsrc & MASK_SYS_STATUS_CMD_DONE)
+		goto exit;
+
+#if 0
+	if (irqsrc & MASK_SYS_STATUS_EOBI)
+		snd_printdd(LXP "interrupt: EOBI\n");
+
+	if (irqsrc & MASK_SYS_STATUS_EOBO)
+		snd_printdd(LXP "interrupt: EOBO\n");
+
+	if (irqsrc & MASK_SYS_STATUS_URUN)
+		snd_printdd(LXP "interrupt: URUN\n");
+
+	if (irqsrc & MASK_SYS_STATUS_ORUN)
+		snd_printdd(LXP "interrupt: ORUN\n");
+#endif
+
+	if (async_pending) {
+		u64 notified_in_pipe_mask = 0;
+		u64 notified_out_pipe_mask = 0;
+		int freq_changed;
+		int err;
+
+		/* handle async events */
+		err = lx_interrupt_handle_async_events(chip, irqsrc,
+						       &freq_changed,
+						       &notified_in_pipe_mask,
+						       &notified_out_pipe_mask);
+		if (err)
+			snd_printk(KERN_ERR LXP
+				   "error handling async events\n");
+
+		err = lx_interrupt_handle_audio_transfer(chip,
+							 notified_in_pipe_mask,
+							 notified_out_pipe_mask
+			);
+		if (err)
+			snd_printk(KERN_ERR LXP
+				   "error during audio transfer\n");
+	}
+
+	if (async_escmd) {
+#if 0
+		/* backdoor for ethersound commands
+		 *
+		 * for now, we do not need this
+		 *
+		 * */
+
+		snd_printdd("lx6464es: interrupt requests escmd handling\n");
+#endif
+	}
+
+exit:
+	spin_unlock(&chip->lock);
+	return IRQ_HANDLED;	/* this device caused the interrupt */
+}
+
+
+static void lx_irq_set(struct lx6464es *chip, int enable)
+{
+	u32 reg = lx_plx_reg_read(chip, ePLX_IRQCS);
+
+	/* enable/disable interrupts
+	 *
+	 * Set the Doorbell and PCI interrupt enable bits
+	 *
+	 * */
+	if (enable)
+		reg |=  (IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB);
+	else
+		reg &= ~(IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB);
+	lx_plx_reg_write(chip, ePLX_IRQCS, reg);
+}
+
+void lx_irq_enable(struct lx6464es *chip)
+{
+	snd_printdd("->lx_irq_enable\n");
+	lx_irq_set(chip, 1);
+}
+
+void lx_irq_disable(struct lx6464es *chip)
+{
+	snd_printdd("->lx_irq_disable\n");
+	lx_irq_set(chip, 0);
+}
diff --git a/sound/pci/lx6464es/lx_core.h b/sound/pci/lx6464es/lx_core.h
new file mode 100644
index 0000000..6bd9cbb
--- /dev/null
+++ b/sound/pci/lx6464es/lx_core.h
@@ -0,0 +1,242 @@
+/* -*- linux-c -*- *
+ *
+ * ALSA driver for the digigram lx6464es interface
+ * low-level interface
+ *
+ * Copyright (c) 2009 Tim Blechmann <tim@klingt.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; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef LX_CORE_H
+#define LX_CORE_H
+
+#include <linux/interrupt.h>
+
+#include "lx_defs.h"
+
+#define REG_CRM_NUMBER		12
+
+struct lx6464es;
+
+/* low-level register access */
+
+/* dsp register access */
+enum {
+	eReg_BASE,
+	eReg_CSM,
+	eReg_CRM1,
+	eReg_CRM2,
+	eReg_CRM3,
+	eReg_CRM4,
+	eReg_CRM5,
+	eReg_CRM6,
+	eReg_CRM7,
+	eReg_CRM8,
+	eReg_CRM9,
+	eReg_CRM10,
+	eReg_CRM11,
+	eReg_CRM12,
+
+	eReg_ICR,
+	eReg_CVR,
+	eReg_ISR,
+	eReg_RXHTXH,
+	eReg_RXMTXM,
+	eReg_RHLTXL,
+	eReg_RESETDSP,
+
+	eReg_CSUF,
+	eReg_CSES,
+	eReg_CRESMSB,
+	eReg_CRESLSB,
+	eReg_ADMACESMSB,
+	eReg_ADMACESLSB,
+	eReg_CONFES,
+
+	eMaxPortLx
+};
+
+unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port);
+void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len);
+void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data);
+void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data,
+			 u32 len);
+
+/* plx register access */
+enum {
+    ePLX_PCICR,
+
+    ePLX_MBOX0,
+    ePLX_MBOX1,
+    ePLX_MBOX2,
+    ePLX_MBOX3,
+    ePLX_MBOX4,
+    ePLX_MBOX5,
+    ePLX_MBOX6,
+    ePLX_MBOX7,
+
+    ePLX_L2PCIDB,
+    ePLX_IRQCS,
+    ePLX_CHIPSC,
+
+    eMaxPort
+};
+
+unsigned long lx_plx_reg_read(struct lx6464es *chip, int port);
+void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data);
+
+/* rhm */
+struct lx_rmh {
+	u16	cmd_len;	/* length of the command to send (WORDs) */
+	u16	stat_len;	/* length of the status received (WORDs) */
+	u16	dsp_stat;	/* status type, RMP_SSIZE_XXX */
+	u16	cmd_idx;	/* index of the command */
+	u32	cmd[REG_CRM_NUMBER];
+	u32	stat[REG_CRM_NUMBER];
+};
+
+
+/* low-level dsp access */
+int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version);
+int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq);
+int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran);
+int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data);
+int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address);
+
+
+/* low-level pipe handling */
+int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture,
+		     int channels);
+int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture);
+int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture,
+			 u64 *rsample_count);
+int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate);
+int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture);
+int lx_pipe_start(struct lx6464es *chip, u32 pipe, int is_capture);
+int lx_pipe_pause(struct lx6464es *chip, u32 pipe, int is_capture);
+
+int lx_pipe_wait_for_start(struct lx6464es *chip, u32 pipe, int is_capture);
+int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture);
+
+/* low-level stream handling */
+int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime,
+			 u32 pipe, int is_capture);
+int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture,
+		    int *rstate);
+int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture,
+			      u64 *r_bytepos);
+
+int lx_stream_set_state(struct lx6464es *chip, u32 pipe,
+			int is_capture, enum stream_state_t state);
+
+static inline int lx_stream_start(struct lx6464es *chip, u32 pipe,
+				  int is_capture)
+{
+	snd_printdd("->lx_stream_start\n");
+	return lx_stream_set_state(chip, pipe, is_capture, SSTATE_RUN);
+}
+
+static inline int lx_stream_pause(struct lx6464es *chip, u32 pipe,
+				  int is_capture)
+{
+	snd_printdd("->lx_stream_pause\n");
+	return lx_stream_set_state(chip, pipe, is_capture, SSTATE_PAUSE);
+}
+
+static inline int lx_stream_stop(struct lx6464es *chip, u32 pipe,
+				 int is_capture)
+{
+	snd_printdd("->lx_stream_stop\n");
+	return lx_stream_set_state(chip, pipe, is_capture, SSTATE_STOP);
+}
+
+/* low-level buffer handling */
+int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
+		  u32 *r_needed, u32 *r_freed, u32 *size_array);
+int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture,
+		   u32 buffer_size, u32 buf_address_lo, u32 buf_address_hi,
+		   u32 *r_buffer_index);
+int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture,
+		   u32 *r_buffer_size);
+int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture,
+		     u32 buffer_index);
+
+/* low-level gain/peak handling */
+int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute);
+int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels,
+		   u32 *r_levels);
+
+
+/* interrupt handling */
+irqreturn_t lx_interrupt(int irq, void *dev_id);
+void lx_irq_enable(struct lx6464es *chip);
+void lx_irq_disable(struct lx6464es *chip);
+
+void lx_tasklet_capture(unsigned long data);
+void lx_tasklet_playback(unsigned long data);
+
+
+/* Stream Format Header Defines (for LIN and IEEE754) */
+#define HEADER_FMT_BASE		HEADER_FMT_BASE_LIN
+#define HEADER_FMT_BASE_LIN	0xFED00000
+#define HEADER_FMT_BASE_FLOAT	0xFAD00000
+#define HEADER_FMT_MONO		0x00000080 /* bit 23 in header_lo. WARNING: old
+					    * bit 22 is ignored in float
+					    * format */
+#define HEADER_FMT_INTEL	0x00008000
+#define HEADER_FMT_16BITS	0x00002000
+#define HEADER_FMT_24BITS	0x00004000
+#define HEADER_FMT_UPTO11	0x00000200 /* frequency is less or equ. to 11k.
+					    * */
+#define HEADER_FMT_UPTO32	0x00000100 /* frequency is over 11k and less
+					    * then 32k.*/
+
+
+#define BIT_FMP_HEADER          23
+#define BIT_FMP_SD              22
+#define BIT_FMP_MULTICHANNEL    19
+
+#define START_STATE             1
+#define PAUSE_STATE             0
+
+
+
+
+
+/* from PcxAll_e.h */
+/* Start/Pause condition for pipes (PCXStartPipe, PCXPausePipe) */
+#define START_PAUSE_IMMEDIATE           0
+#define START_PAUSE_ON_SYNCHRO          1
+#define START_PAUSE_ON_TIME_CODE        2
+
+
+/* Pipe / Stream state */
+#define START_STATE             1
+#define PAUSE_STATE             0
+
+static inline void unpack_pointer(dma_addr_t ptr, u32 *r_low, u32 *r_high)
+{
+	*r_low = (u32)(ptr & 0xffffffff);
+#if BITS_PER_LONG == 32
+	*r_high = 0;
+#else
+	*r_high = (u32)((u64)ptr>>32);
+#endif
+}
+
+#endif /* LX_CORE_H */
diff --git a/sound/pci/lx6464es/lx_defs.h b/sound/pci/lx6464es/lx_defs.h
new file mode 100644
index 0000000..49d36bd
--- /dev/null
+++ b/sound/pci/lx6464es/lx_defs.h
@@ -0,0 +1,376 @@
+/* -*- linux-c -*- *
+ *
+ * ALSA driver for the digigram lx6464es interface
+ * adapted upstream headers
+ *
+ * Copyright (c) 2009 Tim Blechmann <tim@klingt.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; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef LX_DEFS_H
+#define LX_DEFS_H
+
+/* code adapted from ethersound.h */
+#define	XES_FREQ_COUNT8_MASK    0x00001FFF /* compteur 25MHz entre 8 ech. */
+#define	XES_FREQ_COUNT8_44_MIN  0x00001288 /* 25M /
+					    * [ 44k - ( 44.1k + 48k ) / 2 ]
+					    * * 8 */
+#define	XES_FREQ_COUNT8_44_MAX	0x000010F0 /* 25M / [ ( 44.1k + 48k ) / 2 ]
+					    * * 8 */
+#define	XES_FREQ_COUNT8_48_MAX	0x00000F08 /* 25M /
+					    * [ 48k + ( 44.1k + 48k ) / 2 ]
+					    * * 8 */
+
+/* code adapted from LXES_registers.h */
+
+#define IOCR_OUTPUTS_OFFSET 0	/* (rw) offset for the number of OUTs in the
+				 * ConfES register. */
+#define IOCR_INPUTS_OFFSET  8	/* (rw) offset for the number of INs in the
+				 * ConfES register. */
+#define FREQ_RATIO_OFFSET  19	/* (rw) offset for frequency ratio in the
+				 * ConfES register. */
+#define	FREQ_RATIO_SINGLE_MODE 0x01 /* value for single mode frequency ratio:
+				     * sample rate = frequency rate. */
+
+#define CONFES_READ_PART_MASK	0x00070000
+#define CONFES_WRITE_PART_MASK	0x00F80000
+
+/* code adapted from if_drv_mb.h */
+
+#define MASK_SYS_STATUS_ERROR	(1L << 31) /* events that lead to a PCI irq if
+					    * not yet pending */
+#define MASK_SYS_STATUS_URUN	(1L << 30)
+#define MASK_SYS_STATUS_ORUN	(1L << 29)
+#define MASK_SYS_STATUS_EOBO	(1L << 28)
+#define MASK_SYS_STATUS_EOBI	(1L << 27)
+#define MASK_SYS_STATUS_FREQ	(1L << 26)
+#define MASK_SYS_STATUS_ESA	(1L << 25) /* reserved, this is set by the
+					    * XES */
+#define MASK_SYS_STATUS_TIMER	(1L << 24)
+
+#define MASK_SYS_ASYNC_EVENTS	(MASK_SYS_STATUS_ERROR |		\
+				 MASK_SYS_STATUS_URUN  |		\
+				 MASK_SYS_STATUS_ORUN  |		\
+				 MASK_SYS_STATUS_EOBO  |		\
+				 MASK_SYS_STATUS_EOBI  |		\
+				 MASK_SYS_STATUS_FREQ  |		\
+				 MASK_SYS_STATUS_ESA)
+
+#define MASK_SYS_PCI_EVENTS		(MASK_SYS_ASYNC_EVENTS |	\
+					 MASK_SYS_STATUS_TIMER)
+
+#define MASK_SYS_TIMER_COUNT	0x0000FFFF
+
+#define MASK_SYS_STATUS_EOT_PLX		(1L << 22) /* event that remains
+						    * internal: reserved fo end
+						    * of plx dma */
+#define MASK_SYS_STATUS_XES		(1L << 21) /* event that remains
+						    * internal: pending XES
+						    * IRQ */
+#define MASK_SYS_STATUS_CMD_DONE	(1L << 20) /* alternate command
+						    * management: notify driver
+						    * instead of polling */
+
+
+#define MAX_STREAM_BUFFER 5	/* max amount of stream buffers. */
+
+#define MICROBLAZE_IBL_MIN		 32
+#define MICROBLAZE_IBL_DEFAULT	        128
+#define MICROBLAZE_IBL_MAX		512
+/* #define MASK_GRANULARITY		(2*MICROBLAZE_IBL_MAX-1) */
+
+
+
+/* command opcodes, see reference for details */
+
+/*
+ the capture bit position in the object_id field in driver commands
+ depends upon the number of managed channels. For now, 64 IN + 64 OUT are
+ supported. HOwever, the communication protocol forsees 1024 channels, hence
+ bit 10 indicates a capture (input) object).
+*/
+#define ID_IS_CAPTURE (1L << 10)
+#define ID_OFFSET	13	/* object ID is at the 13th bit in the
+				 * 1st command word.*/
+#define ID_CH_MASK    0x3F
+#define OPCODE_OFFSET	24	/* offset of the command opcode in the first
+				 * command word.*/
+
+enum cmd_mb_opcodes {
+	CMD_00_INFO_DEBUG	        = 0x00,
+	CMD_01_GET_SYS_CFG		= 0x01,
+	CMD_02_SET_GRANULARITY		= 0x02,
+	CMD_03_SET_TIMER_IRQ		= 0x03,
+	CMD_04_GET_EVENT		= 0x04,
+	CMD_05_GET_PIPES		= 0x05,
+
+	CMD_06_ALLOCATE_PIPE            = 0x06,
+	CMD_07_RELEASE_PIPE		= 0x07,
+	CMD_08_ASK_BUFFERS		= 0x08,
+	CMD_09_STOP_PIPE		= 0x09,
+	CMD_0A_GET_PIPE_SPL_COUNT	= 0x0a,
+	CMD_0B_TOGGLE_PIPE_STATE	= 0x0b,
+
+	CMD_0C_DEF_STREAM		= 0x0c,
+	CMD_0D_SET_MUTE			= 0x0d,
+	CMD_0E_GET_STREAM_SPL_COUNT     = 0x0e,
+	CMD_0F_UPDATE_BUFFER		= 0x0f,
+	CMD_10_GET_BUFFER		= 0x10,
+	CMD_11_CANCEL_BUFFER		= 0x11,
+	CMD_12_GET_PEAK			= 0x12,
+	CMD_13_SET_STREAM_STATE		= 0x13,
+	CMD_14_INVALID			= 0x14,
+};
+
+/* pipe states */
+enum pipe_state_t {
+	PSTATE_IDLE	= 0,	/* the pipe is not processed in the XES_IRQ
+				 * (free or stopped, or paused). */
+	PSTATE_RUN	= 1,	/* sustained play/record state. */
+	PSTATE_PURGE	= 2,	/* the ES channels are now off, render pipes do
+				 * not DMA, record pipe do a last DMA. */
+	PSTATE_ACQUIRE	= 3,	/* the ES channels are now on, render pipes do
+				 * not yet increase their sample count, record
+				 * pipes do not DMA. */
+	PSTATE_CLOSING	= 4,	/* the pipe is releasing, and may not yet
+				 * receive an "alloc" command. */
+};
+
+/* stream states */
+enum stream_state_t {
+	SSTATE_STOP	=  0x00,       /* setting to stop resets the stream spl
+					* count.*/
+	SSTATE_RUN	= (0x01 << 0), /* start DMA and spl count handling. */
+	SSTATE_PAUSE	= (0x01 << 1), /* pause DMA and spl count handling. */
+};
+
+/* buffer flags */
+enum buffer_flags {
+	BF_VALID	= 0x80,	/* set if the buffer is valid, clear if free.*/
+	BF_CURRENT	= 0x40,	/* set if this is the current buffer (there is
+				 * always a current buffer).*/
+	BF_NOTIFY_EOB	= 0x20,	/* set if this buffer must cause a PCI event
+				 * when finished.*/
+	BF_CIRCULAR	= 0x10,	/* set if buffer[1] must be copied to buffer[0]
+				 * by the end of this buffer.*/
+	BF_64BITS_ADR	= 0x08,	/* set if the hi part of the address is valid.*/
+	BF_xx		= 0x04,	/* future extension.*/
+	BF_EOB		= 0x02,	/* set if finished, but not yet free.*/
+	BF_PAUSE	= 0x01,	/* pause stream at buffer end.*/
+	BF_ZERO		= 0x00,	/* no flags (init).*/
+};
+
+/**
+*	Stream Flags definitions
+*/
+enum stream_flags {
+	SF_ZERO		= 0x00000000, /* no flags (stream invalid). */
+	SF_VALID	= 0x10000000, /* the stream has a valid DMA_conf
+				       * info (setstreamformat). */
+	SF_XRUN		= 0x20000000, /* the stream is un x-run state. */
+	SF_START	= 0x40000000, /* the DMA is running.*/
+	SF_ASIO		= 0x80000000, /* ASIO.*/
+};
+
+
+#define MASK_SPL_COUNT_HI 0x00FFFFFF /* 4 MSBits are status bits */
+#define PSTATE_OFFSET             28 /* 4 MSBits are status bits */
+
+
+#define MASK_STREAM_HAS_MAPPING	(1L << 12)
+#define MASK_STREAM_IS_ASIO	(1L <<  9)
+#define STREAM_FMT_OFFSET	10   /* the stream fmt bits start at the 10th
+				      * bit in the command word. */
+
+#define STREAM_FMT_16b          0x02
+#define STREAM_FMT_intel        0x01
+
+#define FREQ_FIELD_OFFSET	15  /* offset of the freq field in the response
+				     * word */
+
+#define BUFF_FLAGS_OFFSET	  24 /*  offset of the buffer flags in the
+				      *  response word. */
+#define MASK_DATA_SIZE	  0x00FFFFFF /* this must match the field size of
+				      * datasize in the buffer_t structure. */
+
+#define MASK_BUFFER_ID	        0xFF /* the cancel command awaits a buffer ID,
+				      * may be 0xFF for "current". */
+
+
+/* code adapted from PcxErr_e.h */
+
+/* Bits masks */
+
+#define ERROR_MASK              0x8000
+
+#define SOURCE_MASK             0x7800
+
+#define E_SOURCE_BOARD          0x4000 /* 8 >> 1 */
+#define E_SOURCE_DRV            0x2000 /* 4 >> 1 */
+#define E_SOURCE_API            0x1000 /* 2 >> 1 */
+/* Error tools */
+#define E_SOURCE_TOOLS          0x0800 /* 1 >> 1 */
+/* Error pcxaudio */
+#define E_SOURCE_AUDIO          0x1800 /* 3 >> 1 */
+/* Error virtual pcx */
+#define E_SOURCE_VPCX           0x2800 /* 5 >> 1 */
+/* Error dispatcher */
+#define E_SOURCE_DISPATCHER     0x3000 /* 6 >> 1 */
+/* Error from CobraNet firmware */
+#define E_SOURCE_COBRANET       0x3800 /* 7 >> 1 */
+
+#define E_SOURCE_USER           0x7800
+
+#define CLASS_MASK              0x0700
+
+#define CODE_MASK               0x00FF
+
+/* Bits values */
+
+/* Values for the error/warning bit */
+#define ERROR_VALUE             0x8000
+#define WARNING_VALUE           0x0000
+
+/* Class values */
+#define E_CLASS_GENERAL                  0x0000
+#define E_CLASS_INVALID_CMD              0x0100
+#define E_CLASS_INVALID_STD_OBJECT       0x0200
+#define E_CLASS_RSRC_IMPOSSIBLE          0x0300
+#define E_CLASS_WRONG_CONTEXT            0x0400
+#define E_CLASS_BAD_SPECIFIC_PARAMETER   0x0500
+#define E_CLASS_REAL_TIME_ERROR          0x0600
+#define E_CLASS_DIRECTSHOW               0x0700
+#define E_CLASS_FREE                     0x0700
+
+
+/* Complete DRV error code for the general class */
+#define ED_GN           (ERROR_VALUE | E_SOURCE_DRV | E_CLASS_GENERAL)
+#define ED_CONCURRENCY                  (ED_GN | 0x01)
+#define ED_DSP_CRASHED                  (ED_GN | 0x02)
+#define ED_UNKNOWN_BOARD                (ED_GN | 0x03)
+#define ED_NOT_INSTALLED                (ED_GN | 0x04)
+#define ED_CANNOT_OPEN_SVC_MANAGER      (ED_GN | 0x05)
+#define ED_CANNOT_READ_REGISTRY         (ED_GN | 0x06)
+#define ED_DSP_VERSION_MISMATCH         (ED_GN | 0x07)
+#define ED_UNAVAILABLE_FEATURE          (ED_GN | 0x08)
+#define ED_CANCELLED                    (ED_GN | 0x09)
+#define ED_NO_RESPONSE_AT_IRQA          (ED_GN | 0x10)
+#define ED_INVALID_ADDRESS              (ED_GN | 0x11)
+#define ED_DSP_CORRUPTED                (ED_GN | 0x12)
+#define ED_PENDING_OPERATION            (ED_GN | 0x13)
+#define ED_NET_ALLOCATE_MEMORY_IMPOSSIBLE   (ED_GN | 0x14)
+#define ED_NET_REGISTER_ERROR               (ED_GN | 0x15)
+#define ED_NET_THREAD_ERROR                 (ED_GN | 0x16)
+#define ED_NET_OPEN_ERROR                   (ED_GN | 0x17)
+#define ED_NET_CLOSE_ERROR                  (ED_GN | 0x18)
+#define ED_NET_NO_MORE_PACKET               (ED_GN | 0x19)
+#define ED_NET_NO_MORE_BUFFER               (ED_GN | 0x1A)
+#define ED_NET_SEND_ERROR                   (ED_GN | 0x1B)
+#define ED_NET_RECEIVE_ERROR                (ED_GN | 0x1C)
+#define ED_NET_WRONG_MSG_SIZE               (ED_GN | 0x1D)
+#define ED_NET_WAIT_ERROR                   (ED_GN | 0x1E)
+#define ED_NET_EEPROM_ERROR                 (ED_GN | 0x1F)
+#define ED_INVALID_RS232_COM_NUMBER         (ED_GN | 0x20)
+#define ED_INVALID_RS232_INIT               (ED_GN | 0x21)
+#define ED_FILE_ERROR                       (ED_GN | 0x22)
+#define ED_INVALID_GPIO_CMD                 (ED_GN | 0x23)
+#define ED_RS232_ALREADY_OPENED             (ED_GN | 0x24)
+#define ED_RS232_NOT_OPENED                 (ED_GN | 0x25)
+#define ED_GPIO_ALREADY_OPENED              (ED_GN | 0x26)
+#define ED_GPIO_NOT_OPENED                  (ED_GN | 0x27)
+#define ED_REGISTRY_ERROR                   (ED_GN | 0x28) /* <- NCX */
+#define ED_INVALID_SERVICE                  (ED_GN | 0x29) /* <- NCX */
+
+#define ED_READ_FILE_ALREADY_OPENED	    (ED_GN | 0x2a) /* <- Decalage
+							    * pour RCX
+							    * (old 0x28)
+							    * */
+#define ED_READ_FILE_INVALID_COMMAND	    (ED_GN | 0x2b) /* ~ */
+#define ED_READ_FILE_INVALID_PARAMETER	    (ED_GN | 0x2c) /* ~ */
+#define ED_READ_FILE_ALREADY_CLOSED	    (ED_GN | 0x2d) /* ~ */
+#define ED_READ_FILE_NO_INFORMATION	    (ED_GN | 0x2e) /* ~ */
+#define ED_READ_FILE_INVALID_HANDLE	    (ED_GN | 0x2f) /* ~ */
+#define ED_READ_FILE_END_OF_FILE	    (ED_GN | 0x30) /* ~ */
+#define ED_READ_FILE_ERROR	            (ED_GN | 0x31) /* ~ */
+
+#define ED_DSP_CRASHED_EXC_DSPSTACK_OVERFLOW (ED_GN | 0x32) /* <- Decalage pour
+							     * PCX (old 0x14) */
+#define ED_DSP_CRASHED_EXC_SYSSTACK_OVERFLOW (ED_GN | 0x33) /* ~ */
+#define ED_DSP_CRASHED_EXC_ILLEGAL           (ED_GN | 0x34) /* ~ */
+#define ED_DSP_CRASHED_EXC_TIMER_REENTRY     (ED_GN | 0x35) /* ~ */
+#define ED_DSP_CRASHED_EXC_FATAL_ERROR       (ED_GN | 0x36) /* ~ */
+
+#define ED_FLASH_PCCARD_NOT_PRESENT          (ED_GN | 0x37)
+
+#define ED_NO_CURRENT_CLOCK                  (ED_GN | 0x38)
+
+/* Complete DRV error code for real time class */
+#define ED_RT           (ERROR_VALUE | E_SOURCE_DRV | E_CLASS_REAL_TIME_ERROR)
+#define ED_DSP_TIMED_OUT                (ED_RT | 0x01)
+#define ED_DSP_CHK_TIMED_OUT            (ED_RT | 0x02)
+#define ED_STREAM_OVERRUN               (ED_RT | 0x03)
+#define ED_DSP_BUSY                     (ED_RT | 0x04)
+#define ED_DSP_SEMAPHORE_TIME_OUT       (ED_RT | 0x05)
+#define ED_BOARD_TIME_OUT               (ED_RT | 0x06)
+#define ED_XILINX_ERROR                 (ED_RT | 0x07)
+#define ED_COBRANET_ITF_NOT_RESPONDING  (ED_RT | 0x08)
+
+/* Complete BOARD error code for the invaid standard object class */
+#define EB_ISO          (ERROR_VALUE | E_SOURCE_BOARD | \
+			 E_CLASS_INVALID_STD_OBJECT)
+#define EB_INVALID_EFFECT               (EB_ISO | 0x00)
+#define EB_INVALID_PIPE                 (EB_ISO | 0x40)
+#define EB_INVALID_STREAM               (EB_ISO | 0x80)
+#define EB_INVALID_AUDIO                (EB_ISO | 0xC0)
+
+/* Complete BOARD error code for impossible resource allocation class */
+#define EB_RI           (ERROR_VALUE | E_SOURCE_BOARD | E_CLASS_RSRC_IMPOSSIBLE)
+#define EB_ALLOCATE_ALL_STREAM_TRANSFERT_BUFFERS_IMPOSSIBLE (EB_RI | 0x01)
+#define EB_ALLOCATE_PIPE_SAMPLE_BUFFER_IMPOSSIBLE           (EB_RI | 0x02)
+
+#define EB_ALLOCATE_MEM_STREAM_IMPOSSIBLE		\
+	EB_ALLOCATE_ALL_STREAM_TRANSFERT_BUFFERS_IMPOSSIBLE
+#define EB_ALLOCATE_MEM_PIPE_IMPOSSIBLE			\
+	EB_ALLOCATE_PIPE_SAMPLE_BUFFER_IMPOSSIBLE
+
+#define EB_ALLOCATE_DIFFERED_CMD_IMPOSSIBLE     (EB_RI | 0x03)
+#define EB_TOO_MANY_DIFFERED_CMD                (EB_RI | 0x04)
+#define EB_RBUFFERS_TABLE_OVERFLOW              (EB_RI | 0x05)
+#define EB_ALLOCATE_EFFECTS_IMPOSSIBLE          (EB_RI | 0x08)
+#define EB_ALLOCATE_EFFECT_POS_IMPOSSIBLE       (EB_RI | 0x09)
+#define EB_RBUFFER_NOT_AVAILABLE                (EB_RI | 0x0A)
+#define EB_ALLOCATE_CONTEXT_LIII_IMPOSSIBLE     (EB_RI | 0x0B)
+#define EB_STATUS_DIALOG_IMPOSSIBLE             (EB_RI | 0x1D)
+#define EB_CONTROL_CMD_IMPOSSIBLE               (EB_RI | 0x1E)
+#define EB_STATUS_SEND_IMPOSSIBLE               (EB_RI | 0x1F)
+#define EB_ALLOCATE_PIPE_IMPOSSIBLE             (EB_RI | 0x40)
+#define EB_ALLOCATE_STREAM_IMPOSSIBLE           (EB_RI | 0x80)
+#define EB_ALLOCATE_AUDIO_IMPOSSIBLE            (EB_RI | 0xC0)
+
+/* Complete BOARD error code for wrong call context class */
+#define EB_WCC          (ERROR_VALUE | E_SOURCE_BOARD | E_CLASS_WRONG_CONTEXT)
+#define EB_CMD_REFUSED                  (EB_WCC | 0x00)
+#define EB_START_STREAM_REFUSED         (EB_WCC | 0xFC)
+#define EB_SPC_REFUSED                  (EB_WCC | 0xFD)
+#define EB_CSN_REFUSED                  (EB_WCC | 0xFE)
+#define EB_CSE_REFUSED                  (EB_WCC | 0xFF)
+
+
+
+
+#endif /* LX_DEFS_H */
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index c262049..3b5ca70 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -487,10 +487,14 @@
 {
 	struct oxygen *chip = snd_pcm_substream_chip(substream);
 	unsigned int channel = oxygen_substream_channel(substream);
+	unsigned int channel_mask = 1 << channel;
 
 	spin_lock_irq(&chip->reg_lock);
-	chip->interrupt_mask &= ~(1 << channel);
+	chip->interrupt_mask &= ~channel_mask;
 	oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
+
+	oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
+	oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
 	spin_unlock_irq(&chip->reg_lock);
 
 	return snd_pcm_lib_free_pages(substream);
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index bc5ce11..bf971f7 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -113,8 +113,8 @@
  */
 
 /*
- * Xonar Essence STX
- * -----------------
+ * Xonar Essence ST (Deluxe)/STX
+ * -----------------------------
  *
  * CMI8788:
  *
@@ -180,6 +180,8 @@
 	MODEL_DX,
 	MODEL_HDAV,	/* without daughterboard */
 	MODEL_HDAV_H6,	/* with H6 daughterboard */
+	MODEL_ST,
+	MODEL_ST_H6,
 	MODEL_STX,
 };
 
@@ -188,8 +190,10 @@
 	{ OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX },
 	{ OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X },
 	{ OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV },
+	{ OXYGEN_PCI_SUBID(0x1043, 0x8327), .driver_data = MODEL_DX },
 	{ OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 },
 	{ OXYGEN_PCI_SUBID(0x1043, 0x835c), .driver_data = MODEL_STX },
+	{ OXYGEN_PCI_SUBID(0x1043, 0x835d), .driver_data = MODEL_ST },
 	{ OXYGEN_PCI_SUBID_BROKEN_EEPROM },
 	{ }
 };
@@ -210,9 +214,9 @@
 #define GPIO_DX_FRONT_PANEL	0x0002
 #define GPIO_DX_INPUT_ROUTE	0x0100
 
-#define GPIO_HDAV_DB_MASK	0x0030
-#define GPIO_HDAV_DB_H6		0x0000
-#define GPIO_HDAV_DB_XX		0x0020
+#define GPIO_DB_MASK		0x0030
+#define GPIO_DB_H6		0x0000
+#define GPIO_DB_XX		0x0020
 
 #define GPIO_ST_HP_REAR		0x0002
 #define GPIO_ST_HP		0x0080
@@ -530,7 +534,7 @@
 	snd_component_add(chip->card, "CS5381");
 }
 
-static void xonar_stx_init(struct oxygen *chip)
+static void xonar_st_init(struct oxygen *chip)
 {
 	struct xonar_data *data = chip->model_data;
 
@@ -539,12 +543,11 @@
 		       OXYGEN_2WIRE_INTERRUPT_MASK |
 		       OXYGEN_2WIRE_SPEED_FAST);
 
+	if (chip->model.private_data == MODEL_ST_H6)
+		chip->model.dac_channels = 8;
 	data->anti_pop_delay = 100;
-	data->dacs = 1;
+	data->dacs = chip->model.private_data == MODEL_ST_H6 ? 4 : 1;
 	data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
-	data->ext_power_reg = OXYGEN_GPI_DATA;
-	data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
-	data->ext_power_bit = GPI_DX_EXT_POWER;
 	data->pcm1796_oversampling = PCM1796_OS_64;
 
 	pcm1796_init(chip);
@@ -560,6 +563,17 @@
 	snd_component_add(chip->card, "CS5381");
 }
 
+static void xonar_stx_init(struct oxygen *chip)
+{
+	struct xonar_data *data = chip->model_data;
+
+	data->ext_power_reg = OXYGEN_GPI_DATA;
+	data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+	data->ext_power_bit = GPI_DX_EXT_POWER;
+
+	xonar_st_init(chip);
+}
+
 static void xonar_disable_output(struct oxygen *chip)
 {
 	struct xonar_data *data = chip->model_data;
@@ -1021,7 +1035,8 @@
 	.model_data_size = sizeof(struct xonar_data),
 	.device_config = PLAYBACK_0_TO_I2S |
 			 PLAYBACK_1_TO_SPDIF |
-			 CAPTURE_0_FROM_I2S_2,
+			 CAPTURE_0_FROM_I2S_2 |
+			 CAPTURE_1_FROM_SPDIF,
 	.dac_channels = 8,
 	.dac_volume_min = 255 - 2*60,
 	.dac_volume_max = 255,
@@ -1034,7 +1049,7 @@
 static const struct oxygen_model model_xonar_st = {
 	.longname = "Asus Virtuoso 100",
 	.chip = "AV200",
-	.init = xonar_stx_init,
+	.init = xonar_st_init,
 	.control_filter = xonar_st_control_filter,
 	.mixer_init = xonar_st_mixer_init,
 	.cleanup = xonar_st_cleanup,
@@ -1067,6 +1082,7 @@
 		[MODEL_D2]	= &model_xonar_d2,
 		[MODEL_D2X]	= &model_xonar_d2,
 		[MODEL_HDAV]	= &model_xonar_hdav,
+		[MODEL_ST]	= &model_xonar_st,
 		[MODEL_STX]	= &model_xonar_st,
 	};
 	static const char *const names[] = {
@@ -1076,6 +1092,8 @@
 		[MODEL_D2X]	= "Xonar D2X",
 		[MODEL_HDAV]	= "Xonar HDAV1.3",
 		[MODEL_HDAV_H6]	= "Xonar HDAV1.3+H6",
+		[MODEL_ST]	= "Xonar Essence ST",
+		[MODEL_ST_H6]	= "Xonar Essence ST+H6",
 		[MODEL_STX]	= "Xonar Essence STX",
 	};
 	unsigned int model = id->driver_data;
@@ -1092,21 +1110,27 @@
 		chip->model.init = xonar_dx_init;
 		break;
 	case MODEL_HDAV:
-		oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
-				    GPIO_HDAV_DB_MASK);
-		switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) &
-			GPIO_HDAV_DB_MASK) {
-		case GPIO_HDAV_DB_H6:
+		oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
+		switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
+		case GPIO_DB_H6:
 			model = MODEL_HDAV_H6;
 			break;
-		case GPIO_HDAV_DB_XX:
+		case GPIO_DB_XX:
 			snd_printk(KERN_ERR "unknown daughterboard\n");
 			return -ENODEV;
 		}
 		break;
+	case MODEL_ST:
+		oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
+		switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
+		case GPIO_DB_H6:
+			model = MODEL_ST_H6;
+			break;
+		}
+		break;
 	case MODEL_STX:
-		oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
-				    GPIO_HDAV_DB_MASK);
+		chip->model.init = xonar_stx_init;
+		oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
 		break;
 	}
 
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index e51a5ef..235a71e 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -507,41 +507,19 @@
  */
 
 static struct pci_device_id snd_riptide_ids[] = {
-	{
-	 .vendor = 0x127a,.device = 0x4310,
-	 .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-	 },
-	{
-	 .vendor = 0x127a,.device = 0x4320,
-	 .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-	 },
-	{
-	 .vendor = 0x127a,.device = 0x4330,
-	 .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-	 },
-	{
-	 .vendor = 0x127a,.device = 0x4340,
-	 .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-	 },
+	{ PCI_DEVICE(0x127a, 0x4310) },
+	{ PCI_DEVICE(0x127a, 0x4320) },
+	{ PCI_DEVICE(0x127a, 0x4330) },
+	{ PCI_DEVICE(0x127a, 0x4340) },
 	{0,},
 };
 
 #ifdef SUPPORT_JOYSTICK
 static struct pci_device_id snd_riptide_joystick_ids[] __devinitdata = {
-	{
-	 .vendor = 0x127a,.device = 0x4312,
-	 .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-	 },
-	{
-	 .vendor = 0x127a,.device = 0x4322,
-	 .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-	 },
-	{.vendor = 0x127a,.device = 0x4332,
-	 .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-	 },
-	{.vendor = 0x127a,.device = 0x4342,
-	 .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-	 },
+	{ PCI_DEVICE(0x127a, 0x4312) },
+	{ PCI_DEVICE(0x127a, 0x4322) },
+	{ PCI_DEVICE(0x127a, 0x4332) },
+	{ PCI_DEVICE(0x127a, 0x4342) },
 	{0,},
 };
 #endif
@@ -1209,12 +1187,79 @@
 }
 #endif
 
+static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip)
+{
+	union firmware_version firmware = { .ret = CMDRET_ZERO };
+	int i, timeout, err;
+
+	for (i = 0; i < 2; i++) {
+		WRITE_PORT_ULONG(cif->hwport->port[i].data1, 0);
+		WRITE_PORT_ULONG(cif->hwport->port[i].data2, 0);
+	}
+	SET_GRESET(cif->hwport);
+	udelay(100);
+	UNSET_GRESET(cif->hwport);
+	udelay(100);
+
+	for (timeout = 100000; --timeout; udelay(10)) {
+		if (IS_READY(cif->hwport) && !IS_GERR(cif->hwport))
+			break;
+	}
+	if (!timeout) {
+		snd_printk(KERN_ERR
+			   "Riptide: device not ready, audio status: 0x%x "
+			   "ready: %d gerr: %d\n",
+			   READ_AUDIO_STATUS(cif->hwport),
+			   IS_READY(cif->hwport), IS_GERR(cif->hwport));
+		return -EIO;
+	} else {
+		snd_printdd
+			("Riptide: audio status: 0x%x ready: %d gerr: %d\n",
+			 READ_AUDIO_STATUS(cif->hwport),
+			 IS_READY(cif->hwport), IS_GERR(cif->hwport));
+	}
+
+	SEND_GETV(cif, &firmware.ret);
+	snd_printdd("Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n",
+		    firmware.firmware.ASIC, firmware.firmware.CODEC,
+		    firmware.firmware.AUXDSP, firmware.firmware.PROG);
+
+	for (i = 0; i < FIRMWARE_VERSIONS; i++) {
+		if (!memcmp(&firmware_versions[i], &firmware, sizeof(firmware)))
+			break;
+	}
+	if (i >= FIRMWARE_VERSIONS)
+		return 0; /* no match */
+
+	if (!chip)
+		return 1; /* OK */
+
+	snd_printdd("Writing Firmware\n");
+	if (!chip->fw_entry) {
+		err = request_firmware(&chip->fw_entry, "riptide.hex",
+				       &chip->pci->dev);
+		if (err) {
+			snd_printk(KERN_ERR
+				   "Riptide: Firmware not available %d\n", err);
+			return -EIO;
+		}
+	}
+	err = loadfirmware(cif, chip->fw_entry->data, chip->fw_entry->size);
+	if (err) {
+		snd_printk(KERN_ERR
+			   "Riptide: Could not load firmware %d\n", err);
+		return err;
+	}
+
+	chip->firmware = firmware;
+
+	return 1; /* OK */
+}
+
 static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip)
 {
-	int timeout, tries;
 	union cmdret rptr = CMDRET_ZERO;
-	union firmware_version firmware;
-	int i, j, err, has_firmware;
+	int err, tries;
 
 	if (!cif)
 		return -EINVAL;
@@ -1227,75 +1272,11 @@
 	cif->is_reset = 0;
 
 	tries = RESET_TRIES;
-	has_firmware = 0;
-	while (has_firmware == 0 && tries-- > 0) {
-		for (i = 0; i < 2; i++) {
-			WRITE_PORT_ULONG(cif->hwport->port[i].data1, 0);
-			WRITE_PORT_ULONG(cif->hwport->port[i].data2, 0);
-		}
-		SET_GRESET(cif->hwport);
-		udelay(100);
-		UNSET_GRESET(cif->hwport);
-		udelay(100);
-
-		for (timeout = 100000; --timeout; udelay(10)) {
-			if (IS_READY(cif->hwport) && !IS_GERR(cif->hwport))
-				break;
-		}
-		if (timeout == 0) {
-			snd_printk(KERN_ERR
-				   "Riptide: device not ready, audio status: 0x%x ready: %d gerr: %d\n",
-				   READ_AUDIO_STATUS(cif->hwport),
-				   IS_READY(cif->hwport), IS_GERR(cif->hwport));
-			return -EIO;
-		} else {
-			snd_printdd
-			    ("Riptide: audio status: 0x%x ready: %d gerr: %d\n",
-			     READ_AUDIO_STATUS(cif->hwport),
-			     IS_READY(cif->hwport), IS_GERR(cif->hwport));
-		}
-
-		SEND_GETV(cif, &rptr);
-		for (i = 0; i < 4; i++)
-			firmware.ret.retwords[i] = rptr.retwords[i];
-
-		snd_printdd
-		    ("Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n",
-		     firmware.firmware.ASIC, firmware.firmware.CODEC,
-		     firmware.firmware.AUXDSP, firmware.firmware.PROG);
-
-		for (j = 0; j < FIRMWARE_VERSIONS; j++) {
-			has_firmware = 1;
-			for (i = 0; i < 4; i++) {
-				if (firmware_versions[j].ret.retwords[i] !=
-				    firmware.ret.retwords[i])
-					has_firmware = 0;
-			}
-			if (has_firmware)
-				break;
-		}
-
-		if (chip != NULL && has_firmware == 0) {
-			snd_printdd("Writing Firmware\n");
-			if (!chip->fw_entry) {
-				if ((err =
-				     request_firmware(&chip->fw_entry,
-						      "riptide.hex",
-						      &chip->pci->dev)) != 0) {
-					snd_printk(KERN_ERR
-						   "Riptide: Firmware not available %d\n",
-						   err);
-					return -EIO;
-				}
-			}
-			err = loadfirmware(cif, chip->fw_entry->data,
-					   chip->fw_entry->size);
-			if (err)
-				snd_printk(KERN_ERR
-					   "Riptide: Could not load firmware %d\n",
-					   err);
-		}
-	}
+	do {
+		err = try_to_load_firmware(cif, chip);
+		if (err < 0)
+			return err;
+	} while (!err && --tries);
 
 	SEND_SACR(cif, 0, AC97_RESET);
 	SEND_RACR(cif, AC97_RESET, &rptr);
@@ -1337,11 +1318,6 @@
 	SET_AIE(cif->hwport);
 	SET_AIACK(cif->hwport);
 	cif->is_reset = 1;
-	if (chip) {
-		for (i = 0; i < 4; i++)
-			chip->firmware.ret.retwords[i] =
-			    firmware.ret.retwords[i];
-	}
 
 	return 0;
 }
@@ -2038,14 +2014,12 @@
 }
 
 #ifdef SUPPORT_JOYSTICK
-static int have_joystick;
-static struct pci_dev *riptide_gameport_pci;
-static struct gameport *riptide_gameport;
 
 static int __devinit
 snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id)
 {
 	static int dev;
+	struct gameport *gameport;
 
 	if (dev >= SNDRV_CARDS)
 		return -ENODEV;
@@ -2054,36 +2028,33 @@
 		return -ENOENT;
 	}
 
-	if (joystick_port[dev]) {
-		riptide_gameport = gameport_allocate_port();
-		if (riptide_gameport) {
-			if (!request_region
-			    (joystick_port[dev], 8, "Riptide gameport")) {
-				snd_printk(KERN_WARNING
-					   "Riptide: cannot grab gameport 0x%x\n",
-					   joystick_port[dev]);
-				gameport_free_port(riptide_gameport);
-				riptide_gameport = NULL;
-			} else {
-				riptide_gameport_pci = pci;
-				riptide_gameport->io = joystick_port[dev];
-				gameport_register_port(riptide_gameport);
-			}
-		}
+	if (!joystick_port[dev++])
+		return 0;
+
+	gameport = gameport_allocate_port();
+	if (!gameport)
+		return -ENOMEM;
+	if (!request_region(joystick_port[dev], 8, "Riptide gameport")) {
+		snd_printk(KERN_WARNING
+			   "Riptide: cannot grab gameport 0x%x\n",
+			   joystick_port[dev]);
+		gameport_free_port(gameport);
+		return -EBUSY;
 	}
-	dev++;
+
+	gameport->io = joystick_port[dev];
+	gameport_register_port(gameport);
+	pci_set_drvdata(pci, gameport);
 	return 0;
 }
 
 static void __devexit snd_riptide_joystick_remove(struct pci_dev *pci)
 {
-	if (riptide_gameport) {
-		if (riptide_gameport_pci == pci) {
-			release_region(riptide_gameport->io, 8);
-			riptide_gameport_pci = NULL;
-			gameport_unregister_port(riptide_gameport);
-			riptide_gameport = NULL;
-		}
+	struct gameport *gameport = pci_get_drvdata(pci);
+	if (gameport) {
+		release_region(gameport->io, 8);
+		gameport_unregister_port(gameport);
+		pci_set_drvdata(pci, NULL);
 	}
 }
 #endif
@@ -2094,8 +2065,8 @@
 	static int dev;
 	struct snd_card *card;
 	struct snd_riptide *chip;
-	unsigned short addr;
-	int err = 0;
+	unsigned short val;
+	int err;
 
 	if (dev >= SNDRV_CARDS)
 		return -ENODEV;
@@ -2107,60 +2078,63 @@
 	err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
 	if (err < 0)
 		return err;
-	if ((err = snd_riptide_create(card, pci, &chip)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	err = snd_riptide_create(card, pci, &chip);
+	if (err < 0)
+		goto error;
 	card->private_data = chip;
-	if ((err = snd_riptide_pcm(chip, 0, NULL)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	if ((err = snd_riptide_mixer(chip)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	pci_write_config_word(chip->pci, PCI_EXT_Legacy_Mask, LEGACY_ENABLE_ALL
-			      | (opl3_port[dev] ? LEGACY_ENABLE_FM : 0)
+	err = snd_riptide_pcm(chip, 0, NULL);
+	if (err < 0)
+		goto error;
+	err = snd_riptide_mixer(chip);
+	if (err < 0)
+		goto error;
+
+	val = LEGACY_ENABLE_ALL;
+	if (opl3_port[dev])
+		val |= LEGACY_ENABLE_FM;
 #ifdef SUPPORT_JOYSTICK
-			      | (joystick_port[dev] ? LEGACY_ENABLE_GAMEPORT :
-				 0)
+	if (joystick_port[dev])
+		val |= LEGACY_ENABLE_GAMEPORT;
 #endif
-			      | (mpu_port[dev]
-				 ? (LEGACY_ENABLE_MPU_INT | LEGACY_ENABLE_MPU) :
-				 0)
-			      | ((chip->irq << 4) & 0xF0));
-	if ((addr = mpu_port[dev]) != 0) {
-		pci_write_config_word(chip->pci, PCI_EXT_MPU_Base, addr);
-		if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_RIPTIDE,
-					       addr, 0, chip->irq, 0,
-					       &chip->rmidi)) < 0)
+	if (mpu_port[dev])
+		val |= LEGACY_ENABLE_MPU_INT | LEGACY_ENABLE_MPU;
+	val |= (chip->irq << 4) & 0xf0;
+	pci_write_config_word(chip->pci, PCI_EXT_Legacy_Mask, val);
+	if (mpu_port[dev]) {
+		val = mpu_port[dev];
+		pci_write_config_word(chip->pci, PCI_EXT_MPU_Base, val);
+		err = snd_mpu401_uart_new(card, 0, MPU401_HW_RIPTIDE,
+					  val, 0, chip->irq, 0,
+					  &chip->rmidi);
+		if (err < 0)
 			snd_printk(KERN_WARNING
 				   "Riptide: Can't Allocate MPU at 0x%x\n",
-				   addr);
+				   val);
 		else
-			chip->mpuaddr = addr;
+			chip->mpuaddr = val;
 	}
-	if ((addr = opl3_port[dev]) != 0) {
-		pci_write_config_word(chip->pci, PCI_EXT_FM_Base, addr);
-		if ((err = snd_opl3_create(card, addr, addr + 2,
-					   OPL3_HW_RIPTIDE, 0,
-					   &chip->opl3)) < 0)
+	if (opl3_port[dev]) {
+		val = opl3_port[dev];
+		pci_write_config_word(chip->pci, PCI_EXT_FM_Base, val);
+		err = snd_opl3_create(card, val, val + 2,
+				      OPL3_HW_RIPTIDE, 0, &chip->opl3);
+		if (err < 0)
 			snd_printk(KERN_WARNING
 				   "Riptide: Can't Allocate OPL3 at 0x%x\n",
-				   addr);
+				   val);
 		else {
-			chip->opladdr = addr;
-			if ((err =
-			     snd_opl3_hwdep_new(chip->opl3, 0, 1, NULL)) < 0)
+			chip->opladdr = val;
+			err = snd_opl3_hwdep_new(chip->opl3, 0, 1, NULL);
+			if (err < 0)
 				snd_printk(KERN_WARNING
 					   "Riptide: Can't Allocate OPL3-HWDEP\n");
 		}
 	}
 #ifdef SUPPORT_JOYSTICK
-	if ((addr = joystick_port[dev]) != 0) {
-		pci_write_config_word(chip->pci, PCI_EXT_Game_Base, addr);
-		chip->gameaddr = addr;
+	if (joystick_port[dev]) {
+		val = joystick_port[dev];
+		pci_write_config_word(chip->pci, PCI_EXT_Game_Base, val);
+		chip->gameaddr = val;
 	}
 #endif
 
@@ -2178,13 +2152,16 @@
 		 chip->opladdr);
 #endif
 	snd_riptide_proc_init(chip);
-	if ((err = snd_card_register(card)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	err = snd_card_register(card);
+	if (err < 0)
+		goto error;
 	pci_set_drvdata(pci, card);
 	dev++;
 	return 0;
+
+ error:
+	snd_card_free(card);
+	return err;
 }
 
 static void __devexit snd_card_riptide_remove(struct pci_dev *pci)
@@ -2216,14 +2193,11 @@
 static int __init alsa_card_riptide_init(void)
 {
 	int err;
-	if ((err = pci_register_driver(&driver)) < 0)
+	err = pci_register_driver(&driver);
+	if (err < 0)
 		return err;
 #if defined(SUPPORT_JOYSTICK)
-	if (pci_register_driver(&joystick_driver) < 0) {
-		have_joystick = 0;
-		snd_printk(KERN_INFO "no joystick found\n");
-	} else
-		have_joystick = 1;
+	pci_register_driver(&joystick_driver);
 #endif
 	return 0;
 }
@@ -2232,8 +2206,7 @@
 {
 	pci_unregister_driver(&driver);
 #if defined(SUPPORT_JOYSTICK)
-	if (have_joystick)
-		pci_unregister_driver(&joystick_driver);
+	pci_unregister_driver(&joystick_driver);
 #endif
 }
 
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 314e735..3da5c02 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -28,6 +28,7 @@
 #include <linux/pci.h>
 #include <linux/firmware.h>
 #include <linux/moduleparam.h>
+#include <linux/math64.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -402,9 +403,9 @@
 #define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES)
 #define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024)
 
-/* use hotplug firmeare loader? */
+/* use hotplug firmware loader? */
 #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
-#if !defined(HDSP_USE_HWDEP_LOADER) && !defined(CONFIG_SND_HDSP)
+#if !defined(HDSP_USE_HWDEP_LOADER)
 #define HDSP_FW_LOADER
 #endif
 #endif
@@ -1047,7 +1048,6 @@
 static void hdsp_set_dds_value(struct hdsp *hdsp, int rate)
 {
 	u64 n;
-	u32 r;
 
 	if (rate >= 112000)
 		rate /= 4;
@@ -1055,7 +1055,7 @@
 		rate /= 2;
 
 	n = DDS_NUMERATOR;
-	div64_32(&n, rate, &r);
+	n = div_u64(n, rate);
 	/* n should be less than 2^32 for being written to FREQ register */
 	snd_BUG_ON(n >> 32);
 	/* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS
@@ -3097,7 +3097,6 @@
 static int hdsp_dds_offset(struct hdsp *hdsp)
 {
 	u64 n;
-	u32 r;
 	unsigned int dds_value = hdsp->dds_value;
 	int system_sample_rate = hdsp->system_sample_rate;
 
@@ -3109,7 +3108,7 @@
 	 * dds_value = n / rate
 	 * rate = n / dds_value
 	 */
-	div64_32(&n, dds_value, &r);
+	n = div_u64(n, dds_value);
 	if (system_sample_rate >= 112000)
 		n *= 4;
 	else if (system_sample_rate >= 56000)
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index bac2dc0..0dce331 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -29,6 +29,7 @@
 #include <linux/moduleparam.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/math64.h>
 #include <asm/io.h>
 
 #include <sound/core.h>
@@ -831,7 +832,6 @@
 static void hdspm_set_dds_value(struct hdspm *hdspm, int rate)
 {
 	u64 n;
-	u32 r;
 	
 	if (rate >= 112000)
 		rate /= 4;
@@ -844,7 +844,7 @@
         */	   
 	/* n = 104857600000000ULL; */ /*  =  2^20 * 10^8 */
 	n = 110100480000000ULL;    /* Value checked for AES32 and MADI */
-	div64_32(&n, rate, &r);
+	n = div_u64(n, rate);
 	/* n should be less than 2^32 for being written to FREQ register */
 	snd_BUG_ON(n >> 32);
 	hdspm_write(hdspm, HDSPM_freqReg, (u32)n);
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c
index 80df9b1..2cc0eda 100644
--- a/sound/ppc/awacs.c
+++ b/sound/ppc/awacs.c
@@ -477,7 +477,7 @@
 #define AMP_CH_SPK	0
 #define AMP_CH_HD	1
 
-static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __devinitdata = {
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	  .name = "PC Speaker Playback Volume",
 	  .info = snd_pmac_awacs_info_volume_amp,
@@ -514,7 +514,7 @@
 	},
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Headphone Playback Switch",
 	.info = snd_pmac_boolean_stereo_info,
@@ -523,7 +523,7 @@
 	.private_value = AMP_CH_HD,
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "PC Speaker Playback Switch",
 	.info = snd_pmac_boolean_stereo_info,
@@ -595,46 +595,46 @@
 /*
  * lists of mixer elements
  */
-static struct snd_kcontrol_new snd_pmac_awacs_mixers[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mixers[] __devinitdata = {
 	AWACS_SWITCH("Master Capture Switch", 1, SHIFT_LOOPTHRU, 0),
 	AWACS_VOLUME("Master Capture Volume", 0, 4, 0),
 /*	AWACS_SWITCH("Unknown Playback Switch", 6, SHIFT_PAROUT0, 0), */
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] __devinitdata = {
 	AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
 	AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1),
 	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
 	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_LINE, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mixers_lo[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_lo[] __devinitdata = {
 	AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] __devinitdata = {
 	AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1),
 	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mixers_g4agp[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_g4agp[] __devinitdata = {
 	AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
 	AWACS_VOLUME("Master Playback Volume", 5, 6, 1),
 	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
 	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] __devinitdata = {
 	AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
 	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
 	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac5500[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac5500[] __devinitdata = {
 	AWACS_VOLUME("Headphone Playback Volume", 2, 6, 1),
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __devinitdata = {
 	AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
 	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
 };
@@ -642,34 +642,34 @@
 /* FIXME: is this correct order?
  * screamer (powerbook G3 pismo) seems to have different bits...
  */
-static struct snd_kcontrol_new snd_pmac_awacs_mixers2[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mixers2[] __devinitdata = {
 	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_LINE, 0),
 	AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_MIC, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] __devinitdata = {
 	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
 	AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_LINE, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_mixers2_pmac5500[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mixers2_pmac5500[] __devinitdata = {
 	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_master_sw __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_master_sw __devinitdata =
 AWACS_SWITCH("Master Playback Switch", 1, SHIFT_HDMUTE, 1);
 
-static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac __devinitdata =
 AWACS_SWITCH("Line out Playback Switch", 1, SHIFT_HDMUTE, 1);
 
-static struct snd_kcontrol_new snd_pmac_awacs_master_sw_pmac5500 __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_master_sw_pmac5500 __devinitdata =
 AWACS_SWITCH("Headphone Playback Switch", 1, SHIFT_HDMUTE, 1);
 
-static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __devinitdata = {
 	AWACS_SWITCH("Mic Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __devinitdata = {
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	  .name = "Mic Boost Capture Volume",
 	  .info = snd_pmac_screamer_mic_boost_info,
@@ -678,34 +678,34 @@
 	},
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] __devinitdata =
 {
 	AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] __initdata =
+static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] __devinitdata =
 {
 	AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
 	AWACS_SWITCH("CD Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __initdata =
+static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __devinitdata =
 {
 	AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
 	AWACS_SWITCH("Mic Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __devinitdata = {
 	AWACS_VOLUME("PC Speaker Playback Volume", 4, 6, 1),
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __devinitdata =
 AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1);
 
-static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 __devinitdata =
 AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 1);
 
-static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 __devinitdata =
 AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 0);
 
 
@@ -872,7 +872,7 @@
 /*
  * initialize chip
  */
-int __init
+int __devinit
 snd_pmac_awacs_init(struct snd_pmac *chip)
 {
 	int pm7500 = IS_PM7500;
diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c
index 89f5c32..a9d3507 100644
--- a/sound/ppc/beep.c
+++ b/sound/ppc/beep.c
@@ -215,7 +215,7 @@
 };
 
 /* Initialize beep stuff */
-int __init snd_pmac_attach_beep(struct snd_pmac *chip)
+int __devinit snd_pmac_attach_beep(struct snd_pmac *chip)
 {
 	struct pmac_beep *beep;
 	struct input_dev *input_dev;
diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c
index 45a7629..16ed240 100644
--- a/sound/ppc/burgundy.c
+++ b/sound/ppc/burgundy.c
@@ -46,12 +46,12 @@
 	timeout = 50;
 	while (!(in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
 		udelay(1);
-	if (! timeout)
+	if (timeout < 0)
 		printk(KERN_DEBUG "burgundy_extend_wait: timeout #1\n");
 	timeout = 50;
 	while ((in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
 		udelay(1);
-	if (! timeout)
+	if (timeout < 0)
 		printk(KERN_DEBUG "burgundy_extend_wait: timeout #2\n");
 }
 
@@ -468,7 +468,7 @@
 /*
  * Burgundy mixers
  */
-static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __devinitdata = {
 	BURGUNDY_VOLUME_W("Master Playback Volume", 0,
 			MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8),
 	BURGUNDY_VOLUME_W("CD Capture Volume", 0,
@@ -496,7 +496,7 @@
  */	BURGUNDY_SWITCH_B("PCM Capture Switch", 0,
 			MASK_ADDR_BURGUNDY_HOSTIFEH, 0x01, 0, 0)
 };
-static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __devinitdata = {
 	BURGUNDY_VOLUME_W("Line in Capture Volume", 0,
 			MASK_ADDR_BURGUNDY_VOLLINE, 16),
 	BURGUNDY_VOLUME_W("Mic Capture Volume", 0,
@@ -522,7 +522,7 @@
 	BURGUNDY_SWITCH_B("Mic Boost Capture Switch", 0,
 			MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1)
 };
-static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __devinitdata = {
 	BURGUNDY_VOLUME_W("Line in Capture Volume", 0,
 			MASK_ADDR_BURGUNDY_VOLMIC, 16),
 	BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0,
@@ -538,33 +538,33 @@
 /*	BURGUNDY_SWITCH_B("Line in Boost Capture Switch", 0,
  *		MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) */
 };
-static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __initdata =
+static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __devinitdata =
 BURGUNDY_SWITCH_B("Master Playback Switch", 0,
 	MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 	BURGUNDY_OUTPUT_LEFT | BURGUNDY_LINEOUT_LEFT | BURGUNDY_HP_LEFT,
 	BURGUNDY_OUTPUT_RIGHT | BURGUNDY_LINEOUT_RIGHT | BURGUNDY_HP_RIGHT, 1);
-static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __initdata =
+static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __devinitdata =
 BURGUNDY_SWITCH_B("Master Playback Switch", 0,
 	MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 	BURGUNDY_OUTPUT_INTERN
 	| BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
-static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __initdata =
+static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __devinitdata =
 BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0,
 	MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 	BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
-static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __initdata =
+static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __devinitdata =
 BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0,
 	MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 	BURGUNDY_OUTPUT_INTERN, 0, 0);
-static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __initdata =
+static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __devinitdata =
 BURGUNDY_SWITCH_B("Line out Playback Switch", 0,
 	MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 	BURGUNDY_LINEOUT_LEFT, BURGUNDY_LINEOUT_RIGHT, 1);
-static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __initdata =
+static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __devinitdata =
 BURGUNDY_SWITCH_B("Line out Playback Switch", 0,
 	MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 	BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
-static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __initdata =
+static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __devinitdata =
 BURGUNDY_SWITCH_B("Headphone Playback Switch", 0,
 	MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 	BURGUNDY_HP_LEFT, BURGUNDY_HP_RIGHT, 1);
@@ -618,7 +618,7 @@
 /*
  * initialize burgundy
  */
-int __init snd_pmac_burgundy_init(struct snd_pmac *chip)
+int __devinit snd_pmac_burgundy_init(struct snd_pmac *chip)
 {
 	int imac = machine_is_compatible("iMac");
 	int i, err;
diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c
index f8d478c..24200b7 100644
--- a/sound/ppc/daca.c
+++ b/sound/ppc/daca.c
@@ -244,7 +244,7 @@
 }
 
 /* exported */
-int __init snd_pmac_daca_init(struct snd_pmac *chip)
+int __devinit snd_pmac_daca_init(struct snd_pmac *chip)
 {
 	int i, err;
 	struct pmac_daca *mix;
diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c
index a5afb26..835fa19 100644
--- a/sound/ppc/keywest.c
+++ b/sound/ppc/keywest.c
@@ -33,10 +33,6 @@
 static struct pmac_keywest *keywest_ctx;
 
 
-#ifndef i2c_device_name
-#define i2c_device_name(x)	((x)->name)
-#endif
-
 static int keywest_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
@@ -56,7 +52,7 @@
 	if (! keywest_ctx)
 		return -EINVAL;
 
-	if (strncmp(i2c_device_name(adapter), "mac-io", 6))
+	if (strncmp(adapter->name, "mac-io", 6))
 		return 0; /* ignored */
 
 	memset(&info, 0, sizeof(struct i2c_board_info));
@@ -109,7 +105,7 @@
 	}
 }
 
-int __init snd_pmac_tumbler_post_init(void)
+int __devinit snd_pmac_tumbler_post_init(void)
 {
 	int err;
 	
@@ -124,7 +120,7 @@
 }
 
 /* exported */
-int __init snd_pmac_keywest_init(struct pmac_keywest *i2c)
+int __devinit snd_pmac_keywest_init(struct pmac_keywest *i2c)
 {
 	int err;
 
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index 9b4e9c3..7bc492e 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -702,7 +702,7 @@
 	.pointer =	snd_pmac_capture_pointer,
 };
 
-int __init snd_pmac_pcm_new(struct snd_pmac *chip)
+int __devinit snd_pmac_pcm_new(struct snd_pmac *chip)
 {
 	struct snd_pcm *pcm;
 	int err;
@@ -908,7 +908,7 @@
  * check the machine support byteswap (little-endian)
  */
 
-static void __init detect_byte_swap(struct snd_pmac *chip)
+static void __devinit detect_byte_swap(struct snd_pmac *chip)
 {
 	struct device_node *mio;
 
@@ -934,7 +934,7 @@
 /*
  * detect a sound chip
  */
-static int __init snd_pmac_detect(struct snd_pmac *chip)
+static int __devinit snd_pmac_detect(struct snd_pmac *chip)
 {
 	struct device_node *sound;
 	struct device_node *dn;
@@ -1143,7 +1143,7 @@
 	return 0;
 }
 
-static struct snd_kcontrol_new auto_mute_controls[] __initdata = {
+static struct snd_kcontrol_new auto_mute_controls[] __devinitdata = {
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	  .name = "Auto Mute Switch",
 	  .info = snd_pmac_boolean_mono_info,
@@ -1158,7 +1158,7 @@
 	},
 };
 
-int __init snd_pmac_add_automute(struct snd_pmac *chip)
+int __devinit snd_pmac_add_automute(struct snd_pmac *chip)
 {
 	int err;
 	chip->auto_mute = 1;
@@ -1175,7 +1175,7 @@
 /*
  * create and detect a pmac chip record
  */
-int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
+int __devinit snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
 {
 	struct snd_pmac *chip;
 	struct device_node *np;
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
index f361c26..53c81a5 100644
--- a/sound/ppc/snd_ps3.c
+++ b/sound/ppc/snd_ps3.c
@@ -18,80 +18,30 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
 #include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/io.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <sound/asound.h>
+#include <sound/control.h>
 #include <sound/core.h>
 #include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/asound.h>
 #include <sound/memalloc.h>
+#include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/control.h>
-#include <linux/dmapool.h>
-#include <linux/dma-mapping.h>
-#include <asm/firmware.h>
+
 #include <asm/dma.h>
+#include <asm/firmware.h>
 #include <asm/lv1call.h>
 #include <asm/ps3.h>
 #include <asm/ps3av.h>
 
-#include "snd_ps3_reg.h"
 #include "snd_ps3.h"
+#include "snd_ps3_reg.h"
 
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PS3 sound driver");
-MODULE_AUTHOR("Sony Computer Entertainment Inc.");
-
-/* module  entries */
-static int __init snd_ps3_init(void);
-static void __exit snd_ps3_exit(void);
-
-/* ALSA snd driver ops */
-static int snd_ps3_pcm_open(struct snd_pcm_substream *substream);
-static int snd_ps3_pcm_close(struct snd_pcm_substream *substream);
-static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream);
-static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
-				 int cmd);
-static snd_pcm_uframes_t snd_ps3_pcm_pointer(struct snd_pcm_substream
-					     *substream);
-static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
-				 struct snd_pcm_hw_params *hw_params);
-static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream);
-
-
-/* ps3_system_bus_driver entries */
-static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev);
-static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev);
-
-/* address setup */
-static int snd_ps3_map_mmio(void);
-static void snd_ps3_unmap_mmio(void);
-static int snd_ps3_allocate_irq(void);
-static void snd_ps3_free_irq(void);
-static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start);
-
-/* interrupt handler */
-static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id);
-
-
-/* set sampling rate/format */
-static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream);
-/* take effect parameter change */
-static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card);
-/* initialize avsetting and take it effect */
-static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card);
-/* setup dma */
-static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
-			       enum snd_ps3_dma_filltype filltype);
-static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card);
-
-static dma_addr_t v_to_bus(struct snd_ps3_card_info *, void  *vaddr, int ch);
-
-
-module_init(snd_ps3_init);
-module_exit(snd_ps3_exit);
 
 /*
  * global
@@ -165,25 +115,13 @@
 	.fifo_size = PS3_AUDIO_FIFO_SIZE
 };
 
-static struct snd_pcm_ops snd_ps3_pcm_spdif_ops =
-{
-	.open = snd_ps3_pcm_open,
-	.close = snd_ps3_pcm_close,
-	.prepare = snd_ps3_pcm_prepare,
-	.ioctl = snd_pcm_lib_ioctl,
-	.trigger = snd_ps3_pcm_trigger,
-	.pointer = snd_ps3_pcm_pointer,
-	.hw_params = snd_ps3_pcm_hw_params,
-	.hw_free = snd_ps3_pcm_hw_free
-};
-
 static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info *card,
 				   int count, int force_stop)
 {
 	int dma_ch, done, retries, stop_forced = 0;
 	uint32_t status;
 
-	for (dma_ch = 0; dma_ch < 8; dma_ch ++) {
+	for (dma_ch = 0; dma_ch < 8; dma_ch++) {
 		retries = count;
 		do {
 			status = read_reg(PS3_AUDIO_KICK(dma_ch)) &
@@ -259,9 +197,7 @@
 /*
  * convert virtual addr to ioif bus addr.
  */
-static dma_addr_t v_to_bus(struct snd_ps3_card_info *card,
-			   void * paddr,
-			   int ch)
+static dma_addr_t v_to_bus(struct snd_ps3_card_info *card, void *paddr, int ch)
 {
 	return card->dma_start_bus_addr[ch] +
 		(paddr - card->dma_start_vaddr[ch]);
@@ -321,7 +257,7 @@
 	spin_lock_irqsave(&card->dma_lock, irqsave);
 	for (ch = 0; ch < 2; ch++) {
 		start_vaddr = card->dma_next_transfer_vaddr[0];
-		for (stage = 0; stage < fill_stages; stage ++) {
+		for (stage = 0; stage < fill_stages; stage++) {
 			dma_ch = stage * 2 + ch;
 			if (silent)
 				dma_addr = card->null_buffer_start_dma_addr;
@@ -372,6 +308,71 @@
 }
 
 /*
+ * Interrupt handler
+ */
+static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id)
+{
+
+	uint32_t port_intr;
+	int underflow_occured = 0;
+	struct snd_ps3_card_info *card = dev_id;
+
+	if (!card->running) {
+		update_reg(PS3_AUDIO_AX_IS, 0);
+		update_reg(PS3_AUDIO_INTR_0, 0);
+		return IRQ_HANDLED;
+	}
+
+	port_intr = read_reg(PS3_AUDIO_AX_IS);
+	/*
+	 *serial buffer empty detected (every 4 times),
+	 *program next dma and kick it
+	 */
+	if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) {
+		write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0));
+		if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
+			write_reg(PS3_AUDIO_AX_IS, port_intr);
+			underflow_occured = 1;
+		}
+		if (card->silent) {
+			/* we are still in silent time */
+			snd_ps3_program_dma(card,
+				(underflow_occured) ?
+				SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL :
+				SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
+			snd_ps3_kick_dma(card);
+			card->silent--;
+		} else {
+			snd_ps3_program_dma(card,
+				(underflow_occured) ?
+				SND_PS3_DMA_FILLTYPE_FIRSTFILL :
+				SND_PS3_DMA_FILLTYPE_RUNNING);
+			snd_ps3_kick_dma(card);
+			snd_pcm_period_elapsed(card->substream);
+		}
+	} else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
+		write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0));
+		/*
+		 * serial out underflow, but buffer empty not detected.
+		 * in this case, fill fifo with 0 to recover.  After
+		 * filling dummy data, serial automatically start to
+		 * consume them and then will generate normal buffer
+		 * empty interrupts.
+		 * If both buffer underflow and buffer empty are occured,
+		 * it is better to do nomal data transfer than empty one
+		 */
+		snd_ps3_program_dma(card,
+				    SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+		snd_ps3_kick_dma(card);
+		snd_ps3_program_dma(card,
+				    SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+		snd_ps3_kick_dma(card);
+	}
+	/* clear interrupt cause */
+	return IRQ_HANDLED;
+};
+
+/*
  * audio mute on/off
  * mute_on : 0 output enabled
  *           1 mute
@@ -382,6 +383,142 @@
 }
 
 /*
+ * av setting
+ * NOTE: calling this function may generate audio interrupt.
+ */
+static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card)
+{
+	int ret, retries, i;
+	pr_debug("%s: start\n", __func__);
+
+	ret = ps3av_set_audio_mode(card->avs.avs_audio_ch,
+				  card->avs.avs_audio_rate,
+				  card->avs.avs_audio_width,
+				  card->avs.avs_audio_format,
+				  card->avs.avs_audio_source);
+	/*
+	 * Reset the following unwanted settings:
+	 */
+
+	/* disable all 3wire buffers */
+	update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
+			~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) |
+			  PS3_AUDIO_AO_3WMCTRL_ASOEN(1) |
+			  PS3_AUDIO_AO_3WMCTRL_ASOEN(2) |
+			  PS3_AUDIO_AO_3WMCTRL_ASOEN(3)),
+			0);
+	wmb();	/* ensure the hardware sees the change */
+	/* wait for actually stopped */
+	retries = 1000;
+	while ((read_reg(PS3_AUDIO_AO_3WMCTRL) &
+		(PS3_AUDIO_AO_3WMCTRL_ASORUN(0) |
+		 PS3_AUDIO_AO_3WMCTRL_ASORUN(1) |
+		 PS3_AUDIO_AO_3WMCTRL_ASORUN(2) |
+		 PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) &&
+	       --retries) {
+		udelay(1);
+	}
+
+	/* reset buffer pointer */
+	for (i = 0; i < 4; i++) {
+		update_reg(PS3_AUDIO_AO_3WCTRL(i),
+			   PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET);
+		udelay(10);
+	}
+	wmb(); /* ensure the hardware actually start resetting */
+
+	/* enable 3wire#0 buffer */
+	update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0));
+
+
+	/* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */
+	update_mask_reg(PS3_AUDIO_AO_3WCTRL(0),
+			~PS3_AUDIO_AO_3WCTRL_ASODF,
+			PS3_AUDIO_AO_3WCTRL_ASODF_LSB);
+	update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0),
+			~PS3_AUDIO_AO_SPDCTRL_SPODF,
+			PS3_AUDIO_AO_SPDCTRL_SPODF_LSB);
+	/* ensure all the setting above is written back to register */
+	wmb();
+	/* avsetting driver altered AX_IE, caller must reset it if you want */
+	pr_debug("%s: end\n", __func__);
+	return ret;
+}
+
+/*
+ *  set sampling rate according to the substream
+ */
+static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream)
+{
+	struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+	struct snd_ps3_avsetting_info avs;
+	int ret;
+
+	avs = card->avs;
+
+	pr_debug("%s: called freq=%d width=%d\n", __func__,
+		 substream->runtime->rate,
+		 snd_pcm_format_width(substream->runtime->format));
+
+	pr_debug("%s: before freq=%d width=%d\n", __func__,
+		 card->avs.avs_audio_rate, card->avs.avs_audio_width);
+
+	/* sample rate */
+	switch (substream->runtime->rate) {
+	case 44100:
+		avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K;
+		break;
+	case 48000:
+		avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
+		break;
+	case 88200:
+		avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K;
+		break;
+	case 96000:
+		avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K;
+		break;
+	default:
+		pr_info("%s: invalid rate %d\n", __func__,
+			substream->runtime->rate);
+		return 1;
+	}
+
+	/* width */
+	switch (snd_pcm_format_width(substream->runtime->format)) {
+	case 16:
+		avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
+		break;
+	case 24:
+		avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24;
+		break;
+	default:
+		pr_info("%s: invalid width %d\n", __func__,
+			snd_pcm_format_width(substream->runtime->format));
+		return 1;
+	}
+
+	memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8);
+
+	if (memcmp(&card->avs, &avs, sizeof(avs))) {
+		pr_debug("%s: after freq=%d width=%d\n", __func__,
+			 card->avs.avs_audio_rate, card->avs.avs_audio_width);
+
+		card->avs = avs;
+		snd_ps3_change_avsetting(card);
+		ret = 0;
+	} else
+		ret = 1;
+
+	/* check CS non-audio bit and mute accordingly */
+	if (avs.avs_cs_info[0] & 0x02)
+		ps3av_audio_mute_analog(1); /* mute if non-audio */
+	else
+		ps3av_audio_mute_analog(0);
+
+	return ret;
+}
+
+/*
  * PCM operators
  */
 static int snd_ps3_pcm_open(struct snd_pcm_substream *substream)
@@ -406,6 +543,13 @@
 	return 0;
 };
 
+static int snd_ps3_pcm_close(struct snd_pcm_substream *substream)
+{
+	/* mute on */
+	snd_ps3_mute(1);
+	return 0;
+};
+
 static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *hw_params)
 {
@@ -417,6 +561,13 @@
 	return 0;
 };
 
+static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	int ret;
+	ret = snd_pcm_lib_free_pages(substream);
+	return ret;
+};
+
 static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream,
 				  unsigned int delay_ms)
 {
@@ -556,202 +707,6 @@
 	return ret;
 };
 
-static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	int ret;
-	ret = snd_pcm_lib_free_pages(substream);
-	return ret;
-};
-
-static int snd_ps3_pcm_close(struct snd_pcm_substream *substream)
-{
-	/* mute on */
-	snd_ps3_mute(1);
-	return 0;
-};
-
-static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card)
-{
-	/*
-	 * avsetting driver seems to never change the followings
-	 * so, init them here once
-	 */
-
-	/* no dma interrupt needed */
-	write_reg(PS3_AUDIO_INTR_EN_0, 0);
-
-	/* use every 4 buffer empty interrupt */
-	update_mask_reg(PS3_AUDIO_AX_IC,
-			PS3_AUDIO_AX_IC_AASOIMD_MASK,
-			PS3_AUDIO_AX_IC_AASOIMD_EVERY4);
-
-	/* enable 3wire clocks */
-	update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
-			~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED |
-			  PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED),
-			0);
-	update_reg(PS3_AUDIO_AO_3WMCTRL,
-		   PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT);
-}
-
-/*
- * av setting
- * NOTE: calling this function may generate audio interrupt.
- */
-static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card)
-{
-	int ret, retries, i;
-	pr_debug("%s: start\n", __func__);
-
-	ret = ps3av_set_audio_mode(card->avs.avs_audio_ch,
-				  card->avs.avs_audio_rate,
-				  card->avs.avs_audio_width,
-				  card->avs.avs_audio_format,
-				  card->avs.avs_audio_source);
-	/*
-	 * Reset the following unwanted settings:
-	 */
-
-	/* disable all 3wire buffers */
-	update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
-			~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) |
-			  PS3_AUDIO_AO_3WMCTRL_ASOEN(1) |
-			  PS3_AUDIO_AO_3WMCTRL_ASOEN(2) |
-			  PS3_AUDIO_AO_3WMCTRL_ASOEN(3)),
-			0);
-	wmb(); 	/* ensure the hardware sees the change */
-	/* wait for actually stopped */
-	retries = 1000;
-	while ((read_reg(PS3_AUDIO_AO_3WMCTRL) &
-		(PS3_AUDIO_AO_3WMCTRL_ASORUN(0) |
-		 PS3_AUDIO_AO_3WMCTRL_ASORUN(1) |
-		 PS3_AUDIO_AO_3WMCTRL_ASORUN(2) |
-		 PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) &&
-	       --retries) {
-		udelay(1);
-	}
-
-	/* reset buffer pointer */
-	for (i = 0; i < 4; i++) {
-		update_reg(PS3_AUDIO_AO_3WCTRL(i),
-			   PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET);
-		udelay(10);
-	}
-	wmb(); /* ensure the hardware actually start resetting */
-
-	/* enable 3wire#0 buffer */
-	update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0));
-
-
-	/* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */
-	update_mask_reg(PS3_AUDIO_AO_3WCTRL(0),
-			~PS3_AUDIO_AO_3WCTRL_ASODF,
-			PS3_AUDIO_AO_3WCTRL_ASODF_LSB);
-	update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0),
-			~PS3_AUDIO_AO_SPDCTRL_SPODF,
-			PS3_AUDIO_AO_SPDCTRL_SPODF_LSB);
-	/* ensure all the setting above is written back to register */
-	wmb();
-	/* avsetting driver altered AX_IE, caller must reset it if you want */
-	pr_debug("%s: end\n", __func__);
-	return ret;
-}
-
-static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card)
-{
-	int ret;
-	pr_debug("%s: start\n", __func__);
-	card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2;
-	card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
-	card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
-	card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM;
-	card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
-	memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8);
-
-	ret = snd_ps3_change_avsetting(card);
-
-	snd_ps3_audio_fixup(card);
-
-	/* to start to generate SPDIF signal, fill data */
-	snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
-	snd_ps3_kick_dma(card);
-	pr_debug("%s: end\n", __func__);
-	return ret;
-}
-
-/*
- *  set sampling rate according to the substream
- */
-static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream)
-{
-	struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
-	struct snd_ps3_avsetting_info avs;
-	int ret;
-
-	avs = card->avs;
-
-	pr_debug("%s: called freq=%d width=%d\n", __func__,
-		 substream->runtime->rate,
-		 snd_pcm_format_width(substream->runtime->format));
-
-	pr_debug("%s: before freq=%d width=%d\n", __func__,
-		 card->avs.avs_audio_rate, card->avs.avs_audio_width);
-
-	/* sample rate */
-	switch (substream->runtime->rate) {
-	case 44100:
-		avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K;
-		break;
-	case 48000:
-		avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
-		break;
-	case 88200:
-		avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K;
-		break;
-	case 96000:
-		avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K;
-		break;
-	default:
-		pr_info("%s: invalid rate %d\n", __func__,
-			substream->runtime->rate);
-		return 1;
-	}
-
-	/* width */
-	switch (snd_pcm_format_width(substream->runtime->format)) {
-	case 16:
-		avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
-		break;
-	case 24:
-		avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24;
-		break;
-	default:
-		pr_info("%s: invalid width %d\n", __func__,
-			snd_pcm_format_width(substream->runtime->format));
-		return 1;
-	}
-
-	memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8);
-
-	if (memcmp(&card->avs, &avs, sizeof(avs))) {
-		pr_debug("%s: after freq=%d width=%d\n", __func__,
-			 card->avs.avs_audio_rate, card->avs.avs_audio_width);
-
-		card->avs = avs;
-		snd_ps3_change_avsetting(card);
-		ret = 0;
-	} else
-		ret = 1;
-
-	/* check CS non-audio bit and mute accordingly */
-	if (avs.avs_cs_info[0] & 0x02)
-		ps3av_audio_mute_analog(1); /* mute if non-audio */
-	else
-		ps3av_audio_mute_analog(0);
-
-	return ret;
-}
-
 /*
  * SPDIF status bits controls
  */
@@ -798,28 +753,39 @@
 	{
 		.access = SNDRV_CTL_ELEM_ACCESS_READ,
 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
-		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
 		.info = snd_ps3_spdif_mask_info,
 		.get = snd_ps3_spdif_cmask_get,
 	},
 	{
 		.access = SNDRV_CTL_ELEM_ACCESS_READ,
 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
-		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
+		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
 		.info = snd_ps3_spdif_mask_info,
 		.get = snd_ps3_spdif_pmask_get,
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
-		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
 		.info = snd_ps3_spdif_mask_info,
 		.get = snd_ps3_spdif_default_get,
 		.put = snd_ps3_spdif_default_put,
 	},
 };
 
+static struct snd_pcm_ops snd_ps3_pcm_spdif_ops = {
+	.open = snd_ps3_pcm_open,
+	.close = snd_ps3_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_ps3_pcm_hw_params,
+	.hw_free = snd_ps3_pcm_hw_free,
+	.prepare = snd_ps3_pcm_prepare,
+	.trigger = snd_ps3_pcm_trigger,
+	.pointer = snd_ps3_pcm_pointer,
+};
 
-static int snd_ps3_map_mmio(void)
+
+static int __devinit snd_ps3_map_mmio(void)
 {
 	the_card.mapped_mmio_vaddr =
 		ioremap(the_card.ps3_dev->m_region->bus_addr,
@@ -841,7 +807,7 @@
 	the_card.mapped_mmio_vaddr = NULL;
 }
 
-static int snd_ps3_allocate_irq(void)
+static int __devinit snd_ps3_allocate_irq(void)
 {
 	int ret;
 	u64 lpar_addr, lpar_size;
@@ -899,7 +865,7 @@
 	ps3_irq_plug_destroy(the_card.irq_no);
 }
 
-static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start)
+static void __devinit snd_ps3_audio_set_base_addr(uint64_t ioaddr_start)
 {
 	uint64_t val;
 	int ret;
@@ -915,7 +881,53 @@
 			ret);
 }
 
-static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
+static void __devinit snd_ps3_audio_fixup(struct snd_ps3_card_info *card)
+{
+	/*
+	 * avsetting driver seems to never change the followings
+	 * so, init them here once
+	 */
+
+	/* no dma interrupt needed */
+	write_reg(PS3_AUDIO_INTR_EN_0, 0);
+
+	/* use every 4 buffer empty interrupt */
+	update_mask_reg(PS3_AUDIO_AX_IC,
+			PS3_AUDIO_AX_IC_AASOIMD_MASK,
+			PS3_AUDIO_AX_IC_AASOIMD_EVERY4);
+
+	/* enable 3wire clocks */
+	update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
+			~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED |
+			  PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED),
+			0);
+	update_reg(PS3_AUDIO_AO_3WMCTRL,
+		   PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT);
+}
+
+static int __devinit snd_ps3_init_avsetting(struct snd_ps3_card_info *card)
+{
+	int ret;
+	pr_debug("%s: start\n", __func__);
+	card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2;
+	card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
+	card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
+	card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM;
+	card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
+	memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8);
+
+	ret = snd_ps3_change_avsetting(card);
+
+	snd_ps3_audio_fixup(card);
+
+	/* to start to generate SPDIF signal, fill data */
+	snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+	snd_ps3_kick_dma(card);
+	pr_debug("%s: end\n", __func__);
+	return ret;
+}
+
+static int __devinit snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
 {
 	int i, ret;
 	u64 lpar_addr, lpar_size;
@@ -1020,11 +1032,12 @@
 	 * its size should be lager than PS3_AUDIO_FIFO_STAGE_SIZE * 2
 	 * PAGE_SIZE is enogh
 	 */
-	if (!(the_card.null_buffer_start_vaddr =
-	      dma_alloc_coherent(&the_card.ps3_dev->core,
-				 PAGE_SIZE,
-				 &the_card.null_buffer_start_dma_addr,
-				 GFP_KERNEL))) {
+	the_card.null_buffer_start_vaddr =
+		dma_alloc_coherent(&the_card.ps3_dev->core,
+				   PAGE_SIZE,
+				   &the_card.null_buffer_start_dma_addr,
+				   GFP_KERNEL);
+	if (!the_card.null_buffer_start_vaddr) {
 		pr_info("%s: nullbuffer alloc failed\n", __func__);
 		goto clean_preallocate;
 	}
@@ -1115,71 +1128,6 @@
 
 
 /*
- * Interrupt handler
- */
-static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id)
-{
-
-	uint32_t port_intr;
-	int underflow_occured = 0;
-	struct snd_ps3_card_info *card = dev_id;
-
-	if (!card->running) {
-		update_reg(PS3_AUDIO_AX_IS, 0);
-		update_reg(PS3_AUDIO_INTR_0, 0);
-		return IRQ_HANDLED;
-	}
-
-	port_intr = read_reg(PS3_AUDIO_AX_IS);
-	/*
-	 *serial buffer empty detected (every 4 times),
-	 *program next dma and kick it
-	 */
-	if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) {
-		write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0));
-		if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
-			write_reg(PS3_AUDIO_AX_IS, port_intr);
-			underflow_occured = 1;
-		}
-		if (card->silent) {
-			/* we are still in silent time */
-			snd_ps3_program_dma(card,
-				(underflow_occured) ?
-				SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL :
-				SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
-			snd_ps3_kick_dma(card);
-			card->silent --;
-		} else {
-			snd_ps3_program_dma(card,
-				(underflow_occured) ?
-				SND_PS3_DMA_FILLTYPE_FIRSTFILL :
-				SND_PS3_DMA_FILLTYPE_RUNNING);
-			snd_ps3_kick_dma(card);
-			snd_pcm_period_elapsed(card->substream);
-		}
-	} else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
-		write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0));
-		/*
-		 * serial out underflow, but buffer empty not detected.
-		 * in this case, fill fifo with 0 to recover.  After
-		 * filling dummy data, serial automatically start to
-		 * consume them and then will generate normal buffer
-		 * empty interrupts.
-		 * If both buffer underflow and buffer empty are occured,
-		 * it is better to do nomal data transfer than empty one
-		 */
-		snd_ps3_program_dma(card,
-				    SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
-		snd_ps3_kick_dma(card);
-		snd_ps3_program_dma(card,
-				    SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
-		snd_ps3_kick_dma(card);
-	}
-	/* clear interrupt cause */
-	return IRQ_HANDLED;
-};
-
-/*
  * module/subsystem initialize/terminate
  */
 static int __init snd_ps3_init(void)
@@ -1197,10 +1145,15 @@
 
 	return ret;
 }
+module_init(snd_ps3_init);
 
 static void __exit snd_ps3_exit(void)
 {
 	ps3_system_bus_driver_unregister(&snd_ps3_bus_driver_info);
 }
+module_exit(snd_ps3_exit);
 
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PS3 sound driver");
+MODULE_AUTHOR("Sony Computer Entertainment Inc.");
 MODULE_ALIAS(PS3_MODULE_ALIAS_SOUND);
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 40222fc..08e584d 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -838,7 +838,7 @@
 
 /*
  */
-static struct snd_kcontrol_new tumbler_mixers[] __initdata = {
+static struct snd_kcontrol_new tumbler_mixers[] __devinitdata = {
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	  .name = "Master Playback Volume",
 	  .info = tumbler_info_master_volume,
@@ -862,7 +862,7 @@
 	},
 };
 
-static struct snd_kcontrol_new snapper_mixers[] __initdata = {
+static struct snd_kcontrol_new snapper_mixers[] __devinitdata = {
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	  .name = "Master Playback Volume",
 	  .info = tumbler_info_master_volume,
@@ -895,7 +895,7 @@
 	},
 };
 
-static struct snd_kcontrol_new tumbler_hp_sw __initdata = {
+static struct snd_kcontrol_new tumbler_hp_sw __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Headphone Playback Switch",
 	.info = snd_pmac_boolean_mono_info,
@@ -903,7 +903,7 @@
 	.put = tumbler_put_mute_switch,
 	.private_value = TUMBLER_MUTE_HP,
 };
-static struct snd_kcontrol_new tumbler_speaker_sw __initdata = {
+static struct snd_kcontrol_new tumbler_speaker_sw __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "PC Speaker Playback Switch",
 	.info = snd_pmac_boolean_mono_info,
@@ -911,7 +911,7 @@
 	.put = tumbler_put_mute_switch,
 	.private_value = TUMBLER_MUTE_AMP,
 };
-static struct snd_kcontrol_new tumbler_lineout_sw __initdata = {
+static struct snd_kcontrol_new tumbler_lineout_sw __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Line Out Playback Switch",
 	.info = snd_pmac_boolean_mono_info,
@@ -919,7 +919,7 @@
 	.put = tumbler_put_mute_switch,
 	.private_value = TUMBLER_MUTE_LINE,
 };
-static struct snd_kcontrol_new tumbler_drc_sw __initdata = {
+static struct snd_kcontrol_new tumbler_drc_sw __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "DRC Switch",
 	.info = snd_pmac_boolean_mono_info,
@@ -1269,7 +1269,7 @@
 #endif
 
 /* initialize tumbler */
-static int __init tumbler_init(struct snd_pmac *chip)
+static int __devinit tumbler_init(struct snd_pmac *chip)
 {
 	int irq;
 	struct pmac_tumbler *mix = chip->mixer_data;
@@ -1339,7 +1339,7 @@
 }
 
 /* exported */
-int __init snd_pmac_tumbler_init(struct snd_pmac *chip)
+int __devinit snd_pmac_tumbler_init(struct snd_pmac *chip)
 {
 	int i, err;
 	struct pmac_tumbler *mix;
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 3d2bb6f..d3e786a 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -32,7 +32,9 @@
 source "sound/soc/omap/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
+source "sound/soc/s6000/Kconfig"
 source "sound/soc/sh/Kconfig"
+source "sound/soc/txx9/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 0237879..6f1e28d 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -10,4 +10,6 @@
 obj-$(CONFIG_SND_SOC)	+= omap/
 obj-$(CONFIG_SND_SOC)	+= pxa/
 obj-$(CONFIG_SND_SOC)	+= s3c24xx/
+obj-$(CONFIG_SND_SOC)	+= s6000/
 obj-$(CONFIG_SND_SOC)	+= sh/
+obj-$(CONFIG_SND_SOC)	+= txx9/
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index a608d70..e720d5e 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -41,3 +41,11 @@
           and FRAME signals on the PlayPaq.  Unless you want to play
           with the AT32 as the SSC master, you probably want to say N here,
           as this will give you better sound quality.
+
+config SND_AT91_SOC_AFEB9260
+	tristate "SoC Audio support for AFEB9260 board"
+	depends on ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
+	select SND_ATMEL_SOC_SSC
+	select SND_SOC_TLV320AIC23
+	help
+	  Say Y here to support sound on AFEB9260 board.
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
index f54a7cc..e7ea56b 100644
--- a/sound/soc/atmel/Makefile
+++ b/sound/soc/atmel/Makefile
@@ -13,3 +13,4 @@
 
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
 obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o
+obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o
diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c
index 7065753..9eb610c 100644
--- a/sound/soc/atmel/playpaq_wm8510.c
+++ b/sound/soc/atmel/playpaq_wm8510.c
@@ -117,7 +117,7 @@
 	 * Find actual rate, compare to requested rate
 	 */
 	actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1));
-	pr_debug("playpaq_wm8510: Request rate = %d, actual rate = %d\n",
+	pr_debug("playpaq_wm8510: Request rate = %u, actual rate = %u\n",
 		 rate, actual_rate);
 
 
diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c
new file mode 100644
index 0000000..23349de
--- /dev/null
+++ b/sound/soc/atmel/snd-soc-afeb9260.c
@@ -0,0 +1,203 @@
+/*
+ * afeb9260.c  --  SoC audio for AFEB9260
+ *
+ * Copyright (C) 2009 Sergey Lapin <slapin@ossfans.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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <linux/atmel-ssc.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <linux/gpio.h>
+
+#include "../codecs/tlv320aic23.h"
+#include "atmel-pcm.h"
+#include "atmel_ssc_dai.h"
+
+#define CODEC_CLOCK 	12000000
+
+static int afeb9260_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->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->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);
+
+	if (err < 0) {
+		printk(KERN_ERR "can't set codec system clock\n");
+		return err;
+	}
+
+	return err;
+}
+
+static struct snd_soc_ops afeb9260_ops = {
+	.hw_params = afeb9260_hw_params,
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_LINE("Line In", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	{"Headphone Jack", NULL, "LHPOUT"},
+	{"Headphone Jack", NULL, "RHPOUT"},
+
+	{"LLINEIN", NULL, "Line In"},
+	{"RLINEIN", NULL, "Line In"},
+
+	{"MICIN", NULL, "Mic Jack"},
+};
+
+static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
+{
+
+	/* Add afeb9260 specific widgets */
+	snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+				  ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+	/* Set up afeb9260 specific audio path audio_map */
+	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+	snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+	snd_soc_dapm_enable_pin(codec, "Line In");
+	snd_soc_dapm_enable_pin(codec, "Mic Jack");
+
+	snd_soc_dapm_sync(codec);
+
+	return 0;
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link afeb9260_dai = {
+	.name = "TLV320AIC23",
+	.stream_name = "AIC23",
+	.cpu_dai = &atmel_ssc_dai[0],
+	.codec_dai = &tlv320aic23_dai,
+	.init = afeb9260_tlv320aic23_init,
+	.ops = &afeb9260_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_machine_afeb9260 = {
+	.name = "AFEB9260",
+	.platform = &atmel_soc_platform,
+	.dai_link = &afeb9260_dai,
+	.num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device afeb9260_snd_devdata = {
+	.card = &snd_soc_machine_afeb9260,
+	.codec_dev = &soc_codec_dev_tlv320aic23,
+};
+
+static struct platform_device *afeb9260_snd_device;
+
+static int __init afeb9260_soc_init(void)
+{
+	int err;
+	struct device *dev;
+	struct atmel_ssc_info *ssc_p = afeb9260_dai.cpu_dai->private_data;
+	struct ssc_device *ssc = NULL;
+
+	if (!(machine_is_afeb9260()))
+		return -ENODEV;
+
+	ssc = ssc_request(0);
+	if (IS_ERR(ssc)) {
+		printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
+		err = PTR_ERR(ssc);
+		ssc = NULL;
+		goto err_ssc;
+	}
+	ssc_p->ssc = ssc;
+
+	afeb9260_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!afeb9260_snd_device) {
+		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(afeb9260_snd_device, &afeb9260_snd_devdata);
+	afeb9260_snd_devdata.dev = &afeb9260_snd_device->dev;
+	err = platform_device_add(afeb9260_snd_device);
+	if (err)
+		goto err1;
+
+	dev = &afeb9260_snd_device->dev;
+
+	return 0;
+err1:
+	platform_device_del(afeb9260_snd_device);
+	platform_device_put(afeb9260_snd_device);
+err_ssc:
+	return err;
+
+}
+
+static void __exit afeb9260_soc_exit(void)
+{
+	platform_device_unregister(afeb9260_snd_device);
+}
+
+module_init(afeb9260_soc_init);
+module_exit(afeb9260_soc_exit);
+
+MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>");
+MODULE_DESCRIPTION("ALSA SoC for AFEB9260");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index 8a935f2..b1ed423 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -31,6 +31,15 @@
 #include "bf5xx-sport.h"
 #include "bf5xx-ac97.h"
 
+/* Anomaly notes:
+ *  05000250 -	AD1980 is running in TDM mode and RFS/TFS are generated by SPORT
+ *		contrtoller. But, RFSDIV and TFSDIV are always set to 16*16-1,
+ *		while the max AC97 data size is 13*16. The DIV is always larger
+ *		than data size. AD73311 and ad2602 are not running in TDM mode.
+ *		AD1836 and AD73322 depend on external RFS/TFS only. So, this
+ *		anomaly does not affect blackfin sound drivers.
+*/
+
 static int *cmd_count;
 static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
 
diff --git a/sound/soc/blackfin/bf5xx-sport.c b/sound/soc/blackfin/bf5xx-sport.c
index b7953c8..469ce7f 100644
--- a/sound/soc/blackfin/bf5xx-sport.c
+++ b/sound/soc/blackfin/bf5xx-sport.c
@@ -190,7 +190,7 @@
 	desc = get_dma_next_desc_ptr(sport->dma_rx_chan);
 	/* Copy the descriptor which will be damaged to backup */
 	temp_desc = *desc;
-	desc->x_count = 0xa;
+	desc->x_count = sport->dummy_count / 2;
 	desc->y_count = 0;
 	desc->next_desc_addr = sport->dummy_rx_desc;
 	local_irq_restore(flags);
@@ -309,7 +309,7 @@
 	desc = get_dma_next_desc_ptr(sport->dma_tx_chan);
 	/* Store the descriptor which will be damaged */
 	temp_desc = *desc;
-	desc->x_count = 0xa;
+	desc->x_count = sport->dummy_count / 2;
 	desc->y_count = 0;
 	desc->next_desc_addr = sport->dummy_tx_desc;
 	local_irq_restore(flags);
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index b6c7f7a..bbc97fd 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -18,7 +18,9 @@
 	select SND_SOC_AK4535 if I2C
 	select SND_SOC_CS4270 if I2C
 	select SND_SOC_PCM3008
+	select SND_SOC_SPDIF
 	select SND_SOC_SSM2602 if I2C
+	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_TLV320AIC23 if I2C
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
 	select SND_SOC_TLV320AIC3X if I2C
@@ -35,8 +37,12 @@
 	select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8900 if I2C
 	select SND_SOC_WM8903 if I2C
+	select SND_SOC_WM8940 if I2C
+	select SND_SOC_WM8960 if I2C
 	select SND_SOC_WM8971 if I2C
+	select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8990 if I2C
+	select SND_SOC_WM9081 if I2C
 	select SND_SOC_WM9705 if SND_SOC_AC97_BUS
 	select SND_SOC_WM9712 if SND_SOC_AC97_BUS
 	select SND_SOC_WM9713 if SND_SOC_AC97_BUS
@@ -86,9 +92,15 @@
 config SND_SOC_PCM3008
        tristate
 
+config SND_SOC_SPDIF
+	tristate
+
 config SND_SOC_SSM2602
 	tristate
 
+config SND_SOC_STAC9766
+	tristate
+
 config SND_SOC_TLV320AIC23
 	tristate
 
@@ -138,12 +150,24 @@
 config SND_SOC_WM8903
 	tristate
 
+config SND_SOC_WM8940
+        tristate
+
+config SND_SOC_WM8960
+	tristate
+
 config SND_SOC_WM8971
 	tristate
 
+config SND_SOC_WM8988
+	tristate
+
 config SND_SOC_WM8990
 	tristate
 
+config SND_SOC_WM9081
+	tristate
+
 config SND_SOC_WM9705
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f265380..8b75305 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -6,7 +6,9 @@
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-l3-objs := l3.o
 snd-soc-pcm3008-objs := pcm3008.o
+snd-soc-spdif-objs := spdif_transciever.o
 snd-soc-ssm2602-objs := ssm2602.o
+snd-soc-stac9766-objs := stac9766.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
@@ -23,8 +25,12 @@
 snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
+snd-soc-wm8940-objs := wm8940.o
+snd-soc-wm8960-objs := wm8960.o
 snd-soc-wm8971-objs := wm8971.o
+snd-soc-wm8988-objs := wm8988.o
 snd-soc-wm8990-objs := wm8990.o
+snd-soc-wm9081-objs := wm9081.o
 snd-soc-wm9705-objs := wm9705.o
 snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
@@ -37,7 +43,9 @@
 obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
+obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif.o
 obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
+obj-$(CONFIG_SND_SOC_STAC9766)	+= snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)	+= snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
@@ -55,7 +63,11 @@
 obj-$(CONFIG_SND_SOC_WM8900)	+= snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)	+= snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8971)	+= snd-soc-wm8971.o
+obj-$(CONFIG_SND_SOC_WM8940)	+= snd-soc-wm8940.o
+obj-$(CONFIG_SND_SOC_WM8960)	+= snd-soc-wm8960.o
+obj-$(CONFIG_SND_SOC_WM8988)	+= snd-soc-wm8988.o
 obj-$(CONFIG_SND_SOC_WM8990)	+= snd-soc-wm8990.o
+obj-$(CONFIG_SND_SOC_WM9081)	+= snd-soc-wm9081.o
 obj-$(CONFIG_SND_SOC_WM9705)	+= snd-soc-wm9705.o
 obj-$(CONFIG_SND_SOC_WM9712)	+= snd-soc-wm9712.o
 obj-$(CONFIG_SND_SOC_WM9713)	+= snd-soc-wm9713.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index b0d4af1..932299b 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -53,13 +53,13 @@
 		.channels_min = 1,
 		.channels_max = 2,
 		.rates = STD_AC97_RATES,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+		.formats = SND_SOC_STD_AC97_FMTS,},
 	.capture = {
 		.stream_name = "AC97 Capture",
 		.channels_min = 1,
 		.channels_max = 2,
 		.rates = STD_AC97_RATES,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+		.formats = SND_SOC_STD_AC97_FMTS,},
 	.ops = &ac97_dai_ops,
 };
 EXPORT_SYMBOL_GPL(ac97_dai);
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index ddb3b08..d7440a9 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -137,13 +137,13 @@
 		.channels_min = 2,
 		.channels_max = 6,
 		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+		.formats = SND_SOC_STD_AC97_FMTS, },
 	.capture = {
 		.stream_name = "Capture",
 		.channels_min = 2,
 		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+		.formats = SND_SOC_STD_AC97_FMTS, },
 };
 EXPORT_SYMBOL_GPL(ad1980_dai);
 
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 7fa09a3..a32b822 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -18,7 +18,7 @@
  * - The machine driver's 'startup' function must call
  *   cs4270_set_dai_sysclk() with the value of MCLK.
  * - Only I2S and left-justified modes are supported
- * - Power management is not supported
+ * - Power management is supported
  */
 
 #include <linux/module.h>
@@ -27,6 +27,7 @@
 #include <sound/soc.h>
 #include <sound/initval.h>
 #include <linux/i2c.h>
+#include <linux/delay.h>
 
 #include "cs4270.h"
 
@@ -56,6 +57,7 @@
 #define CS4270_FIRSTREG	0x01
 #define CS4270_LASTREG	0x08
 #define CS4270_NUMREGS	(CS4270_LASTREG - CS4270_FIRSTREG + 1)
+#define CS4270_I2C_INCR	0x80
 
 /* Bit masks for the CS4270 registers */
 #define CS4270_CHIPID_ID	0xF0
@@ -64,6 +66,8 @@
 #define CS4270_PWRCTL_PDN_ADC	0x20
 #define CS4270_PWRCTL_PDN_DAC	0x02
 #define CS4270_PWRCTL_PDN	0x01
+#define CS4270_PWRCTL_PDN_ALL	\
+	(CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC | CS4270_PWRCTL_PDN)
 #define CS4270_MODE_SPEED_MASK	0x30
 #define CS4270_MODE_1X		0x00
 #define CS4270_MODE_2X		0x10
@@ -109,6 +113,7 @@
 	unsigned int mclk; /* Input frequency of the MCLK pin */
 	unsigned int mode; /* The mode (I2S or left-justified) */
 	unsigned int slave_mode;
+	unsigned int manual_mute;
 };
 
 /**
@@ -295,7 +300,7 @@
 	s32 length;
 
 	length = i2c_smbus_read_i2c_block_data(i2c_client,
-		CS4270_FIRSTREG | 0x80, CS4270_NUMREGS, cache);
+		CS4270_FIRSTREG | CS4270_I2C_INCR, CS4270_NUMREGS, cache);
 
 	if (length != CS4270_NUMREGS) {
 		dev_err(codec->dev, "i2c read failure, addr=0x%x\n",
@@ -453,7 +458,7 @@
 }
 
 /**
- * cs4270_mute - enable/disable the CS4270 external mute
+ * cs4270_dai_mute - enable/disable the CS4270 external mute
  * @dai: the SOC DAI
  * @mute: 0 = disable mute, 1 = enable mute
  *
@@ -462,21 +467,52 @@
  * board does not have the MUTEA or MUTEB pins connected to such circuitry,
  * then this function will do nothing.
  */
-static int cs4270_mute(struct snd_soc_dai *dai, int mute)
+static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute)
 {
 	struct snd_soc_codec *codec = dai->codec;
+	struct cs4270_private *cs4270 = codec->private_data;
 	int reg6;
 
 	reg6 = snd_soc_read(codec, CS4270_MUTE);
 
 	if (mute)
 		reg6 |= CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B;
-	else
+	else {
 		reg6 &= ~(CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B);
+		reg6 |= cs4270->manual_mute;
+	}
 
 	return snd_soc_write(codec, CS4270_MUTE, reg6);
 }
 
+/**
+ * cs4270_soc_put_mute - put callback for the 'Master Playback switch'
+ * 			 alsa control.
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * This function basically passes the arguments on to the generic
+ * snd_soc_put_volsw() function and saves the mute information in
+ * our private data structure. This is because we want to prevent
+ * cs4270_dai_mute() neglecting the user's decision to manually
+ * mute the codec's output.
+ *
+ * Returns 0 for success.
+ */
+static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cs4270_private *cs4270 = codec->private_data;
+	int left = !ucontrol->value.integer.value[0];
+	int right = !ucontrol->value.integer.value[1];
+
+	cs4270->manual_mute = (left ? CS4270_MUTE_DAC_A : 0) |
+			      (right ? CS4270_MUTE_DAC_B : 0);
+
+	return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
 /* A list of non-DAPM controls that the CS4270 supports */
 static const struct snd_kcontrol_new cs4270_snd_controls[] = {
 	SOC_DOUBLE_R("Master Playback Volume",
@@ -486,7 +522,9 @@
 	SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 1, 0),
 	SOC_SINGLE("Popguard Switch", CS4270_MODE, 0, 1, 1),
 	SOC_SINGLE("Auto-Mute Switch", CS4270_MUTE, 5, 1, 0),
-	SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 0)
+	SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 1),
+	SOC_DOUBLE_EXT("Master Playback Switch", CS4270_MUTE, 0, 1, 1, 1,
+		snd_soc_get_volsw, cs4270_soc_put_mute),
 };
 
 /*
@@ -506,7 +544,7 @@
 	.hw_params	= cs4270_hw_params,
 	.set_sysclk	= cs4270_set_dai_sysclk,
 	.set_fmt	= cs4270_set_dai_fmt,
-	.digital_mute	= cs4270_mute,
+	.digital_mute	= cs4270_dai_mute,
 };
 
 struct snd_soc_dai cs4270_dai = {
@@ -753,6 +791,57 @@
 };
 MODULE_DEVICE_TABLE(i2c, cs4270_id);
 
+#ifdef CONFIG_PM
+
+/* This suspend/resume implementation can handle both - a simple standby
+ * where the codec remains powered, and a full suspend, where the voltage
+ * domain the codec is connected to is teared down and/or any other hardware
+ * reset condition is asserted.
+ *
+ * The codec's own power saving features are enabled in the suspend callback,
+ * and all registers are written back to the hardware when resuming.
+ */
+
+static int cs4270_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct cs4270_private *cs4270 = i2c_get_clientdata(client);
+	struct snd_soc_codec *codec = &cs4270->codec;
+	int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL;
+
+	return snd_soc_write(codec, CS4270_PWRCTL, reg);
+}
+
+static int cs4270_i2c_resume(struct i2c_client *client)
+{
+	struct cs4270_private *cs4270 = i2c_get_clientdata(client);
+	struct snd_soc_codec *codec = &cs4270->codec;
+	int reg;
+
+	/* In case the device was put to hard reset during sleep, we need to
+	 * wait 500ns here before any I2C communication. */
+	ndelay(500);
+
+	/* first restore the entire register cache ... */
+	for (reg = CS4270_FIRSTREG; reg <= CS4270_LASTREG; reg++) {
+		u8 val = snd_soc_read(codec, reg);
+
+		if (i2c_smbus_write_byte_data(client, reg, val)) {
+			dev_err(codec->dev, "i2c write failed\n");
+			return -EIO;
+		}
+	}
+
+	/* ... then disable the power-down bits */
+	reg = snd_soc_read(codec, CS4270_PWRCTL);
+	reg &= ~CS4270_PWRCTL_PDN_ALL;
+
+	return snd_soc_write(codec, CS4270_PWRCTL, reg);
+}
+#else
+#define cs4270_i2c_suspend	NULL
+#define cs4270_i2c_resume	NULL
+#endif /* CONFIG_PM */
+
 /*
  * cs4270_i2c_driver - I2C device identification
  *
@@ -767,6 +856,8 @@
 	.id_table = cs4270_id,
 	.probe = cs4270_i2c_probe,
 	.remove = cs4270_i2c_remove,
+	.suspend = cs4270_i2c_suspend,
+	.resume = cs4270_i2c_resume,
 };
 
 /*
diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c
new file mode 100644
index 0000000..218b33a
--- /dev/null
+++ b/sound/soc/codecs/spdif_transciever.c
@@ -0,0 +1,71 @@
+/*
+ * ALSA SoC SPDIF DIT driver
+ *
+ *  This driver is used by controllers which can operate in DIT (SPDI/F) where
+ *  no codec is needed.  This file provides stub codec that can be used
+ *  in these configurations. TI DaVinci Audio controller uses this driver.
+ *
+ * Author:      Steve Chen,  <schen@mvista.com>
+ * Copyright:   (C) 2009 MontaVista Software, Inc., <source@mvista.com>
+ * Copyright:   (C) 2009  Texas Instruments, India
+ *
+ * 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 <sound/soc.h>
+#include <sound/pcm.h>
+
+#include "spdif_transciever.h"
+
+#define STUB_RATES	SNDRV_PCM_RATE_8000_96000
+#define STUB_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
+
+struct snd_soc_dai dit_stub_dai = {
+	.name		= "DIT",
+	.playback 	= {
+		.stream_name	= "Playback",
+		.channels_min	= 1,
+		.channels_max	= 384,
+		.rates		= STUB_RATES,
+		.formats	= STUB_FORMATS,
+	},
+};
+
+static int spdif_dit_probe(struct platform_device *pdev)
+{
+	dit_stub_dai.dev = &pdev->dev;
+	return snd_soc_register_dai(&dit_stub_dai);
+}
+
+static int spdif_dit_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&dit_stub_dai);
+	return 0;
+}
+
+static struct platform_driver spdif_dit_driver = {
+	.probe		= spdif_dit_probe,
+	.remove		= spdif_dit_remove,
+	.driver		= {
+		.name	= "spdif-dit",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init dit_modinit(void)
+{
+	return platform_driver_register(&spdif_dit_driver);
+}
+
+static void __exit dit_exit(void)
+{
+	platform_driver_unregister(&spdif_dit_driver);
+}
+
+module_init(dit_modinit);
+module_exit(dit_exit);
+
diff --git a/sound/soc/codecs/spdif_transciever.h b/sound/soc/codecs/spdif_transciever.h
new file mode 100644
index 0000000..296f2eb
--- /dev/null
+++ b/sound/soc/codecs/spdif_transciever.h
@@ -0,0 +1,17 @@
+/*
+ * ALSA SoC DIT/DIR driver header
+ *
+ * Author:      Steve Chen,  <schen@mvista.com>
+ * Copyright:   (C) 2008 MontaVista Software, Inc., <source@mvista.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 CODEC_STUBS_H
+#define CODEC_STUBS_H
+
+extern struct snd_soc_dai dit_stub_dai;
+
+#endif /* CODEC_STUBS_H */
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 87f606c..1fc4c8e 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -336,15 +336,17 @@
 			master_runtime->sample_bits,
 			master_runtime->rate);
 
-		snd_pcm_hw_constraint_minmax(substream->runtime,
-					     SNDRV_PCM_HW_PARAM_RATE,
-					     master_runtime->rate,
-					     master_runtime->rate);
+		if (master_runtime->rate != 0)
+			snd_pcm_hw_constraint_minmax(substream->runtime,
+						     SNDRV_PCM_HW_PARAM_RATE,
+						     master_runtime->rate,
+						     master_runtime->rate);
 
-		snd_pcm_hw_constraint_minmax(substream->runtime,
-					     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-					     master_runtime->sample_bits,
-					     master_runtime->sample_bits);
+		if (master_runtime->sample_bits != 0)
+			snd_pcm_hw_constraint_minmax(substream->runtime,
+						     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+						     master_runtime->sample_bits,
+						     master_runtime->sample_bits);
 
 		ssm2602->slave_substream = substream;
 	} else
@@ -372,6 +374,11 @@
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
 	struct ssm2602_priv *ssm2602 = codec->private_data;
+
+	if (ssm2602->master_substream == substream)
+		ssm2602->master_substream = ssm2602->slave_substream;
+
+	ssm2602->slave_substream = NULL;
 	/* deactivate */
 	if (!codec->active)
 		ssm2602_write(codec, SSM2602_ACTIVE, 0);
@@ -497,11 +504,9 @@
 	return 0;
 }
 
-#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
-		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
-		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
-		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
-		SNDRV_PCM_RATE_96000)
+#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_32000 |\
+		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+		SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
 #define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
new file mode 100644
index 0000000..8ad4b7b
--- /dev/null
+++ b/sound/soc/codecs/stac9766.c
@@ -0,0 +1,463 @@
+/*
+ * stac9766.c  --  ALSA SoC STAC9766 codec support
+ *
+ * Copyright 2009 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@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.
+ *
+ *  Features:-
+ *
+ *   o Support for AC97 Codec, S/PDIF
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/soc-of-simple.h>
+
+#include "stac9766.h"
+
+#define STAC9766_VERSION "0.10"
+
+/*
+ * STAC9766 register cache
+ */
+static const u16 stac9766_reg[] = {
+	0x6A90, 0x8000, 0x8000, 0x8000, /* 6 */
+	0x0000, 0x0000, 0x8008, 0x8008, /* e */
+	0x8808, 0x8808, 0x8808, 0x8808, /* 16 */
+	0x8808, 0x0000, 0x8000, 0x0000, /* 1e */
+	0x0000, 0x0000, 0x0000, 0x000f, /* 26 */
+	0x0a05, 0x0400, 0xbb80, 0x0000, /* 2e */
+	0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */
+	0x0000, 0x2000, 0x0000, 0x0100, /* 3e */
+	0x0000, 0x0000, 0x0080, 0x0000, /* 46 */
+	0x0000, 0x0000, 0x0003, 0xffff, /* 4e */
+	0x0000, 0x0000, 0x0000, 0x0000, /* 56 */
+	0x4000, 0x0000, 0x0000, 0x0000, /* 5e */
+	0x1201, 0xFFFF, 0xFFFF, 0x0000, /* 66 */
+	0x0000, 0x0000, 0x0000, 0x0000, /* 6e */
+	0x0000, 0x0000, 0x0000, 0x0006, /* 76 */
+	0x0000, 0x0000, 0x0000, 0x0000, /* 7e */
+};
+
+static const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX",
+			"Line", "Stereo Mix", "Mono Mix", "Phone"};
+static const char *stac9766_mono_mux[] = {"Mix", "Mic"};
+static const char *stac9766_mic_mux[] = {"Mic1", "Mic2"};
+static const char *stac9766_SPDIF_mux[] = {"PCM", "ADC Record"};
+static const char *stac9766_popbypass_mux[] = {"Normal", "Bypass Mixer"};
+static const char *stac9766_record_all_mux[] = {"All analog",
+	"Analog plus DAC"};
+static const char *stac9766_boost1[] = {"0dB", "10dB"};
+static const char *stac9766_boost2[] = {"0dB", "20dB"};
+static const char *stac9766_stereo_mic[] = {"Off", "On"};
+
+static const struct soc_enum stac9766_record_enum =
+	SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, stac9766_record_mux);
+static const struct soc_enum stac9766_mono_enum =
+	SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 9, 2, stac9766_mono_mux);
+static const struct soc_enum stac9766_mic_enum =
+	SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, stac9766_mic_mux);
+static const struct soc_enum stac9766_SPDIF_enum =
+	SOC_ENUM_SINGLE(AC97_STAC_DA_CONTROL, 1, 2, stac9766_SPDIF_mux);
+static const struct soc_enum stac9766_popbypass_enum =
+	SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, stac9766_popbypass_mux);
+static const struct soc_enum stac9766_record_all_enum =
+	SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 12, 2,
+			stac9766_record_all_mux);
+static const struct soc_enum stac9766_boost1_enum =
+	SOC_ENUM_SINGLE(AC97_MIC, 6, 2, stac9766_boost1); /* 0/10dB */
+static const struct soc_enum stac9766_boost2_enum =
+	SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 2, 2, stac9766_boost2); /* 0/20dB */
+static const struct soc_enum stac9766_stereo_mic_enum =
+	SOC_ENUM_SINGLE(AC97_STAC_STEREO_MIC, 2, 1, stac9766_stereo_mic);
+
+static const DECLARE_TLV_DB_LINEAR(master_tlv, -4600, 0);
+static const DECLARE_TLV_DB_LINEAR(record_tlv, 0, 2250);
+static const DECLARE_TLV_DB_LINEAR(beep_tlv, -4500, 0);
+static const DECLARE_TLV_DB_LINEAR(mix_tlv, -3450, 1200);
+
+static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = {
+	SOC_DOUBLE_TLV("Speaker Volume", AC97_MASTER, 8, 0, 31, 1, master_tlv),
+	SOC_SINGLE("Speaker Switch", AC97_MASTER, 15, 1, 1),
+	SOC_DOUBLE_TLV("Headphone Volume", AC97_HEADPHONE, 8, 0, 31, 1,
+		       master_tlv),
+	SOC_SINGLE("Headphone Switch", AC97_HEADPHONE, 15, 1, 1),
+	SOC_SINGLE_TLV("Mono Out Volume", AC97_MASTER_MONO, 0, 31, 1,
+		       master_tlv),
+	SOC_SINGLE("Mono Out Switch", AC97_MASTER_MONO, 15, 1, 1),
+
+	SOC_DOUBLE_TLV("Record Volume", AC97_REC_GAIN, 8, 0, 15, 0, record_tlv),
+	SOC_SINGLE("Record Switch", AC97_REC_GAIN, 15, 1, 1),
+
+
+	SOC_SINGLE_TLV("Beep Volume", AC97_PC_BEEP, 1, 15, 1, beep_tlv),
+	SOC_SINGLE("Beep Switch", AC97_PC_BEEP, 15, 1, 1),
+	SOC_SINGLE("Beep Frequency", AC97_PC_BEEP, 5, 127, 1),
+	SOC_SINGLE_TLV("Phone Volume", AC97_PHONE, 0, 31, 1, mix_tlv),
+	SOC_SINGLE("Phone Switch", AC97_PHONE, 15, 1, 1),
+
+	SOC_ENUM("Mic Boost1", stac9766_boost1_enum),
+	SOC_ENUM("Mic Boost2", stac9766_boost2_enum),
+	SOC_SINGLE_TLV("Mic Volume", AC97_MIC, 0, 31, 1, mix_tlv),
+	SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1),
+	SOC_ENUM("Stereo Mic", stac9766_stereo_mic_enum),
+
+	SOC_DOUBLE_TLV("Line Volume", AC97_LINE, 8, 0, 31, 1, mix_tlv),
+	SOC_SINGLE("Line Switch", AC97_LINE, 15, 1, 1),
+	SOC_DOUBLE_TLV("CD Volume", AC97_CD, 8, 0, 31, 1, mix_tlv),
+	SOC_SINGLE("CD Switch", AC97_CD, 15, 1, 1),
+	SOC_DOUBLE_TLV("AUX Volume", AC97_AUX, 8, 0, 31, 1, mix_tlv),
+	SOC_SINGLE("AUX Switch", AC97_AUX, 15, 1, 1),
+	SOC_DOUBLE_TLV("Video Volume", AC97_VIDEO, 8, 0, 31, 1, mix_tlv),
+	SOC_SINGLE("Video Switch", AC97_VIDEO, 15, 1, 1),
+
+	SOC_DOUBLE_TLV("DAC Volume", AC97_PCM, 8, 0, 31, 1, mix_tlv),
+	SOC_SINGLE("DAC Switch", AC97_PCM, 15, 1, 1),
+	SOC_SINGLE("Loopback Test Switch", AC97_GENERAL_PURPOSE, 7, 1, 0),
+	SOC_SINGLE("3D Volume", AC97_3D_CONTROL, 3, 2, 1),
+	SOC_SINGLE("3D Switch", AC97_GENERAL_PURPOSE, 13, 1, 0),
+
+	SOC_ENUM("SPDIF Mux", stac9766_SPDIF_enum),
+	SOC_ENUM("Mic1/2 Mux", stac9766_mic_enum),
+	SOC_ENUM("Record All Mux", stac9766_record_all_enum),
+	SOC_ENUM("Record Mux", stac9766_record_enum),
+	SOC_ENUM("Mono Mux", stac9766_mono_enum),
+	SOC_ENUM("Pop Bypass Mux", stac9766_popbypass_enum),
+};
+
+static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg,
+			       unsigned int val)
+{
+	u16 *cache = codec->reg_cache;
+
+	if (reg > AC97_STAC_PAGE0) {
+		stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
+		soc_ac97_ops.write(codec->ac97, reg, val);
+		stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
+		return 0;
+	}
+	if (reg / 2 > ARRAY_SIZE(stac9766_reg))
+		return -EIO;
+
+	soc_ac97_ops.write(codec->ac97, reg, val);
+	cache[reg / 2] = val;
+	return 0;
+}
+
+static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,
+				       unsigned int reg)
+{
+	u16 val = 0, *cache = codec->reg_cache;
+
+	if (reg > AC97_STAC_PAGE0) {
+		stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
+		val = soc_ac97_ops.read(codec->ac97, reg - AC97_STAC_PAGE0);
+		stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
+		return val;
+	}
+	if (reg / 2 > ARRAY_SIZE(stac9766_reg))
+		return -EIO;
+
+	if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
+		reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 ||
+		reg == AC97_VENDOR_ID2) {
+
+		val = soc_ac97_ops.read(codec->ac97, reg);
+		return val;
+	}
+	return cache[reg / 2];
+}
+
+static int ac97_analog_prepare(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned short reg, vra;
+
+	vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS);
+
+	vra |= 0x1; /* enable variable rate audio */
+
+	stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		reg = AC97_PCM_FRONT_DAC_RATE;
+	else
+		reg = AC97_PCM_LR_ADC_RATE;
+
+	return stac9766_ac97_write(codec, reg, runtime->rate);
+}
+
+static int ac97_digital_prepare(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned short reg, vra;
+
+	stac9766_ac97_write(codec, AC97_SPDIF, 0x2002);
+
+	vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS);
+	vra |= 0x5; /* Enable VRA and SPDIF out */
+
+	stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra);
+
+	reg = AC97_PCM_FRONT_DAC_RATE;
+
+	return stac9766_ac97_write(codec, reg, runtime->rate);
+}
+
+static int ac97_digital_trigger(struct snd_pcm_substream *substream,
+				int cmd, struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned short vra;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_STOP:
+		vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS);
+		vra &= !0x04;
+		stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra);
+		break;
+	}
+	return 0;
+}
+
+static int stac9766_set_bias_level(struct snd_soc_codec *codec,
+				   enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON: /* full On */
+	case SND_SOC_BIAS_PREPARE: /* partial On */
+	case SND_SOC_BIAS_STANDBY: /* Off, with power */
+		stac9766_ac97_write(codec, AC97_POWERDOWN, 0x0000);
+		break;
+	case SND_SOC_BIAS_OFF: /* Off, without power */
+		/* disable everything including AC link */
+		stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff);
+		break;
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+static int stac9766_reset(struct snd_soc_codec *codec, int try_warm)
+{
+	if (try_warm && soc_ac97_ops.warm_reset) {
+		soc_ac97_ops.warm_reset(codec->ac97);
+		if (stac9766_ac97_read(codec, 0) == stac9766_reg[0])
+			return 1;
+	}
+
+	soc_ac97_ops.reset(codec->ac97);
+	if (soc_ac97_ops.warm_reset)
+		soc_ac97_ops.warm_reset(codec->ac97);
+	if (stac9766_ac97_read(codec, 0) != stac9766_reg[0])
+		return -EIO;
+	return 0;
+}
+
+static int stac9766_codec_suspend(struct platform_device *pdev,
+				  pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	stac9766_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int stac9766_codec_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+	u16 id, reset;
+
+	reset = 0;
+	/* give the codec an AC97 warm reset to start the link */
+reset:
+	if (reset > 5) {
+		printk(KERN_ERR "stac9766 failed to resume");
+		return -EIO;
+	}
+	codec->ac97->bus->ops->warm_reset(codec->ac97);
+	id = soc_ac97_ops.read(codec->ac97, AC97_VENDOR_ID2);
+	if (id != 0x4c13) {
+		stac9766_reset(codec, 0);
+		reset++;
+		goto reset;
+	}
+	stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
+		stac9766_set_bias_level(codec, SND_SOC_BIAS_ON);
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops stac9766_dai_ops_analog = {
+	.prepare = ac97_analog_prepare,
+};
+
+static struct snd_soc_dai_ops stac9766_dai_ops_digital = {
+	.prepare = ac97_digital_prepare,
+	.trigger = ac97_digital_trigger,
+};
+
+struct snd_soc_dai stac9766_dai[] = {
+{
+	.name = "stac9766 analog",
+	.id = 0,
+	.ac97_control = 1,
+
+	/* stream cababilities */
+	.playback = {
+		.stream_name = "stac9766 analog",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SND_SOC_STD_AC97_FMTS,
+	},
+	.capture = {
+		.stream_name = "stac9766 analog",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SND_SOC_STD_AC97_FMTS,
+	},
+	/* alsa ops */
+	.ops = &stac9766_dai_ops_analog,
+},
+{
+	.name = "stac9766 IEC958",
+	.id = 1,
+	.ac97_control = 1,
+
+	/* stream cababilities */
+	.playback = {
+		.stream_name = "stac9766 IEC958",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_32000 | \
+			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE,
+	},
+	/* alsa ops */
+	.ops = &stac9766_dai_ops_digital,
+}
+};
+EXPORT_SYMBOL_GPL(stac9766_dai);
+
+static int stac9766_codec_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION);
+
+	socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (socdev->card->codec == NULL)
+		return -ENOMEM;
+	codec = socdev->card->codec;
+	mutex_init(&codec->mutex);
+
+	codec->reg_cache = kmemdup(stac9766_reg, sizeof(stac9766_reg),
+				   GFP_KERNEL);
+	if (codec->reg_cache == NULL) {
+		ret = -ENOMEM;
+		goto cache_err;
+	}
+	codec->reg_cache_size = sizeof(stac9766_reg);
+	codec->reg_cache_step = 2;
+
+	codec->name = "STAC9766";
+	codec->owner = THIS_MODULE;
+	codec->dai = stac9766_dai;
+	codec->num_dai = ARRAY_SIZE(stac9766_dai);
+	codec->write = stac9766_ac97_write;
+	codec->read = stac9766_ac97_read;
+	codec->set_bias_level = stac9766_set_bias_level;
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+	if (ret < 0)
+		goto codec_err;
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0)
+		goto pcm_err;
+
+	/* do a cold reset for the controller and then try
+	 * a warm reset followed by an optional cold reset for codec */
+	stac9766_reset(codec, 0);
+	ret = stac9766_reset(codec, 1);
+	if (ret < 0) {
+		printk(KERN_ERR "Failed to reset STAC9766: AC97 link error\n");
+		goto reset_err;
+	}
+
+	stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	snd_soc_add_controls(codec, stac9766_snd_ac97_controls,
+			     ARRAY_SIZE(stac9766_snd_ac97_controls));
+
+	ret = snd_soc_init_card(socdev);
+	if (ret < 0)
+		goto reset_err;
+	return 0;
+
+reset_err:
+	snd_soc_free_pcms(socdev);
+pcm_err:
+	snd_soc_free_ac97_codec(codec);
+codec_err:
+	kfree(codec->private_data);
+cache_err:
+	kfree(socdev->card->codec);
+	socdev->card->codec = NULL;
+	return ret;
+}
+
+static int stac9766_codec_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	if (codec == NULL)
+		return 0;
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_free_ac97_codec(codec);
+	kfree(codec->reg_cache);
+	kfree(codec);
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_stac9766 = {
+	.probe = stac9766_codec_probe,
+	.remove = stac9766_codec_remove,
+	.suspend = stac9766_codec_suspend,
+	.resume = stac9766_codec_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_stac9766);
+
+MODULE_DESCRIPTION("ASoC stac9766 driver");
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/stac9766.h b/sound/soc/codecs/stac9766.h
new file mode 100644
index 0000000..65642eb
--- /dev/null
+++ b/sound/soc/codecs/stac9766.h
@@ -0,0 +1,21 @@
+/*
+ * stac9766.h  --  STAC9766 Soc Audio driver
+ */
+
+#ifndef _STAC9766_H
+#define _STAC9766_H
+
+#define AC97_STAC_PAGE0 0x1000
+#define AC97_STAC_DA_CONTROL (AC97_STAC_PAGE0 | 0x6A)
+#define AC97_STAC_ANALOG_SPECIAL (AC97_STAC_PAGE0 | 0x6E)
+#define AC97_STAC_STEREO_MIC 0x78
+
+/* STAC9766 DAI ID's */
+#define STAC9766_DAI_AC97_ANALOG		0
+#define STAC9766_DAI_AC97_DIGITAL		1
+
+extern struct snd_soc_dai stac9766_dai[];
+extern struct snd_soc_codec_device soc_codec_dev_stac9766;
+
+
+#endif
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index c3f4afb..0b8dcb5 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -86,7 +86,7 @@
 	 */
 
 	if ((reg < 0 || reg > 9) && (reg != 15)) {
-		printk(KERN_WARNING "%s Invalid register R%d\n", __func__, reg);
+		printk(KERN_WARNING "%s Invalid register R%u\n", __func__, reg);
 		return -1;
 	}
 
@@ -98,7 +98,7 @@
 	if (codec->hw_write(codec->control_data, data, 2) == 2)
 		return 0;
 
-	printk(KERN_ERR "%s cannot write %03x to register R%d\n", __func__,
+	printk(KERN_ERR "%s cannot write %03x to register R%u\n", __func__,
 	       value, reg);
 
 	return -EIO;
@@ -273,14 +273,14 @@
  * Every divisor is a factor of 11*12
  */
 #define SR_MULT (11*12)
-#define A(x) (x) ? (SR_MULT/x) : 0
+#define A(x) (SR_MULT/x)
 static const unsigned char sr_adc_mult_table[] = {
-	A(2), A(2), A(12), A(12),  A(0), A(0), A(3), A(1),
-	A(2), A(2), A(11), A(11),  A(0), A(0), A(0), A(1)
+	A(2), A(2), A(12), A(12),  0, 0, A(3), A(1),
+	A(2), A(2), A(11), A(11),  0, 0, 0, A(1)
 };
 static const unsigned char sr_dac_mult_table[] = {
-	A(2), A(12), A(2), A(12),  A(0), A(0), A(3), A(1),
-	A(2), A(11), A(2), A(11),  A(0), A(0), A(0), A(1)
+	A(2), A(12), A(2), A(12),  0, 0, A(3), A(1),
+	A(2), A(11), A(2), A(11),  0, 0, 0, A(1)
 };
 
 static unsigned get_score(int adc, int adc_l, int adc_h, int need_adc,
@@ -523,6 +523,8 @@
 	case SND_SOC_DAIFMT_I2S:
 		iface_reg |= TLV320AIC23_FOR_I2S;
 		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface_reg |= TLV320AIC23_LRP_ON;
 	case SND_SOC_DAIFMT_DSP_B:
 		iface_reg |= TLV320AIC23_FOR_DSP;
 		break;
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index df7c8c2..4dbb853 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -115,6 +115,7 @@
 	0x00, /* REG_VIBRA_PWM_SET	(0x47)	*/
 	0x00, /* REG_ANAMIC_GAIN	(0x48)	*/
 	0x00, /* REG_MISC_SET_2		(0x49)	*/
+	0x00, /* REG_SW_SHADOW		(0x4A)	- Shadow, non HW register */
 };
 
 /* codec private data */
@@ -125,6 +126,17 @@
 
 	struct snd_pcm_substream *master_substream;
 	struct snd_pcm_substream *slave_substream;
+
+	unsigned int configured;
+	unsigned int rate;
+	unsigned int sample_bits;
+	unsigned int channels;
+
+	unsigned int sysclk;
+
+	/* Headset output state handling */
+	unsigned int hsl_enabled;
+	unsigned int hsr_enabled;
 };
 
 /*
@@ -161,7 +173,11 @@
 			unsigned int reg, unsigned int value)
 {
 	twl4030_write_reg_cache(codec, reg, value);
-	return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
+	if (likely(reg < TWL4030_REG_SW_SHADOW))
+		return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value,
+					    reg);
+	else
+		return 0;
 }
 
 static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
@@ -188,6 +204,7 @@
 
 static void twl4030_init_chip(struct snd_soc_codec *codec)
 {
+	u8 *cache = codec->reg_cache;
 	int i;
 
 	/* clear CODECPDZ prior to setting register defaults */
@@ -195,7 +212,7 @@
 
 	/* set all audio section registers to reasonable defaults */
 	for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++)
-		twl4030_write(codec, i,	twl4030_reg[i]);
+		twl4030_write(codec, i,	cache[i]);
 
 }
 
@@ -232,7 +249,7 @@
 					TWL4030_REG_PRECKL_CTL);
 		reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PRECKR_CTL);
 		twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
-					reg_val & (~TWL4030_PRECKL_GAIN),
+					reg_val & (~TWL4030_PRECKR_GAIN),
 					TWL4030_REG_PRECKR_CTL);
 
 		/* Disable PLL */
@@ -316,104 +333,60 @@
 }
 
 /* Earpiece */
-static const char *twl4030_earpiece_texts[] =
-		{"Off", "DACL1", "DACL2", "DACR1"};
-
-static const unsigned int twl4030_earpiece_values[] =
-		{0x0, 0x1, 0x2, 0x4};
-
-static const struct soc_enum twl4030_earpiece_enum =
-	SOC_VALUE_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, 0x7,
-			ARRAY_SIZE(twl4030_earpiece_texts),
-			twl4030_earpiece_texts,
-			twl4030_earpiece_values);
-
-static const struct snd_kcontrol_new twl4030_dapm_earpiece_control =
-SOC_DAPM_VALUE_ENUM("Route", twl4030_earpiece_enum);
+static const struct snd_kcontrol_new twl4030_dapm_earpiece_controls[] = {
+	SOC_DAPM_SINGLE("Voice", TWL4030_REG_EAR_CTL, 0, 1, 0),
+	SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_EAR_CTL, 1, 1, 0),
+	SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_EAR_CTL, 2, 1, 0),
+	SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_EAR_CTL, 3, 1, 0),
+};
 
 /* PreDrive Left */
-static const char *twl4030_predrivel_texts[] =
-		{"Off", "DACL1", "DACL2", "DACR2"};
-
-static const unsigned int twl4030_predrivel_values[] =
-		{0x0, 0x1, 0x2, 0x4};
-
-static const struct soc_enum twl4030_predrivel_enum =
-	SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, 0x7,
-			ARRAY_SIZE(twl4030_predrivel_texts),
-			twl4030_predrivel_texts,
-			twl4030_predrivel_values);
-
-static const struct snd_kcontrol_new twl4030_dapm_predrivel_control =
-SOC_DAPM_VALUE_ENUM("Route", twl4030_predrivel_enum);
+static const struct snd_kcontrol_new twl4030_dapm_predrivel_controls[] = {
+	SOC_DAPM_SINGLE("Voice", TWL4030_REG_PREDL_CTL, 0, 1, 0),
+	SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_PREDL_CTL, 1, 1, 0),
+	SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PREDL_CTL, 2, 1, 0),
+	SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PREDL_CTL, 3, 1, 0),
+};
 
 /* PreDrive Right */
-static const char *twl4030_predriver_texts[] =
-		{"Off", "DACR1", "DACR2", "DACL2"};
-
-static const unsigned int twl4030_predriver_values[] =
-		{0x0, 0x1, 0x2, 0x4};
-
-static const struct soc_enum twl4030_predriver_enum =
-	SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, 0x7,
-			ARRAY_SIZE(twl4030_predriver_texts),
-			twl4030_predriver_texts,
-			twl4030_predriver_values);
-
-static const struct snd_kcontrol_new twl4030_dapm_predriver_control =
-SOC_DAPM_VALUE_ENUM("Route", twl4030_predriver_enum);
+static const struct snd_kcontrol_new twl4030_dapm_predriver_controls[] = {
+	SOC_DAPM_SINGLE("Voice", TWL4030_REG_PREDR_CTL, 0, 1, 0),
+	SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_PREDR_CTL, 1, 1, 0),
+	SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PREDR_CTL, 2, 1, 0),
+	SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PREDR_CTL, 3, 1, 0),
+};
 
 /* Headset Left */
-static const char *twl4030_hsol_texts[] =
-		{"Off", "DACL1", "DACL2"};
-
-static const struct soc_enum twl4030_hsol_enum =
-	SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 1,
-			ARRAY_SIZE(twl4030_hsol_texts),
-			twl4030_hsol_texts);
-
-static const struct snd_kcontrol_new twl4030_dapm_hsol_control =
-SOC_DAPM_ENUM("Route", twl4030_hsol_enum);
+static const struct snd_kcontrol_new twl4030_dapm_hsol_controls[] = {
+	SOC_DAPM_SINGLE("Voice", TWL4030_REG_HS_SEL, 0, 1, 0),
+	SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_HS_SEL, 1, 1, 0),
+	SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_HS_SEL, 2, 1, 0),
+};
 
 /* Headset Right */
-static const char *twl4030_hsor_texts[] =
-		{"Off", "DACR1", "DACR2"};
-
-static const struct soc_enum twl4030_hsor_enum =
-	SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 4,
-			ARRAY_SIZE(twl4030_hsor_texts),
-			twl4030_hsor_texts);
-
-static const struct snd_kcontrol_new twl4030_dapm_hsor_control =
-SOC_DAPM_ENUM("Route", twl4030_hsor_enum);
+static const struct snd_kcontrol_new twl4030_dapm_hsor_controls[] = {
+	SOC_DAPM_SINGLE("Voice", TWL4030_REG_HS_SEL, 3, 1, 0),
+	SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_HS_SEL, 4, 1, 0),
+	SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_HS_SEL, 5, 1, 0),
+};
 
 /* Carkit Left */
-static const char *twl4030_carkitl_texts[] =
-		{"Off", "DACL1", "DACL2"};
-
-static const struct soc_enum twl4030_carkitl_enum =
-	SOC_ENUM_SINGLE(TWL4030_REG_PRECKL_CTL, 1,
-			ARRAY_SIZE(twl4030_carkitl_texts),
-			twl4030_carkitl_texts);
-
-static const struct snd_kcontrol_new twl4030_dapm_carkitl_control =
-SOC_DAPM_ENUM("Route", twl4030_carkitl_enum);
+static const struct snd_kcontrol_new twl4030_dapm_carkitl_controls[] = {
+	SOC_DAPM_SINGLE("Voice", TWL4030_REG_PRECKL_CTL, 0, 1, 0),
+	SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_PRECKL_CTL, 1, 1, 0),
+	SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PRECKL_CTL, 2, 1, 0),
+};
 
 /* Carkit Right */
-static const char *twl4030_carkitr_texts[] =
-		{"Off", "DACR1", "DACR2"};
-
-static const struct soc_enum twl4030_carkitr_enum =
-	SOC_ENUM_SINGLE(TWL4030_REG_PRECKR_CTL, 1,
-			ARRAY_SIZE(twl4030_carkitr_texts),
-			twl4030_carkitr_texts);
-
-static const struct snd_kcontrol_new twl4030_dapm_carkitr_control =
-SOC_DAPM_ENUM("Route", twl4030_carkitr_enum);
+static const struct snd_kcontrol_new twl4030_dapm_carkitr_controls[] = {
+	SOC_DAPM_SINGLE("Voice", TWL4030_REG_PRECKR_CTL, 0, 1, 0),
+	SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_PRECKR_CTL, 1, 1, 0),
+	SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PRECKR_CTL, 2, 1, 0),
+};
 
 /* Handsfree Left */
 static const char *twl4030_handsfreel_texts[] =
-		{"Voice", "DACL1", "DACL2", "DACR2"};
+		{"Voice", "AudioL1", "AudioL2", "AudioR2"};
 
 static const struct soc_enum twl4030_handsfreel_enum =
 	SOC_ENUM_SINGLE(TWL4030_REG_HFL_CTL, 0,
@@ -423,9 +396,13 @@
 static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control =
 SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum);
 
+/* Handsfree Left virtual mute */
+static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control =
+	SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 0, 1, 0);
+
 /* Handsfree Right */
 static const char *twl4030_handsfreer_texts[] =
-		{"Voice", "DACR1", "DACR2", "DACL2"};
+		{"Voice", "AudioR1", "AudioR2", "AudioL2"};
 
 static const struct soc_enum twl4030_handsfreer_enum =
 	SOC_ENUM_SINGLE(TWL4030_REG_HFR_CTL, 0,
@@ -435,37 +412,48 @@
 static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control =
 SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum);
 
+/* Handsfree Right virtual mute */
+static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control =
+	SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 1, 1, 0);
+
+/* Vibra */
+/* Vibra audio path selection */
+static const char *twl4030_vibra_texts[] =
+		{"AudioL1", "AudioR1", "AudioL2", "AudioR2"};
+
+static const struct soc_enum twl4030_vibra_enum =
+	SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 2,
+			ARRAY_SIZE(twl4030_vibra_texts),
+			twl4030_vibra_texts);
+
+static const struct snd_kcontrol_new twl4030_dapm_vibra_control =
+SOC_DAPM_ENUM("Route", twl4030_vibra_enum);
+
+/* Vibra path selection: local vibrator (PWM) or audio driven */
+static const char *twl4030_vibrapath_texts[] =
+		{"Local vibrator", "Audio"};
+
+static const struct soc_enum twl4030_vibrapath_enum =
+	SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 4,
+			ARRAY_SIZE(twl4030_vibrapath_texts),
+			twl4030_vibrapath_texts);
+
+static const struct snd_kcontrol_new twl4030_dapm_vibrapath_control =
+SOC_DAPM_ENUM("Route", twl4030_vibrapath_enum);
+
 /* Left analog microphone selection */
-static const char *twl4030_analoglmic_texts[] =
-		{"Off", "Main mic", "Headset mic", "AUXL", "Carkit mic"};
-
-static const unsigned int twl4030_analoglmic_values[] =
-		{0x0, 0x1, 0x2, 0x4, 0x8};
-
-static const struct soc_enum twl4030_analoglmic_enum =
-	SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICL, 0, 0xf,
-			ARRAY_SIZE(twl4030_analoglmic_texts),
-			twl4030_analoglmic_texts,
-			twl4030_analoglmic_values);
-
-static const struct snd_kcontrol_new twl4030_dapm_analoglmic_control =
-SOC_DAPM_VALUE_ENUM("Route", twl4030_analoglmic_enum);
+static const struct snd_kcontrol_new twl4030_dapm_analoglmic_controls[] = {
+	SOC_DAPM_SINGLE("Main mic", TWL4030_REG_ANAMICL, 0, 1, 0),
+	SOC_DAPM_SINGLE("Headset mic", TWL4030_REG_ANAMICL, 1, 1, 0),
+	SOC_DAPM_SINGLE("AUXL", TWL4030_REG_ANAMICL, 2, 1, 0),
+	SOC_DAPM_SINGLE("Carkit mic", TWL4030_REG_ANAMICL, 3, 1, 0),
+};
 
 /* Right analog microphone selection */
-static const char *twl4030_analogrmic_texts[] =
-		{"Off", "Sub mic", "AUXR"};
-
-static const unsigned int twl4030_analogrmic_values[] =
-		{0x0, 0x1, 0x4};
-
-static const struct soc_enum twl4030_analogrmic_enum =
-	SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICR, 0, 0x5,
-			ARRAY_SIZE(twl4030_analogrmic_texts),
-			twl4030_analogrmic_texts,
-			twl4030_analogrmic_values);
-
-static const struct snd_kcontrol_new twl4030_dapm_analogrmic_control =
-SOC_DAPM_VALUE_ENUM("Route", twl4030_analogrmic_enum);
+static const struct snd_kcontrol_new twl4030_dapm_analogrmic_controls[] = {
+	SOC_DAPM_SINGLE("Sub mic", TWL4030_REG_ANAMICR, 0, 1, 0),
+	SOC_DAPM_SINGLE("AUXR", TWL4030_REG_ANAMICR, 2, 1, 0),
+};
 
 /* TX1 L/R Analog/Digital microphone selection */
 static const char *twl4030_micpathtx1_texts[] =
@@ -507,6 +495,10 @@
 static const struct snd_kcontrol_new twl4030_dapm_abypassl2_control =
 	SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXL2_APGA_CTL, 2, 1, 0);
 
+/* Analog bypass for Voice */
+static const struct snd_kcontrol_new twl4030_dapm_abypassv_control =
+	SOC_DAPM_SINGLE("Switch", TWL4030_REG_VDL_APGA_CTL, 2, 1, 0);
+
 /* Digital bypass gain, 0 mutes the bypass */
 static const unsigned int twl4030_dapm_dbypass_tlv[] = {
 	TLV_DB_RANGE_HEAD(2),
@@ -526,6 +518,18 @@
 			TWL4030_REG_ATX2ARXPGA, 0, 7, 0,
 			twl4030_dapm_dbypass_tlv);
 
+/*
+ * Voice Sidetone GAIN volume control:
+ * from -51 to -10 dB in 1 dB steps (mute instead of -51 dB)
+ */
+static DECLARE_TLV_DB_SCALE(twl4030_dapm_dbypassv_tlv, -5100, 100, 1);
+
+/* Digital bypass voice: sidetone (VUL -> VDL)*/
+static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =
+	SOC_DAPM_SINGLE_TLV("Volume",
+			TWL4030_REG_VSTPGA, 0, 0x29, 0,
+			twl4030_dapm_dbypassv_tlv);
+
 static int micpath_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -556,63 +560,143 @@
 	return 0;
 }
 
-static int handsfree_event(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
+static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp)
 {
-	struct soc_enum *e = (struct soc_enum *)w->kcontrols->private_value;
 	unsigned char hs_ctl;
 
-	hs_ctl = twl4030_read_reg_cache(w->codec, e->reg);
+	hs_ctl = twl4030_read_reg_cache(codec, reg);
 
-	if (hs_ctl & TWL4030_HF_CTL_REF_EN) {
+	if (ramp) {
+		/* HF ramp-up */
+		hs_ctl |= TWL4030_HF_CTL_REF_EN;
+		twl4030_write(codec, reg, hs_ctl);
+		udelay(10);
 		hs_ctl |= TWL4030_HF_CTL_RAMP_EN;
-		twl4030_write(w->codec, e->reg, hs_ctl);
+		twl4030_write(codec, reg, hs_ctl);
+		udelay(40);
 		hs_ctl |= TWL4030_HF_CTL_LOOP_EN;
-		twl4030_write(w->codec, e->reg, hs_ctl);
 		hs_ctl |= TWL4030_HF_CTL_HB_EN;
-		twl4030_write(w->codec, e->reg, hs_ctl);
+		twl4030_write(codec, reg, hs_ctl);
 	} else {
-		hs_ctl &= ~(TWL4030_HF_CTL_RAMP_EN | TWL4030_HF_CTL_LOOP_EN
-				| TWL4030_HF_CTL_HB_EN);
-		twl4030_write(w->codec, e->reg, hs_ctl);
+		/* HF ramp-down */
+		hs_ctl &= ~TWL4030_HF_CTL_LOOP_EN;
+		hs_ctl &= ~TWL4030_HF_CTL_HB_EN;
+		twl4030_write(codec, reg, hs_ctl);
+		hs_ctl &= ~TWL4030_HF_CTL_RAMP_EN;
+		twl4030_write(codec, reg, hs_ctl);
+		udelay(40);
+		hs_ctl &= ~TWL4030_HF_CTL_REF_EN;
+		twl4030_write(codec, reg, hs_ctl);
 	}
+}
 
+static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 0);
+		break;
+	}
 	return 0;
 }
 
-static int headsetl_event(struct snd_soc_dapm_widget *w,
+static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
-	unsigned char hs_gain, hs_pop;
-
-	/* Save the current volume */
-	hs_gain = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_GAIN_SET);
-	hs_pop = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_POPN_SET);
-
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		/* Do the anti-pop/bias ramp enable according to the TRM */
-		hs_pop |= TWL4030_VMID_EN;
-		twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
-		/* Is this needed? Can we just use whatever gain here? */
-		twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET,
-				(hs_gain & (~0x0f)) | 0x0a);
-		hs_pop |= TWL4030_RAMP_EN;
-		twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
-
-		/* Restore the original volume */
-		twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET, hs_gain);
+		handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 1);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		/* Do the anti-pop/bias ramp disable according to the TRM */
+		handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 0);
+		break;
+	}
+	return 0;
+}
+
+static void headset_ramp(struct snd_soc_codec *codec, int ramp)
+{
+	unsigned char hs_gain, hs_pop;
+	struct twl4030_priv *twl4030 = codec->private_data;
+	/* Base values for ramp delay calculation: 2^19 - 2^26 */
+	unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
+				    8388608, 16777216, 33554432, 67108864};
+
+	hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET);
+	hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
+
+	if (ramp) {
+		/* Headset ramp-up according to the TRM */
+		hs_pop |= TWL4030_VMID_EN;
+		twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+		twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hs_gain);
+		hs_pop |= TWL4030_RAMP_EN;
+		twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+	} else {
+		/* Headset ramp-down _not_ according to
+		 * the TRM, but in a way that it is working */
 		hs_pop &= ~TWL4030_RAMP_EN;
-		twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+		twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+		/* Wait ramp delay time + 1, so the VMID can settle */
+		mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
+			twl4030->sysclk) + 1);
 		/* Bypass the reg_cache to mute the headset */
 		twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
 					hs_gain & (~0x0f),
 					TWL4030_REG_HS_GAIN_SET);
+
 		hs_pop &= ~TWL4030_VMID_EN;
-		twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+		twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+	}
+}
+
+static int headsetlpga_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct twl4030_priv *twl4030 = w->codec->private_data;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Do the ramp-up only once */
+		if (!twl4030->hsr_enabled)
+			headset_ramp(w->codec, 1);
+
+		twl4030->hsl_enabled = 1;
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Do the ramp-down only if both headsetL/R is disabled */
+		if (!twl4030->hsr_enabled)
+			headset_ramp(w->codec, 0);
+
+		twl4030->hsl_enabled = 0;
+		break;
+	}
+	return 0;
+}
+
+static int headsetrpga_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct twl4030_priv *twl4030 = w->codec->private_data;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Do the ramp-up only once */
+		if (!twl4030->hsl_enabled)
+			headset_ramp(w->codec, 1);
+
+		twl4030->hsr_enabled = 1;
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Do the ramp-down only if both headsetL/R is disabled */
+		if (!twl4030->hsl_enabled)
+			headset_ramp(w->codec, 0);
+
+		twl4030->hsr_enabled = 0;
 		break;
 	}
 	return 0;
@@ -624,7 +708,7 @@
 	struct soc_mixer_control *m =
 		(struct soc_mixer_control *)w->kcontrols->private_value;
 	struct twl4030_priv *twl4030 = w->codec->private_data;
-	unsigned char reg;
+	unsigned char reg, misc;
 
 	reg = twl4030_read_reg_cache(w->codec, m->reg);
 
@@ -636,14 +720,34 @@
 		else
 			twl4030->bypass_state &=
 				~(1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));
+	} else if (m->reg == TWL4030_REG_VDL_APGA_CTL) {
+		/* Analog voice bypass */
+		if (reg & (1 << m->shift))
+			twl4030->bypass_state |= (1 << 4);
+		else
+			twl4030->bypass_state &= ~(1 << 4);
+	} else if (m->reg == TWL4030_REG_VSTPGA) {
+		/* Voice digital bypass */
+		if (reg)
+			twl4030->bypass_state |= (1 << 5);
+		else
+			twl4030->bypass_state &= ~(1 << 5);
 	} else {
 		/* Digital bypass */
 		if (reg & (0x7 << m->shift))
-			twl4030->bypass_state |= (1 << (m->shift ? 5 : 4));
+			twl4030->bypass_state |= (1 << (m->shift ? 7 : 6));
 		else
-			twl4030->bypass_state &= ~(1 << (m->shift ? 5 : 4));
+			twl4030->bypass_state &= ~(1 << (m->shift ? 7 : 6));
 	}
 
+	/* Enable master analog loopback mode if any analog switch is enabled*/
+	misc = twl4030_read_reg_cache(w->codec, TWL4030_REG_MISC_SET_1);
+	if (twl4030->bypass_state & 0x1F)
+		misc |= TWL4030_FMLOOP_EN;
+	else
+		misc &= ~TWL4030_FMLOOP_EN;
+	twl4030_write(w->codec, TWL4030_REG_MISC_SET_1, misc);
+
 	if (w->codec->bias_level == SND_SOC_BIAS_STANDBY) {
 		if (twl4030->bypass_state)
 			twl4030_codec_mute(w->codec, 0);
@@ -810,6 +914,48 @@
 	return err;
 }
 
+/* Codec operation modes */
+static const char *twl4030_op_modes_texts[] = {
+	"Option 2 (voice/audio)", "Option 1 (audio)"
+};
+
+static const struct soc_enum twl4030_op_modes_enum =
+	SOC_ENUM_SINGLE(TWL4030_REG_CODEC_MODE, 0,
+			ARRAY_SIZE(twl4030_op_modes_texts),
+			twl4030_op_modes_texts);
+
+int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct twl4030_priv *twl4030 = codec->private_data;
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned short val;
+	unsigned short mask, bitmask;
+
+	if (twl4030->configured) {
+		printk(KERN_ERR "twl4030 operation mode cannot be "
+			"changed on-the-fly\n");
+		return -EBUSY;
+	}
+
+	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
+		;
+	if (ucontrol->value.enumerated.item[0] > e->max - 1)
+		return -EINVAL;
+
+	val = ucontrol->value.enumerated.item[0] << e->shift_l;
+	mask = (bitmask - 1) << e->shift_l;
+	if (e->shift_l != e->shift_r) {
+		if (ucontrol->value.enumerated.item[1] > e->max - 1)
+			return -EINVAL;
+		val |= ucontrol->value.enumerated.item[1] << e->shift_r;
+		mask |= (bitmask - 1) << e->shift_r;
+	}
+
+	return snd_soc_update_bits(codec, e->reg, mask, val);
+}
+
 /*
  * FGAIN volume control:
  * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB)
@@ -824,6 +970,12 @@
 static DECLARE_TLV_DB_SCALE(digital_coarse_tlv, 0, 600, 0);
 
 /*
+ * Voice Downlink GAIN volume control:
+ * from -37 to 12 dB in 1 dB steps (mute instead of -37 dB)
+ */
+static DECLARE_TLV_DB_SCALE(digital_voice_downlink_tlv, -3700, 100, 1);
+
+/*
  * Analog playback gain
  * -24 dB to 12 dB in 2 dB steps
  */
@@ -864,7 +1016,32 @@
 			ARRAY_SIZE(twl4030_rampdelay_texts),
 			twl4030_rampdelay_texts);
 
+/* Vibra H-bridge direction mode */
+static const char *twl4030_vibradirmode_texts[] = {
+	"Vibra H-bridge direction", "Audio data MSB",
+};
+
+static const struct soc_enum twl4030_vibradirmode_enum =
+	SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 5,
+			ARRAY_SIZE(twl4030_vibradirmode_texts),
+			twl4030_vibradirmode_texts);
+
+/* Vibra H-bridge direction */
+static const char *twl4030_vibradir_texts[] = {
+	"Positive polarity", "Negative polarity",
+};
+
+static const struct soc_enum twl4030_vibradir_enum =
+	SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 1,
+			ARRAY_SIZE(twl4030_vibradir_texts),
+			twl4030_vibradir_texts);
+
 static const struct snd_kcontrol_new twl4030_snd_controls[] = {
+	/* Codec operation mode control */
+	SOC_ENUM_EXT("Codec Operation Mode", twl4030_op_modes_enum,
+		snd_soc_get_enum_double,
+		snd_soc_put_twl4030_opmode_enum_double),
+
 	/* Common playback gain controls */
 	SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume",
 		TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA,
@@ -893,6 +1070,16 @@
 		TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL,
 		1, 1, 0),
 
+	/* Common voice downlink gain controls */
+	SOC_SINGLE_TLV("DAC Voice Digital Downlink Volume",
+		TWL4030_REG_VRXPGA, 0, 0x31, 0, digital_voice_downlink_tlv),
+
+	SOC_SINGLE_TLV("DAC Voice Analog Downlink Volume",
+		TWL4030_REG_VDL_APGA_CTL, 3, 0x12, 1, analog_tlv),
+
+	SOC_SINGLE("DAC Voice Analog Downlink Switch",
+		TWL4030_REG_VDL_APGA_CTL, 1, 1, 0),
+
 	/* Separate output gain controls */
 	SOC_DOUBLE_R_TLV_TWL4030("PreDriv Playback Volume",
 		TWL4030_REG_PREDL_CTL, TWL4030_REG_PREDR_CTL,
@@ -920,6 +1107,9 @@
 		0, 3, 5, 0, input_gain_tlv),
 
 	SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum),
+
+	SOC_ENUM("Vibra H-bridge mode", twl4030_vibradirmode_enum),
+	SOC_ENUM("Vibra H-bridge direction", twl4030_vibradir_enum),
 };
 
 static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
@@ -947,26 +1137,19 @@
 	SND_SOC_DAPM_OUTPUT("CARKITR"),
 	SND_SOC_DAPM_OUTPUT("HFL"),
 	SND_SOC_DAPM_OUTPUT("HFR"),
+	SND_SOC_DAPM_OUTPUT("VIBRA"),
 
 	/* DACs */
-	SND_SOC_DAPM_DAC("DAC Right1", "Right Front Playback",
+	SND_SOC_DAPM_DAC("DAC Right1", "Right Front HiFi Playback",
 			SND_SOC_NOPM, 0, 0),
-	SND_SOC_DAPM_DAC("DAC Left1", "Left Front Playback",
+	SND_SOC_DAPM_DAC("DAC Left1", "Left Front HiFi Playback",
 			SND_SOC_NOPM, 0, 0),
-	SND_SOC_DAPM_DAC("DAC Right2", "Right Rear Playback",
+	SND_SOC_DAPM_DAC("DAC Right2", "Right Rear HiFi Playback",
 			SND_SOC_NOPM, 0, 0),
-	SND_SOC_DAPM_DAC("DAC Left2", "Left Rear Playback",
+	SND_SOC_DAPM_DAC("DAC Left2", "Left Rear HiFi Playback",
 			SND_SOC_NOPM, 0, 0),
-
-	/* Analog PGAs */
-	SND_SOC_DAPM_PGA("ARXR1_APGA", TWL4030_REG_ARXR1_APGA_CTL,
-			0, 0, NULL, 0),
-	SND_SOC_DAPM_PGA("ARXL1_APGA", TWL4030_REG_ARXL1_APGA_CTL,
-			0, 0, NULL, 0),
-	SND_SOC_DAPM_PGA("ARXR2_APGA", TWL4030_REG_ARXR2_APGA_CTL,
-			0, 0, NULL, 0),
-	SND_SOC_DAPM_PGA("ARXL2_APGA", TWL4030_REG_ARXL2_APGA_CTL,
-			0, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("DAC Voice", "Voice Playback",
+			SND_SOC_NOPM, 0, 0),
 
 	/* Analog bypasses */
 	SND_SOC_DAPM_SWITCH_E("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0,
@@ -981,6 +1164,9 @@
 	SND_SOC_DAPM_SWITCH_E("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0,
 			&twl4030_dapm_abypassl2_control,
 			bypass_event, SND_SOC_DAPM_POST_REG),
+	SND_SOC_DAPM_SWITCH_E("Voice Analog Loopback", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_abypassv_control,
+			bypass_event, SND_SOC_DAPM_POST_REG),
 
 	/* Digital bypasses */
 	SND_SOC_DAPM_SWITCH_E("Left Digital Loopback", SND_SOC_NOPM, 0, 0,
@@ -989,43 +1175,88 @@
 	SND_SOC_DAPM_SWITCH_E("Right Digital Loopback", SND_SOC_NOPM, 0, 0,
 			&twl4030_dapm_dbypassr_control, bypass_event,
 			SND_SOC_DAPM_POST_REG),
+	SND_SOC_DAPM_SWITCH_E("Voice Digital Loopback", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_dbypassv_control, bypass_event,
+			SND_SOC_DAPM_POST_REG),
 
-	SND_SOC_DAPM_MIXER("Analog R1 Playback Mixer", TWL4030_REG_AVDAC_CTL,
-			0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("Analog L1 Playback Mixer", TWL4030_REG_AVDAC_CTL,
-			1, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("Analog R2 Playback Mixer", TWL4030_REG_AVDAC_CTL,
-			2, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("Analog L2 Playback Mixer", TWL4030_REG_AVDAC_CTL,
-			3, 0, NULL, 0),
+	/* Digital mixers, power control for the physical DACs */
+	SND_SOC_DAPM_MIXER("Digital R1 Playback Mixer",
+			TWL4030_REG_AVDAC_CTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Digital L1 Playback Mixer",
+			TWL4030_REG_AVDAC_CTL, 1, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Digital R2 Playback Mixer",
+			TWL4030_REG_AVDAC_CTL, 2, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Digital L2 Playback Mixer",
+			TWL4030_REG_AVDAC_CTL, 3, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Digital Voice Playback Mixer",
+			TWL4030_REG_AVDAC_CTL, 4, 0, NULL, 0),
+
+	/* Analog mixers, power control for the physical PGAs */
+	SND_SOC_DAPM_MIXER("Analog R1 Playback Mixer",
+			TWL4030_REG_ARXR1_APGA_CTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Analog L1 Playback Mixer",
+			TWL4030_REG_ARXL1_APGA_CTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Analog R2 Playback Mixer",
+			TWL4030_REG_ARXR2_APGA_CTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Analog L2 Playback Mixer",
+			TWL4030_REG_ARXL2_APGA_CTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Analog Voice Playback Mixer",
+			TWL4030_REG_VDL_APGA_CTL, 0, 0, NULL, 0),
+
+	/* Output MIXER controls */
+	/* Earpiece */
+	SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_earpiece_controls[0],
+			ARRAY_SIZE(twl4030_dapm_earpiece_controls)),
+	/* PreDrivL/R */
+	SND_SOC_DAPM_MIXER("PredriveL Mixer", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_predrivel_controls[0],
+			ARRAY_SIZE(twl4030_dapm_predrivel_controls)),
+	SND_SOC_DAPM_MIXER("PredriveR Mixer", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_predriver_controls[0],
+			ARRAY_SIZE(twl4030_dapm_predriver_controls)),
+	/* HeadsetL/R */
+	SND_SOC_DAPM_MIXER("HeadsetL Mixer", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_hsol_controls[0],
+			ARRAY_SIZE(twl4030_dapm_hsol_controls)),
+	SND_SOC_DAPM_PGA_E("HeadsetL PGA", SND_SOC_NOPM,
+			0, 0, NULL, 0, headsetlpga_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("HeadsetR Mixer", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_hsor_controls[0],
+			ARRAY_SIZE(twl4030_dapm_hsor_controls)),
+	SND_SOC_DAPM_PGA_E("HeadsetR PGA", SND_SOC_NOPM,
+			0, 0, NULL, 0, headsetrpga_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+	/* CarkitL/R */
+	SND_SOC_DAPM_MIXER("CarkitL Mixer", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_carkitl_controls[0],
+			ARRAY_SIZE(twl4030_dapm_carkitl_controls)),
+	SND_SOC_DAPM_MIXER("CarkitR Mixer", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_carkitr_controls[0],
+			ARRAY_SIZE(twl4030_dapm_carkitr_controls)),
 
 	/* Output MUX controls */
-	/* Earpiece */
-	SND_SOC_DAPM_VALUE_MUX("Earpiece Mux", SND_SOC_NOPM, 0, 0,
-		&twl4030_dapm_earpiece_control),
-	/* PreDrivL/R */
-	SND_SOC_DAPM_VALUE_MUX("PredriveL Mux", SND_SOC_NOPM, 0, 0,
-		&twl4030_dapm_predrivel_control),
-	SND_SOC_DAPM_VALUE_MUX("PredriveR Mux", SND_SOC_NOPM, 0, 0,
-		&twl4030_dapm_predriver_control),
-	/* HeadsetL/R */
-	SND_SOC_DAPM_MUX_E("HeadsetL Mux", SND_SOC_NOPM, 0, 0,
-		&twl4030_dapm_hsol_control, headsetl_event,
-		SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MUX("HeadsetR Mux", SND_SOC_NOPM, 0, 0,
-		&twl4030_dapm_hsor_control),
-	/* CarkitL/R */
-	SND_SOC_DAPM_MUX("CarkitL Mux", SND_SOC_NOPM, 0, 0,
-		&twl4030_dapm_carkitl_control),
-	SND_SOC_DAPM_MUX("CarkitR Mux", SND_SOC_NOPM, 0, 0,
-		&twl4030_dapm_carkitr_control),
 	/* HandsfreeL/R */
-	SND_SOC_DAPM_MUX_E("HandsfreeL Mux", TWL4030_REG_HFL_CTL, 5, 0,
-		&twl4030_dapm_handsfreel_control, handsfree_event,
-		SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MUX_E("HandsfreeR Mux", TWL4030_REG_HFR_CTL, 5, 0,
-		&twl4030_dapm_handsfreer_control, handsfree_event,
-		SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX("HandsfreeL Mux", SND_SOC_NOPM, 0, 0,
+		&twl4030_dapm_handsfreel_control),
+	SND_SOC_DAPM_SWITCH("HandsfreeL Switch", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_handsfreelmute_control),
+	SND_SOC_DAPM_PGA_E("HandsfreeL PGA", SND_SOC_NOPM,
+			0, 0, NULL, 0, handsfreelpga_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX("HandsfreeR Mux", SND_SOC_NOPM, 5, 0,
+		&twl4030_dapm_handsfreer_control),
+	SND_SOC_DAPM_SWITCH("HandsfreeR Switch", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_handsfreermute_control),
+	SND_SOC_DAPM_PGA_E("HandsfreeR PGA", SND_SOC_NOPM,
+			0, 0, NULL, 0, handsfreerpga_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+	/* Vibra */
+	SND_SOC_DAPM_MUX("Vibra Mux", TWL4030_REG_VIBRA_CTL, 0, 0,
+		&twl4030_dapm_vibra_control),
+	SND_SOC_DAPM_MUX("Vibra Route", SND_SOC_NOPM, 0, 0,
+		&twl4030_dapm_vibrapath_control),
 
 	/* Introducing four virtual ADC, since TWL4030 have four channel for
 	   capture */
@@ -1050,11 +1281,15 @@
 		SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD|
 		SND_SOC_DAPM_POST_REG),
 
-	/* Analog input muxes with switch for the capture amplifiers */
-	SND_SOC_DAPM_VALUE_MUX("Analog Left Capture Route",
-		TWL4030_REG_ANAMICL, 4, 0, &twl4030_dapm_analoglmic_control),
-	SND_SOC_DAPM_VALUE_MUX("Analog Right Capture Route",
-		TWL4030_REG_ANAMICR, 4, 0, &twl4030_dapm_analogrmic_control),
+	/* Analog input mixers for the capture amplifiers */
+	SND_SOC_DAPM_MIXER("Analog Left Capture Route",
+		TWL4030_REG_ANAMICL, 4, 0,
+		&twl4030_dapm_analoglmic_controls[0],
+		ARRAY_SIZE(twl4030_dapm_analoglmic_controls)),
+	SND_SOC_DAPM_MIXER("Analog Right Capture Route",
+		TWL4030_REG_ANAMICR, 4, 0,
+		&twl4030_dapm_analogrmic_controls[0],
+		ARRAY_SIZE(twl4030_dapm_analogrmic_controls)),
 
 	SND_SOC_DAPM_PGA("ADC Physical Left",
 		TWL4030_REG_AVADC_CTL, 3, 0, NULL, 0),
@@ -1073,62 +1308,86 @@
 };
 
 static const struct snd_soc_dapm_route intercon[] = {
-	{"Analog L1 Playback Mixer", NULL, "DAC Left1"},
-	{"Analog R1 Playback Mixer", NULL, "DAC Right1"},
-	{"Analog L2 Playback Mixer", NULL, "DAC Left2"},
-	{"Analog R2 Playback Mixer", NULL, "DAC Right2"},
+	{"Digital L1 Playback Mixer", NULL, "DAC Left1"},
+	{"Digital R1 Playback Mixer", NULL, "DAC Right1"},
+	{"Digital L2 Playback Mixer", NULL, "DAC Left2"},
+	{"Digital R2 Playback Mixer", NULL, "DAC Right2"},
+	{"Digital Voice Playback Mixer", NULL, "DAC Voice"},
 
-	{"ARXL1_APGA", NULL, "Analog L1 Playback Mixer"},
-	{"ARXR1_APGA", NULL, "Analog R1 Playback Mixer"},
-	{"ARXL2_APGA", NULL, "Analog L2 Playback Mixer"},
-	{"ARXR2_APGA", NULL, "Analog R2 Playback Mixer"},
+	{"Analog L1 Playback Mixer", NULL, "Digital L1 Playback Mixer"},
+	{"Analog R1 Playback Mixer", NULL, "Digital R1 Playback Mixer"},
+	{"Analog L2 Playback Mixer", NULL, "Digital L2 Playback Mixer"},
+	{"Analog R2 Playback Mixer", NULL, "Digital R2 Playback Mixer"},
+	{"Analog Voice Playback Mixer", NULL, "Digital Voice Playback Mixer"},
 
 	/* Internal playback routings */
 	/* Earpiece */
-	{"Earpiece Mux", "DACL1", "ARXL1_APGA"},
-	{"Earpiece Mux", "DACL2", "ARXL2_APGA"},
-	{"Earpiece Mux", "DACR1", "ARXR1_APGA"},
+	{"Earpiece Mixer", "Voice", "Analog Voice Playback Mixer"},
+	{"Earpiece Mixer", "AudioL1", "Analog L1 Playback Mixer"},
+	{"Earpiece Mixer", "AudioL2", "Analog L2 Playback Mixer"},
+	{"Earpiece Mixer", "AudioR1", "Analog R1 Playback Mixer"},
 	/* PreDrivL */
-	{"PredriveL Mux", "DACL1", "ARXL1_APGA"},
-	{"PredriveL Mux", "DACL2", "ARXL2_APGA"},
-	{"PredriveL Mux", "DACR2", "ARXR2_APGA"},
+	{"PredriveL Mixer", "Voice", "Analog Voice Playback Mixer"},
+	{"PredriveL Mixer", "AudioL1", "Analog L1 Playback Mixer"},
+	{"PredriveL Mixer", "AudioL2", "Analog L2 Playback Mixer"},
+	{"PredriveL Mixer", "AudioR2", "Analog R2 Playback Mixer"},
 	/* PreDrivR */
-	{"PredriveR Mux", "DACR1", "ARXR1_APGA"},
-	{"PredriveR Mux", "DACR2", "ARXR2_APGA"},
-	{"PredriveR Mux", "DACL2", "ARXL2_APGA"},
+	{"PredriveR Mixer", "Voice", "Analog Voice Playback Mixer"},
+	{"PredriveR Mixer", "AudioR1", "Analog R1 Playback Mixer"},
+	{"PredriveR Mixer", "AudioR2", "Analog R2 Playback Mixer"},
+	{"PredriveR Mixer", "AudioL2", "Analog L2 Playback Mixer"},
 	/* HeadsetL */
-	{"HeadsetL Mux", "DACL1", "ARXL1_APGA"},
-	{"HeadsetL Mux", "DACL2", "ARXL2_APGA"},
+	{"HeadsetL Mixer", "Voice", "Analog Voice Playback Mixer"},
+	{"HeadsetL Mixer", "AudioL1", "Analog L1 Playback Mixer"},
+	{"HeadsetL Mixer", "AudioL2", "Analog L2 Playback Mixer"},
+	{"HeadsetL PGA", NULL, "HeadsetL Mixer"},
 	/* HeadsetR */
-	{"HeadsetR Mux", "DACR1", "ARXR1_APGA"},
-	{"HeadsetR Mux", "DACR2", "ARXR2_APGA"},
+	{"HeadsetR Mixer", "Voice", "Analog Voice Playback Mixer"},
+	{"HeadsetR Mixer", "AudioR1", "Analog R1 Playback Mixer"},
+	{"HeadsetR Mixer", "AudioR2", "Analog R2 Playback Mixer"},
+	{"HeadsetR PGA", NULL, "HeadsetR Mixer"},
 	/* CarkitL */
-	{"CarkitL Mux", "DACL1", "ARXL1_APGA"},
-	{"CarkitL Mux", "DACL2", "ARXL2_APGA"},
+	{"CarkitL Mixer", "Voice", "Analog Voice Playback Mixer"},
+	{"CarkitL Mixer", "AudioL1", "Analog L1 Playback Mixer"},
+	{"CarkitL Mixer", "AudioL2", "Analog L2 Playback Mixer"},
 	/* CarkitR */
-	{"CarkitR Mux", "DACR1", "ARXR1_APGA"},
-	{"CarkitR Mux", "DACR2", "ARXR2_APGA"},
+	{"CarkitR Mixer", "Voice", "Analog Voice Playback Mixer"},
+	{"CarkitR Mixer", "AudioR1", "Analog R1 Playback Mixer"},
+	{"CarkitR Mixer", "AudioR2", "Analog R2 Playback Mixer"},
 	/* HandsfreeL */
-	{"HandsfreeL Mux", "DACL1", "ARXL1_APGA"},
-	{"HandsfreeL Mux", "DACL2", "ARXL2_APGA"},
-	{"HandsfreeL Mux", "DACR2", "ARXR2_APGA"},
+	{"HandsfreeL Mux", "Voice", "Analog Voice Playback Mixer"},
+	{"HandsfreeL Mux", "AudioL1", "Analog L1 Playback Mixer"},
+	{"HandsfreeL Mux", "AudioL2", "Analog L2 Playback Mixer"},
+	{"HandsfreeL Mux", "AudioR2", "Analog R2 Playback Mixer"},
+	{"HandsfreeL Switch", "Switch", "HandsfreeL Mux"},
+	{"HandsfreeL PGA", NULL, "HandsfreeL Switch"},
 	/* HandsfreeR */
-	{"HandsfreeR Mux", "DACR1", "ARXR1_APGA"},
-	{"HandsfreeR Mux", "DACR2", "ARXR2_APGA"},
-	{"HandsfreeR Mux", "DACL2", "ARXL2_APGA"},
+	{"HandsfreeR Mux", "Voice", "Analog Voice Playback Mixer"},
+	{"HandsfreeR Mux", "AudioR1", "Analog R1 Playback Mixer"},
+	{"HandsfreeR Mux", "AudioR2", "Analog R2 Playback Mixer"},
+	{"HandsfreeR Mux", "AudioL2", "Analog L2 Playback Mixer"},
+	{"HandsfreeR Switch", "Switch", "HandsfreeR Mux"},
+	{"HandsfreeR PGA", NULL, "HandsfreeR Switch"},
+	/* Vibra */
+	{"Vibra Mux", "AudioL1", "DAC Left1"},
+	{"Vibra Mux", "AudioR1", "DAC Right1"},
+	{"Vibra Mux", "AudioL2", "DAC Left2"},
+	{"Vibra Mux", "AudioR2", "DAC Right2"},
 
 	/* outputs */
-	{"OUTL", NULL, "ARXL2_APGA"},
-	{"OUTR", NULL, "ARXR2_APGA"},
-	{"EARPIECE", NULL, "Earpiece Mux"},
-	{"PREDRIVEL", NULL, "PredriveL Mux"},
-	{"PREDRIVER", NULL, "PredriveR Mux"},
-	{"HSOL", NULL, "HeadsetL Mux"},
-	{"HSOR", NULL, "HeadsetR Mux"},
-	{"CARKITL", NULL, "CarkitL Mux"},
-	{"CARKITR", NULL, "CarkitR Mux"},
-	{"HFL", NULL, "HandsfreeL Mux"},
-	{"HFR", NULL, "HandsfreeR Mux"},
+	{"OUTL", NULL, "Analog L2 Playback Mixer"},
+	{"OUTR", NULL, "Analog R2 Playback Mixer"},
+	{"EARPIECE", NULL, "Earpiece Mixer"},
+	{"PREDRIVEL", NULL, "PredriveL Mixer"},
+	{"PREDRIVER", NULL, "PredriveR Mixer"},
+	{"HSOL", NULL, "HeadsetL PGA"},
+	{"HSOR", NULL, "HeadsetR PGA"},
+	{"CARKITL", NULL, "CarkitL Mixer"},
+	{"CARKITR", NULL, "CarkitR Mixer"},
+	{"HFL", NULL, "HandsfreeL PGA"},
+	{"HFR", NULL, "HandsfreeR PGA"},
+	{"Vibra Route", "Audio", "Vibra Mux"},
+	{"VIBRA", NULL, "Vibra Route"},
 
 	/* Capture path */
 	{"Analog Left Capture Route", "Main mic", "MAINMIC"},
@@ -1168,18 +1427,22 @@
 	{"Left1 Analog Loopback", "Switch", "Analog Left Capture Route"},
 	{"Right2 Analog Loopback", "Switch", "Analog Right Capture Route"},
 	{"Left2 Analog Loopback", "Switch", "Analog Left Capture Route"},
+	{"Voice Analog Loopback", "Switch", "Analog Left Capture Route"},
 
 	{"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"},
 	{"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"},
 	{"Analog R2 Playback Mixer", NULL, "Right2 Analog Loopback"},
 	{"Analog L2 Playback Mixer", NULL, "Left2 Analog Loopback"},
+	{"Analog Voice Playback Mixer", NULL, "Voice Analog Loopback"},
 
 	/* Digital bypass routes */
 	{"Right Digital Loopback", "Volume", "TX1 Capture Route"},
 	{"Left Digital Loopback", "Volume", "TX1 Capture Route"},
+	{"Voice Digital Loopback", "Volume", "TX2 Capture Route"},
 
-	{"Analog R2 Playback Mixer", NULL, "Right Digital Loopback"},
-	{"Analog L2 Playback Mixer", NULL, "Left Digital Loopback"},
+	{"Digital R2 Playback Mixer", NULL, "Right Digital Loopback"},
+	{"Digital L2 Playback Mixer", NULL, "Left Digital Loopback"},
+	{"Digital Voice Playback Mixer", NULL, "Voice Digital Loopback"},
 
 };
 
@@ -1226,6 +1489,58 @@
 	return 0;
 }
 
+static void twl4030_constraints(struct twl4030_priv *twl4030,
+				struct snd_pcm_substream *mst_substream)
+{
+	struct snd_pcm_substream *slv_substream;
+
+	/* Pick the stream, which need to be constrained */
+	if (mst_substream == twl4030->master_substream)
+		slv_substream = twl4030->slave_substream;
+	else if (mst_substream == twl4030->slave_substream)
+		slv_substream = twl4030->master_substream;
+	else /* This should not happen.. */
+		return;
+
+	/* Set the constraints according to the already configured stream */
+	snd_pcm_hw_constraint_minmax(slv_substream->runtime,
+				SNDRV_PCM_HW_PARAM_RATE,
+				twl4030->rate,
+				twl4030->rate);
+
+	snd_pcm_hw_constraint_minmax(slv_substream->runtime,
+				SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+				twl4030->sample_bits,
+				twl4030->sample_bits);
+
+	snd_pcm_hw_constraint_minmax(slv_substream->runtime,
+				SNDRV_PCM_HW_PARAM_CHANNELS,
+				twl4030->channels,
+				twl4030->channels);
+}
+
+/* In case of 4 channel mode, the RX1 L/R for playback and the TX2 L/R for
+ * capture has to be enabled/disabled. */
+static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction,
+				int enable)
+{
+	u8 reg, mask;
+
+	reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION);
+
+	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+		mask = TWL4030_ARXL1_VRX_EN | TWL4030_ARXR1_EN;
+	else
+		mask = TWL4030_ATXL2_VTXL_EN | TWL4030_ATXR2_VTXR_EN;
+
+	if (enable)
+		reg |= mask;
+	else
+		reg &= ~mask;
+
+	twl4030_write(codec, TWL4030_REG_OPTION, reg);
+}
+
 static int twl4030_startup(struct snd_pcm_substream *substream,
 			   struct snd_soc_dai *dai)
 {
@@ -1234,26 +1549,25 @@
 	struct snd_soc_codec *codec = socdev->card->codec;
 	struct twl4030_priv *twl4030 = codec->private_data;
 
-	/* If we already have a playback or capture going then constrain
-	 * this substream to match it.
-	 */
 	if (twl4030->master_substream) {
-		struct snd_pcm_runtime *master_runtime;
-		master_runtime = twl4030->master_substream->runtime;
-
-		snd_pcm_hw_constraint_minmax(substream->runtime,
-					     SNDRV_PCM_HW_PARAM_RATE,
-					     master_runtime->rate,
-					     master_runtime->rate);
-
-		snd_pcm_hw_constraint_minmax(substream->runtime,
-					     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-					     master_runtime->sample_bits,
-					     master_runtime->sample_bits);
-
 		twl4030->slave_substream = substream;
-	} else
+		/* The DAI has one configuration for playback and capture, so
+		 * if the DAI has been already configured then constrain this
+		 * substream to match it. */
+		if (twl4030->configured)
+			twl4030_constraints(twl4030, twl4030->master_substream);
+	} else {
+		if (!(twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) &
+			TWL4030_OPTION_1)) {
+			/* In option2 4 channel is not supported, set the
+			 * constraint for the first stream for channels, the
+			 * second stream will 'inherit' this cosntraint */
+			snd_pcm_hw_constraint_minmax(substream->runtime,
+						SNDRV_PCM_HW_PARAM_CHANNELS,
+						2, 2);
+		}
 		twl4030->master_substream = substream;
+	}
 
 	return 0;
 }
@@ -1270,6 +1584,17 @@
 		twl4030->master_substream = twl4030->slave_substream;
 
 	twl4030->slave_substream = NULL;
+
+	/* If all streams are closed, or the remaining stream has not yet
+	 * been configured than set the DAI as not configured. */
+	if (!twl4030->master_substream)
+		twl4030->configured = 0;
+	 else if (!twl4030->master_substream->runtime->channels)
+		twl4030->configured = 0;
+
+	 /* If the closing substream had 4 channel, do the necessary cleanup */
+	if (substream->runtime->channels == 4)
+		twl4030_tdm_enable(codec, substream->stream, 0);
 }
 
 static int twl4030_hw_params(struct snd_pcm_substream *substream,
@@ -1282,8 +1607,24 @@
 	struct twl4030_priv *twl4030 = codec->private_data;
 	u8 mode, old_mode, format, old_format;
 
-	if (substream == twl4030->slave_substream)
-		/* Ignoring hw_params for slave substream */
+	 /* If the substream has 4 channel, do the necessary setup */
+	if (params_channels(params) == 4) {
+		u8 format, mode;
+
+		format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
+		mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
+
+		/* Safety check: are we in the correct operating mode and
+		 * the interface is in TDM mode? */
+		if ((mode & TWL4030_OPTION_1) &&
+		    ((format & TWL4030_AIF_FORMAT) == TWL4030_AIF_FORMAT_TDM))
+			twl4030_tdm_enable(codec, substream->stream, 1);
+		else
+			return -EINVAL;
+	}
+
+	if (twl4030->configured)
+		/* Ignoring hw_params for already configured DAI */
 		return 0;
 
 	/* bit rate */
@@ -1363,6 +1704,21 @@
 		/* set CODECPDZ afterwards */
 		twl4030_codec_enable(codec, 1);
 	}
+
+	/* Store the important parameters for the DAI configuration and set
+	 * the DAI as configured */
+	twl4030->configured = 1;
+	twl4030->rate = params_rate(params);
+	twl4030->sample_bits = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
+	twl4030->channels = params_channels(params);
+
+	/* If both playback and capture streams are open, and one of them
+	 * is setting the hw parameters right now (since we are here), set
+	 * constraints to the other stream to match the current one. */
+	if (twl4030->slave_substream)
+		twl4030_constraints(twl4030, substream);
+
 	return 0;
 }
 
@@ -1370,17 +1726,21 @@
 		int clk_id, unsigned int freq, int dir)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
+	struct twl4030_priv *twl4030 = codec->private_data;
 	u8 infreq;
 
 	switch (freq) {
 	case 19200000:
 		infreq = TWL4030_APLL_INFREQ_19200KHZ;
+		twl4030->sysclk = 19200;
 		break;
 	case 26000000:
 		infreq = TWL4030_APLL_INFREQ_26000KHZ;
+		twl4030->sysclk = 26000;
 		break;
 	case 38400000:
 		infreq = TWL4030_APLL_INFREQ_38400KHZ;
+		twl4030->sysclk = 38400;
 		break;
 	default:
 		printk(KERN_ERR "TWL4030 set sysclk: unknown rate %d\n",
@@ -1424,6 +1784,9 @@
 	case SND_SOC_DAIFMT_I2S:
 		format |= TWL4030_AIF_FORMAT_CODEC;
 		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		format |= TWL4030_AIF_FORMAT_TDM;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -1443,6 +1806,180 @@
 	return 0;
 }
 
+/* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R
+ * (VTXL, VTXR) for uplink has to be enabled/disabled. */
+static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
+				int enable)
+{
+	u8 reg, mask;
+
+	reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION);
+
+	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+		mask = TWL4030_ARXL1_VRX_EN;
+	else
+		mask = TWL4030_ATXL2_VTXL_EN | TWL4030_ATXR2_VTXR_EN;
+
+	if (enable)
+		reg |= mask;
+	else
+		reg &= ~mask;
+
+	twl4030_write(codec, TWL4030_REG_OPTION, reg);
+}
+
+static int twl4030_voice_startup(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	u8 infreq;
+	u8 mode;
+
+	/* If the system master clock is not 26MHz, the voice PCM interface is
+	 * not avilable.
+	 */
+	infreq = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL)
+		& TWL4030_APLL_INFREQ;
+
+	if (infreq != TWL4030_APLL_INFREQ_26000KHZ) {
+		printk(KERN_ERR "TWL4030 voice startup: "
+			"MCLK is not 26MHz, call set_sysclk() on init\n");
+		return -EINVAL;
+	}
+
+	/* If the codec mode is not option2, the voice PCM interface is not
+	 * avilable.
+	 */
+	mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE)
+		& TWL4030_OPT_MODE;
+
+	if (mode != TWL4030_OPTION_2) {
+		printk(KERN_ERR "TWL4030 voice startup: "
+			"the codec mode is not option2\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	/* Enable voice digital filters */
+	twl4030_voice_enable(codec, substream->stream, 0);
+}
+
+static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	u8 old_mode, mode;
+
+	/* Enable voice digital filters */
+	twl4030_voice_enable(codec, substream->stream, 1);
+
+	/* bit rate */
+	old_mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE)
+		& ~(TWL4030_CODECPDZ);
+	mode = old_mode;
+
+	switch (params_rate(params)) {
+	case 8000:
+		mode &= ~(TWL4030_SEL_16K);
+		break;
+	case 16000:
+		mode |= TWL4030_SEL_16K;
+		break;
+	default:
+		printk(KERN_ERR "TWL4030 voice hw params: unknown rate %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	if (mode != old_mode) {
+		/* change rate and set CODECPDZ */
+		twl4030_codec_enable(codec, 0);
+		twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+		twl4030_codec_enable(codec, 1);
+	}
+
+	return 0;
+}
+
+static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 infreq;
+
+	switch (freq) {
+	case 26000000:
+		infreq = TWL4030_APLL_INFREQ_26000KHZ;
+		break;
+	default:
+		printk(KERN_ERR "TWL4030 voice set sysclk: unknown rate %d\n",
+			freq);
+		return -EINVAL;
+	}
+
+	infreq |= TWL4030_APLL_EN;
+	twl4030_write(codec, TWL4030_REG_APLL_CTL, infreq);
+
+	return 0;
+}
+
+static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 old_format, format;
+
+	/* get format */
+	old_format = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF);
+	format = old_format;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFM:
+		format &= ~(TWL4030_VIF_SLAVE_EN);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		format |= TWL4030_VIF_SLAVE_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_NF:
+		format &= ~(TWL4030_VIF_FORMAT);
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		format |= TWL4030_VIF_FORMAT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (format != old_format) {
+		/* change format and set CODECPDZ */
+		twl4030_codec_enable(codec, 0);
+		twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
+		twl4030_codec_enable(codec, 1);
+	}
+
+	return 0;
+}
+
 #define TWL4030_RATES	 (SNDRV_PCM_RATE_8000_48000)
 #define TWL4030_FORMATS	 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
 
@@ -1454,21 +1991,47 @@
 	.set_fmt	= twl4030_set_dai_fmt,
 };
 
-struct snd_soc_dai twl4030_dai = {
+static struct snd_soc_dai_ops twl4030_dai_voice_ops = {
+	.startup	= twl4030_voice_startup,
+	.shutdown	= twl4030_voice_shutdown,
+	.hw_params	= twl4030_voice_hw_params,
+	.set_sysclk	= twl4030_voice_set_dai_sysclk,
+	.set_fmt	= twl4030_voice_set_dai_fmt,
+};
+
+struct snd_soc_dai twl4030_dai[] = {
+{
 	.name = "twl4030",
 	.playback = {
-		.stream_name = "Playback",
+		.stream_name = "HiFi Playback",
 		.channels_min = 2,
-		.channels_max = 2,
+		.channels_max = 4,
 		.rates = TWL4030_RATES | SNDRV_PCM_RATE_96000,
 		.formats = TWL4030_FORMATS,},
 	.capture = {
 		.stream_name = "Capture",
 		.channels_min = 2,
-		.channels_max = 2,
+		.channels_max = 4,
 		.rates = TWL4030_RATES,
 		.formats = TWL4030_FORMATS,},
 	.ops = &twl4030_dai_ops,
+},
+{
+	.name = "twl4030 Voice",
+	.playback = {
+		.stream_name = "Voice Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = &twl4030_dai_voice_ops,
+},
 };
 EXPORT_SYMBOL_GPL(twl4030_dai);
 
@@ -1500,6 +2063,8 @@
 static int twl4030_init(struct snd_soc_device *socdev)
 {
 	struct snd_soc_codec *codec = socdev->card->codec;
+	struct twl4030_setup_data *setup = socdev->codec_data;
+	struct twl4030_priv *twl4030 = codec->private_data;
 	int ret = 0;
 
 	printk(KERN_INFO "TWL4030 Audio Codec init \n");
@@ -1509,14 +2074,31 @@
 	codec->read = twl4030_read_reg_cache;
 	codec->write = twl4030_write;
 	codec->set_bias_level = twl4030_set_bias_level;
-	codec->dai = &twl4030_dai;
-	codec->num_dai = 1;
+	codec->dai = twl4030_dai;
+	codec->num_dai = ARRAY_SIZE(twl4030_dai),
 	codec->reg_cache_size = sizeof(twl4030_reg);
 	codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg),
 					GFP_KERNEL);
 	if (codec->reg_cache == NULL)
 		return -ENOMEM;
 
+	/* Configuration for headset ramp delay from setup data */
+	if (setup) {
+		unsigned char hs_pop;
+
+		if (setup->sysclk)
+			twl4030->sysclk = setup->sysclk;
+		else
+			twl4030->sysclk = 26000;
+
+		hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
+		hs_pop &= ~TWL4030_RAMP_DELAY;
+		hs_pop |= (setup->ramp_delay_value << 2);
+		twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+	} else {
+		twl4030->sysclk = 26000;
+	}
+
 	/* register pcms */
 	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
 	if (ret < 0) {
@@ -1604,13 +2186,13 @@
 
 static int __init twl4030_modinit(void)
 {
-	return snd_soc_register_dai(&twl4030_dai);
+	return snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
 }
 module_init(twl4030_modinit);
 
 static void __exit twl4030_exit(void)
 {
-	snd_soc_unregister_dai(&twl4030_dai);
+	snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
 }
 module_exit(twl4030_exit);
 
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
index cb63765..fe5f395 100644
--- a/sound/soc/codecs/twl4030.h
+++ b/sound/soc/codecs/twl4030.h
@@ -92,8 +92,9 @@
 #define TWL4030_REG_VIBRA_PWM_SET	0x47
 #define TWL4030_REG_ANAMIC_GAIN		0x48
 #define TWL4030_REG_MISC_SET_2		0x49
+#define TWL4030_REG_SW_SHADOW		0x4A
 
-#define TWL4030_CACHEREGNUM	(TWL4030_REG_MISC_SET_2 + 1)
+#define TWL4030_CACHEREGNUM	(TWL4030_REG_SW_SHADOW + 1)
 
 /* Bitfield Definitions */
 
@@ -110,9 +111,22 @@
 #define TWL4030_APLL_RATE_44100		0x90
 #define TWL4030_APLL_RATE_48000		0xA0
 #define TWL4030_APLL_RATE_96000		0xE0
-#define TWL4030_SEL_16K			0x04
+#define TWL4030_SEL_16K			0x08
 #define TWL4030_CODECPDZ		0x02
 #define TWL4030_OPT_MODE		0x01
+#define TWL4030_OPTION_1		(1 << 0)
+#define TWL4030_OPTION_2		(0 << 0)
+
+/* TWL4030_OPTION (0x02) Fields */
+
+#define TWL4030_ATXL1_EN		(1 << 0)
+#define TWL4030_ATXR1_EN		(1 << 1)
+#define TWL4030_ATXL2_VTXL_EN		(1 << 2)
+#define TWL4030_ATXR2_VTXR_EN		(1 << 3)
+#define TWL4030_ARXL1_VRX_EN		(1 << 4)
+#define TWL4030_ARXR1_EN		(1 << 5)
+#define TWL4030_ARXL2_EN		(1 << 6)
+#define TWL4030_ARXR2_EN		(1 << 7)
 
 /* TWL4030_REG_MICBIAS_CTL (0x04) Fields */
 
@@ -171,6 +185,17 @@
 #define TWL4030_CLK256FS_EN		0x02
 #define TWL4030_AIF_EN			0x01
 
+/* VOICE_IF (0x0F) Fields */
+
+#define TWL4030_VIF_SLAVE_EN		0x80
+#define TWL4030_VIF_DIN_EN		0x40
+#define TWL4030_VIF_DOUT_EN		0x20
+#define TWL4030_VIF_SWAP		0x10
+#define TWL4030_VIF_FORMAT		0x08
+#define TWL4030_VIF_TRI_EN		0x04
+#define TWL4030_VIF_SUB_EN		0x02
+#define TWL4030_VIF_EN			0x01
+
 /* EAR_CTL (0x21) */
 #define TWL4030_EAR_GAIN		0x30
 
@@ -236,7 +261,19 @@
 #define TWL4030_SMOOTH_ANAVOL_EN	0x02
 #define TWL4030_DIGMIC_LR_SWAP_EN	0x01
 
-extern struct snd_soc_dai twl4030_dai;
+/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
+#define TWL4030_HFL_EN			0x01
+#define TWL4030_HFR_EN			0x02
+
+#define TWL4030_DAI_HIFI		0
+#define TWL4030_DAI_VOICE		1
+
+extern struct snd_soc_dai twl4030_dai[2];
 extern struct snd_soc_codec_device soc_codec_dev_twl4030;
 
+struct twl4030_setup_data {
+	unsigned int ramp_delay_value;
+	unsigned int sysclk;
+};
+
 #endif	/* End of __TWL4030_AUDIO_H__ */
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index ddefb8f..269b108 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -101,7 +101,7 @@
 	pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value);
 
 	if (reg >= UDA134X_REGS_NUM) {
-		printk(KERN_ERR "%s unkown register: reg: %d",
+		printk(KERN_ERR "%s unkown register: reg: %u",
 		       __func__, reg);
 		return -EINVAL;
 	}
@@ -296,7 +296,7 @@
 	struct snd_soc_codec *codec = codec_dai->codec;
 	struct uda134x_priv *uda134x = codec->private_data;
 
-	pr_debug("%s clk_id: %d, freq: %d, dir: %d\n", __func__,
+	pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
 		 clk_id, freq, dir);
 
 	/* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 0275321..e7348d3 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -1108,7 +1108,7 @@
 	if (ret < 0)
 		return ret;
 	dev_dbg(wm8350->dev,
-		"FLL in %d FLL out %d N 0x%x K 0x%x div %d ratio %d",
+		"FLL in %u FLL out %u N 0x%x K 0x%x div %d ratio %d",
 		freq_in, freq_out, fll_div.n, fll_div.k, fll_div.div,
 		fll_div.ratio);
 
diff --git a/sound/soc/codecs/wm8350.h b/sound/soc/codecs/wm8350.h
index d11bd92..d088eb4 100644
--- a/sound/soc/codecs/wm8350.h
+++ b/sound/soc/codecs/wm8350.h
@@ -13,6 +13,7 @@
 #define _WM8350_H
 
 #include <sound/soc.h>
+#include <linux/mfd/wm8350/audio.h>
 
 extern struct snd_soc_dai wm8350_dai;
 extern struct snd_soc_codec_device soc_codec_dev_wm8350;
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 510efa6..502eefa 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -954,7 +954,7 @@
 		factors->outdiv *= 2;
 		if (factors->outdiv > 32) {
 			dev_err(wm8400->wm8400->dev,
-				"Unsupported FLL output frequency %dHz\n",
+				"Unsupported FLL output frequency %uHz\n",
 				Fout);
 			return -EINVAL;
 		}
@@ -1003,7 +1003,7 @@
 	factors->k = K / 10;
 
 	dev_dbg(wm8400->wm8400->dev,
-		"FLL: Fref=%d Fout=%d N=%x K=%x, FRATIO=%x OUTDIV=%x\n",
+		"FLL: Fref=%u Fout=%u N=%x K=%x, FRATIO=%x OUTDIV=%x\n",
 		Fref, Fout,
 		factors->n, factors->k, factors->fratio, factors->outdiv);
 
@@ -1473,8 +1473,8 @@
 
 	codec = &priv->codec;
 	codec->private_data = priv;
-	codec->control_data = dev->dev.driver_data;
-	priv->wm8400 = dev->dev.driver_data;
+	codec->control_data = dev_get_drvdata(&dev->dev);
+	priv->wm8400 = dev_get_drvdata(&dev->dev);
 
 	ret = regulator_bulk_get(priv->wm8400->dev,
 				 ARRAY_SIZE(power), &power[0]);
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 6a4cea0..c8b8dba 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -298,7 +298,7 @@
 
 	if ((Ndiv < 6) || (Ndiv > 12))
 		printk(KERN_WARNING
-			"WM8510 N value %d outwith recommended range!d\n",
+			"WM8510 N value %u outwith recommended range!d\n",
 			Ndiv);
 
 	pll_div.n = Ndiv;
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 9f6be3d..86c4b24d 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -415,7 +415,7 @@
 	unsigned int K, Ndiv, Nmod;
 	int i;
 
-	pr_debug("wm8580: PLL %dHz->%dHz\n", source, target);
+	pr_debug("wm8580: PLL %uHz->%uHz\n", source, target);
 
 	/* Scale the output frequency up; the PLL should run in the
 	 * region of 90-100MHz.
@@ -447,7 +447,7 @@
 
 	if ((Ndiv < 5) || (Ndiv > 13)) {
 		printk(KERN_ERR
-			"WM8580 N=%d outside supported range\n", Ndiv);
+			"WM8580 N=%u outside supported range\n", Ndiv);
 		return -EINVAL;
 	}
 
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index e043e3f..7a20587 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -666,14 +666,14 @@
 	codec->hw_write = (hw_write_t)wm8731_spi_write;
 	codec->dev = &spi->dev;
 
-	spi->dev.driver_data = wm8731;
+	dev_set_drvdata(&spi->dev, wm8731);
 
 	return wm8731_register(wm8731);
 }
 
 static int __devexit wm8731_spi_remove(struct spi_device *spi)
 {
-	struct wm8731_priv *wm8731 = spi->dev.driver_data;
+	struct wm8731_priv *wm8731 = dev_get_drvdata(&spi->dev);
 
 	wm8731_unregister(wm8731);
 
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index a6e8f3f..d28eeac 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -703,7 +703,7 @@
 
 	if ((Ndiv < 6) || (Ndiv > 12))
 		printk(KERN_WARNING
-			"wm8753: unsupported N = %d\n", Ndiv);
+			"wm8753: unsupported N = %u\n", Ndiv);
 
 	pll_div->n = Ndiv;
 	Nmod = target % source;
@@ -1822,14 +1822,14 @@
 	codec->hw_write = (hw_write_t)wm8753_spi_write;
 	codec->dev = &spi->dev;
 
-	spi->dev.driver_data = wm8753;
+	dev_set_drvdata(&spi->dev, wm8753);
 
 	return wm8753_register(wm8753);
 }
 
 static int __devexit wm8753_spi_remove(struct spi_device *spi)
 {
-	struct wm8753_priv *wm8753 = spi->dev.driver_data;
+	struct wm8753_priv *wm8753 = dev_get_drvdata(&spi->dev);
 	wm8753_unregister(wm8753);
 	return 0;
 }
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 46c5ea1..3c78945 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -778,11 +778,11 @@
 	}
 
 	if (target > 100000000)
-		printk(KERN_WARNING "wm8900: FLL rate %d out of range, Fref=%d"
-		       " Fout=%d\n", target, Fref, Fout);
+		printk(KERN_WARNING "wm8900: FLL rate %u out of range, Fref=%u"
+		       " Fout=%u\n", target, Fref, Fout);
 	if (div > 32) {
 		printk(KERN_ERR "wm8900: Invalid FLL division rate %u, "
-		       "Fref=%d, Fout=%d, target=%d\n",
+		       "Fref=%u, Fout=%u, target=%u\n",
 		       div, Fref, Fout, target);
 		return -EINVAL;
 	}
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 8cf571f..d8a9222 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -217,7 +217,6 @@
 	int sysclk;
 
 	/* Reference counts */
-	int charge_pump_users;
 	int class_w_users;
 	int playback_active;
 	int capture_active;
@@ -373,6 +372,15 @@
 #define WM8903_OUTPUT_INT   0x2
 #define WM8903_OUTPUT_IN    0x1
 
+static int wm8903_cp_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	WARN_ON(event != SND_SOC_DAPM_POST_PMU);
+	mdelay(4);
+
+	return 0;
+}
+
 /*
  * Event for headphone and line out amplifier power changes.  Special
  * power up/down sequences are required in order to maximise pop/click
@@ -382,19 +390,20 @@
 			       struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
-	struct wm8903_priv *wm8903 = codec->private_data;
-	struct i2c_client *i2c = codec->control_data;
 	u16 val;
 	u16 reg;
+	u16 dcs_reg;
+	u16 dcs_bit;
 	int shift;
-	u16 cp_reg = wm8903_read(codec, WM8903_CHARGE_PUMP_0);
 
 	switch (w->reg) {
 	case WM8903_POWER_MANAGEMENT_2:
 		reg = WM8903_ANALOGUE_HP_0;
+		dcs_bit = 0 + w->shift;
 		break;
 	case WM8903_POWER_MANAGEMENT_3:
 		reg = WM8903_ANALOGUE_LINEOUT_0;
+		dcs_bit = 2 + w->shift;
 		break;
 	default:
 		BUG();
@@ -419,18 +428,6 @@
 		/* Short the output */
 		val &= ~(WM8903_OUTPUT_SHORT << shift);
 		wm8903_write(codec, reg, val);
-
-		wm8903->charge_pump_users++;
-
-		dev_dbg(&i2c->dev, "Charge pump use count now %d\n",
-			wm8903->charge_pump_users);
-
-		if (wm8903->charge_pump_users == 1) {
-			dev_dbg(&i2c->dev, "Enabling charge pump\n");
-			wm8903_write(codec, WM8903_CHARGE_PUMP_0,
-				     cp_reg | WM8903_CP_ENA);
-			mdelay(4);
-		}
 	}
 
 	if (event & SND_SOC_DAPM_POST_PMU) {
@@ -446,6 +443,11 @@
 		val |= (WM8903_OUTPUT_OUT << shift);
 		wm8903_write(codec, reg, val);
 
+		/* Enable the DC servo */
+		dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0);
+		dcs_reg |= dcs_bit;
+		wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg);
+
 		/* Remove the short */
 		val |= (WM8903_OUTPUT_SHORT << shift);
 		wm8903_write(codec, reg, val);
@@ -458,25 +460,17 @@
 		val &= ~(WM8903_OUTPUT_SHORT << shift);
 		wm8903_write(codec, reg, val);
 
+		/* Disable the DC servo */
+		dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0);
+		dcs_reg &= ~dcs_bit;
+		wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg);
+
 		/* Then disable the intermediate and output stages */
 		val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT |
 			  WM8903_OUTPUT_IN) << shift);
 		wm8903_write(codec, reg, val);
 	}
 
-	if (event & SND_SOC_DAPM_POST_PMD) {
-		wm8903->charge_pump_users--;
-
-		dev_dbg(&i2c->dev, "Charge pump use count now %d\n",
-			wm8903->charge_pump_users);
-
-		if (wm8903->charge_pump_users == 0) {
-			dev_dbg(&i2c->dev, "Disabling charge pump\n");
-			wm8903_write(codec, WM8903_CHARGE_PUMP_0,
-				     cp_reg & ~WM8903_CP_ENA);
-		}
-	}
-
 	return 0;
 }
 
@@ -539,6 +533,7 @@
 /* ALSA can only do steps of .01dB */
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
 
+static const DECLARE_TLV_DB_SCALE(digital_sidetone_tlv, -3600, 300, 0);
 static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
 
 static const DECLARE_TLV_DB_SCALE(drc_tlv_thresh, 0, 75, 0);
@@ -657,6 +652,16 @@
 	SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text);
 
 
+static const char *sidetone_text[] = {
+	"None", "Left", "Right"
+};
+
+static const struct soc_enum lsidetone_enum =
+	SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 2, 3, sidetone_text);
+
+static const struct soc_enum rsidetone_enum =
+	SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text);
+
 static const struct snd_kcontrol_new wm8903_snd_controls[] = {
 
 /* Input PGAs - No TLV since the scale depends on PGA mode */
@@ -700,6 +705,9 @@
 SOC_ENUM("ADC Companding Mode", adc_companding),
 SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0),
 
+SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8903_DAC_DIGITAL_0, 4, 8,
+	       12, 0, digital_sidetone_tlv),
+
 /* DAC */
 SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8903_DAC_DIGITAL_VOLUME_LEFT,
 		 WM8903_DAC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv),
@@ -762,6 +770,12 @@
 static const struct snd_kcontrol_new rinput_inv_mux =
 	SOC_DAPM_ENUM("Right Inverting Input Mux", rinput_inv_enum);
 
+static const struct snd_kcontrol_new lsidetone_mux =
+	SOC_DAPM_ENUM("DACL Sidetone Mux", lsidetone_enum);
+
+static const struct snd_kcontrol_new rsidetone_mux =
+	SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum);
+
 static const struct snd_kcontrol_new left_output_mixer[] = {
 SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0),
 SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0),
@@ -828,6 +842,9 @@
 SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8903_POWER_MANAGEMENT_6, 1, 0),
 SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8903_POWER_MANAGEMENT_6, 0, 0),
 
+SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &lsidetone_mux),
+SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &rsidetone_mux),
+
 SND_SOC_DAPM_DAC("DACL", "Left Playback", WM8903_POWER_MANAGEMENT_6, 3, 0),
 SND_SOC_DAPM_DAC("DACR", "Right Playback", WM8903_POWER_MANAGEMENT_6, 2, 0),
 
@@ -844,26 +861,29 @@
 SND_SOC_DAPM_PGA_E("Left Headphone Output PGA", WM8903_POWER_MANAGEMENT_2,
 		   1, 0, NULL, 0, wm8903_output_event,
 		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+		   SND_SOC_DAPM_PRE_PMD),
 SND_SOC_DAPM_PGA_E("Right Headphone Output PGA", WM8903_POWER_MANAGEMENT_2,
 		   0, 0, NULL, 0, wm8903_output_event,
 		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+		   SND_SOC_DAPM_PRE_PMD),
 
 SND_SOC_DAPM_PGA_E("Left Line Output PGA", WM8903_POWER_MANAGEMENT_3, 1, 0,
 		   NULL, 0, wm8903_output_event,
 		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+		   SND_SOC_DAPM_PRE_PMD),
 SND_SOC_DAPM_PGA_E("Right Line Output PGA", WM8903_POWER_MANAGEMENT_3, 0, 0,
 		   NULL, 0, wm8903_output_event,
 		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+		   SND_SOC_DAPM_PRE_PMD),
 
 SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0,
 		 NULL, 0),
 SND_SOC_DAPM_PGA("Right Speaker PGA", WM8903_POWER_MANAGEMENT_5, 0, 0,
 		 NULL, 0),
 
+SND_SOC_DAPM_SUPPLY("Charge Pump", WM8903_CHARGE_PUMP_0, 0, 0,
+		    wm8903_cp_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0),
 };
 
 static const struct snd_soc_dapm_route intercon[] = {
@@ -909,7 +929,19 @@
 	{ "Right Input PGA", NULL, "Right Input Mode Mux" },
 
 	{ "ADCL", NULL, "Left Input PGA" },
+	{ "ADCL", NULL, "CLK_DSP" },
 	{ "ADCR", NULL, "Right Input PGA" },
+	{ "ADCR", NULL, "CLK_DSP" },
+
+	{ "DACL Sidetone", "Left", "ADCL" },
+	{ "DACL Sidetone", "Right", "ADCR" },
+	{ "DACR Sidetone", "Left", "ADCL" },
+	{ "DACR Sidetone", "Right", "ADCR" },
+
+	{ "DACL", NULL, "DACL Sidetone" },
+	{ "DACL", NULL, "CLK_DSP" },
+	{ "DACR", NULL, "DACR Sidetone" },
+	{ "DACR", NULL, "CLK_DSP" },
 
 	{ "Left Output Mixer", "Left Bypass Switch", "Left Input PGA" },
 	{ "Left Output Mixer", "Right Bypass Switch", "Right Input PGA" },
@@ -951,6 +983,11 @@
 
 	{ "ROP", NULL, "Right Speaker PGA" },
 	{ "RON", NULL, "Right Speaker PGA" },
+
+	{ "Left Headphone Output PGA", NULL, "Charge Pump" },
+	{ "Right Headphone Output PGA", NULL, "Charge Pump" },
+	{ "Left Line Output PGA", NULL, "Charge Pump" },
+	{ "Right Line Output PGA", NULL, "Charge Pump" },
 };
 
 static int wm8903_add_widgets(struct snd_soc_codec *codec)
@@ -985,6 +1022,11 @@
 			wm8903_write(codec, WM8903_CLOCK_RATES_2,
 				     WM8903_CLK_SYS_ENA);
 
+			/* Change DC servo dither level in startup sequence */
+			wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11);
+			wm8903_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257);
+			wm8903_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2);
+
 			wm8903_run_sequence(codec, 0);
 			wm8903_sync_reg_cache(codec, codec->reg_cache);
 
@@ -1277,14 +1319,8 @@
 	if (wm8903->master_substream) {
 		master_runtime = wm8903->master_substream->runtime;
 
-		dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n",
-			master_runtime->sample_bits,
-			master_runtime->rate);
-
-		snd_pcm_hw_constraint_minmax(substream->runtime,
-					     SNDRV_PCM_HW_PARAM_RATE,
-					     master_runtime->rate,
-					     master_runtime->rate);
+		dev_dbg(&i2c->dev, "Constraining to %d bits\n",
+			master_runtime->sample_bits);
 
 		snd_pcm_hw_constraint_minmax(substream->runtime,
 					     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
@@ -1523,6 +1559,7 @@
 		 .formats = WM8903_FORMATS,
 	 },
 	.ops = &wm8903_dai_ops,
+	.symmetric_rates = 1,
 };
 EXPORT_SYMBOL_GPL(wm8903_dai);
 
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
new file mode 100644
index 0000000..b8e17d6
--- /dev/null
+++ b/sound/soc/codecs/wm8940.c
@@ -0,0 +1,955 @@
+/*
+ * wm8940.c  --  WM8940 ALSA Soc Audio driver
+ *
+ * Author: Jonathan Cameron <jic23@cam.ac.uk>
+ *
+ * Based on wm8510.c
+ *    Copyright  2006 Wolfson Microelectronics PLC.
+ *    Author:  Liam Girdwood <lrg@slimlogic.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.
+ *
+ * Not currently handled:
+ * Notch filter control
+ * AUXMode (inverting vs mixer)
+ * No means to obtain current gain if alc enabled.
+ * No use made of gpio
+ * Fast VMID discharge for power down
+ * Soft Start
+ * DLR and ALR Swaps not enabled
+ * Digital Sidetone not supported
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8940.h"
+
+struct wm8940_priv {
+	unsigned int sysclk;
+	u16 reg_cache[WM8940_CACHEREGNUM];
+	struct snd_soc_codec codec;
+};
+
+static u16 wm8940_reg_defaults[] = {
+	0x8940, /* Soft Reset */
+	0x0000, /* Power 1 */
+	0x0000, /* Power 2 */
+	0x0000, /* Power 3 */
+	0x0010, /* Interface Control */
+	0x0000, /* Companding Control */
+	0x0140, /* Clock Control */
+	0x0000, /* Additional Controls */
+	0x0000, /* GPIO Control */
+	0x0002, /* Auto Increment Control */
+	0x0000, /* DAC Control */
+	0x00FF, /* DAC Volume */
+	0,
+	0,
+	0x0100, /* ADC Control */
+	0x00FF, /* ADC Volume */
+	0x0000, /* Notch Filter 1 Control 1 */
+	0x0000, /* Notch Filter 1 Control 2 */
+	0x0000, /* Notch Filter 2 Control 1 */
+	0x0000, /* Notch Filter 2 Control 2 */
+	0x0000, /* Notch Filter 3 Control 1 */
+	0x0000, /* Notch Filter 3 Control 2 */
+	0x0000, /* Notch Filter 4 Control 1 */
+	0x0000, /* Notch Filter 4 Control 2 */
+	0x0032, /* DAC Limit Control 1 */
+	0x0000, /* DAC Limit Control 2 */
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0x0038, /* ALC Control 1 */
+	0x000B, /* ALC Control 2 */
+	0x0032, /* ALC Control 3 */
+	0x0000, /* Noise Gate */
+	0x0041, /* PLLN */
+	0x000C, /* PLLK1 */
+	0x0093, /* PLLK2 */
+	0x00E9, /* PLLK3 */
+	0,
+	0,
+	0x0030, /* ALC Control 4 */
+	0,
+	0x0002, /* Input Control */
+	0x0050, /* PGA Gain */
+	0,
+	0x0002, /* ADC Boost Control */
+	0,
+	0x0002, /* Output Control */
+	0x0000, /* Speaker Mixer Control */
+	0,
+	0,
+	0,
+	0x0079, /* Speaker Volume */
+	0,
+	0x0000, /* Mono Mixer Control */
+};
+
+static inline unsigned int wm8940_read_reg_cache(struct snd_soc_codec *codec,
+						 unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+
+	if (reg >= ARRAY_SIZE(wm8940_reg_defaults))
+		return -1;
+
+	return cache[reg];
+}
+
+static inline int wm8940_write_reg_cache(struct snd_soc_codec *codec,
+					  u16 reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+
+	if (reg >= ARRAY_SIZE(wm8940_reg_defaults))
+		return -1;
+
+	cache[reg] = value;
+
+	return 0;
+}
+
+static int wm8940_write(struct snd_soc_codec *codec, unsigned int reg,
+			unsigned int value)
+{
+	int ret;
+	u8 data[3] = { reg,
+		       (value & 0xff00) >> 8,
+		       (value & 0x00ff)
+	};
+
+	wm8940_write_reg_cache(codec, reg, value);
+
+	ret = codec->hw_write(codec->control_data, data, 3);
+
+	if (ret < 0)
+		return ret;
+	else if (ret != 3)
+		return -EIO;
+	return 0;
+}
+
+static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" };
+static const struct soc_enum wm8940_adc_companding_enum
+= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding);
+static const struct soc_enum wm8940_dac_companding_enum
+= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 3, 4, wm8940_companding);
+
+static const char *wm8940_alc_mode_text[] = {"ALC", "Limiter"};
+static const struct soc_enum wm8940_alc_mode_enum
+= SOC_ENUM_SINGLE(WM8940_ALC3, 8, 2, wm8940_alc_mode_text);
+
+static const char *wm8940_mic_bias_level_text[] = {"0.9", "0.65"};
+static const struct soc_enum wm8940_mic_bias_level_enum
+= SOC_ENUM_SINGLE(WM8940_INPUTCTL, 8, 2, wm8940_mic_bias_level_text);
+
+static const char *wm8940_filter_mode_text[] = {"Audio", "Application"};
+static const struct soc_enum wm8940_filter_mode_enum
+= SOC_ENUM_SINGLE(WM8940_ADC, 7, 2, wm8940_filter_mode_text);
+
+static DECLARE_TLV_DB_SCALE(wm8940_spk_vol_tlv, -5700, 100, 1);
+static DECLARE_TLV_DB_SCALE(wm8940_att_tlv, -1000, 1000, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_pga_vol_tlv, -1200, 75, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_alc_min_tlv, -1200, 600, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_alc_max_tlv, 675, 600, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_alc_tar_tlv, -2250, 50, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_lim_boost_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_lim_thresh_tlv, -600, 100, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_adc_tlv, -12750, 50, 1);
+static DECLARE_TLV_DB_SCALE(wm8940_capture_boost_vol_tlv, 0, 2000, 0);
+
+static const struct snd_kcontrol_new wm8940_snd_controls[] = {
+	SOC_SINGLE("Digital Loopback Switch", WM8940_COMPANDINGCTL,
+		   6, 1, 0),
+	SOC_ENUM("DAC Companding", wm8940_dac_companding_enum),
+	SOC_ENUM("ADC Companding", wm8940_adc_companding_enum),
+
+	SOC_ENUM("ALC Mode", wm8940_alc_mode_enum),
+	SOC_SINGLE("ALC Switch", WM8940_ALC1, 8, 1, 0),
+	SOC_SINGLE_TLV("ALC Capture Max Gain", WM8940_ALC1,
+		       3, 7, 1, wm8940_alc_max_tlv),
+	SOC_SINGLE_TLV("ALC Capture Min Gain", WM8940_ALC1,
+		       0, 7, 0, wm8940_alc_min_tlv),
+	SOC_SINGLE_TLV("ALC Capture Target", WM8940_ALC2,
+		       0, 14, 0, wm8940_alc_tar_tlv),
+	SOC_SINGLE("ALC Capture Hold", WM8940_ALC2, 4, 10, 0),
+	SOC_SINGLE("ALC Capture Decay", WM8940_ALC3, 4, 10, 0),
+	SOC_SINGLE("ALC Capture Attach", WM8940_ALC3, 0, 10, 0),
+	SOC_SINGLE("ALC ZC Switch", WM8940_ALC4, 1, 1, 0),
+	SOC_SINGLE("ALC Capture Noise Gate Switch", WM8940_NOISEGATE,
+		   3, 1, 0),
+	SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8940_NOISEGATE,
+		   0, 7, 0),
+
+	SOC_SINGLE("DAC Playback Limiter Switch", WM8940_DACLIM1, 8, 1, 0),
+	SOC_SINGLE("DAC Playback Limiter Attack", WM8940_DACLIM1, 0, 9, 0),
+	SOC_SINGLE("DAC Playback Limiter Decay", WM8940_DACLIM1, 4, 11, 0),
+	SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8940_DACLIM2,
+		       4, 9, 1, wm8940_lim_thresh_tlv),
+	SOC_SINGLE_TLV("DAC Playback Limiter Boost", WM8940_DACLIM2,
+		       0, 12, 0, wm8940_lim_boost_tlv),
+
+	SOC_SINGLE("Capture PGA ZC Switch", WM8940_PGAGAIN, 7, 1, 0),
+	SOC_SINGLE_TLV("Capture PGA Volume", WM8940_PGAGAIN,
+		       0, 63, 0, wm8940_pga_vol_tlv),
+	SOC_SINGLE_TLV("Digital Playback Volume", WM8940_DACVOL,
+		       0, 255, 0, wm8940_adc_tlv),
+	SOC_SINGLE_TLV("Digital Capture Volume", WM8940_ADCVOL,
+		       0, 255, 0, wm8940_adc_tlv),
+	SOC_ENUM("Mic Bias Level", wm8940_mic_bias_level_enum),
+	SOC_SINGLE_TLV("Capture Boost Volue", WM8940_ADCBOOST,
+		       8, 1, 0, wm8940_capture_boost_vol_tlv),
+	SOC_SINGLE_TLV("Speaker Playback Volume", WM8940_SPKVOL,
+		       0, 63, 0, wm8940_spk_vol_tlv),
+	SOC_SINGLE("Speaker Playback Switch", WM8940_SPKVOL,  6, 1, 1),
+
+	SOC_SINGLE_TLV("Speaker Mixer Line Bypass Volume", WM8940_SPKVOL,
+		       8, 1, 1, wm8940_att_tlv),
+	SOC_SINGLE("Speaker Playback ZC Switch", WM8940_SPKVOL, 7, 1, 0),
+
+	SOC_SINGLE("Mono Out Switch", WM8940_MONOMIX, 6, 1, 1),
+	SOC_SINGLE_TLV("Mono Mixer Line Bypass Volume", WM8940_MONOMIX,
+		       7, 1, 1, wm8940_att_tlv),
+
+	SOC_SINGLE("High Pass Filter Switch", WM8940_ADC, 8, 1, 0),
+	SOC_ENUM("High Pass Filter Mode", wm8940_filter_mode_enum),
+	SOC_SINGLE("High Pass Filter Cut Off", WM8940_ADC, 4, 7, 0),
+	SOC_SINGLE("ADC Inversion Switch", WM8940_ADC, 0, 1, 0),
+	SOC_SINGLE("DAC Inversion Switch", WM8940_DAC, 0, 1, 0),
+	SOC_SINGLE("DAC Auto Mute Switch", WM8940_DAC, 2, 1, 0),
+	SOC_SINGLE("ZC Timeout Clock Switch", WM8940_ADDCNTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8940_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", WM8940_SPKMIX, 1, 1, 0),
+	SOC_DAPM_SINGLE("Aux Playback Switch", WM8940_SPKMIX, 5, 1, 0),
+	SOC_DAPM_SINGLE("PCM Playback Switch", WM8940_SPKMIX, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8940_mono_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", WM8940_MONOMIX, 1, 1, 0),
+	SOC_DAPM_SINGLE("Aux Playback Switch", WM8940_MONOMIX, 2, 1, 0),
+	SOC_DAPM_SINGLE("PCM Playback Switch", WM8940_MONOMIX, 0, 1, 0),
+};
+
+static DECLARE_TLV_DB_SCALE(wm8940_boost_vol_tlv, -1500, 300, 1);
+static const struct snd_kcontrol_new wm8940_input_boost_controls[] = {
+	SOC_DAPM_SINGLE("Mic PGA Switch", WM8940_PGAGAIN, 6, 1, 1),
+	SOC_DAPM_SINGLE_TLV("Aux Volume", WM8940_ADCBOOST,
+			    0, 7, 0, wm8940_boost_vol_tlv),
+	SOC_DAPM_SINGLE_TLV("Mic Volume", WM8940_ADCBOOST,
+			    4, 7, 0, wm8940_boost_vol_tlv),
+};
+
+static const struct snd_kcontrol_new wm8940_micpga_controls[] = {
+	SOC_DAPM_SINGLE("AUX Switch", WM8940_INPUTCTL, 2, 1, 0),
+	SOC_DAPM_SINGLE("MICP Switch", WM8940_INPUTCTL, 0, 1, 0),
+	SOC_DAPM_SINGLE("MICN Switch", WM8940_INPUTCTL, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8940_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Speaker Mixer", WM8940_POWER3, 2, 0,
+			   &wm8940_speaker_mixer_controls[0],
+			   ARRAY_SIZE(wm8940_speaker_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono Mixer", WM8940_POWER3, 3, 0,
+			   &wm8940_mono_mixer_controls[0],
+			   ARRAY_SIZE(wm8940_mono_mixer_controls)),
+	SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8940_POWER3, 0, 0),
+
+	SND_SOC_DAPM_PGA("SpkN Out", WM8940_POWER3, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SpkP Out", WM8940_POWER3, 6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono Out", WM8940_POWER3, 7, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("MONOOUT"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+
+	SND_SOC_DAPM_PGA("Aux Input", WM8940_POWER1, 6, 0, NULL, 0),
+	SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8940_POWER2, 0, 0),
+	SND_SOC_DAPM_MIXER("Mic PGA", WM8940_POWER2, 2, 0,
+			   &wm8940_micpga_controls[0],
+			   ARRAY_SIZE(wm8940_micpga_controls)),
+	SND_SOC_DAPM_MIXER("Boost Mixer", WM8940_POWER2, 4, 0,
+			   &wm8940_input_boost_controls[0],
+			   ARRAY_SIZE(wm8940_input_boost_controls)),
+	SND_SOC_DAPM_MICBIAS("Mic Bias", WM8940_POWER1, 4, 0),
+
+	SND_SOC_DAPM_INPUT("MICN"),
+	SND_SOC_DAPM_INPUT("MICP"),
+	SND_SOC_DAPM_INPUT("AUX"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* Mono output mixer */
+	{"Mono Mixer", "PCM Playback Switch", "DAC"},
+	{"Mono Mixer", "Aux Playback Switch", "Aux Input"},
+	{"Mono Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+	/* Speaker output mixer */
+	{"Speaker Mixer", "PCM Playback Switch", "DAC"},
+	{"Speaker Mixer", "Aux Playback Switch", "Aux Input"},
+	{"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+	/* Outputs */
+	{"Mono Out", NULL, "Mono Mixer"},
+	{"MONOOUT", NULL, "Mono Out"},
+	{"SpkN Out", NULL, "Speaker Mixer"},
+	{"SpkP Out", NULL, "Speaker Mixer"},
+	{"SPKOUTN", NULL, "SpkN Out"},
+	{"SPKOUTP", NULL, "SpkP Out"},
+
+	/*  Microphone PGA */
+	{"Mic PGA", "MICN Switch", "MICN"},
+	{"Mic PGA", "MICP Switch", "MICP"},
+	{"Mic PGA", "AUX Switch", "AUX"},
+
+	/* Boost Mixer */
+	{"Boost Mixer", "Mic PGA Switch", "Mic PGA"},
+	{"Boost Mixer", "Mic Volume",  "MICP"},
+	{"Boost Mixer", "Aux Volume", "Aux Input"},
+
+	{"ADC", NULL, "Boost Mixer"},
+};
+
+static int wm8940_add_widgets(struct snd_soc_codec *codec)
+{
+	int ret;
+
+	ret = snd_soc_dapm_new_controls(codec, wm8940_dapm_widgets,
+					ARRAY_SIZE(wm8940_dapm_widgets));
+	if (ret)
+		goto error_ret;
+	ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+	if (ret)
+		goto error_ret;
+	ret = snd_soc_dapm_new_widgets(codec);
+
+error_ret:
+	return ret;
+}
+
+#define wm8940_reset(c) wm8940_write(c, WM8940_SOFTRESET, 0);
+
+static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFE67;
+	u16 clk = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0x1fe;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		clk |= 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+	wm8940_write(codec, WM8940_CLOCK, clk);
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= (2 << 3);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= (1 << 3);
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= (3 << 3);
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= (3 << 3) | (1 << 7);
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= (1 << 7);
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= (1 << 8);
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= (1 << 8) | (1 << 7);
+		break;
+	}
+
+	wm8940_write(codec, WM8940_IFACE, iface);
+
+	return 0;
+}
+
+static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFD9F;
+	u16 addcntrl = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFF1;
+	u16 companding =  wm8940_read_reg_cache(codec,
+						WM8940_COMPANDINGCTL) & 0xFFDF;
+	int ret;
+
+	/* LoutR control */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE
+	    && params_channels(params) == 2)
+		iface |= (1 << 9);
+
+	switch (params_rate(params)) {
+	case SNDRV_PCM_RATE_8000:
+		addcntrl |= (0x5 << 1);
+		break;
+	case SNDRV_PCM_RATE_11025:
+		addcntrl |= (0x4 << 1);
+		break;
+	case SNDRV_PCM_RATE_16000:
+		addcntrl |= (0x3 << 1);
+		break;
+	case SNDRV_PCM_RATE_22050:
+		addcntrl |= (0x2 << 1);
+		break;
+	case SNDRV_PCM_RATE_32000:
+		addcntrl |= (0x1 << 1);
+		break;
+	case SNDRV_PCM_RATE_44100:
+	case SNDRV_PCM_RATE_48000:
+		break;
+	}
+	ret = wm8940_write(codec, WM8940_ADDCNTRL, addcntrl);
+	if (ret)
+		goto error_ret;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		companding = companding | (1 << 5);
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= (1 << 5);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= (2 << 5);
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		iface |= (3 << 5);
+		break;
+	}
+	ret = wm8940_write(codec, WM8940_COMPANDINGCTL, companding);
+	if (ret)
+		goto error_ret;
+	ret = wm8940_write(codec, WM8940_IFACE, iface);
+
+error_ret:
+	return ret;
+}
+
+static int wm8940_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 mute_reg = wm8940_read_reg_cache(codec, WM8940_DAC) & 0xffbf;
+
+	if (mute)
+		mute_reg |= 0x40;
+
+	return wm8940_write(codec, WM8940_DAC, mute_reg);
+}
+
+static int wm8940_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	u16 val;
+	u16 pwr_reg = wm8940_read_reg_cache(codec, WM8940_POWER1) & 0x1F0;
+	int ret = 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* ensure bufioen and biasen */
+		pwr_reg |= (1 << 2) | (1 << 3);
+		/* Enable thermal shutdown */
+		val = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL);
+		ret = wm8940_write(codec, WM8940_OUTPUTCTL, val | 0x2);
+		if (ret)
+			break;
+		/* set vmid to 75k */
+		ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* ensure bufioen and biasen */
+		pwr_reg |= (1 << 2) | (1 << 3);
+		ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* ensure bufioen and biasen */
+		pwr_reg |= (1 << 2) | (1 << 3);
+		/* set vmid to 300k for standby */
+		ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x2);
+		break;
+	case SND_SOC_BIAS_OFF:
+		ret = wm8940_write(codec, WM8940_POWER1, pwr_reg);
+		break;
+	}
+
+	return ret;
+}
+
+struct pll_ {
+	unsigned int pre_scale:2;
+	unsigned int n:4;
+	unsigned int k;
+};
+
+static struct pll_ pll_div;
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 24) * 10)
+static void pll_factors(unsigned int target, unsigned int source)
+{
+	unsigned long long Kpart;
+	unsigned int K, Ndiv, Nmod;
+	/* The left shift ist to avoid accuracy loss when right shifting */
+	Ndiv = target / source;
+
+	if (Ndiv > 12) {
+		source <<= 1;
+		/* Multiply by 2 */
+		pll_div.pre_scale = 0;
+		Ndiv = target / source;
+	} else if (Ndiv < 3) {
+		source >>= 2;
+		/* Divide by 4 */
+		pll_div.pre_scale = 3;
+		Ndiv = target / source;
+	} else if (Ndiv < 6) {
+		source >>= 1;
+		/* divide by 2 */
+		pll_div.pre_scale = 2;
+		Ndiv = target / source;
+	} else
+		pll_div.pre_scale = 1;
+
+	if ((Ndiv < 6) || (Ndiv > 12))
+		printk(KERN_WARNING
+			"WM8940 N value %d outwith recommended range!d\n",
+			Ndiv);
+
+	pll_div.n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	/* Check if we need to round */
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	K /= 10;
+
+	pll_div.k = K;
+}
+
+/* Untested at the moment */
+static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai,
+		int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 reg;
+
+	/* Turn off PLL */
+	reg = wm8940_read_reg_cache(codec, WM8940_POWER1);
+	wm8940_write(codec, WM8940_POWER1, reg & 0x1df);
+
+	if (freq_in == 0 || freq_out == 0) {
+		/* Clock CODEC directly from MCLK */
+		reg = wm8940_read_reg_cache(codec, WM8940_CLOCK);
+		wm8940_write(codec, WM8940_CLOCK, reg & 0x0ff);
+		/* Pll power down */
+		wm8940_write(codec, WM8940_PLLN, (1 << 7));
+		return 0;
+	}
+
+	/* Pll is followed by a frequency divide by 4 */
+	pll_factors(freq_out*4, freq_in);
+	if (pll_div.k)
+		wm8940_write(codec, WM8940_PLLN,
+			     (pll_div.pre_scale << 4) | pll_div.n | (1 << 6));
+	else /* No factional component */
+		wm8940_write(codec, WM8940_PLLN,
+			     (pll_div.pre_scale << 4) | pll_div.n);
+	wm8940_write(codec, WM8940_PLLK1, pll_div.k >> 18);
+	wm8940_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff);
+	wm8940_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff);
+	/* Enable the PLL */
+	reg = wm8940_read_reg_cache(codec, WM8940_POWER1);
+	wm8940_write(codec, WM8940_POWER1, reg | 0x020);
+
+	/* Run CODEC from PLL instead of MCLK */
+	reg = wm8940_read_reg_cache(codec, WM8940_CLOCK);
+	wm8940_write(codec, WM8940_CLOCK, reg | 0x100);
+
+	return 0;
+}
+
+static int wm8940_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct wm8940_priv *wm8940 = codec->private_data;
+
+	switch (freq) {
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 16934400:
+	case 18432000:
+		wm8940->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+				 int div_id, int div)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 reg;
+	int ret = 0;
+
+	switch (div_id) {
+	case WM8940_BCLKDIV:
+		reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFFEF3;
+		ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 2));
+		break;
+	case WM8940_MCLKDIV:
+		reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFF1F;
+		ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 5));
+		break;
+	case WM8940_OPCLKDIV:
+		reg = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFCF;
+		ret = wm8940_write(codec, WM8940_ADDCNTRL, reg | (div << 4));
+		break;
+	}
+	return ret;
+}
+
+#define WM8940_RATES SNDRV_PCM_RATE_8000_48000
+
+#define WM8940_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)
+
+static struct snd_soc_dai_ops wm8940_dai_ops = {
+	.hw_params = wm8940_i2s_hw_params,
+	.set_sysclk = wm8940_set_dai_sysclk,
+	.digital_mute = wm8940_mute,
+	.set_fmt = wm8940_set_dai_fmt,
+	.set_clkdiv = wm8940_set_dai_clkdiv,
+	.set_pll = wm8940_set_dai_pll,
+};
+
+struct snd_soc_dai wm8940_dai = {
+	.name = "WM8940",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8940_RATES,
+		.formats = WM8940_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8940_RATES,
+		.formats = WM8940_FORMATS,
+	},
+	.ops = &wm8940_dai_ops,
+	.symmetric_rates = 1,
+};
+EXPORT_SYMBOL_GPL(wm8940_dai);
+
+static int wm8940_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
+}
+
+static int wm8940_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+	int i;
+	int ret;
+	u8 data[3];
+	u16 *cache = codec->reg_cache;
+
+	/* Sync reg_cache with the hardware
+	 * Could use auto incremented writes to speed this up
+	 */
+	for (i = 0; i < ARRAY_SIZE(wm8940_reg_defaults); i++) {
+		data[0] = i;
+		data[1] = (cache[i] & 0xFF00) >> 8;
+		data[2] = cache[i] & 0x00FF;
+		ret = codec->hw_write(codec->control_data, data, 3);
+		if (ret < 0)
+			goto error_ret;
+		else if (ret != 3) {
+			ret = -EIO;
+			goto error_ret;
+		}
+	}
+	ret = wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	if (ret)
+		goto error_ret;
+	ret = wm8940_set_bias_level(codec, codec->suspend_bias_level);
+
+error_ret:
+	return ret;
+}
+
+static struct snd_soc_codec *wm8940_codec;
+
+static int wm8940_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+
+	int ret = 0;
+
+	if (wm8940_codec == NULL) {
+		dev_err(&pdev->dev, "Codec device not registered\n");
+		return -ENODEV;
+	}
+
+	socdev->card->codec = wm8940_codec;
+	codec = wm8940_codec;
+
+	mutex_init(&codec->mutex);
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+		goto pcm_err;
+	}
+
+	ret = snd_soc_add_controls(codec, wm8940_snd_controls,
+			     ARRAY_SIZE(wm8940_snd_controls));
+	if (ret)
+		goto error_free_pcms;
+	ret = wm8940_add_widgets(codec);
+	if (ret)
+		goto error_free_pcms;
+
+	ret = snd_soc_init_card(socdev);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to register card: %d\n", ret);
+		goto error_free_pcms;
+	}
+
+	return ret;
+
+error_free_pcms:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	return ret;
+}
+
+static int wm8940_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8940 = {
+	.probe = wm8940_probe,
+	.remove = wm8940_remove,
+	.suspend = wm8940_suspend,
+	.resume = wm8940_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940);
+
+static int wm8940_register(struct wm8940_priv *wm8940)
+{
+	struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data;
+	struct snd_soc_codec *codec = &wm8940->codec;
+	int ret;
+	u16 reg;
+	if (wm8940_codec) {
+		dev_err(codec->dev, "Another WM8940 is registered\n");
+		return -EINVAL;
+	}
+
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	codec->private_data = wm8940;
+	codec->name = "WM8940";
+	codec->owner = THIS_MODULE;
+	codec->read = wm8940_read_reg_cache;
+	codec->write = wm8940_write;
+	codec->bias_level = SND_SOC_BIAS_OFF;
+	codec->set_bias_level = wm8940_set_bias_level;
+	codec->dai = &wm8940_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults);
+	codec->reg_cache = &wm8940->reg_cache;
+
+	memcpy(codec->reg_cache, wm8940_reg_defaults,
+	       sizeof(wm8940_reg_defaults));
+
+	ret = wm8940_reset(codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	wm8940_dai.dev = codec->dev;
+
+	wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	ret = wm8940_write(codec, WM8940_POWER1, 0x180);
+	if (ret < 0)
+		return ret;
+
+	if (!pdata)
+		dev_warn(codec->dev, "No platform data supplied\n");
+	else {
+		reg = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL);
+		ret = wm8940_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi);
+		if (ret < 0)
+			return ret;
+	}
+
+
+	wm8940_codec = codec;
+
+	ret = snd_soc_register_codec(codec);
+	if (ret) {
+		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_register_dai(&wm8940_dai);
+	if (ret) {
+		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+		snd_soc_unregister_codec(codec);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void wm8940_unregister(struct wm8940_priv *wm8940)
+{
+	wm8940_set_bias_level(&wm8940->codec, SND_SOC_BIAS_OFF);
+	snd_soc_unregister_dai(&wm8940_dai);
+	snd_soc_unregister_codec(&wm8940->codec);
+	kfree(wm8940);
+	wm8940_codec = NULL;
+}
+
+static int wm8940_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8940_priv *wm8940;
+	struct snd_soc_codec *codec;
+
+	wm8940 = kzalloc(sizeof *wm8940, GFP_KERNEL);
+	if (wm8940 == NULL)
+		return -ENOMEM;
+
+	codec = &wm8940->codec;
+	codec->hw_write = (hw_write_t)i2c_master_send;
+	i2c_set_clientdata(i2c, wm8940);
+	codec->control_data = i2c;
+	codec->dev = &i2c->dev;
+
+	return wm8940_register(wm8940);
+}
+
+static int __devexit wm8940_i2c_remove(struct i2c_client *client)
+{
+	struct wm8940_priv *wm8940 = i2c_get_clientdata(client);
+
+	wm8940_unregister(wm8940);
+
+	return 0;
+}
+
+static const struct i2c_device_id wm8940_i2c_id[] = {
+	{ "wm8940", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id);
+
+static struct i2c_driver wm8940_i2c_driver = {
+	.driver = {
+		.name = "WM8940 I2C Codec",
+		.owner = THIS_MODULE,
+	},
+	.probe = wm8940_i2c_probe,
+	.remove = __devexit_p(wm8940_i2c_remove),
+	.id_table = wm8940_i2c_id,
+};
+
+static int __init wm8940_modinit(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&wm8940_i2c_driver);
+	if (ret)
+		printk(KERN_ERR "Failed to register WM8940 I2C driver: %d\n",
+		       ret);
+	return ret;
+}
+module_init(wm8940_modinit);
+
+static void __exit wm8940_exit(void)
+{
+	i2c_del_driver(&wm8940_i2c_driver);
+}
+module_exit(wm8940_exit);
+
+MODULE_DESCRIPTION("ASoC WM8940 driver");
+MODULE_AUTHOR("Jonathan Cameron");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8940.h b/sound/soc/codecs/wm8940.h
new file mode 100644
index 0000000..8410eed
--- /dev/null
+++ b/sound/soc/codecs/wm8940.h
@@ -0,0 +1,104 @@
+/*
+ * wm8940.h -- WM8940 Soc Audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8940_H
+#define _WM8940_H
+
+struct wm8940_setup_data {
+	/* Vref to analogue output resistance */
+#define WM8940_VROI_1K 0
+#define WM8940_VROI_30K 1
+	unsigned int vroi:1;
+};
+extern struct snd_soc_dai wm8940_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8940;
+
+/* WM8940 register space */
+#define WM8940_SOFTRESET	0x00
+#define WM8940_POWER1		0x01
+#define WM8940_POWER2		0x02
+#define WM8940_POWER3		0x03
+#define WM8940_IFACE		0x04
+#define WM8940_COMPANDINGCTL	0x05
+#define WM8940_CLOCK		0x06
+#define WM8940_ADDCNTRL		0x07
+#define WM8940_GPIO		0x08
+#define WM8940_CTLINT		0x09
+#define WM8940_DAC		0x0A
+#define WM8940_DACVOL		0x0B
+
+#define WM8940_ADC		0x0E
+#define WM8940_ADCVOL		0x0F
+#define WM8940_NOTCH1		0x10
+#define WM8940_NOTCH2		0x11
+#define WM8940_NOTCH3		0x12
+#define WM8940_NOTCH4		0x13
+#define WM8940_NOTCH5		0x14
+#define WM8940_NOTCH6		0x15
+#define WM8940_NOTCH7		0x16
+#define WM8940_NOTCH8		0x17
+#define WM8940_DACLIM1		0x18
+#define WM8940_DACLIM2		0x19
+
+#define WM8940_ALC1		0x20
+#define WM8940_ALC2		0x21
+#define WM8940_ALC3		0x22
+#define WM8940_NOISEGATE	0x23
+#define WM8940_PLLN		0x24
+#define WM8940_PLLK1		0x25
+#define WM8940_PLLK2		0x26
+#define WM8940_PLLK3		0x27
+
+#define WM8940_ALC4		0x2A
+
+#define WM8940_INPUTCTL		0x2C
+#define WM8940_PGAGAIN		0x2D
+
+#define WM8940_ADCBOOST		0x2F
+
+#define WM8940_OUTPUTCTL	0x31
+#define WM8940_SPKMIX		0x32
+
+#define WM8940_SPKVOL		0x36
+
+#define WM8940_MONOMIX		0x38
+
+#define WM8940_CACHEREGNUM  0x57
+
+
+/* Clock divider Id's */
+#define WM8940_BCLKDIV 0
+#define WM8940_MCLKDIV 1
+#define WM8940_OPCLKDIV 2
+
+/* MCLK clock dividers */
+#define WM8940_MCLKDIV_1	0
+#define WM8940_MCLKDIV_1_5	1
+#define WM8940_MCLKDIV_2	2
+#define WM8940_MCLKDIV_3	3
+#define WM8940_MCLKDIV_4	4
+#define WM8940_MCLKDIV_6	5
+#define WM8940_MCLKDIV_8	6
+#define WM8940_MCLKDIV_12	7
+
+/* BCLK clock dividers */
+#define WM8940_BCLKDIV_1 0
+#define WM8940_BCLKDIV_2 1
+#define WM8940_BCLKDIV_4 2
+#define WM8940_BCLKDIV_8 3
+#define WM8940_BCLKDIV_16 4
+#define WM8940_BCLKDIV_32 5
+
+/* PLL Out Dividers */
+#define WM8940_OPCLKDIV_1 0
+#define WM8940_OPCLKDIV_2 1
+#define WM8940_OPCLKDIV_3 2
+#define WM8940_OPCLKDIV_4 3
+
+#endif /* _WM8940_H */
+
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
new file mode 100644
index 0000000..e224d8a
--- /dev/null
+++ b/sound/soc/codecs/wm8960.c
@@ -0,0 +1,969 @@
+/*
+ * wm8960.c  --  WM8960 ALSA SoC Audio driver
+ *
+ * Author: Liam Girdwood
+ *
+ * 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/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8960.h"
+
+#define AUDIO_NAME "wm8960"
+
+struct snd_soc_codec_device soc_codec_dev_wm8960;
+
+/* R25 - Power 1 */
+#define WM8960_VREF      0x40
+
+/* R28 - Anti-pop 1 */
+#define WM8960_POBCTRL   0x80
+#define WM8960_BUFDCOPEN 0x10
+#define WM8960_BUFIOEN   0x08
+#define WM8960_SOFT_ST   0x04
+#define WM8960_HPSTBY    0x01
+
+/* R29 - Anti-pop 2 */
+#define WM8960_DISOP     0x40
+
+/*
+ * wm8960 register cache
+ * We can't read the WM8960 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ */
+static const u16 wm8960_reg[WM8960_CACHEREGNUM] = {
+	0x0097, 0x0097, 0x0000, 0x0000,
+	0x0000, 0x0008, 0x0000, 0x000a,
+	0x01c0, 0x0000, 0x00ff, 0x00ff,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x007b, 0x0100, 0x0032,
+	0x0000, 0x00c3, 0x00c3, 0x01c0,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0100, 0x0100, 0x0050, 0x0050,
+	0x0050, 0x0050, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0040, 0x0000,
+	0x0000, 0x0050, 0x0050, 0x0000,
+	0x0002, 0x0037, 0x004d, 0x0080,
+	0x0008, 0x0031, 0x0026, 0x00e9,
+};
+
+struct wm8960_priv {
+	u16 reg_cache[WM8960_CACHEREGNUM];
+	struct snd_soc_codec codec;
+};
+
+/*
+ * read wm8960 register cache
+ */
+static inline unsigned int wm8960_read_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg == WM8960_RESET)
+		return 0;
+	if (reg >= WM8960_CACHEREGNUM)
+		return -1;
+	return cache[reg];
+}
+
+/*
+ * write wm8960 register cache
+ */
+static inline void wm8960_write_reg_cache(struct snd_soc_codec *codec,
+	u16 reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg >= WM8960_CACHEREGNUM)
+		return;
+	cache[reg] = value;
+}
+
+static inline unsigned int wm8960_read(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	return wm8960_read_reg_cache(codec, reg);
+}
+
+/*
+ * write to the WM8960 register space
+ */
+static int wm8960_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	u8 data[2];
+
+	/* data is
+	 *   D15..D9 WM8960 register offset
+	 *   D8...D0 register data
+	 */
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
+
+	wm8960_write_reg_cache(codec, reg, value);
+	if (codec->hw_write(codec->control_data, data, 2) == 2)
+		return 0;
+	else
+		return -EIO;
+}
+
+#define wm8960_reset(c)	wm8960_write(c, WM8960_RESET, 0)
+
+/* enumerated controls */
+static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted",
+	"Right Inverted", "Stereo Inversion"};
+static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"};
+static const char *wm8960_3d_lower_cutoff[] = {"Low", "High"};
+static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"};
+static const char *wm8960_alcmode[] = {"ALC", "Limiter"};
+
+static const struct soc_enum wm8960_enum[] = {
+	SOC_ENUM_SINGLE(WM8960_DACCTL1, 1, 4, wm8960_deemph),
+	SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity),
+	SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity),
+	SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff),
+	SOC_ENUM_SINGLE(WM8960_3D, 5, 2, wm8960_3d_lower_cutoff),
+	SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc),
+	SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode),
+};
+
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+
+static const struct snd_kcontrol_new wm8960_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL,
+		 0, 63, 0, adc_tlv),
+SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL,
+	6, 1, 0),
+SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL,
+	7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Playback Volume", WM8960_LDAC, WM8960_RDAC,
+		 0, 255, 0, dac_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8960_LOUT1, WM8960_ROUT1,
+		 0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8960_LOUT1, WM8960_ROUT1,
+	7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8960_LOUT2, WM8960_ROUT2,
+		 0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8960_LOUT2, WM8960_ROUT2,
+	7, 1, 0),
+SOC_SINGLE("Speaker DC Volume", WM8960_CLASSD3, 3, 5, 0),
+SOC_SINGLE("Speaker AC Volume", WM8960_CLASSD3, 0, 5, 0),
+
+SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0),
+SOC_ENUM("ADC Polarity", wm8960_enum[1]),
+SOC_ENUM("Playback De-emphasis", wm8960_enum[0]),
+SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0),
+
+SOC_ENUM("DAC Polarity", wm8960_enum[2]),
+
+SOC_ENUM("3D Filter Upper Cut-Off", wm8960_enum[3]),
+SOC_ENUM("3D Filter Lower Cut-Off", wm8960_enum[4]),
+SOC_SINGLE("3D Volume", WM8960_3D, 1, 15, 0),
+SOC_SINGLE("3D Switch", WM8960_3D, 0, 1, 0),
+
+SOC_ENUM("ALC Function", wm8960_enum[5]),
+SOC_SINGLE("ALC Max Gain", WM8960_ALC1, 4, 7, 0),
+SOC_SINGLE("ALC Target", WM8960_ALC1, 0, 15, 1),
+SOC_SINGLE("ALC Min Gain", WM8960_ALC2, 4, 7, 0),
+SOC_SINGLE("ALC Hold Time", WM8960_ALC2, 0, 15, 0),
+SOC_ENUM("ALC Mode", wm8960_enum[6]),
+SOC_SINGLE("ALC Decay", WM8960_ALC3, 4, 15, 0),
+SOC_SINGLE("ALC Attack", WM8960_ALC3, 0, 15, 0),
+
+SOC_SINGLE("Noise Gate Threshold", WM8960_NOISEG, 3, 31, 0),
+SOC_SINGLE("Noise Gate Switch", WM8960_NOISEG, 0, 1, 0),
+
+SOC_DOUBLE_R("ADC PCM Capture Volume", WM8960_LINPATH, WM8960_RINPATH,
+	0, 127, 0),
+
+SOC_SINGLE_TLV("Left Output Mixer Boost Bypass Volume",
+	       WM8960_BYPASS1, 4, 7, 1, bypass_tlv),
+SOC_SINGLE_TLV("Left Output Mixer LINPUT3 Volume",
+	       WM8960_LOUTMIX, 4, 7, 1, bypass_tlv),
+SOC_SINGLE_TLV("Right Output Mixer Boost Bypass Volume",
+	       WM8960_BYPASS2, 4, 7, 1, bypass_tlv),
+SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume",
+	       WM8960_ROUTMIX, 4, 7, 1, bypass_tlv),
+};
+
+static const struct snd_kcontrol_new wm8960_lin_boost[] = {
+SOC_DAPM_SINGLE("LINPUT2 Switch", WM8960_LINPATH, 6, 1, 0),
+SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LINPATH, 7, 1, 0),
+SOC_DAPM_SINGLE("LINPUT1 Switch", WM8960_LINPATH, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_lin[] = {
+SOC_DAPM_SINGLE("Boost Switch", WM8960_LINPATH, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_rin_boost[] = {
+SOC_DAPM_SINGLE("RINPUT2 Switch", WM8960_RINPATH, 6, 1, 0),
+SOC_DAPM_SINGLE("RINPUT3 Switch", WM8960_RINPATH, 7, 1, 0),
+SOC_DAPM_SINGLE("RINPUT1 Switch", WM8960_RINPATH, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_rin[] = {
+SOC_DAPM_SINGLE("Boost Switch", WM8960_RINPATH, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_loutput_mixer[] = {
+SOC_DAPM_SINGLE("PCM Playback Switch", WM8960_LOUTMIX, 8, 1, 0),
+SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LOUTMIX, 7, 1, 0),
+SOC_DAPM_SINGLE("Boost Bypass Switch", WM8960_BYPASS1, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_routput_mixer[] = {
+SOC_DAPM_SINGLE("PCM Playback Switch", WM8960_ROUTMIX, 8, 1, 0),
+SOC_DAPM_SINGLE("RINPUT3 Switch", WM8960_ROUTMIX, 7, 1, 0),
+SOC_DAPM_SINGLE("Boost Bypass Switch", WM8960_BYPASS2, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_mono_out[] = {
+SOC_DAPM_SINGLE("Left Switch", WM8960_MONOMIX1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Switch", WM8960_MONOMIX2, 7, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8960_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("LINPUT1"),
+SND_SOC_DAPM_INPUT("RINPUT1"),
+SND_SOC_DAPM_INPUT("LINPUT2"),
+SND_SOC_DAPM_INPUT("RINPUT2"),
+SND_SOC_DAPM_INPUT("LINPUT3"),
+SND_SOC_DAPM_INPUT("RINPUT3"),
+
+SND_SOC_DAPM_MICBIAS("MICB", WM8960_POWER1, 1, 0),
+
+SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8960_POWER1, 5, 0,
+		   wm8960_lin_boost, ARRAY_SIZE(wm8960_lin_boost)),
+SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8960_POWER1, 4, 0,
+		   wm8960_rin_boost, ARRAY_SIZE(wm8960_rin_boost)),
+
+SND_SOC_DAPM_MIXER("Left Input Mixer", WM8960_POWER3, 5, 0,
+		   wm8960_lin, ARRAY_SIZE(wm8960_lin)),
+SND_SOC_DAPM_MIXER("Right Input Mixer", WM8960_POWER3, 4, 0,
+		   wm8960_rin, ARRAY_SIZE(wm8960_rin)),
+
+SND_SOC_DAPM_ADC("Left ADC", "Capture", WM8960_POWER2, 3, 0),
+SND_SOC_DAPM_ADC("Right ADC", "Capture", WM8960_POWER2, 2, 0),
+
+SND_SOC_DAPM_DAC("Left DAC", "Playback", WM8960_POWER2, 8, 0),
+SND_SOC_DAPM_DAC("Right DAC", "Playback", WM8960_POWER2, 7, 0),
+
+SND_SOC_DAPM_MIXER("Left Output Mixer", WM8960_POWER3, 3, 0,
+	&wm8960_loutput_mixer[0],
+	ARRAY_SIZE(wm8960_loutput_mixer)),
+SND_SOC_DAPM_MIXER("Right Output Mixer", WM8960_POWER3, 2, 0,
+	&wm8960_routput_mixer[0],
+	ARRAY_SIZE(wm8960_routput_mixer)),
+
+SND_SOC_DAPM_MIXER("Mono Output Mixer", WM8960_POWER2, 1, 0,
+	&wm8960_mono_out[0],
+	ARRAY_SIZE(wm8960_mono_out)),
+
+SND_SOC_DAPM_PGA("LOUT1 PGA", WM8960_POWER2, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ROUT1 PGA", WM8960_POWER2, 5, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Left Speaker PGA", WM8960_POWER2, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Speaker PGA", WM8960_POWER2, 3, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Right Speaker Output", WM8960_CLASSD1, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Left Speaker Output", WM8960_CLASSD1, 6, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("SPK_LP"),
+SND_SOC_DAPM_OUTPUT("SPK_LN"),
+SND_SOC_DAPM_OUTPUT("HP_L"),
+SND_SOC_DAPM_OUTPUT("HP_R"),
+SND_SOC_DAPM_OUTPUT("SPK_RP"),
+SND_SOC_DAPM_OUTPUT("SPK_RN"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+};
+
+static const struct snd_soc_dapm_route audio_paths[] = {
+	{ "Left Boost Mixer", "LINPUT1 Switch", "LINPUT1" },
+	{ "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" },
+	{ "Left Boost Mixer", "LINPUT3 Switch", "LINPUT3" },
+
+	{ "Left Input Mixer", "Boost Switch", "Left Boost Mixer", },
+	{ "Left Input Mixer", NULL, "LINPUT1", },  /* Really Boost Switch */
+	{ "Left Input Mixer", NULL, "LINPUT2" },
+	{ "Left Input Mixer", NULL, "LINPUT3" },
+
+	{ "Right Boost Mixer", "RINPUT1 Switch", "RINPUT1" },
+	{ "Right Boost Mixer", "RINPUT2 Switch", "RINPUT2" },
+	{ "Right Boost Mixer", "RINPUT3 Switch", "RINPUT3" },
+
+	{ "Right Input Mixer", "Boost Switch", "Right Boost Mixer", },
+	{ "Right Input Mixer", NULL, "RINPUT1", },  /* Really Boost Switch */
+	{ "Right Input Mixer", NULL, "RINPUT2" },
+	{ "Right Input Mixer", NULL, "LINPUT3" },
+
+	{ "Left ADC", NULL, "Left Input Mixer" },
+	{ "Right ADC", NULL, "Right Input Mixer" },
+
+	{ "Left Output Mixer", "LINPUT3 Switch", "LINPUT3" },
+	{ "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer"} ,
+	{ "Left Output Mixer", "PCM Playback Switch", "Left DAC" },
+
+	{ "Right Output Mixer", "RINPUT3 Switch", "RINPUT3" },
+	{ "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" } ,
+	{ "Right Output Mixer", "PCM Playback Switch", "Right DAC" },
+
+	{ "Mono Output Mixer", "Left Switch", "Left Output Mixer" },
+	{ "Mono Output Mixer", "Right Switch", "Right Output Mixer" },
+
+	{ "LOUT1 PGA", NULL, "Left Output Mixer" },
+	{ "ROUT1 PGA", NULL, "Right Output Mixer" },
+
+	{ "HP_L", NULL, "LOUT1 PGA" },
+	{ "HP_R", NULL, "ROUT1 PGA" },
+
+	{ "Left Speaker PGA", NULL, "Left Output Mixer" },
+	{ "Right Speaker PGA", NULL, "Right Output Mixer" },
+
+	{ "Left Speaker Output", NULL, "Left Speaker PGA" },
+	{ "Right Speaker Output", NULL, "Right Speaker PGA" },
+
+	{ "SPK_LN", NULL, "Left Speaker Output" },
+	{ "SPK_LP", NULL, "Left Speaker Output" },
+	{ "SPK_RN", NULL, "Right Speaker Output" },
+	{ "SPK_RP", NULL, "Right Speaker Output" },
+
+	{ "OUT3", NULL, "Mono Output Mixer", }
+};
+
+static int wm8960_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, wm8960_dapm_widgets,
+				  ARRAY_SIZE(wm8960_dapm_widgets));
+
+	snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
+
+	snd_soc_dapm_new_widgets(codec);
+	return 0;
+}
+
+static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface |= 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface */
+	wm8960_write(codec, WM8960_IFACE1, iface);
+	return 0;
+}
+
+static int wm8960_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	u16 iface = wm8960_read(codec, WM8960_IFACE1) & 0xfff3;
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= 0x0004;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= 0x0008;
+		break;
+	}
+
+	/* set iface */
+	wm8960_write(codec, WM8960_IFACE1, iface);
+	return 0;
+}
+
+static int wm8960_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 mute_reg = wm8960_read(codec, WM8960_DACCTL1) & 0xfff7;
+
+	if (mute)
+		wm8960_write(codec, WM8960_DACCTL1, mute_reg | 0x8);
+	else
+		wm8960_write(codec, WM8960_DACCTL1, mute_reg);
+	return 0;
+}
+
+static int wm8960_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8960_data *pdata = codec->dev->platform_data;
+	u16 reg;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* Set VMID to 2x50k */
+		reg = wm8960_read(codec, WM8960_POWER1);
+		reg &= ~0x180;
+		reg |= 0x80;
+		wm8960_write(codec, WM8960_POWER1, reg);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->bias_level == SND_SOC_BIAS_OFF) {
+			/* Enable anti-pop features */
+			wm8960_write(codec, WM8960_APOP1,
+				     WM8960_POBCTRL | WM8960_SOFT_ST |
+				     WM8960_BUFDCOPEN | WM8960_BUFIOEN);
+
+			/* Discharge HP output */
+			reg = WM8960_DISOP;
+			if (pdata)
+				reg |= pdata->dres << 4;
+			wm8960_write(codec, WM8960_APOP2, reg);
+
+			msleep(400);
+
+			wm8960_write(codec, WM8960_APOP2, 0);
+
+			/* Enable & ramp VMID at 2x50k */
+			reg = wm8960_read(codec, WM8960_POWER1);
+			reg |= 0x80;
+			wm8960_write(codec, WM8960_POWER1, reg);
+			msleep(100);
+
+			/* Enable VREF */
+			wm8960_write(codec, WM8960_POWER1, reg | WM8960_VREF);
+
+			/* Disable anti-pop features */
+			wm8960_write(codec, WM8960_APOP1, WM8960_BUFIOEN);
+		}
+
+		/* Set VMID to 2x250k */
+		reg = wm8960_read(codec, WM8960_POWER1);
+		reg &= ~0x180;
+		reg |= 0x100;
+		wm8960_write(codec, WM8960_POWER1, reg);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* Enable anti-pop features */
+		wm8960_write(codec, WM8960_APOP1,
+			     WM8960_POBCTRL | WM8960_SOFT_ST |
+			     WM8960_BUFDCOPEN | WM8960_BUFIOEN);
+
+		/* Disable VMID and VREF, let them discharge */
+		wm8960_write(codec, WM8960_POWER1, 0);
+		msleep(600);
+
+		wm8960_write(codec, WM8960_APOP1, 0);
+		break;
+	}
+
+	codec->bias_level = level;
+
+	return 0;
+}
+
+/* PLL divisors */
+struct _pll_div {
+	u32 pre_div:1;
+	u32 n:4;
+	u32 k:24;
+};
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 24) * 10)
+
+static int pll_factors(unsigned int source, unsigned int target,
+		       struct _pll_div *pll_div)
+{
+	unsigned long long Kpart;
+	unsigned int K, Ndiv, Nmod;
+
+	pr_debug("WM8960 PLL: setting %dHz->%dHz\n", source, target);
+
+	/* Scale up target to PLL operating frequency */
+	target *= 4;
+
+	Ndiv = target / source;
+	if (Ndiv < 6) {
+		source >>= 1;
+		pll_div->pre_div = 1;
+		Ndiv = target / source;
+	} else
+		pll_div->pre_div = 0;
+
+	if ((Ndiv < 6) || (Ndiv > 12)) {
+		pr_err("WM8960 PLL: Unsupported N=%d\n", Ndiv);
+		return -EINVAL;
+	}
+
+	pll_div->n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	/* Check if we need to round */
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	K /= 10;
+
+	pll_div->k = K;
+
+	pr_debug("WM8960 PLL: N=%x K=%x pre_div=%d\n",
+		 pll_div->n, pll_div->k, pll_div->pre_div);
+
+	return 0;
+}
+
+static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai,
+		int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 reg;
+	static struct _pll_div pll_div;
+	int ret;
+
+	if (freq_in && freq_out) {
+		ret = pll_factors(freq_in, freq_out, &pll_div);
+		if (ret != 0)
+			return ret;
+	}
+
+	/* Disable the PLL: even if we are changing the frequency the
+	 * PLL needs to be disabled while we do so. */
+	wm8960_write(codec, WM8960_CLOCK1,
+		     wm8960_read(codec, WM8960_CLOCK1) & ~1);
+	wm8960_write(codec, WM8960_POWER2,
+		     wm8960_read(codec, WM8960_POWER2) & ~1);
+
+	if (!freq_in || !freq_out)
+		return 0;
+
+	reg = wm8960_read(codec, WM8960_PLL1) & ~0x3f;
+	reg |= pll_div.pre_div << 4;
+	reg |= pll_div.n;
+
+	if (pll_div.k) {
+		reg |= 0x20;
+
+		wm8960_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f);
+		wm8960_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff);
+		wm8960_write(codec, WM8960_PLL4, pll_div.k & 0x1ff);
+	}
+	wm8960_write(codec, WM8960_PLL1, reg);
+
+	/* Turn it on */
+	wm8960_write(codec, WM8960_POWER2,
+		     wm8960_read(codec, WM8960_POWER2) | 1);
+	msleep(250);
+	wm8960_write(codec, WM8960_CLOCK1,
+		     wm8960_read(codec, WM8960_CLOCK1) | 1);
+
+	return 0;
+}
+
+static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+		int div_id, int div)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 reg;
+
+	switch (div_id) {
+	case WM8960_SYSCLKSEL:
+		reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1fe;
+		wm8960_write(codec, WM8960_CLOCK1, reg | div);
+		break;
+	case WM8960_SYSCLKDIV:
+		reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1f9;
+		wm8960_write(codec, WM8960_CLOCK1, reg | div);
+		break;
+	case WM8960_DACDIV:
+		reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1c7;
+		wm8960_write(codec, WM8960_CLOCK1, reg | div);
+		break;
+	case WM8960_OPCLKDIV:
+		reg = wm8960_read(codec, WM8960_PLL1) & 0x03f;
+		wm8960_write(codec, WM8960_PLL1, reg | div);
+		break;
+	case WM8960_DCLKDIV:
+		reg = wm8960_read(codec, WM8960_CLOCK2) & 0x03f;
+		wm8960_write(codec, WM8960_CLOCK2, reg | div);
+		break;
+	case WM8960_TOCLKSEL:
+		reg = wm8960_read(codec, WM8960_ADDCTL1) & 0x1fd;
+		wm8960_write(codec, WM8960_ADDCTL1, reg | div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+#define WM8960_RATES SNDRV_PCM_RATE_8000_48000
+
+#define WM8960_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8960_dai_ops = {
+	.hw_params = wm8960_hw_params,
+	.digital_mute = wm8960_mute,
+	.set_fmt = wm8960_set_dai_fmt,
+	.set_clkdiv = wm8960_set_dai_clkdiv,
+	.set_pll = wm8960_set_dai_pll,
+};
+
+struct snd_soc_dai wm8960_dai = {
+	.name = "WM8960",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8960_RATES,
+		.formats = WM8960_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8960_RATES,
+		.formats = WM8960_FORMATS,},
+	.ops = &wm8960_dai_ops,
+	.symmetric_rates = 1,
+};
+EXPORT_SYMBOL_GPL(wm8960_dai);
+
+static int wm8960_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	wm8960_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8960_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+	int i;
+	u8 data[2];
+	u16 *cache = codec->reg_cache;
+
+	/* Sync reg_cache with the hardware */
+	for (i = 0; i < ARRAY_SIZE(wm8960_reg); i++) {
+		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+		data[1] = cache[i] & 0x00ff;
+		codec->hw_write(codec->control_data, data, 2);
+	}
+
+	wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	wm8960_set_bias_level(codec, codec->suspend_bias_level);
+	return 0;
+}
+
+static struct snd_soc_codec *wm8960_codec;
+
+static int wm8960_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	if (wm8960_codec == NULL) {
+		dev_err(&pdev->dev, "Codec device not registered\n");
+		return -ENODEV;
+	}
+
+	socdev->card->codec = wm8960_codec;
+	codec = wm8960_codec;
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+		goto pcm_err;
+	}
+
+	snd_soc_add_controls(codec, wm8960_snd_controls,
+			     ARRAY_SIZE(wm8960_snd_controls));
+	wm8960_add_widgets(codec);
+	ret = snd_soc_init_card(socdev);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to register card: %d\n", ret);
+		goto card_err;
+	}
+
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	return ret;
+}
+
+/* power down chip */
+static int wm8960_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8960 = {
+	.probe = 	wm8960_probe,
+	.remove = 	wm8960_remove,
+	.suspend = 	wm8960_suspend,
+	.resume =	wm8960_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8960);
+
+static int wm8960_register(struct wm8960_priv *wm8960)
+{
+	struct wm8960_data *pdata = wm8960->codec.dev->platform_data;
+	struct snd_soc_codec *codec = &wm8960->codec;
+	int ret;
+	u16 reg;
+
+	if (wm8960_codec) {
+		dev_err(codec->dev, "Another WM8960 is registered\n");
+		return -EINVAL;
+	}
+
+	if (!pdata) {
+		dev_warn(codec->dev, "No platform data supplied\n");
+	} else {
+		if (pdata->dres > WM8960_DRES_MAX) {
+			dev_err(codec->dev, "Invalid DRES: %d\n", pdata->dres);
+			pdata->dres = 0;
+		}
+	}
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	codec->private_data = wm8960;
+	codec->name = "WM8960";
+	codec->owner = THIS_MODULE;
+	codec->read = wm8960_read_reg_cache;
+	codec->write = wm8960_write;
+	codec->bias_level = SND_SOC_BIAS_OFF;
+	codec->set_bias_level = wm8960_set_bias_level;
+	codec->dai = &wm8960_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = WM8960_CACHEREGNUM;
+	codec->reg_cache = &wm8960->reg_cache;
+
+	memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg));
+
+	ret = wm8960_reset(codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	wm8960_dai.dev = codec->dev;
+
+	wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	/* Latch the update bits */
+	reg = wm8960_read(codec, WM8960_LINVOL);
+	wm8960_write(codec, WM8960_LINVOL, reg | 0x100);
+	reg = wm8960_read(codec, WM8960_RINVOL);
+	wm8960_write(codec, WM8960_RINVOL, reg | 0x100);
+	reg = wm8960_read(codec, WM8960_LADC);
+	wm8960_write(codec, WM8960_LADC, reg | 0x100);
+	reg = wm8960_read(codec, WM8960_RADC);
+	wm8960_write(codec, WM8960_RADC, reg | 0x100);
+	reg = wm8960_read(codec, WM8960_LDAC);
+	wm8960_write(codec, WM8960_LDAC, reg | 0x100);
+	reg = wm8960_read(codec, WM8960_RDAC);
+	wm8960_write(codec, WM8960_RDAC, reg | 0x100);
+	reg = wm8960_read(codec, WM8960_LOUT1);
+	wm8960_write(codec, WM8960_LOUT1, reg | 0x100);
+	reg = wm8960_read(codec, WM8960_ROUT1);
+	wm8960_write(codec, WM8960_ROUT1, reg | 0x100);
+	reg = wm8960_read(codec, WM8960_LOUT2);
+	wm8960_write(codec, WM8960_LOUT2, reg | 0x100);
+	reg = wm8960_read(codec, WM8960_ROUT2);
+	wm8960_write(codec, WM8960_ROUT2, reg | 0x100);
+
+	wm8960_codec = codec;
+
+	ret = snd_soc_register_codec(codec);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_register_dai(&wm8960_dai);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+		snd_soc_unregister_codec(codec);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void wm8960_unregister(struct wm8960_priv *wm8960)
+{
+	wm8960_set_bias_level(&wm8960->codec, SND_SOC_BIAS_OFF);
+	snd_soc_unregister_dai(&wm8960_dai);
+	snd_soc_unregister_codec(&wm8960->codec);
+	kfree(wm8960);
+	wm8960_codec = NULL;
+}
+
+static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct wm8960_priv *wm8960;
+	struct snd_soc_codec *codec;
+
+	wm8960 = kzalloc(sizeof(struct wm8960_priv), GFP_KERNEL);
+	if (wm8960 == NULL)
+		return -ENOMEM;
+
+	codec = &wm8960->codec;
+	codec->hw_write = (hw_write_t)i2c_master_send;
+
+	i2c_set_clientdata(i2c, wm8960);
+	codec->control_data = i2c;
+
+	codec->dev = &i2c->dev;
+
+	return wm8960_register(wm8960);
+}
+
+static __devexit int wm8960_i2c_remove(struct i2c_client *client)
+{
+	struct wm8960_priv *wm8960 = i2c_get_clientdata(client);
+	wm8960_unregister(wm8960);
+	return 0;
+}
+
+static const struct i2c_device_id wm8960_i2c_id[] = {
+	{ "wm8960", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id);
+
+static struct i2c_driver wm8960_i2c_driver = {
+	.driver = {
+		.name = "WM8960 I2C Codec",
+		.owner = THIS_MODULE,
+	},
+	.probe =    wm8960_i2c_probe,
+	.remove =   __devexit_p(wm8960_i2c_remove),
+	.id_table = wm8960_i2c_id,
+};
+
+static int __init wm8960_modinit(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&wm8960_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n",
+		       ret);
+	}
+
+	return ret;
+}
+module_init(wm8960_modinit);
+
+static void __exit wm8960_exit(void)
+{
+	i2c_del_driver(&wm8960_i2c_driver);
+}
+module_exit(wm8960_exit);
+
+
+MODULE_DESCRIPTION("ASoC WM8960 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h
new file mode 100644
index 0000000..c9af56c
--- /dev/null
+++ b/sound/soc/codecs/wm8960.h
@@ -0,0 +1,127 @@
+/*
+ * wm8960.h  --  WM8960 Soc Audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8960_H
+#define _WM8960_H
+
+/* WM8960 register space */
+
+
+#define WM8960_CACHEREGNUM 	56
+
+#define WM8960_LINVOL		0x0
+#define WM8960_RINVOL		0x1
+#define WM8960_LOUT1		0x2
+#define WM8960_ROUT1		0x3
+#define WM8960_CLOCK1		0x4
+#define WM8960_DACCTL1		0x5
+#define WM8960_DACCTL2		0x6
+#define WM8960_IFACE1		0x7
+#define WM8960_CLOCK2		0x8
+#define WM8960_IFACE2		0x9
+#define WM8960_LDAC		0xa
+#define WM8960_RDAC		0xb
+
+#define WM8960_RESET		0xf
+#define WM8960_3D		0x10
+#define WM8960_ALC1		0x11
+#define WM8960_ALC2		0x12
+#define WM8960_ALC3		0x13
+#define WM8960_NOISEG		0x14
+#define WM8960_LADC		0x15
+#define WM8960_RADC		0x16
+#define WM8960_ADDCTL1		0x17
+#define WM8960_ADDCTL2		0x18
+#define WM8960_POWER1		0x19
+#define WM8960_POWER2		0x1a
+#define WM8960_ADDCTL3		0x1b
+#define WM8960_APOP1		0x1c
+#define WM8960_APOP2		0x1d
+
+#define WM8960_LINPATH		0x20
+#define WM8960_RINPATH		0x21
+#define WM8960_LOUTMIX		0x22
+
+#define WM8960_ROUTMIX		0x25
+#define WM8960_MONOMIX1		0x26
+#define WM8960_MONOMIX2		0x27
+#define WM8960_LOUT2		0x28
+#define WM8960_ROUT2		0x29
+#define WM8960_MONO		0x2a
+#define WM8960_INBMIX1		0x2b
+#define WM8960_INBMIX2		0x2c
+#define WM8960_BYPASS1		0x2d
+#define WM8960_BYPASS2		0x2e
+#define WM8960_POWER3		0x2f
+#define WM8960_ADDCTL4		0x30
+#define WM8960_CLASSD1		0x31
+
+#define WM8960_CLASSD3		0x33
+#define WM8960_PLL1		0x34
+#define WM8960_PLL2		0x35
+#define WM8960_PLL3		0x36
+#define WM8960_PLL4		0x37
+
+
+/*
+ * WM8960 Clock dividers
+ */
+#define WM8960_SYSCLKDIV 		0
+#define WM8960_DACDIV			1
+#define WM8960_OPCLKDIV			2
+#define WM8960_DCLKDIV			3
+#define WM8960_TOCLKSEL			4
+#define WM8960_SYSCLKSEL		5
+
+#define WM8960_SYSCLK_DIV_1		(0 << 1)
+#define WM8960_SYSCLK_DIV_2		(2 << 1)
+
+#define WM8960_SYSCLK_MCLK		(0 << 0)
+#define WM8960_SYSCLK_PLL		(1 << 0)
+
+#define WM8960_DAC_DIV_1		(0 << 3)
+#define WM8960_DAC_DIV_1_5		(1 << 3)
+#define WM8960_DAC_DIV_2		(2 << 3)
+#define WM8960_DAC_DIV_3		(3 << 3)
+#define WM8960_DAC_DIV_4		(4 << 3)
+#define WM8960_DAC_DIV_5_5		(5 << 3)
+#define WM8960_DAC_DIV_6		(6 << 3)
+
+#define WM8960_DCLK_DIV_1_5		(0 << 6)
+#define WM8960_DCLK_DIV_2		(1 << 6)
+#define WM8960_DCLK_DIV_3		(2 << 6)
+#define WM8960_DCLK_DIV_4		(3 << 6)
+#define WM8960_DCLK_DIV_6		(4 << 6)
+#define WM8960_DCLK_DIV_8		(5 << 6)
+#define WM8960_DCLK_DIV_12		(6 << 6)
+#define WM8960_DCLK_DIV_16		(7 << 6)
+
+#define WM8960_TOCLK_F19		(0 << 1)
+#define WM8960_TOCLK_F21		(1 << 1)
+
+#define WM8960_OPCLK_DIV_1		(0 << 0)
+#define WM8960_OPCLK_DIV_2		(1 << 0)
+#define WM8960_OPCLK_DIV_3		(2 << 0)
+#define WM8960_OPCLK_DIV_4		(3 << 0)
+#define WM8960_OPCLK_DIV_5_5		(4 << 0)
+#define WM8960_OPCLK_DIV_6		(5 << 0)
+
+extern struct snd_soc_dai wm8960_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8960;
+
+#define WM8960_DRES_400R 0
+#define WM8960_DRES_200R 1
+#define WM8960_DRES_600R 2
+#define WM8960_DRES_150R 3
+#define WM8960_DRES_MAX  3
+
+struct wm8960_data {
+	int dres;
+};
+
+#endif
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
new file mode 100644
index 0000000..c05f718
--- /dev/null
+++ b/sound/soc/codecs/wm8988.c
@@ -0,0 +1,1097 @@
+/*
+ * wm8988.c -- WM8988 ALSA SoC audio driver
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * 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/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8988.h"
+
+/*
+ * wm8988 register cache
+ * 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 */
+};
+
+/* codec private data */
+struct wm8988_priv {
+	unsigned int sysclk;
+	struct snd_soc_codec codec;
+	struct snd_pcm_hw_constraint_list *sysclk_constraints;
+	u16 reg_cache[WM8988_NUM_REG];
+};
+
+
+/*
+ * read wm8988 register cache
+ */
+static inline unsigned int wm8988_read_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg > WM8988_NUM_REG)
+		return -1;
+	return cache[reg];
+}
+
+/*
+ * write wm8988 register cache
+ */
+static inline void wm8988_write_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg > WM8988_NUM_REG)
+		return;
+	cache[reg] = value;
+}
+
+static int wm8988_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	u8 data[2];
+
+	/* data is
+	 *   D15..D9 WM8753 register offset
+	 *   D8...D0 register data
+	 */
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
+
+	wm8988_write_reg_cache(codec, reg, value);
+	if (codec->hw_write(codec->control_data, data, 2) == 2)
+		return 0;
+	else
+		return -EIO;
+}
+
+#define wm8988_reset(c)	wm8988_write(c, WM8988_RESET, 0)
+
+/*
+ * WM8988 Controls
+ */
+
+static const char *bass_boost_txt[] = {"Linear Control", "Adaptive Boost"};
+static const struct soc_enum bass_boost =
+	SOC_ENUM_SINGLE(WM8988_BASS, 7, 2, bass_boost_txt);
+
+static const char *bass_filter_txt[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };
+static const struct soc_enum bass_filter =
+	SOC_ENUM_SINGLE(WM8988_BASS, 6, 2, bass_filter_txt);
+
+static const char *treble_txt[] = {"8kHz", "4kHz"};
+static const struct soc_enum treble =
+	SOC_ENUM_SINGLE(WM8988_TREBLE, 6, 2, treble_txt);
+
+static const char *stereo_3d_lc_txt[] = {"200Hz", "500Hz"};
+static const struct soc_enum stereo_3d_lc =
+	SOC_ENUM_SINGLE(WM8988_3D, 5, 2, stereo_3d_lc_txt);
+
+static const char *stereo_3d_uc_txt[] = {"2.2kHz", "1.5kHz"};
+static const struct soc_enum stereo_3d_uc =
+	SOC_ENUM_SINGLE(WM8988_3D, 6, 2, stereo_3d_uc_txt);
+
+static const char *stereo_3d_func_txt[] = {"Capture", "Playback"};
+static const struct soc_enum stereo_3d_func =
+	SOC_ENUM_SINGLE(WM8988_3D, 7, 2, stereo_3d_func_txt);
+
+static const char *alc_func_txt[] = {"Off", "Right", "Left", "Stereo"};
+static const struct soc_enum alc_func =
+	SOC_ENUM_SINGLE(WM8988_ALC1, 7, 4, alc_func_txt);
+
+static const char *ng_type_txt[] = {"Constant PGA Gain",
+				    "Mute ADC Output"};
+static const struct soc_enum ng_type =
+	SOC_ENUM_SINGLE(WM8988_NGATE, 1, 2, ng_type_txt);
+
+static const char *deemph_txt[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+static const struct soc_enum deemph =
+	SOC_ENUM_SINGLE(WM8988_ADCDAC, 1, 4, deemph_txt);
+
+static const char *adcpol_txt[] = {"Normal", "L Invert", "R Invert",
+				   "L + R Invert"};
+static const struct soc_enum adcpol =
+	SOC_ENUM_SINGLE(WM8988_ADCDAC, 5, 4, adcpol_txt);
+
+static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+
+static const struct snd_kcontrol_new wm8988_snd_controls[] = {
+
+SOC_ENUM("Bass Boost", bass_boost),
+SOC_ENUM("Bass Filter", bass_filter),
+SOC_SINGLE("Bass Volume", WM8988_BASS, 0, 15, 1),
+
+SOC_SINGLE("Treble Volume", WM8988_TREBLE, 0, 15, 0),
+SOC_ENUM("Treble Cut-off", treble),
+
+SOC_SINGLE("3D Switch", WM8988_3D, 0, 1, 0),
+SOC_SINGLE("3D Volume", WM8988_3D, 1, 15, 0),
+SOC_ENUM("3D Lower Cut-off", stereo_3d_lc),
+SOC_ENUM("3D Upper Cut-off", stereo_3d_uc),
+SOC_ENUM("3D Mode", stereo_3d_func),
+
+SOC_SINGLE("ALC Capture Target Volume", WM8988_ALC1, 0, 7, 0),
+SOC_SINGLE("ALC Capture Max Volume", WM8988_ALC1, 4, 7, 0),
+SOC_ENUM("ALC Capture Function", alc_func),
+SOC_SINGLE("ALC Capture ZC Switch", WM8988_ALC2, 7, 1, 0),
+SOC_SINGLE("ALC Capture Hold Time", WM8988_ALC2, 0, 15, 0),
+SOC_SINGLE("ALC Capture Decay Time", WM8988_ALC3, 4, 15, 0),
+SOC_SINGLE("ALC Capture Attack Time", WM8988_ALC3, 0, 15, 0),
+SOC_SINGLE("ALC Capture NG Threshold", WM8988_NGATE, 3, 31, 0),
+SOC_ENUM("ALC Capture NG Type", ng_type),
+SOC_SINGLE("ALC Capture NG Switch", WM8988_NGATE, 0, 1, 0),
+
+SOC_SINGLE("ZC Timeout Switch", WM8988_ADCTL1, 0, 1, 0),
+
+SOC_DOUBLE_R_TLV("Capture Digital Volume", WM8988_LADC, WM8988_RADC,
+		 0, 255, 0, adc_tlv),
+SOC_DOUBLE_R_TLV("Capture Volume", WM8988_LINVOL, WM8988_RINVOL,
+		 0, 63, 0, pga_tlv),
+SOC_DOUBLE_R("Capture ZC Switch", WM8988_LINVOL, WM8988_RINVOL, 6, 1, 0),
+SOC_DOUBLE_R("Capture Switch", WM8988_LINVOL, WM8988_RINVOL, 7, 1, 1),
+
+SOC_ENUM("Playback De-emphasis", deemph),
+
+SOC_ENUM("Capture Polarity", adcpol),
+SOC_SINGLE("Playback 6dB Attenuate", WM8988_ADCDAC, 7, 1, 0),
+SOC_SINGLE("Capture 6dB Attenuate", WM8988_ADCDAC, 8, 1, 0),
+
+SOC_DOUBLE_R_TLV("PCM Volume", WM8988_LDAC, WM8988_RDAC, 0, 255, 0, dac_tlv),
+
+SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", WM8988_LOUTM1, 4, 7, 1,
+	       bypass_tlv),
+SOC_SINGLE_TLV("Left Mixer Right Bypass Volume", WM8988_LOUTM2, 4, 7, 1,
+	       bypass_tlv),
+SOC_SINGLE_TLV("Right Mixer Left Bypass Volume", WM8988_ROUTM1, 4, 7, 1,
+	       bypass_tlv),
+SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", WM8988_ROUTM2, 4, 7, 1,
+	       bypass_tlv),
+
+SOC_DOUBLE_R("Output 1 Playback ZC Switch", WM8988_LOUT1V,
+	     WM8988_ROUT1V, 7, 1, 0),
+SOC_DOUBLE_R_TLV("Output 1 Playback Volume", WM8988_LOUT1V, WM8988_ROUT1V,
+		 0, 127, 0, out_tlv),
+
+SOC_DOUBLE_R("Output 2 Playback ZC Switch", WM8988_LOUT2V,
+	     WM8988_ROUT2V, 7, 1, 0),
+SOC_DOUBLE_R_TLV("Output 2 Playback Volume", WM8988_LOUT2V, WM8988_ROUT2V,
+		 0, 127, 0, out_tlv),
+
+};
+
+/*
+ * DAPM Controls
+ */
+
+static int wm8988_lrc_control(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 adctl2 = wm8988_read_reg_cache(codec, WM8988_ADCTL2);
+
+	/* Use the DAC to gate LRC if active, otherwise use ADC */
+	if (wm8988_read_reg_cache(codec, WM8988_PWR2) & 0x180)
+		adctl2 &= ~0x4;
+	else
+		adctl2 |= 0x4;
+
+	return wm8988_write(codec, WM8988_ADCTL2, adctl2);
+}
+
+static const char *wm8988_line_texts[] = {
+	"Line 1", "Line 2", "PGA", "Differential"};
+
+static const unsigned int wm8988_line_values[] = {
+	0, 1, 3, 4};
+
+static const struct soc_enum wm8988_lline_enum =
+	SOC_VALUE_ENUM_SINGLE(WM8988_LOUTM1, 0, 7,
+			      ARRAY_SIZE(wm8988_line_texts),
+			      wm8988_line_texts,
+			      wm8988_line_values);
+static const struct snd_kcontrol_new wm8988_left_line_controls =
+	SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum);
+
+static const struct soc_enum wm8988_rline_enum =
+	SOC_VALUE_ENUM_SINGLE(WM8988_ROUTM1, 0, 7,
+			      ARRAY_SIZE(wm8988_line_texts),
+			      wm8988_line_texts,
+			      wm8988_line_values);
+static const struct snd_kcontrol_new wm8988_right_line_controls =
+	SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum);
+
+/* Left Mixer */
+static const struct snd_kcontrol_new wm8988_left_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Playback Switch", WM8988_LOUTM1, 8, 1, 0),
+	SOC_DAPM_SINGLE("Left Bypass Switch", WM8988_LOUTM1, 7, 1, 0),
+	SOC_DAPM_SINGLE("Right Playback Switch", WM8988_LOUTM2, 8, 1, 0),
+	SOC_DAPM_SINGLE("Right Bypass Switch", WM8988_LOUTM2, 7, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new wm8988_right_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left Playback Switch", WM8988_ROUTM1, 8, 1, 0),
+	SOC_DAPM_SINGLE("Left Bypass Switch", WM8988_ROUTM1, 7, 1, 0),
+	SOC_DAPM_SINGLE("Playback Switch", WM8988_ROUTM2, 8, 1, 0),
+	SOC_DAPM_SINGLE("Right Bypass Switch", WM8988_ROUTM2, 7, 1, 0),
+};
+
+static const char *wm8988_pga_sel[] = {"Line 1", "Line 2", "Differential"};
+static const unsigned int wm8988_pga_val[] = { 0, 1, 3 };
+
+/* Left PGA Mux */
+static const struct soc_enum wm8988_lpga_enum =
+	SOC_VALUE_ENUM_SINGLE(WM8988_LADCIN, 6, 3,
+			      ARRAY_SIZE(wm8988_pga_sel),
+			      wm8988_pga_sel,
+			      wm8988_pga_val);
+static const struct snd_kcontrol_new wm8988_left_pga_controls =
+	SOC_DAPM_VALUE_ENUM("Route", wm8988_lpga_enum);
+
+/* Right PGA Mux */
+static const struct soc_enum wm8988_rpga_enum =
+	SOC_VALUE_ENUM_SINGLE(WM8988_RADCIN, 6, 3,
+			      ARRAY_SIZE(wm8988_pga_sel),
+			      wm8988_pga_sel,
+			      wm8988_pga_val);
+static const struct snd_kcontrol_new wm8988_right_pga_controls =
+	SOC_DAPM_VALUE_ENUM("Route", wm8988_rpga_enum);
+
+/* Differential Mux */
+static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"};
+static const struct soc_enum diffmux =
+	SOC_ENUM_SINGLE(WM8988_ADCIN, 8, 2, wm8988_diff_sel);
+static const struct snd_kcontrol_new wm8988_diffmux_controls =
+	SOC_DAPM_ENUM("Route", diffmux);
+
+/* Mono ADC Mux */
+static const char *wm8988_mono_mux[] = {"Stereo", "Mono (Left)",
+	"Mono (Right)", "Digital Mono"};
+static const struct soc_enum monomux =
+	SOC_ENUM_SINGLE(WM8988_ADCIN, 6, 4, wm8988_mono_mux);
+static const struct snd_kcontrol_new wm8988_monomux_controls =
+	SOC_DAPM_ENUM("Route", monomux);
+
+static const struct snd_soc_dapm_widget wm8988_dapm_widgets[] = {
+	SND_SOC_DAPM_MICBIAS("Mic Bias", WM8988_PWR1, 1, 0),
+
+	SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+		&wm8988_diffmux_controls),
+	SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
+		&wm8988_monomux_controls),
+	SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
+		&wm8988_monomux_controls),
+
+	SND_SOC_DAPM_MUX("Left PGA Mux", WM8988_PWR1, 5, 0,
+		&wm8988_left_pga_controls),
+	SND_SOC_DAPM_MUX("Right PGA Mux", WM8988_PWR1, 4, 0,
+		&wm8988_right_pga_controls),
+
+	SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
+		&wm8988_left_line_controls),
+	SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
+		&wm8988_right_line_controls),
+
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8988_PWR1, 2, 0),
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8988_PWR1, 3, 0),
+
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8988_PWR2, 7, 0),
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8988_PWR2, 8, 0),
+
+	SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+		&wm8988_left_mixer_controls[0],
+		ARRAY_SIZE(wm8988_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+		&wm8988_right_mixer_controls[0],
+		ARRAY_SIZE(wm8988_right_mixer_controls)),
+
+	SND_SOC_DAPM_PGA("Right Out 2", WM8988_PWR2, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 2", WM8988_PWR2, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Out 1", WM8988_PWR2, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 1", WM8988_PWR2, 6, 0, NULL, 0),
+
+	SND_SOC_DAPM_POST("LRC control", wm8988_lrc_control),
+
+	SND_SOC_DAPM_OUTPUT("LOUT1"),
+	SND_SOC_DAPM_OUTPUT("ROUT1"),
+	SND_SOC_DAPM_OUTPUT("LOUT2"),
+	SND_SOC_DAPM_OUTPUT("ROUT2"),
+	SND_SOC_DAPM_OUTPUT("VREF"),
+
+	SND_SOC_DAPM_INPUT("LINPUT1"),
+	SND_SOC_DAPM_INPUT("LINPUT2"),
+	SND_SOC_DAPM_INPUT("RINPUT1"),
+	SND_SOC_DAPM_INPUT("RINPUT2"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+
+	{ "Left Line Mux", "Line 1", "LINPUT1" },
+	{ "Left Line Mux", "Line 2", "LINPUT2" },
+	{ "Left Line Mux", "PGA", "Left PGA Mux" },
+	{ "Left Line Mux", "Differential", "Differential Mux" },
+
+	{ "Right Line Mux", "Line 1", "RINPUT1" },
+	{ "Right Line Mux", "Line 2", "RINPUT2" },
+	{ "Right Line Mux", "PGA", "Right PGA Mux" },
+	{ "Right Line Mux", "Differential", "Differential Mux" },
+
+	{ "Left PGA Mux", "Line 1", "LINPUT1" },
+	{ "Left PGA Mux", "Line 2", "LINPUT2" },
+	{ "Left PGA Mux", "Differential", "Differential Mux" },
+
+	{ "Right PGA Mux", "Line 1", "RINPUT1" },
+	{ "Right PGA Mux", "Line 2", "RINPUT2" },
+	{ "Right PGA Mux", "Differential", "Differential Mux" },
+
+	{ "Differential Mux", "Line 1", "LINPUT1" },
+	{ "Differential Mux", "Line 1", "RINPUT1" },
+	{ "Differential Mux", "Line 2", "LINPUT2" },
+	{ "Differential Mux", "Line 2", "RINPUT2" },
+
+	{ "Left ADC Mux", "Stereo", "Left PGA Mux" },
+	{ "Left ADC Mux", "Mono (Left)", "Left PGA Mux" },
+	{ "Left ADC Mux", "Digital Mono", "Left PGA Mux" },
+
+	{ "Right ADC Mux", "Stereo", "Right PGA Mux" },
+	{ "Right ADC Mux", "Mono (Right)", "Right PGA Mux" },
+	{ "Right ADC Mux", "Digital Mono", "Right PGA Mux" },
+
+	{ "Left ADC", NULL, "Left ADC Mux" },
+	{ "Right ADC", NULL, "Right ADC Mux" },
+
+	{ "Left Line Mux", "Line 1", "LINPUT1" },
+	{ "Left Line Mux", "Line 2", "LINPUT2" },
+	{ "Left Line Mux", "PGA", "Left PGA Mux" },
+	{ "Left Line Mux", "Differential", "Differential Mux" },
+
+	{ "Right Line Mux", "Line 1", "RINPUT1" },
+	{ "Right Line Mux", "Line 2", "RINPUT2" },
+	{ "Right Line Mux", "PGA", "Right PGA Mux" },
+	{ "Right Line Mux", "Differential", "Differential Mux" },
+
+	{ "Left Mixer", "Playback Switch", "Left DAC" },
+	{ "Left Mixer", "Left Bypass Switch", "Left Line Mux" },
+	{ "Left Mixer", "Right Playback Switch", "Right DAC" },
+	{ "Left Mixer", "Right Bypass Switch", "Right Line Mux" },
+
+	{ "Right Mixer", "Left Playback Switch", "Left DAC" },
+	{ "Right Mixer", "Left Bypass Switch", "Left Line Mux" },
+	{ "Right Mixer", "Playback Switch", "Right DAC" },
+	{ "Right Mixer", "Right Bypass Switch", "Right Line Mux" },
+
+	{ "Left Out 1", NULL, "Left Mixer" },
+	{ "LOUT1", NULL, "Left Out 1" },
+	{ "Right Out 1", NULL, "Right Mixer" },
+	{ "ROUT1", NULL, "Right Out 1" },
+
+	{ "Left Out 2", NULL, "Left Mixer" },
+	{ "LOUT2", NULL, "Left Out 2" },
+	{ "Right Out 2", NULL, "Right Mixer" },
+	{ "ROUT2", NULL, "Right Out 2" },
+};
+
+struct _coeff_div {
+	u32 mclk;
+	u32 rate;
+	u16 fs;
+	u8 sr:5;
+	u8 usb:1;
+};
+
+/* codec hifi mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	/* 8k */
+	{12288000, 8000, 1536, 0x6, 0x0},
+	{11289600, 8000, 1408, 0x16, 0x0},
+	{18432000, 8000, 2304, 0x7, 0x0},
+	{16934400, 8000, 2112, 0x17, 0x0},
+	{12000000, 8000, 1500, 0x6, 0x1},
+
+	/* 11.025k */
+	{11289600, 11025, 1024, 0x18, 0x0},
+	{16934400, 11025, 1536, 0x19, 0x0},
+	{12000000, 11025, 1088, 0x19, 0x1},
+
+	/* 16k */
+	{12288000, 16000, 768, 0xa, 0x0},
+	{18432000, 16000, 1152, 0xb, 0x0},
+	{12000000, 16000, 750, 0xa, 0x1},
+
+	/* 22.05k */
+	{11289600, 22050, 512, 0x1a, 0x0},
+	{16934400, 22050, 768, 0x1b, 0x0},
+	{12000000, 22050, 544, 0x1b, 0x1},
+
+	/* 32k */
+	{12288000, 32000, 384, 0xc, 0x0},
+	{18432000, 32000, 576, 0xd, 0x0},
+	{12000000, 32000, 375, 0xa, 0x1},
+
+	/* 44.1k */
+	{11289600, 44100, 256, 0x10, 0x0},
+	{16934400, 44100, 384, 0x11, 0x0},
+	{12000000, 44100, 272, 0x11, 0x1},
+
+	/* 48k */
+	{12288000, 48000, 256, 0x0, 0x0},
+	{18432000, 48000, 384, 0x1, 0x0},
+	{12000000, 48000, 250, 0x0, 0x1},
+
+	/* 88.2k */
+	{11289600, 88200, 128, 0x1e, 0x0},
+	{16934400, 88200, 192, 0x1f, 0x0},
+	{12000000, 88200, 136, 0x1f, 0x1},
+
+	/* 96k */
+	{12288000, 96000, 128, 0xe, 0x0},
+	{18432000, 96000, 192, 0xf, 0x0},
+	{12000000, 96000, 125, 0xe, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+/* The set of rates we can generate from the above for each SYSCLK */
+
+static unsigned int rates_12288[] = {
+	8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12288 = {
+	.count	= ARRAY_SIZE(rates_12288),
+	.list	= rates_12288,
+};
+
+static unsigned int rates_112896[] = {
+	8000, 11025, 22050, 44100,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_112896 = {
+	.count	= ARRAY_SIZE(rates_112896),
+	.list	= rates_112896,
+};
+
+static unsigned int rates_12[] = {
+	8000, 11025, 12000, 16000, 22050, 2400, 32000, 41100, 48000,
+	48000, 88235, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12 = {
+	.count	= ARRAY_SIZE(rates_12),
+	.list	= rates_12,
+};
+
+/*
+ * Note that this should be called from init rather than from hw_params.
+ */
+static int wm8988_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct wm8988_priv *wm8988 = codec->private_data;
+
+	switch (freq) {
+	case 11289600:
+	case 18432000:
+	case 22579200:
+	case 36864000:
+		wm8988->sysclk_constraints = &constraints_112896;
+		wm8988->sysclk = freq;
+		return 0;
+
+	case 12288000:
+	case 16934400:
+	case 24576000:
+	case 33868800:
+		wm8988->sysclk_constraints = &constraints_12288;
+		wm8988->sysclk = freq;
+		return 0;
+
+	case 12000000:
+	case 24000000:
+		wm8988->sysclk_constraints = &constraints_12;
+		wm8988->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int wm8988_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface = 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8988_write(codec, WM8988_IFACE, iface);
+	return 0;
+}
+
+static int wm8988_pcm_startup(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct wm8988_priv *wm8988 = codec->private_data;
+
+	/* The set of sample rates that can be supported depends on the
+	 * MCLK supplied to the CODEC - enforce this.
+	 */
+	if (!wm8988->sysclk) {
+		dev_err(codec->dev,
+			"No MCLK configured, call set_sysclk() on init\n");
+		return -EINVAL;
+	}
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+				   SNDRV_PCM_HW_PARAM_RATE,
+				   wm8988->sysclk_constraints);
+
+	return 0;
+}
+
+static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	struct wm8988_priv *wm8988 = codec->private_data;
+	u16 iface = wm8988_read_reg_cache(codec, WM8988_IFACE) & 0x1f3;
+	u16 srate = wm8988_read_reg_cache(codec, WM8988_SRATE) & 0x180;
+	int coeff;
+
+	coeff = get_coeff(wm8988->sysclk, params_rate(params));
+	if (coeff < 0) {
+		coeff = get_coeff(wm8988->sysclk / 2, params_rate(params));
+		srate |= 0x40;
+	}
+	if (coeff < 0) {
+		dev_err(codec->dev,
+			"Unable to configure sample rate %dHz with %dHz MCLK\n",
+			params_rate(params), wm8988->sysclk);
+		return coeff;
+	}
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= 0x0004;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= 0x0008;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		iface |= 0x000c;
+		break;
+	}
+
+	/* set iface & srate */
+	wm8988_write(codec, WM8988_IFACE, iface);
+	if (coeff >= 0)
+		wm8988_write(codec, WM8988_SRATE, srate |
+			(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
+
+	return 0;
+}
+
+static int wm8988_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 mute_reg = wm8988_read_reg_cache(codec, WM8988_ADCDAC) & 0xfff7;
+
+	if (mute)
+		wm8988_write(codec, WM8988_ADCDAC, mute_reg | 0x8);
+	else
+		wm8988_write(codec, WM8988_ADCDAC, mute_reg);
+	return 0;
+}
+
+static int wm8988_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	u16 pwr_reg = wm8988_read_reg_cache(codec, WM8988_PWR1) & ~0x1c1;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* VREF, VMID=2x50k, digital enabled */
+		wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x00c0);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->bias_level == SND_SOC_BIAS_OFF) {
+			/* VREF, VMID=2x5k */
+			wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x1c1);
+
+			/* Charge caps */
+			msleep(100);
+		}
+
+		/* VREF, VMID=2*500k, digital stopped */
+		wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x0141);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		wm8988_write(codec, WM8988_PWR1, 0x0000);
+		break;
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+#define WM8988_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8988_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8988_ops = {
+	.startup = wm8988_pcm_startup,
+	.hw_params = wm8988_pcm_hw_params,
+	.set_fmt = wm8988_set_dai_fmt,
+	.set_sysclk = wm8988_set_dai_sysclk,
+	.digital_mute = wm8988_mute,
+};
+
+struct snd_soc_dai wm8988_dai = {
+	.name = "WM8988",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8988_RATES,
+		.formats = WM8988_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8988_RATES,
+		.formats = WM8988_FORMATS,
+	 },
+	.ops = &wm8988_ops,
+	.symmetric_rates = 1,
+};
+EXPORT_SYMBOL_GPL(wm8988_dai);
+
+static int wm8988_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8988_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+	int i;
+	u8 data[2];
+	u16 *cache = codec->reg_cache;
+
+	/* Sync reg_cache with the hardware */
+	for (i = 0; i < WM8988_NUM_REG; i++) {
+		if (i == WM8988_RESET)
+			continue;
+		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+		data[1] = cache[i] & 0x00ff;
+		codec->hw_write(codec->control_data, data, 2);
+	}
+
+	wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+
+static struct snd_soc_codec *wm8988_codec;
+
+static int wm8988_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	if (wm8988_codec == NULL) {
+		dev_err(&pdev->dev, "Codec device not registered\n");
+		return -ENODEV;
+	}
+
+	socdev->card->codec = wm8988_codec;
+	codec = wm8988_codec;
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+		goto pcm_err;
+	}
+
+	snd_soc_add_controls(codec, wm8988_snd_controls,
+				ARRAY_SIZE(wm8988_snd_controls));
+	snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets,
+				  ARRAY_SIZE(wm8988_dapm_widgets));
+	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+	snd_soc_dapm_new_widgets(codec);
+
+	ret = snd_soc_init_card(socdev);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to register card: %d\n", ret);
+		goto card_err;
+	}
+
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	return ret;
+}
+
+static int wm8988_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8988 = {
+	.probe = 	wm8988_probe,
+	.remove = 	wm8988_remove,
+	.suspend = 	wm8988_suspend,
+	.resume =	wm8988_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988);
+
+static int wm8988_register(struct wm8988_priv *wm8988)
+{
+	struct snd_soc_codec *codec = &wm8988->codec;
+	int ret;
+	u16 reg;
+
+	if (wm8988_codec) {
+		dev_err(codec->dev, "Another WM8988 is registered\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	codec->private_data = wm8988;
+	codec->name = "WM8988";
+	codec->owner = THIS_MODULE;
+	codec->read = wm8988_read_reg_cache;
+	codec->write = wm8988_write;
+	codec->dai = &wm8988_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache);
+	codec->reg_cache = &wm8988->reg_cache;
+	codec->bias_level = SND_SOC_BIAS_OFF;
+	codec->set_bias_level = wm8988_set_bias_level;
+
+	memcpy(codec->reg_cache, wm8988_reg,
+	       sizeof(wm8988_reg));
+
+	ret = wm8988_reset(codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	/* set the update bits (we always update left then right) */
+	reg = wm8988_read_reg_cache(codec, WM8988_RADC);
+	wm8988_write(codec, WM8988_RADC, reg | 0x100);
+	reg = wm8988_read_reg_cache(codec, WM8988_RDAC);
+	wm8988_write(codec, WM8988_RDAC, reg | 0x0100);
+	reg = wm8988_read_reg_cache(codec, WM8988_ROUT1V);
+	wm8988_write(codec, WM8988_ROUT1V, reg | 0x0100);
+	reg = wm8988_read_reg_cache(codec, WM8988_ROUT2V);
+	wm8988_write(codec, WM8988_ROUT2V, reg | 0x0100);
+	reg = wm8988_read_reg_cache(codec, WM8988_RINVOL);
+	wm8988_write(codec, WM8988_RINVOL, reg | 0x0100);
+
+	wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY);
+
+	wm8988_dai.dev = codec->dev;
+
+	wm8988_codec = codec;
+
+	ret = snd_soc_register_codec(codec);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_register_dai(&wm8988_dai);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+		snd_soc_unregister_codec(codec);
+		return ret;
+	}
+
+	return 0;
+
+err:
+	kfree(wm8988);
+	return ret;
+}
+
+static void wm8988_unregister(struct wm8988_priv *wm8988)
+{
+	wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_OFF);
+	snd_soc_unregister_dai(&wm8988_dai);
+	snd_soc_unregister_codec(&wm8988->codec);
+	kfree(wm8988);
+	wm8988_codec = NULL;
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int wm8988_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8988_priv *wm8988;
+	struct snd_soc_codec *codec;
+
+	wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
+	if (wm8988 == NULL)
+		return -ENOMEM;
+
+	codec = &wm8988->codec;
+	codec->hw_write = (hw_write_t)i2c_master_send;
+
+	i2c_set_clientdata(i2c, wm8988);
+	codec->control_data = i2c;
+
+	codec->dev = &i2c->dev;
+
+	return wm8988_register(wm8988);
+}
+
+static int wm8988_i2c_remove(struct i2c_client *client)
+{
+	struct wm8988_priv *wm8988 = i2c_get_clientdata(client);
+	wm8988_unregister(wm8988);
+	return 0;
+}
+
+static const struct i2c_device_id wm8988_i2c_id[] = {
+	{ "wm8988", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id);
+
+static struct i2c_driver wm8988_i2c_driver = {
+	.driver = {
+		.name = "WM8988",
+		.owner = THIS_MODULE,
+	},
+	.probe = wm8988_i2c_probe,
+	.remove = wm8988_i2c_remove,
+	.id_table = wm8988_i2c_id,
+};
+#endif
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8988_spi_write(struct spi_device *spi, const char *data, int len)
+{
+	struct spi_transfer t;
+	struct spi_message m;
+	u8 msg[2];
+
+	if (len <= 0)
+		return 0;
+
+	msg[0] = data[0];
+	msg[1] = data[1];
+
+	spi_message_init(&m);
+	memset(&t, 0, (sizeof t));
+
+	t.tx_buf = &msg[0];
+	t.len = len;
+
+	spi_message_add_tail(&t, &m);
+	spi_sync(spi, &m);
+
+	return len;
+}
+
+static int __devinit wm8988_spi_probe(struct spi_device *spi)
+{
+	struct wm8988_priv *wm8988;
+	struct snd_soc_codec *codec;
+
+	wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
+	if (wm8988 == NULL)
+		return -ENOMEM;
+
+	codec = &wm8988->codec;
+	codec->hw_write = (hw_write_t)wm8988_spi_write;
+	codec->control_data = spi;
+	codec->dev = &spi->dev;
+
+	spi->dev.driver_data = wm8988;
+
+	return wm8988_register(wm8988);
+}
+
+static int __devexit wm8988_spi_remove(struct spi_device *spi)
+{
+	struct wm8988_priv *wm8988 = spi->dev.driver_data;
+
+	wm8988_unregister(wm8988);
+
+	return 0;
+}
+
+static struct spi_driver wm8988_spi_driver = {
+	.driver = {
+		.name	= "wm8988",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm8988_spi_probe,
+	.remove		= __devexit_p(wm8988_spi_remove),
+};
+#endif
+
+static int __init wm8988_modinit(void)
+{
+	int ret;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	ret = i2c_add_driver(&wm8988_i2c_driver);
+	if (ret != 0)
+		pr_err("WM8988: Unable to register I2C driver: %d\n", ret);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8988_spi_driver);
+	if (ret != 0)
+		pr_err("WM8988: Unable to register SPI driver: %d\n", ret);
+#endif
+	return ret;
+}
+module_init(wm8988_modinit);
+
+static void __exit wm8988_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&wm8988_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8988_spi_driver);
+#endif
+}
+module_exit(wm8988_exit);
+
+
+MODULE_DESCRIPTION("ASoC WM8988 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8988.h b/sound/soc/codecs/wm8988.h
new file mode 100644
index 0000000..4552d37
--- /dev/null
+++ b/sound/soc/codecs/wm8988.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on WM8753.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 _WM8988_H
+#define _WM8988_H
+
+/* WM8988 register space */
+
+#define WM8988_LINVOL    0x00
+#define WM8988_RINVOL    0x01
+#define WM8988_LOUT1V    0x02
+#define WM8988_ROUT1V    0x03
+#define WM8988_ADCDAC    0x05
+#define WM8988_IFACE     0x07
+#define WM8988_SRATE     0x08
+#define WM8988_LDAC      0x0a
+#define WM8988_RDAC      0x0b
+#define WM8988_BASS      0x0c
+#define WM8988_TREBLE    0x0d
+#define WM8988_RESET     0x0f
+#define WM8988_3D        0x10
+#define WM8988_ALC1      0x11
+#define WM8988_ALC2      0x12
+#define WM8988_ALC3      0x13
+#define WM8988_NGATE     0x14
+#define WM8988_LADC      0x15
+#define WM8988_RADC      0x16
+#define WM8988_ADCTL1    0x17
+#define WM8988_ADCTL2    0x18
+#define WM8988_PWR1      0x19
+#define WM8988_PWR2      0x1a
+#define WM8988_ADCTL3    0x1b
+#define WM8988_ADCIN     0x1f
+#define WM8988_LADCIN    0x20
+#define WM8988_RADCIN    0x21
+#define WM8988_LOUTM1    0x22
+#define WM8988_LOUTM2    0x23
+#define WM8988_ROUTM1    0x24
+#define WM8988_ROUTM2    0x25
+#define WM8988_LOUT2V    0x28
+#define WM8988_ROUT2V    0x29
+#define WM8988_LPPB      0x43
+#define WM8988_NUM_REG   0x44
+
+#define WM8988_SYSCLK	0
+
+extern struct snd_soc_dai wm8988_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8988;
+
+#endif
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 40cd274..d029818 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -998,7 +998,7 @@
 
 	if ((Ndiv < 6) || (Ndiv > 12))
 		printk(KERN_WARNING
-		"WM8990 N value outwith recommended range! N = %d\n", Ndiv);
+		"WM8990 N value outwith recommended range! N = %u\n", Ndiv);
 
 	pll_div->n = Ndiv;
 	Nmod = target % source;
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
new file mode 100644
index 0000000..86fc57e2
--- /dev/null
+++ b/sound/soc/codecs/wm9081.c
@@ -0,0 +1,1534 @@
+/*
+ * wm9081.c  --  WM9081 ALSA SoC Audio driver
+ *
+ * Author: Mark Brown
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <sound/wm9081.h>
+#include "wm9081.h"
+
+static u16 wm9081_reg_defaults[] = {
+	0x0000,     /* R0  - Software Reset */
+	0x0000,     /* R1 */
+	0x00B9,     /* R2  - Analogue Lineout */
+	0x00B9,     /* R3  - Analogue Speaker PGA */
+	0x0001,     /* R4  - VMID Control */
+	0x0068,     /* R5  - Bias Control 1 */
+	0x0000,     /* R6 */
+	0x0000,     /* R7  - Analogue Mixer */
+	0x0000,     /* R8  - Anti Pop Control */
+	0x01DB,     /* R9  - Analogue Speaker 1 */
+	0x0018,     /* R10 - Analogue Speaker 2 */
+	0x0180,     /* R11 - Power Management */
+	0x0000,     /* R12 - Clock Control 1 */
+	0x0038,     /* R13 - Clock Control 2 */
+	0x4000,     /* R14 - Clock Control 3 */
+	0x0000,     /* R15 */
+	0x0000,     /* R16 - FLL Control 1 */
+	0x0200,     /* R17 - FLL Control 2 */
+	0x0000,     /* R18 - FLL Control 3 */
+	0x0204,     /* R19 - FLL Control 4 */
+	0x0000,     /* R20 - FLL Control 5 */
+	0x0000,     /* R21 */
+	0x0000,     /* R22 - Audio Interface 1 */
+	0x0002,     /* R23 - Audio Interface 2 */
+	0x0008,     /* R24 - Audio Interface 3 */
+	0x0022,     /* R25 - Audio Interface 4 */
+	0x0000,     /* R26 - Interrupt Status */
+	0x0006,     /* R27 - Interrupt Status Mask */
+	0x0000,     /* R28 - Interrupt Polarity */
+	0x0000,     /* R29 - Interrupt Control */
+	0x00C0,     /* R30 - DAC Digital 1 */
+	0x0008,     /* R31 - DAC Digital 2 */
+	0x09AF,     /* R32 - DRC 1 */
+	0x4201,     /* R33 - DRC 2 */
+	0x0000,     /* R34 - DRC 3 */
+	0x0000,     /* R35 - DRC 4 */
+	0x0000,     /* R36 */
+	0x0000,     /* R37 */
+	0x0000,     /* R38 - Write Sequencer 1 */
+	0x0000,     /* R39 - Write Sequencer 2 */
+	0x0002,     /* R40 - MW Slave 1 */
+	0x0000,     /* R41 */
+	0x0000,     /* R42 - EQ 1 */
+	0x0000,     /* R43 - EQ 2 */
+	0x0FCA,     /* R44 - EQ 3 */
+	0x0400,     /* R45 - EQ 4 */
+	0x00B8,     /* R46 - EQ 5 */
+	0x1EB5,     /* R47 - EQ 6 */
+	0xF145,     /* R48 - EQ 7 */
+	0x0B75,     /* R49 - EQ 8 */
+	0x01C5,     /* R50 - EQ 9 */
+	0x169E,     /* R51 - EQ 10 */
+	0xF829,     /* R52 - EQ 11 */
+	0x07AD,     /* R53 - EQ 12 */
+	0x1103,     /* R54 - EQ 13 */
+	0x1C58,     /* R55 - EQ 14 */
+	0xF373,     /* R56 - EQ 15 */
+	0x0A54,     /* R57 - EQ 16 */
+	0x0558,     /* R58 - EQ 17 */
+	0x0564,     /* R59 - EQ 18 */
+	0x0559,     /* R60 - EQ 19 */
+	0x4000,     /* R61 - EQ 20 */
+};
+
+static struct {
+	int ratio;
+	int clk_sys_rate;
+} clk_sys_rates[] = {
+	{ 64,   0 },
+	{ 128,  1 },
+	{ 192,  2 },
+	{ 256,  3 },
+	{ 384,  4 },
+	{ 512,  5 },
+	{ 768,  6 },
+	{ 1024, 7 },
+	{ 1408, 8 },
+	{ 1536, 9 },
+};
+
+static struct {
+	int rate;
+	int sample_rate;
+} sample_rates[] = {
+	{ 8000,  0  },
+	{ 11025, 1  },
+	{ 12000, 2  },
+	{ 16000, 3  },
+	{ 22050, 4  },
+	{ 24000, 5  },
+	{ 32000, 6  },
+	{ 44100, 7  },
+	{ 48000, 8  },
+	{ 88200, 9  },
+	{ 96000, 10 },
+};
+
+static struct {
+	int div; /* *10 due to .5s */
+	int bclk_div;
+} bclk_divs[] = {
+	{ 10,  0  },
+	{ 15,  1  },
+	{ 20,  2  },
+	{ 30,  3  },
+	{ 40,  4  },
+	{ 50,  5  },
+	{ 55,  6  },
+	{ 60,  7  },
+	{ 80,  8  },
+	{ 100, 9  },
+	{ 110, 10 },
+	{ 120, 11 },
+	{ 160, 12 },
+	{ 200, 13 },
+	{ 220, 14 },
+	{ 240, 15 },
+	{ 250, 16 },
+	{ 300, 17 },
+	{ 320, 18 },
+	{ 440, 19 },
+	{ 480, 20 },
+};
+
+struct wm9081_priv {
+	struct snd_soc_codec codec;
+	u16 reg_cache[WM9081_MAX_REGISTER + 1];
+	int sysclk_source;
+	int mclk_rate;
+	int sysclk_rate;
+	int fs;
+	int bclk;
+	int master;
+	int fll_fref;
+	int fll_fout;
+	struct wm9081_retune_mobile_config *retune;
+};
+
+static int wm9081_reg_is_volatile(int reg)
+{
+	switch (reg) {
+	default:
+		return 0;
+	}
+}
+
+static unsigned int wm9081_read_reg_cache(struct snd_soc_codec *codec,
+					  unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	BUG_ON(reg > WM9081_MAX_REGISTER);
+	return cache[reg];
+}
+
+static unsigned int wm9081_read_hw(struct snd_soc_codec *codec, u8 reg)
+{
+	struct i2c_msg xfer[2];
+	u16 data;
+	int ret;
+	struct i2c_client *client = codec->control_data;
+
+	BUG_ON(reg > WM9081_MAX_REGISTER);
+
+	/* Write register */
+	xfer[0].addr = client->addr;
+	xfer[0].flags = 0;
+	xfer[0].len = 1;
+	xfer[0].buf = &reg;
+
+	/* Read data */
+	xfer[1].addr = client->addr;
+	xfer[1].flags = I2C_M_RD;
+	xfer[1].len = 2;
+	xfer[1].buf = (u8 *)&data;
+
+	ret = i2c_transfer(client->adapter, xfer, 2);
+	if (ret != 2) {
+		dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+		return 0;
+	}
+
+	return (data >> 8) | ((data & 0xff) << 8);
+}
+
+static unsigned int wm9081_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+	if (wm9081_reg_is_volatile(reg))
+		return wm9081_read_hw(codec, reg);
+	else
+		return wm9081_read_reg_cache(codec, reg);
+}
+
+static int wm9081_write(struct snd_soc_codec *codec, unsigned int reg,
+			unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+	u8 data[3];
+
+	BUG_ON(reg > WM9081_MAX_REGISTER);
+
+	if (!wm9081_reg_is_volatile(reg))
+		cache[reg] = value;
+
+	data[0] = reg;
+	data[1] = value >> 8;
+	data[2] = value & 0x00ff;
+
+	if (codec->hw_write(codec->control_data, data, 3) == 3)
+		return 0;
+	else
+		return -EIO;
+}
+
+static int wm9081_reset(struct snd_soc_codec *codec)
+{
+	return wm9081_write(codec, WM9081_SOFTWARE_RESET, 0);
+}
+
+static const DECLARE_TLV_DB_SCALE(drc_in_tlv, -4500, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_out_tlv, -2250, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0);
+static unsigned int drc_max_tlv[] = {
+	TLV_DB_RANGE_HEAD(4),
+	0, 0, TLV_DB_SCALE_ITEM(1200, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(1800, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0),
+};
+static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -300, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(in_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+
+static const char *drc_high_text[] = {
+	"1",
+	"1/2",
+	"1/4",
+	"1/8",
+	"1/16",
+	"0",
+};
+
+static const struct soc_enum drc_high =
+	SOC_ENUM_SINGLE(WM9081_DRC_3, 3, 6, drc_high_text);
+
+static const char *drc_low_text[] = {
+	"1",
+	"1/2",
+	"1/4",
+	"1/8",
+	"0",
+};
+
+static const struct soc_enum drc_low =
+	SOC_ENUM_SINGLE(WM9081_DRC_3, 0, 5, drc_low_text);
+
+static const char *drc_atk_text[] = {
+	"181us",
+	"181us",
+	"363us",
+	"726us",
+	"1.45ms",
+	"2.9ms",
+	"5.8ms",
+	"11.6ms",
+	"23.2ms",
+	"46.4ms",
+	"92.8ms",
+	"185.6ms",
+};
+
+static const struct soc_enum drc_atk =
+	SOC_ENUM_SINGLE(WM9081_DRC_2, 12, 12, drc_atk_text);
+
+static const char *drc_dcy_text[] = {
+	"186ms",
+	"372ms",
+	"743ms",
+	"1.49s",
+	"2.97s",
+	"5.94s",
+	"11.89s",
+	"23.78s",
+	"47.56s",
+};
+
+static const struct soc_enum drc_dcy =
+	SOC_ENUM_SINGLE(WM9081_DRC_2, 8, 9, drc_dcy_text);
+
+static const char *drc_qr_dcy_text[] = {
+	"0.725ms",
+	"1.45ms",
+	"5.8ms",
+};
+
+static const struct soc_enum drc_qr_dcy =
+	SOC_ENUM_SINGLE(WM9081_DRC_2, 4, 3, drc_qr_dcy_text);
+
+static const char *dac_deemph_text[] = {
+	"None",
+	"32kHz",
+	"44.1kHz",
+	"48kHz",
+};
+
+static const struct soc_enum dac_deemph =
+	SOC_ENUM_SINGLE(WM9081_DAC_DIGITAL_2, 1, 4, dac_deemph_text);
+
+static const char *speaker_mode_text[] = {
+	"Class D",
+	"Class AB",
+};
+
+static const struct soc_enum speaker_mode =
+	SOC_ENUM_SINGLE(WM9081_ANALOGUE_SPEAKER_2, 6, 2, speaker_mode_text);
+
+static int speaker_mode_get(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int reg;
+
+	reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2);
+	if (reg & WM9081_SPK_MODE)
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	return 0;
+}
+
+/*
+ * Stop any attempts to change speaker mode while the speaker is enabled.
+ *
+ * We also have some special anti-pop controls dependant on speaker
+ * mode which must be changed along with the mode.
+ */
+static int speaker_mode_put(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int reg_pwr = wm9081_read(codec, WM9081_POWER_MANAGEMENT);
+	unsigned int reg2 = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2);
+
+	/* Are we changing anything? */
+	if (ucontrol->value.integer.value[0] ==
+	    ((reg2 & WM9081_SPK_MODE) != 0))
+		return 0;
+
+	/* Don't try to change modes while enabled */
+	if (reg_pwr & WM9081_SPK_ENA)
+		return -EINVAL;
+
+	if (ucontrol->value.integer.value[0]) {
+		/* Class AB */
+		reg2 &= ~(WM9081_SPK_INV_MUTE | WM9081_OUT_SPK_CTRL);
+		reg2 |= WM9081_SPK_MODE;
+	} else {
+		/* Class D */
+		reg2 |= WM9081_SPK_INV_MUTE | WM9081_OUT_SPK_CTRL;
+		reg2 &= ~WM9081_SPK_MODE;
+	}
+
+	wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_2, reg2);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new wm9081_snd_controls[] = {
+SOC_SINGLE_TLV("IN1 Volume", WM9081_ANALOGUE_MIXER, 1, 1, 1, in_tlv),
+SOC_SINGLE_TLV("IN2 Volume", WM9081_ANALOGUE_MIXER, 3, 1, 1, in_tlv),
+
+SOC_SINGLE_TLV("Playback Volume", WM9081_DAC_DIGITAL_1, 1, 96, 0, dac_tlv),
+
+SOC_SINGLE("LINEOUT Switch", WM9081_ANALOGUE_LINEOUT, 7, 1, 1),
+SOC_SINGLE("LINEOUT ZC Switch", WM9081_ANALOGUE_LINEOUT, 6, 1, 0),
+SOC_SINGLE_TLV("LINEOUT Volume", WM9081_ANALOGUE_LINEOUT, 0, 63, 0, out_tlv),
+
+SOC_SINGLE("DRC Switch", WM9081_DRC_1, 15, 1, 0),
+SOC_ENUM("DRC High Slope", drc_high),
+SOC_ENUM("DRC Low Slope", drc_low),
+SOC_SINGLE_TLV("DRC Input Volume", WM9081_DRC_4, 5, 60, 1, drc_in_tlv),
+SOC_SINGLE_TLV("DRC Output Volume", WM9081_DRC_4, 0, 30, 1, drc_out_tlv),
+SOC_SINGLE_TLV("DRC Minimum Volume", WM9081_DRC_2, 2, 3, 1, drc_min_tlv),
+SOC_SINGLE_TLV("DRC Maximum Volume", WM9081_DRC_2, 0, 3, 0, drc_max_tlv),
+SOC_ENUM("DRC Attack", drc_atk),
+SOC_ENUM("DRC Decay", drc_dcy),
+SOC_SINGLE("DRC Quick Release Switch", WM9081_DRC_1, 2, 1, 0),
+SOC_SINGLE_TLV("DRC Quick Release Volume", WM9081_DRC_2, 6, 3, 0, drc_qr_tlv),
+SOC_ENUM("DRC Quick Release Decay", drc_qr_dcy),
+SOC_SINGLE_TLV("DRC Startup Volume", WM9081_DRC_1, 6, 18, 0, drc_startup_tlv),
+
+SOC_SINGLE("EQ Switch", WM9081_EQ_1, 0, 1, 0),
+
+SOC_SINGLE("Speaker DC Volume", WM9081_ANALOGUE_SPEAKER_1, 3, 5, 0),
+SOC_SINGLE("Speaker AC Volume", WM9081_ANALOGUE_SPEAKER_1, 0, 5, 0),
+SOC_SINGLE("Speaker Switch", WM9081_ANALOGUE_SPEAKER_PGA, 7, 1, 1),
+SOC_SINGLE("Speaker ZC Switch", WM9081_ANALOGUE_SPEAKER_PGA, 6, 1, 0),
+SOC_SINGLE_TLV("Speaker Volume", WM9081_ANALOGUE_SPEAKER_PGA, 0, 63, 0,
+	       out_tlv),
+SOC_ENUM("DAC Deemphasis", dac_deemph),
+SOC_ENUM_EXT("Speaker Mode", speaker_mode, speaker_mode_get, speaker_mode_put),
+};
+
+static const struct snd_kcontrol_new wm9081_eq_controls[] = {
+SOC_SINGLE_TLV("EQ1 Volume", WM9081_EQ_1, 11, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Volume", WM9081_EQ_1, 6, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Volume", WM9081_EQ_1, 1, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Volume", WM9081_EQ_2, 11, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ5 Volume", WM9081_EQ_2, 6, 24, 0, eq_tlv),
+};
+
+static const struct snd_kcontrol_new mixer[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM9081_ANALOGUE_MIXER, 0, 1, 0),
+SOC_DAPM_SINGLE("IN2 Switch", WM9081_ANALOGUE_MIXER, 2, 1, 0),
+SOC_DAPM_SINGLE("Playback Switch", WM9081_ANALOGUE_MIXER, 4, 1, 0),
+};
+
+static int speaker_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	unsigned int reg = wm9081_read(codec, WM9081_POWER_MANAGEMENT);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		reg |= WM9081_SPK_ENA;
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		reg &= ~WM9081_SPK_ENA;
+		break;
+	}
+
+	wm9081_write(codec, WM9081_POWER_MANAGEMENT, reg);
+
+	return 0;
+}
+
+struct _fll_div {
+	u16 fll_fratio;
+	u16 fll_outdiv;
+	u16 fll_clk_ref_div;
+	u16 n;
+	u16 k;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+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)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod, target;
+	unsigned int div;
+	int i;
+
+	/* Fref must be <=13.5MHz */
+	div = 1;
+	while ((Fref / div) > 13500000) {
+		div *= 2;
+
+		if (div > 8) {
+			pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+			       Fref);
+			return -EINVAL;
+		}
+	}
+	fll_div->fll_clk_ref_div = div / 2;
+
+	pr_debug("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 = 0;
+	target = Fout * 2;
+	while (target < 90000000) {
+		div++;
+		target *= 2;
+		if (div > 7) {
+			pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+			       Fout);
+			return -EINVAL;
+		}
+	}
+	fll_div->fll_outdiv = div;
+
+	pr_debug("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;
+			target /= 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;
+	}
+
+	/* Now, calculate N.K */
+	Ndiv = target / Fref;
+
+	fll_div->n = Ndiv;
+	Nmod = target % Fref;
+	pr_debug("Nmod=%d\n", Nmod);
+
+	/* Calculate fractional part - scale up so we can round. */
+	Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, Fref);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	fll_div->k = K / 10;
+
+	pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n",
+		 fll_div->n, fll_div->k,
+		 fll_div->fll_fratio, fll_div->fll_outdiv,
+		 fll_div->fll_clk_ref_div);
+
+	return 0;
+}
+
+static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct wm9081_priv *wm9081 = codec->private_data;
+	u16 reg1, reg4, reg5;
+	struct _fll_div fll_div;
+	int ret;
+	int clk_sys_reg;
+
+	/* Any change? */
+	if (Fref == wm9081->fll_fref && Fout == wm9081->fll_fout)
+		return 0;
+
+	/* Disable the FLL */
+	if (Fout == 0) {
+		dev_dbg(codec->dev, "FLL disabled\n");
+		wm9081->fll_fref = 0;
+		wm9081->fll_fout = 0;
+
+		return 0;
+	}
+
+	ret = fll_factors(&fll_div, Fref, Fout);
+	if (ret != 0)
+		return ret;
+
+	reg5 = wm9081_read(codec, WM9081_FLL_CONTROL_5);
+	reg5 &= ~WM9081_FLL_CLK_SRC_MASK;
+
+	switch (fll_id) {
+	case WM9081_SYSCLK_FLL_MCLK:
+		reg5 |= 0x1;
+		break;
+
+	default:
+		dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id);
+		return -EINVAL;
+	}
+
+	/* Disable CLK_SYS while we reconfigure */
+	clk_sys_reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3);
+	if (clk_sys_reg & WM9081_CLK_SYS_ENA)
+		wm9081_write(codec, WM9081_CLOCK_CONTROL_3,
+			     clk_sys_reg & ~WM9081_CLK_SYS_ENA);
+
+	/* Any FLL configuration change requires that the FLL be
+	 * disabled first. */
+	reg1 = wm9081_read(codec, WM9081_FLL_CONTROL_1);
+	reg1 &= ~WM9081_FLL_ENA;
+	wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1);
+
+	/* Apply the configuration */
+	if (fll_div.k)
+		reg1 |= WM9081_FLL_FRAC_MASK;
+	else
+		reg1 &= ~WM9081_FLL_FRAC_MASK;
+	wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1);
+
+	wm9081_write(codec, WM9081_FLL_CONTROL_2,
+		     (fll_div.fll_outdiv << WM9081_FLL_OUTDIV_SHIFT) |
+		     (fll_div.fll_fratio << WM9081_FLL_FRATIO_SHIFT));
+	wm9081_write(codec, WM9081_FLL_CONTROL_3, fll_div.k);
+
+	reg4 = wm9081_read(codec, WM9081_FLL_CONTROL_4);
+	reg4 &= ~WM9081_FLL_N_MASK;
+	reg4 |= fll_div.n << WM9081_FLL_N_SHIFT;
+	wm9081_write(codec, WM9081_FLL_CONTROL_4, reg4);
+
+	reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK;
+	reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT;
+	wm9081_write(codec, WM9081_FLL_CONTROL_5, reg5);
+
+	/* Enable the FLL */
+	wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA);
+
+	/* Then bring CLK_SYS up again if it was disabled */
+	if (clk_sys_reg & WM9081_CLK_SYS_ENA)
+		wm9081_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg);
+
+	dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
+
+	wm9081->fll_fref = Fref;
+	wm9081->fll_fout = Fout;
+
+	return 0;
+}
+
+static int configure_clock(struct snd_soc_codec *codec)
+{
+	struct wm9081_priv *wm9081 = codec->private_data;
+	int new_sysclk, i, target;
+	unsigned int reg;
+	int ret = 0;
+	int mclkdiv = 0;
+	int fll = 0;
+
+	switch (wm9081->sysclk_source) {
+	case WM9081_SYSCLK_MCLK:
+		if (wm9081->mclk_rate > 12225000) {
+			mclkdiv = 1;
+			wm9081->sysclk_rate = wm9081->mclk_rate / 2;
+		} else {
+			wm9081->sysclk_rate = wm9081->mclk_rate;
+		}
+		wm9081_set_fll(codec, WM9081_SYSCLK_FLL_MCLK, 0, 0);
+		break;
+
+	case WM9081_SYSCLK_FLL_MCLK:
+		/* If we have a sample rate calculate a CLK_SYS that
+		 * gives us a suitable DAC configuration, plus BCLK.
+		 * Ideally we would check to see if we can clock
+		 * directly from MCLK and only use the FLL if this is
+		 * not the case, though care must be taken with free
+		 * running mode.
+		 */
+		if (wm9081->master && wm9081->bclk) {
+			/* Make sure we can generate CLK_SYS and BCLK
+			 * and that we've got 3MHz for optimal
+			 * performance. */
+			for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) {
+				target = wm9081->fs * clk_sys_rates[i].ratio;
+				new_sysclk = target;
+				if (target >= wm9081->bclk &&
+				    target > 3000000)
+					break;
+			}
+		} else if (wm9081->fs) {
+			for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) {
+				new_sysclk = clk_sys_rates[i].ratio
+					* wm9081->fs;
+				if (new_sysclk > 3000000)
+					break;
+			}
+		} else {
+			new_sysclk = 12288000;
+		}
+
+		ret = wm9081_set_fll(codec, WM9081_SYSCLK_FLL_MCLK,
+				     wm9081->mclk_rate, new_sysclk);
+		if (ret == 0) {
+			wm9081->sysclk_rate = new_sysclk;
+
+			/* Switch SYSCLK over to FLL */
+			fll = 1;
+		} else {
+			wm9081->sysclk_rate = wm9081->mclk_rate;
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_1);
+	if (mclkdiv)
+		reg |= WM9081_MCLKDIV2;
+	else
+		reg &= ~WM9081_MCLKDIV2;
+	wm9081_write(codec, WM9081_CLOCK_CONTROL_1, reg);
+
+	reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3);
+	if (fll)
+		reg |= WM9081_CLK_SRC_SEL;
+	else
+		reg &= ~WM9081_CLK_SRC_SEL;
+	wm9081_write(codec, WM9081_CLOCK_CONTROL_3, reg);
+
+	dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm9081->sysclk_rate);
+
+	return ret;
+}
+
+static int clk_sys_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct wm9081_priv *wm9081 = codec->private_data;
+
+	/* This should be done on init() for bypass paths */
+	switch (wm9081->sysclk_source) {
+	case WM9081_SYSCLK_MCLK:
+		dev_dbg(codec->dev, "Using %dHz MCLK\n", wm9081->mclk_rate);
+		break;
+	case WM9081_SYSCLK_FLL_MCLK:
+		dev_dbg(codec->dev, "Using %dHz MCLK with FLL\n",
+			wm9081->mclk_rate);
+		break;
+	default:
+		dev_err(codec->dev, "System clock not configured\n");
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		configure_clock(codec);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		/* Disable the FLL if it's running */
+		wm9081_set_fll(codec, 0, 0, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget wm9081_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1"),
+SND_SOC_DAPM_INPUT("IN2"),
+
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM9081_POWER_MANAGEMENT, 0, 0),
+
+SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0,
+			     mixer, ARRAY_SIZE(mixer)),
+
+SND_SOC_DAPM_PGA("LINEOUT PGA", WM9081_POWER_MANAGEMENT, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_E("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0,
+		   speaker_event,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("LINEOUT"),
+SND_SOC_DAPM_OUTPUT("SPKN"),
+SND_SOC_DAPM_OUTPUT("SPKP"),
+
+SND_SOC_DAPM_SUPPLY("CLK_SYS", WM9081_CLOCK_CONTROL_3, 0, 0, clk_sys_event,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("CLK_DSP", WM9081_CLOCK_CONTROL_3, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TOCLK", WM9081_CLOCK_CONTROL_3, 2, 0, NULL, 0),
+};
+
+
+static const struct snd_soc_dapm_route audio_paths[] = {
+	{ "DAC", NULL, "CLK_SYS" },
+	{ "DAC", NULL, "CLK_DSP" },
+
+	{ "Mixer", "IN1 Switch", "IN1" },
+	{ "Mixer", "IN2 Switch", "IN2" },
+	{ "Mixer", "Playback Switch", "DAC" },
+
+	{ "LINEOUT PGA", NULL, "Mixer" },
+	{ "LINEOUT PGA", NULL, "TOCLK" },
+	{ "LINEOUT PGA", NULL, "CLK_SYS" },
+
+	{ "LINEOUT", NULL, "LINEOUT PGA" },
+
+	{ "Speaker PGA", NULL, "Mixer" },
+	{ "Speaker PGA", NULL, "TOCLK" },
+	{ "Speaker PGA", NULL, "CLK_SYS" },
+
+	{ "SPKN", NULL, "Speaker PGA" },
+	{ "SPKP", NULL, "Speaker PGA" },
+};
+
+static int wm9081_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	u16 reg;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* VMID=2*40k */
+		reg = wm9081_read(codec, WM9081_VMID_CONTROL);
+		reg &= ~WM9081_VMID_SEL_MASK;
+		reg |= 0x2;
+		wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+
+		/* Normal bias current */
+		reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+		reg &= ~WM9081_STBY_BIAS_ENA;
+		wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		/* Initial cold start */
+		if (codec->bias_level == SND_SOC_BIAS_OFF) {
+			/* Disable LINEOUT discharge */
+			reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL);
+			reg &= ~WM9081_LINEOUT_DISCH;
+			wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg);
+
+			/* Select startup bias source */
+			reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+			reg |= WM9081_BIAS_SRC | WM9081_BIAS_ENA;
+			wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+
+			/* VMID 2*4k; Soft VMID ramp enable */
+			reg = wm9081_read(codec, WM9081_VMID_CONTROL);
+			reg |= WM9081_VMID_RAMP | 0x6;
+			wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+
+			mdelay(100);
+
+			/* Normal bias enable & soft start off */
+			reg |= WM9081_BIAS_ENA;
+			reg &= ~WM9081_VMID_RAMP;
+			wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+
+			/* Standard bias source */
+			reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+			reg &= ~WM9081_BIAS_SRC;
+			wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+		}
+
+		/* VMID 2*240k */
+		reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+		reg &= ~WM9081_VMID_SEL_MASK;
+		reg |= 0x40;
+		wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+
+		/* Standby bias current on */
+		reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+		reg |= WM9081_STBY_BIAS_ENA;
+		wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* Startup bias source */
+		reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+		reg |= WM9081_BIAS_SRC;
+		wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+
+		/* Disable VMID and biases with soft ramping */
+		reg = wm9081_read(codec, WM9081_VMID_CONTROL);
+		reg &= ~(WM9081_VMID_SEL_MASK | WM9081_BIAS_ENA);
+		reg |= WM9081_VMID_RAMP;
+		wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+
+		/* Actively discharge LINEOUT */
+		reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL);
+		reg |= WM9081_LINEOUT_DISCH;
+		wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg);
+		break;
+	}
+
+	codec->bias_level = level;
+
+	return 0;
+}
+
+static int wm9081_set_dai_fmt(struct snd_soc_dai *dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct wm9081_priv *wm9081 = codec->private_data;
+	unsigned int aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2);
+
+	aif2 &= ~(WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV |
+		  WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		wm9081->master = 0;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		aif2 |= WM9081_LRCLK_DIR;
+		wm9081->master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		aif2 |= WM9081_BCLK_DIR;
+		wm9081->master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif2 |= WM9081_LRCLK_DIR | WM9081_BCLK_DIR;
+		wm9081->master = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_B:
+		aif2 |= WM9081_AIF_LRCLK_INV;
+	case SND_SOC_DAIFMT_DSP_A:
+		aif2 |= 0x3;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aif2 |= 0x2;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif2 |= 0x1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		/* frame inversion not valid for DSP modes */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif2 |= WM9081_AIF_BCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			aif2 |= WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif2 |= WM9081_AIF_BCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			aif2 |= WM9081_AIF_LRCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2);
+
+	return 0;
+}
+
+static int wm9081_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 wm9081_priv *wm9081 = codec->private_data;
+	int ret, i, best, best_val, cur_val;
+	unsigned int clk_ctrl2, aif1, aif2, aif3, aif4;
+
+	clk_ctrl2 = wm9081_read(codec, WM9081_CLOCK_CONTROL_2);
+	clk_ctrl2 &= ~(WM9081_CLK_SYS_RATE_MASK | WM9081_SAMPLE_RATE_MASK);
+
+	aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1);
+
+	aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2);
+	aif2 &= ~WM9081_AIF_WL_MASK;
+
+	aif3 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_3);
+	aif3 &= ~WM9081_BCLK_DIV_MASK;
+
+	aif4 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_4);
+	aif4 &= ~WM9081_LRCLK_RATE_MASK;
+
+	/* What BCLK do we need? */
+	wm9081->fs = params_rate(params);
+	wm9081->bclk = 2 * wm9081->fs;
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		wm9081->bclk *= 16;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		wm9081->bclk *= 20;
+		aif2 |= 0x4;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		wm9081->bclk *= 24;
+		aif2 |= 0x8;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		wm9081->bclk *= 32;
+		aif2 |= 0xc;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (aif1 & WM9081_AIFDAC_TDM_MODE_MASK) {
+		int slots = ((aif1 & WM9081_AIFDAC_TDM_MODE_MASK) >>
+			     WM9081_AIFDAC_TDM_MODE_SHIFT) + 1;
+		wm9081->bclk *= slots;
+	}
+
+	dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm9081->bclk);
+
+	ret = configure_clock(codec);
+	if (ret != 0)
+		return ret;
+
+	/* Select nearest CLK_SYS_RATE */
+	best = 0;
+	best_val = abs((wm9081->sysclk_rate / clk_sys_rates[0].ratio)
+		       - wm9081->fs);
+	for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) {
+		cur_val = abs((wm9081->sysclk_rate /
+			       clk_sys_rates[i].ratio) - wm9081->fs);;
+		if (cur_val < best_val) {
+			best = i;
+			best_val = cur_val;
+		}
+	}
+	dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n",
+		clk_sys_rates[best].ratio);
+	clk_ctrl2 |= (clk_sys_rates[best].clk_sys_rate
+		      << WM9081_CLK_SYS_RATE_SHIFT);
+
+	/* SAMPLE_RATE */
+	best = 0;
+	best_val = abs(wm9081->fs - sample_rates[0].rate);
+	for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
+		/* Closest match */
+		cur_val = abs(wm9081->fs - sample_rates[i].rate);
+		if (cur_val < best_val) {
+			best = i;
+			best_val = cur_val;
+		}
+	}
+	dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n",
+		sample_rates[best].rate);
+	clk_ctrl2 |= (sample_rates[best].sample_rate
+			<< WM9081_SAMPLE_RATE_SHIFT);
+
+	/* BCLK_DIV */
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+		cur_val = ((wm9081->sysclk_rate * 10) / bclk_divs[i].div)
+			- wm9081->bclk;
+		if (cur_val < 0) /* Table is sorted */
+			break;
+		if (cur_val < best_val) {
+			best = i;
+			best_val = cur_val;
+		}
+	}
+	wm9081->bclk = (wm9081->sysclk_rate * 10) / bclk_divs[best].div;
+	dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
+		bclk_divs[best].div, wm9081->bclk);
+	aif3 |= bclk_divs[best].bclk_div;
+
+	/* LRCLK is a simple fraction of BCLK */
+	dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm9081->bclk / wm9081->fs);
+	aif4 |= wm9081->bclk / wm9081->fs;
+
+	/* Apply a ReTune Mobile configuration if it's in use */
+	if (wm9081->retune) {
+		struct wm9081_retune_mobile_config *retune = wm9081->retune;
+		struct wm9081_retune_mobile_setting *s;
+		int eq1;
+
+		best = 0;
+		best_val = abs(retune->configs[0].rate - wm9081->fs);
+		for (i = 0; i < retune->num_configs; i++) {
+			cur_val = abs(retune->configs[i].rate - wm9081->fs);
+			if (cur_val < best_val) {
+				best_val = cur_val;
+				best = i;
+			}
+		}
+		s = &retune->configs[best];
+
+		dev_dbg(codec->dev, "ReTune Mobile %s tuned for %dHz\n",
+			s->name, s->rate);
+
+		/* If the EQ is enabled then disable it while we write out */
+		eq1 = wm9081_read(codec, WM9081_EQ_1) & WM9081_EQ_ENA;
+		if (eq1 & WM9081_EQ_ENA)
+			wm9081_write(codec, WM9081_EQ_1, 0);
+
+		/* Write out the other values */
+		for (i = 1; i < ARRAY_SIZE(s->config); i++)
+			wm9081_write(codec, WM9081_EQ_1 + i, s->config[i]);
+
+		eq1 |= (s->config[0] & ~WM9081_EQ_ENA);
+		wm9081_write(codec, WM9081_EQ_1, eq1);
+	}
+
+	wm9081_write(codec, WM9081_CLOCK_CONTROL_2, clk_ctrl2);
+	wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2);
+	wm9081_write(codec, WM9081_AUDIO_INTERFACE_3, aif3);
+	wm9081_write(codec, WM9081_AUDIO_INTERFACE_4, aif4);
+
+	return 0;
+}
+
+static int wm9081_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	unsigned int reg;
+
+	reg = wm9081_read(codec, WM9081_DAC_DIGITAL_2);
+
+	if (mute)
+		reg |= WM9081_DAC_MUTE;
+	else
+		reg &= ~WM9081_DAC_MUTE;
+
+	wm9081_write(codec, WM9081_DAC_DIGITAL_2, reg);
+
+	return 0;
+}
+
+static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai,
+			     int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct wm9081_priv *wm9081 = codec->private_data;
+
+	switch (clk_id) {
+	case WM9081_SYSCLK_MCLK:
+	case WM9081_SYSCLK_FLL_MCLK:
+		wm9081->sysclk_source = clk_id;
+		wm9081->mclk_rate = freq;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
+			       unsigned int mask, int slots)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1);
+
+	aif1 &= ~(WM9081_AIFDAC_TDM_SLOT_MASK | WM9081_AIFDAC_TDM_MODE_MASK);
+
+	if (slots < 1 || slots > 4)
+		return -EINVAL;
+
+	aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT;
+
+	switch (mask) {
+	case 1:
+		break;
+	case 2:
+		aif1 |= 0x10;
+		break;
+	case 4:
+		aif1 |= 0x20;
+		break;
+	case 8:
+		aif1 |= 0x30;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm9081_write(codec, WM9081_AUDIO_INTERFACE_1, aif1);
+
+	return 0;
+}
+
+#define WM9081_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM9081_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_ops wm9081_dai_ops = {
+	.hw_params = wm9081_hw_params,
+	.set_sysclk = wm9081_set_sysclk,
+	.set_fmt = wm9081_set_dai_fmt,
+	.digital_mute = wm9081_digital_mute,
+	.set_tdm_slot = wm9081_set_tdm_slot,
+};
+
+/* We report two channels because the CODEC processes a stereo signal, even
+ * though it is only capable of handling a mono output.
+ */
+struct snd_soc_dai wm9081_dai = {
+	.name = "WM9081",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM9081_RATES,
+		.formats = WM9081_FORMATS,
+	},
+	.ops = &wm9081_dai_ops,
+};
+EXPORT_SYMBOL_GPL(wm9081_dai);
+
+
+static struct snd_soc_codec *wm9081_codec;
+
+static int wm9081_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	struct wm9081_priv *wm9081;
+	int ret = 0;
+
+	if (wm9081_codec == NULL) {
+		dev_err(&pdev->dev, "Codec device not registered\n");
+		return -ENODEV;
+	}
+
+	socdev->card->codec = wm9081_codec;
+	codec = wm9081_codec;
+	wm9081 = codec->private_data;
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+		goto pcm_err;
+	}
+
+	snd_soc_add_controls(codec, wm9081_snd_controls,
+			     ARRAY_SIZE(wm9081_snd_controls));
+	if (!wm9081->retune) {
+		dev_dbg(codec->dev,
+			"No ReTune Mobile data, using normal EQ\n");
+		snd_soc_add_controls(codec, wm9081_eq_controls,
+				     ARRAY_SIZE(wm9081_eq_controls));
+	}
+
+	snd_soc_dapm_new_controls(codec, wm9081_dapm_widgets,
+				  ARRAY_SIZE(wm9081_dapm_widgets));
+	snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
+	snd_soc_dapm_new_widgets(codec);
+
+	ret = snd_soc_init_card(socdev);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to register card: %d\n", ret);
+		goto card_err;
+	}
+
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	return ret;
+}
+
+static int wm9081_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm9081_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int wm9081_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+	u16 *reg_cache = codec->reg_cache;
+	int i;
+
+	for (i = 0; i < codec->reg_cache_size; i++) {
+		if (i == WM9081_SOFTWARE_RESET)
+			continue;
+
+		wm9081_write(codec, i, reg_cache[i]);
+	}
+
+	wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+#else
+#define wm9081_suspend NULL
+#define wm9081_resume NULL
+#endif
+
+struct snd_soc_codec_device soc_codec_dev_wm9081 = {
+	.probe = 	wm9081_probe,
+	.remove = 	wm9081_remove,
+	.suspend =	wm9081_suspend,
+	.resume =	wm9081_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm9081);
+
+static int wm9081_register(struct wm9081_priv *wm9081)
+{
+	struct snd_soc_codec *codec = &wm9081->codec;
+	int ret;
+	u16 reg;
+
+	if (wm9081_codec) {
+		dev_err(codec->dev, "Another WM9081 is registered\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	codec->private_data = wm9081;
+	codec->name = "WM9081";
+	codec->owner = THIS_MODULE;
+	codec->read = wm9081_read;
+	codec->write = wm9081_write;
+	codec->dai = &wm9081_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = ARRAY_SIZE(wm9081->reg_cache);
+	codec->reg_cache = &wm9081->reg_cache;
+	codec->bias_level = SND_SOC_BIAS_OFF;
+	codec->set_bias_level = wm9081_set_bias_level;
+
+	memcpy(codec->reg_cache, wm9081_reg_defaults,
+	       sizeof(wm9081_reg_defaults));
+
+	reg = wm9081_read_hw(codec, WM9081_SOFTWARE_RESET);
+	if (reg != 0x9081) {
+		dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret = wm9081_reset(codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	/* Enable zero cross by default */
+	reg = wm9081_read(codec, WM9081_ANALOGUE_LINEOUT);
+	wm9081_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC);
+	reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_PGA);
+	wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
+		     reg | WM9081_SPKPGAZC);
+
+	wm9081_dai.dev = codec->dev;
+
+	wm9081_codec = codec;
+
+	ret = snd_soc_register_codec(codec);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_register_dai(&wm9081_dai);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+		snd_soc_unregister_codec(codec);
+		return ret;
+	}
+
+	return 0;
+
+err:
+	kfree(wm9081);
+	return ret;
+}
+
+static void wm9081_unregister(struct wm9081_priv *wm9081)
+{
+	wm9081_set_bias_level(&wm9081->codec, SND_SOC_BIAS_OFF);
+	snd_soc_unregister_dai(&wm9081_dai);
+	snd_soc_unregister_codec(&wm9081->codec);
+	kfree(wm9081);
+	wm9081_codec = NULL;
+}
+
+static __devinit int wm9081_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct wm9081_priv *wm9081;
+	struct snd_soc_codec *codec;
+
+	wm9081 = kzalloc(sizeof(struct wm9081_priv), GFP_KERNEL);
+	if (wm9081 == NULL)
+		return -ENOMEM;
+
+	codec = &wm9081->codec;
+	codec->hw_write = (hw_write_t)i2c_master_send;
+	wm9081->retune = i2c->dev.platform_data;
+
+	i2c_set_clientdata(i2c, wm9081);
+	codec->control_data = i2c;
+
+	codec->dev = &i2c->dev;
+
+	return wm9081_register(wm9081);
+}
+
+static __devexit int wm9081_i2c_remove(struct i2c_client *client)
+{
+	struct wm9081_priv *wm9081 = i2c_get_clientdata(client);
+	wm9081_unregister(wm9081);
+	return 0;
+}
+
+static const struct i2c_device_id wm9081_i2c_id[] = {
+	{ "wm9081", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id);
+
+static struct i2c_driver wm9081_i2c_driver = {
+	.driver = {
+		.name = "wm9081",
+		.owner = THIS_MODULE,
+	},
+	.probe =    wm9081_i2c_probe,
+	.remove =   __devexit_p(wm9081_i2c_remove),
+	.id_table = wm9081_i2c_id,
+};
+
+static int __init wm9081_modinit(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&wm9081_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM9081 I2C driver: %d\n",
+		       ret);
+	}
+
+	return ret;
+}
+module_init(wm9081_modinit);
+
+static void __exit wm9081_exit(void)
+{
+	i2c_del_driver(&wm9081_i2c_driver);
+}
+module_exit(wm9081_exit);
+
+
+MODULE_DESCRIPTION("ASoC WM9081 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm9081.h b/sound/soc/codecs/wm9081.h
new file mode 100644
index 0000000..42d3bc7
--- /dev/null
+++ b/sound/soc/codecs/wm9081.h
@@ -0,0 +1,787 @@
+#ifndef WM9081_H
+#define WM9081_H
+
+/*
+ * wm9081.c  --  WM9081 ALSA SoC Audio driver
+ *
+ * Author: Mark Brown
+ *
+ * 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 <sound/soc.h>
+
+extern struct snd_soc_dai wm9081_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm9081;
+
+/*
+ * SYSCLK sources
+ */
+#define WM9081_SYSCLK_MCLK      1   /* Use MCLK without FLL */
+#define WM9081_SYSCLK_FLL_MCLK  2   /* Use MCLK, enabling FLL if required */
+
+/*
+ * Register values.
+ */
+#define WM9081_SOFTWARE_RESET                   0x00
+#define WM9081_ANALOGUE_LINEOUT                 0x02
+#define WM9081_ANALOGUE_SPEAKER_PGA             0x03
+#define WM9081_VMID_CONTROL                     0x04
+#define WM9081_BIAS_CONTROL_1                   0x05
+#define WM9081_ANALOGUE_MIXER                   0x07
+#define WM9081_ANTI_POP_CONTROL                 0x08
+#define WM9081_ANALOGUE_SPEAKER_1               0x09
+#define WM9081_ANALOGUE_SPEAKER_2               0x0A
+#define WM9081_POWER_MANAGEMENT                 0x0B
+#define WM9081_CLOCK_CONTROL_1                  0x0C
+#define WM9081_CLOCK_CONTROL_2                  0x0D
+#define WM9081_CLOCK_CONTROL_3                  0x0E
+#define WM9081_FLL_CONTROL_1                    0x10
+#define WM9081_FLL_CONTROL_2                    0x11
+#define WM9081_FLL_CONTROL_3                    0x12
+#define WM9081_FLL_CONTROL_4                    0x13
+#define WM9081_FLL_CONTROL_5                    0x14
+#define WM9081_AUDIO_INTERFACE_1                0x16
+#define WM9081_AUDIO_INTERFACE_2                0x17
+#define WM9081_AUDIO_INTERFACE_3                0x18
+#define WM9081_AUDIO_INTERFACE_4                0x19
+#define WM9081_INTERRUPT_STATUS                 0x1A
+#define WM9081_INTERRUPT_STATUS_MASK            0x1B
+#define WM9081_INTERRUPT_POLARITY               0x1C
+#define WM9081_INTERRUPT_CONTROL                0x1D
+#define WM9081_DAC_DIGITAL_1                    0x1E
+#define WM9081_DAC_DIGITAL_2                    0x1F
+#define WM9081_DRC_1                            0x20
+#define WM9081_DRC_2                            0x21
+#define WM9081_DRC_3                            0x22
+#define WM9081_DRC_4                            0x23
+#define WM9081_WRITE_SEQUENCER_1                0x26
+#define WM9081_WRITE_SEQUENCER_2                0x27
+#define WM9081_MW_SLAVE_1                       0x28
+#define WM9081_EQ_1                             0x2A
+#define WM9081_EQ_2                             0x2B
+#define WM9081_EQ_3                             0x2C
+#define WM9081_EQ_4                             0x2D
+#define WM9081_EQ_5                             0x2E
+#define WM9081_EQ_6                             0x2F
+#define WM9081_EQ_7                             0x30
+#define WM9081_EQ_8                             0x31
+#define WM9081_EQ_9                             0x32
+#define WM9081_EQ_10                            0x33
+#define WM9081_EQ_11                            0x34
+#define WM9081_EQ_12                            0x35
+#define WM9081_EQ_13                            0x36
+#define WM9081_EQ_14                            0x37
+#define WM9081_EQ_15                            0x38
+#define WM9081_EQ_16                            0x39
+#define WM9081_EQ_17                            0x3A
+#define WM9081_EQ_18                            0x3B
+#define WM9081_EQ_19                            0x3C
+#define WM9081_EQ_20                            0x3D
+
+#define WM9081_REGISTER_COUNT                   55
+#define WM9081_MAX_REGISTER                     0x3D
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM9081_SW_RST_DEV_ID1_MASK              0xFFFF  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM9081_SW_RST_DEV_ID1_SHIFT                  0  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM9081_SW_RST_DEV_ID1_WIDTH                 16  /* SW_RST_DEV_ID1 - [15:0] */
+
+/*
+ * R2 (0x02) - Analogue Lineout
+ */
+#define WM9081_LINEOUT_MUTE                     0x0080  /* LINEOUT_MUTE */
+#define WM9081_LINEOUT_MUTE_MASK                0x0080  /* LINEOUT_MUTE */
+#define WM9081_LINEOUT_MUTE_SHIFT                    7  /* LINEOUT_MUTE */
+#define WM9081_LINEOUT_MUTE_WIDTH                    1  /* LINEOUT_MUTE */
+#define WM9081_LINEOUTZC                        0x0040  /* LINEOUTZC */
+#define WM9081_LINEOUTZC_MASK                   0x0040  /* LINEOUTZC */
+#define WM9081_LINEOUTZC_SHIFT                       6  /* LINEOUTZC */
+#define WM9081_LINEOUTZC_WIDTH                       1  /* LINEOUTZC */
+#define WM9081_LINEOUT_VOL_MASK                 0x003F  /* LINEOUT_VOL - [5:0] */
+#define WM9081_LINEOUT_VOL_SHIFT                     0  /* LINEOUT_VOL - [5:0] */
+#define WM9081_LINEOUT_VOL_WIDTH                     6  /* LINEOUT_VOL - [5:0] */
+
+/*
+ * R3 (0x03) - Analogue Speaker PGA
+ */
+#define WM9081_SPKPGA_MUTE                      0x0080  /* SPKPGA_MUTE */
+#define WM9081_SPKPGA_MUTE_MASK                 0x0080  /* SPKPGA_MUTE */
+#define WM9081_SPKPGA_MUTE_SHIFT                     7  /* SPKPGA_MUTE */
+#define WM9081_SPKPGA_MUTE_WIDTH                     1  /* SPKPGA_MUTE */
+#define WM9081_SPKPGAZC                         0x0040  /* SPKPGAZC */
+#define WM9081_SPKPGAZC_MASK                    0x0040  /* SPKPGAZC */
+#define WM9081_SPKPGAZC_SHIFT                        6  /* SPKPGAZC */
+#define WM9081_SPKPGAZC_WIDTH                        1  /* SPKPGAZC */
+#define WM9081_SPKPGA_VOL_MASK                  0x003F  /* SPKPGA_VOL - [5:0] */
+#define WM9081_SPKPGA_VOL_SHIFT                      0  /* SPKPGA_VOL - [5:0] */
+#define WM9081_SPKPGA_VOL_WIDTH                      6  /* SPKPGA_VOL - [5:0] */
+
+/*
+ * R4 (0x04) - VMID Control
+ */
+#define WM9081_VMID_BUF_ENA                     0x0020  /* VMID_BUF_ENA */
+#define WM9081_VMID_BUF_ENA_MASK                0x0020  /* VMID_BUF_ENA */
+#define WM9081_VMID_BUF_ENA_SHIFT                    5  /* VMID_BUF_ENA */
+#define WM9081_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
+#define WM9081_VMID_RAMP                        0x0008  /* VMID_RAMP */
+#define WM9081_VMID_RAMP_MASK                   0x0008  /* VMID_RAMP */
+#define WM9081_VMID_RAMP_SHIFT                       3  /* VMID_RAMP */
+#define WM9081_VMID_RAMP_WIDTH                       1  /* VMID_RAMP */
+#define WM9081_VMID_SEL_MASK                    0x0006  /* VMID_SEL - [2:1] */
+#define WM9081_VMID_SEL_SHIFT                        1  /* VMID_SEL - [2:1] */
+#define WM9081_VMID_SEL_WIDTH                        2  /* VMID_SEL - [2:1] */
+#define WM9081_VMID_FAST_ST                     0x0001  /* VMID_FAST_ST */
+#define WM9081_VMID_FAST_ST_MASK                0x0001  /* VMID_FAST_ST */
+#define WM9081_VMID_FAST_ST_SHIFT                    0  /* VMID_FAST_ST */
+#define WM9081_VMID_FAST_ST_WIDTH                    1  /* VMID_FAST_ST */
+
+/*
+ * R5 (0x05) - Bias Control 1
+ */
+#define WM9081_BIAS_SRC                         0x0040  /* BIAS_SRC */
+#define WM9081_BIAS_SRC_MASK                    0x0040  /* BIAS_SRC */
+#define WM9081_BIAS_SRC_SHIFT                        6  /* BIAS_SRC */
+#define WM9081_BIAS_SRC_WIDTH                        1  /* BIAS_SRC */
+#define WM9081_STBY_BIAS_LVL                    0x0020  /* STBY_BIAS_LVL */
+#define WM9081_STBY_BIAS_LVL_MASK               0x0020  /* STBY_BIAS_LVL */
+#define WM9081_STBY_BIAS_LVL_SHIFT                   5  /* STBY_BIAS_LVL */
+#define WM9081_STBY_BIAS_LVL_WIDTH                   1  /* STBY_BIAS_LVL */
+#define WM9081_STBY_BIAS_ENA                    0x0010  /* STBY_BIAS_ENA */
+#define WM9081_STBY_BIAS_ENA_MASK               0x0010  /* STBY_BIAS_ENA */
+#define WM9081_STBY_BIAS_ENA_SHIFT                   4  /* STBY_BIAS_ENA */
+#define WM9081_STBY_BIAS_ENA_WIDTH                   1  /* STBY_BIAS_ENA */
+#define WM9081_BIAS_LVL_MASK                    0x000C  /* BIAS_LVL - [3:2] */
+#define WM9081_BIAS_LVL_SHIFT                        2  /* BIAS_LVL - [3:2] */
+#define WM9081_BIAS_LVL_WIDTH                        2  /* BIAS_LVL - [3:2] */
+#define WM9081_BIAS_ENA                         0x0002  /* BIAS_ENA */
+#define WM9081_BIAS_ENA_MASK                    0x0002  /* BIAS_ENA */
+#define WM9081_BIAS_ENA_SHIFT                        1  /* BIAS_ENA */
+#define WM9081_BIAS_ENA_WIDTH                        1  /* BIAS_ENA */
+#define WM9081_STARTUP_BIAS_ENA                 0x0001  /* STARTUP_BIAS_ENA */
+#define WM9081_STARTUP_BIAS_ENA_MASK            0x0001  /* STARTUP_BIAS_ENA */
+#define WM9081_STARTUP_BIAS_ENA_SHIFT                0  /* STARTUP_BIAS_ENA */
+#define WM9081_STARTUP_BIAS_ENA_WIDTH                1  /* STARTUP_BIAS_ENA */
+
+/*
+ * R7 (0x07) - Analogue Mixer
+ */
+#define WM9081_DAC_SEL                          0x0010  /* DAC_SEL */
+#define WM9081_DAC_SEL_MASK                     0x0010  /* DAC_SEL */
+#define WM9081_DAC_SEL_SHIFT                         4  /* DAC_SEL */
+#define WM9081_DAC_SEL_WIDTH                         1  /* DAC_SEL */
+#define WM9081_IN2_VOL                          0x0008  /* IN2_VOL */
+#define WM9081_IN2_VOL_MASK                     0x0008  /* IN2_VOL */
+#define WM9081_IN2_VOL_SHIFT                         3  /* IN2_VOL */
+#define WM9081_IN2_VOL_WIDTH                         1  /* IN2_VOL */
+#define WM9081_IN2_ENA                          0x0004  /* IN2_ENA */
+#define WM9081_IN2_ENA_MASK                     0x0004  /* IN2_ENA */
+#define WM9081_IN2_ENA_SHIFT                         2  /* IN2_ENA */
+#define WM9081_IN2_ENA_WIDTH                         1  /* IN2_ENA */
+#define WM9081_IN1_VOL                          0x0002  /* IN1_VOL */
+#define WM9081_IN1_VOL_MASK                     0x0002  /* IN1_VOL */
+#define WM9081_IN1_VOL_SHIFT                         1  /* IN1_VOL */
+#define WM9081_IN1_VOL_WIDTH                         1  /* IN1_VOL */
+#define WM9081_IN1_ENA                          0x0001  /* IN1_ENA */
+#define WM9081_IN1_ENA_MASK                     0x0001  /* IN1_ENA */
+#define WM9081_IN1_ENA_SHIFT                         0  /* IN1_ENA */
+#define WM9081_IN1_ENA_WIDTH                         1  /* IN1_ENA */
+
+/*
+ * R8 (0x08) - Anti Pop Control
+ */
+#define WM9081_LINEOUT_DISCH                    0x0004  /* LINEOUT_DISCH */
+#define WM9081_LINEOUT_DISCH_MASK               0x0004  /* LINEOUT_DISCH */
+#define WM9081_LINEOUT_DISCH_SHIFT                   2  /* LINEOUT_DISCH */
+#define WM9081_LINEOUT_DISCH_WIDTH                   1  /* LINEOUT_DISCH */
+#define WM9081_LINEOUT_VROI                     0x0002  /* LINEOUT_VROI */
+#define WM9081_LINEOUT_VROI_MASK                0x0002  /* LINEOUT_VROI */
+#define WM9081_LINEOUT_VROI_SHIFT                    1  /* LINEOUT_VROI */
+#define WM9081_LINEOUT_VROI_WIDTH                    1  /* LINEOUT_VROI */
+#define WM9081_LINEOUT_CLAMP                    0x0001  /* LINEOUT_CLAMP */
+#define WM9081_LINEOUT_CLAMP_MASK               0x0001  /* LINEOUT_CLAMP */
+#define WM9081_LINEOUT_CLAMP_SHIFT                   0  /* LINEOUT_CLAMP */
+#define WM9081_LINEOUT_CLAMP_WIDTH                   1  /* LINEOUT_CLAMP */
+
+/*
+ * R9 (0x09) - Analogue Speaker 1
+ */
+#define WM9081_SPK_DCGAIN_MASK                  0x0038  /* SPK_DCGAIN - [5:3] */
+#define WM9081_SPK_DCGAIN_SHIFT                      3  /* SPK_DCGAIN - [5:3] */
+#define WM9081_SPK_DCGAIN_WIDTH                      3  /* SPK_DCGAIN - [5:3] */
+#define WM9081_SPK_ACGAIN_MASK                  0x0007  /* SPK_ACGAIN - [2:0] */
+#define WM9081_SPK_ACGAIN_SHIFT                      0  /* SPK_ACGAIN - [2:0] */
+#define WM9081_SPK_ACGAIN_WIDTH                      3  /* SPK_ACGAIN - [2:0] */
+
+/*
+ * R10 (0x0A) - Analogue Speaker 2
+ */
+#define WM9081_SPK_MODE                         0x0040  /* SPK_MODE */
+#define WM9081_SPK_MODE_MASK                    0x0040  /* SPK_MODE */
+#define WM9081_SPK_MODE_SHIFT                        6  /* SPK_MODE */
+#define WM9081_SPK_MODE_WIDTH                        1  /* SPK_MODE */
+#define WM9081_SPK_INV_MUTE                     0x0010  /* SPK_INV_MUTE */
+#define WM9081_SPK_INV_MUTE_MASK                0x0010  /* SPK_INV_MUTE */
+#define WM9081_SPK_INV_MUTE_SHIFT                    4  /* SPK_INV_MUTE */
+#define WM9081_SPK_INV_MUTE_WIDTH                    1  /* SPK_INV_MUTE */
+#define WM9081_OUT_SPK_CTRL                     0x0008  /* OUT_SPK_CTRL */
+#define WM9081_OUT_SPK_CTRL_MASK                0x0008  /* OUT_SPK_CTRL */
+#define WM9081_OUT_SPK_CTRL_SHIFT                    3  /* OUT_SPK_CTRL */
+#define WM9081_OUT_SPK_CTRL_WIDTH                    1  /* OUT_SPK_CTRL */
+
+/*
+ * R11 (0x0B) - Power Management
+ */
+#define WM9081_TSHUT_ENA                        0x0100  /* TSHUT_ENA */
+#define WM9081_TSHUT_ENA_MASK                   0x0100  /* TSHUT_ENA */
+#define WM9081_TSHUT_ENA_SHIFT                       8  /* TSHUT_ENA */
+#define WM9081_TSHUT_ENA_WIDTH                       1  /* TSHUT_ENA */
+#define WM9081_TSENSE_ENA                       0x0080  /* TSENSE_ENA */
+#define WM9081_TSENSE_ENA_MASK                  0x0080  /* TSENSE_ENA */
+#define WM9081_TSENSE_ENA_SHIFT                      7  /* TSENSE_ENA */
+#define WM9081_TSENSE_ENA_WIDTH                      1  /* TSENSE_ENA */
+#define WM9081_TEMP_SHUT                        0x0040  /* TEMP_SHUT */
+#define WM9081_TEMP_SHUT_MASK                   0x0040  /* TEMP_SHUT */
+#define WM9081_TEMP_SHUT_SHIFT                       6  /* TEMP_SHUT */
+#define WM9081_TEMP_SHUT_WIDTH                       1  /* TEMP_SHUT */
+#define WM9081_LINEOUT_ENA                      0x0010  /* LINEOUT_ENA */
+#define WM9081_LINEOUT_ENA_MASK                 0x0010  /* LINEOUT_ENA */
+#define WM9081_LINEOUT_ENA_SHIFT                     4  /* LINEOUT_ENA */
+#define WM9081_LINEOUT_ENA_WIDTH                     1  /* LINEOUT_ENA */
+#define WM9081_SPKPGA_ENA                       0x0004  /* SPKPGA_ENA */
+#define WM9081_SPKPGA_ENA_MASK                  0x0004  /* SPKPGA_ENA */
+#define WM9081_SPKPGA_ENA_SHIFT                      2  /* SPKPGA_ENA */
+#define WM9081_SPKPGA_ENA_WIDTH                      1  /* SPKPGA_ENA */
+#define WM9081_SPK_ENA                          0x0002  /* SPK_ENA */
+#define WM9081_SPK_ENA_MASK                     0x0002  /* SPK_ENA */
+#define WM9081_SPK_ENA_SHIFT                         1  /* SPK_ENA */
+#define WM9081_SPK_ENA_WIDTH                         1  /* SPK_ENA */
+#define WM9081_DAC_ENA                          0x0001  /* DAC_ENA */
+#define WM9081_DAC_ENA_MASK                     0x0001  /* DAC_ENA */
+#define WM9081_DAC_ENA_SHIFT                         0  /* DAC_ENA */
+#define WM9081_DAC_ENA_WIDTH                         1  /* DAC_ENA */
+
+/*
+ * R12 (0x0C) - Clock Control 1
+ */
+#define WM9081_CLK_OP_DIV_MASK                  0x1C00  /* CLK_OP_DIV - [12:10] */
+#define WM9081_CLK_OP_DIV_SHIFT                     10  /* CLK_OP_DIV - [12:10] */
+#define WM9081_CLK_OP_DIV_WIDTH                      3  /* CLK_OP_DIV - [12:10] */
+#define WM9081_CLK_TO_DIV_MASK                  0x0300  /* CLK_TO_DIV - [9:8] */
+#define WM9081_CLK_TO_DIV_SHIFT                      8  /* CLK_TO_DIV - [9:8] */
+#define WM9081_CLK_TO_DIV_WIDTH                      2  /* CLK_TO_DIV - [9:8] */
+#define WM9081_MCLKDIV2                         0x0080  /* MCLKDIV2 */
+#define WM9081_MCLKDIV2_MASK                    0x0080  /* MCLKDIV2 */
+#define WM9081_MCLKDIV2_SHIFT                        7  /* MCLKDIV2 */
+#define WM9081_MCLKDIV2_WIDTH                        1  /* MCLKDIV2 */
+
+/*
+ * R13 (0x0D) - Clock Control 2
+ */
+#define WM9081_CLK_SYS_RATE_MASK                0x00F0  /* CLK_SYS_RATE - [7:4] */
+#define WM9081_CLK_SYS_RATE_SHIFT                    4  /* CLK_SYS_RATE - [7:4] */
+#define WM9081_CLK_SYS_RATE_WIDTH                    4  /* CLK_SYS_RATE - [7:4] */
+#define WM9081_SAMPLE_RATE_MASK                 0x000F  /* SAMPLE_RATE - [3:0] */
+#define WM9081_SAMPLE_RATE_SHIFT                     0  /* SAMPLE_RATE - [3:0] */
+#define WM9081_SAMPLE_RATE_WIDTH                     4  /* SAMPLE_RATE - [3:0] */
+
+/*
+ * R14 (0x0E) - Clock Control 3
+ */
+#define WM9081_CLK_SRC_SEL                      0x2000  /* CLK_SRC_SEL */
+#define WM9081_CLK_SRC_SEL_MASK                 0x2000  /* CLK_SRC_SEL */
+#define WM9081_CLK_SRC_SEL_SHIFT                    13  /* CLK_SRC_SEL */
+#define WM9081_CLK_SRC_SEL_WIDTH                     1  /* CLK_SRC_SEL */
+#define WM9081_CLK_OP_ENA                       0x0020  /* CLK_OP_ENA */
+#define WM9081_CLK_OP_ENA_MASK                  0x0020  /* CLK_OP_ENA */
+#define WM9081_CLK_OP_ENA_SHIFT                      5  /* CLK_OP_ENA */
+#define WM9081_CLK_OP_ENA_WIDTH                      1  /* CLK_OP_ENA */
+#define WM9081_CLK_TO_ENA                       0x0004  /* CLK_TO_ENA */
+#define WM9081_CLK_TO_ENA_MASK                  0x0004  /* CLK_TO_ENA */
+#define WM9081_CLK_TO_ENA_SHIFT                      2  /* CLK_TO_ENA */
+#define WM9081_CLK_TO_ENA_WIDTH                      1  /* CLK_TO_ENA */
+#define WM9081_CLK_DSP_ENA                      0x0002  /* CLK_DSP_ENA */
+#define WM9081_CLK_DSP_ENA_MASK                 0x0002  /* CLK_DSP_ENA */
+#define WM9081_CLK_DSP_ENA_SHIFT                     1  /* CLK_DSP_ENA */
+#define WM9081_CLK_DSP_ENA_WIDTH                     1  /* CLK_DSP_ENA */
+#define WM9081_CLK_SYS_ENA                      0x0001  /* CLK_SYS_ENA */
+#define WM9081_CLK_SYS_ENA_MASK                 0x0001  /* CLK_SYS_ENA */
+#define WM9081_CLK_SYS_ENA_SHIFT                     0  /* CLK_SYS_ENA */
+#define WM9081_CLK_SYS_ENA_WIDTH                     1  /* CLK_SYS_ENA */
+
+/*
+ * R16 (0x10) - FLL Control 1
+ */
+#define WM9081_FLL_HOLD                         0x0008  /* FLL_HOLD */
+#define WM9081_FLL_HOLD_MASK                    0x0008  /* FLL_HOLD */
+#define WM9081_FLL_HOLD_SHIFT                        3  /* FLL_HOLD */
+#define WM9081_FLL_HOLD_WIDTH                        1  /* FLL_HOLD */
+#define WM9081_FLL_FRAC                         0x0004  /* FLL_FRAC */
+#define WM9081_FLL_FRAC_MASK                    0x0004  /* FLL_FRAC */
+#define WM9081_FLL_FRAC_SHIFT                        2  /* FLL_FRAC */
+#define WM9081_FLL_FRAC_WIDTH                        1  /* FLL_FRAC */
+#define WM9081_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM9081_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM9081_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM9081_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R17 (0x11) - FLL Control 2
+ */
+#define WM9081_FLL_OUTDIV_MASK                  0x0700  /* FLL_OUTDIV - [10:8] */
+#define WM9081_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [10:8] */
+#define WM9081_FLL_OUTDIV_WIDTH                      3  /* FLL_OUTDIV - [10:8] */
+#define WM9081_FLL_CTRL_RATE_MASK               0x0070  /* FLL_CTRL_RATE - [6:4] */
+#define WM9081_FLL_CTRL_RATE_SHIFT                   4  /* FLL_CTRL_RATE - [6:4] */
+#define WM9081_FLL_CTRL_RATE_WIDTH                   3  /* FLL_CTRL_RATE - [6:4] */
+#define WM9081_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM9081_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM9081_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R18 (0x12) - FLL Control 3
+ */
+#define WM9081_FLL_K_MASK                       0xFFFF  /* FLL_K - [15:0] */
+#define WM9081_FLL_K_SHIFT                           0  /* FLL_K - [15:0] */
+#define WM9081_FLL_K_WIDTH                          16  /* FLL_K - [15:0] */
+
+/*
+ * R19 (0x13) - FLL Control 4
+ */
+#define WM9081_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM9081_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM9081_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM9081_FLL_GAIN_MASK                    0x000F  /* FLL_GAIN - [3:0] */
+#define WM9081_FLL_GAIN_SHIFT                        0  /* FLL_GAIN - [3:0] */
+#define WM9081_FLL_GAIN_WIDTH                        4  /* FLL_GAIN - [3:0] */
+
+/*
+ * R20 (0x14) - FLL Control 5
+ */
+#define WM9081_FLL_CLK_REF_DIV_MASK             0x0018  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM9081_FLL_CLK_REF_DIV_SHIFT                 3  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM9081_FLL_CLK_REF_DIV_WIDTH                 2  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM9081_FLL_CLK_SRC_MASK                 0x0003  /* FLL_CLK_SRC - [1:0] */
+#define WM9081_FLL_CLK_SRC_SHIFT                     0  /* FLL_CLK_SRC - [1:0] */
+#define WM9081_FLL_CLK_SRC_WIDTH                     2  /* FLL_CLK_SRC - [1:0] */
+
+/*
+ * R22 (0x16) - Audio Interface 1
+ */
+#define WM9081_AIFDAC_CHAN                      0x0040  /* AIFDAC_CHAN */
+#define WM9081_AIFDAC_CHAN_MASK                 0x0040  /* AIFDAC_CHAN */
+#define WM9081_AIFDAC_CHAN_SHIFT                     6  /* AIFDAC_CHAN */
+#define WM9081_AIFDAC_CHAN_WIDTH                     1  /* AIFDAC_CHAN */
+#define WM9081_AIFDAC_TDM_SLOT_MASK             0x0030  /* AIFDAC_TDM_SLOT - [5:4] */
+#define WM9081_AIFDAC_TDM_SLOT_SHIFT                 4  /* AIFDAC_TDM_SLOT - [5:4] */
+#define WM9081_AIFDAC_TDM_SLOT_WIDTH                 2  /* AIFDAC_TDM_SLOT - [5:4] */
+#define WM9081_AIFDAC_TDM_MODE_MASK             0x000C  /* AIFDAC_TDM_MODE - [3:2] */
+#define WM9081_AIFDAC_TDM_MODE_SHIFT                 2  /* AIFDAC_TDM_MODE - [3:2] */
+#define WM9081_AIFDAC_TDM_MODE_WIDTH                 2  /* AIFDAC_TDM_MODE - [3:2] */
+#define WM9081_DAC_COMP                         0x0002  /* DAC_COMP */
+#define WM9081_DAC_COMP_MASK                    0x0002  /* DAC_COMP */
+#define WM9081_DAC_COMP_SHIFT                        1  /* DAC_COMP */
+#define WM9081_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM9081_DAC_COMPMODE                     0x0001  /* DAC_COMPMODE */
+#define WM9081_DAC_COMPMODE_MASK                0x0001  /* DAC_COMPMODE */
+#define WM9081_DAC_COMPMODE_SHIFT                    0  /* DAC_COMPMODE */
+#define WM9081_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+
+/*
+ * R23 (0x17) - Audio Interface 2
+ */
+#define WM9081_AIF_TRIS                         0x0200  /* AIF_TRIS */
+#define WM9081_AIF_TRIS_MASK                    0x0200  /* AIF_TRIS */
+#define WM9081_AIF_TRIS_SHIFT                        9  /* AIF_TRIS */
+#define WM9081_AIF_TRIS_WIDTH                        1  /* AIF_TRIS */
+#define WM9081_DAC_DAT_INV                      0x0100  /* DAC_DAT_INV */
+#define WM9081_DAC_DAT_INV_MASK                 0x0100  /* DAC_DAT_INV */
+#define WM9081_DAC_DAT_INV_SHIFT                     8  /* DAC_DAT_INV */
+#define WM9081_DAC_DAT_INV_WIDTH                     1  /* DAC_DAT_INV */
+#define WM9081_AIF_BCLK_INV                     0x0080  /* AIF_BCLK_INV */
+#define WM9081_AIF_BCLK_INV_MASK                0x0080  /* AIF_BCLK_INV */
+#define WM9081_AIF_BCLK_INV_SHIFT                    7  /* AIF_BCLK_INV */
+#define WM9081_AIF_BCLK_INV_WIDTH                    1  /* AIF_BCLK_INV */
+#define WM9081_BCLK_DIR                         0x0040  /* BCLK_DIR */
+#define WM9081_BCLK_DIR_MASK                    0x0040  /* BCLK_DIR */
+#define WM9081_BCLK_DIR_SHIFT                        6  /* BCLK_DIR */
+#define WM9081_BCLK_DIR_WIDTH                        1  /* BCLK_DIR */
+#define WM9081_LRCLK_DIR                        0x0020  /* LRCLK_DIR */
+#define WM9081_LRCLK_DIR_MASK                   0x0020  /* LRCLK_DIR */
+#define WM9081_LRCLK_DIR_SHIFT                       5  /* LRCLK_DIR */
+#define WM9081_LRCLK_DIR_WIDTH                       1  /* LRCLK_DIR */
+#define WM9081_AIF_LRCLK_INV                    0x0010  /* AIF_LRCLK_INV */
+#define WM9081_AIF_LRCLK_INV_MASK               0x0010  /* AIF_LRCLK_INV */
+#define WM9081_AIF_LRCLK_INV_SHIFT                   4  /* AIF_LRCLK_INV */
+#define WM9081_AIF_LRCLK_INV_WIDTH                   1  /* AIF_LRCLK_INV */
+#define WM9081_AIF_WL_MASK                      0x000C  /* AIF_WL - [3:2] */
+#define WM9081_AIF_WL_SHIFT                          2  /* AIF_WL - [3:2] */
+#define WM9081_AIF_WL_WIDTH                          2  /* AIF_WL - [3:2] */
+#define WM9081_AIF_FMT_MASK                     0x0003  /* AIF_FMT - [1:0] */
+#define WM9081_AIF_FMT_SHIFT                         0  /* AIF_FMT - [1:0] */
+#define WM9081_AIF_FMT_WIDTH                         2  /* AIF_FMT - [1:0] */
+
+/*
+ * R24 (0x18) - Audio Interface 3
+ */
+#define WM9081_BCLK_DIV_MASK                    0x001F  /* BCLK_DIV - [4:0] */
+#define WM9081_BCLK_DIV_SHIFT                        0  /* BCLK_DIV - [4:0] */
+#define WM9081_BCLK_DIV_WIDTH                        5  /* BCLK_DIV - [4:0] */
+
+/*
+ * R25 (0x19) - Audio Interface 4
+ */
+#define WM9081_LRCLK_RATE_MASK                  0x07FF  /* LRCLK_RATE - [10:0] */
+#define WM9081_LRCLK_RATE_SHIFT                      0  /* LRCLK_RATE - [10:0] */
+#define WM9081_LRCLK_RATE_WIDTH                     11  /* LRCLK_RATE - [10:0] */
+
+/*
+ * R26 (0x1A) - Interrupt Status
+ */
+#define WM9081_WSEQ_BUSY_EINT                   0x0004  /* WSEQ_BUSY_EINT */
+#define WM9081_WSEQ_BUSY_EINT_MASK              0x0004  /* WSEQ_BUSY_EINT */
+#define WM9081_WSEQ_BUSY_EINT_SHIFT                  2  /* WSEQ_BUSY_EINT */
+#define WM9081_WSEQ_BUSY_EINT_WIDTH                  1  /* WSEQ_BUSY_EINT */
+#define WM9081_TSHUT_EINT                       0x0001  /* TSHUT_EINT */
+#define WM9081_TSHUT_EINT_MASK                  0x0001  /* TSHUT_EINT */
+#define WM9081_TSHUT_EINT_SHIFT                      0  /* TSHUT_EINT */
+#define WM9081_TSHUT_EINT_WIDTH                      1  /* TSHUT_EINT */
+
+/*
+ * R27 (0x1B) - Interrupt Status Mask
+ */
+#define WM9081_IM_WSEQ_BUSY_EINT                0x0004  /* IM_WSEQ_BUSY_EINT */
+#define WM9081_IM_WSEQ_BUSY_EINT_MASK           0x0004  /* IM_WSEQ_BUSY_EINT */
+#define WM9081_IM_WSEQ_BUSY_EINT_SHIFT               2  /* IM_WSEQ_BUSY_EINT */
+#define WM9081_IM_WSEQ_BUSY_EINT_WIDTH               1  /* IM_WSEQ_BUSY_EINT */
+#define WM9081_IM_TSHUT_EINT                    0x0001  /* IM_TSHUT_EINT */
+#define WM9081_IM_TSHUT_EINT_MASK               0x0001  /* IM_TSHUT_EINT */
+#define WM9081_IM_TSHUT_EINT_SHIFT                   0  /* IM_TSHUT_EINT */
+#define WM9081_IM_TSHUT_EINT_WIDTH                   1  /* IM_TSHUT_EINT */
+
+/*
+ * R28 (0x1C) - Interrupt Polarity
+ */
+#define WM9081_TSHUT_INV                        0x0001  /* TSHUT_INV */
+#define WM9081_TSHUT_INV_MASK                   0x0001  /* TSHUT_INV */
+#define WM9081_TSHUT_INV_SHIFT                       0  /* TSHUT_INV */
+#define WM9081_TSHUT_INV_WIDTH                       1  /* TSHUT_INV */
+
+/*
+ * R29 (0x1D) - Interrupt Control
+ */
+#define WM9081_IRQ_POL                          0x8000  /* IRQ_POL */
+#define WM9081_IRQ_POL_MASK                     0x8000  /* IRQ_POL */
+#define WM9081_IRQ_POL_SHIFT                        15  /* IRQ_POL */
+#define WM9081_IRQ_POL_WIDTH                         1  /* IRQ_POL */
+#define WM9081_IRQ_OP_CTRL                      0x0001  /* IRQ_OP_CTRL */
+#define WM9081_IRQ_OP_CTRL_MASK                 0x0001  /* IRQ_OP_CTRL */
+#define WM9081_IRQ_OP_CTRL_SHIFT                     0  /* IRQ_OP_CTRL */
+#define WM9081_IRQ_OP_CTRL_WIDTH                     1  /* IRQ_OP_CTRL */
+
+/*
+ * R30 (0x1E) - DAC Digital 1
+ */
+#define WM9081_DAC_VOL_MASK                     0x00FF  /* DAC_VOL - [7:0] */
+#define WM9081_DAC_VOL_SHIFT                         0  /* DAC_VOL - [7:0] */
+#define WM9081_DAC_VOL_WIDTH                         8  /* DAC_VOL - [7:0] */
+
+/*
+ * R31 (0x1F) - DAC Digital 2
+ */
+#define WM9081_DAC_MUTERATE                     0x0400  /* DAC_MUTERATE */
+#define WM9081_DAC_MUTERATE_MASK                0x0400  /* DAC_MUTERATE */
+#define WM9081_DAC_MUTERATE_SHIFT                   10  /* DAC_MUTERATE */
+#define WM9081_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM9081_DAC_MUTEMODE                     0x0200  /* DAC_MUTEMODE */
+#define WM9081_DAC_MUTEMODE_MASK                0x0200  /* DAC_MUTEMODE */
+#define WM9081_DAC_MUTEMODE_SHIFT                    9  /* DAC_MUTEMODE */
+#define WM9081_DAC_MUTEMODE_WIDTH                    1  /* DAC_MUTEMODE */
+#define WM9081_DAC_MUTE                         0x0008  /* DAC_MUTE */
+#define WM9081_DAC_MUTE_MASK                    0x0008  /* DAC_MUTE */
+#define WM9081_DAC_MUTE_SHIFT                        3  /* DAC_MUTE */
+#define WM9081_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM9081_DEEMPH_MASK                      0x0006  /* DEEMPH - [2:1] */
+#define WM9081_DEEMPH_SHIFT                          1  /* DEEMPH - [2:1] */
+#define WM9081_DEEMPH_WIDTH                          2  /* DEEMPH - [2:1] */
+
+/*
+ * R32 (0x20) - DRC 1
+ */
+#define WM9081_DRC_ENA                          0x8000  /* DRC_ENA */
+#define WM9081_DRC_ENA_MASK                     0x8000  /* DRC_ENA */
+#define WM9081_DRC_ENA_SHIFT                        15  /* DRC_ENA */
+#define WM9081_DRC_ENA_WIDTH                         1  /* DRC_ENA */
+#define WM9081_DRC_STARTUP_GAIN_MASK            0x07C0  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM9081_DRC_STARTUP_GAIN_SHIFT                6  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM9081_DRC_STARTUP_GAIN_WIDTH                5  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM9081_DRC_FF_DLY                       0x0020  /* DRC_FF_DLY */
+#define WM9081_DRC_FF_DLY_MASK                  0x0020  /* DRC_FF_DLY */
+#define WM9081_DRC_FF_DLY_SHIFT                      5  /* DRC_FF_DLY */
+#define WM9081_DRC_FF_DLY_WIDTH                      1  /* DRC_FF_DLY */
+#define WM9081_DRC_QR                           0x0004  /* DRC_QR */
+#define WM9081_DRC_QR_MASK                      0x0004  /* DRC_QR */
+#define WM9081_DRC_QR_SHIFT                          2  /* DRC_QR */
+#define WM9081_DRC_QR_WIDTH                          1  /* DRC_QR */
+#define WM9081_DRC_ANTICLIP                     0x0002  /* DRC_ANTICLIP */
+#define WM9081_DRC_ANTICLIP_MASK                0x0002  /* DRC_ANTICLIP */
+#define WM9081_DRC_ANTICLIP_SHIFT                    1  /* DRC_ANTICLIP */
+#define WM9081_DRC_ANTICLIP_WIDTH                    1  /* DRC_ANTICLIP */
+
+/*
+ * R33 (0x21) - DRC 2
+ */
+#define WM9081_DRC_ATK_MASK                     0xF000  /* DRC_ATK - [15:12] */
+#define WM9081_DRC_ATK_SHIFT                        12  /* DRC_ATK - [15:12] */
+#define WM9081_DRC_ATK_WIDTH                         4  /* DRC_ATK - [15:12] */
+#define WM9081_DRC_DCY_MASK                     0x0F00  /* DRC_DCY - [11:8] */
+#define WM9081_DRC_DCY_SHIFT                         8  /* DRC_DCY - [11:8] */
+#define WM9081_DRC_DCY_WIDTH                         4  /* DRC_DCY - [11:8] */
+#define WM9081_DRC_QR_THR_MASK                  0x00C0  /* DRC_QR_THR - [7:6] */
+#define WM9081_DRC_QR_THR_SHIFT                      6  /* DRC_QR_THR - [7:6] */
+#define WM9081_DRC_QR_THR_WIDTH                      2  /* DRC_QR_THR - [7:6] */
+#define WM9081_DRC_QR_DCY_MASK                  0x0030  /* DRC_QR_DCY - [5:4] */
+#define WM9081_DRC_QR_DCY_SHIFT                      4  /* DRC_QR_DCY - [5:4] */
+#define WM9081_DRC_QR_DCY_WIDTH                      2  /* DRC_QR_DCY - [5:4] */
+#define WM9081_DRC_MINGAIN_MASK                 0x000C  /* DRC_MINGAIN - [3:2] */
+#define WM9081_DRC_MINGAIN_SHIFT                     2  /* DRC_MINGAIN - [3:2] */
+#define WM9081_DRC_MINGAIN_WIDTH                     2  /* DRC_MINGAIN - [3:2] */
+#define WM9081_DRC_MAXGAIN_MASK                 0x0003  /* DRC_MAXGAIN - [1:0] */
+#define WM9081_DRC_MAXGAIN_SHIFT                     0  /* DRC_MAXGAIN - [1:0] */
+#define WM9081_DRC_MAXGAIN_WIDTH                     2  /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R34 (0x22) - DRC 3
+ */
+#define WM9081_DRC_HI_COMP_MASK                 0x0038  /* DRC_HI_COMP - [5:3] */
+#define WM9081_DRC_HI_COMP_SHIFT                     3  /* DRC_HI_COMP - [5:3] */
+#define WM9081_DRC_HI_COMP_WIDTH                     3  /* DRC_HI_COMP - [5:3] */
+#define WM9081_DRC_LO_COMP_MASK                 0x0007  /* DRC_LO_COMP - [2:0] */
+#define WM9081_DRC_LO_COMP_SHIFT                     0  /* DRC_LO_COMP - [2:0] */
+#define WM9081_DRC_LO_COMP_WIDTH                     3  /* DRC_LO_COMP - [2:0] */
+
+/*
+ * R35 (0x23) - DRC 4
+ */
+#define WM9081_DRC_KNEE_IP_MASK                 0x07E0  /* DRC_KNEE_IP - [10:5] */
+#define WM9081_DRC_KNEE_IP_SHIFT                     5  /* DRC_KNEE_IP - [10:5] */
+#define WM9081_DRC_KNEE_IP_WIDTH                     6  /* DRC_KNEE_IP - [10:5] */
+#define WM9081_DRC_KNEE_OP_MASK                 0x001F  /* DRC_KNEE_OP - [4:0] */
+#define WM9081_DRC_KNEE_OP_SHIFT                     0  /* DRC_KNEE_OP - [4:0] */
+#define WM9081_DRC_KNEE_OP_WIDTH                     5  /* DRC_KNEE_OP - [4:0] */
+
+/*
+ * R38 (0x26) - Write Sequencer 1
+ */
+#define WM9081_WSEQ_ENA                         0x8000  /* WSEQ_ENA */
+#define WM9081_WSEQ_ENA_MASK                    0x8000  /* WSEQ_ENA */
+#define WM9081_WSEQ_ENA_SHIFT                       15  /* WSEQ_ENA */
+#define WM9081_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM9081_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM9081_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM9081_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM9081_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM9081_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM9081_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM9081_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM9081_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM9081_WSEQ_START_INDEX_MASK            0x007F  /* WSEQ_START_INDEX - [6:0] */
+#define WM9081_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [6:0] */
+#define WM9081_WSEQ_START_INDEX_WIDTH                7  /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R39 (0x27) - Write Sequencer 2
+ */
+#define WM9081_WSEQ_CURRENT_INDEX_MASK          0x07F0  /* WSEQ_CURRENT_INDEX - [10:4] */
+#define WM9081_WSEQ_CURRENT_INDEX_SHIFT              4  /* WSEQ_CURRENT_INDEX - [10:4] */
+#define WM9081_WSEQ_CURRENT_INDEX_WIDTH              7  /* WSEQ_CURRENT_INDEX - [10:4] */
+#define WM9081_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM9081_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM9081_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM9081_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R40 (0x28) - MW Slave 1
+ */
+#define WM9081_SPI_CFG                          0x0020  /* SPI_CFG */
+#define WM9081_SPI_CFG_MASK                     0x0020  /* SPI_CFG */
+#define WM9081_SPI_CFG_SHIFT                         5  /* SPI_CFG */
+#define WM9081_SPI_CFG_WIDTH                         1  /* SPI_CFG */
+#define WM9081_SPI_4WIRE                        0x0010  /* SPI_4WIRE */
+#define WM9081_SPI_4WIRE_MASK                   0x0010  /* SPI_4WIRE */
+#define WM9081_SPI_4WIRE_SHIFT                       4  /* SPI_4WIRE */
+#define WM9081_SPI_4WIRE_WIDTH                       1  /* SPI_4WIRE */
+#define WM9081_ARA_ENA                          0x0008  /* ARA_ENA */
+#define WM9081_ARA_ENA_MASK                     0x0008  /* ARA_ENA */
+#define WM9081_ARA_ENA_SHIFT                         3  /* ARA_ENA */
+#define WM9081_ARA_ENA_WIDTH                         1  /* ARA_ENA */
+#define WM9081_AUTO_INC                         0x0002  /* AUTO_INC */
+#define WM9081_AUTO_INC_MASK                    0x0002  /* AUTO_INC */
+#define WM9081_AUTO_INC_SHIFT                        1  /* AUTO_INC */
+#define WM9081_AUTO_INC_WIDTH                        1  /* AUTO_INC */
+
+/*
+ * R42 (0x2A) - EQ 1
+ */
+#define WM9081_EQ_B1_GAIN_MASK                  0xF800  /* EQ_B1_GAIN - [15:11] */
+#define WM9081_EQ_B1_GAIN_SHIFT                     11  /* EQ_B1_GAIN - [15:11] */
+#define WM9081_EQ_B1_GAIN_WIDTH                      5  /* EQ_B1_GAIN - [15:11] */
+#define WM9081_EQ_B2_GAIN_MASK                  0x07C0  /* EQ_B2_GAIN - [10:6] */
+#define WM9081_EQ_B2_GAIN_SHIFT                      6  /* EQ_B2_GAIN - [10:6] */
+#define WM9081_EQ_B2_GAIN_WIDTH                      5  /* EQ_B2_GAIN - [10:6] */
+#define WM9081_EQ_B4_GAIN_MASK                  0x003E  /* EQ_B4_GAIN - [5:1] */
+#define WM9081_EQ_B4_GAIN_SHIFT                      1  /* EQ_B4_GAIN - [5:1] */
+#define WM9081_EQ_B4_GAIN_WIDTH                      5  /* EQ_B4_GAIN - [5:1] */
+#define WM9081_EQ_ENA                           0x0001  /* EQ_ENA */
+#define WM9081_EQ_ENA_MASK                      0x0001  /* EQ_ENA */
+#define WM9081_EQ_ENA_SHIFT                          0  /* EQ_ENA */
+#define WM9081_EQ_ENA_WIDTH                          1  /* EQ_ENA */
+
+/*
+ * R43 (0x2B) - EQ 2
+ */
+#define WM9081_EQ_B3_GAIN_MASK                  0xF800  /* EQ_B3_GAIN - [15:11] */
+#define WM9081_EQ_B3_GAIN_SHIFT                     11  /* EQ_B3_GAIN - [15:11] */
+#define WM9081_EQ_B3_GAIN_WIDTH                      5  /* EQ_B3_GAIN - [15:11] */
+#define WM9081_EQ_B5_GAIN_MASK                  0x07C0  /* EQ_B5_GAIN - [10:6] */
+#define WM9081_EQ_B5_GAIN_SHIFT                      6  /* EQ_B5_GAIN - [10:6] */
+#define WM9081_EQ_B5_GAIN_WIDTH                      5  /* EQ_B5_GAIN - [10:6] */
+
+/*
+ * R44 (0x2C) - EQ 3
+ */
+#define WM9081_EQ_B1_A_MASK                     0xFFFF  /* EQ_B1_A - [15:0] */
+#define WM9081_EQ_B1_A_SHIFT                         0  /* EQ_B1_A - [15:0] */
+#define WM9081_EQ_B1_A_WIDTH                        16  /* EQ_B1_A - [15:0] */
+
+/*
+ * R45 (0x2D) - EQ 4
+ */
+#define WM9081_EQ_B1_B_MASK                     0xFFFF  /* EQ_B1_B - [15:0] */
+#define WM9081_EQ_B1_B_SHIFT                         0  /* EQ_B1_B - [15:0] */
+#define WM9081_EQ_B1_B_WIDTH                        16  /* EQ_B1_B - [15:0] */
+
+/*
+ * R46 (0x2E) - EQ 5
+ */
+#define WM9081_EQ_B1_PG_MASK                    0xFFFF  /* EQ_B1_PG - [15:0] */
+#define WM9081_EQ_B1_PG_SHIFT                        0  /* EQ_B1_PG - [15:0] */
+#define WM9081_EQ_B1_PG_WIDTH                       16  /* EQ_B1_PG - [15:0] */
+
+/*
+ * R47 (0x2F) - EQ 6
+ */
+#define WM9081_EQ_B2_A_MASK                     0xFFFF  /* EQ_B2_A - [15:0] */
+#define WM9081_EQ_B2_A_SHIFT                         0  /* EQ_B2_A - [15:0] */
+#define WM9081_EQ_B2_A_WIDTH                        16  /* EQ_B2_A - [15:0] */
+
+/*
+ * R48 (0x30) - EQ 7
+ */
+#define WM9081_EQ_B2_B_MASK                     0xFFFF  /* EQ_B2_B - [15:0] */
+#define WM9081_EQ_B2_B_SHIFT                         0  /* EQ_B2_B - [15:0] */
+#define WM9081_EQ_B2_B_WIDTH                        16  /* EQ_B2_B - [15:0] */
+
+/*
+ * R49 (0x31) - EQ 8
+ */
+#define WM9081_EQ_B2_C_MASK                     0xFFFF  /* EQ_B2_C - [15:0] */
+#define WM9081_EQ_B2_C_SHIFT                         0  /* EQ_B2_C - [15:0] */
+#define WM9081_EQ_B2_C_WIDTH                        16  /* EQ_B2_C - [15:0] */
+
+/*
+ * R50 (0x32) - EQ 9
+ */
+#define WM9081_EQ_B2_PG_MASK                    0xFFFF  /* EQ_B2_PG - [15:0] */
+#define WM9081_EQ_B2_PG_SHIFT                        0  /* EQ_B2_PG - [15:0] */
+#define WM9081_EQ_B2_PG_WIDTH                       16  /* EQ_B2_PG - [15:0] */
+
+/*
+ * R51 (0x33) - EQ 10
+ */
+#define WM9081_EQ_B4_A_MASK                     0xFFFF  /* EQ_B4_A - [15:0] */
+#define WM9081_EQ_B4_A_SHIFT                         0  /* EQ_B4_A - [15:0] */
+#define WM9081_EQ_B4_A_WIDTH                        16  /* EQ_B4_A - [15:0] */
+
+/*
+ * R52 (0x34) - EQ 11
+ */
+#define WM9081_EQ_B4_B_MASK                     0xFFFF  /* EQ_B4_B - [15:0] */
+#define WM9081_EQ_B4_B_SHIFT                         0  /* EQ_B4_B - [15:0] */
+#define WM9081_EQ_B4_B_WIDTH                        16  /* EQ_B4_B - [15:0] */
+
+/*
+ * R53 (0x35) - EQ 12
+ */
+#define WM9081_EQ_B4_C_MASK                     0xFFFF  /* EQ_B4_C - [15:0] */
+#define WM9081_EQ_B4_C_SHIFT                         0  /* EQ_B4_C - [15:0] */
+#define WM9081_EQ_B4_C_WIDTH                        16  /* EQ_B4_C - [15:0] */
+
+/*
+ * R54 (0x36) - EQ 13
+ */
+#define WM9081_EQ_B4_PG_MASK                    0xFFFF  /* EQ_B4_PG - [15:0] */
+#define WM9081_EQ_B4_PG_SHIFT                        0  /* EQ_B4_PG - [15:0] */
+#define WM9081_EQ_B4_PG_WIDTH                       16  /* EQ_B4_PG - [15:0] */
+
+/*
+ * R55 (0x37) - EQ 14
+ */
+#define WM9081_EQ_B3_A_MASK                     0xFFFF  /* EQ_B3_A - [15:0] */
+#define WM9081_EQ_B3_A_SHIFT                         0  /* EQ_B3_A - [15:0] */
+#define WM9081_EQ_B3_A_WIDTH                        16  /* EQ_B3_A - [15:0] */
+
+/*
+ * R56 (0x38) - EQ 15
+ */
+#define WM9081_EQ_B3_B_MASK                     0xFFFF  /* EQ_B3_B - [15:0] */
+#define WM9081_EQ_B3_B_SHIFT                         0  /* EQ_B3_B - [15:0] */
+#define WM9081_EQ_B3_B_WIDTH                        16  /* EQ_B3_B - [15:0] */
+
+/*
+ * R57 (0x39) - EQ 16
+ */
+#define WM9081_EQ_B3_C_MASK                     0xFFFF  /* EQ_B3_C - [15:0] */
+#define WM9081_EQ_B3_C_SHIFT                         0  /* EQ_B3_C - [15:0] */
+#define WM9081_EQ_B3_C_WIDTH                        16  /* EQ_B3_C - [15:0] */
+
+/*
+ * R58 (0x3A) - EQ 17
+ */
+#define WM9081_EQ_B3_PG_MASK                    0xFFFF  /* EQ_B3_PG - [15:0] */
+#define WM9081_EQ_B3_PG_SHIFT                        0  /* EQ_B3_PG - [15:0] */
+#define WM9081_EQ_B3_PG_WIDTH                       16  /* EQ_B3_PG - [15:0] */
+
+/*
+ * R59 (0x3B) - EQ 18
+ */
+#define WM9081_EQ_B5_A_MASK                     0xFFFF  /* EQ_B5_A - [15:0] */
+#define WM9081_EQ_B5_A_SHIFT                         0  /* EQ_B5_A - [15:0] */
+#define WM9081_EQ_B5_A_WIDTH                        16  /* EQ_B5_A - [15:0] */
+
+/*
+ * R60 (0x3C) - EQ 19
+ */
+#define WM9081_EQ_B5_B_MASK                     0xFFFF  /* EQ_B5_B - [15:0] */
+#define WM9081_EQ_B5_B_SHIFT                         0  /* EQ_B5_B - [15:0] */
+#define WM9081_EQ_B5_B_WIDTH                        16  /* EQ_B5_B - [15:0] */
+
+/*
+ * R61 (0x3D) - EQ 20
+ */
+#define WM9081_EQ_B5_PG_MASK                    0xFFFF  /* EQ_B5_PG - [15:0] */
+#define WM9081_EQ_B5_PG_SHIFT                        0  /* EQ_B5_PG - [15:0] */
+#define WM9081_EQ_B5_PG_WIDTH                       16  /* EQ_B5_PG - [15:0] */
+
+
+#endif
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index c2d1a7a..fa88b46 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -282,14 +282,14 @@
 			.channels_min = 1,
 			.channels_max = 2,
 			.rates = WM9705_AC97_RATES,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.formats = SND_SOC_STD_AC97_FMTS,
 		},
 		.capture = {
 			.stream_name = "HiFi Capture",
 			.channels_min = 1,
 			.channels_max = 2,
 			.rates = WM9705_AC97_RATES,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.formats = SND_SOC_STD_AC97_FMTS,
 		},
 		.ops = &wm9705_dai_ops,
 	},
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 765cf1e..1fd4e88 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -534,13 +534,13 @@
 		.channels_min = 1,
 		.channels_max = 2,
 		.rates = WM9712_AC97_RATES,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+		.formats = SND_SOC_STD_AC97_FMTS,},
 	.capture = {
 		.stream_name = "HiFi Capture",
 		.channels_min = 1,
 		.channels_max = 2,
 		.rates = WM9712_AC97_RATES,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+		.formats = SND_SOC_STD_AC97_FMTS,},
 	.ops = &wm9712_dai_ops_hifi,
 },
 {
@@ -550,7 +550,7 @@
 		.channels_min = 1,
 		.channels_max = 1,
 		.rates = WM9712_AC97_RATES,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+		.formats = SND_SOC_STD_AC97_FMTS,},
 	.ops = &wm9712_dai_ops_aux,
 }
 };
@@ -585,6 +585,8 @@
 	}
 
 	soc_ac97_ops.reset(codec->ac97);
+	if (soc_ac97_ops.warm_reset)
+		soc_ac97_ops.warm_reset(codec->ac97);
 	if (ac97_read(codec, 0) != wm9712_reg[0])
 		goto err;
 	return 0;
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 523bad0..abed37a 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -189,6 +189,26 @@
 SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1),
 };
 
+static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 status, rate;
+
+	BUG_ON(event != SND_SOC_DAPM_PRE_PMD);
+
+	/* Gracefully shut down the voice interface. */
+	status = ac97_read(codec, AC97_EXTENDED_MID) | 0x1000;
+	rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF;
+	ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200);
+	schedule_timeout_interruptible(msecs_to_jiffies(1));
+	ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00);
+	ac97_write(codec, AC97_EXTENDED_MID, status);
+
+	return 0;
+}
+
+
 /* We have to create a fake left and right HP mixers because
  * the codec only has a single control that is shared by both channels.
  * This makes it impossible to determine the audio path using the current
@@ -400,7 +420,8 @@
 SND_SOC_DAPM_MIXER("HP Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 SND_SOC_DAPM_MIXER("Capture Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
-SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1),
+SND_SOC_DAPM_DAC_E("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1,
+		   wm9713_voice_shutdown, SND_SOC_DAPM_PRE_PMD),
 SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", AC97_EXTENDED_MID, 11, 1),
 SND_SOC_DAPM_PGA("Left ADC", AC97_EXTENDED_MID, 5, 1, NULL, 0),
 SND_SOC_DAPM_PGA("Right ADC", AC97_EXTENDED_MID, 4, 1, NULL, 0),
@@ -689,7 +710,7 @@
 	Ndiv = target / source;
 	if ((Ndiv < 5) || (Ndiv > 12))
 		printk(KERN_WARNING
-			"WM9713 PLL N value %d out of recommended range!\n",
+			"WM9713 PLL N value %u out of recommended range!\n",
 			Ndiv);
 
 	pll_div->n = Ndiv;
@@ -936,21 +957,6 @@
 	return 0;
 }
 
-static void wm9713_voiceshutdown(struct snd_pcm_substream *substream,
-				 struct snd_soc_dai *dai)
-{
-	struct snd_soc_codec *codec = dai->codec;
-	u16 status, rate;
-
-	/* Gracefully shut down the voice interface. */
-	status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000;
-	rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF;
-	ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200);
-	schedule_timeout_interruptible(msecs_to_jiffies(1));
-	ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00);
-	ac97_write(codec, AC97_EXTENDED_MID, status);
-}
-
 static int ac97_hifi_prepare(struct snd_pcm_substream *substream,
 			     struct snd_soc_dai *dai)
 {
@@ -1019,7 +1025,6 @@
 
 static struct snd_soc_dai_ops wm9713_dai_ops_voice = {
 	.hw_params	= wm9713_pcm_hw_params,
-	.shutdown	= wm9713_voiceshutdown,
 	.set_clkdiv	= wm9713_set_dai_clkdiv,
 	.set_pll	= wm9713_set_dai_pll,
 	.set_fmt	= wm9713_set_dai_fmt,
@@ -1035,13 +1040,13 @@
 		.channels_min = 1,
 		.channels_max = 2,
 		.rates = WM9713_RATES,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+		.formats = SND_SOC_STD_AC97_FMTS,},
 	.capture = {
 		.stream_name = "HiFi Capture",
 		.channels_min = 1,
 		.channels_max = 2,
 		.rates = WM9713_RATES,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+		.formats = SND_SOC_STD_AC97_FMTS,},
 	.ops = &wm9713_dai_ops_hifi,
 	},
 	{
@@ -1051,7 +1056,7 @@
 		.channels_min = 1,
 		.channels_max = 1,
 		.rates = WM9713_RATES,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+		.formats = SND_SOC_STD_AC97_FMTS,},
 	.ops = &wm9713_dai_ops_aux,
 	},
 	{
@@ -1069,6 +1074,7 @@
 		.rates = WM9713_PCM_RATES,
 		.formats = WM9713_PCM_FORMATS,},
 	.ops = &wm9713_dai_ops_voice,
+	.symmetric_rates = 1,
 	},
 };
 EXPORT_SYMBOL_GPL(wm9713_dai);
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 9fc9082..5dbebf8 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,5 +1,8 @@
 config SND_SOC_OF_SIMPLE
 	tristate
+	
+config SND_MPC52xx_DMA
+	tristate
 
 # ASoC platform support for the Freescale MPC8610 SOC.  This compiles drivers
 # for the SSI and the Elo DMA controller.  You will still need to select
@@ -22,7 +25,34 @@
 config SND_SOC_MPC5200_I2S
 	tristate "Freescale MPC5200 PSC in I2S mode driver"
 	depends on PPC_MPC52xx && PPC_BESTCOMM
-	select SND_SOC_OF_SIMPLE
+	select SND_MPC52xx_DMA
 	select PPC_BESTCOMM_GEN_BD
 	help
 	  Say Y here to support the MPC5200 PSCs in I2S mode.
+
+config SND_SOC_MPC5200_AC97
+	tristate "Freescale MPC5200 PSC in AC97 mode driver"
+	depends on PPC_MPC52xx && PPC_BESTCOMM
+	select AC97_BUS
+	select SND_MPC52xx_DMA
+	select PPC_BESTCOMM_GEN_BD
+	help
+	  Say Y here to support the MPC5200 PSCs in AC97 mode.
+
+config SND_MPC52xx_SOC_PCM030
+	tristate "SoC AC97 Audio support for Phytec pcm030 and WM9712"
+	depends on PPC_MPC5200_SIMPLE && BROKEN
+	select SND_SOC_MPC5200_AC97
+	select SND_SOC_WM9712
+	help
+	  Say Y if you want to add support for sound on the Phytec pcm030
+	  baseboard.
+
+config SND_MPC52xx_SOC_EFIKA
+	tristate "SoC AC97 Audio support for bbplan Efika and STAC9766"
+	depends on PPC_EFIKA && BROKEN
+	select SND_SOC_MPC5200_AC97
+	select SND_SOC_STAC9766
+	help
+	  Say Y if you want to add support for sound on the Efika.
+
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index f85134c..a83a739 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -10,5 +10,12 @@
 snd-soc-fsl-dma-objs := fsl_dma.o
 obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
 
+# MPC5200 Platform Support
+obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
 obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
+obj-$(CONFIG_SND_SOC_MPC5200_AC97) += mpc5200_psc_ac97.o
+
+# MPC5200 Machine Support
+obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o
+obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o
 
diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c
new file mode 100644
index 0000000..85b0e75
--- /dev/null
+++ b/sound/soc/fsl/efika-audio-fabric.c
@@ -0,0 +1,90 @@
+/*
+ * Efika driver for the PSC of the Freescale MPC52xx
+ * configured as AC97 interface
+ *
+ * Copyright 2008 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-of-simple.h>
+
+#include "mpc5200_dma.h"
+#include "mpc5200_psc_ac97.h"
+#include "../codecs/stac9766.h"
+
+static struct snd_soc_device device;
+static struct snd_soc_card card;
+
+static struct snd_soc_dai_link efika_fabric_dai[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 Analog",
+	.codec_dai = &stac9766_dai[STAC9766_DAI_AC97_ANALOG],
+	.cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+},
+{
+	.name = "AC97",
+	.stream_name = "AC97 IEC958",
+	.codec_dai = &stac9766_dai[STAC9766_DAI_AC97_DIGITAL],
+	.cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+},
+};
+
+static __init int efika_fabric_init(void)
+{
+	struct platform_device *pdev;
+	int rc;
+
+	if (!machine_is_compatible("bplan,efika"))
+		return -ENODEV;
+
+	card.platform = &mpc5200_audio_dma_platform;
+	card.name = "Efika";
+	card.dai_link = efika_fabric_dai;
+	card.num_links = ARRAY_SIZE(efika_fabric_dai);
+
+	device.card = &card;
+	device.codec_dev = &soc_codec_dev_stac9766;
+
+	pdev = platform_device_alloc("soc-audio", 1);
+	if (!pdev) {
+		pr_err("efika_fabric_init: platform_device_alloc() failed\n");
+		return -ENODEV;
+	}
+
+	platform_set_drvdata(pdev, &device);
+	device.dev = &pdev->dev;
+
+	rc = platform_device_add(pdev);
+	if (rc) {
+		pr_err("efika_fabric_init: platform_device_add() failed\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+module_init(efika_fabric_init);
+
+
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_DESCRIPTION(DRV_NAME ": mpc5200 Efika fabric driver");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 3711d84..93f0f38 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -375,18 +375,14 @@
 		struct snd_pcm_runtime *first_runtime =
 			ssi_private->first_stream->runtime;
 
-		if (!first_runtime->rate || !first_runtime->sample_bits) {
+		if (!first_runtime->sample_bits) {
 			dev_err(substream->pcm->card->dev,
-				"set sample rate and size in %s stream first\n",
+				"set sample size in %s stream first\n",
 				substream->stream == SNDRV_PCM_STREAM_PLAYBACK
 				? "capture" : "playback");
 			return -EAGAIN;
 		}
 
-		snd_pcm_hw_constraint_minmax(substream->runtime,
-			SNDRV_PCM_HW_PARAM_RATE,
-			first_runtime->rate, first_runtime->rate);
-
 		/* If we're in synchronous mode, then we need to constrain
 		 * the sample size as well.  We don't support independent sample
 		 * rates in asynchronous mode.
@@ -674,7 +670,7 @@
 	ssi_private->dev = ssi_info->dev;
 	ssi_private->asynchronous = ssi_info->asynchronous;
 
-	ssi_private->dev->driver_data = fsl_ssi_dai;
+	dev_set_drvdata(ssi_private->dev, fsl_ssi_dai);
 
 	/* Initialize the the device_attribute structure */
 	dev_attr->attr.name = "ssi-stats";
@@ -693,6 +689,7 @@
 	fsl_ssi_dai->name = ssi_private->name;
 	fsl_ssi_dai->id = ssi_info->id;
 	fsl_ssi_dai->dev = ssi_info->dev;
+	fsl_ssi_dai->symmetric_rates = 1;
 
 	ret = snd_soc_register_dai(fsl_ssi_dai);
 	if (ret != 0) {
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
new file mode 100644
index 0000000..efec33a
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -0,0 +1,564 @@
+/*
+ * Freescale MPC5200 PSC DMA
+ * ALSA SoC Platform driver
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ * Copyright (C) 2009 Jon Smirl, Digispeaker
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+#include <sound/soc.h>
+
+#include <sysdev/bestcomm/bestcomm.h>
+#include <sysdev/bestcomm/gen_bd.h>
+#include <asm/mpc52xx_psc.h>
+
+#include "mpc5200_dma.h"
+
+/*
+ * Interrupt handlers
+ */
+static irqreturn_t psc_dma_status_irq(int irq, void *_psc_dma)
+{
+	struct psc_dma *psc_dma = _psc_dma;
+	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+	u16 isr;
+
+	isr = in_be16(&regs->mpc52xx_psc_isr);
+
+	/* Playback underrun error */
+	if (psc_dma->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP))
+		psc_dma->stats.underrun_count++;
+
+	/* Capture overrun error */
+	if (psc_dma->capture.active && (isr & MPC52xx_PSC_IMR_ORERR))
+		psc_dma->stats.overrun_count++;
+
+	out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * psc_dma_bcom_enqueue_next_buffer - Enqueue another audio buffer
+ * @s: pointer to stream private data structure
+ *
+ * Enqueues another audio period buffer into the bestcomm queue.
+ *
+ * Note: The routine must only be called when there is space available in
+ * the queue.  Otherwise the enqueue will fail and the audio ring buffer
+ * will get out of sync
+ */
+static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s)
+{
+	struct bcom_bd *bd;
+
+	/* Prepare and enqueue the next buffer descriptor */
+	bd = bcom_prepare_next_buffer(s->bcom_task);
+	bd->status = s->period_bytes;
+	bd->data[0] = s->period_next_pt;
+	bcom_submit_next_buffer(s->bcom_task, NULL);
+
+	/* Update for next period */
+	s->period_next_pt += s->period_bytes;
+	if (s->period_next_pt >= s->period_end)
+		s->period_next_pt = s->period_start;
+}
+
+static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s)
+{
+	while (s->appl_ptr < s->runtime->control->appl_ptr) {
+
+		if (bcom_queue_full(s->bcom_task))
+			return;
+
+		s->appl_ptr += s->period_size;
+
+		psc_dma_bcom_enqueue_next_buffer(s);
+	}
+}
+
+/* Bestcomm DMA irq handler */
+static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream)
+{
+	struct psc_dma_stream *s = _psc_dma_stream;
+
+	spin_lock(&s->psc_dma->lock);
+	/* For each finished period, dequeue the completed period buffer
+	 * and enqueue a new one in it's place. */
+	while (bcom_buffer_done(s->bcom_task)) {
+		bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+
+		s->period_current_pt += s->period_bytes;
+		if (s->period_current_pt >= s->period_end)
+			s->period_current_pt = s->period_start;
+	}
+	psc_dma_bcom_enqueue_tx(s);
+	spin_unlock(&s->psc_dma->lock);
+
+	/* If the stream is active, then also inform the PCM middle layer
+	 * of the period finished event. */
+	if (s->active)
+		snd_pcm_period_elapsed(s->stream);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t psc_dma_bcom_irq_rx(int irq, void *_psc_dma_stream)
+{
+	struct psc_dma_stream *s = _psc_dma_stream;
+
+	spin_lock(&s->psc_dma->lock);
+	/* For each finished period, dequeue the completed period buffer
+	 * and enqueue a new one in it's place. */
+	while (bcom_buffer_done(s->bcom_task)) {
+		bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+
+		s->period_current_pt += s->period_bytes;
+		if (s->period_current_pt >= s->period_end)
+			s->period_current_pt = s->period_start;
+
+		psc_dma_bcom_enqueue_next_buffer(s);
+	}
+	spin_unlock(&s->psc_dma->lock);
+
+	/* If the stream is active, then also inform the PCM middle layer
+	 * of the period finished event. */
+	if (s->active)
+		snd_pcm_period_elapsed(s->stream);
+
+	return IRQ_HANDLED;
+}
+
+static int psc_dma_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_set_runtime_buffer(substream, NULL);
+	return 0;
+}
+
+/**
+ * psc_dma_trigger: start and stop the DMA transfer.
+ *
+ * This function is called by ALSA to start, stop, pause, and resume the DMA
+ * transfer of data.
+ */
+static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct psc_dma_stream *s;
+	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+	u16 imr;
+	unsigned long flags;
+	int i;
+
+	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+		s = &psc_dma->capture;
+	else
+		s = &psc_dma->playback;
+
+	dev_dbg(psc_dma->dev, "psc_dma_trigger(substream=%p, cmd=%i)"
+		" stream_id=%i\n",
+		substream, cmd, substream->pstr->stream);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		s->period_bytes = frames_to_bytes(runtime,
+						  runtime->period_size);
+		s->period_start = virt_to_phys(runtime->dma_area);
+		s->period_end = s->period_start +
+				(s->period_bytes * runtime->periods);
+		s->period_next_pt = s->period_start;
+		s->period_current_pt = s->period_start;
+		s->period_size = runtime->period_size;
+		s->active = 1;
+
+		/* track appl_ptr so that we have a better chance of detecting
+		 * end of stream and not over running it.
+		 */
+		s->runtime = runtime;
+		s->appl_ptr = s->runtime->control->appl_ptr -
+				(runtime->period_size * runtime->periods);
+
+		/* Fill up the bestcomm bd queue and enable DMA.
+		 * This will begin filling the PSC's fifo.
+		 */
+		spin_lock_irqsave(&psc_dma->lock, flags);
+
+		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			bcom_gen_bd_rx_reset(s->bcom_task);
+			for (i = 0; i < runtime->periods; i++)
+				if (!bcom_queue_full(s->bcom_task))
+					psc_dma_bcom_enqueue_next_buffer(s);
+		} else {
+			bcom_gen_bd_tx_reset(s->bcom_task);
+			psc_dma_bcom_enqueue_tx(s);
+		}
+
+		bcom_enable(s->bcom_task);
+		spin_unlock_irqrestore(&psc_dma->lock, flags);
+
+		out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
+
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		s->active = 0;
+
+		spin_lock_irqsave(&psc_dma->lock, flags);
+		bcom_disable(s->bcom_task);
+		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+			bcom_gen_bd_rx_reset(s->bcom_task);
+		else
+			bcom_gen_bd_tx_reset(s->bcom_task);
+		spin_unlock_irqrestore(&psc_dma->lock, flags);
+
+		break;
+
+	default:
+		dev_dbg(psc_dma->dev, "invalid command\n");
+		return -EINVAL;
+	}
+
+	/* Update interrupt enable settings */
+	imr = 0;
+	if (psc_dma->playback.active)
+		imr |= MPC52xx_PSC_IMR_TXEMP;
+	if (psc_dma->capture.active)
+		imr |= MPC52xx_PSC_IMR_ORERR;
+	out_be16(&regs->isr_imr.imr, psc_dma->imr | imr);
+
+	return 0;
+}
+
+
+/* ---------------------------------------------------------------------
+ * The PSC DMA 'ASoC platform' driver
+ *
+ * Can be referenced by an 'ASoC machine' driver
+ * This driver only deals with the audio bus; it doesn't have any
+ * interaction with the attached codec
+ */
+
+static const struct snd_pcm_hardware psc_dma_hardware = {
+	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+		SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		SNDRV_PCM_INFO_BATCH,
+	.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |
+		SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
+	.rate_min = 8000,
+	.rate_max = 48000,
+	.channels_min = 1,
+	.channels_max = 2,
+	.period_bytes_max	= 1024 * 1024,
+	.period_bytes_min	= 32,
+	.periods_min		= 2,
+	.periods_max		= 256,
+	.buffer_bytes_max	= 2 * 1024 * 1024,
+	.fifo_size		= 512,
+};
+
+static int psc_dma_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+	struct psc_dma_stream *s;
+	int rc;
+
+	dev_dbg(psc_dma->dev, "psc_dma_open(substream=%p)\n", substream);
+
+	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+		s = &psc_dma->capture;
+	else
+		s = &psc_dma->playback;
+
+	snd_soc_set_runtime_hwparams(substream, &psc_dma_hardware);
+
+	rc = snd_pcm_hw_constraint_integer(runtime,
+		SNDRV_PCM_HW_PARAM_PERIODS);
+	if (rc < 0) {
+		dev_err(substream->pcm->card->dev, "invalid buffer size\n");
+		return rc;
+	}
+
+	s->stream = substream;
+	return 0;
+}
+
+static int psc_dma_close(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+	struct psc_dma_stream *s;
+
+	dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream);
+
+	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+		s = &psc_dma->capture;
+	else
+		s = &psc_dma->playback;
+
+	if (!psc_dma->playback.active &&
+	    !psc_dma->capture.active) {
+
+		/* Disable all interrupts and reset the PSC */
+		out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
+		out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */
+	}
+	s->stream = NULL;
+	return 0;
+}
+
+static snd_pcm_uframes_t
+psc_dma_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+	struct psc_dma_stream *s;
+	dma_addr_t count;
+
+	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+		s = &psc_dma->capture;
+	else
+		s = &psc_dma->playback;
+
+	count = s->period_current_pt - s->period_start;
+
+	return bytes_to_frames(substream->runtime, count);
+}
+
+static int
+psc_dma_hw_params(struct snd_pcm_substream *substream,
+			 struct snd_pcm_hw_params *params)
+{
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+
+static struct snd_pcm_ops psc_dma_ops = {
+	.open		= psc_dma_open,
+	.close		= psc_dma_close,
+	.hw_free	= psc_dma_hw_free,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.pointer	= psc_dma_pointer,
+	.trigger	= psc_dma_trigger,
+	.hw_params	= psc_dma_hw_params,
+};
+
+static u64 psc_dma_dmamask = 0xffffffff;
+static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
+			   struct snd_pcm *pcm)
+{
+	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+	size_t size = psc_dma_hardware.buffer_bytes_max;
+	int rc = 0;
+
+	dev_dbg(rtd->socdev->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
+		card, dai, pcm);
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &psc_dma_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = 0xffffffff;
+
+	if (pcm->streams[0].substream) {
+		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,
+				size, &pcm->streams[0].substream->dma_buffer);
+		if (rc)
+			goto playback_alloc_err;
+	}
+
+	if (pcm->streams[1].substream) {
+		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,
+				size, &pcm->streams[1].substream->dma_buffer);
+		if (rc)
+			goto capture_alloc_err;
+	}
+
+	if (rtd->socdev->card->codec->ac97)
+		rtd->socdev->card->codec->ac97->private_data = psc_dma;
+
+	return 0;
+
+ capture_alloc_err:
+	if (pcm->streams[0].substream)
+		snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+
+ playback_alloc_err:
+	dev_err(card->dev, "Cannot allocate buffer(s)\n");
+
+	return -ENOMEM;
+}
+
+static void psc_dma_free(struct snd_pcm *pcm)
+{
+	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+	struct snd_pcm_substream *substream;
+	int stream;
+
+	dev_dbg(rtd->socdev->dev, "psc_dma_free(pcm=%p)\n", pcm);
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (substream) {
+			snd_dma_free_pages(&substream->dma_buffer);
+			substream->dma_buffer.area = NULL;
+			substream->dma_buffer.addr = 0;
+		}
+	}
+}
+
+struct snd_soc_platform mpc5200_audio_dma_platform = {
+	.name		= "mpc5200-psc-audio",
+	.pcm_ops	= &psc_dma_ops,
+	.pcm_new	= &psc_dma_new,
+	.pcm_free	= &psc_dma_free,
+};
+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform);
+
+int mpc5200_audio_dma_create(struct of_device *op)
+{
+	phys_addr_t fifo;
+	struct psc_dma *psc_dma;
+	struct resource res;
+	int size, irq, rc;
+	const __be32 *prop;
+	void __iomem *regs;
+
+	/* Fetch the registers and IRQ of the PSC */
+	irq = irq_of_parse_and_map(op->node, 0);
+	if (of_address_to_resource(op->node, 0, &res)) {
+		dev_err(&op->dev, "Missing reg property\n");
+		return -ENODEV;
+	}
+	regs = ioremap(res.start, 1 + res.end - res.start);
+	if (!regs) {
+		dev_err(&op->dev, "Could not map registers\n");
+		return -ENODEV;
+	}
+
+	/* Allocate and initialize the driver private data */
+	psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL);
+	if (!psc_dma) {
+		iounmap(regs);
+		return -ENOMEM;
+	}
+
+	/* Get the PSC ID */
+	prop = of_get_property(op->node, "cell-index", &size);
+	if (!prop || size < sizeof *prop)
+		return -ENODEV;
+
+	spin_lock_init(&psc_dma->lock);
+	psc_dma->id = be32_to_cpu(*prop);
+	psc_dma->irq = irq;
+	psc_dma->psc_regs = regs;
+	psc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs;
+	psc_dma->dev = &op->dev;
+	psc_dma->playback.psc_dma = psc_dma;
+	psc_dma->capture.psc_dma = psc_dma;
+	snprintf(psc_dma->name, sizeof psc_dma->name, "PSC%u", psc_dma->id);
+
+	/* Find the address of the fifo data registers and setup the
+	 * DMA tasks */
+	fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
+	psc_dma->capture.bcom_task =
+		bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512);
+	psc_dma->playback.bcom_task =
+		bcom_psc_gen_bd_tx_init(psc_dma->id, 10, fifo);
+	if (!psc_dma->capture.bcom_task ||
+	    !psc_dma->playback.bcom_task) {
+		dev_err(&op->dev, "Could not allocate bestcomm tasks\n");
+		iounmap(regs);
+		kfree(psc_dma);
+		return -ENODEV;
+	}
+
+	/* Disable all interrupts and reset the PSC */
+	out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
+	 /* reset receiver */
+	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_RX);
+	 /* reset transmitter */
+	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_TX);
+	 /* reset error */
+	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_ERR_STAT);
+	 /* reset mode */
+	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_SEL_MODE_REG_1);
+
+	/* Set up mode register;
+	 * First write: RxRdy (FIFO Alarm) generates rx FIFO irq
+	 * Second write: register Normal mode for non loopback
+	 */
+	out_8(&psc_dma->psc_regs->mode, 0);
+	out_8(&psc_dma->psc_regs->mode, 0);
+
+	/* Set the TX and RX fifo alarm thresholds */
+	out_be16(&psc_dma->fifo_regs->rfalarm, 0x100);
+	out_8(&psc_dma->fifo_regs->rfcntl, 0x4);
+	out_be16(&psc_dma->fifo_regs->tfalarm, 0x100);
+	out_8(&psc_dma->fifo_regs->tfcntl, 0x7);
+
+	/* Lookup the IRQ numbers */
+	psc_dma->playback.irq =
+		bcom_get_task_irq(psc_dma->playback.bcom_task);
+	psc_dma->capture.irq =
+		bcom_get_task_irq(psc_dma->capture.bcom_task);
+
+	rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,
+			 "psc-dma-status", psc_dma);
+	rc |= request_irq(psc_dma->capture.irq,
+			  &psc_dma_bcom_irq_rx, IRQF_SHARED,
+			  "psc-dma-capture", &psc_dma->capture);
+	rc |= request_irq(psc_dma->playback.irq,
+			  &psc_dma_bcom_irq_tx, IRQF_SHARED,
+			  "psc-dma-playback", &psc_dma->playback);
+	if (rc) {
+		free_irq(psc_dma->irq, psc_dma);
+		free_irq(psc_dma->capture.irq,
+			 &psc_dma->capture);
+		free_irq(psc_dma->playback.irq,
+			 &psc_dma->playback);
+		return -ENODEV;
+	}
+
+	/* Save what we've done so it can be found again later */
+	dev_set_drvdata(&op->dev, psc_dma);
+
+	/* Tell the ASoC OF helpers about it */
+	return snd_soc_register_platform(&mpc5200_audio_dma_platform);
+}
+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
+
+int mpc5200_audio_dma_destroy(struct of_device *op)
+{
+	struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
+
+	dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n");
+
+	snd_soc_unregister_platform(&mpc5200_audio_dma_platform);
+
+	bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
+	bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);
+
+	/* Release irqs */
+	free_irq(psc_dma->irq, psc_dma);
+	free_irq(psc_dma->capture.irq, &psc_dma->capture);
+	free_irq(psc_dma->playback.irq, &psc_dma->playback);
+
+	iounmap(psc_dma->psc_regs);
+	kfree(psc_dma);
+	dev_set_drvdata(&op->dev, NULL);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy);
+
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h
new file mode 100644
index 0000000..2000803
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_dma.h
@@ -0,0 +1,80 @@
+/*
+ * Freescale MPC5200 Audio DMA driver
+ */
+
+#ifndef __SOUND_SOC_FSL_MPC5200_DMA_H__
+#define __SOUND_SOC_FSL_MPC5200_DMA_H__
+
+#define PSC_STREAM_NAME_LEN 32
+
+/**
+ * psc_ac97_stream - Data specific to a single stream (playback or capture)
+ * @active:		flag indicating if the stream is active
+ * @psc_dma:		pointer back to parent psc_dma data structure
+ * @bcom_task:		bestcomm task structure
+ * @irq:		irq number for bestcomm task
+ * @period_start:	physical address of start of DMA region
+ * @period_end:		physical address of end of DMA region
+ * @period_next_pt:	physical address of next DMA buffer to enqueue
+ * @period_bytes:	size of DMA period in bytes
+ */
+struct psc_dma_stream {
+	struct snd_pcm_runtime *runtime;
+	snd_pcm_uframes_t appl_ptr;
+
+	int active;
+	struct psc_dma *psc_dma;
+	struct bcom_task *bcom_task;
+	int irq;
+	struct snd_pcm_substream *stream;
+	dma_addr_t period_start;
+	dma_addr_t period_end;
+	dma_addr_t period_next_pt;
+	dma_addr_t period_current_pt;
+	int period_bytes;
+	int period_size;
+};
+
+/**
+ * psc_dma - Private driver data
+ * @name: short name for this device ("PSC0", "PSC1", etc)
+ * @psc_regs: pointer to the PSC's registers
+ * @fifo_regs: pointer to the PSC's FIFO registers
+ * @irq: IRQ of this PSC
+ * @dev: struct device pointer
+ * @dai: the CPU DAI for this device
+ * @sicr: Base value used in serial interface control register; mode is ORed
+ *        with this value.
+ * @playback: Playback stream context data
+ * @capture: Capture stream context data
+ */
+struct psc_dma {
+	char name[32];
+	struct mpc52xx_psc __iomem *psc_regs;
+	struct mpc52xx_psc_fifo __iomem *fifo_regs;
+	unsigned int irq;
+	struct device *dev;
+	spinlock_t lock;
+	u32 sicr;
+	uint sysclk;
+	int imr;
+	int id;
+	unsigned int slots;
+
+	/* per-stream data */
+	struct psc_dma_stream playback;
+	struct psc_dma_stream capture;
+
+	/* Statistics */
+	struct {
+		unsigned long overrun_count;
+		unsigned long underrun_count;
+	} stats;
+};
+
+int mpc5200_audio_dma_create(struct of_device *op);
+int mpc5200_audio_dma_destroy(struct of_device *op);
+
+extern struct snd_soc_platform mpc5200_audio_dma_platform;
+
+#endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
new file mode 100644
index 0000000..794a247
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -0,0 +1,329 @@
+/*
+ * linux/sound/mpc5200-ac97.c -- AC97 support for the Freescale MPC52xx chip.
+ *
+ * Copyright (C) 2009 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@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/of_device.h>
+#include <linux/of_platform.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/time.h>
+#include <asm/delay.h>
+#include <asm/mpc52xx_psc.h>
+
+#include "mpc5200_dma.h"
+#include "mpc5200_psc_ac97.h"
+
+#define DRV_NAME "mpc5200-psc-ac97"
+
+/* ALSA only supports a single AC97 device so static is recommend here */
+static struct psc_dma *psc_dma;
+
+static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
+{
+	int status;
+	unsigned int val;
+
+	/* Wait for command send status zero = ready */
+	status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
+				MPC52xx_PSC_SR_CMDSEND), 100, 0);
+	if (status == 0) {
+		pr_err("timeout on ac97 bus (rdy)\n");
+		return -ENODEV;
+	}
+	/* Send the read */
+	out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24));
+
+	/* Wait for the answer */
+	status = spin_event_timeout((in_be16(&psc_dma->psc_regs->sr_csr.status) &
+				MPC52xx_PSC_SR_DATA_VAL), 100, 0);
+	if (status == 0) {
+		pr_err("timeout on ac97 read (val) %x\n",
+				in_be16(&psc_dma->psc_regs->sr_csr.status));
+		return -ENODEV;
+	}
+	/* Get the data */
+	val = in_be32(&psc_dma->psc_regs->ac97_data);
+	if (((val >> 24) & 0x7f) != reg) {
+		pr_err("reg echo error on ac97 read\n");
+		return -ENODEV;
+	}
+	val = (val >> 8) & 0xffff;
+
+	return (unsigned short) val;
+}
+
+static void psc_ac97_write(struct snd_ac97 *ac97,
+				unsigned short reg, unsigned short val)
+{
+	int status;
+
+	/* Wait for command status zero = ready */
+	status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
+				MPC52xx_PSC_SR_CMDSEND), 100, 0);
+	if (status == 0) {
+		pr_err("timeout on ac97 bus (write)\n");
+		return;
+	}
+	/* Write data */
+	out_be32(&psc_dma->psc_regs->ac97_cmd,
+			((reg & 0x7f) << 24) | (val << 8));
+}
+
+static void psc_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+
+	out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR);
+	udelay(3);
+	out_be32(&regs->sicr, psc_dma->sicr);
+}
+
+static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+
+	/* Do a cold reset */
+	out_8(&regs->op1, MPC52xx_PSC_OP_RES);
+	udelay(10);
+	out_8(&regs->op0, MPC52xx_PSC_OP_RES);
+	udelay(50);
+	psc_ac97_warm_reset(ac97);
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+	.read		= psc_ac97_read,
+	.write		= psc_ac97_write,
+	.reset		= psc_ac97_cold_reset,
+	.warm_reset	= psc_ac97_warm_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *cpu_dai)
+{
+	struct psc_dma *psc_dma = cpu_dai->private_data;
+
+	dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
+		" periods=%i buffer_size=%i  buffer_bytes=%i channels=%i"
+		" rate=%i format=%i\n",
+		__func__, substream, params_period_size(params),
+		params_period_bytes(params), params_periods(params),
+		params_buffer_size(params), params_buffer_bytes(params),
+		params_channels(params), params_rate(params),
+		params_format(params));
+
+
+	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (params_channels(params) == 1)
+			psc_dma->slots |= 0x00000100;
+		else
+			psc_dma->slots |= 0x00000300;
+	} else {
+		if (params_channels(params) == 1)
+			psc_dma->slots |= 0x01000000;
+		else
+			psc_dma->slots |= 0x03000000;
+	}
+	out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
+
+	return 0;
+}
+
+static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *cpu_dai)
+{
+	struct psc_dma *psc_dma = cpu_dai->private_data;
+
+	if (params_channels(params) == 1)
+		out_be32(&psc_dma->psc_regs->ac97_slots, 0x01000000);
+	else
+		out_be32(&psc_dma->psc_regs->ac97_slots, 0x03000000);
+
+	return 0;
+}
+
+static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
+							struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_STOP:
+		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+			psc_dma->slots &= 0xFFFF0000;
+		else
+			psc_dma->slots &= 0x0000FFFF;
+
+		out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
+		break;
+	}
+	return 0;
+}
+
+static int psc_ac97_probe(struct platform_device *pdev,
+					struct snd_soc_dai *cpu_dai)
+{
+	struct psc_dma *psc_dma = cpu_dai->private_data;
+	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+
+	/* Go */
+	out_8(&regs->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+	return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * ALSA SoC Bindings
+ *
+ * - Digital Audio Interface (DAI) template
+ * - create/destroy dai hooks
+ */
+
+/**
+ * psc_ac97_dai_template: template CPU Digital Audio Interface
+ */
+static struct snd_soc_dai_ops psc_ac97_analog_ops = {
+	.hw_params	= psc_ac97_hw_analog_params,
+	.trigger	= psc_ac97_trigger,
+};
+
+static struct snd_soc_dai_ops psc_ac97_digital_ops = {
+	.hw_params	= psc_ac97_hw_digital_params,
+};
+
+struct snd_soc_dai psc_ac97_dai[] = {
+{
+	.name   = "AC97",
+	.ac97_control = 1,
+	.probe	= psc_ac97_probe,
+	.playback = {
+		.channels_min   = 1,
+		.channels_max   = 6,
+		.rates          = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S32_BE,
+	},
+	.capture = {
+		.channels_min   = 1,
+		.channels_max   = 2,
+		.rates          = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S32_BE,
+	},
+	.ops = &psc_ac97_analog_ops,
+},
+{
+	.name   = "SPDIF",
+	.ac97_control = 1,
+	.playback = {
+		.channels_min   = 1,
+		.channels_max   = 2,
+		.rates          = SNDRV_PCM_RATE_32000 | \
+			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE,
+	},
+	.ops = &psc_ac97_digital_ops,
+} };
+EXPORT_SYMBOL_GPL(psc_ac97_dai);
+
+
+
+/* ---------------------------------------------------------------------
+ * OF platform bus binding code:
+ * - Probe/remove operations
+ * - OF device match table
+ */
+static int __devinit psc_ac97_of_probe(struct of_device *op,
+				      const struct of_device_id *match)
+{
+	int rc, i;
+	struct snd_ac97 ac97;
+	struct mpc52xx_psc __iomem *regs;
+
+	rc = mpc5200_audio_dma_create(op);
+	if (rc != 0)
+		return rc;
+
+	for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
+		psc_ac97_dai[i].dev = &op->dev;
+
+	rc = snd_soc_register_dais(psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
+	if (rc != 0) {
+		dev_err(&op->dev, "Failed to register DAI\n");
+		return rc;
+	}
+
+	psc_dma = dev_get_drvdata(&op->dev);
+	regs = psc_dma->psc_regs;
+	ac97.private_data = psc_dma;
+
+	for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
+		psc_ac97_dai[i].private_data = psc_dma;
+
+	psc_dma->imr = 0;
+	out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
+
+	/* Configure the serial interface mode to AC97 */
+	psc_dma->sicr = MPC52xx_PSC_SICR_SIM_AC97 | MPC52xx_PSC_SICR_ENAC97;
+	out_be32(&regs->sicr, psc_dma->sicr);
+
+	/* No slots active */
+	out_be32(&regs->ac97_slots, 0x00000000);
+
+	return 0;
+}
+
+static int __devexit psc_ac97_of_remove(struct of_device *op)
+{
+	return mpc5200_audio_dma_destroy(op);
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id psc_ac97_match[] __devinitdata = {
+	{ .compatible = "fsl,mpc5200-psc-ac97", },
+	{ .compatible = "fsl,mpc5200b-psc-ac97", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, psc_ac97_match);
+
+static struct of_platform_driver psc_ac97_driver = {
+	.match_table = psc_ac97_match,
+	.probe = psc_ac97_of_probe,
+	.remove = __devexit_p(psc_ac97_of_remove),
+	.driver = {
+		.name = "mpc5200-psc-ac97",
+		.owner = THIS_MODULE,
+	},
+};
+
+/* ---------------------------------------------------------------------
+ * Module setup and teardown; simply register the of_platform driver
+ * for the PSC in AC97 mode.
+ */
+static int __init psc_ac97_init(void)
+{
+	return of_register_platform_driver(&psc_ac97_driver);
+}
+module_init(psc_ac97_init);
+
+static void __exit psc_ac97_exit(void)
+{
+	of_unregister_platform_driver(&psc_ac97_driver);
+}
+module_exit(psc_ac97_exit);
+
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_DESCRIPTION("mpc5200 AC97 module");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.h b/sound/soc/fsl/mpc5200_psc_ac97.h
new file mode 100644
index 0000000..4bc18c3
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_ac97.h
@@ -0,0 +1,15 @@
+/*
+ * Freescale MPC5200 PSC in AC97 mode
+ * ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ */
+
+#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
+#define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
+
+extern struct snd_soc_dai psc_ac97_dai[];
+
+#define MPC5200_AC97_NORMAL 0
+#define MPC5200_AC97_SPDIF 1
+
+#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ */
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 1111c71..ce8de90 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -3,31 +3,21 @@
  * ALSA SoC Digital Audio Interface (DAI) driver
  *
  * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ * Copyright (C) 2009 Jon Smirl, Digispeaker
  */
 
-#include <linux/init.h>
 #include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/delay.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
-#include <linux/dma-mapping.h>
 
-#include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/soc-of-simple.h>
 
-#include <sysdev/bestcomm/bestcomm.h>
-#include <sysdev/bestcomm/gen_bd.h>
 #include <asm/mpc52xx_psc.h>
 
-MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
-MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
-MODULE_LICENSE("GPL");
+#include "mpc5200_psc_i2s.h"
+#include "mpc5200_dma.h"
 
 /**
  * PSC_I2S_RATES: sample rates supported by the I2S
@@ -44,191 +34,17 @@
  * PSC_I2S_FORMATS: audio formats supported by the PSC I2S mode
  */
 #define PSC_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
-			 SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE | \
-			 SNDRV_PCM_FMTBIT_S32_BE)
-
-/**
- * psc_i2s_stream - Data specific to a single stream (playback or capture)
- * @active:		flag indicating if the stream is active
- * @psc_i2s:		pointer back to parent psc_i2s data structure
- * @bcom_task:		bestcomm task structure
- * @irq:		irq number for bestcomm task
- * @period_start:	physical address of start of DMA region
- * @period_end:		physical address of end of DMA region
- * @period_next_pt:	physical address of next DMA buffer to enqueue
- * @period_bytes:	size of DMA period in bytes
- */
-struct psc_i2s_stream {
-	int active;
-	struct psc_i2s *psc_i2s;
-	struct bcom_task *bcom_task;
-	int irq;
-	struct snd_pcm_substream *stream;
-	dma_addr_t period_start;
-	dma_addr_t period_end;
-	dma_addr_t period_next_pt;
-	dma_addr_t period_current_pt;
-	int period_bytes;
-};
-
-/**
- * psc_i2s - Private driver data
- * @name: short name for this device ("PSC0", "PSC1", etc)
- * @psc_regs: pointer to the PSC's registers
- * @fifo_regs: pointer to the PSC's FIFO registers
- * @irq: IRQ of this PSC
- * @dev: struct device pointer
- * @dai: the CPU DAI for this device
- * @sicr: Base value used in serial interface control register; mode is ORed
- *        with this value.
- * @playback: Playback stream context data
- * @capture: Capture stream context data
- */
-struct psc_i2s {
-	char name[32];
-	struct mpc52xx_psc __iomem *psc_regs;
-	struct mpc52xx_psc_fifo __iomem *fifo_regs;
-	unsigned int irq;
-	struct device *dev;
-	struct snd_soc_dai dai;
-	spinlock_t lock;
-	u32 sicr;
-
-	/* per-stream data */
-	struct psc_i2s_stream playback;
-	struct psc_i2s_stream capture;
-
-	/* Statistics */
-	struct {
-		int overrun_count;
-		int underrun_count;
-	} stats;
-};
-
-/*
- * Interrupt handlers
- */
-static irqreturn_t psc_i2s_status_irq(int irq, void *_psc_i2s)
-{
-	struct psc_i2s *psc_i2s = _psc_i2s;
-	struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs;
-	u16 isr;
-
-	isr = in_be16(&regs->mpc52xx_psc_isr);
-
-	/* Playback underrun error */
-	if (psc_i2s->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP))
-		psc_i2s->stats.underrun_count++;
-
-	/* Capture overrun error */
-	if (psc_i2s->capture.active && (isr & MPC52xx_PSC_IMR_ORERR))
-		psc_i2s->stats.overrun_count++;
-
-	out_8(&regs->command, 4 << 4);	/* reset the error status */
-
-	return IRQ_HANDLED;
-}
-
-/**
- * psc_i2s_bcom_enqueue_next_buffer - Enqueue another audio buffer
- * @s: pointer to stream private data structure
- *
- * Enqueues another audio period buffer into the bestcomm queue.
- *
- * Note: The routine must only be called when there is space available in
- * the queue.  Otherwise the enqueue will fail and the audio ring buffer
- * will get out of sync
- */
-static void psc_i2s_bcom_enqueue_next_buffer(struct psc_i2s_stream *s)
-{
-	struct bcom_bd *bd;
-
-	/* Prepare and enqueue the next buffer descriptor */
-	bd = bcom_prepare_next_buffer(s->bcom_task);
-	bd->status = s->period_bytes;
-	bd->data[0] = s->period_next_pt;
-	bcom_submit_next_buffer(s->bcom_task, NULL);
-
-	/* Update for next period */
-	s->period_next_pt += s->period_bytes;
-	if (s->period_next_pt >= s->period_end)
-		s->period_next_pt = s->period_start;
-}
-
-/* Bestcomm DMA irq handler */
-static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream)
-{
-	struct psc_i2s_stream *s = _psc_i2s_stream;
-
-	/* For each finished period, dequeue the completed period buffer
-	 * and enqueue a new one in it's place. */
-	while (bcom_buffer_done(s->bcom_task)) {
-		bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
-		s->period_current_pt += s->period_bytes;
-		if (s->period_current_pt >= s->period_end)
-			s->period_current_pt = s->period_start;
-		psc_i2s_bcom_enqueue_next_buffer(s);
-		bcom_enable(s->bcom_task);
-	}
-
-	/* If the stream is active, then also inform the PCM middle layer
-	 * of the period finished event. */
-	if (s->active)
-		snd_pcm_period_elapsed(s->stream);
-
-	return IRQ_HANDLED;
-}
-
-/**
- * psc_i2s_startup: create a new substream
- *
- * This is the first function called when a stream is opened.
- *
- * If this is the first stream open, then grab the IRQ and program most of
- * the PSC registers.
- */
-static int psc_i2s_startup(struct snd_pcm_substream *substream,
-			   struct snd_soc_dai *dai)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
-	int rc;
-
-	dev_dbg(psc_i2s->dev, "psc_i2s_startup(substream=%p)\n", substream);
-
-	if (!psc_i2s->playback.active &&
-	    !psc_i2s->capture.active) {
-		/* Setup the IRQs */
-		rc = request_irq(psc_i2s->irq, &psc_i2s_status_irq, IRQF_SHARED,
-				 "psc-i2s-status", psc_i2s);
-		rc |= request_irq(psc_i2s->capture.irq,
-				  &psc_i2s_bcom_irq, IRQF_SHARED,
-				  "psc-i2s-capture", &psc_i2s->capture);
-		rc |= request_irq(psc_i2s->playback.irq,
-				  &psc_i2s_bcom_irq, IRQF_SHARED,
-				  "psc-i2s-playback", &psc_i2s->playback);
-		if (rc) {
-			free_irq(psc_i2s->irq, psc_i2s);
-			free_irq(psc_i2s->capture.irq,
-				 &psc_i2s->capture);
-			free_irq(psc_i2s->playback.irq,
-				 &psc_i2s->playback);
-			return -ENODEV;
-		}
-	}
-
-	return 0;
-}
+			 SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
 
 static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
 	u32 mode;
 
-	dev_dbg(psc_i2s->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
+	dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
 		" periods=%i buffer_size=%i  buffer_bytes=%i\n",
 		__func__, substream, params_period_size(params),
 		params_period_bytes(params), params_periods(params),
@@ -248,174 +64,14 @@
 		mode = MPC52xx_PSC_SICR_SIM_CODEC_32;
 		break;
 	default:
-		dev_dbg(psc_i2s->dev, "invalid format\n");
+		dev_dbg(psc_dma->dev, "invalid format\n");
 		return -EINVAL;
 	}
-	out_be32(&psc_i2s->psc_regs->sicr, psc_i2s->sicr | mode);
-
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	out_be32(&psc_dma->psc_regs->sicr, psc_dma->sicr | mode);
 
 	return 0;
 }
 
-static int psc_i2s_hw_free(struct snd_pcm_substream *substream,
-			   struct snd_soc_dai *dai)
-{
-	snd_pcm_set_runtime_buffer(substream, NULL);
-	return 0;
-}
-
-/**
- * psc_i2s_trigger: start and stop the DMA transfer.
- *
- * This function is called by ALSA to start, stop, pause, and resume the DMA
- * transfer of data.
- */
-static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
-			   struct snd_soc_dai *dai)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct psc_i2s_stream *s;
-	struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs;
-	u16 imr;
-	u8 psc_cmd;
-	unsigned long flags;
-
-	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
-		s = &psc_i2s->capture;
-	else
-		s = &psc_i2s->playback;
-
-	dev_dbg(psc_i2s->dev, "psc_i2s_trigger(substream=%p, cmd=%i)"
-		" stream_id=%i\n",
-		substream, cmd, substream->pstr->stream);
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		s->period_bytes = frames_to_bytes(runtime,
-						  runtime->period_size);
-		s->period_start = virt_to_phys(runtime->dma_area);
-		s->period_end = s->period_start +
-				(s->period_bytes * runtime->periods);
-		s->period_next_pt = s->period_start;
-		s->period_current_pt = s->period_start;
-		s->active = 1;
-
-		/* First; reset everything */
-		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			out_8(&regs->command, MPC52xx_PSC_RST_RX);
-			out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
-		} else {
-			out_8(&regs->command, MPC52xx_PSC_RST_TX);
-			out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
-		}
-
-		/* Next, fill up the bestcomm bd queue and enable DMA.
-		 * This will begin filling the PSC's fifo. */
-		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
-			bcom_gen_bd_rx_reset(s->bcom_task);
-		else
-			bcom_gen_bd_tx_reset(s->bcom_task);
-		while (!bcom_queue_full(s->bcom_task))
-			psc_i2s_bcom_enqueue_next_buffer(s);
-		bcom_enable(s->bcom_task);
-
-		/* Due to errata in the i2s mode; need to line up enabling
-		 * the transmitter with a transition on the frame sync
-		 * line */
-
-		spin_lock_irqsave(&psc_i2s->lock, flags);
-		/* first make sure it is low */
-		while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) != 0)
-			;
-		/* then wait for the transition to high */
-		while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) == 0)
-			;
-		/* Finally, enable the PSC.
-		 * Receiver must always be enabled; even when we only want
-		 * transmit.  (see 15.3.2.3 of MPC5200B User's Guide) */
-		psc_cmd = MPC52xx_PSC_RX_ENABLE;
-		if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			psc_cmd |= MPC52xx_PSC_TX_ENABLE;
-		out_8(&regs->command, psc_cmd);
-		spin_unlock_irqrestore(&psc_i2s->lock, flags);
-
-		break;
-
-	case SNDRV_PCM_TRIGGER_STOP:
-		/* Turn off the PSC */
-		s->active = 0;
-		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			if (!psc_i2s->playback.active) {
-				out_8(&regs->command, 2 << 4);	/* reset rx */
-				out_8(&regs->command, 3 << 4);	/* reset tx */
-				out_8(&regs->command, 4 << 4);	/* reset err */
-			}
-		} else {
-			out_8(&regs->command, 3 << 4);	/* reset tx */
-			out_8(&regs->command, 4 << 4);	/* reset err */
-			if (!psc_i2s->capture.active)
-				out_8(&regs->command, 2 << 4);	/* reset rx */
-		}
-
-		bcom_disable(s->bcom_task);
-		while (!bcom_queue_empty(s->bcom_task))
-			bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
-
-		break;
-
-	default:
-		dev_dbg(psc_i2s->dev, "invalid command\n");
-		return -EINVAL;
-	}
-
-	/* Update interrupt enable settings */
-	imr = 0;
-	if (psc_i2s->playback.active)
-		imr |= MPC52xx_PSC_IMR_TXEMP;
-	if (psc_i2s->capture.active)
-		imr |= MPC52xx_PSC_IMR_ORERR;
-	out_be16(&regs->isr_imr.imr, imr);
-
-	return 0;
-}
-
-/**
- * psc_i2s_shutdown: shutdown the data transfer on a stream
- *
- * Shutdown the PSC if there are no other substreams open.
- */
-static void psc_i2s_shutdown(struct snd_pcm_substream *substream,
-			     struct snd_soc_dai *dai)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
-
-	dev_dbg(psc_i2s->dev, "psc_i2s_shutdown(substream=%p)\n", substream);
-
-	/*
-	 * If this is the last active substream, disable the PSC and release
-	 * the IRQ.
-	 */
-	if (!psc_i2s->playback.active &&
-	    !psc_i2s->capture.active) {
-
-		/* Disable all interrupts and reset the PSC */
-		out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0);
-		out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset tx */
-		out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset rx */
-		out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */
-		out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */
-
-		/* Release irqs */
-		free_irq(psc_i2s->irq, psc_i2s);
-		free_irq(psc_i2s->capture.irq, &psc_i2s->capture);
-		free_irq(psc_i2s->playback.irq, &psc_i2s->playback);
-	}
-}
-
 /**
  * psc_i2s_set_sysclk: set the clock frequency and direction
  *
@@ -433,8 +89,8 @@
 static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
 			      int clk_id, unsigned int freq, int dir)
 {
-	struct psc_i2s *psc_i2s = cpu_dai->private_data;
-	dev_dbg(psc_i2s->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
+	struct psc_dma *psc_dma = cpu_dai->private_data;
+	dev_dbg(psc_dma->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
 				cpu_dai, dir);
 	return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
 }
@@ -452,8 +108,8 @@
  */
 static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
 {
-	struct psc_i2s *psc_i2s = cpu_dai->private_data;
-	dev_dbg(psc_i2s->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n",
+	struct psc_dma *psc_dma = cpu_dai->private_data;
+	dev_dbg(psc_dma->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n",
 				cpu_dai, format);
 	return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
 }
@@ -469,16 +125,13 @@
  * psc_i2s_dai_template: template CPU Digital Audio Interface
  */
 static struct snd_soc_dai_ops psc_i2s_dai_ops = {
-	.startup	= psc_i2s_startup,
 	.hw_params	= psc_i2s_hw_params,
-	.hw_free	= psc_i2s_hw_free,
-	.shutdown	= psc_i2s_shutdown,
-	.trigger	= psc_i2s_trigger,
 	.set_sysclk	= psc_i2s_set_sysclk,
 	.set_fmt	= psc_i2s_set_fmt,
 };
 
-static struct snd_soc_dai psc_i2s_dai_template = {
+struct snd_soc_dai psc_i2s_dai[] = {{
+	.name   = "I2S",
 	.playback = {
 		.channels_min = 2,
 		.channels_max = 2,
@@ -492,223 +145,8 @@
 		.formats = PSC_I2S_FORMATS,
 	},
 	.ops = &psc_i2s_dai_ops,
-};
-
-/* ---------------------------------------------------------------------
- * The PSC I2S 'ASoC platform' driver
- *
- * Can be referenced by an 'ASoC machine' driver
- * This driver only deals with the audio bus; it doesn't have any
- * interaction with the attached codec
- */
-
-static const struct snd_pcm_hardware psc_i2s_pcm_hardware = {
-	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-		SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-		SNDRV_PCM_INFO_BATCH,
-	.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |
-		   SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
-	.rate_min = 8000,
-	.rate_max = 48000,
-	.channels_min = 2,
-	.channels_max = 2,
-	.period_bytes_max	= 1024 * 1024,
-	.period_bytes_min	= 32,
-	.periods_min		= 2,
-	.periods_max		= 256,
-	.buffer_bytes_max	= 2 * 1024 * 1024,
-	.fifo_size		= 0,
-};
-
-static int psc_i2s_pcm_open(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
-	struct psc_i2s_stream *s;
-
-	dev_dbg(psc_i2s->dev, "psc_i2s_pcm_open(substream=%p)\n", substream);
-
-	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
-		s = &psc_i2s->capture;
-	else
-		s = &psc_i2s->playback;
-
-	snd_soc_set_runtime_hwparams(substream, &psc_i2s_pcm_hardware);
-
-	s->stream = substream;
-	return 0;
-}
-
-static int psc_i2s_pcm_close(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
-	struct psc_i2s_stream *s;
-
-	dev_dbg(psc_i2s->dev, "psc_i2s_pcm_close(substream=%p)\n", substream);
-
-	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
-		s = &psc_i2s->capture;
-	else
-		s = &psc_i2s->playback;
-
-	s->stream = NULL;
-	return 0;
-}
-
-static snd_pcm_uframes_t
-psc_i2s_pcm_pointer(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
-	struct psc_i2s_stream *s;
-	dma_addr_t count;
-
-	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
-		s = &psc_i2s->capture;
-	else
-		s = &psc_i2s->playback;
-
-	count = s->period_current_pt - s->period_start;
-
-	return bytes_to_frames(substream->runtime, count);
-}
-
-static struct snd_pcm_ops psc_i2s_pcm_ops = {
-	.open		= psc_i2s_pcm_open,
-	.close		= psc_i2s_pcm_close,
-	.ioctl		= snd_pcm_lib_ioctl,
-	.pointer	= psc_i2s_pcm_pointer,
-};
-
-static u64 psc_i2s_pcm_dmamask = 0xffffffff;
-static int psc_i2s_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
-			   struct snd_pcm *pcm)
-{
-	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
-	size_t size = psc_i2s_pcm_hardware.buffer_bytes_max;
-	int rc = 0;
-
-	dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_new(card=%p, dai=%p, pcm=%p)\n",
-		card, dai, pcm);
-
-	if (!card->dev->dma_mask)
-		card->dev->dma_mask = &psc_i2s_pcm_dmamask;
-	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = 0xffffffff;
-
-	if (pcm->streams[0].substream) {
-		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
-					&pcm->streams[0].substream->dma_buffer);
-		if (rc)
-			goto playback_alloc_err;
-	}
-
-	if (pcm->streams[1].substream) {
-		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
-					&pcm->streams[1].substream->dma_buffer);
-		if (rc)
-			goto capture_alloc_err;
-	}
-
-	return 0;
-
- capture_alloc_err:
-	if (pcm->streams[0].substream)
-		snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
- playback_alloc_err:
-	dev_err(card->dev, "Cannot allocate buffer(s)\n");
-	return -ENOMEM;
-}
-
-static void psc_i2s_pcm_free(struct snd_pcm *pcm)
-{
-	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
-	struct snd_pcm_substream *substream;
-	int stream;
-
-	dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_free(pcm=%p)\n", pcm);
-
-	for (stream = 0; stream < 2; stream++) {
-		substream = pcm->streams[stream].substream;
-		if (substream) {
-			snd_dma_free_pages(&substream->dma_buffer);
-			substream->dma_buffer.area = NULL;
-			substream->dma_buffer.addr = 0;
-		}
-	}
-}
-
-struct snd_soc_platform psc_i2s_pcm_soc_platform = {
-	.name		= "mpc5200-psc-audio",
-	.pcm_ops	= &psc_i2s_pcm_ops,
-	.pcm_new	= &psc_i2s_pcm_new,
-	.pcm_free	= &psc_i2s_pcm_free,
-};
-
-/* ---------------------------------------------------------------------
- * Sysfs attributes for debugging
- */
-
-static ssize_t psc_i2s_status_show(struct device *dev,
-			   struct device_attribute *attr, char *buf)
-{
-	struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
-
-	return sprintf(buf, "status=%.4x sicr=%.8x rfnum=%i rfstat=0x%.4x "
-			"tfnum=%i tfstat=0x%.4x\n",
-			in_be16(&psc_i2s->psc_regs->sr_csr.status),
-			in_be32(&psc_i2s->psc_regs->sicr),
-			in_be16(&psc_i2s->fifo_regs->rfnum) & 0x1ff,
-			in_be16(&psc_i2s->fifo_regs->rfstat),
-			in_be16(&psc_i2s->fifo_regs->tfnum) & 0x1ff,
-			in_be16(&psc_i2s->fifo_regs->tfstat));
-}
-
-static int *psc_i2s_get_stat_attr(struct psc_i2s *psc_i2s, const char *name)
-{
-	if (strcmp(name, "playback_underrun") == 0)
-		return &psc_i2s->stats.underrun_count;
-	if (strcmp(name, "capture_overrun") == 0)
-		return &psc_i2s->stats.overrun_count;
-
-	return NULL;
-}
-
-static ssize_t psc_i2s_stat_show(struct device *dev,
-				 struct device_attribute *attr, char *buf)
-{
-	struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
-	int *attrib;
-
-	attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name);
-	if (!attrib)
-		return 0;
-
-	return sprintf(buf, "%i\n", *attrib);
-}
-
-static ssize_t psc_i2s_stat_store(struct device *dev,
-				  struct device_attribute *attr,
-				  const char *buf,
-				  size_t count)
-{
-	struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
-	int *attrib;
-
-	attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name);
-	if (!attrib)
-		return 0;
-
-	*attrib = simple_strtoul(buf, NULL, 0);
-	return count;
-}
-
-static DEVICE_ATTR(status, 0644, psc_i2s_status_show, NULL);
-static DEVICE_ATTR(playback_underrun, 0644, psc_i2s_stat_show,
-			psc_i2s_stat_store);
-static DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show,
-			psc_i2s_stat_store);
+} };
+EXPORT_SYMBOL_GPL(psc_i2s_dai);
 
 /* ---------------------------------------------------------------------
  * OF platform bus binding code:
@@ -718,150 +156,65 @@
 static int __devinit psc_i2s_of_probe(struct of_device *op,
 				      const struct of_device_id *match)
 {
-	phys_addr_t fifo;
-	struct psc_i2s *psc_i2s;
-	struct resource res;
-	int size, psc_id, irq, rc;
-	const __be32 *prop;
-	void __iomem *regs;
+	int rc;
+	struct psc_dma *psc_dma;
+	struct mpc52xx_psc __iomem *regs;
 
-	dev_dbg(&op->dev, "probing psc i2s device\n");
+	rc = mpc5200_audio_dma_create(op);
+	if (rc != 0)
+		return rc;
 
-	/* Get the PSC ID */
-	prop = of_get_property(op->node, "cell-index", &size);
-	if (!prop || size < sizeof *prop)
-		return -ENODEV;
-	psc_id = be32_to_cpu(*prop);
-
-	/* Fetch the registers and IRQ of the PSC */
-	irq = irq_of_parse_and_map(op->node, 0);
-	if (of_address_to_resource(op->node, 0, &res)) {
-		dev_err(&op->dev, "Missing reg property\n");
-		return -ENODEV;
-	}
-	regs = ioremap(res.start, 1 + res.end - res.start);
-	if (!regs) {
-		dev_err(&op->dev, "Could not map registers\n");
-		return -ENODEV;
+	rc = snd_soc_register_dais(psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
+	if (rc != 0) {
+		pr_err("Failed to register DAI\n");
+		return 0;
 	}
 
-	/* Allocate and initialize the driver private data */
-	psc_i2s = kzalloc(sizeof *psc_i2s, GFP_KERNEL);
-	if (!psc_i2s) {
-		iounmap(regs);
-		return -ENOMEM;
-	}
-	spin_lock_init(&psc_i2s->lock);
-	psc_i2s->irq = irq;
-	psc_i2s->psc_regs = regs;
-	psc_i2s->fifo_regs = regs + sizeof *psc_i2s->psc_regs;
-	psc_i2s->dev = &op->dev;
-	psc_i2s->playback.psc_i2s = psc_i2s;
-	psc_i2s->capture.psc_i2s = psc_i2s;
-	snprintf(psc_i2s->name, sizeof psc_i2s->name, "PSC%u", psc_id+1);
-
-	/* Fill out the CPU DAI structure */
-	memcpy(&psc_i2s->dai, &psc_i2s_dai_template, sizeof psc_i2s->dai);
-	psc_i2s->dai.private_data = psc_i2s;
-	psc_i2s->dai.name = psc_i2s->name;
-	psc_i2s->dai.id = psc_id;
-
-	/* Find the address of the fifo data registers and setup the
-	 * DMA tasks */
-	fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
-	psc_i2s->capture.bcom_task =
-		bcom_psc_gen_bd_rx_init(psc_id, 10, fifo, 512);
-	psc_i2s->playback.bcom_task =
-		bcom_psc_gen_bd_tx_init(psc_id, 10, fifo);
-	if (!psc_i2s->capture.bcom_task ||
-	    !psc_i2s->playback.bcom_task) {
-		dev_err(&op->dev, "Could not allocate bestcomm tasks\n");
-		iounmap(regs);
-		kfree(psc_i2s);
-		return -ENODEV;
-	}
-
-	/* Disable all interrupts and reset the PSC */
-	out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0);
-	out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset transmitter */
-	out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset receiver */
-	out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */
-	out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */
+	psc_dma = dev_get_drvdata(&op->dev);
+	regs = psc_dma->psc_regs;
 
 	/* Configure the serial interface mode; defaulting to CODEC8 mode */
-	psc_i2s->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S |
+	psc_dma->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S |
 			MPC52xx_PSC_SICR_CLKPOL;
-	if (of_get_property(op->node, "fsl,cellslave", NULL))
-		psc_i2s->sicr |= MPC52xx_PSC_SICR_CELLSLAVE |
-				 MPC52xx_PSC_SICR_GENCLK;
-	out_be32(&psc_i2s->psc_regs->sicr,
-		 psc_i2s->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8);
+	out_be32(&psc_dma->psc_regs->sicr,
+		 psc_dma->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8);
 
 	/* Check for the codec handle.  If it is not present then we
 	 * are done */
 	if (!of_get_property(op->node, "codec-handle", NULL))
 		return 0;
 
-	/* Set up mode register;
-	 * First write: RxRdy (FIFO Alarm) generates rx FIFO irq
-	 * Second write: register Normal mode for non loopback
-	 */
-	out_8(&psc_i2s->psc_regs->mode, 0);
-	out_8(&psc_i2s->psc_regs->mode, 0);
+	/* Due to errata in the dma mode; need to line up enabling
+	 * the transmitter with a transition on the frame sync
+	 * line */
 
-	/* Set the TX and RX fifo alarm thresholds */
-	out_be16(&psc_i2s->fifo_regs->rfalarm, 0x100);
-	out_8(&psc_i2s->fifo_regs->rfcntl, 0x4);
-	out_be16(&psc_i2s->fifo_regs->tfalarm, 0x100);
-	out_8(&psc_i2s->fifo_regs->tfcntl, 0x7);
+	/* first make sure it is low */
+	while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) != 0)
+		;
+	/* then wait for the transition to high */
+	while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) == 0)
+		;
+	/* Finally, enable the PSC.
+	 * Receiver must always be enabled; even when we only want
+	 * transmit.  (see 15.3.2.3 of MPC5200B User's Guide) */
 
-	/* Lookup the IRQ numbers */
-	psc_i2s->playback.irq =
-		bcom_get_task_irq(psc_i2s->playback.bcom_task);
-	psc_i2s->capture.irq =
-		bcom_get_task_irq(psc_i2s->capture.bcom_task);
-
-	/* Save what we've done so it can be found again later */
-	dev_set_drvdata(&op->dev, psc_i2s);
-
-	/* Register the SYSFS files */
-	rc = device_create_file(psc_i2s->dev, &dev_attr_status);
-	rc |= device_create_file(psc_i2s->dev, &dev_attr_capture_overrun);
-	rc |= device_create_file(psc_i2s->dev, &dev_attr_playback_underrun);
-	if (rc)
-		dev_info(psc_i2s->dev, "error creating sysfs files\n");
-
-	snd_soc_register_platform(&psc_i2s_pcm_soc_platform);
-
-	/* Tell the ASoC OF helpers about it */
-	of_snd_soc_register_platform(&psc_i2s_pcm_soc_platform, op->node,
-				     &psc_i2s->dai);
+	/* Go */
+	out_8(&psc_dma->psc_regs->command,
+			MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
 
 	return 0;
+
 }
 
 static int __devexit psc_i2s_of_remove(struct of_device *op)
 {
-	struct psc_i2s *psc_i2s = dev_get_drvdata(&op->dev);
-
-	dev_dbg(&op->dev, "psc_i2s_remove()\n");
-
-	snd_soc_unregister_platform(&psc_i2s_pcm_soc_platform);
-
-	bcom_gen_bd_rx_release(psc_i2s->capture.bcom_task);
-	bcom_gen_bd_tx_release(psc_i2s->playback.bcom_task);
-
-	iounmap(psc_i2s->psc_regs);
-	iounmap(psc_i2s->fifo_regs);
-	kfree(psc_i2s);
-	dev_set_drvdata(&op->dev, NULL);
-
-	return 0;
+	return mpc5200_audio_dma_destroy(op);
 }
 
 /* Match table for of_platform binding */
 static struct of_device_id psc_i2s_match[] __devinitdata = {
 	{ .compatible = "fsl,mpc5200-psc-i2s", },
+	{ .compatible = "fsl,mpc5200b-psc-i2s", },
 	{}
 };
 MODULE_DEVICE_TABLE(of, psc_i2s_match);
@@ -892,4 +245,7 @@
 }
 module_exit(psc_i2s_exit);
 
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
+MODULE_LICENSE("GPL");
 
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.h b/sound/soc/fsl/mpc5200_psc_i2s.h
new file mode 100644
index 0000000..ce55e07
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_i2s.h
@@ -0,0 +1,12 @@
+/*
+ * Freescale MPC5200 PSC in I2S mode
+ * ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ */
+
+#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__
+#define __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__
+
+extern struct snd_soc_dai psc_i2s_dai[];
+
+#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ */
diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c
new file mode 100644
index 0000000..8766f7a
--- /dev/null
+++ b/sound/soc/fsl/pcm030-audio-fabric.c
@@ -0,0 +1,90 @@
+/*
+ * Phytec pcm030 driver for the PSC of the Freescale MPC52xx
+ * configured as AC97 interface
+ *
+ * Copyright 2008 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-of-simple.h>
+
+#include "mpc5200_dma.h"
+#include "mpc5200_psc_ac97.h"
+#include "../codecs/wm9712.h"
+
+static struct snd_soc_device device;
+static struct snd_soc_card card;
+
+static struct snd_soc_dai_link pcm030_fabric_dai[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 Analog",
+	.codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+	.cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+},
+{
+	.name = "AC97",
+	.stream_name = "AC97 IEC958",
+	.codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+	.cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+},
+};
+
+static __init int pcm030_fabric_init(void)
+{
+	struct platform_device *pdev;
+	int rc;
+
+	if (!machine_is_compatible("phytec,pcm030"))
+		return -ENODEV;
+
+	card.platform = &mpc5200_audio_dma_platform;
+	card.name = "pcm030";
+	card.dai_link = pcm030_fabric_dai;
+	card.num_links = ARRAY_SIZE(pcm030_fabric_dai);
+
+	device.card = &card;
+	device.codec_dev = &soc_codec_dev_wm9712;
+
+	pdev = platform_device_alloc("soc-audio", 1);
+	if (!pdev) {
+		pr_err("pcm030_fabric_init: platform_device_alloc() failed\n");
+		return -ENODEV;
+	}
+
+	platform_set_drvdata(pdev, &device);
+	device.dev = &pdev->dev;
+
+	rc = platform_device_add(pdev);
+	if (rc) {
+		pr_err("pcm030_fabric_init: platform_device_add() failed\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+module_init(pcm030_fabric_init);
+
+
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_DESCRIPTION(DRV_NAME ": mpc5200 pcm030 fabric driver");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 675732e..b771238 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -39,6 +39,14 @@
 	help
 	  Say Y if you want to add support for SoC audio on the omap2evm board.
 
+config SND_OMAP_SOC_OMAP3EVM
+	tristate "SoC Audio support for OMAP3EVM board"
+	depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3EVM
+	select SND_OMAP_SOC_MCBSP
+	select SND_SOC_TWL4030
+	help
+	  Say Y if you want to add support for SoC audio on the omap3evm board.
+
 config SND_OMAP_SOC_SDP3430
 	tristate "SoC Audio support for Texas Instruments SDP3430"
 	depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index 0c9e4ac..a37f498 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -10,6 +10,7 @@
 snd-soc-osk5912-objs := osk5912.o
 snd-soc-overo-objs := overo.o
 snd-soc-omap2evm-objs := omap2evm.o
+snd-soc-omap3evm-objs := omap3evm.o
 snd-soc-sdp3430-objs := sdp3430.o
 snd-soc-omap3pandora-objs := omap3pandora.o
 snd-soc-omap3beagle-objs := omap3beagle.o
@@ -18,6 +19,7 @@
 obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
 obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o
 obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o
+obj-$(CONFIG_MACH_OMAP3EVM) += snd-soc-omap3evm.o
 obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 91ef179..b60b1df 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -383,10 +383,9 @@
 	clk_set_parent(sys_clkout2_src, func96m_clk);
 	clk_set_rate(sys_clkout2, 12000000);
 
-	if (gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0)
-		BUG();
-	if (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0)
-		BUG();
+	BUG_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) ||
+	       (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0));
+
 	gpio_direction_output(N810_HEADSET_AMP_GPIO, 0);
 	gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0);
 
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 9126142..a5d46a7 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -215,8 +215,9 @@
 	struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
 	struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
 	int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id;
-	int wlen, channels;
+	int wlen, channels, wpf;
 	unsigned long port;
+	unsigned int format;
 
 	if (cpu_class_is_omap1()) {
 		dma = omap1_dma_reqs[bus_id][substream->stream];
@@ -244,18 +245,24 @@
 		return 0;
 	}
 
-	channels = params_channels(params);
+	format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+	wpf = channels = params_channels(params);
 	switch (channels) {
 	case 2:
-		/* Use dual-phase frames */
-		regs->rcr2	|= RPHASE;
-		regs->xcr2	|= XPHASE;
+		if (format == SND_SOC_DAIFMT_I2S) {
+			/* Use dual-phase frames */
+			regs->rcr2	|= RPHASE;
+			regs->xcr2	|= XPHASE;
+			/* Set 1 word per (McBSP) frame for phase1 and phase2 */
+			wpf--;
+			regs->rcr2	|= RFRLEN2(wpf - 1);
+			regs->xcr2	|= XFRLEN2(wpf - 1);
+		}
 	case 1:
-		/* Set 1 word per (McBSP) frame */
-		regs->rcr2	|= RFRLEN2(1 - 1);
-		regs->rcr1	|= RFRLEN1(1 - 1);
-		regs->xcr2	|= XFRLEN2(1 - 1);
-		regs->xcr1	|= XFRLEN1(1 - 1);
+	case 4:
+		/* Set word per (McBSP) frame for phase1 */
+		regs->rcr1	|= RFRLEN1(wpf - 1);
+		regs->xcr1	|= XFRLEN1(wpf - 1);
 		break;
 	default:
 		/* Unsupported number of channels */
@@ -277,11 +284,12 @@
 	}
 
 	/* Set FS period and length in terms of bit clock periods */
-	switch (mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	switch (format) {
 	case SND_SOC_DAIFMT_I2S:
-		regs->srgr2	|= FPER(wlen * 2 - 1);
+		regs->srgr2	|= FPER(wlen * channels - 1);
 		regs->srgr1	|= FWID(wlen - 1);
 		break;
+	case SND_SOC_DAIFMT_DSP_A:
 	case SND_SOC_DAIFMT_DSP_B:
 		regs->srgr2	|= FPER(wlen * channels - 1);
 		regs->srgr1	|= FWID(0);
@@ -326,6 +334,13 @@
 		regs->rcr2	|= RDATDLY(1);
 		regs->xcr2	|= XDATDLY(1);
 		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		/* 1-bit data delay */
+		regs->rcr2      |= RDATDLY(1);
+		regs->xcr2      |= XDATDLY(1);
+		/* Invert FS polarity configuration */
+		temp_fmt ^= SND_SOC_DAIFMT_NB_IF;
+		break;
 	case SND_SOC_DAIFMT_DSP_B:
 		/* 0-bit data delay */
 		regs->rcr2      |= RDATDLY(0);
@@ -492,13 +507,13 @@
 	.id = (link_id),					\
 	.playback = {						\
 		.channels_min = 1,				\
-		.channels_max = 2,				\
+		.channels_max = 4,				\
 		.rates = OMAP_MCBSP_RATES,			\
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,		\
 	},							\
 	.capture = {						\
 		.channels_min = 1,				\
-		.channels_max = 2,				\
+		.channels_max = 4,				\
 		.rates = OMAP_MCBSP_RATES,			\
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,		\
 	},							\
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 07cf7f4..6454e15 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -87,8 +87,10 @@
 	struct omap_pcm_dma_data *dma_data = rtd->dai->cpu_dai->dma_data;
 	int err = 0;
 
+	/* return if this is a bufferless transfer e.g.
+	 * codec <--> BT codec or GSM modem -- lg FIXME */
 	if (!dma_data)
-		return -ENODEV;
+		return 0;
 
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 	runtime->dma_bytes = params_buffer_bytes(params);
@@ -134,6 +136,11 @@
 	struct omap_pcm_dma_data *dma_data = prtd->dma_data;
 	struct omap_dma_channel_params dma_params;
 
+	/* return if this is a bufferless transfer e.g.
+	 * codec <--> BT codec or GSM modem -- lg FIXME */
+	if (!prtd->dma_data)
+		return 0;
+
 	memset(&dma_params, 0, sizeof(dma_params));
 	/*
 	 * Note: Regardless of interface data formats supported by OMAP McBSP
diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c
index 0c2322d..027e1a4 100644
--- a/sound/soc/omap/omap2evm.c
+++ b/sound/soc/omap/omap2evm.c
@@ -86,7 +86,7 @@
 	.name = "TWL4030",
 	.stream_name = "TWL4030",
 	.cpu_dai = &omap_mcbsp_dai[0],
-	.codec_dai = &twl4030_dai,
+	.codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
 	.ops = &omap2evm_ops,
 };
 
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
index fd24a4a..b0cff9f 100644
--- a/sound/soc/omap/omap3beagle.c
+++ b/sound/soc/omap/omap3beagle.c
@@ -41,23 +41,33 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int fmt;
 	int ret;
 
+	switch (params_channels(params)) {
+	case 2: /* Stereo I2S mode */
+		fmt =	SND_SOC_DAIFMT_I2S |
+			SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBM_CFM;
+		break;
+	case 4: /* Four channel TDM mode */
+		fmt =	SND_SOC_DAIFMT_DSP_A |
+			SND_SOC_DAIFMT_IB_NF |
+			SND_SOC_DAIFMT_CBM_CFM;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	/* 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);
+	ret = snd_soc_dai_set_fmt(codec_dai, fmt);
 	if (ret < 0) {
 		printk(KERN_ERR "can't set codec DAI configuration\n");
 		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);
+	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
 	if (ret < 0) {
 		printk(KERN_ERR "can't set cpu DAI configuration\n");
 		return ret;
@@ -83,7 +93,7 @@
 	.name = "TWL4030",
 	.stream_name = "TWL4030",
 	.cpu_dai = &omap_mcbsp_dai[0],
-	.codec_dai = &twl4030_dai,
+	.codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
 	.ops = &omap3beagle_ops,
 };
 
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
new file mode 100644
index 0000000..9114c26
--- /dev/null
+++ b/sound/soc/omap/omap3evm.c
@@ -0,0 +1,147 @@
+/*
+ * omap3evm.c  -- ALSA SoC support for OMAP3 EVM
+ *
+ * Author: Anuj Aggarwal <anuj.aggarwal@ti.com>
+ *
+ * Based on sound/soc/omap/beagle.c by Steve Sakoman
+ *
+ * Copyright (C) 2008 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <mach/mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+#include "../codecs/twl4030.h"
+
+static int omap3evm_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->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret;
+
+	/* 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) {
+		printk(KERN_ERR "Can't set codec DAI configuration\n");
+		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) {
+		printk(KERN_ERR "Can't set cpu DAI configuration\n");
+		return ret;
+	}
+
+	/* Set the codec system clock for DAC and ADC */
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
+				     SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		printk(KERN_ERR "Can't set codec system clock\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops omap3evm_ops = {
+	.hw_params = omap3evm_hw_params,
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link omap3evm_dai = {
+	.name 		= "TWL4030",
+	.stream_name 	= "TWL4030",
+	.cpu_dai 	= &omap_mcbsp_dai[0],
+	.codec_dai 	= &twl4030_dai[TWL4030_DAI_HIFI],
+	.ops 		= &omap3evm_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_omap3evm = {
+	.name = "omap3evm",
+	.platform = &omap_soc_platform,
+	.dai_link = &omap3evm_dai,
+	.num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device omap3evm_snd_devdata = {
+	.card = &snd_soc_omap3evm,
+	.codec_dev = &soc_codec_dev_twl4030,
+};
+
+static struct platform_device *omap3evm_snd_device;
+
+static int __init omap3evm_soc_init(void)
+{
+	int ret;
+
+	if (!machine_is_omap3evm()) {
+		pr_err("Not OMAP3 EVM!\n");
+		return -ENODEV;
+	}
+	pr_info("OMAP3 EVM SoC init\n");
+
+	omap3evm_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!omap3evm_snd_device) {
+		printk(KERN_ERR "Platform device allocation failed\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(omap3evm_snd_device, &omap3evm_snd_devdata);
+	omap3evm_snd_devdata.dev = &omap3evm_snd_device->dev;
+	*(unsigned int *)omap3evm_dai.cpu_dai->private_data = 1;
+
+	ret = platform_device_add(omap3evm_snd_device);
+	if (ret)
+		goto err1;
+
+	return 0;
+
+err1:
+	printk(KERN_ERR "Unable to add platform device\n");
+	platform_device_put(omap3evm_snd_device);
+
+	return ret;
+}
+
+static void __exit omap3evm_soc_exit(void)
+{
+	platform_device_unregister(omap3evm_snd_device);
+}
+
+module_init(omap3evm_soc_init);
+module_exit(omap3evm_soc_exit);
+
+MODULE_AUTHOR("Anuj Aggarwal <anuj.aggarwal@ti.com>");
+MODULE_DESCRIPTION("ALSA SoC OMAP3 EVM");
+MODULE_LICENSE("GPLv2");
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index fe282d4..ad219aa 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -228,14 +228,14 @@
 		.name = "PCM1773",
 		.stream_name = "HiFi Out",
 		.cpu_dai = &omap_mcbsp_dai[0],
-		.codec_dai = &twl4030_dai,
+		.codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
 		.ops = &omap3pandora_out_ops,
 		.init = omap3pandora_out_init,
 	}, {
 		.name = "TWL4030",
 		.stream_name = "Line/Mic In",
 		.cpu_dai = &omap_mcbsp_dai[1],
-		.codec_dai = &twl4030_dai,
+		.codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
 		.ops = &omap3pandora_in_ops,
 		.init = omap3pandora_in_init,
 	}
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
index a72dc4e..ec4f8fd 100644
--- a/sound/soc/omap/overo.c
+++ b/sound/soc/omap/overo.c
@@ -83,7 +83,7 @@
 	.name = "TWL4030",
 	.stream_name = "TWL4030",
 	.cpu_dai = &omap_mcbsp_dai[0],
-	.codec_dai = &twl4030_dai,
+	.codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
 	.ops = &overo_ops,
 };
 
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 10f1c86..b719e5d 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -84,6 +84,49 @@
 	.hw_params = sdp3430_hw_params,
 };
 
+static int sdp3430_hw_voice_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->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret;
+
+	/* Set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai,
+				SND_SOC_DAIFMT_DSP_A |
+				SND_SOC_DAIFMT_IB_NF |
+				SND_SOC_DAIFMT_CBS_CFM);
+	if (ret) {
+		printk(KERN_ERR "can't set codec DAI configuration\n");
+		return ret;
+	}
+
+	/* Set cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai,
+				SND_SOC_DAIFMT_DSP_A |
+				SND_SOC_DAIFMT_IB_NF |
+				SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0) {
+		printk(KERN_ERR "can't set cpu DAI configuration\n");
+		return ret;
+	}
+
+	/* Set the codec system clock for DAC and ADC */
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
+					    SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		printk(KERN_ERR "can't set codec system clock\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops sdp3430_voice_ops = {
+	.hw_params = sdp3430_hw_voice_params,
+};
+
 /* Headset jack */
 static struct snd_soc_jack hs_jack;
 
@@ -192,28 +235,58 @@
 	return ret;
 }
 
+static int sdp3430_twl4030_voice_init(struct snd_soc_codec *codec)
+{
+	unsigned short reg;
+
+	/* Enable voice interface */
+	reg = codec->read(codec, TWL4030_REG_VOICE_IF);
+	reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
+	codec->write(codec, TWL4030_REG_VOICE_IF, reg);
+
+	return 0;
+}
+
+
 /* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link sdp3430_dai = {
-	.name = "TWL4030",
-	.stream_name = "TWL4030",
-	.cpu_dai = &omap_mcbsp_dai[0],
-	.codec_dai = &twl4030_dai,
-	.init = sdp3430_twl4030_init,
-	.ops = &sdp3430_ops,
+static struct snd_soc_dai_link sdp3430_dai[] = {
+	{
+		.name = "TWL4030 I2S",
+		.stream_name = "TWL4030 Audio",
+		.cpu_dai = &omap_mcbsp_dai[0],
+		.codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+		.init = sdp3430_twl4030_init,
+		.ops = &sdp3430_ops,
+	},
+	{
+		.name = "TWL4030 PCM",
+		.stream_name = "TWL4030 Voice",
+		.cpu_dai = &omap_mcbsp_dai[1],
+		.codec_dai = &twl4030_dai[TWL4030_DAI_VOICE],
+		.init = sdp3430_twl4030_voice_init,
+		.ops = &sdp3430_voice_ops,
+	},
 };
 
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_sdp3430 = {
 	.name = "SDP3430",
 	.platform = &omap_soc_platform,
-	.dai_link = &sdp3430_dai,
-	.num_links = 1,
+	.dai_link = sdp3430_dai,
+	.num_links = ARRAY_SIZE(sdp3430_dai),
+};
+
+/* twl4030 setup */
+static struct twl4030_setup_data twl4030_setup = {
+	.ramp_delay_value = 3,
+	.sysclk = 26000,
 };
 
 /* Audio subsystem */
 static struct snd_soc_device sdp3430_snd_devdata = {
 	.card = &snd_soc_sdp3430,
 	.codec_dev = &soc_codec_dev_twl4030,
+	.codec_data = &twl4030_setup,
 };
 
 static struct platform_device *sdp3430_snd_device;
@@ -236,7 +309,8 @@
 
 	platform_set_drvdata(sdp3430_snd_device, &sdp3430_snd_devdata);
 	sdp3430_snd_devdata.dev = &sdp3430_snd_device->dev;
-	*(unsigned int *)sdp3430_dai.cpu_dai->private_data = 1; /* McBSP2 */
+	*(unsigned int *)sdp3430_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
+	*(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
 
 	ret = platform_device_add(sdp3430_snd_device);
 	if (ret)
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index ad8a10f..6375b4e 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -89,22 +89,23 @@
 	  Toshiba e800 PDA
 
 config SND_PXA2XX_SOC_EM_X270
-	tristate "SoC Audio support for CompuLab EM-x270"
+	tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300"
 	depends on SND_PXA2XX_SOC && MACH_EM_X270
 	select SND_PXA2XX_SOC_AC97
 	select SND_SOC_WM9712
 	help
 	  Say Y if you want to add support for SoC audio on
-	  CompuLab EM-x270.
+	  CompuLab EM-x270, eXeda and CM-X300 machines.
 
 config SND_PXA2XX_SOC_PALM27X
-	bool "SoC Audio support for Palm T|X, T5 and LifeDrive"
-	depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || MACH_PALMT5)
+	bool "SoC Audio support for Palm T|X, T5, E2 and LifeDrive"
+	depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || \
+			MACH_PALMT5 || MACH_PALMTE2)
 	select SND_PXA2XX_SOC_AC97
 	select SND_SOC_WM9712
 	help
 	  Say Y if you want to add support for SoC audio on
-	  Palm T|X, T5 or LifeDrive handheld computer.
+	  Palm T|X, T5, E2 or LifeDrive handheld computer.
 
 config SND_SOC_ZYLONITE
 	tristate "SoC Audio support for Marvell Zylonite"
@@ -134,3 +135,12 @@
         help
           Say Y if you want to add support for SoC audio on the
           MIO A701.
+
+config SND_PXA2XX_SOC_IMOTE2
+       tristate "SoC Audio support for IMote 2"
+       depends on SND_PXA2XX_SOC && MACH_INTELMOTE2
+       select SND_PXA2XX_SOC_I2S
+       select SND_SOC_WM8940
+       help
+         Say Y if you want to add support for SoC audio on the
+	 IMote 2.
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index 4b90c3c..6e096b4 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -22,6 +22,7 @@
 snd-soc-zylonite-objs := zylonite.o
 snd-soc-magician-objs := magician.o
 snd-soc-mioa701-objs := mioa701_wm9713.o
+snd-soc-imote2-objs := imote2.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
 obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
@@ -35,3 +36,4 @@
 obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
 obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
+obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c
index 949be9c..f4756e4 100644
--- a/sound/soc/pxa/em-x270.c
+++ b/sound/soc/pxa/em-x270.c
@@ -1,7 +1,7 @@
 /*
- * em-x270.c  --  SoC audio for EM-X270
+ * SoC audio driver for EM-X270, eXeda and CM-X300
  *
- * Copyright 2007 CompuLab, Ltd.
+ * Copyright 2007, 2009 CompuLab, Ltd.
  *
  * Author: Mike Rapoport <mike@compulab.co.il>
  *
@@ -68,7 +68,8 @@
 {
 	int ret;
 
-	if (!machine_is_em_x270())
+	if (!(machine_is_em_x270() || machine_is_exeda()
+	      || machine_is_cm_x300()))
 		return -ENODEV;
 
 	em_x270_snd_device = platform_device_alloc("soc-audio", -1);
@@ -95,5 +96,5 @@
 
 /* Module information */
 MODULE_AUTHOR("Mike Rapoport");
-MODULE_DESCRIPTION("ALSA SoC EM-X270");
+MODULE_DESCRIPTION("ALSA SoC EM-X270, eXeda and CM-X300");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/imote2.c b/sound/soc/pxa/imote2.c
new file mode 100644
index 0000000..405587a
--- /dev/null
+++ b/sound/soc/pxa/imote2.c
@@ -0,0 +1,114 @@
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/wm8940.h"
+#include "pxa2xx-i2s.h"
+#include "pxa2xx-pcm.h"
+
+static int imote2_asoc_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->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int clk = 0;
+	int ret;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		clk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk = 11289600;
+		break;
+	}
+
+	/* set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
+				  | SND_SOC_DAIFMT_NB_NF
+				  | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* CPU should be clock master */
+	ret = snd_soc_dai_set_fmt(cpu_dai,  SND_SOC_DAIFMT_I2S
+				  | SND_SOC_DAIFMT_NB_NF
+				  | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
+				     SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as input (unused) */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, clk,
+		SND_SOC_CLOCK_OUT);
+
+	return ret;
+}
+
+static struct snd_soc_ops imote2_asoc_ops = {
+	.hw_params = imote2_asoc_hw_params,
+};
+
+static struct snd_soc_dai_link imote2_dai = {
+	.name = "WM8940",
+	.stream_name = "WM8940",
+	.cpu_dai = &pxa_i2s_dai,
+	.codec_dai = &wm8940_dai,
+	.ops = &imote2_asoc_ops,
+};
+
+static struct snd_soc_card snd_soc_imote2 = {
+	.name = "Imote2",
+	.platform = &pxa2xx_soc_platform,
+	.dai_link = &imote2_dai,
+	.num_links = 1,
+};
+
+static struct snd_soc_device imote2_snd_devdata = {
+	.card = &snd_soc_imote2,
+	.codec_dev = &soc_codec_dev_wm8940,
+};
+
+static struct platform_device *imote2_snd_device;
+
+static int __init imote2_asoc_init(void)
+{
+	int ret;
+
+	if (!machine_is_intelmote2())
+		return -ENODEV;
+	imote2_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!imote2_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(imote2_snd_device, &imote2_snd_devdata);
+	imote2_snd_devdata.dev = &imote2_snd_device->dev;
+	ret = platform_device_add(imote2_snd_device);
+	if (ret)
+		platform_device_put(imote2_snd_device);
+
+	return ret;
+}
+module_init(imote2_asoc_init);
+
+static void __exit imote2_asoc_exit(void)
+{
+	platform_device_unregister(imote2_snd_device);
+}
+module_exit(imote2_asoc_exit);
+
+MODULE_AUTHOR("Jonathan Cameron");
+MODULE_DESCRIPTION("ALSA SoC Imote 2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index 0625c34..c89a3cd 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -106,7 +106,7 @@
 			/* 513156 Hz ~= _2_ * 8000 Hz * 32 (+0.23%) */
 			acds = PXA_SSP_CLK_AUDIO_DIV_16;
 			break;
-		case 32:
+		default: /* 32 */
 			/* 1026312 Hz ~= _2_ * 8000 Hz * 64 (+0.23%) */
 			acds = PXA_SSP_CLK_AUDIO_DIV_8;
 		}
@@ -118,7 +118,7 @@
 			/* 351375 Hz ~= 11025 Hz * 32 (-0.41%) */
 			acds = PXA_SSP_CLK_AUDIO_DIV_4;
 			break;
-		case 32:
+		default: /* 32 */
 			/* 702750 Hz ~= 11025 Hz * 64 (-0.41%) */
 			acds = PXA_SSP_CLK_AUDIO_DIV_2;
 		}
@@ -130,7 +130,7 @@
 			/* 702750 Hz ~= 22050 Hz * 32 (-0.41%) */
 			acds = PXA_SSP_CLK_AUDIO_DIV_2;
 			break;
-		case 32:
+		default: /* 32 */
 			/* 1405500 Hz ~= 22050 Hz * 64 (-0.41%) */
 			acds = PXA_SSP_CLK_AUDIO_DIV_1;
 		}
@@ -142,7 +142,7 @@
 			/* 1405500 Hz ~= 44100 Hz * 32 (-0.41%) */
 			acds = PXA_SSP_CLK_AUDIO_DIV_2;
 			break;
-		case 32:
+		default: /* 32 */
 			/* 2811000 Hz ~= 44100 Hz * 64 (-0.41%) */
 			acds = PXA_SSP_CLK_AUDIO_DIV_1;
 		}
@@ -154,19 +154,20 @@
 			/* 1529375 Hz ~= 48000 Hz * 32 (-0.44%) */
 			acds = PXA_SSP_CLK_AUDIO_DIV_2;
 			break;
-		case 32:
+		default: /* 32 */
 			/* 3058750 Hz ~= 48000 Hz * 64 (-0.44%) */
 			acds = PXA_SSP_CLK_AUDIO_DIV_1;
 		}
 		break;
 	case 96000:
+	default:
 		acps = 12235000;
 		switch (width) {
 		case 16:
 			/* 3058750 Hz ~= 96000 Hz * 32 (-0.44%) */
 			acds = PXA_SSP_CLK_AUDIO_DIV_1;
 			break;
-		case 32:
+		default: /* 32 */
 			/* 6117500 Hz ~= 96000 Hz * 64 (-0.44%) */
 			acds = PXA_SSP_CLK_AUDIO_DIV_2;
 			div4 = PXA_SSP_CLK_SCDB_1;
diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c
index 44fcc4e..e6102fd 100644
--- a/sound/soc/pxa/palm27x.c
+++ b/sound/soc/pxa/palm27x.c
@@ -205,7 +205,7 @@
 	int ret;
 
 	if (!(machine_is_palmtx() || machine_is_palmt5() ||
-		machine_is_palmld()))
+		machine_is_palmld() || machine_is_palmte2()))
 		return -ENODEV;
 
 	if (pdev->dev.platform_data)
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 286be31..19c4540 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -50,139 +50,6 @@
 #endif
 };
 
-#define PXA2xx_SSP1_BASE	0x41000000
-#define PXA27x_SSP2_BASE	0x41700000
-#define PXA27x_SSP3_BASE	0x41900000
-#define PXA3xx_SSP4_BASE	0x41a00000
-
-static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_out = {
-	.name			= "SSP1 PCM Mono out",
-	.dev_addr		= PXA2xx_SSP1_BASE + SSDR,
-	.drcmr			= &DRCMR(14),
-	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
-				  DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_in = {
-	.name			= "SSP1 PCM Mono in",
-	.dev_addr		= PXA2xx_SSP1_BASE + SSDR,
-	.drcmr			= &DRCMR(13),
-	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
-				  DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_out = {
-	.name			= "SSP1 PCM Stereo out",
-	.dev_addr		= PXA2xx_SSP1_BASE + SSDR,
-	.drcmr			= &DRCMR(14),
-	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
-				  DCMD_BURST16 | DCMD_WIDTH4,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_in = {
-	.name			= "SSP1 PCM Stereo in",
-	.dev_addr		= PXA2xx_SSP1_BASE + SSDR,
-	.drcmr			= &DRCMR(13),
-	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
-				  DCMD_BURST16 | DCMD_WIDTH4,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_out = {
-	.name			= "SSP2 PCM Mono out",
-	.dev_addr		= PXA27x_SSP2_BASE + SSDR,
-	.drcmr			= &DRCMR(16),
-	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
-				  DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_in = {
-	.name			= "SSP2 PCM Mono in",
-	.dev_addr		= PXA27x_SSP2_BASE + SSDR,
-	.drcmr			= &DRCMR(15),
-	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
-				  DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_out = {
-	.name			= "SSP2 PCM Stereo out",
-	.dev_addr		= PXA27x_SSP2_BASE + SSDR,
-	.drcmr			= &DRCMR(16),
-	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
-				  DCMD_BURST16 | DCMD_WIDTH4,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_in = {
-	.name			= "SSP2 PCM Stereo in",
-	.dev_addr		= PXA27x_SSP2_BASE + SSDR,
-	.drcmr			= &DRCMR(15),
-	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
-				  DCMD_BURST16 | DCMD_WIDTH4,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_out = {
-	.name			= "SSP3 PCM Mono out",
-	.dev_addr		= PXA27x_SSP3_BASE + SSDR,
-	.drcmr			= &DRCMR(67),
-	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
-				  DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_in = {
-	.name			= "SSP3 PCM Mono in",
-	.dev_addr		= PXA27x_SSP3_BASE + SSDR,
-	.drcmr			= &DRCMR(66),
-	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
-				  DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_out = {
-	.name			= "SSP3 PCM Stereo out",
-	.dev_addr		= PXA27x_SSP3_BASE + SSDR,
-	.drcmr			= &DRCMR(67),
-	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
-				  DCMD_BURST16 | DCMD_WIDTH4,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_in = {
-	.name			= "SSP3 PCM Stereo in",
-	.dev_addr		= PXA27x_SSP3_BASE + SSDR,
-	.drcmr			= &DRCMR(66),
-	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
-				  DCMD_BURST16 | DCMD_WIDTH4,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_out = {
-	.name			= "SSP4 PCM Mono out",
-	.dev_addr		= PXA3xx_SSP4_BASE + SSDR,
-	.drcmr			= &DRCMR(67),
-	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
-				  DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_in = {
-	.name			= "SSP4 PCM Mono in",
-	.dev_addr		= PXA3xx_SSP4_BASE + SSDR,
-	.drcmr			= &DRCMR(66),
-	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
-				  DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_out = {
-	.name			= "SSP4 PCM Stereo out",
-	.dev_addr		= PXA3xx_SSP4_BASE + SSDR,
-	.drcmr			= &DRCMR(67),
-	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
-				  DCMD_BURST16 | DCMD_WIDTH4,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_in = {
-	.name			= "SSP4 PCM Stereo in",
-	.dev_addr		= PXA3xx_SSP4_BASE + SSDR,
-	.drcmr			= &DRCMR(66),
-	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
-				  DCMD_BURST16 | DCMD_WIDTH4,
-};
-
 static void dump_registers(struct ssp_device *ssp)
 {
 	dev_dbg(&ssp->pdev->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n",
@@ -194,25 +61,33 @@
 		 ssp_read_reg(ssp, SSACD));
 }
 
-static struct pxa2xx_pcm_dma_params *ssp_dma_params[4][4] = {
-	{
-		&pxa_ssp1_pcm_mono_out, &pxa_ssp1_pcm_mono_in,
-		&pxa_ssp1_pcm_stereo_out, &pxa_ssp1_pcm_stereo_in,
-	},
-	{
-		&pxa_ssp2_pcm_mono_out, &pxa_ssp2_pcm_mono_in,
-		&pxa_ssp2_pcm_stereo_out, &pxa_ssp2_pcm_stereo_in,
-	},
-	{
-		&pxa_ssp3_pcm_mono_out, &pxa_ssp3_pcm_mono_in,
-		&pxa_ssp3_pcm_stereo_out, &pxa_ssp3_pcm_stereo_in,
-	},
-	{
-		&pxa_ssp4_pcm_mono_out, &pxa_ssp4_pcm_mono_in,
-		&pxa_ssp4_pcm_stereo_out, &pxa_ssp4_pcm_stereo_in,
-	},
+struct pxa2xx_pcm_dma_data {
+	struct pxa2xx_pcm_dma_params params;
+	char name[20];
 };
 
+static struct pxa2xx_pcm_dma_params *
+ssp_get_dma_params(struct ssp_device *ssp, int width4, int out)
+{
+	struct pxa2xx_pcm_dma_data *dma;
+
+	dma = kzalloc(sizeof(struct pxa2xx_pcm_dma_data), GFP_KERNEL);
+	if (dma == NULL)
+		return NULL;
+
+	snprintf(dma->name, 20, "SSP%d PCM %s %s", ssp->port_id,
+			width4 ? "32-bit" : "16-bit", out ? "out" : "in");
+
+	dma->params.name = dma->name;
+	dma->params.drcmr = &DRCMR(out ? ssp->drcmr_tx : ssp->drcmr_rx);
+	dma->params.dcmd = (out ? (DCMD_INCSRCADDR | DCMD_FLOWTRG) :
+				  (DCMD_INCTRGADDR | DCMD_FLOWSRC)) |
+			(width4 ? DCMD_WIDTH4 : DCMD_WIDTH2) | DCMD_BURST16;
+	dma->params.dev_addr = ssp->phys_base + SSDR;
+
+	return &dma->params;
+}
+
 static int pxa_ssp_startup(struct snd_pcm_substream *substream,
 			   struct snd_soc_dai *dai)
 {
@@ -227,6 +102,11 @@
 		clk_enable(priv->dev.ssp->clk);
 		ssp_disable(&priv->dev);
 	}
+
+	if (cpu_dai->dma_data) {
+		kfree(cpu_dai->dma_data);
+		cpu_dai->dma_data = NULL;
+	}
 	return ret;
 }
 
@@ -241,6 +121,11 @@
 		ssp_disable(&priv->dev);
 		clk_disable(priv->dev.ssp->clk);
 	}
+
+	if (cpu_dai->dma_data) {
+		kfree(cpu_dai->dma_data);
+		cpu_dai->dma_data = NULL;
+	}
 }
 
 #ifdef CONFIG_PM
@@ -323,7 +208,7 @@
 		~(SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
 
 	dev_dbg(&ssp->pdev->dev,
-		"pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n",
+		"pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %u\n",
 		cpu_dai->id, clk_id, freq);
 
 	switch (clk_id) {
@@ -472,7 +357,7 @@
 			ssacd |= (0x6 << 4);
 
 			dev_dbg(&ssp->pdev->dev,
-				"Using SSACDD %x to supply %dHz\n",
+				"Using SSACDD %x to supply %uHz\n",
 				val, freq_out);
 			break;
 		}
@@ -589,7 +474,10 @@
 		case SND_SOC_DAIFMT_NB_IF:
 			break;
 		case SND_SOC_DAIFMT_IB_IF:
-			sspsp |= SSPSP_SCMODE(3);
+			sspsp |= SSPSP_SCMODE(2);
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP;
 			break;
 		default:
 			return -EINVAL;
@@ -606,7 +494,13 @@
 		case SND_SOC_DAIFMT_NB_NF:
 			sspsp |= SSPSP_SFRMP;
 			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			break;
 		case SND_SOC_DAIFMT_IB_IF:
+			sspsp |= SSPSP_SCMODE(2);
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP;
 			break;
 		default:
 			return -EINVAL;
@@ -644,25 +538,23 @@
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 	struct ssp_priv *priv = cpu_dai->private_data;
 	struct ssp_device *ssp = priv->dev.ssp;
-	int dma = 0, chn = params_channels(params);
+	int chn = params_channels(params);
 	u32 sscr0;
 	u32 sspsp;
 	int width = snd_pcm_format_physical_width(params_format(params));
 	int ttsa = ssp_read_reg(ssp, SSTSA) & 0xf;
 
-	/* select correct DMA params */
-	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
-		dma = 1; /* capture DMA offset is 1,3 */
+	/* generate correct DMA params */
+	if (cpu_dai->dma_data)
+		kfree(cpu_dai->dma_data);
+
 	/* Network mode with one active slot (ttsa == 1) can be used
 	 * to force 16-bit frame width on the wire (for S16_LE), even
 	 * with two channels. Use 16-bit DMA transfers for this case.
 	 */
-	if (((chn == 2) && (ttsa != 1)) || (width == 32))
-		dma += 2; /* 32-bit DMA offset is 2, 16-bit is 0 */
-
-	cpu_dai->dma_data = ssp_dma_params[cpu_dai->id][dma];
-
-	dev_dbg(&ssp->pdev->dev, "pxa_ssp_hw_params: dma %d\n", dma);
+	cpu_dai->dma_data = ssp_get_dma_params(ssp,
+			((chn == 2) && (ttsa != 1)) || (width == 32),
+			substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
 	/* we can only change the settings if the port is not in use */
 	if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 2f4b6e4..4743e26 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -106,10 +106,8 @@
 	if (IS_ERR(clk_i2s))
 		return PTR_ERR(clk_i2s);
 
-	if (!cpu_dai->active) {
-		SACR0 |= SACR0_RST;
+	if (!cpu_dai->active)
 		SACR0 = 0;
-	}
 
 	return 0;
 }
@@ -178,9 +176,7 @@
 
 	/* is port used by another stream */
 	if (!(SACR0 & SACR0_ENB)) {
-
 		SACR0 = 0;
-		SACR1 = 0;
 		if (pxa_i2s.master)
 			SACR0 |= SACR0_BCKD;
 
@@ -226,6 +222,10 @@
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			SACR1 &= ~SACR1_DRPL;
+		else
+			SACR1 &= ~SACR1_DREC;
 		SACR0 |= SACR0_ENB;
 		break;
 	case SNDRV_PCM_TRIGGER_RESUME:
@@ -252,21 +252,16 @@
 		SAIMR &= ~SAIMR_RFS;
 	}
 
-	if (SACR1 & (SACR1_DREC | SACR1_DRPL)) {
+	if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) {
 		SACR0 &= ~SACR0_ENB;
 		pxa_i2s_wait();
 		clk_disable(clk_i2s);
 	}
-
-	clk_put(clk_i2s);
 }
 
 #ifdef CONFIG_PM
 static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai)
 {
-	if (!dai->active)
-		return 0;
-
 	/* store registers */
 	pxa_i2s.sacr0 = SACR0;
 	pxa_i2s.sacr1 = SACR1;
@@ -281,16 +276,14 @@
 
 static int pxa2xx_i2s_resume(struct snd_soc_dai *dai)
 {
-	if (!dai->active)
-		return 0;
-
 	pxa_i2s_wait();
 
-	SACR0 = pxa_i2s.sacr0 &= ~SACR0_ENB;
+	SACR0 = pxa_i2s.sacr0 & ~SACR0_ENB;
 	SACR1 = pxa_i2s.sacr1;
 	SAIMR = pxa_i2s.saimr;
 	SADIV = pxa_i2s.sadiv;
-	SACR0 |= SACR0_ENB;
+
+	SACR0 = pxa_i2s.sacr0;
 
 	return 0;
 }
@@ -329,6 +322,7 @@
 		.rates = PXA2XX_I2S_RATES,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
 	.ops = &pxa_i2s_dai_ops,
+	.symmetric_rates = 1,
 };
 
 EXPORT_SYMBOL_GPL(pxa_i2s_dai);
@@ -346,6 +340,19 @@
 	if (ret != 0)
 		clk_put(clk_i2s);
 
+	/*
+	 * PXA Developer's Manual:
+	 * If SACR0[ENB] is toggled in the middle of a normal operation,
+	 * the SACR0[RST] bit must also be set and cleared to reset all
+	 * I2S controller registers.
+	 */
+	SACR0 = SACR0_RST;
+	SACR0 = 0;
+	/* Make sure RPL and REC are disabled */
+	SACR1 = SACR1_DRPL | SACR1_DREC;
+	/* Along with FIFO servicing */
+	SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
+
 	return ret;
 }
 
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 289fadf..906709e 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -345,9 +345,11 @@
 static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	int reg = kcontrol->private_value & 0xFF;
-	int shift = (kcontrol->private_value >> 8) & 0x0F;
-	int mask = (kcontrol->private_value >> 16) & 0xFF;
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	int reg = mc->reg;
+	int shift = mc->shift;
+	int mask = mc->max;
 
 	pr_debug("Entered %s\n", __func__);
 
@@ -358,9 +360,11 @@
 static int lm4857_set_reg(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	int reg = kcontrol->private_value & 0xFF;
-	int shift = (kcontrol->private_value >> 8) & 0x0F;
-	int mask = (kcontrol->private_value >> 16) & 0xFF;
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	int reg = mc->reg;
+	int shift = mc->shift;
+	int mask = mc->max;
 
 	if (((lm4857_regs[reg] >> shift) & mask) ==
 		ucontrol->value.integer.value[0])
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
index ab680aa..1a28317 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -37,6 +37,20 @@
 
 #include "s3c-i2s-v2.h"
 
+#undef S3C_IIS_V2_SUPPORTED
+
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
+#define S3C_IIS_V2_SUPPORTED
+#endif
+
+#ifdef CONFIG_PLAT_S3C64XX
+#define S3C_IIS_V2_SUPPORTED
+#endif
+
+#ifndef S3C_IIS_V2_SUPPORTED
+#error Unsupported CPU model
+#endif
+
 #define S3C2412_I2S_DEBUG_CON 0
 
 static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
@@ -75,7 +89,7 @@
 
 
 /* Turn on or off the transmission path. */
-void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
+static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
 {
 	void __iomem *regs = i2s->regs;
 	u32 fic, con, mod;
@@ -105,7 +119,9 @@
 			break;
 
 		default:
-			dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n");
+			dev_err(i2s->dev, "TXEN: Invalid MODE %x in IISMOD\n",
+				mod & S3C2412_IISMOD_MODE_MASK);
+			break;
 		}
 
 		writel(con, regs + S3C2412_IISCON);
@@ -132,7 +148,9 @@
 			break;
 
 		default:
-			dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n");
+			dev_err(i2s->dev, "TXDIS: Invalid MODE %x in IISMOD\n",
+				mod & S3C2412_IISMOD_MODE_MASK);
+			break;
 		}
 
 		writel(mod, regs + S3C2412_IISMOD);
@@ -143,9 +161,8 @@
 	dbg_showcon(__func__, con);
 	pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
 }
-EXPORT_SYMBOL_GPL(s3c2412_snd_txctrl);
 
-void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
+static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
 {
 	void __iomem *regs = i2s->regs;
 	u32 fic, con, mod;
@@ -175,7 +192,8 @@
 			break;
 
 		default:
-			dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
+			dev_err(i2s->dev, "RXEN: Invalid MODE %x in IISMOD\n",
+				mod & S3C2412_IISMOD_MODE_MASK);
 		}
 
 		writel(mod, regs + S3C2412_IISMOD);
@@ -199,7 +217,8 @@
 			break;
 
 		default:
-			dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
+			dev_err(i2s->dev, "RXDIS: Invalid MODE %x in IISMOD\n",
+				mod & S3C2412_IISMOD_MODE_MASK);
 		}
 
 		writel(con, regs + S3C2412_IISCON);
@@ -209,7 +228,6 @@
 	fic = readl(regs + S3C2412_IISFIC);
 	pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
 }
-EXPORT_SYMBOL_GPL(s3c2412_snd_rxctrl);
 
 /*
  * Wait for the LR signal to allow synchronisation to the L/R clock
@@ -266,7 +284,7 @@
  */
 #define IISMOD_MASTER_MASK (1 << 11)
 #define IISMOD_SLAVE (1 << 11)
-#define IISMOD_MASTER (0x0)
+#define IISMOD_MASTER (0 << 11)
 #endif
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -281,7 +299,7 @@
 		iismod |= IISMOD_MASTER;
 		break;
 	default:
-		pr_debug("unknwon master/slave format\n");
+		pr_err("unknwon master/slave format\n");
 		return -EINVAL;
 	}
 
@@ -298,7 +316,7 @@
 		iismod |= S3C2412_IISMOD_SDF_IIS;
 		break;
 	default:
-		pr_debug("Unknown data format\n");
+		pr_err("Unknown data format\n");
 		return -EINVAL;
 	}
 
@@ -327,6 +345,7 @@
 	iismod = readl(i2s->regs + S3C2412_IISMOD);
 	pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
 
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S8:
 		iismod |= S3C2412_IISMOD_8BIT;
@@ -335,6 +354,25 @@
 		iismod &= ~S3C2412_IISMOD_8BIT;
 		break;
 	}
+#endif
+
+#ifdef CONFIG_PLAT_S3C64XX
+	iismod &= ~0x606;
+	/* Sample size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		/* 8 bit sample, 16fs BCLK */
+		iismod |= 0x2004;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		/* 16 bit sample, 32fs BCLK */
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		/* 24 bit sample, 48fs BCLK */
+		iismod |= 0x4002;
+		break;
+	}
+#endif
 
 	writel(iismod, i2s->regs + S3C2412_IISMOD);
 	pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
@@ -489,6 +527,8 @@
 	unsigned int best_rate = 0;
 	unsigned int best_deviation = INT_MAX;
 
+	pr_debug("Input clock rate %ldHz\n", clkrate);
+
 	if (fstab == NULL)
 		fstab = iis_fs_tab;
 
@@ -507,7 +547,7 @@
 		actual = clkrate / (fsdiv * div);
 		deviation = actual - rate;
 
-		printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n",
+		printk(KERN_DEBUG "%ufs: div %u => result %u, deviation %d\n",
 		       fsdiv, div, actual, deviation);
 
 		deviation = abs(deviation);
@@ -523,7 +563,7 @@
 			break;
 	}
 
-	printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n",
+	printk(KERN_DEBUG "best: fs=%u, div=%u, rate=%u\n",
 	       best_fs, best_div, best_rate);
 
 	info->fs_div = best_fs;
@@ -539,12 +579,31 @@
 		    unsigned long base)
 {
 	struct device *dev = &pdev->dev;
+	unsigned int iismod;
 
 	i2s->dev = dev;
 
 	/* record our i2s structure for later use in the callbacks */
 	dai->private_data = i2s;
 
+	if (!base) {
+		struct resource *res = platform_get_resource(pdev,
+							     IORESOURCE_MEM,
+							     0);
+		if (!res) {
+			dev_err(dev, "Unable to get register resource\n");
+			return -ENXIO;
+		}
+
+		if (!request_mem_region(res->start, resource_size(res),
+					"s3c64xx-i2s-v4")) {
+			dev_err(dev, "Unable to request register region\n");
+			return -EBUSY;
+		}
+
+		base = res->start;
+	}
+
 	i2s->regs = ioremap(base, 0x100);
 	if (i2s->regs == NULL) {
 		dev_err(dev, "cannot ioremap registers\n");
@@ -560,12 +619,16 @@
 
 	clk_enable(i2s->iis_pclk);
 
+	/* Mark ourselves as in TXRX mode so we can run through our cleanup
+	 * process without warnings. */
+	iismod = readl(i2s->regs + S3C2412_IISMOD);
+	iismod |= S3C2412_IISMOD_MODE_TXRX;
+	writel(iismod, i2s->regs + S3C2412_IISMOD);
 	s3c2412_snd_txctrl(i2s, 0);
 	s3c2412_snd_rxctrl(i2s, 0);
 
 	return 0;
 }
-
 EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
 
 #ifdef CONFIG_PM
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
index b7e0b3f..a587ec4 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ b/sound/soc/s3c24xx/s3c2412-i2s.c
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 #include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/io.h>
@@ -120,7 +121,7 @@
 
 	s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk");
 	if (s3c2412_i2s.iis_cclk == NULL) {
-		pr_debug("failed to get i2sclk clock\n");
+		pr_err("failed to get i2sclk clock\n");
 		iounmap(s3c2412_i2s.regs);
 		return -ENODEV;
 	}
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
index 3698f70..3f03d5d 100644
--- a/sound/soc/s3c24xx/s3c2443-ac97.c
+++ b/sound/soc/s3c24xx/s3c2443-ac97.c
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 #include <linux/wait.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 #include <linux/clk.h>
 
 #include <sound/core.h>
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index cc06696..556e35f 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -21,6 +21,8 @@
 #include <linux/clk.h>
 #include <linux/jiffies.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
+
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c
index 169ddad..eecfa5e 100644
--- a/sound/soc/s3c24xx/s3c24xx-pcm.c
+++ b/sound/soc/s3c24xx/s3c24xx-pcm.c
@@ -218,24 +218,17 @@
 	 * sync to pclk, half-word transfers to the IIS-FIFO. */
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		s3c2410_dma_devconfig(prtd->params->channel,
-				S3C2410_DMASRC_MEM, S3C2410_DISRCC_INC |
-				S3C2410_DISRCC_APB, prtd->params->dma_addr);
-
-		s3c2410_dma_config(prtd->params->channel,
-				prtd->params->dma_size,
-				S3C2410_DCON_SYNC_PCLK |
-				S3C2410_DCON_HANDSHAKE);
+				      S3C2410_DMASRC_MEM,
+				      prtd->params->dma_addr);
 	} else {
-		s3c2410_dma_config(prtd->params->channel,
-				prtd->params->dma_size,
-				S3C2410_DCON_HANDSHAKE |
-				S3C2410_DCON_SYNC_PCLK);
-
 		s3c2410_dma_devconfig(prtd->params->channel,
-					S3C2410_DMASRC_HW, 0x3,
-					prtd->params->dma_addr);
+				      S3C2410_DMASRC_HW,
+				      prtd->params->dma_addr);
 	}
 
+	s3c2410_dma_config(prtd->params->channel,
+			   prtd->params->dma_size);
+
 	/* flush the DMA channel */
 	s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH);
 	prtd->dma_loaded = 0;
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
index 33c5de7..3c06c40 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -108,48 +108,19 @@
 	return 0;
 }
 
-
-unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *dai)
+struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai)
 {
 	struct s3c_i2sv2_info *i2s = to_info(dai);
 
-	return clk_get_rate(i2s->iis_cclk);
+	return i2s->iis_cclk;
 }
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clockrate);
+EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock);
 
 static int s3c64xx_i2s_probe(struct platform_device *pdev,
 			     struct snd_soc_dai *dai)
 {
-	struct device *dev = &pdev->dev;
-	struct s3c_i2sv2_info *i2s;
-	int ret;
-
-	dev_dbg(dev, "%s: probing dai %d\n", __func__, pdev->id);
-
-	if (pdev->id < 0 || pdev->id > ARRAY_SIZE(s3c64xx_i2s)) {
-		dev_err(dev, "id %d out of range\n", pdev->id);
-		return -EINVAL;
-	}
-
-	i2s = &s3c64xx_i2s[pdev->id];
-
-	ret = s3c_i2sv2_probe(pdev, dai, i2s,
-			      pdev->id ? S3C64XX_PA_IIS1 : S3C64XX_PA_IIS0);
-	if (ret)
-		return ret;
-
-	i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
-	i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
-
-	i2s->iis_cclk = clk_get(dev, "audio-bus");
-	if (IS_ERR(i2s->iis_cclk)) {
-		dev_err(dev, "failed to get audio-bus");
-		iounmap(i2s->regs);
-		return -ENODEV;
-	}
-
 	/* configure GPIO for i2s port */
-	switch (pdev->id) {
+	switch (dai->id) {
 	case 0:
 		s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK);
 		s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK);
@@ -175,41 +146,122 @@
 	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
 #define S3C64XX_I2S_FMTS \
-	(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE)
+	(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
+	 SNDRV_PCM_FMTBIT_S24_LE)
 
 static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = {
 	.set_sysclk	= s3c64xx_i2s_set_sysclk,	
 };
 
-struct snd_soc_dai s3c64xx_i2s_dai = {
-	.name		= "s3c64xx-i2s",
-	.id		= 0,
-	.probe		= s3c64xx_i2s_probe,
-	.playback = {
-		.channels_min	= 2,
-		.channels_max	= 2,
-		.rates		= S3C64XX_I2S_RATES,
-		.formats	= S3C64XX_I2S_FMTS,
+struct snd_soc_dai s3c64xx_i2s_dai[] = {
+	{
+		.name		= "s3c64xx-i2s",
+		.id		= 0,
+		.probe		= s3c64xx_i2s_probe,
+		.playback = {
+			.channels_min	= 2,
+			.channels_max	= 2,
+			.rates		= S3C64XX_I2S_RATES,
+			.formats	= S3C64XX_I2S_FMTS,
+		},
+		.capture = {
+			 .channels_min	= 2,
+			 .channels_max	= 2,
+			 .rates		= S3C64XX_I2S_RATES,
+			 .formats	= S3C64XX_I2S_FMTS,
+		 },
+		.ops = &s3c64xx_i2s_dai_ops,
+		.symmetric_rates = 1,
 	},
-	.capture = {
-		.channels_min	= 2,
-		.channels_max	= 2,
-		.rates		= S3C64XX_I2S_RATES,
-		.formats	= S3C64XX_I2S_FMTS,
+	{
+		.name		= "s3c64xx-i2s",
+		.id		= 1,
+		.probe		= s3c64xx_i2s_probe,
+		.playback = {
+			.channels_min	= 2,
+			.channels_max	= 2,
+			.rates		= S3C64XX_I2S_RATES,
+			.formats	= S3C64XX_I2S_FMTS,
+		},
+		.capture = {
+			 .channels_min	= 2,
+			 .channels_max	= 2,
+			 .rates		= S3C64XX_I2S_RATES,
+			 .formats	= S3C64XX_I2S_FMTS,
+		 },
+		.ops = &s3c64xx_i2s_dai_ops,
+		.symmetric_rates = 1,
 	},
-	.ops = &s3c64xx_i2s_dai_ops,
 };
 EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
 
+static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
+{
+	struct s3c_i2sv2_info *i2s;
+	struct snd_soc_dai *dai;
+	int ret;
+
+	if (pdev->id >= ARRAY_SIZE(s3c64xx_i2s)) {
+		dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
+		return -EINVAL;
+	}
+
+	i2s = &s3c64xx_i2s[pdev->id];
+	dai = &s3c64xx_i2s_dai[pdev->id];
+	dai->dev = &pdev->dev;
+
+	i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
+	i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
+
+	i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
+	if (IS_ERR(i2s->iis_cclk)) {
+		dev_err(&pdev->dev, "failed to get audio-bus\n");
+		ret = PTR_ERR(i2s->iis_cclk);
+		goto err;
+	}
+
+	ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
+	if (ret)
+		goto err_clk;
+
+	ret = s3c_i2sv2_register_dai(dai);
+	if (ret != 0)
+		goto err_i2sv2;
+
+	return 0;
+
+err_i2sv2:
+	/* Not implemented for I2Sv2 core yet */
+err_clk:
+	clk_put(i2s->iis_cclk);
+err:
+	return ret;
+}
+
+static __devexit int s3c64xx_iis_dev_remove(struct platform_device *pdev)
+{
+	dev_err(&pdev->dev, "Device removal not yet supported\n");
+	return 0;
+}
+
+static struct platform_driver s3c64xx_iis_driver = {
+	.probe  = s3c64xx_iis_dev_probe,
+	.remove = s3c64xx_iis_dev_remove,
+	.driver = {
+		.name = "s3c64xx-iis",
+		.owner = THIS_MODULE,
+	},
+};
+
 static int __init s3c64xx_i2s_init(void)
 {
-	return  s3c_i2sv2_register_dai(&s3c64xx_i2s_dai);
+	return platform_driver_register(&s3c64xx_iis_driver);
 }
 module_init(s3c64xx_i2s_init);
 
 static void __exit s3c64xx_i2s_exit(void)
 {
-	snd_soc_unregister_dai(&s3c64xx_i2s_dai);
+	platform_driver_unregister(&s3c64xx_iis_driver);
 }
 module_exit(s3c64xx_i2s_exit);
 
@@ -217,6 +269,3 @@
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("S3C64XX I2S SoC Interface");
 MODULE_LICENSE("GPL");
-
-
-
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h
index b7ffe3c..02148ce 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.h
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.h
@@ -15,6 +15,8 @@
 #ifndef __SND_SOC_S3C24XX_S3C64XX_I2S_H
 #define __SND_SOC_S3C24XX_S3C64XX_I2S_H __FILE__
 
+struct clk;
+
 #include "s3c-i2s-v2.h"
 
 #define S3C64XX_DIV_BCLK	S3C_I2SV2_DIV_BCLK
@@ -24,8 +26,8 @@
 #define S3C64XX_CLKSRC_PCLK	(0)
 #define S3C64XX_CLKSRC_MUX	(1)
 
-extern struct snd_soc_dai s3c64xx_i2s_dai;
+extern struct snd_soc_dai s3c64xx_i2s_dai[];
 
-extern unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *cpu_dai);
+extern struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai);
 
 #endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */
diff --git a/sound/soc/s6000/Kconfig b/sound/soc/s6000/Kconfig
new file mode 100644
index 0000000..c74eb3d
--- /dev/null
+++ b/sound/soc/s6000/Kconfig
@@ -0,0 +1,19 @@
+config SND_S6000_SOC
+	tristate "SoC Audio for the Stretch s6000 family"
+	depends on XTENSA_VARIANT_S6000
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  s6000 family chips. You will also need to select the platform
+	  to support below.
+
+config SND_S6000_SOC_I2S
+	tristate
+
+config SND_S6000_SOC_S6IPCAM
+	tristate "SoC Audio support for Stretch 6105 IP Camera"
+	depends on SND_S6000_SOC && XTENSA_PLATFORM_S6105
+	select SND_S6000_SOC_I2S
+	select SND_SOC_TLV320AIC3X
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  Stretch s6105 IP Camera Reference Design.
diff --git a/sound/soc/s6000/Makefile b/sound/soc/s6000/Makefile
new file mode 100644
index 0000000..7a61361
--- /dev/null
+++ b/sound/soc/s6000/Makefile
@@ -0,0 +1,11 @@
+# s6000 Platform Support
+snd-soc-s6000-objs := s6000-pcm.o
+snd-soc-s6000-i2s-objs := s6000-i2s.o
+
+obj-$(CONFIG_SND_S6000_SOC) += snd-soc-s6000.o
+obj-$(CONFIG_SND_S6000_SOC_I2S) += snd-soc-s6000-i2s.o
+
+# s6105 Machine Support
+snd-soc-s6ipcam-objs := s6105-ipcam.o
+
+obj-$(CONFIG_SND_S6000_SOC_S6IPCAM) += snd-soc-s6ipcam.o
diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c
new file mode 100644
index 0000000..c5cda18
--- /dev/null
+++ b/sound/soc/s6000/s6000-i2s.c
@@ -0,0 +1,629 @@
+/*
+ * ALSA SoC I2S Audio Layer for the Stretch S6000 family
+ *
+ * Author:      Daniel Gloeckner, <dg@emlix.com>
+ * Copyright:   (C) 2009 emlix GmbH <info@emlix.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/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "s6000-i2s.h"
+#include "s6000-pcm.h"
+
+struct s6000_i2s_dev {
+	dma_addr_t sifbase;
+	u8 __iomem *scbbase;
+	unsigned int wide;
+	unsigned int channel_in;
+	unsigned int channel_out;
+	unsigned int lines_in;
+	unsigned int lines_out;
+	struct s6000_pcm_dma_params dma_params;
+};
+
+#define S6_I2S_INTERRUPT_STATUS	0x00
+#define   S6_I2S_INT_OVERRUN	1
+#define   S6_I2S_INT_UNDERRUN	2
+#define   S6_I2S_INT_ALIGNMENT	4
+#define S6_I2S_INTERRUPT_ENABLE	0x04
+#define S6_I2S_INTERRUPT_RAW	0x08
+#define S6_I2S_INTERRUPT_CLEAR	0x0C
+#define S6_I2S_INTERRUPT_SET	0x10
+#define S6_I2S_MODE		0x20
+#define   S6_I2S_DUAL		0
+#define   S6_I2S_WIDE		1
+#define S6_I2S_TX_DEFAULT	0x24
+#define S6_I2S_DATA_CFG(c)	(0x40 + 0x10 * (c))
+#define   S6_I2S_IN		0
+#define   S6_I2S_OUT		1
+#define   S6_I2S_UNUSED		2
+#define S6_I2S_INTERFACE_CFG(c)	(0x44 + 0x10 * (c))
+#define   S6_I2S_DIV_MASK	0x001fff
+#define   S6_I2S_16BIT		0x000000
+#define   S6_I2S_20BIT		0x002000
+#define   S6_I2S_24BIT		0x004000
+#define   S6_I2S_32BIT		0x006000
+#define   S6_I2S_BITS_MASK	0x006000
+#define   S6_I2S_MEM_16BIT	0x000000
+#define   S6_I2S_MEM_32BIT	0x008000
+#define   S6_I2S_MEM_MASK	0x008000
+#define   S6_I2S_CHANNELS_SHIFT	16
+#define   S6_I2S_CHANNELS_MASK	0x030000
+#define   S6_I2S_SCK_IN		0x000000
+#define   S6_I2S_SCK_OUT	0x040000
+#define   S6_I2S_SCK_DIR	0x040000
+#define   S6_I2S_WS_IN		0x000000
+#define   S6_I2S_WS_OUT		0x080000
+#define   S6_I2S_WS_DIR		0x080000
+#define   S6_I2S_LEFT_FIRST	0x000000
+#define   S6_I2S_RIGHT_FIRST	0x100000
+#define   S6_I2S_FIRST		0x100000
+#define   S6_I2S_CUR_SCK	0x200000
+#define   S6_I2S_CUR_WS		0x400000
+#define S6_I2S_ENABLE(c)	(0x48 + 0x10 * (c))
+#define   S6_I2S_DISABLE_IF	0x02
+#define   S6_I2S_ENABLE_IF	0x03
+#define   S6_I2S_IS_BUSY	0x04
+#define   S6_I2S_DMA_ACTIVE	0x08
+#define   S6_I2S_IS_ENABLED	0x10
+
+#define S6_I2S_NUM_LINES	4
+
+#define S6_I2S_SIF_PORT0	0x0000000
+#define S6_I2S_SIF_PORT1	0x0000080 /* docs say 0x0000010 */
+
+static inline void s6_i2s_write_reg(struct s6000_i2s_dev *dev, int reg, u32 val)
+{
+	writel(val, dev->scbbase + reg);
+}
+
+static inline u32 s6_i2s_read_reg(struct s6000_i2s_dev *dev, int reg)
+{
+	return readl(dev->scbbase + reg);
+}
+
+static inline void s6_i2s_mod_reg(struct s6000_i2s_dev *dev, int reg,
+				  u32 mask, u32 val)
+{
+	val ^= s6_i2s_read_reg(dev, reg) & ~mask;
+	s6_i2s_write_reg(dev, reg, val);
+}
+
+static void s6000_i2s_start_channel(struct s6000_i2s_dev *dev, int channel)
+{
+	int i, j, cur, prev;
+
+	/*
+	 * Wait for WCLK to toggle 5 times before enabling the channel
+	 * s6000 Family Datasheet 3.6.4:
+	 *   "At least two cycles of WS must occur between commands
+	 *    to disable or enable the interface"
+	 */
+	j = 0;
+	prev = ~S6_I2S_CUR_WS;
+	for (i = 1000000; --i && j < 6; ) {
+		cur = s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(channel))
+		       & S6_I2S_CUR_WS;
+		if (prev != cur) {
+			prev = cur;
+			j++;
+		}
+	}
+	if (j < 6)
+		printk(KERN_WARNING "s6000-i2s: timeout waiting for WCLK\n");
+
+	s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_ENABLE_IF);
+}
+
+static void s6000_i2s_stop_channel(struct s6000_i2s_dev *dev, int channel)
+{
+	s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_DISABLE_IF);
+}
+
+static void s6000_i2s_start(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data;
+	int channel;
+
+	channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+			dev->channel_out : dev->channel_in;
+
+	s6000_i2s_start_channel(dev, channel);
+}
+
+static void s6000_i2s_stop(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data;
+	int channel;
+
+	channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+			dev->channel_out : dev->channel_in;
+
+	s6000_i2s_stop_channel(dev, channel);
+}
+
+static int s6000_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			     int after)
+{
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ^ !after)
+			s6000_i2s_start(substream);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (!after)
+			s6000_i2s_stop(substream);
+	}
+	return 0;
+}
+
+static unsigned int s6000_i2s_int_sources(struct s6000_i2s_dev *dev)
+{
+	unsigned int pending;
+	pending = s6_i2s_read_reg(dev, S6_I2S_INTERRUPT_RAW);
+	pending &= S6_I2S_INT_ALIGNMENT |
+		   S6_I2S_INT_UNDERRUN |
+		   S6_I2S_INT_OVERRUN;
+	s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR, pending);
+
+	return pending;
+}
+
+static unsigned int s6000_i2s_check_xrun(struct snd_soc_dai *cpu_dai)
+{
+	struct s6000_i2s_dev *dev = cpu_dai->private_data;
+	unsigned int errors;
+	unsigned int ret;
+
+	errors = s6000_i2s_int_sources(dev);
+	if (likely(!errors))
+		return 0;
+
+	ret = 0;
+	if (errors & S6_I2S_INT_ALIGNMENT)
+		printk(KERN_ERR "s6000-i2s: WCLK misaligned\n");
+	if (errors & S6_I2S_INT_UNDERRUN)
+		ret |= 1 << SNDRV_PCM_STREAM_PLAYBACK;
+	if (errors & S6_I2S_INT_OVERRUN)
+		ret |= 1 << SNDRV_PCM_STREAM_CAPTURE;
+	return ret;
+}
+
+static void s6000_i2s_wait_disabled(struct s6000_i2s_dev *dev)
+{
+	int channel;
+	int n = 50;
+	for (channel = 0; channel < 2; channel++) {
+		while (--n >= 0) {
+			int v = s6_i2s_read_reg(dev, S6_I2S_ENABLE(channel));
+			if ((v & S6_I2S_IS_ENABLED)
+			    || !(v & (S6_I2S_DMA_ACTIVE | S6_I2S_IS_BUSY)))
+				break;
+			udelay(20);
+		}
+	}
+	if (n < 0)
+		printk(KERN_WARNING "s6000-i2s: timeout disabling interfaces");
+}
+
+static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+				   unsigned int fmt)
+{
+	struct s6000_i2s_dev *dev = cpu_dai->private_data;
+	u32 w;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		w = S6_I2S_SCK_IN | S6_I2S_WS_IN;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		w = S6_I2S_SCK_OUT | S6_I2S_WS_IN;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		w = S6_I2S_SCK_IN | S6_I2S_WS_OUT;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		w = S6_I2S_SCK_OUT | S6_I2S_WS_OUT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		w |= S6_I2S_LEFT_FIRST;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		w |= S6_I2S_RIGHT_FIRST;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(0),
+		       S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w);
+	s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(1),
+		       S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w);
+
+	return 0;
+}
+
+static int s6000_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
+{
+	struct s6000_i2s_dev *dev = dai->private_data;
+
+	if (!div || (div & 1) || div > (S6_I2S_DIV_MASK + 1) * 2)
+		return -EINVAL;
+
+	s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(div_id),
+		       S6_I2S_DIV_MASK, div / 2 - 1);
+	return 0;
+}
+
+static int s6000_i2s_hw_params(struct snd_pcm_substream *substream,
+			       struct snd_pcm_hw_params *params,
+			       struct snd_soc_dai *dai)
+{
+	struct s6000_i2s_dev *dev = dai->private_data;
+	int interf;
+	u32 w = 0;
+
+	if (dev->wide)
+		interf = 0;
+	else {
+		w |= (((params_channels(params) - 2) / 2)
+		      << S6_I2S_CHANNELS_SHIFT) & S6_I2S_CHANNELS_MASK;
+		interf = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+				? dev->channel_out : dev->channel_in;
+	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		w |= S6_I2S_16BIT | S6_I2S_MEM_16BIT;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		w |= S6_I2S_32BIT | S6_I2S_MEM_32BIT;
+		break;
+	default:
+		printk(KERN_WARNING "s6000-i2s: unsupported PCM format %x\n",
+		       params_format(params));
+		return -EINVAL;
+	}
+
+	if (s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(interf))
+	     & S6_I2S_IS_ENABLED) {
+		printk(KERN_ERR "s6000-i2s: interface already enabled\n");
+		return -EBUSY;
+	}
+
+	s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(interf),
+		       S6_I2S_CHANNELS_MASK|S6_I2S_MEM_MASK|S6_I2S_BITS_MASK,
+		       w);
+
+	return 0;
+}
+
+static int s6000_i2s_dai_probe(struct platform_device *pdev,
+			       struct snd_soc_dai *dai)
+{
+	struct s6000_i2s_dev *dev = dai->private_data;
+	struct s6000_snd_platform_data *pdata = pdev->dev.platform_data;
+
+	if (!pdata)
+		return -EINVAL;
+
+	dev->wide = pdata->wide;
+	dev->channel_in = pdata->channel_in;
+	dev->channel_out = pdata->channel_out;
+	dev->lines_in = pdata->lines_in;
+	dev->lines_out = pdata->lines_out;
+
+	s6_i2s_write_reg(dev, S6_I2S_MODE,
+			 dev->wide ? S6_I2S_WIDE : S6_I2S_DUAL);
+
+	if (dev->wide) {
+		int i;
+
+		if (dev->lines_in + dev->lines_out > S6_I2S_NUM_LINES)
+			return -EINVAL;
+
+		dev->channel_in = 0;
+		dev->channel_out = 1;
+		dai->capture.channels_min = 2 * dev->lines_in;
+		dai->capture.channels_max = dai->capture.channels_min;
+		dai->playback.channels_min = 2 * dev->lines_out;
+		dai->playback.channels_max = dai->playback.channels_min;
+
+		for (i = 0; i < dev->lines_out; i++)
+			s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_OUT);
+
+		for (; i < S6_I2S_NUM_LINES - dev->lines_in; i++)
+			s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i),
+					 S6_I2S_UNUSED);
+
+		for (; i < S6_I2S_NUM_LINES; i++)
+			s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_IN);
+	} else {
+		unsigned int cfg[2] = {S6_I2S_UNUSED, S6_I2S_UNUSED};
+
+		if (dev->lines_in > 1 || dev->lines_out > 1)
+			return -EINVAL;
+
+		dai->capture.channels_min = 2 * dev->lines_in;
+		dai->capture.channels_max = 8 * dev->lines_in;
+		dai->playback.channels_min = 2 * dev->lines_out;
+		dai->playback.channels_max = 8 * dev->lines_out;
+
+		if (dev->lines_in)
+			cfg[dev->channel_in] = S6_I2S_IN;
+		if (dev->lines_out)
+			cfg[dev->channel_out] = S6_I2S_OUT;
+
+		s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(0), cfg[0]);
+		s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(1), cfg[1]);
+	}
+
+	if (dev->lines_out) {
+		if (dev->lines_in) {
+			if (!dev->dma_params.dma_out)
+				return -ENODEV;
+		} else {
+			dev->dma_params.dma_out = dev->dma_params.dma_in;
+			dev->dma_params.dma_in = 0;
+		}
+	}
+	dev->dma_params.sif_in = dev->sifbase + (dev->channel_in ?
+					S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0);
+	dev->dma_params.sif_out = dev->sifbase + (dev->channel_out ?
+					S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0);
+	dev->dma_params.same_rate = pdata->same_rate | pdata->wide;
+	return 0;
+}
+
+#define S6000_I2S_RATES	(SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_5512 | \
+			 SNDRV_PCM_RATE_8000_192000)
+#define S6000_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops s6000_i2s_dai_ops = {
+	.set_fmt = s6000_i2s_set_dai_fmt,
+	.set_clkdiv = s6000_i2s_set_clkdiv,
+	.hw_params = s6000_i2s_hw_params,
+};
+
+struct snd_soc_dai s6000_i2s_dai = {
+	.name = "s6000-i2s",
+	.id = 0,
+	.probe = s6000_i2s_dai_probe,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 8,
+		.formats = S6000_I2S_FORMATS,
+		.rates = S6000_I2S_RATES,
+		.rate_min = 0,
+		.rate_max = 1562500,
+	},
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 8,
+		.formats = S6000_I2S_FORMATS,
+		.rates = S6000_I2S_RATES,
+		.rate_min = 0,
+		.rate_max = 1562500,
+	},
+	.ops = &s6000_i2s_dai_ops,
+}
+EXPORT_SYMBOL_GPL(s6000_i2s_dai);
+
+static int __devinit s6000_i2s_probe(struct platform_device *pdev)
+{
+	struct s6000_i2s_dev *dev;
+	struct resource *scbmem, *sifmem, *region, *dma1, *dma2;
+	u8 __iomem *mmio;
+	int ret;
+
+	scbmem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!scbmem) {
+		dev_err(&pdev->dev, "no mem resource?\n");
+		ret = -ENODEV;
+		goto err_release_none;
+	}
+
+	region = request_mem_region(scbmem->start,
+				    scbmem->end - scbmem->start + 1,
+				    pdev->name);
+	if (!region) {
+		dev_err(&pdev->dev, "I2S SCB region already claimed\n");
+		ret = -EBUSY;
+		goto err_release_none;
+	}
+
+	mmio = ioremap(scbmem->start, scbmem->end - scbmem->start + 1);
+	if (!mmio) {
+		dev_err(&pdev->dev, "can't ioremap SCB region\n");
+		ret = -ENOMEM;
+		goto err_release_scb;
+	}
+
+	sifmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!sifmem) {
+		dev_err(&pdev->dev, "no second mem resource?\n");
+		ret = -ENODEV;
+		goto err_release_map;
+	}
+
+	region = request_mem_region(sifmem->start,
+				    sifmem->end - sifmem->start + 1,
+				    pdev->name);
+	if (!region) {
+		dev_err(&pdev->dev, "I2S SIF region already claimed\n");
+		ret = -EBUSY;
+		goto err_release_map;
+	}
+
+	dma1 = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!dma1) {
+		dev_err(&pdev->dev, "no dma resource?\n");
+		ret = -ENODEV;
+		goto err_release_sif;
+	}
+
+	region = request_mem_region(dma1->start, dma1->end - dma1->start + 1,
+				    pdev->name);
+	if (!region) {
+		dev_err(&pdev->dev, "I2S DMA region already claimed\n");
+		ret = -EBUSY;
+		goto err_release_sif;
+	}
+
+	dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+	if (dma2) {
+		region = request_mem_region(dma2->start,
+					    dma2->end - dma2->start + 1,
+					    pdev->name);
+		if (!region) {
+			dev_err(&pdev->dev,
+				"I2S DMA region already claimed\n");
+			ret = -EBUSY;
+			goto err_release_dma1;
+		}
+	}
+
+	dev = kzalloc(sizeof(struct s6000_i2s_dev), GFP_KERNEL);
+	if (!dev) {
+		ret = -ENOMEM;
+		goto err_release_dma2;
+	}
+
+	s6000_i2s_dai.dev = &pdev->dev;
+	s6000_i2s_dai.private_data = dev;
+	s6000_i2s_dai.dma_data = &dev->dma_params;
+
+	dev->sifbase = sifmem->start;
+	dev->scbbase = mmio;
+
+	s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0);
+	s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR,
+			 S6_I2S_INT_ALIGNMENT |
+			 S6_I2S_INT_UNDERRUN |
+			 S6_I2S_INT_OVERRUN);
+
+	s6000_i2s_stop_channel(dev, 0);
+	s6000_i2s_stop_channel(dev, 1);
+	s6000_i2s_wait_disabled(dev);
+
+	dev->dma_params.check_xrun = s6000_i2s_check_xrun;
+	dev->dma_params.trigger = s6000_i2s_trigger;
+	dev->dma_params.dma_in = dma1->start;
+	dev->dma_params.dma_out = dma2 ? dma2->start : 0;
+	dev->dma_params.irq = platform_get_irq(pdev, 0);
+	if (dev->dma_params.irq < 0) {
+		dev_err(&pdev->dev, "no irq resource?\n");
+		ret = -ENODEV;
+		goto err_release_dev;
+	}
+
+	s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE,
+			 S6_I2S_INT_ALIGNMENT |
+			 S6_I2S_INT_UNDERRUN |
+			 S6_I2S_INT_OVERRUN);
+
+	ret = snd_soc_register_dai(&s6000_i2s_dai);
+	if (ret)
+		goto err_release_dev;
+
+	return 0;
+
+err_release_dev:
+	kfree(dev);
+err_release_dma2:
+	if (dma2)
+		release_mem_region(dma2->start, dma2->end - dma2->start + 1);
+err_release_dma1:
+	release_mem_region(dma1->start, dma1->end - dma1->start + 1);
+err_release_sif:
+	release_mem_region(sifmem->start, (sifmem->end - sifmem->start) + 1);
+err_release_map:
+	iounmap(mmio);
+err_release_scb:
+	release_mem_region(scbmem->start, (scbmem->end - scbmem->start) + 1);
+err_release_none:
+	return ret;
+}
+
+static void __devexit s6000_i2s_remove(struct platform_device *pdev)
+{
+	struct s6000_i2s_dev *dev = s6000_i2s_dai.private_data;
+	struct resource *region;
+	void __iomem *mmio = dev->scbbase;
+
+	snd_soc_unregister_dai(&s6000_i2s_dai);
+
+	s6000_i2s_stop_channel(dev, 0);
+	s6000_i2s_stop_channel(dev, 1);
+
+	s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0);
+	s6000_i2s_dai.private_data = 0;
+	kfree(dev);
+
+	region = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	release_mem_region(region->start, region->end - region->start + 1);
+
+	region = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+	if (region)
+		release_mem_region(region->start,
+				   region->end - region->start + 1);
+
+	region = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(region->start, (region->end - region->start) + 1);
+
+	iounmap(mmio);
+	region = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	release_mem_region(region->start, (region->end - region->start) + 1);
+}
+
+static struct platform_driver s6000_i2s_driver = {
+	.probe  = s6000_i2s_probe,
+	.remove = __devexit_p(s6000_i2s_remove),
+	.driver = {
+		.name   = "s6000-i2s",
+		.owner  = THIS_MODULE,
+	},
+};
+
+static int __init s6000_i2s_init(void)
+{
+	return platform_driver_register(&s6000_i2s_driver);
+}
+module_init(s6000_i2s_init);
+
+static void __exit s6000_i2s_exit(void)
+{
+	platform_driver_unregister(&s6000_i2s_driver);
+}
+module_exit(s6000_i2s_exit);
+
+MODULE_AUTHOR("Daniel Gloeckner");
+MODULE_DESCRIPTION("Stretch s6000 family I2S SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s6000/s6000-i2s.h b/sound/soc/s6000/s6000-i2s.h
new file mode 100644
index 0000000..2375fdf
--- /dev/null
+++ b/sound/soc/s6000/s6000-i2s.h
@@ -0,0 +1,25 @@
+/*
+ * ALSA SoC I2S Audio Layer for the Stretch s6000 family
+ *
+ * Author:      Daniel Gloeckner, <dg@emlix.com>
+ * Copyright:   (C) 2009 emlix GmbH <info@emlix.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 _S6000_I2S_H
+#define _S6000_I2S_H
+
+extern struct snd_soc_dai s6000_i2s_dai;
+
+struct s6000_snd_platform_data {
+	int lines_in;
+	int lines_out;
+	int channel_in;
+	int channel_out;
+	int wide;
+	int same_rate;
+};
+#endif
diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c
new file mode 100644
index 0000000..83b8028
--- /dev/null
+++ b/sound/soc/s6000/s6000-pcm.c
@@ -0,0 +1,497 @@
+/*
+ * ALSA PCM interface for the Stetch s6000 family
+ *
+ * Author:      Daniel Gloeckner, <dg@emlix.com>
+ * Copyright:   (C) 2009 emlix GmbH <info@emlix.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/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+#include <variant/dmac.h>
+
+#include "s6000-pcm.h"
+
+#define S6_PCM_PREALLOCATE_SIZE (96 * 1024)
+#define S6_PCM_PREALLOCATE_MAX  (2048 * 1024)
+
+static struct snd_pcm_hardware s6000_pcm_hardware = {
+	.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+		 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_JOINT_DUPLEX),
+	.formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE),
+	.rates = (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_5512 | \
+		  SNDRV_PCM_RATE_8000_192000),
+	.rate_min = 0,
+	.rate_max = 1562500,
+	.channels_min = 2,
+	.channels_max = 8,
+	.buffer_bytes_max = 0x7ffffff0,
+	.period_bytes_min = 16,
+	.period_bytes_max = 0xfffff0,
+	.periods_min = 2,
+	.periods_max = 1024, /* no limit */
+	.fifo_size = 0,
+};
+
+struct s6000_runtime_data {
+	spinlock_t lock;
+	int period;		/* current DMA period */
+};
+
+static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct s6000_runtime_data *prtd = runtime->private_data;
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+	int channel;
+	unsigned int period_size;
+	unsigned int dma_offset;
+	dma_addr_t dma_pos;
+	dma_addr_t src, dst;
+
+	period_size = snd_pcm_lib_period_bytes(substream);
+	dma_offset = prtd->period * period_size;
+	dma_pos = runtime->dma_addr + dma_offset;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		src = dma_pos;
+		dst = par->sif_out;
+		channel = par->dma_out;
+	} else {
+		src = par->sif_in;
+		dst = dma_pos;
+		channel = par->dma_in;
+	}
+
+	if (!s6dmac_channel_enabled(DMA_MASK_DMAC(channel),
+				    DMA_INDEX_CHNL(channel)))
+		return;
+
+	if (s6dmac_fifo_full(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel))) {
+		printk(KERN_ERR "s6000-pcm: fifo full\n");
+		return;
+	}
+
+	BUG_ON(period_size & 15);
+	s6dmac_put_fifo(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel),
+			src, dst, period_size);
+
+	prtd->period++;
+	if (unlikely(prtd->period >= runtime->periods))
+		prtd->period = 0;
+}
+
+static irqreturn_t s6000_pcm_irq(int irq, void *data)
+{
+	struct snd_pcm *pcm = data;
+	struct snd_soc_pcm_runtime *runtime = pcm->private_data;
+	struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data;
+	struct s6000_runtime_data *prtd;
+	unsigned int has_xrun;
+	int i, ret = IRQ_NONE;
+	u32 channel[2] = {
+		[SNDRV_PCM_STREAM_PLAYBACK] = params->dma_out,
+		[SNDRV_PCM_STREAM_CAPTURE] = params->dma_in
+	};
+
+	has_xrun = params->check_xrun(runtime->dai->cpu_dai);
+
+	for (i = 0; i < ARRAY_SIZE(channel); ++i) {
+		struct snd_pcm_substream *substream = pcm->streams[i].substream;
+		unsigned int pending;
+
+		if (!channel[i])
+			continue;
+
+		if (unlikely(has_xrun & (1 << i)) &&
+		    substream->runtime &&
+		    snd_pcm_running(substream)) {
+			dev_dbg(pcm->dev, "xrun\n");
+			snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+			ret = IRQ_HANDLED;
+		}
+
+		pending = s6dmac_int_sources(DMA_MASK_DMAC(channel[i]),
+					     DMA_INDEX_CHNL(channel[i]));
+
+		if (pending & 1) {
+			ret = IRQ_HANDLED;
+			if (likely(substream->runtime &&
+				   snd_pcm_running(substream))) {
+				snd_pcm_period_elapsed(substream);
+				dev_dbg(pcm->dev, "period elapsed %x %x\n",
+				       s6dmac_cur_src(DMA_MASK_DMAC(channel[i]),
+						   DMA_INDEX_CHNL(channel[i])),
+				       s6dmac_cur_dst(DMA_MASK_DMAC(channel[i]),
+						   DMA_INDEX_CHNL(channel[i])));
+				prtd = substream->runtime->private_data;
+				spin_lock(&prtd->lock);
+				s6000_pcm_enqueue_dma(substream);
+				spin_unlock(&prtd->lock);
+			}
+		}
+
+		if (unlikely(pending & ~7)) {
+			if (pending & (1 << 3))
+				printk(KERN_WARNING
+				       "s6000-pcm: DMA %x Underflow\n",
+				       channel[i]);
+			if (pending & (1 << 4))
+				printk(KERN_WARNING
+				       "s6000-pcm: DMA %x Overflow\n",
+				       channel[i]);
+			if (pending & 0x1e0)
+				printk(KERN_WARNING
+				       "s6000-pcm: DMA %x Master Error "
+				       "(mask %x)\n",
+				       channel[i], pending >> 5);
+
+		}
+	}
+
+	return ret;
+}
+
+static int s6000_pcm_start(struct snd_pcm_substream *substream)
+{
+	struct s6000_runtime_data *prtd = substream->runtime->private_data;
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+	unsigned long flags;
+	int srcinc;
+	u32 dma;
+
+	spin_lock_irqsave(&prtd->lock, flags);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		srcinc = 1;
+		dma = par->dma_out;
+	} else {
+		srcinc = 0;
+		dma = par->dma_in;
+	}
+	s6dmac_enable_chan(DMA_MASK_DMAC(dma), DMA_INDEX_CHNL(dma),
+			   1 /* priority 1 (0 is max) */,
+			   0 /* peripheral requests w/o xfer length mode */,
+			   srcinc /* source address increment */,
+			   srcinc^1 /* destination address increment */,
+			   0 /* chunksize 0 (skip impossible on this dma) */,
+			   0 /* source skip after chunk (impossible) */,
+			   0 /* destination skip after chunk (impossible) */,
+			   4 /* 16 byte burst size */,
+			   -1 /* don't conserve bandwidth */,
+			   0 /* low watermark irq descriptor theshold */,
+			   0 /* disable hardware timestamps */,
+			   1 /* enable channel */);
+
+	s6000_pcm_enqueue_dma(substream);
+	s6000_pcm_enqueue_dma(substream);
+
+	spin_unlock_irqrestore(&prtd->lock, flags);
+
+	return 0;
+}
+
+static int s6000_pcm_stop(struct snd_pcm_substream *substream)
+{
+	struct s6000_runtime_data *prtd = substream->runtime->private_data;
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+	unsigned long flags;
+	u32 channel;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		channel = par->dma_out;
+	else
+		channel = par->dma_in;
+
+	s6dmac_set_terminal_count(DMA_MASK_DMAC(channel),
+				  DMA_INDEX_CHNL(channel), 0);
+
+	spin_lock_irqsave(&prtd->lock, flags);
+
+	s6dmac_disable_chan(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel));
+
+	spin_unlock_irqrestore(&prtd->lock, flags);
+
+	return 0;
+}
+
+static int s6000_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+	int ret;
+
+	ret = par->trigger(substream, cmd, 0);
+	if (ret < 0)
+		return ret;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ret = s6000_pcm_start(substream);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ret = s6000_pcm_stop(substream);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	if (ret < 0)
+		return ret;
+
+	return par->trigger(substream, cmd, 1);
+}
+
+static int s6000_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct s6000_runtime_data *prtd = substream->runtime->private_data;
+
+	prtd->period = 0;
+
+	return 0;
+}
+
+static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct s6000_runtime_data *prtd = runtime->private_data;
+	unsigned long flags;
+	unsigned int offset;
+	dma_addr_t count;
+
+	spin_lock_irqsave(&prtd->lock, flags);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		count = s6dmac_cur_src(DMA_MASK_DMAC(par->dma_out),
+				       DMA_INDEX_CHNL(par->dma_out));
+	else
+		count = s6dmac_cur_dst(DMA_MASK_DMAC(par->dma_in),
+				       DMA_INDEX_CHNL(par->dma_in));
+
+	count -= runtime->dma_addr;
+
+	spin_unlock_irqrestore(&prtd->lock, flags);
+
+	offset = bytes_to_frames(runtime, count);
+	if (unlikely(offset >= runtime->buffer_size))
+		offset = 0;
+
+	return offset;
+}
+
+static int s6000_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct s6000_runtime_data *prtd;
+	int ret;
+
+	snd_soc_set_runtime_hwparams(substream, &s6000_pcm_hardware);
+
+	ret = snd_pcm_hw_constraint_step(runtime, 0,
+					 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16);
+	if (ret < 0)
+		return ret;
+	ret = snd_pcm_hw_constraint_step(runtime, 0,
+					 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
+	if (ret < 0)
+		return ret;
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		return ret;
+
+	if (par->same_rate) {
+		int rate;
+		spin_lock(&par->lock); /* needed? */
+		rate = par->rate;
+		spin_unlock(&par->lock);
+		if (rate != -1) {
+			ret = snd_pcm_hw_constraint_minmax(runtime,
+							SNDRV_PCM_HW_PARAM_RATE,
+							rate, rate);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	prtd = kzalloc(sizeof(struct s6000_runtime_data), GFP_KERNEL);
+	if (prtd == NULL)
+		return -ENOMEM;
+
+	spin_lock_init(&prtd->lock);
+
+	runtime->private_data = prtd;
+
+	return 0;
+}
+
+static int s6000_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct s6000_runtime_data *prtd = runtime->private_data;
+
+	kfree(prtd);
+
+	return 0;
+}
+
+static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *hw_params)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+	int ret;
+	ret = snd_pcm_lib_malloc_pages(substream,
+				       params_buffer_bytes(hw_params));
+	if (ret < 0) {
+		printk(KERN_WARNING "s6000-pcm: allocation of memory failed\n");
+		return ret;
+	}
+
+	if (par->same_rate) {
+		spin_lock(&par->lock);
+		if (par->rate == -1 ||
+		    !(par->in_use & ~(1 << substream->stream))) {
+			par->rate = params_rate(hw_params);
+			par->in_use |= 1 << substream->stream;
+		} else if (params_rate(hw_params) != par->rate) {
+			snd_pcm_lib_free_pages(substream);
+			par->in_use &= ~(1 << substream->stream);
+			ret = -EBUSY;
+		}
+		spin_unlock(&par->lock);
+	}
+	return ret;
+}
+
+static int s6000_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+
+	spin_lock(&par->lock);
+	par->in_use &= ~(1 << substream->stream);
+	if (!par->in_use)
+		par->rate = -1;
+	spin_unlock(&par->lock);
+
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static struct snd_pcm_ops s6000_pcm_ops = {
+	.open = 	s6000_pcm_open,
+	.close = 	s6000_pcm_close,
+	.ioctl = 	snd_pcm_lib_ioctl,
+	.hw_params = 	s6000_pcm_hw_params,
+	.hw_free = 	s6000_pcm_hw_free,
+	.trigger =	s6000_pcm_trigger,
+	.prepare = 	s6000_pcm_prepare,
+	.pointer = 	s6000_pcm_pointer,
+};
+
+static void s6000_pcm_free(struct snd_pcm *pcm)
+{
+	struct snd_soc_pcm_runtime *runtime = pcm->private_data;
+	struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data;
+
+	free_irq(params->irq, pcm);
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static u64 s6000_pcm_dmamask = DMA_32BIT_MASK;
+
+static int s6000_pcm_new(struct snd_card *card,
+			 struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+	struct snd_soc_pcm_runtime *runtime = pcm->private_data;
+	struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data;
+	int res;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &s6000_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_32BIT_MASK;
+
+	if (params->dma_in) {
+		s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_in),
+				    DMA_INDEX_CHNL(params->dma_in));
+		s6dmac_int_sources(DMA_MASK_DMAC(params->dma_in),
+				   DMA_INDEX_CHNL(params->dma_in));
+	}
+
+	if (params->dma_out) {
+		s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_out),
+				    DMA_INDEX_CHNL(params->dma_out));
+		s6dmac_int_sources(DMA_MASK_DMAC(params->dma_out),
+				   DMA_INDEX_CHNL(params->dma_out));
+	}
+
+	res = request_irq(params->irq, s6000_pcm_irq, IRQF_SHARED,
+			  s6000_soc_platform.name, pcm);
+	if (res) {
+		printk(KERN_ERR "s6000-pcm couldn't get IRQ\n");
+		return res;
+	}
+
+	res = snd_pcm_lib_preallocate_pages_for_all(pcm,
+						    SNDRV_DMA_TYPE_DEV,
+						    card->dev,
+						    S6_PCM_PREALLOCATE_SIZE,
+						    S6_PCM_PREALLOCATE_MAX);
+	if (res)
+		printk(KERN_WARNING "s6000-pcm: preallocation failed\n");
+
+	spin_lock_init(&params->lock);
+	params->in_use = 0;
+	params->rate = -1;
+	return 0;
+}
+
+struct snd_soc_platform s6000_soc_platform = {
+	.name = 	"s6000-audio",
+	.pcm_ops = 	&s6000_pcm_ops,
+	.pcm_new = 	s6000_pcm_new,
+	.pcm_free = 	s6000_pcm_free,
+};
+EXPORT_SYMBOL_GPL(s6000_soc_platform);
+
+static int __init s6000_pcm_init(void)
+{
+	return snd_soc_register_platform(&s6000_soc_platform);
+}
+module_init(s6000_pcm_init);
+
+static void __exit s6000_pcm_exit(void)
+{
+	snd_soc_unregister_platform(&s6000_soc_platform);
+}
+module_exit(s6000_pcm_exit);
+
+MODULE_AUTHOR("Daniel Gloeckner");
+MODULE_DESCRIPTION("Stretch s6000 family PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s6000/s6000-pcm.h b/sound/soc/s6000/s6000-pcm.h
new file mode 100644
index 0000000..96f23f6
--- /dev/null
+++ b/sound/soc/s6000/s6000-pcm.h
@@ -0,0 +1,35 @@
+/*
+ * ALSA PCM interface for the Stretch s6000 family
+ *
+ * Author:      Daniel Gloeckner, <dg@emlix.com>
+ * Copyright:   (C) 2009 emlix GmbH <info@emlix.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 _S6000_PCM_H
+#define _S6000_PCM_H
+
+struct snd_soc_dai;
+struct snd_pcm_substream;
+
+struct s6000_pcm_dma_params {
+	unsigned int (*check_xrun)(struct snd_soc_dai *cpu_dai);
+	int (*trigger)(struct snd_pcm_substream *substream, int cmd, int after);
+	dma_addr_t sif_in;
+	dma_addr_t sif_out;
+	u32 dma_in;
+	u32 dma_out;
+	int irq;
+	int same_rate;
+
+	spinlock_t lock;
+	int in_use;
+	int rate;
+};
+
+extern struct snd_soc_platform s6000_soc_platform;
+
+#endif
diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c
new file mode 100644
index 0000000..b5f95f9
--- /dev/null
+++ b/sound/soc/s6000/s6105-ipcam.c
@@ -0,0 +1,244 @@
+/*
+ * ASoC driver for Stretch s6105 IP camera platform
+ *
+ * Author:      Daniel Gloeckner, <dg@emlix.com>
+ * Copyright:   (C) 2009 emlix GmbH <info@emlix.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/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <variant/dmac.h>
+
+#include "../codecs/tlv320aic3x.h"
+#include "s6000-pcm.h"
+#include "s6000-i2s.h"
+
+#define S6105_CAM_CODEC_CLOCK 12288000
+
+static int s6105_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->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret = 0;
+
+	/* set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+					     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_CBM_CFM |
+					   SND_SOC_DAIFMT_NB_NF);
+	if (ret < 0)
+		return ret;
+
+	/* set the codec system clock */
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, S6105_CAM_CODEC_CLOCK,
+					    SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops s6105_ops = {
+	.hw_params = s6105_hw_params,
+};
+
+/* s6105 machine dapm widgets */
+static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
+	SND_SOC_DAPM_LINE("Audio Out Differential", NULL),
+	SND_SOC_DAPM_LINE("Audio Out Stereo", NULL),
+	SND_SOC_DAPM_LINE("Audio In", NULL),
+};
+
+/* s6105 machine audio_mapnections to the codec pins */
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* Audio Out connected to HPLOUT, HPLCOM, HPROUT */
+	{"Audio Out Differential", NULL, "HPLOUT"},
+	{"Audio Out Differential", NULL, "HPLCOM"},
+	{"Audio Out Stereo", NULL, "HPLOUT"},
+	{"Audio Out Stereo", NULL, "HPROUT"},
+
+	/* Audio In connected to LINE1L, LINE1R */
+	{"LINE1L", NULL, "Audio In"},
+	{"LINE1R", NULL, "Audio In"},
+};
+
+static int output_type_info(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item) {
+		uinfo->value.enumerated.item = 1;
+		strcpy(uinfo->value.enumerated.name, "HPLOUT/HPROUT");
+	} else {
+		strcpy(uinfo->value.enumerated.name, "HPLOUT/HPLCOM");
+	}
+	return 0;
+}
+
+static int output_type_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.enumerated.item[0] = kcontrol->private_value;
+	return 0;
+}
+
+static int output_type_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = kcontrol->private_data;
+	unsigned int val = (ucontrol->value.enumerated.item[0] != 0);
+	char *differential = "Audio Out Differential";
+	char *stereo = "Audio Out Stereo";
+
+	if (kcontrol->private_value == val)
+		return 0;
+	kcontrol->private_value = val;
+	snd_soc_dapm_disable_pin(codec, val ? differential : stereo);
+	snd_soc_dapm_sync(codec);
+	snd_soc_dapm_enable_pin(codec, val ? stereo : differential);
+	snd_soc_dapm_sync(codec);
+
+	return 1;
+}
+
+static const struct snd_kcontrol_new audio_out_mux = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Master Output Mux",
+	.index = 0,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = output_type_info,
+	.get = output_type_get,
+	.put = output_type_put,
+	.private_value = 1 /* default to stereo */
+};
+
+/* Logic for a aic3x as connected on the s6105 ip camera ref design */
+static int s6105_aic3x_init(struct snd_soc_codec *codec)
+{
+	/* Add s6105 specific widgets */
+	snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
+				  ARRAY_SIZE(aic3x_dapm_widgets));
+
+	/* Set up s6105 specific audio path audio_map */
+	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+	/* not present */
+	snd_soc_dapm_nc_pin(codec, "MONO_LOUT");
+	snd_soc_dapm_nc_pin(codec, "LINE2L");
+	snd_soc_dapm_nc_pin(codec, "LINE2R");
+
+	/* not connected */
+	snd_soc_dapm_nc_pin(codec, "MIC3L"); /* LINE2L on this chip */
+	snd_soc_dapm_nc_pin(codec, "MIC3R"); /* LINE2R on this chip */
+	snd_soc_dapm_nc_pin(codec, "LLOUT");
+	snd_soc_dapm_nc_pin(codec, "RLOUT");
+	snd_soc_dapm_nc_pin(codec, "HPRCOM");
+
+	/* always connected */
+	snd_soc_dapm_enable_pin(codec, "Audio In");
+
+	/* must correspond to audio_out_mux.private_value initializer */
+	snd_soc_dapm_disable_pin(codec, "Audio Out Differential");
+	snd_soc_dapm_sync(codec);
+	snd_soc_dapm_enable_pin(codec, "Audio Out Stereo");
+
+	snd_soc_dapm_sync(codec);
+
+	snd_ctl_add(codec->card, snd_ctl_new1(&audio_out_mux, codec));
+
+	return 0;
+}
+
+/* s6105 digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link s6105_dai = {
+	.name = "TLV320AIC31",
+	.stream_name = "AIC31",
+	.cpu_dai = &s6000_i2s_dai,
+	.codec_dai = &aic3x_dai,
+	.init = s6105_aic3x_init,
+	.ops = &s6105_ops,
+};
+
+/* s6105 audio machine driver */
+static struct snd_soc_card snd_soc_card_s6105 = {
+	.name = "Stretch IP Camera",
+	.platform = &s6000_soc_platform,
+	.dai_link = &s6105_dai,
+	.num_links = 1,
+};
+
+/* s6105 audio private data */
+static struct aic3x_setup_data s6105_aic3x_setup = {
+	.i2c_bus = 0,
+	.i2c_address = 0x18,
+};
+
+/* s6105 audio subsystem */
+static struct snd_soc_device s6105_snd_devdata = {
+	.card = &snd_soc_card_s6105,
+	.codec_dev = &soc_codec_dev_aic3x,
+	.codec_data = &s6105_aic3x_setup,
+};
+
+static struct s6000_snd_platform_data __initdata s6105_snd_data = {
+	.wide		= 0,
+	.channel_in	= 0,
+	.channel_out	= 1,
+	.lines_in	= 1,
+	.lines_out	= 1,
+	.same_rate	= 1,
+};
+
+static struct platform_device *s6105_snd_device;
+
+static int __init s6105_init(void)
+{
+	int ret;
+
+	s6105_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!s6105_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(s6105_snd_device, &s6105_snd_devdata);
+	s6105_snd_devdata.dev = &s6105_snd_device->dev;
+	platform_device_add_data(s6105_snd_device, &s6105_snd_data,
+				 sizeof(s6105_snd_data));
+
+	ret = platform_device_add(s6105_snd_device);
+	if (ret)
+		platform_device_put(s6105_snd_device);
+
+	return ret;
+}
+
+static void __exit s6105_exit(void)
+{
+	platform_device_unregister(s6105_snd_device);
+}
+
+module_init(s6105_init);
+module_exit(s6105_exit);
+
+MODULE_AUTHOR("Daniel Gloeckner");
+MODULE_DESCRIPTION("Stretch s6105 IP camera ASoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
index 56fa087..b378096 100644
--- a/sound/soc/sh/ssi.c
+++ b/sound/soc/sh/ssi.c
@@ -145,7 +145,7 @@
 	recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
 
 	pr_debug("ssi_hw_params() enter\nssicr was    %08lx\n", ssicr);
-	pr_debug("bits: %d channels: %d\n", bits, channels);
+	pr_debug("bits: %u channels: %u\n", bits, channels);
 
 	ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA |
 		   CR_SWL_MASK);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 1cd149b..3f44150 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -113,6 +113,35 @@
 }
 #endif
 
+static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_card *card = socdev->card;
+	struct snd_soc_dai_link *machine = rtd->dai;
+	struct snd_soc_dai *cpu_dai = machine->cpu_dai;
+	struct snd_soc_dai *codec_dai = machine->codec_dai;
+	int ret;
+
+	if (codec_dai->symmetric_rates || cpu_dai->symmetric_rates ||
+	    machine->symmetric_rates) {
+		dev_dbg(card->dev, "Symmetry forces %dHz rate\n", 
+			machine->rate);
+
+		ret = snd_pcm_hw_constraint_minmax(substream->runtime,
+						   SNDRV_PCM_HW_PARAM_RATE,
+						   machine->rate,
+						   machine->rate);
+		if (ret < 0) {
+			dev_err(card->dev,
+				"Unable to apply rate symmetry constraint: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 /*
  * 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
@@ -221,6 +250,13 @@
 		goto machine_err;
 	}
 
+	/* Symmetry only applies if we've already got an active stream. */
+	if (cpu_dai->active || codec_dai->active) {
+		ret = soc_pcm_apply_symmetry(substream);
+		if (ret != 0)
+			goto machine_err;
+	}
+
 	pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name);
 	pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates);
 	pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
@@ -263,7 +299,6 @@
 {
 	struct snd_soc_card *card = container_of(work, struct snd_soc_card,
 						 delayed_work.work);
-	struct snd_soc_device *socdev = card->socdev;
 	struct snd_soc_codec *codec = card->codec;
 	struct snd_soc_dai *codec_dai;
 	int i;
@@ -279,27 +314,10 @@
 
 		/* are we waiting on this codec DAI stream */
 		if (codec_dai->pop_wait == 1) {
-
-			/* Reduce power if no longer active */
-			if (codec->active == 0) {
-				pr_debug("pop wq D1 %s %s\n", codec->name,
-					 codec_dai->playback.stream_name);
-				snd_soc_dapm_set_bias_level(socdev,
-					SND_SOC_BIAS_PREPARE);
-			}
-
 			codec_dai->pop_wait = 0;
 			snd_soc_dapm_stream_event(codec,
 				codec_dai->playback.stream_name,
 				SND_SOC_DAPM_STREAM_STOP);
-
-			/* Fall into standby if no longer active */
-			if (codec->active == 0) {
-				pr_debug("pop wq D3 %s %s\n", codec->name,
-					 codec_dai->playback.stream_name);
-				snd_soc_dapm_set_bias_level(socdev,
-					SND_SOC_BIAS_STANDBY);
-			}
 		}
 	}
 	mutex_unlock(&pcm_mutex);
@@ -363,10 +381,6 @@
 		snd_soc_dapm_stream_event(codec,
 			codec_dai->capture.stream_name,
 			SND_SOC_DAPM_STREAM_STOP);
-
-		if (codec->active == 0 && codec_dai->pop_wait == 0)
-			snd_soc_dapm_set_bias_level(socdev,
-						SND_SOC_BIAS_STANDBY);
 	}
 
 	mutex_unlock(&pcm_mutex);
@@ -431,36 +445,16 @@
 		cancel_delayed_work(&card->delayed_work);
 	}
 
-	/* do we need to power up codec */
-	if (codec->bias_level != SND_SOC_BIAS_ON) {
-		snd_soc_dapm_set_bias_level(socdev,
-					    SND_SOC_BIAS_PREPARE);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snd_soc_dapm_stream_event(codec,
+					  codec_dai->playback.stream_name,
+					  SND_SOC_DAPM_STREAM_START);
+	else
+		snd_soc_dapm_stream_event(codec,
+					  codec_dai->capture.stream_name,
+					  SND_SOC_DAPM_STREAM_START);
 
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			snd_soc_dapm_stream_event(codec,
-					codec_dai->playback.stream_name,
-					SND_SOC_DAPM_STREAM_START);
-		else
-			snd_soc_dapm_stream_event(codec,
-					codec_dai->capture.stream_name,
-					SND_SOC_DAPM_STREAM_START);
-
-		snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON);
-		snd_soc_dai_digital_mute(codec_dai, 0);
-
-	} else {
-		/* codec already powered - power on widgets */
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			snd_soc_dapm_stream_event(codec,
-					codec_dai->playback.stream_name,
-					SND_SOC_DAPM_STREAM_START);
-		else
-			snd_soc_dapm_stream_event(codec,
-					codec_dai->capture.stream_name,
-					SND_SOC_DAPM_STREAM_START);
-
-		snd_soc_dai_digital_mute(codec_dai, 0);
-	}
+	snd_soc_dai_digital_mute(codec_dai, 0);
 
 out:
 	mutex_unlock(&pcm_mutex);
@@ -521,6 +515,8 @@
 		}
 	}
 
+	machine->rate = params_rate(params);
+
 out:
 	mutex_unlock(&pcm_mutex);
 	return ret;
@@ -632,6 +628,12 @@
 	struct snd_soc_codec *codec = card->codec;
 	int i;
 
+	/* If the initialization of this soc device failed, there is no codec
+	 * associated with it. Just bail out in this case.
+	 */
+	if (!codec)
+		return 0;
+
 	/* Due to the resume being scheduled into a workqueue we could
 	* suspend before that's finished - wait for it to complete.
 	 */
@@ -1334,6 +1336,7 @@
 		return ret;
 	}
 
+	codec->socdev = socdev;
 	codec->card->dev = socdev->dev;
 	codec->card->private_data = codec;
 	strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
@@ -1744,7 +1747,7 @@
 {
 	int max = kcontrol->private_value;
 
-	if (max == 1)
+	if (max == 1 && !strstr(kcontrol->id.name, " Volume"))
 		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	else
 		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -1774,7 +1777,7 @@
 	unsigned int shift = mc->shift;
 	unsigned int rshift = mc->rshift;
 
-	if (max == 1)
+	if (max == 1 && !strstr(kcontrol->id.name, " Volume"))
 		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	else
 		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -1881,7 +1884,7 @@
 		(struct soc_mixer_control *)kcontrol->private_value;
 	int max = mc->max;
 
-	if (max == 1)
+	if (max == 1 && !strstr(kcontrol->id.name, " Volume"))
 		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	else
 		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -2065,7 +2068,7 @@
 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 	unsigned int freq, int dir)
 {
-	if (dai->ops->set_sysclk)
+	if (dai->ops && dai->ops->set_sysclk)
 		return dai->ops->set_sysclk(dai, clk_id, freq, dir);
 	else
 		return -EINVAL;
@@ -2085,7 +2088,7 @@
 int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
 	int div_id, int div)
 {
-	if (dai->ops->set_clkdiv)
+	if (dai->ops && dai->ops->set_clkdiv)
 		return dai->ops->set_clkdiv(dai, div_id, div);
 	else
 		return -EINVAL;
@@ -2104,7 +2107,7 @@
 int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
 	int pll_id, unsigned int freq_in, unsigned int freq_out)
 {
-	if (dai->ops->set_pll)
+	if (dai->ops && dai->ops->set_pll)
 		return dai->ops->set_pll(dai, pll_id, freq_in, freq_out);
 	else
 		return -EINVAL;
@@ -2120,7 +2123,7 @@
  */
 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	if (dai->ops->set_fmt)
+	if (dai->ops && dai->ops->set_fmt)
 		return dai->ops->set_fmt(dai, fmt);
 	else
 		return -EINVAL;
@@ -2139,7 +2142,7 @@
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
 	unsigned int mask, int slots)
 {
-	if (dai->ops->set_sysclk)
+	if (dai->ops && dai->ops->set_tdm_slot)
 		return dai->ops->set_tdm_slot(dai, mask, slots);
 	else
 		return -EINVAL;
@@ -2155,7 +2158,7 @@
  */
 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-	if (dai->ops->set_sysclk)
+	if (dai->ops && dai->ops->set_tristate)
 		return dai->ops->set_tristate(dai, tristate);
 	else
 		return -EINVAL;
@@ -2171,7 +2174,7 @@
  */
 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-	if (dai->ops->digital_mute)
+	if (dai->ops && dai->ops->digital_mute)
 		return dai->ops->digital_mute(dai, mute);
 	else
 		return -EINVAL;
@@ -2352,6 +2355,39 @@
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
 
+static u64 codec_format_map[] = {
+	SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE,
+	SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE,
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE,
+	SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE,
+	SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE,
+	SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE,
+	SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3BE,
+	SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_U24_3BE,
+	SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE,
+	SNDRV_PCM_FMTBIT_U20_3LE | SNDRV_PCM_FMTBIT_U20_3BE,
+	SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE,
+	SNDRV_PCM_FMTBIT_U18_3LE | SNDRV_PCM_FMTBIT_U18_3BE,
+	SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE,
+	SNDRV_PCM_FMTBIT_FLOAT64_LE | SNDRV_PCM_FMTBIT_FLOAT64_BE,
+	SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE
+	| SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE,
+};
+
+/* Fix up the DAI formats for endianness: codecs don't actually see
+ * the endianness of the data but we're using the CPU format
+ * definitions which do need to include endianness so we ensure that
+ * codec DAIs always have both big and little endian variants set.
+ */
+static void fixup_codec_formats(struct snd_soc_pcm_stream *stream)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(codec_format_map); i++)
+		if (stream->formats & codec_format_map[i])
+			stream->formats |= codec_format_map[i];
+}
+
 /**
  * snd_soc_register_codec - Register a codec with the ASoC core
  *
@@ -2359,6 +2395,8 @@
  */
 int snd_soc_register_codec(struct snd_soc_codec *codec)
 {
+	int i;
+
 	if (!codec->name)
 		return -EINVAL;
 
@@ -2368,6 +2406,11 @@
 
 	INIT_LIST_HEAD(&codec->list);
 
+	for (i = 0; i < codec->num_dai; i++) {
+		fixup_codec_formats(&codec->dai[i].playback);
+		fixup_codec_formats(&codec->dai[i].capture);
+	}
+
 	mutex_lock(&client_mutex);
 	list_add(&codec->list, &codec_list);
 	snd_soc_instantiate_cards();
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 735903a..21c6907 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -12,7 +12,7 @@
  *  Features:
  *    o Changes power status of internal codec blocks depending on the
  *      dynamic configuration of codec internal audio paths and active
- *      DAC's/ADC's.
+ *      DACs/ADCs.
  *    o Platform power domain - can support external components i.e. amps and
  *      mic/meadphone insertion events.
  *    o Automatic Mic Bias support
@@ -52,23 +52,21 @@
 
 /* dapm power sequences - make this per codec in the future */
 static int dapm_up_seq[] = {
-	snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic,
-	snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac,
-	snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_pga,
-	snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post
+	snd_soc_dapm_pre, snd_soc_dapm_supply, snd_soc_dapm_micbias,
+	snd_soc_dapm_mic, snd_soc_dapm_mux, snd_soc_dapm_value_mux,
+	snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl,
+	snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
+	snd_soc_dapm_post
 };
 
 static int dapm_down_seq[] = {
 	snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
 	snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer,
 	snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias,
-	snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_post
+	snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_supply,
+	snd_soc_dapm_post
 };
 
-static int dapm_status = 1;
-module_param(dapm_status, int, 0);
-MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries");
-
 static void pop_wait(u32 pop_time)
 {
 	if (pop_time)
@@ -96,6 +94,48 @@
 	return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
 }
 
+/**
+ * snd_soc_dapm_set_bias_level - set the bias level for the system
+ * @socdev: audio device
+ * @level: level to configure
+ *
+ * Configure the bias (power) levels for the SoC audio device.
+ *
+ * Returns 0 for success else error.
+ */
+static int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
+				       enum snd_soc_bias_level level)
+{
+	struct snd_soc_card *card = socdev->card;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	int ret = 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		dev_dbg(socdev->dev, "Setting full bias\n");
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		dev_dbg(socdev->dev, "Setting bias prepare\n");
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		dev_dbg(socdev->dev, "Setting standby bias\n");
+		break;
+	case SND_SOC_BIAS_OFF:
+		dev_dbg(socdev->dev, "Setting bias off\n");
+		break;
+	default:
+		dev_err(socdev->dev, "Setting invalid bias %d\n", level);
+		return -EINVAL;
+	}
+
+	if (card->set_bias_level)
+		ret = card->set_bias_level(card, level);
+	if (ret == 0 && codec->set_bias_level)
+		ret = codec->set_bias_level(codec, level);
+
+	return ret;
+}
+
 /* set up initial codec paths */
 static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
 	struct snd_soc_dapm_path *p, int i)
@@ -165,6 +205,7 @@
 	case snd_soc_dapm_dac:
 	case snd_soc_dapm_micbias:
 	case snd_soc_dapm_vmid:
+	case snd_soc_dapm_supply:
 		p->connect = 1;
 	break;
 	/* does effect routing - dynamically connected */
@@ -179,7 +220,7 @@
 	}
 }
 
-/* connect mux widget to it's interconnecting audio paths */
+/* connect mux widget to its interconnecting audio paths */
 static int dapm_connect_mux(struct snd_soc_codec *codec,
 	struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
 	struct snd_soc_dapm_path *path, const char *control_name,
@@ -202,7 +243,7 @@
 	return -ENODEV;
 }
 
-/* connect mixer widget to it's interconnecting audio paths */
+/* connect mixer widget to its interconnecting audio paths */
 static int dapm_connect_mixer(struct snd_soc_codec *codec,
 	struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
 	struct snd_soc_dapm_path *path, const char *control_name)
@@ -357,8 +398,9 @@
 				path->long_name);
 			ret = snd_ctl_add(codec->card, path->kcontrol);
 			if (ret < 0) {
-				printk(KERN_ERR "asoc: failed to add dapm kcontrol %s\n",
-						path->long_name);
+				printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n",
+				       path->long_name,
+				       ret);
 				kfree(path->long_name);
 				path->long_name = NULL;
 				return ret;
@@ -434,6 +476,9 @@
 	struct snd_soc_dapm_path *path;
 	int con = 0;
 
+	if (widget->id == snd_soc_dapm_supply)
+		return 0;
+
 	if (widget->id == snd_soc_dapm_adc && widget->active)
 		return 1;
 
@@ -470,6 +515,9 @@
 	struct snd_soc_dapm_path *path;
 	int con = 0;
 
+	if (widget->id == snd_soc_dapm_supply)
+		return 0;
+
 	/* active stream ? */
 	if (widget->id == snd_soc_dapm_dac && widget->active)
 		return 1;
@@ -521,6 +569,126 @@
 }
 EXPORT_SYMBOL_GPL(dapm_reg_event);
 
+/* Standard power change method, used to apply power changes to most
+ * widgets.
+ */
+static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w)
+{
+	int ret;
+
+	/* call any power change event handlers */
+	if (w->event)
+		pr_debug("power %s event for %s flags %x\n",
+			 w->power ? "on" : "off",
+			 w->name, w->event_flags);
+
+	/* power up pre event */
+	if (w->power && w->event &&
+	    (w->event_flags & SND_SOC_DAPM_PRE_PMU)) {
+		ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* power down pre event */
+	if (!w->power && w->event &&
+	    (w->event_flags & SND_SOC_DAPM_PRE_PMD)) {
+		ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* Lower PGA volume to reduce pops */
+	if (w->id == snd_soc_dapm_pga && !w->power)
+		dapm_set_pga(w, w->power);
+
+	dapm_update_bits(w);
+
+	/* Raise PGA volume to reduce pops */
+	if (w->id == snd_soc_dapm_pga && w->power)
+		dapm_set_pga(w, w->power);
+
+	/* power up post event */
+	if (w->power && w->event &&
+	    (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
+		ret = w->event(w,
+			       NULL, SND_SOC_DAPM_POST_PMU);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* power down post event */
+	if (!w->power && w->event &&
+	    (w->event_flags & SND_SOC_DAPM_POST_PMD)) {
+		ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+/* Generic check to see if a widget should be powered.
+ */
+static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
+{
+	int in, out;
+
+	in = is_connected_input_ep(w);
+	dapm_clear_walk(w->codec);
+	out = is_connected_output_ep(w);
+	dapm_clear_walk(w->codec);
+	return out != 0 && in != 0;
+}
+
+/* Check to see if an ADC has power */
+static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
+{
+	int in;
+
+	if (w->active) {
+		in = is_connected_input_ep(w);
+		dapm_clear_walk(w->codec);
+		return in != 0;
+	} else {
+		return dapm_generic_check_power(w);
+	}
+}
+
+/* Check to see if a DAC has power */
+static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
+{
+	int out;
+
+	if (w->active) {
+		out = is_connected_output_ep(w);
+		dapm_clear_walk(w->codec);
+		return out != 0;
+	} else {
+		return dapm_generic_check_power(w);
+	}
+}
+
+/* Check to see if a power supply is needed */
+static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
+{
+	struct snd_soc_dapm_path *path;
+	int power = 0;
+
+	/* Check if one of our outputs is connected */
+	list_for_each_entry(path, &w->sinks, list_source) {
+		if (path->sink && path->sink->power_check &&
+		    path->sink->power_check(path->sink)) {
+			power = 1;
+			break;
+		}
+	}
+
+	dapm_clear_walk(w->codec);
+
+	return power;
+}
+
 /*
  * Scan a single DAPM widget for a complete audio path and update the
  * power status appropriately.
@@ -528,32 +696,10 @@
 static int dapm_power_widget(struct snd_soc_codec *codec, int event,
 			     struct snd_soc_dapm_widget *w)
 {
-	int in, out, power_change, power, ret;
+	int ret;
 
-	/* vmid - no action */
-	if (w->id == snd_soc_dapm_vmid)
-		return 0;
-
-	/* active ADC */
-	if (w->id == snd_soc_dapm_adc && w->active) {
-		in = is_connected_input_ep(w);
-		dapm_clear_walk(w->codec);
-		w->power = (in != 0) ? 1 : 0;
-		dapm_update_bits(w);
-		return 0;
-	}
-
-	/* active DAC */
-	if (w->id == snd_soc_dapm_dac && w->active) {
-		out = is_connected_output_ep(w);
-		dapm_clear_walk(w->codec);
-		w->power = (out != 0) ? 1 : 0;
-		dapm_update_bits(w);
-		return 0;
-	}
-
-	/* pre and post event widgets */
-	if (w->id == snd_soc_dapm_pre) {
+	switch (w->id) {
+	case snd_soc_dapm_pre:
 		if (!w->event)
 			return 0;
 
@@ -569,8 +715,8 @@
 				return ret;
 		}
 		return 0;
-	}
-	if (w->id == snd_soc_dapm_post) {
+
+	case snd_soc_dapm_post:
 		if (!w->event)
 			return 0;
 
@@ -586,70 +732,10 @@
 				return ret;
 		}
 		return 0;
+
+	default:
+		return dapm_generic_apply_power(w);
 	}
-
-	/* all other widgets */
-	in = is_connected_input_ep(w);
-	dapm_clear_walk(w->codec);
-	out = is_connected_output_ep(w);
-	dapm_clear_walk(w->codec);
-	power = (out != 0 && in != 0) ? 1 : 0;
-	power_change = (w->power == power) ? 0 : 1;
-	w->power = power;
-
-	if (!power_change)
-		return 0;
-
-	/* call any power change event handlers */
-	if (w->event)
-		pr_debug("power %s event for %s flags %x\n",
-			 w->power ? "on" : "off",
-			 w->name, w->event_flags);
-
-	/* power up pre event */
-	if (power && w->event &&
-	    (w->event_flags & SND_SOC_DAPM_PRE_PMU)) {
-		ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU);
-		if (ret < 0)
-			return ret;
-	}
-
-	/* power down pre event */
-	if (!power && w->event &&
-	    (w->event_flags & SND_SOC_DAPM_PRE_PMD)) {
-		ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD);
-		if (ret < 0)
-			return ret;
-	}
-
-	/* Lower PGA volume to reduce pops */
-	if (w->id == snd_soc_dapm_pga && !power)
-		dapm_set_pga(w, power);
-
-	dapm_update_bits(w);
-
-	/* Raise PGA volume to reduce pops */
-	if (w->id == snd_soc_dapm_pga && power)
-		dapm_set_pga(w, power);
-
-	/* power up post event */
-	if (power && w->event &&
-	    (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
-		ret = w->event(w,
-			       NULL, SND_SOC_DAPM_POST_PMU);
-		if (ret < 0)
-			return ret;
-	}
-
-	/* power down post event */
-	if (!power && w->event &&
-	    (w->event_flags & SND_SOC_DAPM_POST_PMD)) {
-		ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD);
-		if (ret < 0)
-			return ret;
-	}
-
-	return 0;
 }
 
 /*
@@ -663,31 +749,102 @@
  */
 static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
 {
+	struct snd_soc_device *socdev = codec->socdev;
 	struct snd_soc_dapm_widget *w;
-	int i, c = 1, *seq = NULL, ret = 0;
+	int ret = 0;
+	int i, power;
+	int sys_power = 0;
 
-	/* do we have a sequenced stream event */
-	if (event == SND_SOC_DAPM_STREAM_START) {
-		c = ARRAY_SIZE(dapm_up_seq);
-		seq = dapm_up_seq;
-	} else if (event == SND_SOC_DAPM_STREAM_STOP) {
-		c = ARRAY_SIZE(dapm_down_seq);
-		seq = dapm_down_seq;
+	INIT_LIST_HEAD(&codec->up_list);
+	INIT_LIST_HEAD(&codec->down_list);
+
+	/* Check which widgets we need to power and store them in
+	 * lists indicating if they should be powered up or down.
+	 */
+	list_for_each_entry(w, &codec->dapm_widgets, list) {
+		switch (w->id) {
+		case snd_soc_dapm_pre:
+			list_add_tail(&codec->down_list, &w->power_list);
+			break;
+		case snd_soc_dapm_post:
+			list_add_tail(&codec->up_list, &w->power_list);
+			break;
+
+		default:
+			if (!w->power_check)
+				continue;
+
+			power = w->power_check(w);
+			if (power)
+				sys_power = 1;
+
+			if (w->power == power)
+				continue;
+
+			if (power)
+				list_add_tail(&w->power_list, &codec->up_list);
+			else
+				list_add_tail(&w->power_list,
+					      &codec->down_list);
+
+			w->power = power;
+			break;
+		}
 	}
 
-	for (i = 0; i < c; i++) {
-		list_for_each_entry(w, &codec->dapm_widgets, list) {
+	/* If we're changing to all on or all off then prepare */
+	if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) ||
+	    (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) {
+		ret = snd_soc_dapm_set_bias_level(socdev,
+						  SND_SOC_BIAS_PREPARE);
+		if (ret != 0)
+			pr_err("Failed to prepare bias: %d\n", ret);
+	}
 
+	/* Power down widgets first; try to avoid amplifying pops. */
+	for (i = 0; i < ARRAY_SIZE(dapm_down_seq); i++) {
+		list_for_each_entry(w, &codec->down_list, power_list) {
 			/* is widget in stream order */
-			if (seq && seq[i] && w->id != seq[i])
+			if (w->id != dapm_down_seq[i])
 				continue;
 
 			ret = dapm_power_widget(codec, event, w);
 			if (ret != 0)
-				return ret;
+				pr_err("Failed to power down %s: %d\n",
+				       w->name, ret);
 		}
 	}
 
+	/* Now power up. */
+	for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) {
+		list_for_each_entry(w, &codec->up_list, power_list) {
+			/* is widget in stream order */
+			if (w->id != dapm_up_seq[i])
+				continue;
+
+			ret = dapm_power_widget(codec, event, w);
+			if (ret != 0)
+				pr_err("Failed to power up %s: %d\n",
+				       w->name, ret);
+		}
+	}
+
+	/* If we just powered the last thing off drop to standby bias */
+	if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) {
+		ret = snd_soc_dapm_set_bias_level(socdev,
+						  SND_SOC_BIAS_STANDBY);
+		if (ret != 0)
+			pr_err("Failed to apply standby bias: %d\n", ret);
+	}
+
+	/* If we just powered up then move to active bias */
+	if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) {
+		ret = snd_soc_dapm_set_bias_level(socdev,
+						  SND_SOC_BIAS_ON);
+		if (ret != 0)
+			pr_err("Failed to apply active bias: %d\n", ret);
+	}
+
 	return 0;
 }
 
@@ -723,6 +880,7 @@
 		case snd_soc_dapm_pga:
 		case snd_soc_dapm_mixer:
 		case snd_soc_dapm_mixer_named_ctl:
+		case snd_soc_dapm_supply:
 			if (w->name) {
 				in = is_connected_input_ep(w);
 				dapm_clear_walk(w->codec);
@@ -851,6 +1009,7 @@
 		case snd_soc_dapm_pga:
 		case snd_soc_dapm_mixer:
 		case snd_soc_dapm_mixer_named_ctl:
+		case snd_soc_dapm_supply:
 			if (w->name)
 				count += sprintf(buf + count, "%s: %s\n",
 					w->name, w->power ? "On":"Off");
@@ -883,16 +1042,12 @@
 
 int snd_soc_dapm_sys_add(struct device *dev)
 {
-	if (!dapm_status)
-		return 0;
 	return device_create_file(dev, &dev_attr_dapm_widget);
 }
 
 static void snd_soc_dapm_sys_remove(struct device *dev)
 {
-	if (dapm_status) {
-		device_remove_file(dev, &dev_attr_dapm_widget);
-	}
+	device_remove_file(dev, &dev_attr_dapm_widget);
 }
 
 /* free all dapm widgets and resources */
@@ -1015,6 +1170,7 @@
 	case snd_soc_dapm_vmid:
 	case snd_soc_dapm_pre:
 	case snd_soc_dapm_post:
+	case snd_soc_dapm_supply:
 		list_add(&path->list, &codec->dapm_paths);
 		list_add(&path->list_sink, &wsink->sources);
 		list_add(&path->list_source, &wsource->sinks);
@@ -1108,15 +1264,22 @@
 		case snd_soc_dapm_switch:
 		case snd_soc_dapm_mixer:
 		case snd_soc_dapm_mixer_named_ctl:
+			w->power_check = dapm_generic_check_power;
 			dapm_new_mixer(codec, w);
 			break;
 		case snd_soc_dapm_mux:
 		case snd_soc_dapm_value_mux:
+			w->power_check = dapm_generic_check_power;
 			dapm_new_mux(codec, w);
 			break;
 		case snd_soc_dapm_adc:
+			w->power_check = dapm_adc_check_power;
+			break;
 		case snd_soc_dapm_dac:
+			w->power_check = dapm_dac_check_power;
+			break;
 		case snd_soc_dapm_pga:
+			w->power_check = dapm_generic_check_power;
 			dapm_new_pga(codec, w);
 			break;
 		case snd_soc_dapm_input:
@@ -1126,6 +1289,10 @@
 		case snd_soc_dapm_hp:
 		case snd_soc_dapm_mic:
 		case snd_soc_dapm_line:
+			w->power_check = dapm_generic_check_power;
+			break;
+		case snd_soc_dapm_supply:
+			w->power_check = dapm_supply_check_power;
 		case snd_soc_dapm_vmid:
 		case snd_soc_dapm_pre:
 		case snd_soc_dapm_post:
@@ -1626,35 +1793,11 @@
 EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
 
 /**
- * snd_soc_dapm_set_bias_level - set the bias level for the system
- * @socdev: audio device
- * @level: level to configure
- *
- * Configure the bias (power) levels for the SoC audio device.
- *
- * Returns 0 for success else error.
- */
-int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
-				enum snd_soc_bias_level level)
-{
-	struct snd_soc_card *card = socdev->card;
-	struct snd_soc_codec *codec = socdev->card->codec;
-	int ret = 0;
-
-	if (card->set_bias_level)
-		ret = card->set_bias_level(card, level);
-	if (ret == 0 && codec->set_bias_level)
-		ret = codec->set_bias_level(codec, level);
-
-	return ret;
-}
-
-/**
  * snd_soc_dapm_enable_pin - enable pin.
  * @codec: SoC codec
  * @pin: pin name
  *
- * Enables input/output pin and it's parents or children widgets iff there is
+ * Enables input/output pin and its parents or children widgets iff there is
  * a valid audio route and active audio stream.
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
@@ -1670,7 +1813,7 @@
  * @codec: SoC codec
  * @pin: pin name
  *
- * Disables input/output pin and it's parents or children widgets.
+ * Disables input/output pin and its parents or children widgets.
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
diff --git a/sound/soc/txx9/Kconfig b/sound/soc/txx9/Kconfig
new file mode 100644
index 0000000..ebc9327
--- /dev/null
+++ b/sound/soc/txx9/Kconfig
@@ -0,0 +1,29 @@
+##
+## TXx9 ACLC
+##
+config SND_SOC_TXX9ACLC
+	tristate "SoC Audio for TXx9"
+	depends on HAS_TXX9_ACLC && TXX9_DMAC
+	help
+	  This option enables support for the AC Link Controllers in TXx9 SoC.
+
+config HAS_TXX9_ACLC
+	bool
+
+config SND_SOC_TXX9ACLC_AC97
+	tristate
+	select AC97_BUS
+	select SND_AC97_CODEC
+	select SND_SOC_AC97_BUS
+
+
+##
+## Boards
+##
+config SND_SOC_TXX9ACLC_GENERIC
+	tristate "Generic TXx9 ACLC sound machine"
+	depends on SND_SOC_TXX9ACLC
+	select SND_SOC_TXX9ACLC_AC97
+	select SND_SOC_AC97_CODEC
+	help
+	  This is a generic AC97 sound machine for use in TXx9 based systems.
diff --git a/sound/soc/txx9/Makefile b/sound/soc/txx9/Makefile
new file mode 100644
index 0000000..551f16c
--- /dev/null
+++ b/sound/soc/txx9/Makefile
@@ -0,0 +1,11 @@
+# Platform
+snd-soc-txx9aclc-objs := txx9aclc.o
+snd-soc-txx9aclc-ac97-objs := txx9aclc-ac97.o
+
+obj-$(CONFIG_SND_SOC_TXX9ACLC) += snd-soc-txx9aclc.o
+obj-$(CONFIG_SND_SOC_TXX9ACLC_AC97) += snd-soc-txx9aclc-ac97.o
+
+# Machine
+snd-soc-txx9aclc-generic-objs := txx9aclc-generic.o
+
+obj-$(CONFIG_SND_SOC_TXX9ACLC_GENERIC) += snd-soc-txx9aclc-generic.o
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
new file mode 100644
index 0000000..0f83bdb
--- /dev/null
+++ b/sound/soc/txx9/txx9aclc-ac97.c
@@ -0,0 +1,255 @@
+/*
+ * TXx9 ACLC AC97 driver
+ *
+ * Copyright (C) 2009 Atsushi Nemoto
+ *
+ * Based on RBTX49xx patch from CELF patch archive.
+ * (C) Copyright TOSHIBA CORPORATION 2004-2006
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include "txx9aclc.h"
+
+#define AC97_DIR	\
+	(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
+
+#define AC97_RATES	\
+	SNDRV_PCM_RATE_8000_48000
+
+#ifdef __BIG_ENDIAN
+#define AC97_FMTS	SNDRV_PCM_FMTBIT_S16_BE
+#else
+#define AC97_FMTS	SNDRV_PCM_FMTBIT_S16_LE
+#endif
+
+static DECLARE_WAIT_QUEUE_HEAD(ac97_waitq);
+
+/* REVISIT: How to find txx9aclc_soc_device from snd_ac97? */
+static struct txx9aclc_soc_device *txx9aclc_soc_dev;
+
+static int txx9aclc_regready(struct txx9aclc_soc_device *dev)
+{
+	struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+
+	return __raw_readl(drvdata->base + ACINTSTS) & ACINT_REGACCRDY;
+}
+
+/* AC97 controller reads codec register */
+static unsigned short txx9aclc_ac97_read(struct snd_ac97 *ac97,
+					 unsigned short reg)
+{
+	struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
+	struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+	void __iomem *base = drvdata->base;
+	u32 dat;
+
+	if (!(__raw_readl(base + ACINTSTS) & ACINT_CODECRDY(ac97->num)))
+		return 0xffff;
+	reg |= ac97->num << 7;
+	dat = (reg << ACREGACC_REG_SHIFT) | ACREGACC_READ;
+	__raw_writel(dat, base + ACREGACC);
+	__raw_writel(ACINT_REGACCRDY, base + ACINTEN);
+	if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) {
+		__raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
+		dev_err(dev->soc_dev.dev, "ac97 read timeout (reg %#x)\n", reg);
+		dat = 0xffff;
+		goto done;
+	}
+	dat = __raw_readl(base + ACREGACC);
+	if (((dat >> ACREGACC_REG_SHIFT) & 0xff) != reg) {
+		dev_err(dev->soc_dev.dev, "reg mismatch %x with %x\n",
+			dat, reg);
+		dat = 0xffff;
+		goto done;
+	}
+	dat = (dat >> ACREGACC_DAT_SHIFT) & 0xffff;
+done:
+	__raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
+	return dat;
+}
+
+/* AC97 controller writes to codec register */
+static void txx9aclc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+				unsigned short val)
+{
+	struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
+	struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+	void __iomem *base = drvdata->base;
+
+	__raw_writel(((reg | (ac97->num << 7)) << ACREGACC_REG_SHIFT) |
+		     (val << ACREGACC_DAT_SHIFT),
+		     base + ACREGACC);
+	__raw_writel(ACINT_REGACCRDY, base + ACINTEN);
+	if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) {
+		dev_err(dev->soc_dev.dev,
+			"ac97 write timeout (reg %#x)\n", reg);
+	}
+	__raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
+}
+
+static void txx9aclc_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+	struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
+	struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+	void __iomem *base = drvdata->base;
+	u32 ready = ACINT_CODECRDY(ac97->num) | ACINT_REGACCRDY;
+
+	__raw_writel(ACCTL_ENLINK, base + ACCTLDIS);
+	mmiowb();
+	udelay(1);
+	__raw_writel(ACCTL_ENLINK, base + ACCTLEN);
+	/* wait for primary codec ready status */
+	__raw_writel(ready, base + ACINTEN);
+	if (!wait_event_timeout(ac97_waitq,
+				(__raw_readl(base + ACINTSTS) & ready) == ready,
+				HZ)) {
+		dev_err(&ac97->dev, "primary codec is not ready "
+			"(status %#x)\n",
+			__raw_readl(base + ACINTSTS));
+	}
+	__raw_writel(ACINT_REGACCRDY, base + ACINTSTS);
+	__raw_writel(ready, base + ACINTDIS);
+}
+
+/* AC97 controller operations */
+struct snd_ac97_bus_ops soc_ac97_ops = {
+	.read		= txx9aclc_ac97_read,
+	.write		= txx9aclc_ac97_write,
+	.reset		= txx9aclc_ac97_cold_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static irqreturn_t txx9aclc_ac97_irq(int irq, void *dev_id)
+{
+	struct txx9aclc_plat_drvdata *drvdata = dev_id;
+	void __iomem *base = drvdata->base;
+
+	__raw_writel(__raw_readl(base + ACINTMSTS), base + ACINTDIS);
+	wake_up(&ac97_waitq);
+	return IRQ_HANDLED;
+}
+
+static int txx9aclc_ac97_probe(struct platform_device *pdev,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct txx9aclc_soc_device *dev =
+		container_of(socdev, struct txx9aclc_soc_device, soc_dev);
+
+	dev->aclc_pdev = to_platform_device(dai->dev);
+	txx9aclc_soc_dev = dev;
+	return 0;
+}
+
+static void txx9aclc_ac97_remove(struct platform_device *pdev,
+				 struct snd_soc_dai *dai)
+{
+	struct platform_device *aclc_pdev = to_platform_device(dai->dev);
+	struct txx9aclc_plat_drvdata *drvdata = platform_get_drvdata(aclc_pdev);
+
+	/* disable AC-link */
+	__raw_writel(ACCTL_ENLINK, drvdata->base + ACCTLDIS);
+	txx9aclc_soc_dev = NULL;
+}
+
+struct snd_soc_dai txx9aclc_ac97_dai = {
+	.name			= "txx9aclc_ac97",
+	.ac97_control		= 1,
+	.probe			= txx9aclc_ac97_probe,
+	.remove			= txx9aclc_ac97_remove,
+	.playback = {
+		.rates		= AC97_RATES,
+		.formats	= AC97_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 2,
+	},
+	.capture = {
+		.rates		= AC97_RATES,
+		.formats	= AC97_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 2,
+	},
+};
+EXPORT_SYMBOL_GPL(txx9aclc_ac97_dai);
+
+static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev)
+{
+	struct txx9aclc_plat_drvdata *drvdata;
+	struct resource *r;
+	int err;
+	int irq;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r)
+		return -EBUSY;
+
+	if (!devm_request_mem_region(&pdev->dev, r->start, resource_size(r),
+				     dev_name(&pdev->dev)))
+		return -EBUSY;
+
+	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drvdata);
+	drvdata->physbase = r->start;
+	if (sizeof(drvdata->physbase) > sizeof(r->start) &&
+	    r->start >= TXX9_DIRECTMAP_BASE &&
+	    r->start < TXX9_DIRECTMAP_BASE + 0x400000)
+		drvdata->physbase |= 0xf00000000ull;
+	drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+	if (!drvdata->base)
+		return -EBUSY;
+	err = devm_request_irq(&pdev->dev, irq, txx9aclc_ac97_irq,
+			       IRQF_DISABLED, dev_name(&pdev->dev), drvdata);
+	if (err < 0)
+		return err;
+
+	txx9aclc_ac97_dai.dev = &pdev->dev;
+	return snd_soc_register_dai(&txx9aclc_ac97_dai);
+}
+
+static int __devexit txx9aclc_ac97_dev_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&txx9aclc_ac97_dai);
+	return 0;
+}
+
+static struct platform_driver txx9aclc_ac97_driver = {
+	.probe		= txx9aclc_ac97_dev_probe,
+	.remove		= __devexit_p(txx9aclc_ac97_dev_remove),
+	.driver		= {
+		.name	= "txx9aclc-ac97",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init txx9aclc_ac97_init(void)
+{
+	return platform_driver_register(&txx9aclc_ac97_driver);
+}
+
+static void __exit txx9aclc_ac97_exit(void)
+{
+	platform_driver_unregister(&txx9aclc_ac97_driver);
+}
+
+module_init(txx9aclc_ac97_init);
+module_exit(txx9aclc_ac97_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("TXx9 ACLC AC97 driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/txx9/txx9aclc-generic.c b/sound/soc/txx9/txx9aclc-generic.c
new file mode 100644
index 0000000..3175de9
--- /dev/null
+++ b/sound/soc/txx9/txx9aclc-generic.c
@@ -0,0 +1,98 @@
+/*
+ * Generic TXx9 ACLC machine driver
+ *
+ * Copyright (C) 2009 Atsushi Nemoto
+ *
+ * Based on RBTX49xx patch from CELF patch archive.
+ * (C) Copyright TOSHIBA CORPORATION 2004-2006
+ *
+ * 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 is a very generic AC97 sound machine driver for boards which
+ * have (AC97) audio at ACLC (e.g. RBTX49XX boards).
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include "../codecs/ac97.h"
+#include "txx9aclc.h"
+
+static struct snd_soc_dai_link txx9aclc_generic_dai = {
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &txx9aclc_ac97_dai,
+	.codec_dai = &ac97_dai,
+};
+
+static struct snd_soc_card txx9aclc_generic_card = {
+	.name		= "Generic TXx9 ACLC Audio",
+	.platform	= &txx9aclc_soc_platform,
+	.dai_link	= &txx9aclc_generic_dai,
+	.num_links	= 1,
+};
+
+static struct txx9aclc_soc_device txx9aclc_generic_soc_device = {
+	.soc_dev = {
+		.card		= &txx9aclc_generic_card,
+		.codec_dev	= &soc_codec_dev_ac97,
+	},
+};
+
+static int __init txx9aclc_generic_probe(struct platform_device *pdev)
+{
+	struct txx9aclc_soc_device *dev = &txx9aclc_generic_soc_device;
+	struct platform_device *soc_pdev;
+	int ret;
+
+	soc_pdev = platform_device_alloc("soc-audio", -1);
+	if (!soc_pdev)
+		return -ENOMEM;
+	platform_set_drvdata(soc_pdev, &dev->soc_dev);
+	dev->soc_dev.dev = &soc_pdev->dev;
+	ret = platform_device_add(soc_pdev);
+	if (ret) {
+		platform_device_put(soc_pdev);
+		return ret;
+	}
+	platform_set_drvdata(pdev, soc_pdev);
+	return 0;
+}
+
+static int __exit txx9aclc_generic_remove(struct platform_device *pdev)
+{
+	struct platform_device *soc_pdev = platform_get_drvdata(pdev);
+
+	platform_device_unregister(soc_pdev);
+	return 0;
+}
+
+static struct platform_driver txx9aclc_generic_driver = {
+	.remove = txx9aclc_generic_remove,
+	.driver = {
+		.name = "txx9aclc-generic",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init txx9aclc_generic_init(void)
+{
+	return platform_driver_probe(&txx9aclc_generic_driver,
+				     txx9aclc_generic_probe);
+}
+
+static void __exit txx9aclc_generic_exit(void)
+{
+	platform_driver_unregister(&txx9aclc_generic_driver);
+}
+
+module_init(txx9aclc_generic_init);
+module_exit(txx9aclc_generic_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Generic TXx9 ACLC ALSA SoC audio driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
new file mode 100644
index 0000000..fa33661
--- /dev/null
+++ b/sound/soc/txx9/txx9aclc.c
@@ -0,0 +1,430 @@
+/*
+ * Generic TXx9 ACLC platform driver
+ *
+ * Copyright (C) 2009 Atsushi Nemoto
+ *
+ * Based on RBTX49xx patch from CELF patch archive.
+ * (C) Copyright TOSHIBA CORPORATION 2004-2006
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "txx9aclc.h"
+
+static const struct snd_pcm_hardware txx9aclc_pcm_hardware = {
+	/*
+	 * REVISIT: SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
+	 * needs more works for noncoherent MIPS.
+	 */
+	.info		  = SNDRV_PCM_INFO_INTERLEAVED |
+			    SNDRV_PCM_INFO_BATCH |
+			    SNDRV_PCM_INFO_PAUSE,
+#ifdef __BIG_ENDIAN
+	.formats	  = SNDRV_PCM_FMTBIT_S16_BE,
+#else
+	.formats	  = SNDRV_PCM_FMTBIT_S16_LE,
+#endif
+	.period_bytes_min = 1024,
+	.period_bytes_max = 8 * 1024,
+	.periods_min	  = 2,
+	.periods_max	  = 4096,
+	.buffer_bytes_max = 32 * 1024,
+};
+
+static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct txx9aclc_dmadata *dmadata = runtime->private_data;
+	int ret;
+
+	ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(socdev->dev,
+		"runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd "
+		"runtime->min_align %ld\n",
+		(unsigned long)runtime->dma_area,
+		(unsigned long)runtime->dma_addr, runtime->dma_bytes,
+		runtime->min_align);
+	dev_dbg(socdev->dev,
+		"periods %d period_bytes %d stream %d\n",
+		params_periods(params), params_period_bytes(params),
+		substream->stream);
+
+	dmadata->substream = substream;
+	dmadata->pos = 0;
+	return 0;
+}
+
+static int txx9aclc_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int txx9aclc_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct txx9aclc_dmadata *dmadata = runtime->private_data;
+
+	dmadata->dma_addr = runtime->dma_addr;
+	dmadata->buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
+	dmadata->period_bytes = snd_pcm_lib_period_bytes(substream);
+
+	if (dmadata->buffer_bytes == dmadata->period_bytes) {
+		dmadata->frag_bytes = dmadata->period_bytes >> 1;
+		dmadata->frags = 2;
+	} else {
+		dmadata->frag_bytes = dmadata->period_bytes;
+		dmadata->frags = dmadata->buffer_bytes / dmadata->period_bytes;
+	}
+	dmadata->frag_count = 0;
+	dmadata->pos = 0;
+	return 0;
+}
+
+static void txx9aclc_dma_complete(void *arg)
+{
+	struct txx9aclc_dmadata *dmadata = arg;
+	unsigned long flags;
+
+	/* dma completion handler cannot submit new operations */
+	spin_lock_irqsave(&dmadata->dma_lock, flags);
+	if (dmadata->frag_count >= 0) {
+		dmadata->dmacount--;
+		BUG_ON(dmadata->dmacount < 0);
+		tasklet_schedule(&dmadata->tasklet);
+	}
+	spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+}
+
+static struct dma_async_tx_descriptor *
+txx9aclc_dma_submit(struct txx9aclc_dmadata *dmadata, dma_addr_t buf_dma_addr)
+{
+	struct dma_chan *chan = dmadata->dma_chan;
+	struct dma_async_tx_descriptor *desc;
+	struct scatterlist sg;
+
+	sg_init_table(&sg, 1);
+	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,
+		dmadata->substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		DMA_TO_DEVICE : DMA_FROM_DEVICE,
+		DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc) {
+		dev_err(&chan->dev->device, "cannot prepare slave dma\n");
+		return NULL;
+	}
+	desc->callback = txx9aclc_dma_complete;
+	desc->callback_param = dmadata;
+	desc->tx_submit(desc);
+	return desc;
+}
+
+#define NR_DMA_CHAIN		2
+
+static void txx9aclc_dma_tasklet(unsigned long data)
+{
+	struct txx9aclc_dmadata *dmadata = (struct txx9aclc_dmadata *)data;
+	struct dma_chan *chan = dmadata->dma_chan;
+	struct dma_async_tx_descriptor *desc;
+	struct snd_pcm_substream *substream = dmadata->substream;
+	u32 ctlbit = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		ACCTL_AUDODMA : ACCTL_AUDIDMA;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dmadata->dma_lock, flags);
+	if (dmadata->frag_count < 0) {
+		struct txx9aclc_soc_device *dev =
+			container_of(dmadata, struct txx9aclc_soc_device,
+				     dmadata[substream->stream]);
+		struct txx9aclc_plat_drvdata *drvdata =
+			txx9aclc_get_plat_drvdata(dev);
+		void __iomem *base = drvdata->base;
+
+		spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+		chan->device->device_terminate_all(chan);
+		/* first time */
+		for (i = 0; i < NR_DMA_CHAIN; i++) {
+			desc = txx9aclc_dma_submit(dmadata,
+				dmadata->dma_addr + i * dmadata->frag_bytes);
+			if (!desc)
+				return;
+		}
+		dmadata->dmacount = NR_DMA_CHAIN;
+		chan->device->device_issue_pending(chan);
+		spin_lock_irqsave(&dmadata->dma_lock, flags);
+		__raw_writel(ctlbit, base + ACCTLEN);
+		dmadata->frag_count = NR_DMA_CHAIN % dmadata->frags;
+		spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+		return;
+	}
+	BUG_ON(dmadata->dmacount >= NR_DMA_CHAIN);
+	while (dmadata->dmacount < NR_DMA_CHAIN) {
+		dmadata->dmacount++;
+		spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+		desc = txx9aclc_dma_submit(dmadata,
+			dmadata->dma_addr +
+			dmadata->frag_count * dmadata->frag_bytes);
+		if (!desc)
+			return;
+		chan->device->device_issue_pending(chan);
+
+		spin_lock_irqsave(&dmadata->dma_lock, flags);
+		dmadata->frag_count++;
+		dmadata->frag_count %= dmadata->frags;
+		dmadata->pos += dmadata->frag_bytes;
+		dmadata->pos %= dmadata->buffer_bytes;
+		if ((dmadata->frag_count * dmadata->frag_bytes) %
+		    dmadata->period_bytes == 0)
+			snd_pcm_period_elapsed(substream);
+	}
+	spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+}
+
+static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct txx9aclc_soc_device *dev =
+		container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev);
+	struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+	void __iomem *base = drvdata->base;
+	unsigned long flags;
+	int ret = 0;
+	u32 ctlbit = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		ACCTL_AUDODMA : ACCTL_AUDIDMA;
+
+	spin_lock_irqsave(&dmadata->dma_lock, flags);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		dmadata->frag_count = -1;
+		tasklet_schedule(&dmadata->tasklet);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		__raw_writel(ctlbit, base + ACCTLDIS);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		__raw_writel(ctlbit, base + ACCTLEN);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+	return ret;
+}
+
+static snd_pcm_uframes_t
+txx9aclc_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
+
+	return bytes_to_frames(substream->runtime, dmadata->pos);
+}
+
+static int txx9aclc_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct txx9aclc_soc_device *dev =
+		container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev);
+	struct txx9aclc_dmadata *dmadata = &dev->dmadata[substream->stream];
+	int ret;
+
+	ret = snd_soc_set_runtime_hwparams(substream, &txx9aclc_pcm_hardware);
+	if (ret)
+		return ret;
+	/* ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(substream->runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		return ret;
+	substream->runtime->private_data = dmadata;
+	return 0;
+}
+
+static int txx9aclc_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
+	struct dma_chan *chan = dmadata->dma_chan;
+
+	dmadata->frag_count = -1;
+	chan->device->device_terminate_all(chan);
+	return 0;
+}
+
+static struct snd_pcm_ops txx9aclc_pcm_ops = {
+	.open		= txx9aclc_pcm_open,
+	.close		= txx9aclc_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= txx9aclc_pcm_hw_params,
+	.hw_free	= txx9aclc_pcm_hw_free,
+	.prepare	= txx9aclc_pcm_prepare,
+	.trigger	= txx9aclc_pcm_trigger,
+	.pointer	= txx9aclc_pcm_pointer,
+};
+
+static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+			    struct snd_pcm *pcm)
+{
+	return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+		card->dev, 64 * 1024, 4 * 1024 * 1024);
+}
+
+static bool filter(struct dma_chan *chan, void *param)
+{
+	struct txx9aclc_dmadata *dmadata = param;
+	char devname[BUS_ID_SIZE + 2];
+
+	sprintf(devname, "%s.%d", dmadata->dma_res->name,
+		(int)dmadata->dma_res->start);
+	if (strcmp(dev_name(chan->device->dev), devname) == 0) {
+		chan->private = &dmadata->dma_slave;
+		return true;
+	}
+	return false;
+}
+
+static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
+			     struct txx9aclc_dmadata *dmadata)
+{
+	struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+	struct txx9dmac_slave *ds = &dmadata->dma_slave;
+	dma_cap_mask_t mask;
+
+	spin_lock_init(&dmadata->dma_lock);
+
+	ds->reg_width = sizeof(u32);
+	if (dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ds->tx_reg = drvdata->physbase + ACAUDODAT;
+		ds->rx_reg = 0;
+	} else {
+		ds->tx_reg = 0;
+		ds->rx_reg = drvdata->physbase + ACAUDIDAT;
+	}
+
+	/* Try to grab a DMA channel */
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	dmadata->dma_chan = dma_request_channel(mask, filter, dmadata);
+	if (!dmadata->dma_chan) {
+		dev_err(dev->soc_dev.dev,
+			"DMA channel for %s is not available\n",
+			dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+			"playback" : "capture");
+		return -EBUSY;
+	}
+	tasklet_init(&dmadata->tasklet, txx9aclc_dma_tasklet,
+		     (unsigned long)dmadata);
+	return 0;
+}
+
+static int txx9aclc_pcm_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct txx9aclc_soc_device *dev =
+		container_of(socdev, struct txx9aclc_soc_device, soc_dev);
+	struct resource *r;
+	int i;
+	int ret;
+
+	dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK;
+	dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE;
+	for (i = 0; i < 2; i++) {
+		r = platform_get_resource(dev->aclc_pdev, IORESOURCE_DMA, i);
+		if (!r) {
+			ret = -EBUSY;
+			goto exit;
+		}
+		dev->dmadata[i].dma_res = r;
+		ret = txx9aclc_dma_init(dev, &dev->dmadata[i]);
+		if (ret)
+			goto exit;
+	}
+	return 0;
+
+exit:
+	for (i = 0; i < 2; i++) {
+		if (dev->dmadata[i].dma_chan)
+			dma_release_channel(dev->dmadata[i].dma_chan);
+		dev->dmadata[i].dma_chan = NULL;
+	}
+	return ret;
+}
+
+static int txx9aclc_pcm_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct txx9aclc_soc_device *dev =
+		container_of(socdev, struct txx9aclc_soc_device, soc_dev);
+	struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+	void __iomem *base = drvdata->base;
+	int i;
+
+	/* disable all FIFO DMAs */
+	__raw_writel(ACCTL_AUDODMA | ACCTL_AUDIDMA, base + ACCTLDIS);
+	/* dummy R/W to clear pending DMAREQ if any */
+	__raw_writel(__raw_readl(base + ACAUDIDAT), base + ACAUDODAT);
+
+	for (i = 0; i < 2; i++) {
+		struct txx9aclc_dmadata *dmadata = &dev->dmadata[i];
+		struct dma_chan *chan = dmadata->dma_chan;
+		if (chan) {
+			dmadata->frag_count = -1;
+			chan->device->device_terminate_all(chan);
+			dma_release_channel(chan);
+		}
+		dev->dmadata[i].dma_chan = NULL;
+	}
+	return 0;
+}
+
+struct snd_soc_platform txx9aclc_soc_platform = {
+	.name		= "txx9aclc-audio",
+	.probe		= txx9aclc_pcm_probe,
+	.remove		= txx9aclc_pcm_remove,
+	.pcm_ops 	= &txx9aclc_pcm_ops,
+	.pcm_new	= txx9aclc_pcm_new,
+	.pcm_free	= txx9aclc_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(txx9aclc_soc_platform);
+
+static int __init txx9aclc_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&txx9aclc_soc_platform);
+}
+
+static void __exit txx9aclc_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&txx9aclc_soc_platform);
+}
+
+module_init(txx9aclc_soc_platform_init);
+module_exit(txx9aclc_soc_platform_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/txx9/txx9aclc.h b/sound/soc/txx9/txx9aclc.h
new file mode 100644
index 0000000..6769aab
--- /dev/null
+++ b/sound/soc/txx9/txx9aclc.h
@@ -0,0 +1,83 @@
+/*
+ * TXx9 SoC AC Link Controller
+ *
+ * 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 __TXX9ACLC_H
+#define __TXX9ACLC_H
+
+#include <linux/interrupt.h>
+#include <asm/txx9/dmac.h>
+
+#define ACCTLEN			0x00	/* control enable */
+#define ACCTLDIS		0x04	/* control disable */
+#define   ACCTL_ENLINK		0x00000001	/* enable/disable AC-link */
+#define   ACCTL_AUDODMA		0x00000100	/* AUDODMA enable/disable */
+#define   ACCTL_AUDIDMA		0x00001000	/* AUDIDMA enable/disable */
+#define   ACCTL_AUDOEHLT	0x00010000	/* AUDO error halt
+						   enable/disable */
+#define   ACCTL_AUDIEHLT	0x00100000	/* AUDI error halt
+						   enable/disable */
+#define ACREGACC		0x08	/* codec register access */
+#define   ACREGACC_DAT_SHIFT	0	/* data field */
+#define   ACREGACC_REG_SHIFT	16	/* address field */
+#define   ACREGACC_CODECID_SHIFT	24	/* CODEC ID field */
+#define   ACREGACC_READ		0x80000000	/* CODEC read */
+#define   ACREGACC_WRITE	0x00000000	/* CODEC write */
+#define ACINTSTS		0x10	/* interrupt status */
+#define ACINTMSTS		0x14	/* interrupt masked status */
+#define ACINTEN			0x18	/* interrupt enable */
+#define ACINTDIS		0x1c	/* interrupt disable */
+#define   ACINT_CODECRDY(n)	(0x00000001 << (n))	/* CODECn ready */
+#define   ACINT_REGACCRDY	0x00000010	/* ACREGACC ready */
+#define   ACINT_AUDOERR		0x00000100	/* AUDO underrun error */
+#define   ACINT_AUDIERR		0x00001000	/* AUDI overrun error */
+#define ACDMASTS		0x80	/* DMA request status */
+#define   ACDMA_AUDO		0x00000001	/* AUDODMA pending */
+#define   ACDMA_AUDI		0x00000010	/* AUDIDMA pending */
+#define ACAUDODAT		0xa0	/* audio out data */
+#define ACAUDIDAT		0xb0	/* audio in data */
+#define ACREVID			0xfc	/* revision ID */
+
+struct txx9aclc_dmadata {
+	struct resource *dma_res;
+	struct txx9dmac_slave dma_slave;
+	struct dma_chan *dma_chan;
+	struct tasklet_struct tasklet;
+	spinlock_t dma_lock;
+	int stream; /* SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE */
+	struct snd_pcm_substream *substream;
+	unsigned long pos;
+	dma_addr_t dma_addr;
+	unsigned long buffer_bytes;
+	unsigned long period_bytes;
+	unsigned long frag_bytes;
+	int frags;
+	int frag_count;
+	int dmacount;
+};
+
+struct txx9aclc_plat_drvdata {
+	void __iomem *base;
+	u64 physbase;
+};
+
+struct txx9aclc_soc_device {
+	struct snd_soc_device soc_dev;
+	struct platform_device *aclc_pdev;	/* for ioresources, drvdata */
+	struct txx9aclc_dmadata dmadata[2];
+};
+
+static inline struct txx9aclc_plat_drvdata *txx9aclc_get_plat_drvdata(
+	struct txx9aclc_soc_device *sdev)
+{
+	return platform_get_drvdata(sdev->aclc_pdev);
+}
+
+extern struct snd_soc_platform txx9aclc_soc_platform;
+extern struct snd_soc_dai txx9aclc_ac97_dai;
+
+#endif /* __TXX9ACLC_H */
diff --git a/sound/synth/Makefile b/sound/synth/Makefile
index e99fd76..11eb06a 100644
--- a/sound/synth/Makefile
+++ b/sound/synth/Makefile
@@ -5,16 +5,8 @@
 
 snd-util-mem-objs := util_mem.o
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_EMU10K1) += snd-util-mem.o
 obj-$(CONFIG_SND_TRIDENT) += snd-util-mem.o
-obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-util-mem.o
-obj-$(call sequencer,$(CONFIG_SND)) += emux/
+obj-$(CONFIG_SND_SBAWE_SEQ) += snd-util-mem.o
+obj-$(CONFIG_SND_SEQUENCER) += emux/
diff --git a/sound/synth/emux/Makefile b/sound/synth/emux/Makefile
index b690352..328594e 100644
--- a/sound/synth/emux/Makefile
+++ b/sound/synth/emux/Makefile
@@ -7,14 +7,6 @@
 		       emux_effect.o emux_proc.o emux_hwdep.o soundfont.o \
 		       $(if $(CONFIG_SND_SEQUENCER_OSS),emux_oss.o)
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 # Toplevel Module Dependencies
-obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emux-synth.o
-obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-emux-synth.o
+obj-$(CONFIG_SND_SBAWE_SEQ) += snd-emux-synth.o
+obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-emux-synth.o
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index b13ce76..b144513 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -42,10 +42,10 @@
 	(stream << 1) | (~(i / (dev->n_streams * BYTES_PER_SAMPLE_USB)) & 1)
 
 static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = {
-	.info 		= (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 
+	.info 		= (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 			   SNDRV_PCM_INFO_BLOCK_TRANSFER),
 	.formats 	= SNDRV_PCM_FMTBIT_S24_3BE,
-	.rates 		= (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | 
+	.rates 		= (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
 			   SNDRV_PCM_RATE_96000),
 	.rate_min	= 44100,
 	.rate_max	= 0, /* will overwrite later */
@@ -68,7 +68,7 @@
 		dev->sub_capture[sub->number] = sub;
 }
 
-static void 
+static void
 deactivate_substream(struct snd_usb_caiaqdev *dev,
 		     struct snd_pcm_substream *sub)
 {
@@ -118,7 +118,7 @@
 			return -EPIPE;
 		}
 	}
-	
+
 	return 0;
 }
 
@@ -129,7 +129,7 @@
 	debug("%s(%p)\n", __func__, dev);
 	if (!dev->streaming)
 		return;
-	
+
 	dev->streaming = 0;
 
 	for (i = 0; i < N_URBS; i++) {
@@ -154,7 +154,7 @@
 	debug("%s(%p)\n", __func__, substream);
 	if (all_substreams_zero(dev->sub_playback) &&
 	    all_substreams_zero(dev->sub_capture)) {
-		/* when the last client has stopped streaming, 
+		/* when the last client has stopped streaming,
 		 * all sample rates are allowed again */
 		stream_stop(dev);
 		dev->pcm_info.rates = dev->samplerates;
@@ -194,7 +194,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
 	debug("%s(%p)\n", __func__, substream);
-	
+
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		dev->period_out_count[index] = BYTES_PER_SAMPLE + 1;
 		dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1;
@@ -205,19 +205,19 @@
 
 	if (dev->streaming)
 		return 0;
-	
+
 	/* the first client that opens a stream defines the sample rate
 	 * setting for all subsequent calls, until the last client closed. */
 	for (i=0; i < ARRAY_SIZE(rates); i++)
 		if (runtime->rate == rates[i])
 			dev->pcm_info.rates = 1 << i;
-	
+
 	snd_pcm_limit_hw_rates(runtime);
 
 	bytes_per_sample = BYTES_PER_SAMPLE;
 	if (dev->spec.data_alignment == 2)
 		bytes_per_sample++;
-	
+
 	bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE)
 		* bytes_per_sample * CHANNELS_PER_STREAM * dev->n_streams;
 
@@ -232,7 +232,7 @@
 	ret = stream_start(dev);
 	if (ret)
 		return ret;
-	
+
 	dev->output_running = 0;
 	wait_event_timeout(dev->prepare_wait_queue, dev->output_running, HZ);
 	if (!dev->output_running) {
@@ -273,7 +273,7 @@
 		return SNDRV_PCM_POS_XRUN;
 
 	if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		return bytes_to_frames(sub->runtime, 
+		return bytes_to_frames(sub->runtime,
 					dev->audio_out_buf_pos[index]);
 	else
 		return bytes_to_frames(sub->runtime,
@@ -291,7 +291,7 @@
 	.trigger =	snd_usb_caiaq_pcm_trigger,
 	.pointer =	snd_usb_caiaq_pcm_pointer
 };
-	
+
 static void check_for_elapsed_periods(struct snd_usb_caiaqdev *dev,
 				      struct snd_pcm_substream **subs)
 {
@@ -333,7 +333,7 @@
 				struct snd_pcm_runtime *rt = sub->runtime;
 				char *audio_buf = rt->dma_area;
 				int sz = frames_to_bytes(rt, rt->buffer_size);
-				audio_buf[dev->audio_in_buf_pos[stream]++] 
+				audio_buf[dev->audio_in_buf_pos[stream]++]
 					= usb_buf[i];
 				dev->period_in_count[stream]++;
 				if (dev->audio_in_buf_pos[stream] == sz)
@@ -354,14 +354,14 @@
 
 	for (i = 0; i < iso->actual_length;) {
 		if (i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 0) {
-			for (stream = 0; 
-			     stream < dev->n_streams; 
+			for (stream = 0;
+			     stream < dev->n_streams;
 			     stream++, i++) {
 				if (dev->first_packet)
 					continue;
 
 				check_byte = MAKE_CHECKBYTE(dev, stream, i);
-				
+
 				if ((usb_buf[i] & 0x3f) != check_byte)
 					dev->input_panic = 1;
 
@@ -410,21 +410,21 @@
 	}
 
 	if ((dev->input_panic || dev->output_panic) && !dev->warned) {
-		debug("streaming error detected %s %s\n", 
+		debug("streaming error detected %s %s\n",
 				dev->input_panic ? "(input)" : "",
 				dev->output_panic ? "(output)" : "");
 		dev->warned = 1;
 	}
 }
 
-static void fill_out_urb(struct snd_usb_caiaqdev *dev, 
-			 struct urb *urb, 
+static void fill_out_urb(struct snd_usb_caiaqdev *dev,
+			 struct urb *urb,
 			 const struct usb_iso_packet_descriptor *iso)
 {
 	unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
 	struct snd_pcm_substream *sub;
 	int stream, i;
-	
+
 	for (i = 0; i < iso->length;) {
 		for (stream = 0; stream < dev->n_streams; stream++, i++) {
 			sub = dev->sub_playback[stream];
@@ -444,7 +444,7 @@
 
 		/* fill in the check bytes */
 		if (dev->spec.data_alignment == 2 &&
-		    i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 
+		    i % (dev->n_streams * BYTES_PER_SAMPLE_USB) ==
 		    	(dev->n_streams * CHANNELS_PER_STREAM))
 		    for (stream = 0; stream < dev->n_streams; stream++, i++)
 		    	usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);
@@ -453,7 +453,7 @@
 
 static void read_completed(struct urb *urb)
 {
-	struct snd_usb_caiaq_cb_info *info = urb->context; 
+	struct snd_usb_caiaq_cb_info *info = urb->context;
 	struct snd_usb_caiaqdev *dev;
 	struct urb *out;
 	int frame, len, send_it = 0, outframe = 0;
@@ -478,7 +478,7 @@
 		out->iso_frame_desc[outframe].length = len;
 		out->iso_frame_desc[outframe].actual_length = 0;
 		out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame;
-		
+
 		if (len > 0) {
 			spin_lock(&dev->spinlock);
 			fill_out_urb(dev, out, &out->iso_frame_desc[outframe]);
@@ -497,14 +497,14 @@
 		out->transfer_flags = URB_ISO_ASAP;
 		usb_submit_urb(out, GFP_ATOMIC);
 	}
-	
+
 	/* re-submit inbound urb */
 	for (frame = 0; frame < FRAMES_PER_URB; frame++) {
 		urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame;
 		urb->iso_frame_desc[frame].length = BYTES_PER_FRAME;
 		urb->iso_frame_desc[frame].actual_length = 0;
 	}
-	
+
 	urb->number_of_packets = FRAMES_PER_URB;
 	urb->transfer_flags = URB_ISO_ASAP;
 	usb_submit_urb(urb, GFP_ATOMIC);
@@ -528,7 +528,7 @@
 	struct usb_device *usb_dev = dev->chip.dev;
 	unsigned int pipe;
 
-	pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ? 
+	pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ?
 		usb_sndisocpipe(usb_dev, ENDPOINT_PLAYBACK) :
 		usb_rcvisocpipe(usb_dev, ENDPOINT_CAPTURE);
 
@@ -547,25 +547,25 @@
 			return urbs;
 		}
 
-		urbs[i]->transfer_buffer = 
+		urbs[i]->transfer_buffer =
 			kmalloc(FRAMES_PER_URB * BYTES_PER_FRAME, GFP_KERNEL);
 		if (!urbs[i]->transfer_buffer) {
 			log("unable to kmalloc() transfer buffer, OOM!?\n");
 			*ret = -ENOMEM;
 			return urbs;
 		}
-		
+
 		for (frame = 0; frame < FRAMES_PER_URB; frame++) {
-			struct usb_iso_packet_descriptor *iso = 
+			struct usb_iso_packet_descriptor *iso =
 				&urbs[i]->iso_frame_desc[frame];
-			
+
 			iso->offset = BYTES_PER_FRAME * frame;
 			iso->length = BYTES_PER_FRAME;
 		}
-		
+
 		urbs[i]->dev = usb_dev;
 		urbs[i]->pipe = pipe;
-		urbs[i]->transfer_buffer_length = FRAMES_PER_URB 
+		urbs[i]->transfer_buffer_length = FRAMES_PER_URB
 						* BYTES_PER_FRAME;
 		urbs[i]->context = &dev->data_cb_info[i];
 		urbs[i]->interval = 1;
@@ -589,7 +589,7 @@
 	for (i = 0; i < N_URBS; i++) {
 		if (!urbs[i])
 			continue;
-		
+
 		usb_kill_urb(urbs[i]);
 		kfree(urbs[i]->transfer_buffer);
 		usb_free_urb(urbs[i]);
@@ -602,11 +602,11 @@
 {
 	int i, ret;
 
-	dev->n_audio_in  = max(dev->spec.num_analog_audio_in, 
-			       dev->spec.num_digital_audio_in) / 
+	dev->n_audio_in  = max(dev->spec.num_analog_audio_in,
+			       dev->spec.num_digital_audio_in) /
 				CHANNELS_PER_STREAM;
 	dev->n_audio_out = max(dev->spec.num_analog_audio_out,
-			       dev->spec.num_digital_audio_out) / 
+			       dev->spec.num_digital_audio_out) /
 				CHANNELS_PER_STREAM;
 	dev->n_streams = max(dev->n_audio_in, dev->n_audio_out);
 
@@ -619,7 +619,7 @@
 		return -EINVAL;
 	}
 
-	ret = snd_pcm_new(dev->chip.card, dev->product_name, 0, 
+	ret = snd_pcm_new(dev->chip.card, dev->product_name, 0,
 			dev->n_audio_out, dev->n_audio_in, &dev->pcm);
 
 	if (ret < 0) {
@@ -632,7 +632,7 @@
 
 	memset(dev->sub_playback, 0, sizeof(dev->sub_playback));
 	memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
-	
+
 	memcpy(&dev->pcm_info, &snd_usb_caiaq_pcm_hardware,
 			sizeof(snd_usb_caiaq_pcm_hardware));
 
@@ -651,9 +651,9 @@
 		break;
 	}
 
-	snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 
+	snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
 				&snd_usb_caiaq_ops);
-	snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 
+	snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
 				&snd_usb_caiaq_ops);
 
 	snd_pcm_lib_preallocate_pages_for_all(dev->pcm,
@@ -662,7 +662,7 @@
 					MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);
 
 	dev->data_cb_info =
-		kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS, 
+		kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS,
 					GFP_KERNEL);
 
 	if (!dev->data_cb_info)
@@ -672,14 +672,14 @@
 		dev->data_cb_info[i].dev = dev;
 		dev->data_cb_info[i].index = i;
 	}
-	
+
 	dev->data_urbs_in = alloc_urbs(dev, SNDRV_PCM_STREAM_CAPTURE, &ret);
 	if (ret < 0) {
 		kfree(dev->data_cb_info);
 		free_urbs(dev->data_urbs_in);
 		return ret;
 	}
-	
+
 	dev->data_urbs_out = alloc_urbs(dev, SNDRV_PCM_STREAM_PLAYBACK, &ret);
 	if (ret < 0) {
 		kfree(dev->data_cb_info);
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index 515de1c..2240624 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -35,7 +35,7 @@
 #include "input.h"
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.14");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.16");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
 			 "{Native Instruments, RigKontrol3},"
@@ -79,7 +79,7 @@
 	{
 		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE,
 		.idVendor =	USB_VID_NATIVEINSTRUMENTS,
-		.idProduct =	USB_PID_RIGKONTROL2 
+		.idProduct =	USB_PID_RIGKONTROL2
 	},
 	{
 		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE,
@@ -197,7 +197,7 @@
 
 	if (buffer && len > 0)
 		memcpy(dev->ep1_out_buf+1, buffer, len);
-	
+
 	dev->ep1_out_buf[0] = command;
 	return usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, 1),
 			   dev->ep1_out_buf, len+1, &actual_len, 200);
@@ -208,7 +208,7 @@
 {
 	int ret;
 	char tmp[5];
-	
+
 	switch (rate) {
 	case 44100:	tmp[0] = SAMPLERATE_44100;   break;
 	case 48000:	tmp[0] = SAMPLERATE_48000;   break;
@@ -237,12 +237,12 @@
 
 	if (ret)
 		return ret;
-	
-	if (!wait_event_timeout(dev->ep1_wait_queue, 
+
+	if (!wait_event_timeout(dev->ep1_wait_queue,
 	    dev->audio_parm_answer >= 0, HZ))
 		return -EPIPE;
-		
-	if (dev->audio_parm_answer != 1) 
+
+	if (dev->audio_parm_answer != 1)
 		debug("unable to set the device's audio params\n");
 	else
 		dev->bpp = bpp;
@@ -250,8 +250,8 @@
 	return dev->audio_parm_answer == 1 ? 0 : -EINVAL;
 }
 
-int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, 
-				int digital, int analog, int erp)
+int snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *dev,
+			       int digital, int analog, int erp)
 {
 	char tmp[3] = { digital, analog, erp };
 	return snd_usb_caiaq_send_command(dev, EP1_CMD_AUTO_MSG,
@@ -262,7 +262,7 @@
 {
 	int ret;
 	char val[4];
-	
+
 	/* device-specific startup specials */
 	switch (dev->chip.usb_id) {
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
@@ -314,7 +314,7 @@
 			dev->control_state, 1);
 		break;
 	}
-	
+
 	if (dev->spec.num_analog_audio_out +
 	    dev->spec.num_analog_audio_in +
 	    dev->spec.num_digital_audio_out +
@@ -323,7 +323,7 @@
 		if (ret < 0)
 			log("Unable to set up audio system (ret=%d)\n", ret);
 	}
-	
+
 	if (dev->spec.num_midi_in +
 	    dev->spec.num_midi_out > 0) {
 		ret = snd_usb_caiaq_midi_init(dev);
@@ -363,7 +363,7 @@
 	if (devnum >= SNDRV_CARDS)
 		return -ENODEV;
 
-	err = snd_card_create(index[devnum], id[devnum], THIS_MODULE, 
+	err = snd_card_create(index[devnum], id[devnum], THIS_MODULE,
 			      sizeof(struct snd_usb_caiaqdev), &card);
 	if (err < 0)
 		return err;
@@ -382,11 +382,11 @@
 
 static int __devinit init_card(struct snd_usb_caiaqdev *dev)
 {
-	char *c;
+	char *c, usbpath[32];
 	struct usb_device *usb_dev = dev->chip.dev;
 	struct snd_card *card = dev->chip.card;
 	int err, len;
-	
+
 	if (usb_set_interface(usb_dev, 0, 1) != 0) {
 		log("can't set alt interface.\n");
 		return -EIO;
@@ -395,19 +395,19 @@
 	usb_init_urb(&dev->ep1_in_urb);
 	usb_init_urb(&dev->midi_out_urb);
 
-	usb_fill_bulk_urb(&dev->ep1_in_urb, usb_dev, 
+	usb_fill_bulk_urb(&dev->ep1_in_urb, usb_dev,
 			  usb_rcvbulkpipe(usb_dev, 0x1),
-			  dev->ep1_in_buf, EP1_BUFSIZE, 
+			  dev->ep1_in_buf, EP1_BUFSIZE,
 			  usb_ep1_command_reply_dispatch, dev);
 
-	usb_fill_bulk_urb(&dev->midi_out_urb, usb_dev, 
+	usb_fill_bulk_urb(&dev->midi_out_urb, usb_dev,
 			  usb_sndbulkpipe(usb_dev, 0x1),
-			  dev->midi_out_buf, EP1_BUFSIZE, 
+			  dev->midi_out_buf, EP1_BUFSIZE,
 			  snd_usb_caiaq_midi_output_done, dev);
-	
+
 	init_waitqueue_head(&dev->ep1_wait_queue);
 	init_waitqueue_head(&dev->prepare_wait_queue);
-	
+
 	if (usb_submit_urb(&dev->ep1_in_urb, GFP_KERNEL) != 0)
 		return -EIO;
 
@@ -420,47 +420,52 @@
 
 	usb_string(usb_dev, usb_dev->descriptor.iManufacturer,
 		   dev->vendor_name, CAIAQ_USB_STR_LEN);
-	
+
 	usb_string(usb_dev, usb_dev->descriptor.iProduct,
 		   dev->product_name, CAIAQ_USB_STR_LEN);
-	
-	usb_string(usb_dev, usb_dev->descriptor.iSerialNumber,
-		   dev->serial, CAIAQ_USB_STR_LEN);
 
-	/* terminate serial string at first white space occurence */
-	c = strchr(dev->serial, ' ');
-	if (c)
-		*c = '\0';
-	
-	strcpy(card->driver, MODNAME);
-	strcpy(card->shortname, dev->product_name);
+	strlcpy(card->driver, MODNAME, sizeof(card->driver));
+	strlcpy(card->shortname, dev->product_name, sizeof(card->shortname));
+	strlcpy(card->mixername, dev->product_name, sizeof(card->mixername));
 
-	len = snprintf(card->longname, sizeof(card->longname),
-		       "%s %s (serial %s, ",
-		       dev->vendor_name, dev->product_name, dev->serial);
+	/* if the id was not passed as module option, fill it with a shortened
+	 * version of the product string which does not contain any
+	 * whitespaces */
 
-	if (len < sizeof(card->longname) - 2)
-		len += usb_make_path(usb_dev, card->longname + len,
-				     sizeof(card->longname) - len);
+	if (*card->id == '\0') {
+		char id[sizeof(card->id)];
 
-	card->longname[len++] = ')';
-	card->longname[len] = '\0';
+		memset(id, 0, sizeof(id));
+
+		for (c = card->shortname, len = 0;
+			*c && len < sizeof(card->id); c++)
+			if (*c != ' ')
+				id[len++] = *c;
+
+		snd_card_set_id(card, id);
+	}
+
+	usb_make_path(usb_dev, usbpath, sizeof(usbpath));
+	snprintf(card->longname, sizeof(card->longname),
+		       "%s %s (%s)",
+		       dev->vendor_name, dev->product_name, usbpath);
+
 	setup_card(dev);
 	return 0;
 }
 
-static int __devinit snd_probe(struct usb_interface *intf, 
+static int __devinit snd_probe(struct usb_interface *intf,
 		     const struct usb_device_id *id)
 {
 	int ret;
 	struct snd_card *card;
 	struct usb_device *device = interface_to_usbdev(intf);
-	
+
 	ret = create_card(device, &card);
-	
+
 	if (ret < 0)
 		return ret;
-			
+
 	usb_set_intfdata(intf, card);
 	ret = init_card(caiaqdev(card));
 	if (ret < 0) {
@@ -468,7 +473,7 @@
 		snd_card_free(card);
 		return ret;
 	}
-	
+
 	return 0;
 }
 
@@ -489,10 +494,10 @@
 	snd_usb_caiaq_input_free(dev);
 #endif
 	snd_usb_caiaq_audio_free(dev);
-	
+
 	usb_kill_urb(&dev->ep1_in_urb);
 	usb_kill_urb(&dev->midi_out_urb);
-	
+
 	snd_card_free(card);
 	usb_reset_device(interface_to_usbdev(intf));
 }
diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h
index 4cce1ad..ece7351 100644
--- a/sound/usb/caiaq/device.h
+++ b/sound/usb/caiaq/device.h
@@ -81,7 +81,6 @@
 
 	char vendor_name[CAIAQ_USB_STR_LEN];
 	char product_name[CAIAQ_USB_STR_LEN];
-	char serial[CAIAQ_USB_STR_LEN];
 
 	int n_streams, n_audio_in, n_audio_out;
 	int streaming, first_packet, output_running;
diff --git a/sound/usb/caiaq/midi.c b/sound/usb/caiaq/midi.c
index 8fa8cd8..538e8c0 100644
--- a/sound/usb/caiaq/midi.c
+++ b/sound/usb/caiaq/midi.c
@@ -40,7 +40,7 @@
 
 	if (!dev)
 		return;
-	
+
 	dev->midi_receive_substream = up ? substream : NULL;
 }
 
@@ -64,18 +64,18 @@
 				    struct snd_rawmidi_substream *substream)
 {
 	int len, ret;
-	
+
 	dev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE;
 	dev->midi_out_buf[1] = 0; /* port */
 	len = snd_rawmidi_transmit(substream, dev->midi_out_buf + 3,
 				   EP1_BUFSIZE - 3);
-	
+
 	if (len <= 0)
 		return;
-	
+
 	dev->midi_out_buf[2] = len;
 	dev->midi_out_urb.transfer_buffer_length = len+3;
-	
+
 	ret = usb_submit_urb(&dev->midi_out_urb, GFP_ATOMIC);
 	if (ret < 0)
 		log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed,"
@@ -88,7 +88,7 @@
 static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
 {
 	struct snd_usb_caiaqdev *dev = substream->rmidi->private_data;
-	
+
 	if (up) {
 		dev->midi_out_substream = substream;
 		if (!dev->midi_out_active)
@@ -113,12 +113,12 @@
 	.trigger =      snd_usb_caiaq_midi_input_trigger,
 };
 
-void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, 
+void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev,
 				     int port, const char *buf, int len)
 {
 	if (!dev->midi_receive_substream)
 		return;
-	
+
 	snd_rawmidi_receive(dev->midi_receive_substream, buf, len);
 }
 
@@ -142,16 +142,16 @@
 
 	if (device->spec.num_midi_out > 0) {
 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
-		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 
+		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
 				    &snd_usb_caiaq_midi_output);
 	}
 
 	if (device->spec.num_midi_in > 0) {
 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
-		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, 
+		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
 				    &snd_usb_caiaq_midi_input);
 	}
-	
+
 	device->rmidi = rmidi;
 
 	return 0;
@@ -160,7 +160,7 @@
 void snd_usb_caiaq_midi_output_done(struct urb* urb)
 {
 	struct snd_usb_caiaqdev *dev = urb->context;
-	
+
 	dev->midi_out_active = 0;
 	if (urb->status != 0)
 		return;
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index a6b8848..c7b9023 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -627,6 +627,7 @@
 	subs->hwptr_done += offs;
 	if (subs->hwptr_done >= runtime->buffer_size)
 		subs->hwptr_done -= runtime->buffer_size;
+	runtime->delay += offs;
 	spin_unlock_irqrestore(&subs->lock, flags);
 	urb->transfer_buffer_length = offs * stride;
 	if (period_elapsed)
@@ -636,12 +637,22 @@
 
 /*
  * process after playback data complete
- * - nothing to do
+ * - decrease the delay count again
  */
 static int retire_playback_urb(struct snd_usb_substream *subs,
 			       struct snd_pcm_runtime *runtime,
 			       struct urb *urb)
 {
+	unsigned long flags;
+	int stride = runtime->frame_bits >> 3;
+	int processed = urb->transfer_buffer_length / stride;
+
+	spin_lock_irqsave(&subs->lock, flags);
+	if (processed > runtime->delay)
+		runtime->delay = 0;
+	else
+		runtime->delay -= processed;
+	spin_unlock_irqrestore(&subs->lock, flags);
 	return 0;
 }
 
@@ -1520,6 +1531,7 @@
 	subs->hwptr_done = 0;
 	subs->transfer_done = 0;
 	subs->phase = 0;
+	runtime->delay = 0;
 
 	/* clear urbs (to be sure) */
 	deactivate_urbs(subs, 0, 1);
@@ -3279,6 +3291,25 @@
 	return snd_usb_cm106_write_int_reg(dev, 2, 0x8004);
 }
 
+/*
+ * C-Media CM6206 is based on CM106 with two additional
+ * registers that are not documented in the data sheet.
+ * Values here are chosen based on sniffing USB traffic
+ * under Windows.
+ */
+static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
+{
+	int err, reg;
+	int val[] = {0x200c, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000};
+
+	for (reg = 0; reg < ARRAY_SIZE(val); reg++) {
+		err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]);
+		if (err < 0)
+			return err;
+	}
+
+	return err;
+}
 
 /*
  * Setup quirks
@@ -3565,6 +3596,12 @@
 			goto __err_val;
 	}
 
+	/* C-Media CM6206 / CM106-Like Sound Device */
+	if (id == USB_ID(0x0d8c, 0x0102)) {
+		if (snd_usb_cm6206_boot_quirk(dev) < 0)
+			goto __err_val;
+	}
+
 	/*
 	 * found a config.  now register to ALSA
 	 */
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
index 5d955aa..f0f7624 100644
--- a/sound/usb/usbquirks.h
+++ b/sound/usb/usbquirks.h
@@ -1470,6 +1470,41 @@
 	}
 },
 {
+	/* Edirol M-16DX */
+	/* FIXME: This quirk gives a good-working capture stream but the
+	 *        playback seems problematic because of lacking of sync
+	 *        with capture stream.  It needs to sync with the capture
+	 *        clock.  As now, you'll get frequent sound distortions
+	 *        via the playback.
+	 */
+	USB_DEVICE(0x0582, 0x00c4),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const struct snd_usb_audio_quirk[]) {
+			{
+				.ifnum = 0,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_MIDI_FIXED_ENDPOINT,
+				.data = & (const struct snd_usb_midi_endpoint_info) {
+					.out_cables = 0x0001,
+					.in_cables  = 0x0001
+				}
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
+{
 	/* BOSS GT-10 */
 	USB_DEVICE(0x0582, 0x00da),
 	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
@@ -1951,6 +1986,14 @@
 	}
 },
 {
+	USB_DEVICE(0x0ccd, 0x0028),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "TerraTec",
+		.product_name = "Aureon 5.1 MkII",
+		.ifnum = QUIRK_NO_INTERFACE
+	}
+},
+{
 	USB_DEVICE(0x0ccd, 0x0035),
 	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
 		.vendor_name = "Miditech",
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 29259e7..0f5771f 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -568,8 +568,11 @@
 	if (!argc && target_pid == -1 && !system_wide)
 		usage_with_options(record_usage, options);
 
-	if (!nr_counters)
-		nr_counters = 1;
+	if (!nr_counters) {
+		nr_counters	= 1;
+		attrs[0].type	= PERF_TYPE_HARDWARE;
+		attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
+	}
 
 	for (counter = 0; counter < nr_counters; counter++) {
 		if (attrs[counter].sample_period)
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index 860e116..f71e0d2 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -440,3 +440,18 @@
 this process has created on other processes.  It only enables or
 disables the group leaders, not any other members in the groups.
 
+
+Arch requirements
+-----------------
+
+If your architecture does not have hardware performance metrics, you can
+still use the generic software counters based on hrtimers for sampling.
+
+So to start with, in order to add HAVE_PERF_COUNTERS to your Kconfig, you
+will need at least this:
+	- asm/perf_counter.h - a basic stub will suffice at first
+	- support for atomic64 types (and associated helper functions)
+	- set_perf_counter_pending() implemented
+
+If your architecture does have hardware capabilities, you can override the
+weak stub hw_perf_counter_init() to register hardware counters.
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index af0a504..87a1aca 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -53,11 +53,12 @@
 	_min1 < _min2 ? _min1 : _min2; })
 
 static inline int
-sys_perf_counter_open(struct perf_counter_attr *attr_uptr,
+sys_perf_counter_open(struct perf_counter_attr *attr,
 		      pid_t pid, int cpu, int group_fd,
 		      unsigned long flags)
 {
-	return syscall(__NR_perf_counter_open, attr_uptr, pid, cpu,
+	attr->size = sizeof(*attr);
+	return syscall(__NR_perf_counter_open, attr, pid, cpu,
 		       group_fd, flags);
 }
 
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 9d5f1ca..5a72586 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -75,7 +75,7 @@
 #define MAX_ALIASES 8
 
 static char *hw_cache [][MAX_ALIASES] = {
-	{ "L1-data"		, "l1-d", "l1d", "l1"				},
+	{ "L1-data"		, "l1-d", "l1d"					},
 	{ "L1-instruction"	, "l1-i", "l1i"					},
 	{ "L2"			, "l2"						},
 	{ "Data-TLB"		, "dtlb", "d-tlb"				},